Create a gist now

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to delete a file from a Git repository, but not other users' working copies

How to delete a file from a Git repository, but not other users' working copies

Suppose you have, by mistake, added your IDE's project folder (you know, these .idea folders with all kinds of local paths and configuration data and settings in it) to the Git repository of your project. (We're talking about a whole folder here, but the same rules apply to individual files as well.)

Of course, you only realize that two days after the fact and have already pushed it, and your colleagues have already pulled it. They use the same IDE as you do, so whenever they change a setting or fix paths, they can either

  • commit that, causing nasty merge conflicts for you and others or
  • ignore the changes and carry around a modified file until the end of time without ever committing it.

Why .gitignore won't help

So the first thing you usually do is thinking "aw shit, I fucked up, better add the folder to .gitignore right now". And after you do that, surprise: Changes to files which are already committed will still cause that file to appear as modified in Git.

This is because .gitignore by design only works for files which are not tracked, i.e. not yet in the repository. If you add a file to the .gitignore after it has already been committed or if you force-add a file (git add -f) which might otherwise be ignored, this file will be tracked just like any other file in your project.

Deleting the files from the repository

So, the next thing you would try is to delete the folder from the repository. Then, Git won't track it anymore and the .gitignore will cause it not to be added again unintentionally.

However, how do you delete it just from the repository? Because you don't want to lose your IDE settings of course. The folder should still be available on your machine after, like, "un-committing" it.

(Of course you could just copy it somewhere else, tell Git to delete it, commit that and than put the copy back. But that would be cheating.)

Turns out there is git rm --cached which does exactly that: Stage "file X has been deleted" without actually deleting it on your disk. So you simply run git rm -r --cached .idea, commit that and be done, right?

Wrong.

How not to be hated by your colleagues

When others pull this "pseudo-deletion" you just committed, their local Git doesn't know that you kept a copy of the folder and didn't actually delete it. So what Git on their machines is going to do is to happily delete the folder in their working copies, causing their IDE to become somewhat unhappy. How can you keep Git from doing that?

Well, to be honest, you can't. The change you committed will cause Git to delete the folder on each and every colleague's machine.

Except … well, except if you delete it before Git does!

Pseudo-delete it before Git deletes it

If the other developers run git rm -r --cached .idea and commit that to their local trees before pulling your changes, Git will see that these two changes are equivalent (both "delete" the folder) and thus not try to delete it again.

So, that would be the first solution. Tell all your coworkers that at 3pm you're going to delete the .idea folder and that they should git rm -r --cached .idea as well and commit that before pulling or merging your changes. (Make sure the folder is in .gitignore first.) But if that's not feasible or if some didn't get the memo, there's a second possibility:

Just restore it

If the folder gets deleted on their machine, they can simply restore it again. After all, this is version control!

There is the git checkout <tree-ish> <file(s)> command that asks Git to place any file from any point in time in your current working copy. So if the last commit that your coworker pulled from you caused the .idea folder to be deleted, she could just say git checkout HEAD^ .idea and get it back from the version before. If there is more than one commit in between, first find the commit where the file has been deleted (git log --stat --diff-filter=D might be handy) and then use the commit before. So, for example, if the folder was deleted in commit c4f3d00d, use git checkout caf3d00d~1 .idea.

But wait! There is one more absolutely crucial step!

