3

This question is about rewriting git history. Six months ago I decided to make changes over an existing subfolder of my repository, and now I've changed my mind and want to undo that and all the associated history. Note, I want changes outside that subfolder should be left as is.

So, specifically, I am trying to remove the history of all the changes made within one of the subfolders of the repo, from a certain date onwards.

The end result I am hoping for should look like no edits/adds/deletes were ever made in the subfolder after that date.

Looking at the the answer to Remove file from git repository (history), and also http://dalibornasevic.com/posts/2-permanently-remove-files-and-folders-from-a-git-repository, the closest I've got is this:

git filter-branch --index-filter 'git rm -r -f --cached --ignore-unmatch TheFolderToRemove' --prune-empty --all xxxxxx..HEAD 
git reset --hard
git remote rm origin
rm -r .git/refs/original/
git reflog expire --expire=now --all
git gc --aggressive
git prune

This removes all the files in the subfolder.

Can someone please show me how to modify this so that it just removes the changes applied within the folder? Many thanks

Community
  • 1
  • 1
Tom Thorne
  • 214
  • 2
  • 9

2 Answers2

4

Running the filter-branch with git rm --cached tells git to remove the directory and stage that removal! It only did what you told it to do.

If you still have the original objects: (i.e. you didn't actually run gc and prune)

You want to use git reset to unstage changes to that directory from the index, not remove the directory itself:

$ git filter-branch --index-filter 'git reset -q xxxxxx TheFolderToRemove' \
>     --prune-empty -- --all xxxxxx..HEAD

where xxxxxx is the commit with state you want the folder to be in.

If you do not still have the original objects: (i.e. you pruned the old tree from your repository)

Checkout the commit in which the folder is shown as removed (I believe it should be the commit after xxxxxx), undo the removal, amend the commit, and rebase the rest of history on top:

$ git checkout -b temp <commit_after_xxxxxx>
$ git checkout HEAD^ <removed_folder>
$ git commit --amend
[temp abcdef1] <message>

Then, if master is your only branch:

$ git rebase --preserve-merges temp master
vergenzt
  • 9,669
  • 4
  • 40
  • 47
  • Trying this, I find that the `git reset` fails if the path is not in the commit. I couldn't find an ignore unmatched option for reset, so I tried modifying this to the following: `git filter-branch --index-filter 'if [ -d TheFolderToRemove ]; then git reset TheFolderToRemove; fi' --prune-empty --all xxxxxx..HEAD`. This runs without error, but no changes are made. Any ideas on how to avoid the reset error? – Tom Thorne Jun 28 '12 at 09:25
  • Try `git reset xxxxxx TheFolderToRemove`, where `xxxxxx` is the sha1 of the commit that has that folder in the state you want it. I tried it with a folder that isn't in the current commit and it worked for me. (I edited the answer.) – vergenzt Jun 28 '12 at 11:40
  • What you had didn't make any changes because it was examining the working tree to see if TheFolderToRemove existed, not the index. If my last comment didn't work, try `if git ls-files --error-unmatch TheFolderToRemove &> /dev/null; then git reset ...`. – vergenzt Jun 28 '12 at 12:06
  • BTW I needed another `--` before the `--all` otherwise it's a syntax error. However, the specific commit form of reset isn't working for me: I get an error on the first rewrite, listing out the unstaged changes after the reset, and then `index filter failed`. – Tom Thorne Jun 28 '12 at 12:37
  • Later - adding `-q` fixed it, ie `git filter-branch --index-filter 'git reset -q xxxxxx TheFolderToRemove' --prune-empty -- --all xxxxxx..HEAD`. Please edit your answer so I can accept it - thx. – Tom Thorne Jun 28 '12 at 12:42
0

git filter-branch --force --index-filter 'git rm -rf --cached --ignore-unmatched somefolder/somefolder' --prune-empty --tag-name-filter cat -- --all

The -rf parameter removes all files in that folder or subfolder recursively.

Marco
  • 4,817
  • 5
  • 34
  • 75