Skip to content

Instantly share code, notes, and snippets.

@guypursey
Last active September 29, 2019 10:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save guypursey/47c65d898cf35d0a975249ba9ab43076 to your computer and use it in GitHub Desktop.
Save guypursey/47c65d898cf35d0a975249ba9ab43076 to your computer and use it in GitHub Desktop.
git-add-atomic
#!/bin/bash
# diff a specific file for now (check it exists, etc.)
# extract hunk texts
bold=$(tput bold)
head=$(tput smul)
oldd=$(tput setaf 1)
newd=$(tput setaf 2)
askq=$(tput setaf 5)
norm=$(tput sgr0)
# work on single, specified file
if [ -e "$1" ] && [ ! -z "$1" ]; then
filediff="$(git diff --word-diff -U0 $1)";
alldiffs="$(echo "$filediff" | tail -n +5)";
filehead="$(echo "$filediff" | head -n 4)";
patchcontent="";
nl=$'\n'
diffnum=$((0))
while IFS= read -r origline; do
if [[ "$origline" =~ ^\@\@.*$ ]]; then
patchcontent="$patchcontent$nl$origline";
else
diffline="$origline";
resetline="$origline";
while read diff; do
echo "${head}${bold}Line diff${norm}"
echo "$diffline"
old=$(echo "$diff" | grep -Po '(?:\[\-(.*?)\-\])');
new=$(echo "$diff" | grep -Po '(?:\{\+(.*?)\+\})');
echo "${head}${bold}Word diff${norm}"
echo "${oldd}$old${newd}$new${norm}"
if [ "$skip" = "q" ]; then
answer=n
else
read -p "${bold}${askq}Stage this diff [y,n,q]?${norm}" answer </dev/tty
fi
# escape removal wrapper characters for use as substitution pattern
if [ ! -z "$old" ]; then
ptn="\[\-${old:2:-2}\-\]$new";
else
ptn="$new";
fi
# create original for line-level patch
resetline="${resetline/$ptn/${old:2:-2}}";
# create curated line for line-level patch
# y = yes, this hunk
if [ "$answer" = "y" ]; then
echo "${bold}Selected:${norm}"
echo "$(tput setaf 2)$new$(tput sgr0)"
diffline="${diffline/$ptn/${new:2:-2}}";
diffnum=$((diffnum + 1))
echo $diffnum
# n = no, not this hunk
elif [ "$answer" = "n" ]; then
diffline="${diffline/$ptn/${old:2:-2}}";
if [ ! -z "$old" ]; then
echo "${bold}Selected:${norm}"
echo "$(tput setaf 1)$old$(tput sgr0)"
else
echo "${bold}Diff not staged.${norm}"
fi
elif [ "$answer" = "q" ]; then
skip=q
fi
echo
done < <(grep -Po '(?:\[\-(.*?)\-\])?(?:\{\+(.*?)\+\})' < <(echo "$diffline"))
patchcontent="$patchcontent$nl-$resetline$nl+$diffline";
fi
done < <(printf '%s\n' "$alldiffs")
patchcontent="$filehead$patchcontent";
echo "$diffnum diff(s) selected"
echo "$patchcontent"
echo "$patchcontent" | git apply --cached
echo "${bold}Selected diffs applied${norm}"
else
echo "Could not find file $1"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment