{"thread":{"id":"23450","subject":"[PATCH] contrib/diffall: Add script to perform directory diff using external diff tool","startedAt":"2010-04-14T01:15:21Z","lastAt":"2010-04-14T01:15:21Z","messageCount":1,"participants":["Tim Henigan"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"139442","messageId":"4BC51729.7090906@gmail.com","threadId":"23450","inReplyTo":null,"subject":"[PATCH] contrib/diffall: Add script to perform directory diff using external diff tool","fromName":"Tim Henigan","fromEmail":"tim.henigan@gmail.com","sentAt":"2010-04-14T01:15:21Z","receivedAt":"2010-04-14T01:15:21Z","isPatch":true,"sender":{"key":"tim.henigan@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42022?v=4"},"body":"The existing 'git difftool' command allows the user to view git diffs\nusing an external diff tool.  However, if multiple files contain\ndifferences, a separate instance of the diff tool is launched for\neach one.\n\nThis script launches a single instance of the external diff tool\nand performs a directory diff between the specified revisions.\nThe before/after files are copied to a tmp directory to do this.\n\nThe 'diff.tool' configuration option must be set for this script\nto work.\n\nThe user interface matches the standard 'git diff' command.\n\nSigned-off-by: Tim Henigan <tim.henigan@gmail.com>\n---\n\nThis script is based on an example provided by Thomas Rast on the Git list [1].\n\nI tested with:\n  - msysgit and kdiff3 (the platform where I first needed this script)\n  - cygwin git and kdiff3\n  - git and meld\n\n[1] http://thread.gmane.org/gmane.comp.version-control.git/124807\n\n\n contrib/diffall/git-diffall |  159 +++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 159 insertions(+), 0 deletions(-)\n create mode 100755 contrib/diffall/git-diffall\n\ndiff --git a/contrib/diffall/git-diffall b/contrib/diffall/git-diffall\nnew file mode 100755\nindex 0000000..c24fba9\n--- /dev/null\n+++ b/contrib/diffall/git-diffall\n@@ -0,0 +1,159 @@\n+#!/bin/sh -e\n+# Copyright 2010, Tim Henigan <tim.henigan@gmail.com>\n+#\n+# Perform a directory diff between commits in the repository using\n+# the external diff tool specified in the 'diff.tool' configuration\n+# option.\n+\n+USAGE='<options> <commit>{0,2} -- <path>*\n+\n+--cached  Compare to the index rather than the working tree\n+commit    SHA1 of a commit\n+path      Limit the diff to the specified paths\n+'\n+\n+. git-sh-setup\n+\n+if [ -z $(git config --get diff.tool) ]; then\n+    echo \"Error: The 'diff.tool' configuration option must be set.\"\n+    usage\n+fi\n+\n+start_dir=$(pwd)\n+cd_to_toplevel      # needed to access tar utility\n+\n+# mktemp is not available on all platforms (missing from msysgit)\n+# Use a hard-coded tmp dir if it is not available\n+if [ -z $(which mktemp) ]; then\n+    tmp=/tmp/git-diffall-tmp\n+else\n+    tmp=\"$(mktemp -d)\"\n+fi\n+mkdir -p \"$tmp\" \"$tmp\"/a \"$tmp\"/b\n+\n+left=\n+right=\n+paths=\n+path_sep=\n+compare_staged=\n+common_anscestor=\n+\n+while test $# != 0; do\n+\tcase \"$1\" in\n+    -h|--h|--he|--hel|--help)\n+        usage\n+        ;;\n+    --cached)\n+        compare_staged=1\n+        ;;\n+    --)\n+        path_sep=1\n+        ;;\n+    -*)\n+        echo Invalid option: \"$1\"\n+        usage\n+        ;;\n+    *)\n+        # could be commit, commit range or path limiter\n+        case \"$1\" in\n+        *...*)\n+            left=${1%...*}\n+            right=${1#*...}\n+            common_anscestor=1\n+            ;;\n+        *..*)\n+            left=${1%..*}\n+            right=${1#*..}\n+            ;;\n+        *)\n+            if [ -n \"$path_sep\" ]; then\n+                if [ -z \"$paths\" ]; then\n+                    paths=$1\n+                else\n+                    paths=\"$paths $1\"\n+                fi\n+            elif [ -z \"$left\" ]; then\n+                left=$1\n+            elif [ -z \"$right\" ]; then\n+                right=$1\n+            else\n+                if [ -z \"$paths\" ]; then\n+                    paths=$1\n+                else\n+                    paths=\"$paths $1\"\n+                fi\n+            fi\n+            ;;\n+        esac\n+        ;;\n+    esac\n+    shift\n+done\n+\n+# Determine the set of files which changed\n+if [ -n \"$left\" ] && [ -n \"$right\" ]; then\n+    if [ -n \"$compare_staged\" ]; then\n+        usage\n+    elif [ -n \"$common_anscestor\" ]; then\n+        git diff --name-only \"$left\"...\"$right\" -- \"$paths\" > \"$tmp\"/filelist\n+    else\n+        git diff --name-only \"$left\" \"$right\" -- \"$paths\" > \"$tmp\"/filelist\n+    fi\n+elif [ -n \"$left\" ]; then\n+    if [ -n \"$compare_staged\" ]; then\n+        git diff --name-only --cached \"$left\" -- \"$paths\" > \"$tmp\"/filelist\n+    else\n+        git diff --name-only \"$left\" -- \"$paths\" > \"$tmp\"/filelist\n+    fi\n+else\n+    if [ -n \"$compare_staged\" ]; then\n+        git diff --name-only --cached -- \"$paths\" > \"$tmp\"/filelist\n+    else\n+        git diff --name-only -- \"$paths\" > \"$tmp\"/filelist\n+    fi\n+fi\n+\n+# Exit immediately if there are no diffs\n+if [ ! -s \"$tmp\"/filelist ]; then\n+    exit 0\n+fi\n+\n+# Populate the tmp/b directory with the files to be compared\n+if [ -n \"$right\" ]; then\n+\twhile read name; do\n+\t\tmkdir -p \"$tmp\"/b/\"$(dirname \"$name\")\"\n+\t\tgit show \"$right\":\"$name\" > \"$tmp\"/b/\"$name\"\n+\tdone < \"$tmp\"/filelist\n+elif [ -n \"$compare_staged\" ]; then\n+\twhile read name; do\n+\t\tmkdir -p \"$tmp\"/b/\"$(dirname \"$name\")\"\n+\t\tgit show :\"$name\" > \"$tmp\"/b/\"$name\"\n+\tdone < \"$tmp\"/filelist\n+else\n+    tar -c -T \"$tmp\"/filelist | (cd \"$tmp\"/b && tar -x)\n+fi\n+\n+# Populate the tmp/a directory with the files to be compared\n+while read name; do\n+\tmkdir -p \"$tmp\"/a/\"$(dirname \"$name\")\"\n+    if [ -n \"$left\" ]; then\n+\t    git show \"$left\":\"$name\" > \"$tmp\"/a/\"$name\"\n+    else\n+        if [ -n \"$compare_staged\" ]; then\n+            git show HEAD:\"$name\" > \"$tmp\"/a/\"$name\"\n+        else\n+            git show :\"$name\" > \"$tmp\"/a/\"$name\"\n+        fi\n+    fi\n+done < \"$tmp\"/filelist\n+\n+cd \"$tmp\"\n+$(git config --get diff.tool) a b\n+\n+# On exit, remove the tmp directory\n+cleanup () {\n+    cd \"$start_dir\"\n+\trm -rf \"$tmp\"\n+}\n+\n+trap cleanup EXIT\n-- \n1.7.0.3.291.g5e4f6.dirty\n"}]}