Suppose I have a chain of local git branches, like this:
master branch1 branch2
| | |
o----o----o----A----B----C----D
I pull in an upstream change onto the master branch:
branch1 branch2
| |
A----B----C----D
/
o----o----o----o
|
master
Now I rebase branch1, giving me this:
branch2
|
A----B----C----D
/
o----o----o----o----A'---B'
| |
master branch1
Note that because of rebasing branch1, commits A and B have been rewritten as A' and B'.
Here's my problem: now I want to rebase branch2. The obvious syntax is git rebase branch1 branch2
, but that definitely does not work. What I want it to do is just reapply C and D on top of branch1, but instead it tries to reconcile A and A' and it considers them conflicting.
This does work:
git rebase --onto branch1 branch2^^ branch2
This assumes I know that branch2 has exactly 2 commits beyond the previous branch1 ref.
Since git rebase --onto
works, is there a 1-line git command that will rebase branch2 on top of a newly-rebased branch1, in a way that I don't have to know exactly how many commits were part of branch2? (I want to specify some magic ref instead of branch2^^ for the middle argument.)
Or is there some other approach I'm overlooking?
I would be most interested in a solution that scales well to extreme cases, not just two branches - suppose I've got something more like 5 local branches, all chained on one another, and I want to rebase all of them together.
One-line:
git rebase --onto branch1 branch1tmp branch2
That supposes to make a branch1tmp
on branch1
before rebasing branch1
.
git checkout branch1
git branch branch1tmp
git rebase master
git rebase --onto branch1 branch1tmp branch2
That being said, check what ORIG_HEAD
references.
From git rebase man page:
ORIG_HEAD
is set to point at the tip of the branch before the reset.
So check if this would work (and scale better):
git checkout branch1
git rebase master
git rebase --onto branch1 ORIG_HEAD branch2
git rebase --onto branch2 ORIG_HEAD branch3
...
git rebase master branch1
git rebase --onto HEAD ORIG_HEAD branch2
git rebase --onto HEAD ORIG_HEAD branch3
# ...
git rebase --onto HEAD ORIG_HEAD branchN
I have a git alias script to do this:
rebase-chain = "!f() { \
for i in ${@}; do \
git rebase --onto HEAD ORIG_HEAD $i; \
done; \
}; f"
which can make the workflow like:
git rebase master branch1 # start with a normal rebase
git rebase-chain branch2 branch3 branch4 ... branchN
bonus
assuming you have bash-completion
for git
:
__git_complete "git rebase-chain" _git_branch
What I would have loved is for git checkout branch2 ; git rebase -i master
to show me branch1
directly in the editor, and then when I save the editor, that the branch1 got updated accordingly. So I could move a commit from branch2 to branch1 directly in git rebase -i
and have that "stick". Maybe with a '--rebase-branches' or something.
So arrhhh, I share your pain.
What I do is somwhat of a hack that mimics this missing feature. I often find that during creating long-lived branches, I keep accumulating stuff that should've gone into master before "this" branch. Fixing coding standard breaches, discovering and fixing obvious errors, documentation updates for existing code, etc. This is what I'd use your branch1
for. And then the commits that actually are part of my new feature go in branch2
.
So what I do instead of creating a branch1
branch is to create a branch1
pseudo-branch "marker" - a tiny commit that I'll throw away later with git rebase
. I create it like:
touch marker.master
git add marker.branch1
git commit -m "*** BRANCH1 ***" marker.branch1
Now when I create commits, I mix commits that should go into master before this branch and "new" commits for this actual branch.
When it becomes time to clean up / rebase, I git rebase -i master
. Now my *** BRANCH1 ***
commit is obvious in the list of commits, and I can move commits destined for branch1
up above that "line".
Because I don't have an actual branch1
branch, git rebase master
does exactly what I want, it moves branch2
and my branch1
pseudo-branch marker as one unit.
When I'm done rebasing and am ready to push, I manually make a note of the commit ID for *** BRANCH1 ***
, say abcdef1
, and then:
git checkout -b branch1 abcdef1^
Then:
git checkout branch2
git rebase -i branch1
And remove the abcdef1
commit.
This way I can easily move commits between my branch1
and branch2
branches during git rebase -i
and only actually create a real git branch1
branch at the very end.
But oh, I'd really like for git rebase -i
to do this for me!
来源:https://stackoverflow.com/questions/20834648/how-do-i-rebase-a-chain-of-local-git-branches