views:

985

answers:

3

Hi All,

I've been using git for about a year now and think it's fantastic, but I've just started on a second version of the project and started a new branch for it. I'm struggling a little with the best way to handle things going forward.

I have two branches called say master10 (for v1) and master20 (for v2). I've been making bug fixes in v1 on branch master10, and developing new stuff of master20. Whenever I make a bug fix I merge it into v2 by checking out master20 and doing "git merge master10". So far so good.

Now however I've made a change in v1 that I don't want in v2, but I want to continue merging other bug fixes. How to I tell git to skip that particular commit (or a range of commits), but that going forward I still want to merge other bug fixes.

I thought git rebase might be what I need but read the doco and my head nearly exploded.

I think what I want is something like a "git sync" command that tells git that two branches are now in-sync and in future only merge the commits from this sync-point on.

Any help appreciated.

Brad

A: 

Create a third branch for the changes you want in master10 but not in master20. Always consider master10 as your "master", the most stable branch of all. The branch all other branches want to keep in sync with at all times.

wilhelmtell
I guess that could work, but I've already got myself into this state, and a third branch would probably confuse me even more. :)
cantabilesoftware
+5  A: 

Commits include ancestry. You can't merge a commit without merging prior commits.

You can cherry-pick them, of course. That's a fine flow when you have a branch that's in maintenance mode.

Dustin
Thanks, cherry pick will do the job. Not as nice as what I was hoping for but it'll do.
cantabilesoftware
+11  A: 

If you want to merge most but not all of the commits on branch "maint" to "master", for instance, you can do this. It requires some work---- as mentioned above, the usual use case is to merge everything from a branch--- but sometimes it happens that you made a change to a release version that shouldn't be integrated back (maybe that code's been superceded in master already), so how do you represent that? Here goes...

So let's suppose maint has had 5 changes applied, and one of those (maint~3) is not to be merged back into master, although all the others should be. You do this in three stages: actually merge everything before that one, tell git to mark maint~3 as merged even when it isn't, and then merge the rest. The magic is:

bash <master>$ git merge maint~4
bash <master>$ git merge -s ours maint~3
bash <master>$ git merge maint

The first command merges everything before your troublesome maint commit onto master. The default merge log message will explain you're merging "branch 'maint' (early part)".

The second command merges the troublesome maint~3 commit, but the "-s ours" option tells git to use a special "merge strategy" which, in fact, works by simply keeping the tree you are merging into and ignoring the commit(s) you are merging completely. But it does still make a new merge commit with HEAD and maint~3 as the parents, so the revision graph now says that maint~3 is merged. So in fact you probably want to use the -m option to 'git merge' as well, to explain that that maint~3 commit is actually being ignored!

The final command simply merges the rest of maint (maint~2..maint) into master so that you're all synced up again.

araqnid
Good description. +1
VonC
I wonder however if that is not a little bit dangerous: what is mast~3 must not be ignored but simply postponed ? With your solution, any subsequent git merge maint would not merge back mast~3.
VonC
For postponed commit, I would created a "sub-branch", do exactly what you describe (including git merge -s ours maint~3), then merge everything from the sub-branch to master. I believe a future "git merge maint" would this time merge "mast~3"
VonC
I think that if you need to postpone merging that commit, you have little choice but to skip it (merge -s ours) and later apply it using the cherry-pick command. Once the commit is reachable from master, it can't be merged again- avoiding merging the same change twice is one of the main git goals.
araqnid
Regarding your sub-branch example: I suspect that once you have merged the sub-branch you are in exactly the same situation as you are after the second step of my post. Creating additional branches makes no difference to the commit relationships.
araqnid
"Creating additional branches makes no difference to the commit relationships": fair enough, I will have to test it out.
VonC
Excellent. That's exactly what I was looking for. All I need to do now is when I make a change in v1 that I want in v2 is git merge master10 and when it's a change I want to ignore is git merge -s ours master10. Perfect. "git merge -s ours" is the "sync" command I suggested in OP. Thanks!
cantabilesoftware