This is very frustrating - I found that even though I had the editor config setup correctly, VS2019 would spontaneously insert tabs into the file.
I vastly prefer tabs, but at my current job they use spaces, so you gotta go with the concensus.
Much to their dismay, my files would be checked in with tabs, and of course Git would natter at you about changes.
It turns out, per this thread: https://developercommunity.visualstudio.com/t/visual-studio-20194-c-insert-spaces-instead-of-tab/847853 Visual Studio 2019 will essentially ignore your setting and decide, based on the contents of the file, to spontaneously switch to what it thinks is correct.
This cannot be changed apparently:
This is the Adaptive Formatting behavior in Visual Studio: the Editor
heuristically determines if the current file should use Tabs or Spaces
for indentation.
We don’t currently have an option to disable adaptive white space, but
if folks feel that’s important, we can add it.
LOTS of people complained, but then you get the (standard for now) disclaimer of "we work on the squeeky wheel".
So we're on our own.
So you can try turning it off, but VS2019 will still maintain the file in what it thinks is proper - even if there is only ONE TAB in the file.
Therefor, the only complete fix, again straight from Microsoft:
Third, if you use .editorconfig in your code repo, we will ALWAYS
honor those settings. It’s not a requirement to use .editorconfig, but
anyone who is particular interested in maintaining a coding style
should know that our of the VS guiding principles is to never believe
we’re “smart enough” to override .editorconfig.
My full editor config:
[*]
indent_style = space
indent_size = 3
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
Note the "end_of_line" ... this also fixes problems with WSL, as otherwise Git may change your line endings to CRLF in .sh files ... which doesn't work with WSL.
Along with this bonus solution, set your .gitattributes file:
* text=auto eol=lf
*.{cmd,[cC][mM][dD]} text eol=crlf
*.{bat,[bB][aA][tT]} text eol=crlf
*.cs text eol=crlf
*.xaml text eol=crlf
*.csproj text eol=crlf
*.njsproj text eol=crlf
*.pyproj text eol=crlf
*.sln text eol=crlf
So you can kill two birds with one stone.