gitbranchgitignoregit-checkout

Preserve ignored untracked files across checkout


I picked up an external project, which I will be developing from now on. As a failsafe measure, I made 2 branches:

Turns out I guessed wrong, and I need to track some of them.

I expected that checking out master after checking out gitignoreless would preserve the ignored files, but it's not so.

Are they now tracked just because they are tracked in a single branch?
Is there another reason that gets them deleted?
Is there a way to obtain this behaviour?

Most of the documentation and answers I found focus on the opposite: having the files deleted.


Solution

  • When you switch to a branch, Git makes sure that your working tree matches the content of the commit you're switching. Quoting an extract of Basic Branching of the Git Pro book:

    when you switch branches, Git resets your working directory to look like it did the last time you committed on that branch. It adds, removes, and modifies files automatically to make sure your working copy is what the branch looked like on your last commit to it.

    This means that:

    In your case, even though master had a .gitignore for some of the files on gitignoreless, once you switched to master those files had to be removed in order to match the content of master's head commit. This is because the files were already tracked on gitignoreless, and every tracked file in the working directory that is not contained in the selected commit is removed.

    As already explained by @matt, .gitignore affects only files that are not already in the index. Therefore, you might want to consider having your .gitignore on all your branches, and build it in such a way to not show undesired files during the staging process. However, since some of the undesired files have already been tracked, you can "untrack" them with the --cached option of git rm. In your case, you could run:

    # untrack the undesired files
    git rm --cached <file1> <file2> ... <fileN>
    
    # add the previous files as entries in your gitignore
    echo <file1> >> .gitgnore
    echo <file2> >> .gitgnore
    ...
    echo <fileN> >> .gitgnore