tags:

views:

70

answers:

3

If I have a public Git repository that contains 3 branches like the following:

  (release-to-customerA)
      |
      U               (master)
     /                    |
A---B---C---D---E ... S---T 
        |
    (release-to-customerB)

where commit 'B' was the original release version and commit 'U' resolved some bugs in 'B'. I want to apply the commit 'U' to both master and release-to-customerB branch, and when the next time I deliver a new release to the customers based on the commit 'D', 'E', ... 'T', I want the commit 'U' included. What is the cleanest way to do it?

I know that git rebase or git cherry-pick may do the trick in my local repository, but will I screw up the history when I submit the rebased work to the public repository?

Thanks for the answers.

A: 

You don't need to rebase for this particular operation, cherry-picking is fine:

git checkout checkout release-to-customerB
git cherry-pick U
git checkout master
git cherry-pick U

Cherry-picking only creates new commits and does not rewrite history, so it's always safe even if you later push to another repository.

Greg Hewgill
+2  A: 

Though cherry-picking will work, I'm not sure why you'd want to. It creates duplicate commits, which can cause problems if you ever want to merge. Indeed, this appears to be a case where you want to merge!

  (bugfixB, releaseA)
        --------------------- Y (master)
       /                     /
      U---X (releaseB)      /
     /   /                 /
A---B---C---D---E ... S---T

Note that I added a branch name bugfixB - this is a very general idea. The commit U should be made on a branch whose purpose is to fix B (it could be several commits). That branch should then be merged into all branches which need the bugfix - in this case, releaseA, releaseB, and master.

 git checkout -b bugfixB <SHA1 of B>
 # fix things, add changes
 git commit

 # for each branch...
 git checkout releaseA
 git merge bugfixB
 git checkout releaseB
 git merge bugfixB
 git checkout master
 git merge bugfixB
Jefromi
Thanks for the answer. What happens if I try to merge 'X' and 'Y'? Is git smart enough to figure out that it can be a fast-forward to Y?
YYC
@YYC: Not sure if you mean X into Y or Y into X, but they're essentially the same. In neither case is this a fast-forward, though. It is quite possible for U to conflict with a commit somewhere from D to T, so it's quite impossible to fast-forward. Of course, it should hopefully be a pretty trivial recursive merge, since there's only one bugfix commit worth of divergence. (And of course, if there are conflicts in that merge, there would be conflicts if you rebased or cherry-picked. It's ultimately the same operation as far as the under-the-hood merge is concerned.)
Jefromi
A: 

You shouldn't rebase in this situation, since clearly other people have seen commits C through T.

As Greg said, you can use git-cherry-pick to get just U; but, this will create a new commit with the same diff but a different ID. If you want to get all commits in release-to-customerA into release-to-customerB and master, you can use git-merge like so:

git checkout release-to-customerB
git merge release-to-customerA

git checkout master
git merge release-to-customerA
Michael Melanson