#!/bin/bash # # this patch can be found here: # http://www.jukie.net/~bart/scripts/tmp/vimdiff-over-unapplied-patch # # this script uses git-cat, inspired by cg-admin-cat, it can be found here: # http://www.jukie.net/~bart/scripts/tmp/git-cat # # use case: you have a patch that you only want to apply, but you don't want to # apply all of it. This script runs vimdiff over each of the files # modified by the patch. You select which deltas you want with 'do' # (see :help do in vim) # # example: you went too long without commiting and you don't want to commit # everything... # # git diff > /tmp/patch ; git clean ; vimdiff-over-unapplied-patch -p 1 /tmp/patch # set -u -e prog=$(basename $0) USAGE="$prog [-h] [-p ] " function bail { rc=$1 ; shift ((to=(rc?2:1))) echo $@ >&$to exit $rc } function warn { echo $@ >&2 } function help { rc=$1 ; shift ((to=($rc?2:1))) cat >&$to < same as patch -p -f force; overwrite temporary files if they exist -h print this help END exit $rc } # return true if repeat requested function cleanup_repeat_prompt { tmp_file=$1 res=xxx echo "Options:" echo " y - yes, cleanup and move to the next file" echo " n - no, don't cleanup but move to the next file" echo " r - reset and repeat same file" echo " q - stop everything" while true ; do read -n 1 -p "Cleanup? [y/n/r/q] " res echo case $res in q) exit 0 ;; # bail y) rm -f "$tmp" ; return 0 ;; # cleanup, next n) return 0 ;; # next r) rm -f "$tmp" ; return 1 ;; # cleanup, repeat esac done exit 1 } PLVL=1 FORCE=false REV=HEAD while [ "${1:0:1}" = '-' ] ; do cmd=$1 ; shift case "$cmd" in -p) PLVL=$1 shift ;; -f) FORCE=true ;; -r) REV=$1 shift ;; -h|--help) help 0 ;; *) warn "invlid option $cmd" help 1 ;; esac done PATCH=$1 if ! [ -f "$PATCH" ] ; then warn "need to specify patch file" help 1 fi for need in diffstat patch filterdiff git-cat ; do ( type $need >/dev/null 2>/dev/null ) || bail "$0 needs $need" done FILES=$(diffstat -l -p$PLVL "$PATCH") for file in $FILES ; do echo "Working on: $file" finished=false until $finished ; do tmp=".tmp."$(echo -n "$file" | tr -c 'A-Za-z0-9_.-' '_') $FORCE && rm -f "$tmp" git-cat -r "$REV" "$file" > "$tmp" filterdiff -p$PLVL -i "$file" < "$PATCH" | patch -p$PLVL "$tmp" if ( diff "$file" "$tmp" >/dev/null ) ; then echo "... identical, skipping." echo finished=true else chmod -w "$tmp" vimdiff "$file" "$tmp" if cleanup_repeat_prompt "$file" ; then finished=true fi fi done done