tags:

views:

95

answers:

3

Hi,

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

   /--a--b--c--d--e--f--g----- branchA (letters are commits)
--o--------------------------- master
   \-------------------------- branchB

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?

+1  A: 

git rebase --interactive

Links:

codeape
Great. Thanks to both of you.
Peter
+1  A: 

git rebase is what you want. Check out the --interactive option.

drmegahertz
+6  A: 

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 - [a+d+e+g] - [b+f] (branchA)
   /
--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.

Jefromi