From 7deb8035375b153609aeda34e0fd49de54661f46 Mon Sep 17 00:00:00 2001 From: "R. Steve McKown" Date: Thu, 27 Feb 2014 16:07:05 -0700 Subject: [PATCH] git-diffall is now in git contribs Update to latest git-diffall in contribs, and update man page with information from the script. --- git-diffall | 271 ++++++++++++++++++++++++++++++++++++++++++++------ git-diffall.1 | 28 ++++-- 2 files changed, 262 insertions(+), 37 deletions(-) diff --git a/git-diffall b/git-diffall index 990d285..84f2b65 100755 --- a/git-diffall +++ b/git-diffall @@ -1,46 +1,257 @@ #!/bin/sh -# Thanks to Thomas Rast -# http://thread.gmane.org/gmane.comp.version-control.git/124807 +# Copyright 2010 - 2012, Tim Henigan +# +# Perform a directory diff between commits in the repository using +# the external diff or merge tool specified in the user's config. + +USAGE='[--cached] [--copy-back] [-x|--extcmd=] {0,2} [-- *] + + --cached Compare to the index rather than the working tree. + + --copy-back Copy files back to the working tree when the diff + tool exits (in case they were modified by the + user). This option is only valid if the diff + compared with the working tree. + + -x= + --extcmd= Specify a custom command for viewing diffs. + git-diffall ignores the configured defaults and + runs $command $LOCAL $REMOTE when this option is + specified. Additionally, $BASE is set in the + environment. +' SUBDIRECTORY_OK=1 . "$(git --exec-path)/git-sh-setup" -cd_to_toplevel # for the tar below -pre="${1-HEAD}" -post="$2" +TOOL_MODE=diff +. "$(git --exec-path)/git-mergetool--lib" + +merge_tool="$(get_merge_tool)" +if test -z "$merge_tool" +then + echo "Error: Either the 'diff.tool' or 'merge.tool' option must be set." + usage +fi -tmp="$(mktemp -d)" +start_dir=$(pwd) -cleanup () { - rm -rf $tmp +# All the file paths returned by the diff command are relative to the root +# of the working copy. So if the script is called from a subdirectory, it +# must switch to the root of working copy before trying to use those paths. +cdup=$(git rev-parse --show-cdup) && +cd "$cdup" || { + echo >&2 "Cannot chdir to $cdup, the toplevel of the working tree" + exit 1 } -trap cleanup EXIT +# set up temp dir +tmp=$(perl -e 'use File::Temp qw(tempdir); + $t=tempdir("/tmp/git-diffall.XXXXX") or exit(1); + print $t') || exit 1 +trap 'rm -rf "$tmp"' EXIT + +left= +right= +paths= +dashdash_seen= +compare_staged= +merge_base= +left_dir= +right_dir= +diff_tool= +copy_back= + +while test $# != 0 +do + case "$1" in + -h|--h|--he|--hel|--help) + usage + ;; + --cached) + compare_staged=1 + ;; + --copy-back) + copy_back=1 + ;; + -x|--e|--ex|--ext|--extc|--extcm|--extcmd) + if test $# = 1 + then + echo You must specify the tool for use with --extcmd + usage + else + diff_tool=$2 + shift + fi + ;; + --) + dashdash_seen=1 + ;; + -*) + echo Invalid option: "$1" + usage + ;; + *) + # could be commit, commit range or path limiter + case "$1" in + *...*) + left=${1%...*} + right=${1#*...} + merge_base=1 + ;; + *..*) + left=${1%..*} + right=${1#*..} + ;; + *) + if test -n "$dashdash_seen" + then + paths="$paths$1 " + elif test -z "$left" + then + left=$1 + elif test -z "$right" + then + right=$1 + else + paths="$paths$1 " + fi + ;; + esac + ;; + esac + shift +done -mkdir "$tmp"/a "$tmp"/b +# Determine the set of files which changed +if test -n "$left" && test -n "$right" +then + left_dir="cmt-$(git rev-parse --short $left)" + right_dir="cmt-$(git rev-parse --short $right)" -if [ -n "$post" ]; then - git diff --name-only "$pre" "$post" > "$tmp"/filelist - while read name; do - mkdir -p "$tmp"/b/"$(dirname "$name")" - git show "$post":"$name" > "$tmp"/b/"$name" - done < "$tmp"/filelist + if test -n "$compare_staged" + then + usage + elif test -n "$merge_base" + then + git diff --name-only "$left"..."$right" -- $paths >"$tmp/filelist" + else + git diff --name-only "$left" "$right" -- $paths >"$tmp/filelist" + fi +elif test -n "$left" +then + left_dir="cmt-$(git rev-parse --short $left)" + + if test -n "$compare_staged" + then + right_dir="staged" + git diff --name-only --cached "$left" -- $paths >"$tmp/filelist" + else + right_dir="working_tree" + git diff --name-only "$left" -- $paths >"$tmp/filelist" + fi else - git diff --name-only "$pre" > "$tmp"/filelist - tar -c -T "$tmp"/filelist | (cd "$tmp"/b && tar -x) + left_dir="HEAD" + + if test -n "$compare_staged" + then + right_dir="staged" + git diff --name-only --cached -- $paths >"$tmp/filelist" + else + right_dir="working_tree" + git diff --name-only -- $paths >"$tmp/filelist" + fi fi -while read name; do - mkdir -p "$tmp"/a/"$(dirname "$name")" - git show "$pre":"$name" > "$tmp"/a/"$name" -done < "$tmp"/filelist - -cd "$tmp" -#meld a b -#diff -ur a b -tool="$(git-config diff.tool)" -if [ -n "$tool" ]; then - "$tool" a b +# Exit immediately if there are no diffs +if test ! -s "$tmp/filelist" +then + exit 0 +fi + +if test -n "$copy_back" && test "$right_dir" != "working_tree" +then + echo "--copy-back is only valid when diff includes the working tree." + exit 1 +fi + +# Create the named tmp directories that will hold the files to be compared +mkdir -p "$tmp/$left_dir" "$tmp/$right_dir" + +# Populate the tmp/right_dir directory with the files to be compared +while read name +do + if test -n "$right" + then + ls_list=$(git ls-tree $right "$name") + if test -n "$ls_list" + then + mkdir -p "$tmp/$right_dir/$(dirname "$name")" + git show "$right":"$name" >"$tmp/$right_dir/$name" || true + fi + elif test -n "$compare_staged" + then + ls_list=$(git ls-files -- "$name") + if test -n "$ls_list" + then + mkdir -p "$tmp/$right_dir/$(dirname "$name")" + git show :"$name" >"$tmp/$right_dir/$name" + fi + else + if test -e "$name" + then + mkdir -p "$tmp/$right_dir/$(dirname "$name")" + cp "$name" "$tmp/$right_dir/$name" + fi + fi +done < "$tmp/filelist" + +# Populate the tmp/left_dir directory with the files to be compared +while read name +do + if test -n "$left" + then + ls_list=$(git ls-tree $left "$name") + if test -n "$ls_list" + then + mkdir -p "$tmp/$left_dir/$(dirname "$name")" + git show "$left":"$name" >"$tmp/$left_dir/$name" || true + fi + else + if test -n "$compare_staged" + then + ls_list=$(git ls-tree HEAD "$name") + if test -n "$ls_list" + then + mkdir -p "$tmp/$left_dir/$(dirname "$name")" + git show HEAD:"$name" >"$tmp/$left_dir/$name" + fi + else + mkdir -p "$tmp/$left_dir/$(dirname "$name")" + git show :"$name" >"$tmp/$left_dir/$name" + fi + fi +done < "$tmp/filelist" + +LOCAL="$tmp/$left_dir" +REMOTE="$tmp/$right_dir" + +if test -n "$diff_tool" +then + export BASE + eval $diff_tool '"$LOCAL"' '"$REMOTE"' else - diff -urN a b + run_merge_tool "$merge_tool" false +fi + +# Copy files back to the working dir, if requested +if test -n "$copy_back" && test "$right_dir" = "working_tree" +then + cd "$start_dir" + git_top_dir=$(git rev-parse --show-toplevel) + find "$tmp/$right_dir" -type f | + while read file + do + cp "$file" "$git_top_dir/${file#$tmp/$right_dir/}" + done fi diff --git a/git-diffall.1 b/git-diffall.1 index fa1d55c..6c8302c 100644 --- a/git-diffall.1 +++ b/git-diffall.1 @@ -4,17 +4,31 @@ git-diffall \- Use a visual diff tool to show all differences .SH SYNOPSIS -\fBgit-diffall\fR [\fIPRE\fR] [\fIPOST\fR] +\fBgit-diffall\fR [\fI--cached\fR] [\fI--copy-back\fR] + [\fI-x|--extcmd=\fR] {0,2} [\fI-- *\fR] .SH "DESCRIPTION" .PP -\fBgit-diffall\fR performs a visual diff using kdiff3 between PRE and POST -of the current project. No arguments will show the differences between the -working directory and HEAD. If in the git config diff.tool is set, this -program is passed the name of the two temporary directories containing the -changed files of each revision. If diff.tool is not defined, the fall-back -is to diff. +\fBgit-diffall\fR performs a diff using the configured diff.tool or merge.tool. + + --cached Compare to the index rather than the working tree. + + --copy-back Copy files back to the working tree when the diff + tool exits (in case they were modified by the + user). This option is only valid if the diff + compared with the working tree. + + -x= + --extcmd= + Specify a custom command for viewing diffs. + git-diffall ignores the configured defaults and + runs $command $LOCAL $REMOTE when this option is + specified. Additionally, $BASE is set in the + environment. + +Thanks to Tim Henigan who created a newer version now +released with git contribs. Thanks to Thomas Rast for publishing this script online: http://thread.gmane.org/gmane.comp.version-control.git/124807 -- 2.39.2