Search code examples
asp.net-mvcgitgit-submodulesgitignore

git add . (dot) doesn't obey .gitignore (or my patterns are wrong)


I have the following situation. In my asp.net webforms projects, I have some shared repositories that I optionally use under my main repositories. The folders are named Shared and then Shared.* for others. For example, I have a folder structure like this.

\main  
.. \\.git  
.. \main-subfolder  

.. \Shared (this should be ignored since own repo)  
.... \\.git  
.... \Shared-subfolder  
.... shared files  

.. main-files

I think this pattern I'm using might be similar to git sub-modules, but that is (hopefully) reserved for another discussion.

My .gitignore file originally simply had: Shared*/ and everything worked great.

Then I discovered that in my asp mvc projects, my Views/Shared folders were getting ignored (as expected given the above pattern). So I tried to add an exclusion with !Views/Shared/ but that didn't work in that git still didn't detect that for the mvc projects it should be adding Views/Shared content.

So I ended up with:

Shared*/*
!Views/Shared/

And all seemed to work, however, I detected a problem in my original webforms projects (that should be ignoring folders of Shared*). So the following image. git status appears to correctly be ignoring the Shared folder, but when I do a git add . then git status, you can see that it has been added.

git add . workflow

Note: git com -am "Commit Message" appears to work too. If that would have been my original step instead of git add ., the Shared folder is ignored on the commit.

Is my setup (nested repository) not supported or is my .gitignore pattern incorrect? Thanks in advance.


Solution

  • I got confused even when I reproduced what you're looking at. My sympathies. Some of what git's doing here caters to abstruse usage (and should arguably not be its default behavior), and the pathname anchoring is just quirky.

    tl;dr, from comments and examples, I think you want:

    Shared*/
    !**/Views/Shared*/
    

    So, the confusing bits:

    git status by default (-u normal) chooses what (unignored and) untracked directories to show based on whether there are any files in them you could git add without forcing -- which isn't the same thing as checking whether there are any untracked submodules in there. It's sometimes useful to bypass untracked submodule boundaries, but an unadorned git status report doesn't look to me like a good place to do it by default.

    Second, git's pattern matching requires a leading / to anchor plain names at the pattern root (.gitignore location or top-of-worktree for other sources), but paths with an embedded / are always anchored at the pattern root, so to exclude a multipart path pattern anywhere, prefix it with **/. I'd hate to have to argue with anyone insisting this violates the principle of least surprise ...