Git merge conflict binary options
Merging in Git is typically fairly easy. Since Git makes it easy to merge another branch multiple times, it means that you can have a very long lived branch but you can keep it up to date as you go, solving small conflicts often, rather than be surprised by one enormous conflict at the end of the series.
However, sometimes tricky conflicts do occur. Unlike some other version control systems, Git does not try to be overly clever about merge conflict resolution. Therefore, if you wait too long to merge two branches that diverge quickly, you can run into some issues. First of all, if at all possible, try to make sure your working directory is clean before doing a merge that may have conflicts.
If you have work in progress, either commit it git merge conflict binary options a temporary branch or stash it. This makes it so that you can undo anything you try here. If you have unsaved changes in your working directory when you try a merge, some of these tips may help you lose that work.
We have a super simple Ruby file that prints hello world. In our repository, we create a new branch named whitespace and proceed to change all the Unix line endings to DOS line endings, essentially changing every line of the file, but just with whitespace.
Now we switch back to our master branch and add some documentation for the function. We now have a few options. The git merge --abort option tries to revert back to your state before you ran the merge. The only cases where it may not be able to do this perfectly would be if you had unstashed, uncommitted changes in your working directory when you ran it, otherwise it should work fine.
If for some reason you just want to start over, you can also run git reset --hard HEADand your repository will be back to the last committed state. In this specific case, the conflicts are whitespace related. The default merge strategy can take arguments though, and a few of them are about properly ignoring whitespace changes. If you see that you have a lot of whitespace issues in a merge, you can simply abort it and do it again, this time with -Xignore-all-space or -Xignore-space-change.
The first option ignores whitespace completely when comparing lines, the second treats sequences of one or more whitespace characters as equivalent.
Since in this git merge conflict binary options, the actual file changes were not conflicting, once we ignore the whitespace changes, everything merges just fine. This is a lifesaver if you have someone on your team who likes to occasionally reformat everything from spaces to tabs or vice-versa. So how would we do that? First, we get into the merge conflict state.
Then we want to fix up either their side or our side and re-try the merge again for just this single file. Getting the three file versions is actually pretty easy. You can extract a copy of each of these versions of the conflicted file with the git show command and a special syntax. If git merge conflict binary options want to get a little more hard core, you can also use the ls-files -u plumbing command to get the actual SHA-1s of the Git blobs for each of these files.
Now that we have the content of all three stages in our working directory, we can manually fix up theirs to fix the whitespace issue and re-merge the file with the little-known git merge-file command which does just that.
At this point we have nicely merged the file. In fact, this actually works better than the ignore-space-change option git merge conflict binary options this actually fixes the whitespace changes before merge instead of git merge conflict binary options ignoring them. In the ignore-space-change merge, we actually ended up with a few lines with DOS line endings, making things mixed.
To compare your result to what you had in your branch before the merge, in other words, to see what the merge introduced, you can run git diff --ours. If we want to see how the result of the merge differed from what was on their side, you can run git diff --theirs.
At this point we can use the git clean command to clear out the extra files we created to do the manual merge but no longer need. For this example, we have two longer lived branches that each have a few commits in them but create a legitimate content conflict when merged.
We now have three unique commits that live only on the master branch and three others that live on the mundo branch. If we try to merge the mundo branch in, we get a conflict. We would like to see what the merge conflict is. Both sides of the merge added content to this file, git merge conflict binary options some of the commits modified the file in the same place that caused this conflict.
You need more context. This will re-checkout the file again and replace the merge conflict markers. This can be useful if you want to reset the markers and try to resolve them again.
You can pass --conflict either diff3 or merge which is the default. If you like this format, you can set it as the default for future merge conflicts by setting the merge. The git checkout command can also take --ours and --theirs options, which can be a really fast way of just choosing either one side or the other without merging things at all.
This can be particularly useful for conflicts of binary files where you can simply choose one side, or where you only want to merge certain files in from another branch - you can do the merge and then checkout certain files from one side or the other before committing.
Another useful tool when resolving merge conflicts is git log. This can help you get context on what may have contributed to the conflicts. Reviewing a little bit of history to remember why two lines of development were touching the same area of code can be really git merge conflict binary options sometimes.
We can further simplify this though to give us much more specific context. If you run that with the -p option instead, you get just the diffs to the file that ended up in conflict. This can be really helpful in quickly giving you the context you need to help understand why something conflicts and how to more intelligently resolve it.
Since Git stages any merge results that are successful, when you run git diff while in a conflicted merge state, you only get what is currently still in conflict. This can be helpful to git merge conflict binary options what you still have to resolve. When you run git diff directly after a merge conflict, it will give you information in a rather unique diff output format.
This can be useful to review before committing the resolution. You can also get this from the git log for any merge to see how something was resolved after the fact. Git will output this format if you run git show on a merge commit, or if you add a --cc option to a git log -p which by default only shows patches for non-merge commits. Merge commits are no different. If the unwanted merge commit only exists on your local repository, the easiest and best solution is to move the branches so that they point where you want them to.
Move the branch HEAD points to. In this case, we want to move master to where it was before the merge commit C6. When git merge conflict binary options invoke a merge into HEAD git merge topicthe new commit has two parents: In this case, we want to undo all the changes introduced by merging in parent 2 C4while git merge conflict binary options all the content from parent 1 C6. Git will get confused if you try to merge topic into master again:.
The best way around this is to un-revert the original merge, since now you want to bring in the changes that were reverted out, then create a new merge commit:. There are other ways to merge branches together however. By default, when Git sees a conflict between two branches being merged, it will add merge conflict markers into your code and mark the file as conflicted and let you resolve it.
If you would prefer for Git to simply choose a specific side and ignore the other side instead of letting you manually resolve git merge conflict binary options conflict, you can pass the merge command either a -Xours or -Xtheirs. If Git sees this, it will not add conflict markers. Any differences that are mergeable, it will merge. Any differences that conflict, it will simply choose the side you specify in whole, including binary files. However, all the other non-conflicting changes on that branch are merged successfully in.
Git merge conflict binary options option can also be passed to the git merge-file command we saw earlier by running something like git merge-file --ours for individual file merges.
This will basically do a fake merge. It will simply record as the result of the merge the exact code git merge conflict binary options your current branch.
You can see that there is no difference between the branch we were on and the result of the merge. This can often be useful to basically trick Git into thinking that a branch is already merged when doing a merge later on.
For example, say you branched off a release branch and have done some work on it that you will want to merge back into your master branch at some point.
In the meantime some bugfix on master needs to be backported into your release branch. You can merge the bugfix branch into the release branch and also merge -s ours the same branch into your master branch even though the fix is already there so when you later merge the release branch again, there are no conflicts from the bugfix. The idea of the subtree merge is that you have two projects, and one of the projects maps to a subdirectory of the other one.
When you specify a subtree merge, Git is often smart enough to figure out that one is a subtree of the other and merge appropriately. If you check out one and then the other, you can see that they have different project roots:. This is sort of a strange concept. Not all the branches in your repository actually have to be branches of the same project. In this case, we want to pull the Rack project into our master project as a subdirectory. We can do that in Git with git read-tree.
When we commit, it looks like we have all the Rack files under that subdirectory — as though we copied them in from a tarball. What gets interesting is that we can fairly easily merge changes from one of the branches to the git merge conflict binary options. So, if the Rack project updates, we can pull in upstream changes by switching to that branch and pulling:.
Then, we can merge those changes back into our master branch. The recursive strategy is the default here, but we include it for clarity.
All the changes from the Rack project are merged in and ready to be committed locally. This gives us a way to have a workflow git merge conflict binary options similar to the submodule workflow without using submodules which we will cover in Submodules. We can keep branches with other related projects in our repository and subtree merge them into our project occasionally.
It is nice in some ways, for example all the code is committed git merge conflict binary options a single place. Instead, you must run git diff-tree with the branch you want to compare to:.