Skip to content

Instantly share code, notes, and snippets.

@bkeating
Created March 11, 2010 21:36
Show Gist options
  • Select an option

  • Save bkeating/329690 to your computer and use it in GitHub Desktop.

Select an option

Save bkeating/329690 to your computer and use it in GitHub Desktop.
HOWTO: Using FileMerge (opendiff) with Git on OSX

HOWTO: Using FileMerge (opendiff) with Git on OSX

FileMerge (opendiff) can really come in handy when you need to visually compare merging conflicts. Other times it's just a nice visual way to review your days work.

The following method works by creating a simple bash script (git-diff-cmd.sh) that sets us up with the proper command line arguments for Git to pass off files to FileMerge.

  1. Open the bash script for editing:

     vi ~/bin/git-diff-cmd.sh
    
  2. Paste the following code:

     #!/bin/sh 
     /usr/bin/opendiff "$2" "$5" -merge "$1"
    
  3. Make the bash script executable:

     chmod +x ~/bin/git-diff-cmd.sh
    
  4. Tell Git (globally) to run our bash script when 'git diff' is issued:

     git config --global diff.external ~/bin/git-diff-cmd.sh
    

Now head over to your Git-aware project directory and issue a git diff /path/to/modified/file.py and FileMerge will pop up showing you the differences against it and HEAD.

You can also do things like git diff --cached to review all the changes against HEAD.

@bkeating

bkeating commented Oct 6, 2010

Copy link
Copy Markdown
Author

Thanks, yllan. Fixed.

@yllan

yllan commented Oct 7, 2010

Copy link
Copy Markdown

I think the leading "" of "#!/bin/sh" also need to be deleted. The correct version should be

!/bin/sh

/usr/bin/opendiff "$2" "$5" -merge "$1"

@bkeating

bkeating commented Oct 8, 2010

Copy link
Copy Markdown
Author

Thanks. Fixed it. Not sure why that was.

@sebm

sebm commented Feb 1, 2011

Copy link
Copy Markdown

This is awesome, thanks very much!

@j-kan

j-kan commented Mar 17, 2011

Copy link
Copy Markdown

You can also use git difftool.

@bkeating

Copy link
Copy Markdown
Author

j-kan, blindly trying git difftool on another machine of mine did not do anything. shrug I'll keep it in mind though. Thanks.

@j-kan

j-kan commented Mar 25, 2011

Copy link
Copy Markdown

Huh... here's what it does for me:

beton:pgm1 kan$ git difftool diagnosis.clj 
merge tool candidates: opendiff kdiff3 tkdiff xxdiff meld kompare gvimdiff diffuse ecmerge p4merge araxis emerge vimdiff

Viewing: 'pgm1/diagnosis.clj'
Hit return to launch 'opendiff': 

...and hitting return does exactly what it says. I'm running 1.7.3.4, if that matters....

@gordonad

gordonad commented Aug 8, 2012

Copy link
Copy Markdown

Very confusing terminology. "Choose Left" moves the arrow from the right to the left. This seems that the code on the right goes into the chosen code on the left. - Please provide an improvement to help the user.

@wamatt

wamatt commented Aug 16, 2012

Copy link
Copy Markdown

Anyone know what diff git natively uses? I like it's terminal output and want to make it my system default.

@CorpusCallosum

Copy link
Copy Markdown

Hi, how do I paste the code in in step 2?
I try to paste it in, but I get an error that reads:

"E486: Pattern not found: usr"

I guess I don't understand how to use VI, it is not intuitive for me, but I want to make this work. Before I had git setup to use opendiff as the mergetool and it worked great. Somehow it stopped working and I don't know how to get it back. Thanks.

-jack

@Frizlab

Frizlab commented May 17, 2013

Copy link
Copy Markdown

There are two mode when you're in vi. The "command" mode in which you type commands, and the edition mode. To enter the edition mode, you should type "i", or "a". Then you can paste the code. To leave the edition mode, hit the escape key. To quit and save the changes, type ":x" then the return key while in command mode.

@mcormier

Copy link
Copy Markdown

This works great but is there any way to make the git diff command line not wait until FileMerge quits?
I made the following modification so that a copy is made of the temp file that git generates so that & can be called on opendiff.

#!/bin/sh
TMPFILE=$(mktemp /tmp/output.XXXXXXXXXX)
# Copy the temp file that git generates
# So that the command line can exit
cp $5 $TMPFILE
/usr/bin/opendiff "$2" "$TMPFILE" &

This works great when I test it directly from the shell.

./git-diff-cmd.sh ignored test.txt ignored ignored test2.txt 

but when asking git to do a diff I don't regain control of the terminal until I quit FileMerge

git diff 263f..4aaa complete.cpp 

@mcormier

Copy link
Copy Markdown

After looking at this more closely it appears the git diff behavior is different depending on whether FileMerge is already running. So if FileMerge is running before a call to git diff then it works.

Here is a fish shell version for working with a temp file.

#!/usr/local/bin/fish

set -l TMPFILE (mktemp /tmp/output.XXXXXXXXXX)

