Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Git Diff and Merge Tool - IntelliJ IDEA
# Linux
# add the following to "~/.gitconfig" file
[merge]
tool = intellij
[mergetool "intellij"]
cmd = /usr/local/bin/idea merge $(cd $(dirname "$LOCAL") && pwd)/$(basename "$LOCAL") $(cd $(dirname "$REMOTE") && pwd)/$(basename "$REMOTE") $(cd $(dirname "$BASE") && pwd)/$(basename "$BASE") $(cd $(dirname "$MERGED") && pwd)/$(basename "$MERGED")
trustExitCode = true
[diff]
tool = intellij
[difftool "intellij"]
cmd = /usr/local/bin/idea diff $(cd $(dirname "$LOCAL") && pwd)/$(basename "$LOCAL") $(cd $(dirname "$REMOTE") && pwd)/$(basename "$REMOTE")
# Mac
# add the following to "~/.gitconfig" file
[merge]
tool = intellij
[mergetool "intellij"]
cmd = /Applications/IntelliJ\\ IDEA.app/Contents/MacOS/idea merge $(cd $(dirname "$LOCAL") && pwd)/$(basename "$LOCAL") $(cd $(dirname "$REMOTE") && pwd)/$(basename "$REMOTE") $(cd $(dirname "$BASE") && pwd)/$(basename "$BASE") $(cd $(dirname "$MERGED") && pwd)/$(basename "$MERGED")
trustExitCode = true
[diff]
tool = intellij
[difftool "intellij"]
cmd = /Applications/IntelliJ\\ IDEA.app/Contents/MacOS/idea diff $(cd $(dirname "$LOCAL") && pwd)/$(basename "$LOCAL") $(cd $(dirname "$REMOTE") && pwd)/$(basename "$REMOTE")
# Windows
# add the following to "C:\Users\<username>\.gitconfig" file
[merge]
tool = intellij
[mergetool "intellij"]
cmd = cmd.exe //c "\"C:/Program Files (x86)/IntelliJ IDEA Community Edition 12.0/bin/idea.bat\" merge \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$MERGED\""
trustExitCode = true
[diff]
tool = intellij
[difftool "intellij"]
cmd = cmd.exe //c "\"C:/Program Files (x86)/IntelliJ IDEA Community Edition 12.0/bin/idea.bat\" diff \"$LOCAL\" \"$REMOTE\""

Invoking IntelliJ IDEA from the command line

On OS X or UNIX:
  • Make sure IntelliJ IDEA is running.
  • On the main menu, choose Tools > Create Command-line Launcher. The dialog box Create Launcher Script opens, with the suggested path and name of the launcher script. You can accept default, or specify your own path.
  • Make notice of it, as you'll need it later. Outside of IntelliJ IDEA, add the path and name of the launcher script to your path.
On Windows:
  • Specify the location of the IntelliJ IDEA executable in the Path system environment variable. In this case, you will be able to invoke the IntelliJ IDEA executable and other IntelliJ IDEA commands from any directory.

For more information, visit https://www.jetbrains.com/help/idea/2016.2/running-intellij-idea-as-a-diff-or-merge-command-line-tool.html

Issues and Solutions

@cosbor11
Copy link

cosbor11 commented Jun 15, 2017

Is this out of date?

fatal: bad config line 7 in file

@yuriteixeira
Copy link

yuriteixeira commented Jun 26, 2017

@cosbor11: for me it was somehow related to the path of the idea executable. Since I symlinked it to /usr/local/bin and this directory is on my $PATH env var, I just changed it to:

[merge]
    tool = intellij
[mergetool "intellij"]
    cmd = idea merge $(cd $(dirname "$LOCAL") && pwd)/$(basename "$LOCAL") $(cd $(dirname "$REMOTE") && pwd)/$(basename "$REMOTE") $(cd $(dirname "$BASE") && pwd)/$(basename "$BASE") $(cd $(dirname "$MERGED") && pwd)/$(basename "$MERGED")
    trustExitCode = true
[diff]
    tool = intellij
[difftool "intellij"]
    cmd = idea diff $(cd $(dirname "$LOCAL") && pwd)/$(basename "$LOCAL") $(cd $(dirname "$REMOTE") && pwd)/$(basename "$REMOTE")

Copy link

ghost commented Jul 19, 2017

For those of you using fish as your shell:

[merge]
  tool = /usr/local/bin/idea
[mergetool "idea"]
	cmd = /usr/local/bin/idea merge (cd (dirname "$LOCAL"); and pwd)/(basename "$LOCAL") (cd (dirname "$REMOTE"); and pwd)/(basename "$REMOTE") (cd (dirname "$BASE"); and pwd)/(basename "$BASE") (cd (dirname "$MERGED"); and pwd)/(basename "$MERGED")
	trustExitCode = true
[diff]
	tool = /usr/local/bin/idea
[difftool "idea"]
  cmd = /usr/local/bin/idea diff (cd (dirname "$LOCAL"); and pwd)/(basename "$LOCAL") (cd (dirname "$REMOTE"); and pwd)/(basename "$REMOTE")

