aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xdotfiles/.local/bin/diffconflicts108
1 files changed, 108 insertions, 0 deletions
diff --git a/dotfiles/.local/bin/diffconflicts b/dotfiles/.local/bin/diffconflicts
new file mode 100755
index 0000000..ccd68f0
--- /dev/null
+++ b/dotfiles/.local/bin/diffconflicts
@@ -0,0 +1,108 @@
+#!/bin/bash
+# A better vimdiff mergetool for Git
+#
+# NOTE: Now also an installable Vim plugin:
+# https://github.com/whiteinge/diffconflicts
+#
+# Git does a great job resolving merge conflicts automatically but there are
+# times when human intervention is still needed. Git resolves all the conflicts
+# that it is able to and finally wraps each conflict it cannot resolve within
+# special markers which must be resolved by a human.
+#
+# The vertical format and lack of syntax highlighting in the plain conflict
+# marker layout makes it difficult to spot subtle conflicts such as
+# single-character changes and this is where a two-way diff really shines!
+# To see this explained using screenshots, see:
+# http://vim.wikia.com/wiki/A_better_Vimdiff_Git_mergetool
+#
+# This script, when used as a Git mergetool, opens each "side" of the conflict
+# markers in a two-way vimdiff window. This combines all the awesome of Git's
+# automatic merging savvy with the awesome and simplicity of a simple two-way
+# diff.
+#
+# Add this mergetool to your ~/.gitconfig (you can substitute gvim for vim):
+#
+# git config --global merge.tool diffconflicts
+# git config --global mergetool.diffconflicts.cmd 'diffconflicts vim $BASE $LOCAL $REMOTE $MERGED'
+# git config --global mergetool.diffconflicts.trustExitCode true
+# git config --global mergetool.diffconflicts.keepBackup false
+#
+# The next time you perform a merge with conflicts, invoke this tool with the
+# following command. (Of course you can set it as your default mergetool as
+# well.)
+#
+# git mergetool --tool diffconflicts
+#
+# This tool can open three tabs in Vim that each provide a different way to
+# view the conflicts. You can resolve the conflicts in the first tab and save
+# and exit the file. This will also mark the conflict as resolved in Git.
+# Only the first tab is opened by default so Vim loads more quickly and also
+# because the other tabs are only occasionally useful for tough merges. To open
+# Tab2 and Tab3 use the mapping <leader>D.
+#
+# Tab1 is a two-way diff of just the conflicts. Resolve the conflicts here
+# and save the file.
+# +--------------------------------+
+# | LCONFL | RCONFL |
+# +--------------------------------+
+# Tab2 is a three-way diff of the original files and the merge base. This is
+# the traditional three-way diff. Although noisy, it is occasionally useful
+# to view the three original states of the conflicting file before the merge.
+# +--------------------------------+
+# | LOCAL | BASE | REMOTE |
+# +--------------------------------+
+# Tab3 is the in-progress merge that Git has written to the filesystem
+# containing the conflict markers. I.e., the file you would normally edit by
+# hand when not using a mergetool.
+# +--------------------------------+
+# | <<<<<<< HEAD |
+# | LCONFL |
+# | ======= |
+# | RCONFL |
+# | >>>>>>> someref |
+# +--------------------------------+
+#
+# Workflow:
+#
+# 1. Save your changes to the LCONFL temporary file (the left window on the
+# first tab; also the only file that isn't read-only).
+# 2. The LOCAL, BASE, and REMOTE versions of the file are available in the
+# second tabpage if you want to look at them.
+# 3. When vimdiff exits cleanly, the file containing the conflict markers
+# will be updated with the contents of your LCONFL file edits.
+#
+# NOTE: Use :cq to abort the merge and exit Vim with an error code.
+
+if [[ -z $@ || $# != "5" ]] ; then
+ echo -e "Usage: $0 \$EDITOR \$BASE \$LOCAL \$REMOTE \$MERGED"
+ exit 1
+fi
+
+cmd="$1"
+BASE="$2"
+LOCAL="$3"
+REMOTE="$4"
+MERGED="$5"
+LCONFL="${MERGED}.$$.LCONFL"
+RCONFL="${MERGED}.$$.RCONFL"
+
+# Always delete our temp files; Git will handle it's own temp files.
+trap 'rm -f "'"${LCONFL}"'" "'"${RCONFL}"'"' SIGINT SIGTERM EXIT
+
+# Remove the conflict markers for each 'side' and put each into a temp file
+sed -E -e '/^=======\r?$/,/^>>>>>>> /d' -e '/^<<<<<<< /d' "${MERGED}" > "${LCONFL}"
+sed -E -e '/^<<<<<<< /,/^=======\r?$/d' -e '/^>>>>>>> /d' "${MERGED}" > "${RCONFL}"
+
+# Fire up vimdiff
+$cmd -f -R -d "${LCONFL}" "${RCONFL}" \
+ -c ":set noro" \
+ -c ":nmap <leader>D :tabe $REMOTE<CR>:vert diffs $BASE<CR>:vert diffs $LOCAL<CR>:winc t<CR>:tabe $MERGED<CR>:tabfir<CR>"
+
+EC=$?
+
+# Overwrite $MERGED only if vimdiff exits cleanly.
+if [[ $EC == "0" ]] ; then
+ cat "${LCONFL}" > "${MERGED}"
+fi
+
+exit $EC