Search code examples
gitbranchgitignore

Git checkout files from a branch without tracking them


My question is this: I have a git repo with a directory in the .gitignore file. Normally this works and any files that are changed in the directory are ignored. However if I checkout files into the ignored directory from a branch that doesn't ignore those files i.e.:

git checkout a_branch /c/IgnoredDirectory 

I find that the directory and files which ought to be ignored are now tracked when I do

git status

So how do I add files from a separate branch without having them be tracked by git? My thought is that git should ignore the files that I add because they are in the ignored directory of the .gitignore file. Where am I seeing it wrong here?

Code:

My .gitignore file

RecordDataBases/

and when I checkout the files from a seperate branch and run a git status I get:

    new file:   RecordDataBases/AstroFiles
    new file:   RecordDataBases/AstroFiles_goodversion
    new file:   RecordDataBases/AstroFiles_old_file
    new file:   RecordDataBases/README.rtf

Thanks


Solution

  • That's correct: git checkout commit-specifier -- paths copies the specified paths from the specified commit, into the index (also known as the staging area). Once they are in the index, they are tracked. It then copies the files from the index to the work-tree, using the same full paths resulting from any directory or glob expansion.

    Since any file that is in the index is tracked by definition, your task is either to avoid getting them into the index in the first place, or to remove them again afterward. The latter is easier:

    git rm -r --cached RecordDataBases/
    

    for instance (but note that it will remove all index entries for such files, not just index entries created by the git checkout step). The --cached option tells git rm to remove files only from the index, not from the work-tree.

    You can, instead of doing the above, extract files from a specified commit without first copying them into the index. The easiest way is to use git show, with the syntax git show commit-specifier:path > path, e.g., git show a_branch:RecordDataBases/AstroFiles > RecordDataBases/AstroFiles. Besides the need to repeat each path name, there are some caveats here:

    • this requires doing one file at a time (there is no easy way to get an entire directory-tree including sub-trees); and
    • by default, any end-of-line, ident, or smudge filter actions are omitted.

    But because this does not copy the expanded paths into the index first, there's no need to remove them from the index afterward.

    Edit: The new-in-Git-2.23 git restore can extract a file from a commit without writing it to the index. (This option was not available at the time of the original question.) That's easier than fixing things up afterward, but still kind of awkward for many files.

    To extract a specific commit (all of it) without disturbing anything else, consider using git worktree add with --detach to create a detached-HEAD extraction of the specified commit. The extra working tree can be used to get at all the files. Or, consider using git archive (see its documentation) to make a tar or zip file of a specific commit or some subset thereof. Note that git archive is potentially slightly different from a checkout (it may do archive substitutions as directed; again, see the documentation).