@rambabusaravanan
Copy link
Author

rambabusaravanan commented Aug 24, 2017

@cosbor11 Can you show us the config file and the error message please ..

@rambabusaravanan
Copy link
Author

rambabusaravanan commented Aug 24, 2017

@robbie-10e Thanks for your contribution for "Fish" shell also. I just came to know about fish shell and love fishing it ..

@dudego
Copy link

dudego commented Sep 5, 2017

I had to double escape the back slashes (for spaces) to make it work on MacOS.

[merge]
	tool = intellij
[mergetool "intellij"]
	cmd = /Applications/IntelliJ\\IDEA\\ CE.app/Contents/MacOS/idea' merge $(cd $(dirname "$LOCAL") && pwd)/$(basename "$LOCAL") $(cd $(dirname "$REMOTE") && pwd)/$(basename "$REMOTE") $(cd $(dirname "$BASE") && pwd)/$(basename "$BASE") $(cd $(dirname "$MERGED") && pwd)/$(basename "$MERGED")
	trustExitCode = true
[diff]
	tool = intellij
[difftool "intellij"]
	cmd = /Applications/IntelliJ\\ IDEA\\ CE.app/Contents/MacOS/idea diff $(cd $(dirname "$LOCAL") && pwd)/$(basename "$LOCAL") $(cd $(dirname "$REMOTE") && pwd)/$(basename "$REMOTE")

@rambabusaravanan
Copy link
Author

rambabusaravanan commented Sep 19, 2017

Thanks for your contribution @dudego.
I have updated the gist with double backslash from IntelliJ\ IDEA to IntelliJ\\ IDEA.

@CoreyKaylor
Copy link

CoreyKaylor commented Nov 10, 2017

This setup worked fine for me on a Mac. Assuming you've already run the create command line launcher step. What doesn't make a lot of sense to me though is why IntelliJ has to already be running. Any context for that? I have the same issue. The reason I find it odd is that if you compare two files directly on the filesystem it works fine without IntelliJ already running. idea diff localfile.txt localfile2.txt

[merge]
    tool = intellij
[mergetool "intellij"]
    cmd = idea merge \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$MERGED\"
    trustExitCode = true
[diff]
    tool = intellij
[difftool "intellij"]
	cmd = idea diff \"$LOCAL\" \"$REMOTE\"
[difftool]
	  prompt = false

@AlexKalinin
Copy link

AlexKalinin commented Dec 26, 2017

Thanks!

@Mincol
Copy link

Mincol commented Jan 11, 2018

On Windows.
If Idea is already running, only first file get opened, for rest I get error that file does not exists.

There are two solutions to the problem.

  1. Close all idea instances. All work as expected.
  2. Set trustExitCode = false Then you need to visit commandline and say that you are finished with merging.

@aaccioly
Copy link

aaccioly commented Jan 23, 2018

I hit a problem running git difftool HEAD~1 --dir-diff on Windows. The files created by Git on %TEMP% are generally deleted a few seconds after the original diff command has run. Looks like the problem is that CMD /C runs the UI and terminates itself (releasing the files) before we get a chance to finish the merge.

A possible workaround is to call pause after idea.bat, e.g.:

[difftool "intellij"]
    cmd = cmd //c "idea.bat diff \"$LOCAL\" \"$REMOTE\"" & cmd //c pause

This will display the iconic "Press any key to continue . . ." message after each command and make sure that the inner cmd is not released until we are done.

Alternatively we can run idea.bat with cmd //k but I dislike the idea of not terminating the process. Distracted users can potentially open dozens of shells without noticing. Also, it gets really weird if you start the process from a different shell such as bash or PowerShell

@injulkarnilesh
Copy link

injulkarnilesh commented Apr 3, 2018

append "&& read -n 1 -s" to mergetool "intellij" command for mac.
Then it would ask to merge one file and wait for key press.

After merging one file go back to terminal press any key to continue merging next files.

@mariohuq
Copy link

mariohuq commented May 20, 2018

On windows version there is some issue:

▒▒▒ 21, 2018 1:11:55 AM java.util.prefs.WindowsPreferences <init>
WARNING: Could not open/create prefs root node Software\JavaSoft\Prefs at root 0x80000002. 
Windows RegCreateKeyEx(...) returned error code 5.

I am using Windows 10.0.17133 Build 17133
jdk's release file contents

JAVA_VERSION="1.8.0_152"
OS_NAME="Windows"
OS_VERSION="5.2"
OS_ARCH="amd64"
SOURCE=""

IntelliJ IDEA Community Edition 2018.1
MINGW64 from Git for Widows.

What's the reason?

@contentfree
Copy link

contentfree commented Apr 4, 2019

Doesn't seem to work on macOS if Intellij is installed from the JetBrains Toolbox app. (Haven't found the workaround yet, either)

@dror-weiss
Copy link

dror-weiss commented May 3, 2019

@contentfree, did you manage to find a solution?

@Yamp
Copy link

Yamp commented Sep 19, 2019

@dror-weiss @contentfree have you found a solution?