# Copy the temp file that git generates
# So that the command line can exit
cp $argv[5] $TMPFILE

function event_git_diff --on-event git_diff_event
  /usr/bin/opendiff $argv[1] $argv[2] &
end

emit git_diff_event $argv[2] $TMPFILE

@kwerle

kwerle commented Jan 31, 2014

Copy link
Copy Markdown

difftool did the right thing for me, too.

% git --version
git version 1.8.3.4 (Apple Git-47)

@nicholasruunu

Copy link
Copy Markdown

Problem for me with difftool is that it will ask for merge file when saving.
Problem for me with this script is that opendiff will open new diffs before I had time to save/quit.

If someone knows how to fix sequential diffs where git will wait for the first file to be saved/quit before diffing another file + have merge path set I'd be really greatful.

Update:
I had this behaviour with svn using filemerge and:
http://soft.vub.ac.be/svn-gen/bdefrain/fmscripts/fmdiff

But can't seem to replicate it with git.

Edit:
@mcormier I think you can just put & after the command to put in the background.

@nicholasruunu

Copy link
Copy Markdown

For anyone interested, this is how I solved it (using git difftool):

[diff]
    tool = opendiff
[difftool]
    prompt = false
[difftool "opendiff"]
    cmd = /usr/bin/opendiff \"$LOCAL\" \"$REMOTE\" -merge \"$MERGED\" | cat

@JakobJingleheimer

Copy link
Copy Markdown

worked like a charm, thanks!

@christopherscott

Copy link
Copy Markdown

Thanks guys!
For me i preferred using difftool over external, since i have some other CLI tools that rely on std output from "git diff" command.

@bblfish

bblfish commented Apr 2, 2015

Copy link
Copy Markdown

if you don't want opendiff to be used all the time, use git difftool ...

@miner

miner commented Apr 25, 2016

Copy link
Copy Markdown

You can get a directory diff from git using the git difftool --dir-diff (or -d). I use that with a little bash script that invokes FileMerge. My script works around the issues with opendiff terminating too soon to save changes and not having the merge directory set.

https://gist.github.com/miner/e73fc98a83a8fe05d9ef000d46d68a9f

git difftool -d -x gdiff

@mfripp

mfripp commented Oct 20, 2016

Copy link
Copy Markdown

Similar to the advice from @nicholasruunu, you can use FileMerge with git by running these commands:

One-time setup:

git config --global diff.tool opendiff

Perform a diff with FileMerge:

git difftool

If you don't want to be prompted before opening each file, you can run this:

git config --global --add difftool.prompt false

Note: When using the git difftool option, you will have to quit FileMerge after each file is shown, and then git will show you the next one. In contrast, the original script above opens all the files at once.

By the way, if you want to undo the original setup, you can run this command:

git config --global --unset-all diff.external

If you want to undo the difftool setup, you can run these commands:

git config --global --unset-all diff.tool
git config --global --unset-all difftool.prompt

I think you can also use FileMerge for merges via this command (see http://stackoverflow.com/a/20123093/3830997), but I haven't tried it:

git config --global merge.tool opendiff

@robrohan

Copy link
Copy Markdown

After doing the above, you can open all the diffs at once (instead of one file at a time) by doing:

git difftool --dir-diff <other_branch>

And if you do this a lot you can setup an alias in ~/.gitconfig:

[alias]
        dt = difftool --dir-diff

Then you can just do:

git dt <other_branch>

@davidparsson

Copy link
Copy Markdown

For me, with git 2.16.1 it's enough to just configure an alias:

[alias]
    opendiff = difftool --no-prompt --tool opendiff --dir-diff

Then run

git opendiff <other_branch>

@gingerbeardman

Copy link
Copy Markdown

Thanks @mfripp

@brody2consult

Copy link
Copy Markdown

Even quicker config, works for me on git 2.15.2:

git config --global alias.opendiff difftool --no-prompt --tool opendiff --dir-diff

@jaredatron

Copy link
Copy Markdown

git config --global alias.opendiff difftool --no-prompt --tool opendiff --dir-diff

this did not work for me. just outputs the usage text.
I'm using:

$ git --version
git version 2.19.0
hub version 2.2.9

@dfernandez79

Copy link
Copy Markdown

git config --global alias.opendiff difftool --no-prompt --tool opendiff --dir-diff

this did not work for me. just outputs the usage text.

Add quotes to the aliased command:

git config --global alias.opendiff "difftool --no-prompt --tool opendiff --dir-diff"

@nonopolarity

Copy link
Copy Markdown

can you have opendiff without installing the whole XCode app? (which is huge)

@bkeating

Copy link
Copy Markdown
Author

I don’t think running opendiff is possible without Xcode, unfortunately. See top answer on this thread: https://apple.stackexchange.com/questions/108025/is-it-possible-to-use-filemerge-as-standalone-app

@1oo7

1oo7 commented May 4, 2020

Copy link
Copy Markdown

Filemerge sucks. Pasting in lines of text it always deletes out all the whitespace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment