I imported a Bazaar repository into Git (using git bzr
), but the resulting repository contains a spurious commit parent link:
Notice that the commit tagged 1.02-6
is based off the 1.02-3
commit, but 1.02-1
is unnecessarily also marked as a parent. (Note: All the commits in this part of the repo are tagged; there are no commits between the ones shown.)
I have tried rebasing in several ways (on the master
branch: git rebase 1.02-3
, git rebase -i upstream-1.02
, git rebase --onto 1.02-1 1.02-3
, git rebase --root upstream-1.02 --onto=other_branch
), but in each case it fails with a merge conflict. These seem to be attempting more than is necessary; the history is correct except for an extra parent pointer being recorded in the commit tagged 1.02-6
.
How do you remove the link in order to linearize the history? Is there a better way than manually cherry-picking all the commits in sequence?
The easiest way to do this (in git >= 1.6.5) is to use:
git replace --edit <sha>
and remove/add/change the Parent: lines.
Once you are happy the change is right, you can rewrite the commits to make the change permanent:
git filter-branch --tag-name-filter cat -- --all
In some cases it'll be noticeably quicker to only rewrite the commits involved and not the full history (thanks to Michael for mentioning this in the comments); e.g. to rewrite only commits on the current branch:
git filter-branch --tag-name-filter cat -- <new parent sha>..head
If you're not sure, use --all
, otherwise you risk ending up with other branches/tags still referencing the temporary replacement object.
You can do it manually using the git commit-tree
internal command.
We want to edit the commit tagged 1.02-6
to remove the spurious parent pointer (to 56a2f3b5948ab54c9239c2b384a6ea9eb1f410c4
).
First, read the information from the existing commit object:
user@host:/path/repo.git$ git cat-file -p 1.02-6
tree c658aa1ebcf2bf2a607696c7868b875be72fb01f
parent 56a2f3b5948ab54c9239c2b384a6ea9eb1f410c4
parent 4e671bf1d2298729c9e5cfd8229051cfe2c40831
author James Damour (Suvarov454) <[email protected]> 1146319620 -0400
committer Bazaar Package Importer <[email protected]> 1146319620 -0400
The "main/" in the Section line of debian/control should be assumed.
Extract the commit message using git log --format=%B -n 1 1.02-6
.
Now create a new commit with the same content (excluding the spurious parent link, and the committer info):
git log --format=%B -n 1 1.02-6 | \
GIT_AUTHOR_NAME="James Damour (Suvarov454)" \
GIT_AUTHOR_EMAIL="[email protected]" \
GIT_AUTHOR_DATE="1146319620 -0400" \
git commit-tree c658aa1ebcf2bf2a607696c7868b875be72fb01f \
-p 4e671bf1d2298729c9e5cfd8229051cfe2c40831
This created a new commit, and printed its hash (cc32e66
...). Now turn it into a new branch:
git checkout -b fixed_commit cc32e66
and rebase master
onto the new branch:
git checkout master
git rebase fixed_commit
And we're done:
You probably want to delete the old branches and re-tag the appropriate commits.
Actually it might be easier to use git filter-branch --parent-filter
. I haven't tried that.
This will correct the parents without changing anything else (eg. committer dates):
git filter-branch --tag-name-filter cat --parent-filter 'test $GIT_COMMIT = [sha of 1.02-6] && echo "-p [sha of 1.02-3]" || cat' -- 1.02-1..master
You will have to replace the bracketed text with the appropriate commit IDs. If you have more downstream branches that need to be rewritten, change 1.02-1..master
to --all
and be prepared to wait.
Of course, don't use this or any other solution if others have branched from any commits after the ones you want to edit. They will hate you.
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