Created
May 19, 2017 21:23
-
-
Save unphased/b71816c8679cec0c7c5c84b56afe8f0d to your computer and use it in GitHub Desktop.
A command line (shell) tool for grokking git merge conflicts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# set -x | |
# PS4='{$LINENO}+' | |
if [ -t 1 ]; then | |
# echo "in terminal" | |
RED="[31m" | |
RESET="[0m" | |
BLUE="[34m" | |
YELLOW="[33m" | |
GREEN="[32m" | |
MAGENTA="[35m" | |
COLORFLAG=" --color=always" | |
# else | |
# echo "in script" | |
fi | |
# this is a simple script to help handle a git conflict situation. It is intended for use in conjunction with the merge.conflictStyle = diff3 git configuration setting. We split a conflicted file as produced by git into two pairs of "temporary" buffers to pipe to sift for each conflicting chunk. This way we can view for each chunk what the original was, what local changes were, and what remote changes were, this shall usually be sufficient to inform the changes we need to make, and so far we have been in dire need of an interface for this. | |
# Unfortunately git's own behavior falls short of what we'd consider reasonable | |
# and I cant just let this be triggered from the ext diff. But I can just run | |
# this and it will: | |
# 1. check that the cwd's repo is in conflict state, quit otherwise | |
# 2. determine which files are in conflict, for each of them: | |
# 3. for each of their conflict chunks: | |
# 4. run sift of each side from the original content. | |
if [[ -n $(git ls-files --unmerged) ]]; then | |
files=$(git diff --name-only --diff-filter=U) | |
for file in $files; do | |
echo ${MAGENTA}Looking at ${file}...$RESET | |
# sanity check for <<< ||| === >>> | |
markers=$(grep -n '^[<=>|]\{7\}' $file) | |
linecount=$(wc -l <<< "$markers") | |
[[ $(($linecount % 4)) -ne 0 ]] && echo "marker count not multiple of 4" && exit 1; | |
matches1=0 | |
result1=$(grep '<' -n <<< "$markers") | |
result11=$(cut -d':' -f1 <<< "$result1") | |
while read idx; do | |
((matches1++)) | |
if [[ $(($idx % 4)) -ne 1 ]] | |
then echo "bad marker index < $idx"; exit 1; | |
fi | |
done <<< "$result11" | |
matches2=0 | |
result2=$(grep '|' -n <<< "$markers") | |
result22=$(cut -d':' -f1 <<< "$result2") | |
while read idx; do ((matches2++)); if [[ $(($idx % 4)) -ne 2 ]] | |
then echo "bad marker index | $idx"; exit 1; fi; done <<< "$result22" | |
matches3=0 | |
result3=$(grep '=' -n <<< "$markers") | |
result33=$(cut -d':' -f1 <<< "$result3") | |
while read idx; do ((matches3++)); if [[ $(($idx % 4)) -ne 3 ]] | |
then echo "bad marker index = $idx"; exit 1; fi; done <<< "$result33" | |
matches4=0 | |
result4=$(grep '>' -n <<< "$markers") | |
result44=$(cut -d':' -f1 <<< "$result4") | |
while read idx; do ((matches4++)); if [[ $(($idx % 4)) -ne 0 ]] | |
then echo "bad marker index > $idx"; exit 1; fi; done <<< "$result44" | |
if [[ $matches4 -ne $matches1 || $matches4 -ne $matches2 || $matches4 -ne $matches3 ]] | |
then echo "not same marker counts $matches1 $matches2 $matches3 $matches4"; exit 1; fi | |
echo "found $matches4 chunks" | |
IFS=$'\n' | |
result111=($(cut -d':' -f2 <<< "$result1")) | |
result222=($(cut -d':' -f2 <<< "$result2")) | |
result333=($(cut -d':' -f2 <<< "$result3")) | |
result444=($(cut -d':' -f2 <<< "$result4")) | |
i=0 | |
while read res4; do | |
echo "${BLUE}============ chunk $i ours ${result111[$i]} ${result222[$i]} theirs ${result333[$i]} ${result444[$i]} original ${result222[$i]} ${result333[$i]}${RESET}" | |
orig=$(sed -n $((${result222[$i]}+1)),$((${result333[$i]}-1))p $file) | |
ours=$(sed -n $((${result111[$i]}+1)),$((${result222[$i]}-1))p $file) | |
theirs=$(sed -n $((${result333[$i]}+1)),$((${result444[$i]}-1))p $file) | |
# printf "orig is $orig, ours is $ours" | |
echo ${YELLOW}OURS$RESET | |
sift -R "$orig" "$ours" | |
echo ${YELLOW}THEIRS$RESET | |
sift -R "$orig" "$theirs" | |
((i++)) | |
done <<< "$result4" | |
done | |
else | |
echo "Current repo not unmerged" | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This has a dependency on the program
sift
which is not included here. It is a program that works just likediff
. It uses the-R
flag with it as well. That flag takes the two arguments themselves as the text to diff (rather than treating them as filenames).