The ultimate mergetool to replace vimdiff
This is kind of tongue-in-cheek, but it is what I ended up converging to as a vimmer after trying vimdiff.
To resolve a merge conflict, what I almost always need is to see:
- REMOTE
- LOCAL
- two diffs:
- diff BASE REMOTE
- diff BASE LOCAL
 
to then try to put both of them together.
While vimdiff does show BASE, LOCAL and REMOTE in the screen:
    +--------------------------------+
    | LOCAL  |     BASE     | REMOTE |
    +--------------------------------+
    |             MERGED             |
    +--------------------------------+
I don't know how to make it clearly show those two diffs that I need besides by looking right left right left a bunch of times.
Furthermore, LOCAL and REMOTE are already visible in the git merge conflict markers, so I don't gain that much from a tool that shows them again.
Therefore, I instead created my own tiny "difftool" that actually shows the diffs that I was missing:
~/bin/cirosantilli-mergetool
#!/usr/bin/env bash
BASE="$1"
LOCAL="$2"
REMOTE="$3"
diff --color -u "$BASE" "$LOCAL"
diff --color -u "$BASE" "$REMOTE"
exit 1
GitHub upstream.
And install it with:
git config --global mergetool.cirosantilli-mergetool.cmd 'cirosantilli-mergetool $BASE $LOCAL $REMOTE'
git config --global mergetool.cirosantilli-mergetool.trustExitCode true
# If you want this to become your default mergetool.
#git config --global merge.tool 'cirosantilli-mergetool'
Now, when you do:
git mergetool -t cirosantilli-mergetool
it shows the two diffs that I want on the terminal, e.g. something along:
--- ./src/dev/arm/RealView_BASE_15560.py        2019-12-27 13:46:41.967021591 +0000
+++ ./src/dev/arm/RealView_LOCAL_15560.py       2019-12-27 13:46:41.979021479 +0000
@@ -994,7 +994,7 @@                                                              
                                       
     def setupBootLoader(self, cur_sys, loc):
         if not cur_sys.boot_loader:                           
-            cur_sys.boot_loader = [ loc('boot_emm.arm64'), loc('boot_emm.arm') ]
+            cur_sys.boot_loader = [ loc('boot.arm64'), loc('boot.arm') ]
         cur_sys.atags_addr = 0x8000000                  
         cur_sys.load_offset = 0x80000000                    
@@ -1054,7 +1054,7 @@                                           
             ]                                                     
                       
     def setupBootLoader(self, cur_sys, loc):
-        cur_sys.boot_loader = [ loc('boot_emm_v2.arm64') ]
+        cur_sys.boot_loader = [ loc('boot_v2.arm64') ]
         super(VExpress_GEM5_V2_Base,self).setupBootLoader(
                 cur_sys, loc)                             
                                                           
--- ./src/dev/arm/RealView_BASE_15560.py        2019-12-27 13:46:41.967021591 +0000
+++ ./src/dev/arm/RealView_REMOTE_15560.py      2019-12-27 13:46:41.991021366 +0000
@@ -610,10 +610,10 @@           
     def attachIO(self, *args, **kwargs):              
         self._attach_io(self._off_chip_devices(), *args, **kwargs)
                                      
-    def setupBootLoader(self, cur_sys, loc):
-        cur_sys.boot_loader = loc('boot.arm') 
-        cur_sys.atags_addr = 0x100                           
-        cur_sys.load_offset = 0       
+    def setupBootLoader(self, cur_sys, boot_loader, atags_addr, load_offset):
+        cur_sys.boot_loader = boot_loader      
+        cur_sys.atags_addr = atags_addr     
+        cur_sys.load_offset = load_offset
So you can see here the two diffs dumped into the terminal:
- RealView_BASE_15560.pyvs- RealView_LOCAL_15560.py
- RealView_BASE_15560.pyvs- RealView_REMOTE_15560.py
If the diffs are big, I'll just search up with my tmux superpowers.
TODO: to achieve Nirvana the last thing left would be a way to show only diffs for the conflicting hunk. Because if the diffs are large but only a small hunk conflicts, it is annoying to find it.
Yes, you you do lose some shortcuts that vimdiff provides, but in general solving conflicts requires careful copy paste from both versions, which I can do fine inside a normal vim session with the git conflict markers.
Observing and diffing files while vimdiff is running
Before I sat down and automated my perfect setup with cirosantilli-mergetool, this is what I was doing to get the two diffs I needed.
While git mergetool is running vimdiff, if there is a conflict on a file named, say, main.py, git generates files for each of the versions, named as:
main_BASE_1367.py
main_LOCAL_1367.py
main_REMOTE_1367.py
in the same directory as main.py where 1367 is the PID of git mergetool, and therefore a "random" integer, as mentioned at: In a git merge conflict, what are the BACKUP, BASE, LOCAL, and REMOTE files that are generated?
So, to see the diffs that I want, I first find the generated files with git status, and then open new terminals and do a vimdiff between the pairs of files that I care about:
vim -d main_BASE_1367.py main_LOCAL_1367.py
vim -d main_BASE_1367.py main_REMOTE_1367.py
Together with git mergetool, this information helps A LOT to figure out what is going on quickly!
Also, even while mergetool is running, you can just open the file:
vim main.py
directly and edit it there if you feel that it is going to be easier with a larger editor window.
Jump directly to merge conflicts
While ]c jumps to the next diff point inside vimdiff, there isn't always a merge conflict there.
To help with this, I have in my ~/.vimrc:
# Git Merge conflict
nnoremap <leader>gm /\v^\<\<\<\<\<\<\< \|\=\=\=\=\=\=\=$\|\>\>\>\>\>\>\> /<cr>
which finds the conflicts directly.
git imerge
Maybe the best option is to just give up on using vimdiff and rely on regular vim + git imerge which was mentioned at: How can I find out which Git commits cause conflicts? since vimdiff's learning curve is annoying, and it doesn't do the functions we need the most.