Because after you've used git checkout to restore the deleted folder, Git will add that folder to the index and stage it for commit! Yes, even when it's in .gitignore. (And no, there's no command line switch to keep it from doing that.) Which means, if you're not careful, you might end up committing the IDE folder again!

Luckily, this is pretty easy to do. Simply do a git reset HEAD .idea after the checkout and everything is fine. And since the folder is in .gitignore (you've added it there, didn't you?), Git won't add it back again.

@msouth

This comment has been minimized.

Show comment
Hide comment
@msouth

msouth Feb 18, 2015

I think it would be really helpful if, at the end, you summarize only the correct steps. You've got a lot of blind alleys in there that can be helpful for people to understand the whole picture, but I ended up not knowing what the correct final sequence was.

msouth commented Feb 18, 2015

I think it would be really helpful if, at the end, you summarize only the correct steps. You've got a lot of blind alleys in there that can be helpful for people to understand the whole picture, but I ended up not knowing what the correct final sequence was.

@jbibla

This comment has been minimized.

Show comment
Hide comment
@jbibla

jbibla Mar 19, 2015

^ agreed. but thank you kindly - it was still helpful for me.

jbibla commented Mar 19, 2015

^ agreed. but thank you kindly - it was still helpful for me.

@kako-nawao

This comment has been minimized.

Show comment
Hide comment
@kako-nawao

kako-nawao Feb 24, 2016

Thank you. It seems that not many people know that So you simply run git rm -r --cached .idea, commit that and be done, right? removes the files in the remote repos when they pull, since there's a lot of incorrect information going around concerning that.

Thank you. It seems that not many people know that So you simply run git rm -r --cached .idea, commit that and be done, right? removes the files in the remote repos when they pull, since there's a lot of incorrect information going around concerning that.

@vedmant

This comment has been minimized.

Show comment
Hide comment
@vedmant

vedmant Oct 18, 2016

Yeah, and this not only makes problem with other participants, but when deleted it with "git rm -r --cached .idea" on one of the branches and then switch to another branch, you switch back and your actual ".idea" gets wiped.

vedmant commented Oct 18, 2016

Yeah, and this not only makes problem with other participants, but when deleted it with "git rm -r --cached .idea" on one of the branches and then switch to another branch, you switch back and your actual ".idea" gets wiped.

@DaleKBurrell

This comment has been minimized.

Show comment
Hide comment
@DaleKBurrell

DaleKBurrell Feb 6, 2017

As @vedmant said, having just tried this, anytime you come back to checkout this branch again it seem to delete the file again. All very well if all development is carried out on a single branch, but if you use more than one branch you're stuffed. Unless I'm doing something wrong?

As @vedmant said, having just tried this, anytime you come back to checkout this branch again it seem to delete the file again. All very well if all development is carried out on a single branch, but if you use more than one branch you're stuffed. Unless I'm doing something wrong?

@pabitrapantha1

This comment has been minimized.

Show comment
Hide comment

.git ignore

@nanmu42

This comment has been minimized.

Show comment
Hide comment
@nanmu42

nanmu42 May 3, 2017

Thank you. This helps a lot!

nanmu42 commented May 3, 2017

Thank you. This helps a lot!

@treestonemedia

This comment has been minimized.

Show comment
Hide comment
@treestonemedia

treestonemedia Jun 13, 2017

is there now way to tell git ignore this directory from now on, remove it from your index and don't touch it on local copies of the repo?

is there now way to tell git ignore this directory from now on, remove it from your index and don't touch it on local copies of the repo?

@Novemburr

This comment has been minimized.

Show comment
Hide comment
@Novemburr

Novemburr Aug 28, 2017

+1 for "aw shit, I fucked up, better add the folder to .gitignore right now"

+1 for "aw shit, I fucked up, better add the folder to .gitignore right now"

@RiceCrisp

This comment has been minimized.

Show comment
Hide comment
@RiceCrisp

RiceCrisp Aug 30, 2017

Wow I've been looking for a solution to this forever. Wish it was simpler, but a million thanks regardless.

Wow I've been looking for a solution to this forever. Wish it was simpler, but a million thanks regardless.

@noffr

This comment has been minimized.

Show comment
Hide comment
@noffr

noffr Nov 10, 2017

Thank you, it was very helpful for me.

noffr commented Nov 10, 2017

Thank you, it was very helpful for me.

@rugano

This comment has been minimized.

Show comment
Hide comment
@rugano

rugano Dec 1, 2017

These are the logs that i am getting after running the commands: `git chackout HEAD^ app/views/contacts/new.html.erb

git reset HEAD app/views/contacts/new.html.erb `

Unstaged changes after reset:
M app/views/contacts/new.html.erb

I need to restore file new.html.erb to the previous state before i deleted it from git.Kindly help.I am new to git and gradually understanding it.

rugano commented Dec 1, 2017

These are the logs that i am getting after running the commands: `git chackout HEAD^ app/views/contacts/new.html.erb

git reset HEAD app/views/contacts/new.html.erb `

Unstaged changes after reset:
M app/views/contacts/new.html.erb

I need to restore file new.html.erb to the previous state before i deleted it from git.Kindly help.I am new to git and gradually understanding it.

@alisatl

This comment has been minimized.

Show comment
Hide comment
@alisatl

alisatl Jun 5, 2018

amazing post, just what I needed. Loved this remark Of course you could just copy it somewhere else, tell Git to delete it, commit that and than put the copy back. But that would be cheating. <3

alisatl commented Jun 5, 2018

amazing post, just what I needed. Loved this remark Of course you could just copy it somewhere else, tell Git to delete it, commit that and than put the copy back. But that would be cheating. <3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment