Although much of the information in this question and answer is available on StackOverflow, it is spread out over lots of pages and among other answers which are either wrong or misleading. It took me a while to piece together everything I wanted to know.
There are a lot of different programs that can be used as your git difftool and mergetool, and there is certainly no consensus as to which is the best (opinions, requirements, and OSes will clearly differ).
Meld is a popular free, open-source, and cross-platform (UNIX/Linux, OSX, Windows) choice as shown in the StackOverflow question, What's the best visual merge tool for Git?, in which the answer proposing Meld has more than 3 times the votes as any other tool.
The following 2 questions will be answered in my answer below:
Note: It is not necessary to use the same program as both your difftool and mergetool, different programs can be set for both.
git difftool displays the diff using a GUI diff program (i.e. Meld) instead of displaying the diff output in your terminal.
Although you can set the GUI program on the command line using -t <tool> / --tool=<tool>
it makes more sense to configure it in your .gitconfig
file. [Note: See the sections about escaping quotes and Windows paths at the bottom.]
# Add the following to your .gitconfig file.
[diff]
tool = meld
[difftool]
prompt = false
[difftool "meld"]
cmd = meld "$LOCAL" "$REMOTE"
[Note: These settings will not alter the behaviour of git diff
which will continue to function as usual.]
You use git difftool
in exactly the same way as you use git diff
. e.g.
git difftool <COMMIT_HASH> file_name
git difftool <BRANCH_NAME> file_name
git difftool <COMMIT_HASH_1> <COMMIT_HASH_2> file_name
If properly configured a Meld window will open displaying the diff using a GUI interface.
The order of the Meld GUI window panes can be controlled by the order of $LOCAL
and $REMOTE
in cmd
, that is to say which file is shown in the left pane and which in the right pane. If you want them the other way around simply swap them around like this:
cmd = meld "$REMOTE" "$LOCAL"
Finally the prompt = false
line simply stops git from prompting you as to whether you want to launch Meld or not, by default git will issue a prompt.
git mergetool allows you to use a GUI merge program (i.e. Meld) to resolve the merge conflicts that have occurred during a merge.
Like difftool you can set the GUI program on the command line using -t <tool> / --tool=<tool>
but, as before, it makes more sense to configure it in your .gitconfig
file. [Note: See the sections about escaping quotes and Windows paths at the bottom.]
# Add the following to your .gitconfig file.
[merge]
tool = meld
[mergetool "meld"]
# Choose one of these 2 lines (not both!) explained below.
cmd = meld "$LOCAL" "$MERGED" "$REMOTE" --output "$MERGED"
cmd = meld "$LOCAL" "$BASE" "$REMOTE" --output "$MERGED"
You do NOT use git mergetool
to perform an actual merge. Before using git mergetool
you perform a merge in the usual way with git. e.g.
git checkout master
git merge branch_name
If there is a merge conflict git will display something like this:
$ git merge branch_name
Auto-merging file_name
CONFLICT (content): Merge conflict in file_name
Automatic merge failed; fix conflicts and then commit the result.
At this point file_name
will contain the partially merged file with the merge conflict information (that's the file with all the >>>>>>>
and <<<<<<<
entries in it).
Mergetool can now be used to resolve the merge conflicts. You start it very easily with:
git mergetool
If properly configured a Meld window will open displaying 3 files. Each file will be contained in a separate pane of its GUI interface.
In the example .gitconfig
entry above, 2 lines are suggested as the [mergetool "meld"]
cmd
line. In fact there are all kinds of ways for advanced users to configure the cmd
line, but that is beyond the scope of this answer.
This answer has 2 alternative cmd
lines which, between them, will cater for most users, and will be a good starting point for advanced users who wish to take the tool to the next level of complexity.
Firstly here is what the parameters mean:
$LOCAL
is the file in the current branch (e.g. master).$REMOTE
is the file in the branch being merged (e.g. branch_name).$MERGED
is the partially merged file with the merge conflict information in it.$BASE
is the shared commit ancestor of $LOCAL
and $REMOTE
, this is to say the file as it was when the branch containing $REMOTE
was originally created.I suggest you use either:
[mergetool "meld"]
cmd = meld "$LOCAL" "$MERGED" "$REMOTE" --output "$MERGED"
or:
[mergetool "meld"]
cmd = meld "$LOCAL" "$BASE" "$REMOTE" --output "$MERGED"
# See 'Note On Output File' which explains --output "$MERGED".
The choice is whether to use $MERGED
or $BASE
in between $LOCAL
and $REMOTE
.
Either way Meld will display 3 panes with $LOCAL
and $REMOTE
in the left and right panes and either $MERGED
or $BASE
in the middle pane.
In BOTH cases the middle pane is the file that you should edit to resolve the merge conflicts. The difference is just in which starting edit position you'd prefer; $MERGED
for the file which contains the partially merged file with the merge conflict information or $BASE
for the shared commit ancestor of $LOCAL
and $REMOTE
. [Since both cmd
lines can be useful I keep them both in my .gitconfig
file. Most of the time I use the $MERGED
line and the $BASE
line is commented out, but the commenting out can be swapped over if I want to use the $BASE
line instead.]
Note On Output File: Do not worry that --output "$MERGED"
is used in cmd
regardless of whether $MERGED
or $BASE
was used earlier in the cmd
line. The --output
option simply tells Meld what filename git wants the conflict resolution file to be saved in. Meld will save your conflict edits in that file regardless of whether you use $MERGED
or $BASE
as your starting edit point.
After editing the middle pane to resolve the merge conflicts, just save the file and close the Meld window. Git will do the update automatically and the file in the current branch (e.g. master) will now contain whatever you ended up with in the middle pane.
git will have made a backup of the partially merged file with the merge conflict information in it by appending .orig
to the original filename. e.g. file_name.orig
. After checking that you are happy with the merge and running any tests you may wish to do, the .orig
file can be deleted.
At this point you can now do a commit to commit the changes.
If, while you are editing the merge conflicts in Meld, you wish to abandon the use of Meld, then quit Meld without saving the merge resolution file in the middle pane. git will respond with the message file_name seems unchanged
and then ask Was the merge successful? [y/n]
, if you answer n
then the merge conflict resolution will be aborted and the file will remain unchanged. Note that if you have saved the file in Meld at any point then you will not receive the warning and prompt from git. [Of course you can just delete the file and replace it with the backup .orig
file that git made for you.]
If you have more than 1 file with merge conflicts then git will open a new Meld window for each, one after another until they are all done. They won't all be opened at the same time, but when you finish editing the conflicts in one, and close Meld, git will then open the next one, and so on until all the merge conflicts have been resolved.
It would be sensible to create a dummy project to test the use of git mergetool
before using it on a live project. Be sure to use a filename containing a space in your test, in case your OS requires you to escape the quotes in the cmd
line, see below.
Some operating systems may need to have the quotes in cmd
escaped. Less experienced users should remember that config command lines should be tested with filenames that include spaces, and if the cmd
lines don't work with the filenames that include spaces then try escaping the quotes. e.g.
cmd = meld \"$LOCAL\" \"$REMOTE\"
In some cases more complex quote escaping may be needed. The 1st of the Windows path links below contains an example of triple-escaping each quote. It's a bore but sometimes necessary. e.g.
cmd = meld \\\"$LOCAL\\\" \\\"$REMOTE\\\"
Windows users will probably need extra configuration added to the Meld cmd
lines. They may need to use the full path to meldc
, which is designed to be called on Windows from the command line, or they may need or want to use a wrapper. They should read the StackOverflow pages linked below which are about setting the correct Meld cmd
line for Windows. Since I am a Linux user I am unable to test the various Windows cmd
lines and have no further information on the subject other than to recommend using my examples with the addition of a full path to Meld or meldc
, or adding the Meld program folder to your path
.
Meld has a number of preferences that can be configured in the GUI.
In the preferences Text Filters
tab there are several useful filters to ignore things like comments when performing a diff. Although there are filters to ignore All whitespace
and Leading whitespace
, there is no ignore Trailing whitespace
filter (this has been suggested as an addition in the Meld mailing list but is not available in my version).
Ignoring trailing whitespace is often very useful, especially when collaborating, and can be manually added easily with a simple regular expression in the Meld preferences Text Filters
tab.
# Use either of these regexes depending on how comprehensive you want it to be.
[ \t]*$
[ \t\r\f\v]*$
I hope this helps everyone.