I have a directory I no longer want to track. And I even want to remove some files within that directory, without afecting the git. Means I would like to remove the files and don't have git status to show those changes to be commited, so as to avoid a git pull from another machine would end up removing the files.
I already tried the option:
git rm --cached directory/
but that ended up deleting the files after I did a git pull from another machine.
Also tried:
git update-index --assume-unchanged directory/
But after deleting the directory I still get an output at git status stating the directory was deleted. I have even added that directory to the .gitignore file.
Is it really impossible to perform such, as stated in the answer under Stop tracking a file in git - without having it deleted either locally or on pull ?
The short answer is "it's not possible".
The problem is not restricted to (and in fact has nothing to do with) directories. It comes about because the files within that directory really are deleted. (It's worth noting here as well that Git does not track directories at all, it just creates them when they are needed to contain files.)
Let's pick an actual file name, for completeness. Call it conf/config.ini
. You clone some repository, and it has a file named conf/config.ini
in it, in commit badc0ff
, which is the tip commit of branch master
. Your Git checks out this commit, so your Git dutifully creates, in your work-tree, a directory conf
and a file named config.ini
in that directory.
Now you command your Git to go fetch (git fetch
) more revisions. There is one new revision after badc0ff
, namely 123face
. Your origin/master
now names commit 123face
.
Next, you command your Git to integrate the changes from badc0ff
to 123face
(using git merge origin/master
or similar). What are the changes? Well, along with anything else, someone removed conf/config.ini
. So your Git removes conf/config.ini
.
(Note: you may be executing these two Git commands by running git pull
. All git pull
does in this case is run git fetch
and then git merge
, so you really are using these two other commands. It's the merge step—going from badc0ff
to 123face
, obtaining and obeying the changes directed by the upstream—that removes the file; and it removes the file because the file really is removed. That's what it takes to get from one commit to the next.)
What's missing here—and has never been considered an important design feature—is a way to tell Git: "Although you may execute a transition from commit X to commit Y that removes path P, please don't actually remove path P from the work-tree—remove it from the index only."
Since this is missing, you need a workaround ... and it's really quite simple. Just check out the previous commit again and save the file—or, equivalently, extract the file from the previous commit without checking it out:
$ git show HEAD@{1}:conf/config.ini > conf/config.ini
(the HEAD@{1}
syntax here is from gitrevisions and means "the commit HEAD
pointed to just before we changed it by obeying the change from the upstream").
(If there are many such files, as in your case, it's probably more convenient to git checkout
the previous commit, i.e., tell your Git to "go back in time" one step, then rename the entire directory-full-of-files out of the way and go back forward in time to the present. Then you can rename the directory back.)
Suppose your conf/config.ini
, at the time you have your Git sitting on commit badc0ff
, is not quite the same as what's actually in commit badc0ff
. That is, you've modified your configuration.
If you now run git merge
(as git pull
does) to merge in the changes from 123face
, your Git tells you no: it cannot do this. The reason is that your work-tree is not "clean"; you have changes to a tracked, committed file that you have not committed yourself. Your Git would have to delete the file, which would lose your changes. So this situation is not supposed to happen in the first place. To make the merge go, you should commit your changes. Let's say that you do and you get commit fedbeef
as a result.
Once you do commit your changes, you will be able to merge. You will get a "merge conflict" on merging their "remove the file" with your "I changed the file", and you can resolve that merge conflict by removing the file. This gets you the right final state (the file is gone, but if you create it, it will be untracked). Then you simply extract your committed version from your commit:
git show fedbeef:conf/config.ini > conf/config.ini
and all is good.