git - skipping specific commits when merging

Solution 1:

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.

Solution 2:

IMHO, the most logical thing to do, is to merge everything, and then use git revert (commit_you_dont_want) to remove it.

Example:

git merge master
git revert 12345678

If you have multiple "to-ignore" commits, or would like to edit revert message:

git merge master
git revert -n 123456
git revert -n abcdef
git commit -m "... Except commits 123456 and abcdef"

Then your history may look like:

| ... Except 123456 and abcdef
|\ Merge branch 'master' into 'your_branch'

If you have conflicts involving ONLY these "to-ignore" commits, you may use:

git merge master -X ours

So your version will persist over the other one. Even without error messages, you may still "revert" those unwanted commits, because they may have other changes that did not conflict, and you still don't want them.

If you have conflicts envolving NOT ONLY the "to-ignore" commits, you should resolve them manually, and you'll probably have to resolve them again during reverting.

Solution 3:

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.