Skip to content

Commit 8c37954

Browse files
authored
Warn about potential unsolicited changes in suggestions
And as a bonus block `git apply`
1 parent 589c84b commit 8c37954

File tree

1 file changed

+155
-110
lines changed

1 file changed

+155
-110
lines changed

git-fmt-diff

Lines changed: 155 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ g_cached_opt=
1515
gf_debug=0
1616
gf_no_term=
1717
gf_use_color=
18+
gf_warn_risky_stderr=
1819

1920
g_rm_list="$(mktemp)"
2021

@@ -80,6 +81,14 @@ sed_esc () (
8081
fi
8182
)
8283

84+
sgr () {
85+
if [ "$gf_use_color" -eq 1 ]; then
86+
printf "\033[%sm%s\033[0m" "$1" "$2"
87+
else
88+
printf '%s' "$2"
89+
fi
90+
}
91+
8392
warn () (
8493
>&2 printf "%s: " "$(basename "$0")"
8594
# printf "\033[30m\033[103m"
@@ -275,10 +284,12 @@ detect_filetype () (
275284

276285
git_changes_formatted () (
277286
tempdir="$1"
278-
b_raw="$2"
279-
a_raw="$3"
280-
b_fmt="$4"
281-
a_fmt="$5"
287+
formatter="$2"
288+
289+
b_raw="$3"
290+
a_raw="$4"
291+
b_fmt="$5"
292+
a_fmt="$6"
282293

283294
merge () { git merge-file -p "$@"; }
284295
chng_fmt="$tempdir"/chng_fmt
@@ -306,20 +317,30 @@ git_changes_formatted () (
306317
if ! git diff -s "$chng_fmt" "$temp"; then
307318
echo "$chng_fmt"
308319
fi
320+
321+
sh -c "$formatter" < "$chng_fmt" > "$temp" 2> /dev/null
322+
if ! git diff -s "$b_fmt" "$temp"; then
323+
return 1
324+
fi
309325
)
310326

311327
git_diff () (
312328
b_raw="$1"
313329
chng_fmt="$2"
314330
filename="$3"
315331

316-
[ "$gf_use_color" = 1 ] && color="--color" || color=
332+
case "$filename" in
333+
/*) ;;
334+
*) a_filename="a/$a_filename" ;;
335+
esac
336+
337+
[ "$gf_use_color" -eq 1 ] && color="--color" || color=
317338

318339
# shellcheck disable=SC2086
319340
git diff $color "$b_raw" "$chng_fmt" | \
320341
sed \
321-
-e "s/$(sed_esc -p "a$b_raw")/$(sed_esc -s "a/$filename")/g" \
322-
-e "s/$(sed_esc -p "b$chng_fmt")/$(sed_esc -s "b/$filename")/g"
342+
-e "s/$(sed_esc -p "a$b_raw")/$(sed_esc -s "$filename")/g" \
343+
-e "s/$(sed_esc -p "b$chng_fmt")/$(sed_esc -s "$filename")/g"
323344
)
324345

325346
git_retrieve_file_from_sha () (
@@ -357,10 +378,12 @@ list_files () (
357378
)
358379

359380
process_file () (
360-
a_hash="$1"
361-
b_hash="$2"
362-
a_name="$3"
363-
b_name="${4:-$a_name}"
381+
risky="$1"
382+
383+
a_hash="$2"
384+
b_hash="$3"
385+
a_name="$4"
386+
b_name="${5:-$a_name}"
364387

365388
debug "--- PROCESSING: $b_name ---"
366389
debug "args = " "$@"
@@ -396,26 +419,29 @@ process_file () (
396419
rm_list__push "$a_raw" "$b_raw"
397420

398421
if [ ! -s "$b_raw" ]; then
399-
warn "couldn't retrieve $b_name"
422+
warn "couldn't retrieve '$b_name'"
423+
return
400424
fi
401425

402426
sh -c "$formatter" < "$b_raw" > "$b_fmt" 2> /dev/null
403427
rm_list__push "$b_fmt"
404428

405-
if ! git diff -s "$b_raw" "$b_fmt"; then
406-
sh -c "$formatter" < "$a_raw" > "$a_fmt" 2> /dev/null
407-
rm_list__push "$a_fmt"
429+
git diff -s "$b_raw" "$b_fmt" && return
408430

409-
chng_fmt="$(git_changes_formatted \
410-
"$tempdir" \
411-
"$b_raw" "$a_raw" \
412-
"$b_fmt" "$a_fmt" \
413-
)"
431+
sh -c "$formatter" < "$a_raw" > "$a_fmt" 2> /dev/null
432+
rm_list__push "$a_fmt"
414433

415-
if [ -n "$chng_fmt" ]; then
416-
git_diff "$b_raw" "$chng_fmt" "$b_name"
417-
fi
418-
fi
434+
chng_fmt="$(git_changes_formatted \
435+
"$tempdir" "$formatter"\
436+
"$b_raw" "$a_raw" \
437+
"$b_fmt" "$a_fmt" \
438+
)"
439+
ret="$?"
440+
441+
[ -z "$chng_fmt" ] && return
442+
443+
[ "$ret" -ne 0 ] && echo "$b_name" >> "$risky"
444+
git_diff "$b_raw" "$chng_fmt" "$b_name"
419445
)
420446

421447
processing () (
@@ -428,7 +454,11 @@ processing () (
428454
repo_root="$(git rev-parse --show-toplevel 2> /dev/null)"
429455
[ -n "$repo_root" ] && { cd "$repo_root" || exit 1; }
430456

431-
i=0
457+
risky="$outdir"/0
458+
touch "$risky"
459+
rm_list__push "$risky"
460+
461+
i=1
432462
i_len="$(echo "$files" | wc -l | tr -d '\n' | wc -m)"
433463
while read -r line; do
434464
[ -z "$line" ] && continue
@@ -437,7 +467,7 @@ processing () (
437467
rm_list__push "$outfile"
438468

439469
# shellcheck disable=SC2086
440-
process_file $line > "$outfile" &
470+
process_file "$risky" $line > "$outfile" &
441471

442472
i=$((i+1))
443473
done << EOL
@@ -446,12 +476,29 @@ EOL
446476

447477
wait
448478

479+
if [ -s "$risky" ]; then
480+
cat > "$risky".temp << EOW
481+
$(sgr 33 '@ WARNING!')
482+
$(sgr 33 '@ Suggestions for the following files might smuggle unsolicited changes:')
483+
$(sort "$risky" | sed 's/^/- /')
484+
$(sgr 33 "@ Review them thoroughly before applying.")
485+
486+
487+
EOW
488+
mv "$risky".temp "$risky"
489+
490+
if [ "$gf_warn_risky_stderr" -eq 1 ]; then
491+
cat "$risky" 1>&2
492+
true > "$risky"
493+
fi
494+
fi
495+
449496
if [ -n "$(ls -A "$outdir")" ]; then
450497
cat "$outdir"/* | sh -c "$(git_conf_get pager)"
451498
fi
452499
)
453500

454-
# start {{{1
501+
# }}}1
455502

456503
usage () (
457504
cat << EOU
@@ -461,97 +508,95 @@ usage: git fmt-diff [<options>] [<commit>] [--] [<path>...]
461508
or: git fmt-diff [<options>] <blob> <blob>
462509
463510
options:
464-
-h display this help and exit
465-
--cached view the changes you staged for the next commit relative
466-
to the named <commit> (which defaults to HEAD)
467-
--staged a synonym of --cached
468-
--color always show colors
469-
--no-color turn off colored diff
470-
--config <file> read config from specified file rather than \$GIT_DIR/.git-$gc_prog_name
511+
-h display this help and exit
512+
--cached view the changes you staged for the next commit relative
513+
to the named <commit> (which defaults to HEAD)
514+
--staged a synonym of --cached
515+
--color always show colors
516+
--no-color turn off colored diff
517+
--config <file> read config from specified file rather than \$GIT_DIR/.git-$gc_prog_name
518+
--warn-risky-stderr redirects warning about potential unsolicited changes in suggestions to stderr;
519+
option not recommended as the warning blocks dangerous 'git apply'
471520
EOU
472521
)
473522

474-
main () (
475-
# parse options {{{2
476-
while :; do
477-
case "$1" in
478-
-h)
479-
usage
480-
exit
481-
;;
482-
--cached|--staged)
483-
g_cached_opt="--cached"
484-
;;
485-
--debug)
486-
gf_debug=1
487-
;;
488-
--debug=*)
489-
gf_debug="${1#--debug=}"
490-
;;
491-
--config)
492-
g_config="$2"
493-
if [ -z "$g_config" ]; then
494-
warn "option 'config' requires a path to config file as argument"
495-
exit 1
496-
fi
497-
shift
498-
;;
499-
--color)
500-
gf_use_color=1
501-
;;
502-
--no-color)
503-
gf_use_color=0
504-
;;
505-
--)
506-
shift
507-
break
508-
;;
509-
-?*)
510-
warn "unknown option: $1"
511-
usage
523+
# parse options {{{2
524+
while :; do
525+
case "$1" in
526+
-h)
527+
usage
528+
exit
529+
;;
530+
--cached|--staged)
531+
g_cached_opt="--cached"
532+
;;
533+
--debug)
534+
gf_debug=1
535+
;;
536+
--debug=*)
537+
gf_debug="${1#--debug=}"
538+
;;
539+
--config)
540+
g_config="$2"
541+
if [ -z "$g_config" ]; then
542+
warn "option 'config' requires a path to config file as argument"
512543
exit 1
513-
;;
514-
*)
515-
break
516-
;;
517-
esac
518-
519-
shift
520-
done
521-
522-
for o in "$@"; do
523-
case "$o" in
524-
-?*)
525-
warn "option '$o' must come before non-option arguments"
526-
return 1
527-
;;
528-
esac
529-
done
544+
fi
545+
shift
546+
;;
547+
--color)
548+
gf_use_color=1
549+
;;
550+
--no-color)
551+
gf_use_color=0
552+
;;
553+
--warn-risky-stderr)
554+
gf_warn_risky_stderr=1
555+
;;
556+
--)
557+
shift
558+
break
559+
;;
560+
-?*)
561+
warn "unknown option: $1"
562+
usage
563+
exit 1
564+
;;
565+
*)
566+
break
567+
;;
568+
esac
530569

531-
[ -t 1 ] && gf_no_term=0 || gf_no_term=1
570+
shift
571+
done
572+
573+
for o in "$@"; do
574+
case "$o" in
575+
-?*)
576+
warn "option '$o' must come before non-option arguments"
577+
return 1
578+
;;
579+
esac
580+
done
532581

533-
repo_root="$(git rev-parse --show-toplevel 2> /dev/null)"
534-
if [ -z "$g_config" ] && [ -n "$repo_root" ]; then
535-
if [ -e "$repo_root/.git-$gc_prog_name" ]; then
536-
g_local_rc="$repo_root/.git-$gc_prog_name"
537-
fi
538-
fi
582+
[ -t 1 ] && gf_no_term=0 || gf_no_term=1
583+
[ -z "$gf_warn_risky_stderr" ] && gf_warn_risky_stderr=0
584+
[ -z "$gf_use_color" ] && [ "$gf_no_term" = 0 ] && gf_use_color=1
585+
[ -z "$gf_use_color" ] && gf_use_color=0
539586

540-
if [ -z "$gf_use_color" ] && [ "$gf_no_term" = 0 ]; then
541-
gf_use_color=1
587+
repo_root="$(git rev-parse --show-toplevel 2> /dev/null)"
588+
if [ -z "$g_config" ] && [ -n "$repo_root" ]; then
589+
if [ -e "$repo_root/.git-$gc_prog_name" ]; then
590+
g_local_rc="$repo_root/.git-$gc_prog_name"
542591
fi
592+
fi
543593

544-
# setup env {{{2
545-
TMPDIR="${TMPDIR:-/tmp}"/git-"$gc_prog_name"
546-
mkdir -p "$TMPDIR"
547-
rm_list__push "$TMPDIR"
548-
549-
trap 'cleanup' EXIT
550-
# }}}2
594+
# setup env {{{2
595+
TMPDIR="${TMPDIR:-/tmp}"/git-"$gc_prog_name"
596+
mkdir -p "$TMPDIR"
597+
rm_list__push "$TMPDIR"
551598

552-
processing "$@"
553-
)
554-
555-
# }}}1
599+
trap 'cleanup' EXIT
600+
# }}}2
556601

557-
main "$@"
602+
processing "$@"

0 commit comments

Comments
 (0)