@ImanMahmoudinasab
Copy link

ImanMahmoudinasab commented May 14, 2020

@Yamp @dror-weiss @contentfree
Follow steps of the following instruction and you will end up with having a global command idea in your terminal:
https://www.jetbrains.com/help/idea/working-with-the-ide-features-from-command-line.html

@rwe
Copy link

rwe commented Nov 30, 2020

The problem on macOS is that the shell script generated by JetBrains Toolbox looks like this:

open -na "/Users/…/202.7660.26/IntelliJ IDEA.app/Contents/MacOS/idea" --args "$@"

However, if you man open, you'll see that the additional flag -W is required:

-W Causes open to wait until the applications it opens (or that were already open) have exited. Use with the -n flag to allow open to function as an appropriate app for the $EDITOR environment variable.

Solution

Caveat: The JetBrains toolbox will likely clobber changes to the generated script, so perhaps instead make a new one named like idea-wait/intellij-wait and replace the name after cmd = in the config below. Alternatively again, you could inline entire open -Wna … command. This would make your .gitconfig non-portable, but would remove the need to muck around with the script files.

Add the additional -W flag to the script. It's also not a bad idea to use exec so that sh doesn't sit in the way of signals:

exec open -Wna "/Users/…/MacOS/idea" --args "$@"

Which allows the following portable and correctly-quoted .gitconfig to work:

[difftool "idea"]
	cmd = idea diff \
		\"$(cd \"$(dirname \"$LOCAL\")\" && pwd)/$(basename \"$LOCAL\")\" \
		\"$(cd \"$(dirname \"$REMOTE\")\" && pwd)/$(basename \"$REMOTE\")\" \

[diff]
	tool = idea
	guitool = idea

[mergetool "idea"]
	cmd = idea merge \
		\"$(cd \"$(dirname \"$LOCAL\")\" && pwd)/$(basename \"$LOCAL\")\" \
		\"$(cd \"$(dirname \"$REMOTE\")\" && pwd)/$(basename \"$REMOTE\")\" \
		\"$(cd \"$(dirname \"$BASE\")\" && pwd)/$(basename \"$BASE\")\" \
		\"$(cd \"$(dirname \"$MERGED\")\" && pwd)/$(basename \"$MERGED\")\" \

[merge]
	tool = idea
	guitool = idea

Note also that if you have realpath available (via brew install coreutils), those awkward \"$(cd \"$(dirname…)\"…)/$(basename …)\" lines can just be replaced by e.g. \"$(realpath \"${LOCAL}\")\".

@tkolleh
Copy link

tkolleh commented Dec 30, 2020

@rwe suggestions worked 👍🏾

@bedge
Copy link

bedge commented Feb 1, 2021

open -na "/Users/…/202.7660.26/IntelliJ IDEA.app/Contents/MacOS/idea" --args "$@"

idea script generated by the Jetbrains toolbox app as of today appears to handle the case @rwe mentioned:
(assuming the caller knows to pass a --wait or -w)

#!/bin/sh
#Generated by JetBrains Toolbox 1.19.7784 at 2021-01-31T16:50:05.012390

declare -a ideargs=()
declare -- wait=""

for o in "$@"; do
  if [[ "$o" = "--wait" || "$o" = "-w" ]]; then
    wait="-W"
    o="--wait"
  fi
  if [[ "$o" =~ " " ]]; then
    ideargs+=("\"$o\"")
  else
    ideargs+=("$o")
  fi
done

open -na "$HOME/Library/Application Support/JetBrains/Toolbox/apps/IDEA-U/ch-0/203.7148.57/IntelliJ IDEA.app/Contents/MacOS/idea" $wait --args "${ideargs[@]}"

Perhaps the OP's config would be OK unmodified with this change?

@contentfree
Copy link

contentfree commented Mar 5, 2021

@bedge Still haven't got it to work. I assume that --wait or -w has to be added somewhere in the gitconfig. Have a hint?

@contentfree
Copy link

contentfree commented Mar 5, 2021

As far as I can tell, with the idea that's generated today, attempting idea --wait diff file1 file2 just shows an error in Intellij IDEA:

Cannot execute command
Can not open file
/path/to/pwd/diff

Where as idea diff file1 file2 works as expected.

@thiemok
Copy link

thiemok commented Mar 11, 2021

There is clearly a bug in the handling of the wait flag in the generated script. Hopefully it will be fixed soon. In the meantime you can easily fix it by replacing the contents of the scripts for loop with this:

  if [[ "$o" = "--wait" || "$o" = "-w" ]]; then
    wait="-W"
    o="--wait"
  elif [[ "$o" =~ " " ]]; then
    ideargs+=("\"$o\"")
  else
    ideargs+=("$o")
  fi

@ypkkhatri
Copy link

ypkkhatri commented Apr 3, 2021

I'm facing a problem with rendering, when I close the IntelliJ mergetool the main IDE looks weird like the top navbar is gone, the breadcrumb is out of the screen, and so on. After restart, it looks fine again.

Am I the only one facing this?

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