Reputation: 1451
Say I have branch 1
with commit A
.
1: A
From 1, I create another branch, 2
.
2: A
On 2
, I add a commit.
2: A->B
Then on 1
, I make some changes and git commit --amend
, overwriting A
.
1: C
On 2
, I want these new changes on 1
and want to just apply my changes from B
onto C
. However, from what I understand, git will see that branch 2
has new commits A
and B
, and try to apply both of these commits on top of C
. So when I'm done rebasing, 2
will look like
2: C->A->B
When what I really want is C->B
.
What would be the proper way to handle this situation? The way I've been dealing with this so far is by creating a new branch off of 1
, and then cherry-picking over commit B
from 2
. But that seems a bit hacky, and not so trivial to do when 2
has more than just one new commit.
Upvotes: 1
Views: 52
Reputation: 164769
Let's lay this out more conventionally and see what's going on.
If A is the first commit things get complicated, so I'll add an ancestor Z.
Say I have branch 1 with commit A.
Z - A [1]
From 1, I create another branch, 2.
Z - A [1][2]
On 2, I add a commit.
Z - A [1]
\
B [2]
Then on 1, I make some changes and git commit --amend, overwriting A.
Here's where things go wonky.
C [1]
/
Z - A
\
B [2]
Git never "overwrites" a commit. It can't. The commit ID is a checksum of the commit contents and all its ancestry. What commit --amend
(and also rebase
) does is creates new commits and pretends it was that way all along.
But the old commit still sticks around. And if anything has it as an ancestor, like branch 2 here, it will be visible.
On 2, I want these new changes on 1 and want to just apply my changes from B onto C. However, from what I understand, git will see that branch 2 has new commits A and B, and try to apply both of these commits on top of C. So when I'm done rebasing, 2 will look like 2: C->A->B when what I really want is C->B.
The problem here is because of the commit --amend
branch 1 and branch 2 no longer have A as a common ancestor. It's now Z. If you try to rebase 2 onto 1 it will put both A and B on top of C.
A1 - B1 [2]
/
C [1]
/
Z - A
\
B
While that might work, it also might result in a messy conflict. You'll have to use a more precise rebase command to let Git know what you really want. Since C is really a reworked A, what you really want is everything on 2 after A.
git rebase --onto 1 A..2
And the result will be what you want.
B1 [2]
/
C [1]
/
Z - A
\
B
(A and B won't be visible, and they will be eventually garbage collected.)
If you think this is complex and fraught with peril, it is!
This is why it's best to not rebase or amend your "stable" branch, usually master
. Instead, just use a normal commit, or a feature branch for a larger change. Then the normal procedure to update branches applies.
Upvotes: 2