Is it possible to exclude specific commits when doing a git merge?
Let’s say that I want to merge from a release branch to the master branch and there are some commits in the release branch that I don’t want to include in the master branch. Is there a way to do the merge so that one or more of those commits will not be merged?
My strategy so far is to do the following (in master):
git merge --no-commit release-branch # Resolve conflicts and apply reverse patch of the commits that I don't want included git commit # Edit commit message so that it lists the commits that have been reverse-patched
Is there a better way to do this?
7 Solutions collect form web for “Is it possible to exclude specific commits when doing a git merge?”
Create a new branch, rebase the branch interactively and drop commits you don’t want, and then merge that.
You can’t take changes out of the middle of a branch without rehashing, but the right thing will happen when it sees the same changes in a later merge (e.g. from cherry-picking and what-not).
I’ve found a solution that works for me in the Pro Git book.
Let’s say you want to exclude the file
On branch A:
Create a file named
.gitattributesin the same dir, with this line:
config.php merge=ours. This tells git what strategy to use when merging the file. In this case it always keep your version, ie. the version on the branch you are merging into.
.gitattributesfile and commit
On branch B: repeat steps 1-2
Try merging now. Your file should be left untouched.
If you have a support branch where you fix bugs and build new versions. On master you have the next version where you also build new versions frequently.
Every time you build a new version you change the version in some file, commit that new file, create a tag and push. Now merges from support to master will always have conflicts in the file containing the version info.
If the file containing the version information only contains the version information, you can go with the answer of fcurella. But if it does indeed may also contain mergeable information (pom.xml, gradle.properties, MANIFEST.MF, …), you must perform some extra action.
Lets use the following example
C---D*---E---F* support / A---B---G---H*---I master
where commits with stars contain only changes due to version changes that should be ignored during merge.
To merge support into master without merge-conflicts due to the version builds, you can do either of the following:
Multiple merge commits
git checkout master git merge C git merge D -s ours git merge E git merge F -s ours
-s ours argument we are telling git to only record a merge without altering the workspace. This is comparable to the
--record-only option of svn.
The above will result in the following layout
-------------C---D*---E---F* support / \ \ \ \ A---B---G---H*---I---J---K----L---M master
One merge commit using cherry-pick
git checkout master git merge support -s ours --no-commit git cherry-pick C E --no-commit git commit -m 'merged support into master'
first we are starting a merge but only record that we are merging, without altering the workspace and without doing the merge commit. Then we are cherry-picking the commits to merge, again without commit. Finally we are committing the merge.
The above will result in the following layout
C---D*---E---F* support / \ A---B---G---H*---I---J master
One could even automate the cherry-picking.
git checkout master git merge support -s ours --no-commit for id in `git log support --reverse --not HEAD --format="%H [%an] %s" | grep -v "bump version" | sed "s/\(\w*\)\s.*/\1/g"` do git cherry-pick --no-commit $id done git commit -m 'merged support into master'
The reason why this can’t be done directly is that every commit contains links to the parent commits (typically just one but several for merges). That way if you have one commit (by its SHA1 sum) the whole history is also fixed as the parents also contain links to their parents and so on. So the only way to leave out patches in the history is to write a new one. git rebase -i on a newly created branch is probably the easiest way of achieving that.
It’s also possible to modify .git/info/attributes file and keep it inside .git folder instead of adding .gitattribute files all over that will require adding them to source control eventually.
The main question is: how do you want to represent the commits you want to skip?
- sneakily hide them (not my favorite)
- explicitly skip them
- explicitly undo them
Unfortunately no. 2 is impossible to express in the history graph.
No. 1 is possible, but I would never do that: a merge commit can contain changes. – Normally a merge commit points to the result of the merge of two more more branches: all things developed in those branches should be in the code after the merge (i.e. in the code pointed to by the merge commit). And nothing else should be in this commit.
But surprise, surprise, you can change the entire code base and represent it as a merge. The effect of a merge is two-fold: it merges the history tree and it should merge two code bases. The former it does for sure (otherwise no-one calls it a merge), for the latter it might fail, e.g. when a merge conflict arose and it was resolved wrongly (then the code bases were not merged properly).
Some of the other answers suggest this hiding. I recommend the explicit way: merge plus revert commits.
If you only want to exclude some commits that are at the end, you can just commit to a specific commit number:
git checkout partlyMergedFrom git whatchanged --> find the commit hash up to where you want to merge git checkout partlyMergedInto git merge e40a0e384f58409fe3c864c655a8d252b6422bfc git whatchanged --> check that you really got all the changes you want to have