开发者

how to remove old commits after filter-branch?

I used filter-branch to fix an incorrect email address in my repository but all the branches are now MIA (except master).

This is what git graph showed prior to filter-branch:

*   d93c7ee (HEAD, master) Merge branch 'f1'
|\  
| * 08e7463 (f1) adding b
|/  
* 7c7bd91 adding a

I issued this filter-branch command:

git filter-branch --env-filter 'export GIT_AUTHOR_EMAIL="fixed-email";
                                开发者_StackOverflowGIT_AUTHOR_NAME="fixed-author"'

And got this:

*   770262a (HEAD, master) Merge branch 'f1'
|\  
| * 0f58ab5 adding b
|/  
* fb012a9 adding a
*   d93c7ee (refs/original/refs/heads/master) Merge branch 'f1'
|\  
| * 08e7463 (f1) adding b
|/  
* 7c7bd91 adding a

A few things that bother me:

1) f1 branch wasn't moved to 0f58ab5.

2) All commits before fb012a9 seem irrelevant to me, can I get rid of them?

I saw in another question someone suggesting to:

rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --aggressive --prune=now

But it didn't quite help, this is what I got afterwards:

*   770262a (HEAD, master) Merge branch 'f1'
|\  
| * 0f58ab5 adding b
|/  
* fb012a9 adding a
* 08e7463 (f1) adding b
* 7c7bd91 adding a

EDIT: doing what VonC had suggested yielded this graph:

*   211632d (HEAD, master) Merge branch 'f1'
|\  
| * bda7577 (f1) adding b
|/  
* 70c7b34 adding a
*   3182b33 (refs/original/refs/heads/master) Merge branch 'f1'
|\  
| * 8b81c21 (refs/original/refs/heads/f1) adding b
|/  
* 4c07dc9 adding a

Which solved problem #1, now I only need to find a way to get rid of the old commits, how do I accomplish that?


Could you try again your git filter-branch with a '-- --all' at the end, like:

git filter-branch --env-filter 'export GIT_AUTHOR_EMAIL="fixed-email";
                                       GIT_AUTHOR_NAME="fixed-author"' -- --all

Note:

  • the -- that separates filter-branch options from revision options,
  • and the --all to rewrite all branches and tags.

That said, in your current situation, no amount of git gc ... prune ... will remove a commit which is still referenced by a branch marker, like f1 which still points to 08e7463.
So what you are seeing is normal, by design.


The OP reports that, once doing the git filter-branch ... -- --all, a rm -r .git/refs/original takes care of the old commits.

Again, this is not surprising: no tag or branch references them anymore, meaning this time, they are candidates for permanent removal from the Git repo.


I had the same problem, I'd forgotten to do -- --all on my filter-branch, as VonC suggests.

git filter-branch --env-filter 'export GIT_AUTHOR_EMAIL="fixed-email";
                                       GIT_AUTHOR_NAME="fixed-author"' -- --all

But I'd additionally pushed it to a remote github repo..

You may need to fix the GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL the same way.. and once the repo includes multiple authors, you'll need to filter on name. My unconfigured name was "unknown".

git filter-branch -f --env-filter '
if [ "$GIT_COMMITTER_NAME" = "unknown" ]
then
 export GIT_COMMITTER_EMAIL="fixed-email"
 export GIT_COMMITTER_NAME="fixed-author"
 export GIT_AUTHOR_EMAIL="fixed-email"
 export GIT_AUTHOR_NAME="fixed-author"
fi
' -- --all

But because I'd pushed it to the repo before the fix, and then pushed it after, I had a weird two-head structure in the history of my git code, in addition to the not-quite-orphaned refs branch:

--E--\                   --E--\
---A--B----\             ---A--B----\
    \----C--D--- master      \----C--D--- refs/original/refs/heads/master
--E-----/                --E-----/

A was the repo before I got to it, E was my locally committed changes I was trying to merge in and push to the repo.

Both B and C have A and E as parents and D is the new head. B is the first push of my work from E with the bad name/address, C is the result of filter-branch fixing all my changes in E to be the right name.

I used git reflog to show the sequence in my local clone, then git reset --hard A to put everything back at A, throwing away all changes and files in B/C/D. Which was fine, it was the same files, just with different authors.

Then I redid the merge from E, and the git filter-branch above, this time including the -- --all which changed my local repo to be

--E--\
---A--C-- master    (plus the refs branch is still there)

So now git shortlog -se shows only authors from A and E(corrected), and not the "unknown" author from B.

Then I used rm -r .git/refs/original to prune the orphaned branch. git branch now shows the right thing.

When I did a git push, it complained about losing commits and refused. Which is true, because commit B above is exactly what I wanted to get rid of.

git push -f did the trick. But be sure you have everything you want in the repo, because it is destructive. But in the end, the remote github repo matches my local structure instead of the mutant.

Oh, and for bonus fun, if you're doing this with msys Git for windows, you may have to update, I couldn't use filter-branch with 1.52, but it worked OK after updating to 1.74.


If you want to modify all the branches remember to use --all

git filter-branch $options -- --all

And to remove the old references:

rm -rf .git/refs/original
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