Reputation: 3771
I have cloned a public repository. In my local repository I have a branch structure like this where letters represent commits:
[public tag: v1] - A - B - C [myBranch1]
\
\- D [myBranch2]
The public repo has moved and released a new tag "v2". I want to rebase my branches onto the new version so I did:
git rebase --onto v2 v1 myBranch1
git rebase --onto v2 v1 myBranch2
This seems to work, except it creates distinct copies of commits A and B with the same contents but different hash codes:
[public tag: v2] - A' - B' - C' [myBranch1]
\
\A''- B''- D' [myBranch2]
I realize I could do something more complicated like:
git rebase --onto v2 v1 myBranch1
git rebase --onto myBranch1 B myBranch2
This should give me the result that I want but is quite a bit more complicated, particularly if/when I create more additional branches. It's far more error prone as I go fishing for commit hashcodes and have to keep track of where each branch diverged from which other branch.
1) Is there a better way to achieve this result? I guess you could suggest alternative workflows, but I'm pretty sure this is the kind of branch/commit structure I'd like to maintain.
2) Why do the hash codes of A' and A'' differ? Aren't they the product of applying the same diff/author/timestamp to the same baseline/contents? I realize the two are produced as two separate operations, but I would have expected those operations to be deterministic and therefore "collide"(correctly).
Upvotes: 0
Views: 216
Reputation: 490118
[Klas Mellbourn beat me to it; my answer just expands his a bit at this point.]
For what it's worth, I've seen a few attempts at "group or en masse rebase" methods that allow this sort of thing. They all need some way of choosing which branch to rebase first, and then to rebase other "dependent" branches on the now-rebased branch.
The answers to these are thus:
No, except that you can automate this. How well you can automate it is another question entirely. :-) The scripts I've seen were not as clever as they should be. (An automated system should grovel over all the branches, compute the appropriate merge bases for each, and do a minimal set of rebase/cherry-pick operations, recording enough "start state" to allow you to do --abort
or --continue
when hitting points that require manual resolution. This requires delaying the moves of the various branch labels too.)
A''
has a different commit timestamp, vs A'
(if it had the exact same commit metadata and the same tree it would indeed wind up being the same actual new commit). As Klas Mellbourn noted, once A''
is different, everything else will be as well.
Upvotes: 1
Reputation: 44447
1) You could automate the finding of B
by using merge-base
:
git merge-base myBranch1 myBranch2
will give you B
2) Rebase is not really moving the original commits, it is rather copying them, or actually replaying the difference that each commit caused. The rebased commits will always have new hashes.
The hash in the commit is a checksum of not only all the content of the entire tree of files that are version controlled, but also of the hash of the parent commit. So even if you would reproduce the same file tree (unlikely) you would still get a new hash since you have a different parent.
Upvotes: 3