0

I accidentally committed some data files to my local repo several commits back. I would like to remove these data files from my local without undoing progress in my working copy.

Joe
  • 3,217
  • 3
  • 21
  • 37

3 Answers3

2

There are several ways.

rebase

One option is to use git rebase. Suppose your history looks like

... x -- o -- A -- B -- C <--(master)

where the incorrect adds occurred in o (along with, possibly, other changes). You could then say

git rebase -i master~5 master

where master~5 is chosen because, in this example, it is an expression that refers to o's parent. (You would substitute a similar expression based on the real state of your repo, of course.)

This will bring up a text editor with a TODO list. Each line in the list will show one of your commits. Find the entry for commit o and change the first word on that line from pick to edit. Then save and exit the editor.

After a little processing, you'll get a command prompt. Remove the unwanted files from the index

git rm --cached file/that/shouldn't/be/committed

Then continue the rebase. The only reason there should be conflicts would be if a subsequent commit also edited one of those files, in which case you'll resolve the conflict by again making sure the file is removed from the index.

filter-branch

There are some problems with rebase if your "recent history" is complicated. In the above example, only one ref (master) can "see" o in its history, and the ref's history back to o is linear; so rebase is fine. But if there are additional branches, or merge commits, then you probably should try something else.

Then you might try git filter-branch with an --index-filter. You could write a shell script to do the git rm commands. (This would be similar to above, but you'd want to say

git rm --cached --ignore-unmatch file/that/shouldn't/be/committed

Suppose you write this script and place it at ../index-filter.sh; and you have a history like

                F -- G -- H
               /            \
... x -- o -- A -- B -- C -- M <--(master)
               \
                D -- E <--(feature)

Then you could say something like

git filter-branch --index-filter ../index-filter.sh -- --all ^master~5

where in this case master~5 is chosen because it refers to x (o's parent). Note we put a ^ before master~5; this limits the rewrite to exclude x and its history, so you only rewrite back to o.

That's potentially important for a few reasons.

First, if you know you haven't pushed o, then you aren't rewriting anything that's been shared. (And anyhow, there's nothing you want to change, even if the same path should happen to appear earlier on, right?)

Also, by limiting the number of commits rewritten, you can help keep filter-branch from taking too long (it is a potentially long-running process).


There are other options, like the BFG Repo Cleaner; but those are likely overkill for your use case, and one of the above is what I would recommend trying first.

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
1

You can amend your commit if they were added to your last commit (git commit --amend).

If it was your last commit, create a branch from the previous commit, before you added your files, recreate the commit without the new files, and then rebase the other commits on top of your new commit.

Then delete the old branch and rename the new one.

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62
-5

Push the commit, take pull, delete the unwanted files, commit, push. -_-