Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
619 views
in Technique[技术] by (71.8m points)

git - Reordering of commits

I'm currently working on a branch and want some commits to merge into other branches:

    a-b-c-d-e-f-g (branchA)
   /
--o-x-x-x-x-x-x-x-x-x-x (master)
   
    x-x-x-x-x (branchB)

(Letters denote commits, and the "x" are irrelevant commits.)

However I noticed that it would be a good idea to pool some commits. I want to "concatenate" commit a, d, e and g into one patch and commit it to master. Commits b and f should go as one commit to branchB. Is there a good 'git'-ish way to achieve it?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The command you're looking for is git rebase, specifically the -i/--interactive option.

I'm going to assume you want to leave commit c on branch A, and that you really do mean you want to move the other commits to the other branches, rather than merging, since merges are straightforward. Let's start by manipulating branch A.

git rebase -i <SHA1 of commit a>^ branchA

The ^ means the previous commit, so this command says to rebase branch A using the commit before "a" as the base. Git will present you with a list of the commits in this range. Reorder them and tell git to squash the appropriate ones:

pick c ...
pick a ...
squash d ...
squash e ...
squash g ...
pick b
squash f

Now the history should look like this:

    c - [a+d+e+g] - [b+f] (branchA)
   /
--o-x-x-x-x-x-x-x-x-x-x (master)

Now, let's grab the newly-squashed commit b+f for branchB.

git checkout branchB
git cherry-pick branchA  # cherry-pick one commit, the tip of branchA

And the same for a+d+e+g for master:

git checkout master
git cherry-pick branchA^

Finally, update branchA so it points to c:

git branch -f branchA branchA^^

We should now have:

    c (branch A) - [a+d+e+g] - [b+f] (dangling commits)
   /
--o-x-x-x-x-x-x-x-x-x-x-[a+d+e+g] (master)
   
    x-x-x-x-x-[b+f] (branchB)

Note that if you had multiple commits you wanted to move between branches, you could use rebase again (non-interactively):

# create a temporary branch
git branch fromAtoB branchA
# move branchA back two commits
git branch -f branchA branchA~2
# rebase those two commits onto branchB
git rebase --onto branchB branchA fromAtoB
# merge (fast-forward) these into branchB
git checkout branchB
git merge fromAtoB
# clean up
git branch -d fromAtoB

Finally, a disclaimer: It's quite possible to reorder commits in such a way that some no longer apply cleanly. This could be because you chose a bad order (putting a patch before the commit introducing the feature it patched); in that case you'll want to abort the rebase (git rebase --abort). Otherwise, you'll have to intelligently fix the conflicts (just as you do with merge conflicts), add the fixes, then run git rebase --continue to move on. These instructions are also provided by the error message printed when the conflict occurs.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...