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";
GIT_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:
--
that separates filter-branch options from revision options, --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 love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With