{"thread":{"id":"284","subject":"Re: [GIT PATCH] Selective diff-tree","startedAt":"2005-04-24T05:09:02Z","lastAt":"2005-04-27T01:09:57Z","messageCount":22,"participants":["Linus Torvalds","David Woodhouse","Junio C Hamano","Nicolas Pitre"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"1491","messageId":"Pine.LNX.4.58.0504232202340.19877@ppc970.osdl.org","threadId":"284","inReplyTo":"1113400651.20848.135.camel@hades.cambridge.redhat.com","subject":"Re: [GIT PATCH] Selective diff-tree","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-04-24T05:09:02Z","receivedAt":"2005-04-24T05:09:02Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 13 Apr 2005, David Woodhouse wrote:\n>\n> The patch below makes diff-tree take extra arguments, specifying the\n> files or directories which should be considered 'interesting'. Changes\n> in uninteresting directories are not reported; we don't even bother to\n> recurse down into those trees.\n\nDavid, I took your patch, updated it for some changes in diff-tree, and\nthen totally rewrote (and simplified) your testing for \"interesting\".\nThere was no reason to consider \"/\" special, as it falls out of the other\ncases quite naturally.\n\nIt passes all the tests I threw at it, but they weren't exhaustive (but I \ndo think I tested the border cases). Mind double-checking that it works \nfor your cases too?\n\n\t\tLinus\n"},{"id":"1500","messageId":"1114323914.3419.70.camel@localhost.localdomain","threadId":"284","inReplyTo":"Pine.LNX.4.58.0504232202340.19877@ppc970.osdl.org","subject":"Re: [GIT PATCH] Selective diff-tree","fromName":"David Woodhouse","fromEmail":"dwmw2@infradead.org","sentAt":"2005-04-24T06:25:13Z","receivedAt":"2005-04-24T06:25:13Z","isPatch":true,"sender":{"key":"dwmw2@infradead.org","avatar":"https://gravatar.com/avatar/7afd4f07e0cf7d7e046ae2d23678296b37777c96488e6f3451e78a5514154ebd?d=mp&s=160"},"body":"On Sat, 2005-04-23 at 22:09 -0700, Linus Torvalds wrote:\n> It passes all the tests I threw at it, but they weren't exhaustive (but I \n> do think I tested the border cases). Mind double-checking that it works \n> for your cases too?\n\nIt seems to work at least as well as my version did -- which is to say\nit's fine for the handful of test cases I tried, which is probably about\nthe same as what you did.\n\nOn the other hand, my gitfilelog.sh is fairly fundamentally flawed and\nprobably needs rewriting in C based on rev-tree.\n\n-- \ndwmw2\n\n"},{"id":"1505","messageId":"7vbr84tyfd.fsf@assigned-by-dhcp.cox.net","threadId":"284","inReplyTo":"Pine.LNX.4.58.0504232202340.19877@ppc970.osdl.org","subject":"Re: [GIT PATCH] Selective diff-tree","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-24T07:40:38Z","receivedAt":"2005-04-24T07:40:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Is either of you planning to do the same for diff-cache?\n\n"},{"id":"1529","messageId":"Pine.LNX.4.58.0504241013110.15879@ppc970.osdl.org","threadId":"284","inReplyTo":"1114323914.3419.70.camel@localhost.localdomain","subject":"Re: [GIT PATCH] Selective diff-tree","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-04-24T17:15:37Z","receivedAt":"2005-04-24T17:15:37Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 24 Apr 2005, David Woodhouse wrote:\n> \n> On the other hand, my gitfilelog.sh is fairly fundamentally flawed and\n> probably needs rewriting in C based on rev-tree.\n\nYeah, I think I'll make the \"tree-diff\" functions be available to others,\nsince they are actually _very_ cheap, and it's a bit sad to have to\nexecute a whole new process just to get a tree-diff. Then writing some\nrev-list thing that just does tree-diff between different versions should\nbe trivial and quite efficient for finding things like \"when did this set\nof files/subdirectory last change\".\n\nWhich definitely is very useful information.\n\n\t\tLinus\n"},{"id":"1530","messageId":"Pine.LNX.4.58.0504241016390.15879@ppc970.osdl.org","threadId":"284","inReplyTo":"7vbr84tyfd.fsf@assigned-by-dhcp.cox.net","subject":"Re: [GIT PATCH] Selective diff-tree","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-04-24T17:20:03Z","receivedAt":"2005-04-24T17:20:03Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 24 Apr 2005, Junio C Hamano wrote:\n>\n> Is either of you planning to do the same for diff-cache?\n\nI wasn't. I don't think it's nearly as relevant for diff-cache, since \ndiff-cache is never run thousands of times.\n\nIOW, with diff-cache you can just do\n\n\tdiff-cache <tree> | grep \"interesting\"\n\nand you're done.\n\nDiff-tree is different, simply because diff-tree is the way you find out\nwhich files changed between two revisions, so if you search for \"when did\nthis file change\" you may well have to do _thousands_ of different\ndiff-tree's. That's why pruning the diff-tree output is important: it\nmakes diff-tree _much_ cheaper.\n\ndiff-cache usually doesn't make sense to do against more than one or two\nthrees (the parent, and after a merge but before you commit maybe the\nparent_s_).\n\n\t\tLinus\n"},{"id":"1595","messageId":"7v1x8zsamn.fsf_-_@assigned-by-dhcp.cox.net","threadId":"284","inReplyTo":"Pine.LNX.4.58.0504232202340.19877@ppc970.osdl.org","subject":"[PATCH 0/2] diff-tree/diff-cache helper","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-25T05:12:16Z","receivedAt":"2005-04-25T05:12:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"I use a set of small scripts [*1*] directly on top of the core\ngit, which needed to make patches out of diff-tree and\ndiff-cache output.  Its output is compatible with what show-diff\nproduces.\n\nSince this helper program would be generally useful for other\nwrapper layer programs like Cogito, I am submitting it in two\nparts.  The first part is to rip out the external diff program\ninterface part out of show-diff.c and moving it into a common\nlibrary.  The second part introduces the diff-tree-helper\nprogram.\n\n[Footnotes]\n\n*1* This is found at http://members.cox.net/junkio/\n\n"},{"id":"1596","messageId":"7vvf6bqvwp.fsf_-_@assigned-by-dhcp.cox.net","threadId":"284","inReplyTo":"7v1x8zsamn.fsf_-_@assigned-by-dhcp.cox.net","subject":"[PATCH 1/2] Split external diff command interface to a separate file.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-25T05:15:34Z","receivedAt":"2005-04-25T05:15:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"With this patch, the non-core'ish part of show-diff command that\ninvokes an external \"diff\" comand to obtain patches is split\ninto a separate file.  The next patch will introduce a new\ncommand, diff-tree-helper, which uses this common diff interface\nto format diff-tree and diff-cache output into a patch form.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\nMakefile    |    4 ++\ndiff.c      |  106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\ndiff.h      |   17 +++++++++\nshow-diff.c |  101 +--------------------------------------------------------\n4 files changed, 130 insertions(+), 98 deletions(-)\n\n--- k/Makefile\n+++ l/Makefile\n@@ -27,6 +27,9 @@ LIB_OBJS=read-cache.o sha1_file.o usage.\n LIB_FILE=libgit.a\n LIB_H=cache.h object.h\n \n+LIB_H += diff.h\n+LIB_OBJS += diff.o\n+\n LIBS = $(LIB_FILE)\n LIBS += -lz\n \n@@ -66,6 +69,7 @@ checkout-cache.o: $(LIB_H)\n commit.o: $(LIB_H)\n commit-tree.o: $(LIB_H)\n convert-cache.o: $(LIB_H)\n+diff.o: $(LIB_H)\n diff-cache.o: $(LIB_H)\n diff-tree.o: $(LIB_H)\n fsck-cache.o: $(LIB_H)\n--- k/diff.c\n+++ l/diff.c\n@@ -0,0 +1,106 @@\n+#include \"cache.h\"\n+#include \"diff.h\"\n+\n+static char *diff_cmd = \"diff -L 'k/%s' -L 'l/%s' \";\n+static char *diff_opts = \"-p -u\";\n+static char *diff_arg_forward  = \" - '%s'\";\n+static char *diff_arg_reverse  = \" '%s' -\";\n+\n+void prepare_diff_cmd(void)\n+{\n+\t/*\n+\t * Default values above are meant to match the\n+\t * Linux kernel development style.  Examples of\n+\t * alternative styles you can specify via environment\n+\t * variables are:\n+\t *\n+\t * GIT_DIFF_CMD=\"diff -L '%s' -L '%s'\"\n+\t * GIT_DIFF_OPTS=\"-c\";\n+\t */\n+\tdiff_cmd = getenv(\"GIT_DIFF_CMD\") ? : diff_cmd;\n+\tdiff_opts = getenv(\"GIT_DIFF_OPTS\") ? : diff_opts;\n+}\n+\n+/* Help to copy the thing properly quoted for the shell safety.\n+ * any single quote is replaced with '\\'', and the caller is\n+ * expected to enclose the result within a single quote pair.\n+ *\n+ * E.g.\n+ *  original     sq_expand     result\n+ *  name     ==> name      ==> 'name'\n+ *  a b      ==> a b       ==> 'a b'\n+ *  a'b      ==> a'\\''b    ==> 'a'\\''b'\n+ */\n+static char *sq_expand(const char *src)\n+{\n+\tstatic char *buf = NULL;\n+\tint cnt, c;\n+\tconst char *cp;\n+\tchar *bp;\n+\n+\t/* count bytes needed to store the quoted string. */ \n+\tfor (cnt = 1, cp = src; *cp; cnt++, cp++)\n+\t\tif (*cp == '\\'')\n+\t\t\tcnt += 3;\n+\n+\tif (! (buf = malloc(cnt)))\n+\t    return buf;\n+\tbp = buf;\n+\twhile ((c = *src++)) {\n+\t\tif (c != '\\'')\n+\t\t\t*bp++ = c;\n+\t\telse {\n+\t\t\tbp = strcpy(bp, \"'\\\\''\");\n+\t\t\tbp += 4;\n+\t\t}\n+\t}\n+\t*bp = 0;\n+\treturn buf;\n+}\n+\n+void show_differences(const char *name, /* filename on the filesystem */\n+\t\t      const char *label, /* diff label to use */\n+\t\t      void *old_contents, /* contents in core */\n+\t\t      unsigned long long old_size, /* size in core */\n+\t\t      int reverse /* 0: diff core file\n+\t\t\t\t     1: diff file core */)\n+{\n+\tFILE *f;\n+\tchar *name_sq = sq_expand(name);\n+\tconst char *label_sq = (name != label) ? sq_expand(label) : name_sq;\n+\tchar *diff_arg = reverse ? diff_arg_reverse : diff_arg_forward;\n+\tint cmd_size = strlen(name_sq) + strlen(label_sq) * 2 +\n+\t\tstrlen(diff_cmd) + strlen(diff_opts) + strlen(diff_arg);\n+\tchar *cmd = malloc(cmd_size);\n+\tint next_at;\n+\n+\tfflush(stdout);\n+\tnext_at = snprintf(cmd, cmd_size, diff_cmd, label_sq, label_sq);\n+\tnext_at += snprintf(cmd+next_at, cmd_size-next_at, \"%s\", diff_opts);\n+\tnext_at += snprintf(cmd+next_at, cmd_size-next_at, diff_arg, name_sq);\n+\tf = popen(cmd, \"w\");\n+\tif (old_size)\n+\t\tfwrite(old_contents, old_size, 1, f);\n+\tpclose(f);\n+\tif (label_sq != name_sq)\n+\t\tfree((void*)label_sq); /* constness */\n+\tfree(name_sq);\n+\tfree(cmd);\n+}\n+\n+void show_diff_empty(const unsigned char *sha1,\n+\t\t     const char *name,\n+\t\t     int reverse)\n+{\n+\tchar *old;\n+\tunsigned long int size;\n+\tunsigned char type[20];\n+\n+\told = read_sha1_file(sha1, type, &size);\n+\tif (! old) {\n+\t\terror(\"unable to read blob object for %s (%s)\", name,\n+\t\t      sha1_to_hex(sha1));\n+\t\treturn;\n+\t}\n+\tshow_differences(\"/dev/null\", name, old, size, reverse);\n+}\n--- k/diff.h\n+++ l/diff.h\n@@ -0,0 +1,17 @@\n+#ifndef DIFF_H\n+#define DIFF_H\n+\n+extern void prepare_diff_cmd(void);\n+\n+extern void show_differences(const char *name, /* filename on the filesystem */\n+\t\t\t     const char *label, /* diff label to use */\n+\t\t\t     void *old_contents, /* contents in core */\n+\t\t\t     unsigned long long old_size, /* size in core */\n+\t\t\t     int reverse /* 0: diff core file\n+\t\t\t\t\t    1: diff file core */);\n+\n+extern void show_diff_empty(const unsigned char *sha1,\n+\t\t\t    const char *name,\n+\t\t\t    int reverse);\n+\n+#endif /* DIFF_H */\n--- k/show-diff.c\n+++ l/show-diff.c\n@@ -4,103 +4,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include \"cache.h\"\n-\n-static char *diff_cmd = \"diff -L 'a/%s' -L 'b/%s' \";\n-static char *diff_opts = \"-p -u\";\n-static char *diff_arg_forward  = \" - '%s'\";\n-static char *diff_arg_reverse  = \" '%s' -\";\n-\n-static void prepare_diff_cmd(void)\n-{\n-\t/*\n-\t * Default values above are meant to match the\n-\t * Linux kernel development style.  Examples of\n-\t * alternative styles you can specify via environment\n-\t * variables are:\n-\t *\n-\t * GIT_DIFF_CMD=\"diff -L '%s' -L '%s'\"\n-\t * GIT_DIFF_OPTS=\"-c\";\n-\t */\n-\tdiff_cmd = getenv(\"GIT_DIFF_CMD\") ? : diff_cmd;\n-\tdiff_opts = getenv(\"GIT_DIFF_OPTS\") ? : diff_opts;\n-}\n-\n-/* Help to copy the thing properly quoted for the shell safety.\n- * any single quote is replaced with '\\'', and the caller is\n- * expected to enclose the result within a single quote pair.\n- *\n- * E.g.\n- *  original     sq_expand     result\n- *  name     ==> name      ==> 'name'\n- *  a b      ==> a b       ==> 'a b'\n- *  a'b      ==> a'\\''b    ==> 'a'\\''b'\n- */\n-static char *sq_expand(char *src)\n-{\n-\tstatic char *buf = NULL;\n-\tint cnt, c;\n-\tchar *cp;\n-\n-\t/* count bytes needed to store the quoted string. */ \n-\tfor (cnt = 1, cp = src; *cp; cnt++, cp++)\n-\t\tif (*cp == '\\'')\n-\t\t\tcnt += 3;\n-\n-\tif (! (buf = malloc(cnt)))\n-\t    return buf;\n-\tcp = buf;\n-\twhile ((c = *src++)) {\n-\t\tif (c != '\\'')\n-\t\t\t*cp++ = c;\n-\t\telse {\n-\t\t\tcp = strcpy(cp, \"'\\\\''\");\n-\t\t\tcp += 4;\n-\t\t}\n-\t}\n-\t*cp = 0;\n-\treturn buf;\n-}\n-\n-static void show_differences(char *name, char *label, void *old_contents,\n-\t\t\t     unsigned long long old_size, int reverse)\n-{\n-\tFILE *f;\n-\tchar *name_sq = sq_expand(name);\n-\tchar *label_sq = (name != label) ? sq_expand(label) : name_sq;\n-\tchar *diff_arg = reverse ? diff_arg_reverse : diff_arg_forward;\n-\tint cmd_size = strlen(name_sq) + strlen(label_sq) * 2 +\n-\t\tstrlen(diff_cmd) + strlen(diff_opts) + strlen(diff_arg);\n-\tchar *cmd = malloc(cmd_size);\n-\tint next_at;\n-\n-\tfflush(stdout);\n-\tnext_at = snprintf(cmd, cmd_size, diff_cmd, label_sq, label_sq);\n-\tnext_at += snprintf(cmd+next_at, cmd_size-next_at, \"%s\", diff_opts);\n-\tnext_at += snprintf(cmd+next_at, cmd_size-next_at, diff_arg, name_sq);\n-\tf = popen(cmd, \"w\");\n-\tif (old_size)\n-\t\tfwrite(old_contents, old_size, 1, f);\n-\tpclose(f);\n-\tif (label_sq != name_sq)\n-\t\tfree(label_sq);\n-\tfree(name_sq);\n-\tfree(cmd);\n-}\n-\n-static void show_diff_empty(struct cache_entry *ce, int reverse)\n-{\n-\tchar *old;\n-\tunsigned long int size;\n-\tunsigned char type[20];\n-\n-\told = read_sha1_file(ce->sha1, type, &size);\n-\tif (! old) {\n-\t\terror(\"unable to read blob object for %s (%s)\", ce->name,\n-\t\t      sha1_to_hex(ce->sha1));\n-\t\treturn;\n-\t}\n-\tshow_differences(\"/dev/null\", ce->name, old, size, reverse);\n-}\n+#include \"diff.h\"\n \n static const char *show_diff_usage = \"show-diff [-q] [-s] [-z] [paths...]\";\n \n@@ -183,7 +87,8 @@ int main(int argc, char **argv)\n \t\t\telse {\n \t\t\t\tprintf(\"%s: %s\\n\", ce->name, strerror(errno));\n \t\t\t\tif (errno == ENOENT)\n-\t\t\t\t\tshow_diff_empty(ce, reverse);\n+\t\t\t\t\tshow_diff_empty(ce->sha1, ce->name,\n+\t\t\t\t\t\t\treverse);\n \t\t\t}\n \t\t\tcontinue;\n \t\t}\n\n"},{"id":"1597","messageId":"7vll77qvti.fsf_-_@assigned-by-dhcp.cox.net","threadId":"284","inReplyTo":"7v1x8zsamn.fsf_-_@assigned-by-dhcp.cox.net","subject":"[PATCH 2/2] Introduce diff-tree-helper.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-25T05:17:29Z","receivedAt":"2005-04-25T05:17:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This patch introduces a new program, diff-tree-helper.  It reads\noutput from diff-cache and diff-tree, and produces a patch file.\nThe diff format customization can be done the same way the\nshow-diff uses; the same external diff interface introduced by\nthe previous patch to drive diff from show-diff is used so this\nis not surprising.\n\nIt is used like the following examples:\n\n   $ diff-cache --cached -z <tree> | diff-tree-helper -z -R paths...\n   $ diff-tree -r -z <tree1> <tree2> | diff-tree-helper -z paths...\n\n - As usual, the use of the -z flag is recommended in the script\n   to pass NUL-terminated filenames through the pipe between\n   commands.\n\n - The -R flag is used to generate reverse diff.  It does not\n   matter for diff-tree case, but it is sometimes useful to get\n   a patch in the desired direction out of diff-cache.\n\n - The paths parameters are used to restrict the paths that\n   appears in the output.  Again this is useful to use with\n   diff-cache, which, unlike diff-tree, does not take such paths\n   restriction parameters.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\nMakefile           |    6 -\ndiff-tree-helper.c |  302 +++++++++++++++++++++++++++++++++++++++++++++++++++++\nstrbuf.c           |   43 +++++++\nstrbuf.h           |   13 ++\n4 files changed, 363 insertions(+), 1 deletion(-)\n\n--- k/Makefile\n+++ l/Makefile\n@@ -16,7 +16,8 @@ AR=ar\n PROG=   update-cache show-diff init-db write-tree read-tree commit-tree \\\n \tcat-file fsck-cache checkout-cache diff-tree rev-tree show-files \\\n \tcheck-files ls-tree merge-base merge-cache unpack-file git-export \\\n-\tdiff-cache convert-cache http-pull rpush rpull rev-list\n+\tdiff-cache convert-cache http-pull rpush rpull rev-list \\\n+\tdiff-tree-helper\n \n all: $(PROG)\n \n@@ -27,6 +28,9 @@ LIB_OBJS=read-cache.o sha1_file.o usage.\n LIB_FILE=libgit.a\n LIB_H=cache.h object.h\n \n+LIB_H += strbuf.h\n+LIB_OBJS += strbuf.o\n+\n LIB_H += diff.h\n LIB_OBJS += diff.o\n \n--- k/diff-tree-helper.c\n+++ l/diff-tree-helper.c\n@@ -0,0 +1,302 @@\n+#include \"cache.h\"\n+#include \"strbuf.h\"\n+#include \"diff.h\"\n+\n+static int matches_pathspec(const char *name, char **spec, int cnt)\n+{\n+\tint i;\n+\tint namelen = strlen(name);\n+\tfor (i = 0; i < cnt; i++) {\n+\t\tint speclen = strlen(spec[i]);\n+\t\tif (! strncmp(spec[i], name, speclen) &&\n+\t\t    speclen <= namelen &&\n+\t\t    (name[speclen] == 0 ||\n+\t\t     name[speclen] == '/'))\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n+static int parse_oneside_change(const char *cp, unsigned char *sha1,\n+\t\t\t\tchar *path) {\n+\tint ch;\n+\twhile ((ch = *cp) && '0' <= ch && ch <= '7')\n+\t\tcp++; /* skip mode bits */\n+\tif (strncmp(cp, \"\\tblob\\t\", 6))\n+\t\treturn -1;\n+\tcp += 6;\n+\tif (get_sha1_hex(cp, sha1))\n+\t\treturn -1;\n+\tcp += 40;\n+\tif (*cp++ != '\\t')\n+\t\treturn -1;\n+\tstrcpy(path, cp);\n+\treturn 0;\n+}\n+\n+#define STATUS_CACHED    0 /* cached and sha1 valid */\n+#define STATUS_ABSENT    1 /* diff-tree says old removed or new added */\n+#define STATUS_UNCACHED  2 /* diff-cache output: read from working tree */\n+\n+static int parse_diff_tree_output(const char *buf,\n+\t\t\t\t  unsigned char *old_sha1,\n+\t\t\t\t  int *old_status,\n+\t\t\t\t  unsigned char *new_sha1,\n+\t\t\t\t  int *new_status,\n+\t\t\t\t  char *path) {\n+\tconst char *cp = buf;\n+\tint ch;\n+\tstatic unsigned char null_sha[20] = { 0, };\n+\n+\tswitch (*cp++) {\n+\tcase '+':\n+\t\t*old_status = STATUS_ABSENT;\n+\t\t*new_status = (memcmp(new_sha1, null_sha, sizeof(null_sha)) ?\n+\t\t\t       STATUS_CACHED : STATUS_UNCACHED);\n+\t\treturn parse_oneside_change(cp, new_sha1, path);\n+\tcase '-':\n+\t\t*new_status = STATUS_ABSENT;\n+\t\t*old_status = (memcmp(old_sha1, null_sha, sizeof(null_sha)) ?\n+\t\t\t       STATUS_CACHED : STATUS_UNCACHED);\n+\t\treturn parse_oneside_change(cp, old_sha1, path);\n+\tcase '*':\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -1;\n+\t}\n+\t\n+\t/* This is for '*' entries */\n+\twhile ((ch = *cp) && ('0' <= ch && ch <= '7'))\n+\t\tcp++; /* skip mode bits */\n+\tif (strncmp(cp, \"->\", 2))\n+\t\treturn -1;\n+\tcp += 2;\n+\twhile ((ch = *cp) && ('0' <= ch && ch <= '7'))\n+\t\tcp++; /* skip mode bits */\n+\tif (strncmp(cp, \"\\tblob\\t\", 6))\n+\t\treturn -1;\n+\tcp += 6;\n+\tif (get_sha1_hex(cp, old_sha1))\n+\t\treturn -1;\n+\tcp += 40;\n+\tif (strncmp(cp, \"->\", 2))\n+\t\treturn -1;\n+\tcp += 2;\n+\tif (get_sha1_hex(cp, new_sha1))\n+\t\treturn -1;\n+\tcp += 40;\n+\tif (*cp++ != '\\t')\n+\t\treturn -1;\n+\tstrcpy(path, cp);\n+\t*old_status = (memcmp(old_sha1, null_sha, sizeof(null_sha)) ?\n+\t\t       STATUS_CACHED : STATUS_UNCACHED);\n+\t*new_status = (memcmp(new_sha1, null_sha, sizeof(null_sha)) ?\n+\t\t       STATUS_CACHED : STATUS_UNCACHED);\n+\treturn 0;\n+}\n+\n+static int sha1err(const char *path, const unsigned char *sha1)\n+{\n+\treturn error(\"diff-tree-helper: unable to read sha1 file of %s (%s)\",\n+\t\t     path, sha1_to_hex(sha1));\n+}\n+\n+static int fserr(const char *path)\n+{\n+\treturn error(\"diff-tree-helper: unable to read file %s\", path);\n+}\n+\n+static char *map_whole_file(const char *path, unsigned long *size) {\n+\tint fd;\n+\tstruct stat st;\n+\tvoid *buf;\n+\n+\tif ((fd = open(path, O_RDONLY)) < 0) {\n+\t\terror(\"diff-tree-helper: unable to read file %s\", path);\n+\t\treturn 0;\n+\t}\n+\tif (fstat(fd, &st) < 0) {\n+\t\tclose(fd);\n+\t\terror(\"diff-tree-helper: unable to stat file %s\", path);\n+\t\treturn 0;\n+\t}\n+\t*size = st.st_size;\n+\tbuf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);\n+\tclose(fd);\n+\treturn buf;\n+}\n+\n+static int show_diff(const unsigned char *old_sha1, int old_status,\n+\t\t     const unsigned char *new_sha1, int new_status,\n+\t\t     const char *path, int reverse_diff)\n+{\n+\tchar other[PATH_MAX];\n+\tunsigned long size;\n+\tchar type[20];\n+\tint fd;\n+\tint reverse;\n+\tvoid *blob = 0;\n+\tconst char *fs = 0;\n+\tint need_unmap = 0;\n+\tint need_unlink = 0;\n+\n+\n+\tswitch (old_status) {\n+\tcase STATUS_CACHED:\n+\t\tblob = read_sha1_file(old_sha1, type, &size);\n+\t\tif (! blob)\n+\t\t\treturn sha1err(path, old_sha1);\n+\t\t\t\n+\t\tswitch (new_status) {\n+\t\tcase STATUS_CACHED:\n+\t\t\tstrcpy(other, \".diff_tree_helper_XXXXXX\");\n+\t\t\tfd = mkstemp(other);\n+\t\t\tif (fd < 0)\n+\t\t\t\tdie(\"unable to create temp-file\");\n+\t\t\tif (write(fd, blob, size) != size)\n+\t\t\t\tdie(\"unable to write temp-file\");\n+\t\t\tclose(fd);\n+\t\t\tfree(blob);\n+\n+\t\t\tblob = read_sha1_file(new_sha1, type, &size);\n+\t\t\tif (! blob)\n+\t\t\t\treturn sha1err(path, new_sha1);\n+\n+\t\t\tneed_unlink = 1;\n+\t\t\t/* new = blob, old = fs */\n+\t\t\treverse = !reverse_diff;\n+\t\t\tfs = other;\n+\t\t\tbreak;\n+\n+\t\tcase STATUS_ABSENT:\n+\t\tcase STATUS_UNCACHED:\n+\t\t\tfs = ((new_status == STATUS_ABSENT) ?\n+\t\t\t      \"/dev/null\" : path);\n+\t\t\treverse = reverse_diff;\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+ \t\t\treverse = reverse_diff;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase STATUS_ABSENT:\n+\t\tswitch (new_status) {\n+\t\tcase STATUS_CACHED:\n+\t\t\tblob = read_sha1_file(new_sha1, type, &size);\n+\t\t\tif (! blob)\n+\t\t\t\treturn sha1err(path, new_sha1);\n+\t\t\t/* old = fs, new = blob */\n+\t\t\tfs = \"/dev/null\";\n+\t\t\treverse = !reverse_diff;\n+\t\t\tbreak;\n+\n+\t\tcase STATUS_ABSENT:\n+\t\t\treturn error(\"diff-tree-helper: absent from both old and new?\");\n+\t\tcase STATUS_UNCACHED:\n+\t\t\tfs = path;\n+\t\t\tblob = strdup(\"\");\n+\t\t\tsize = 0;\n+\t\t\t/* old = blob, new = fs */\n+\t\t\treverse = reverse_diff;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treverse = reverse_diff;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase STATUS_UNCACHED:\n+\t\tfs = path; /* old = fs, new = blob */\n+\t\treverse = !reverse_diff;\n+\n+\t\tswitch (new_status) {\n+\t\tcase STATUS_CACHED:\n+\t\t\tblob = read_sha1_file(new_sha1, type, &size);\n+\t\t\tif (! blob)\n+\t\t\t\treturn sha1err(path, new_sha1);\n+\t\t\tbreak;\n+\n+\t\tcase STATUS_ABSENT:\n+\t\t\tblob = strdup(\"\");\n+\t\t\tsize = 0;\n+\t\t\tbreak;\n+\n+\t\tcase STATUS_UNCACHED:\n+\t\t\t/* old = fs */\n+\t\t\tblob = map_whole_file(path, &size);\n+\t\t\tif (! blob)\n+\t\t\t\treturn fserr(path);\n+\t\t\tneed_unmap = 1;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treverse = reverse_diff;\n+\t\t}\n+\t\tbreak;\n+\n+\tdefault:\n+\t\treverse = reverse_diff;\n+\t}\n+\t\n+\tif (fs)\n+\t\tshow_differences(fs,\n+\t\t\t\t path, /* label */\n+\t\t\t\t blob,\n+\t\t\t\t size,\n+\t\t\t\t reverse /* 0: diff blob fs\n+\t\t\t\t\t    1: diff fs blob */);\n+\n+\tif (need_unlink)\n+\t\tunlink(other);\n+\tif (need_unmap && blob)\n+\t\tmunmap(blob, size);\n+\telse\n+\t\tfree(blob);\n+\treturn 0;\n+}\n+\n+static const char *diff_tree_helper_usage =\n+\"diff-tree-helper [-R] [-z] paths...\";\n+\n+int main(int ac, char **av) {\n+\tstruct strbuf sb;\n+\tint reverse_diff = 0;\n+\tint line_termination = '\\n';\n+\n+\tstrbuf_init(&sb);\n+\n+\twhile (1 < ac && av[1][0] == '-') {\n+\t\tif (av[1][1] == 'R')\n+\t\t\treverse_diff = 1;\n+\t\telse if (av[1][1] == 'z')\n+\t\t\tline_termination = 0;\n+\t\telse\n+\t\t\tusage(diff_tree_helper_usage);\n+\t\tac--; av++;\n+\t}\n+\t/* the remaining parameters are paths patterns */\n+\n+\tprepare_diff_cmd();\n+\n+\twhile (1) {\n+\t\tint old_status, new_status;\n+\t\tunsigned char old_sha1[20], new_sha1[20];\n+\t\tchar path[PATH_MAX];\n+\t\tread_line(&sb, stdin, line_termination);\n+\t\tif (sb.eof)\n+\t\t\tbreak;\n+\t\tif (parse_diff_tree_output(sb.buf,\n+\t\t\t\t\t   old_sha1, &old_status,\n+\t\t\t\t\t   new_sha1, &new_status,\n+\t\t\t\t\t   path)) {\n+\t\t\tfprintf(stderr, \"cannot parse %s\\n\", sb.buf);\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (1 < ac && ! matches_pathspec(path, av+1, ac-1))\n+\t\t\tcontinue;\n+\n+\t\tshow_diff(old_sha1, old_status,\n+\t\t\t  new_sha1, new_status,\n+\t\t\t  path, reverse_diff);\n+\t}\n+\treturn 0;\n+}\n--- k/strbuf.c\n+++ l/strbuf.c\n@@ -0,0 +1,43 @@\n+#include <stdio.h>\n+#include <stdlib.h>\n+#include \"strbuf.h\"\n+\n+void strbuf_init(struct strbuf *sb) {\n+\tsb->buf = 0;\n+\tsb->eof = sb->alloc = sb->len = 0;\n+}\n+\n+static void strbuf_begin(struct strbuf *sb) {\n+\tfree(sb->buf);\n+\tstrbuf_init(sb);\n+}\n+\n+static void inline strbuf_add(struct strbuf *sb, int ch) {\n+\tif (sb->alloc <= sb->len) {\n+\t\tsb->alloc = sb->alloc * 3 / 2 + 16;\n+\t\tsb->buf = realloc(sb->buf, sb->alloc);\n+\t}\n+\tsb->buf[sb->len++] = ch;\n+}\n+\n+static void strbuf_end(struct strbuf *sb) {\n+\tstrbuf_add(sb, 0);\n+}\n+\n+void read_line(struct strbuf *sb, FILE *fp, int term) {\n+\tint ch;\n+\tstrbuf_begin(sb);\n+\tif (feof(fp)) {\n+\t\tsb->eof = 1;\n+\t\treturn;\n+\t}\n+\twhile ((ch = fgetc(fp)) != EOF) {\n+\t\tif (ch == term)\n+\t\t\tbreak;\n+\t\tstrbuf_add(sb, ch);\n+\t}\n+\tif (sb->len == 0)\n+\t\tsb->eof = 1;\n+\tstrbuf_end(sb);\n+}\n+\n--- k/strbuf.h\n+++ l/strbuf.h\n@@ -0,0 +1,13 @@\n+#ifndef STRBUF_H\n+#define STRBUF_H\n+struct strbuf {\n+\tint alloc;\n+\tint len;\n+\tint eof;\n+\tunsigned char *buf;\n+};\n+\n+extern void strbuf_init(struct strbuf *);\n+extern void read_line(struct strbuf *, FILE *, int);\n+\n+#endif /* STRBUF_H */\n\n"},{"id":"1688","messageId":"Pine.LNX.4.58.0504251832480.18901@ppc970.osdl.org","threadId":"284","inReplyTo":"7v1x8zsamn.fsf_-_@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 0/2] diff-tree/diff-cache helper","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-04-26T01:38:05Z","receivedAt":"2005-04-26T01:38:05Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 24 Apr 2005, Junio C Hamano wrote:\n>\n> I use a set of small scripts [*1*] directly on top of the core\n> git, which needed to make patches out of diff-tree and\n> diff-cache output.  Its output is compatible with what show-diff\n> produces.\n\nGood, applied.\n\nThis also makes me think that we should just make \"show-diff\" show the\nsame format, at which point show-diff actually matches all the other\ntools, and it is likely to make show-diff more useful to boot.\n\nThe thing I personally use \"show-diff\" for these days is actually just to\ncheck whether I have anything dirty in my tree, and then it would actually\nbe preferable to just get the filenaname printout (in the same old\n\"diff-cache\" format) rather than the full diff.\n\nMaybe rename the \"show-diff\" command to be \"cache-diff\", and if somebody\nwants the old \"show-diff\" thing, just have a script that does\n\n\t#!/bin/sh\n\tcache-diff | diff-tree-helper\n\nand nothing more.\n\nTalking about renaming, at some point we really should prepend \"git-\" to \nall the git commands. I didn't want to do the extra typing when I started \nout and was unsure about the name, but hey, by now we really should.\n\nJunio, what do you think?\n\n\t\tLinus\n"},{"id":"1692","messageId":"Pine.LNX.4.62.0504252159590.26129@localhost.localdomain","threadId":"284","inReplyTo":"Pine.LNX.4.58.0504251832480.18901@ppc970.osdl.org","subject":"Re: [PATCH 0/2] diff-tree/diff-cache helper","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2005-04-26T02:08:07Z","receivedAt":"2005-04-26T02:08:07Z","isPatch":true,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Mon, 25 Apr 2005, Linus Torvalds wrote:\n\n> This also makes me think that we should just make \"show-diff\" show the\n> same format, at which point show-diff actually matches all the other\n> tools, and it is likely to make show-diff more useful to boot.\n> \n> The thing I personally use \"show-diff\" for these days is actually just to\n> check whether I have anything dirty in my tree, and then it would actually\n> be preferable to just get the filenaname printout (in the same old\n> \"diff-cache\" format) rather than the full diff.\n\nThat makes a lot of sense.  And I think that path filtering in diff-tree \nshould be factored out and supported into all of the diff-* commands as \nwell (not necessarily in diff-tree-helper).\n\n\nNicolas\n"},{"id":"1722","messageId":"7vll76ouk0.fsf@assigned-by-dhcp.cox.net","threadId":"284","inReplyTo":"Pine.LNX.4.58.0504251832480.18901@ppc970.osdl.org","subject":"Re: [PATCH 0/2] diff-tree/diff-cache helper","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-26T07:39:59Z","receivedAt":"2005-04-26T07:39:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":">>>>> \"LT\" == Linus Torvalds <torvalds@osdl.org> writes:\n\nLT> Good, applied.\n\nLT> This also makes me think that we should just make \"show-diff\" show the\nLT> same format, at which point show-diff actually matches all the other\nLT> tools, and it is likely to make show-diff more useful to boot.\n\nMatching is good, ...\n\nLT> Maybe rename the \"show-diff\" command to be \"cache-diff\", and if somebody\nLT> wants the old \"show-diff\" thing, just have a script that does\n\nLT> \t#!/bin/sh\nLT> \tcache-diff | diff-tree-helper\n\nLT> and nothing more.\n\nWell, great minds do not think alike ;-) I was actually going in\nquite the opposite way for the same goal of \"matching\".  My plan\nwas to rewrite the external diff interface once more to make it\nmore generic.  Then to add -p (patch) flag to diff-tree and\ndiff-cache, so that we do not need diff-tree-helper anymore.  My\nultimate motive for all of this is to make the core GIT useful\nenough to render Cogito or any other wrapper layer more or less\nirrelevant ;-).  Well type ^W a couple of times and rephrase\nthat to make things easier for the wrapper layer.\n\nJokes aside, I have updated the external diff interface and will\nbe sending you a patch in a separate message.  The existing\nexternal diff interface had a horrible interface to the callers,\nand it had a hardcoded knowledge of how to call diff and what\nparameters to pass in which order, so the customization the end\nuser or the scripts could make was quite limited.  The updated\ninterface allows pretty much arbitrary formatting, so \"git diff\"\ncan put SHA1 instead of short-and-sweet 'a' or 'b' as directory\nprefix in the patch output, for example.\n\nWhen an environment variable GIT_EXTERNAL_DIFF exists, it names\na script that takes 7 parameters:\n\n    name file1 sha1-1 mode1 file2 sha1-2 mode2\n\nThis is essentially the same idea you used for merge-cache.\nThen the named command can use these information to generate and\nformat the diff any way it wants.  See how it interfaces using\nthe examples like this:\n\n    GIT_EXTERNAL_DIFF=echo show-diff\n    diff-cache $(cat .git/HEAD) | \\\n    GIT_EXTERNAL_DIFF=./jit-external-diff-script diff-tree-helper\n\nThe patch comes with a sample script, jit-external-diff-script,\nbut it is not much better than the built-in one; I do not expect\nit to be used for anything other than starting point for wrapper\nwriters.\n\nWithout the environment variable, it uses a built-in\nimplementation that behaves exactly like the traditional\nshow-diff, and it can be customized via GIT_DIFF_CMD and\nGIT_DIFF_OPTS as before.\n\n"},{"id":"1723","messageId":"7vfyxeotqt.fsf_-_@assigned-by-dhcp.cox.net","threadId":"284","inReplyTo":"7vll76ouk0.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] Diff-tree-helper take two.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-26T07:57:30Z","receivedAt":"2005-04-26T07:57:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This patch reworks the diff-tree-helper and show-diff to further\nmake external diff command interface simpler.  These commands\nnow honor GIT_EXTERNAL_DIFF environment variable which can point\nat an arbitrary program that takes 7 parameters:\n\n  name file1 file1-sha1 file1-mode file2 file2-sha1 file2-mode\n\nThe parameters for an external diff command are as follows:\n\n  name        this invocation of the command is to emit diff\n\t      for the named cache/tree entry.\n\n  file1       pathname that holds the contents of the first\n\t      file.  This can be a file inside the working\n\t      tree, or a temporary file created from the blob\n\t      object, or /dev/null.  The command should not\n\t      attempt to unlink it -- the temporary is\n\t      unlinked by the caller.\n\n  file1-sha1  sha1 hash if file1 is a blob object, or \".\"\n\t      otherwise.\n\n  file1-mode  mode bits for file1, or \".\" for a deleted file.\n\nIf GIT_EXTERNAL_DIFF environment variable is not set, the\ndefault is to invoke diff with the set of parameters old\nshow-diff used to use.  This built-in implementation honors the\nGIT_DIFF_CMD and GIT_DIFF_OPTS environment variables as before.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\ndiff-tree-helper.c       |  242 +++++++-------------------------------------\ndiff.c                   |  254 ++++++++++++++++++++++++++++++++++++++---------\ndiff.h                   |   34 ++++--\njit-external-diff-script |   14 ++\nshow-diff.c              |   17 ---\n5 files changed, 288 insertions(+), 273 deletions(-)\n\n--- k/diff-tree-helper.c\n+++ l/diff-tree-helper.c\n@@ -1,3 +1,6 @@\n+/*\n+ * Copyright (C) 2005 Junio C Hamano\n+ */\n #include \"cache.h\"\n #include \"strbuf.h\"\n #include \"diff.h\"\n@@ -17,15 +20,22 @@ static int matches_pathspec(const char *\n \treturn 0;\n }\n \n-static int parse_oneside_change(const char *cp, unsigned char *sha1,\n-\t\t\t\tchar *path) {\n+static int parse_oneside_change(const char *cp, struct diff_spec *one,\n+\t\t\t\tchar *path)\n+{\n \tint ch;\n-\twhile ((ch = *cp) && '0' <= ch && ch <= '7')\n-\t\tcp++; /* skip mode bits */\n+\n+\tone->file_valid = one->sha1_valid = 1;\n+\tone->mode = 0;\n+\twhile ((ch = *cp) && '0' <= ch && ch <= '7') {\n+\t\tone->mode = (one->mode << 3) | (ch - '0');\n+\t\tcp++;\n+\t}\n+\n \tif (strncmp(cp, \"\\tblob\\t\", 6))\n \t\treturn -1;\n \tcp += 6;\n-\tif (get_sha1_hex(cp, sha1))\n+\tif (get_sha1_hex(cp, one->u.sha1))\n \t\treturn -1;\n \tcp += 40;\n \tif (*cp++ != '\\t')\n@@ -34,31 +44,20 @@ static int parse_oneside_change(const ch\n \treturn 0;\n }\n \n-#define STATUS_CACHED    0 /* cached and sha1 valid */\n-#define STATUS_ABSENT    1 /* diff-tree says old removed or new added */\n-#define STATUS_UNCACHED  2 /* diff-cache output: read from working tree */\n-\n static int parse_diff_tree_output(const char *buf,\n-\t\t\t\t  unsigned char *old_sha1,\n-\t\t\t\t  int *old_status,\n-\t\t\t\t  unsigned char *new_sha1,\n-\t\t\t\t  int *new_status,\n+\t\t\t\t  struct diff_spec *old,\n+\t\t\t\t  struct diff_spec *new,\n \t\t\t\t  char *path) {\n \tconst char *cp = buf;\n \tint ch;\n-\tstatic unsigned char null_sha[20] = { 0, };\n \n \tswitch (*cp++) {\n \tcase '+':\n-\t\t*old_status = STATUS_ABSENT;\n-\t\t*new_status = (memcmp(new_sha1, null_sha, sizeof(null_sha)) ?\n-\t\t\t       STATUS_CACHED : STATUS_UNCACHED);\n-\t\treturn parse_oneside_change(cp, new_sha1, path);\n+\t\told->file_valid = 0;\n+\t\treturn parse_oneside_change(cp, new, path);\n \tcase '-':\n-\t\t*new_status = STATUS_ABSENT;\n-\t\t*old_status = (memcmp(old_sha1, null_sha, sizeof(null_sha)) ?\n-\t\t\t       STATUS_CACHED : STATUS_UNCACHED);\n-\t\treturn parse_oneside_change(cp, old_sha1, path);\n+\t\tnew->file_valid = 0;\n+\t\treturn parse_oneside_change(cp, old, path);\n \tcase '*':\n \t\tbreak;\n \tdefault:\n@@ -66,191 +65,36 @@ static int parse_diff_tree_output(const \n \t}\n \t\n \t/* This is for '*' entries */\n-\twhile ((ch = *cp) && ('0' <= ch && ch <= '7'))\n-\t\tcp++; /* skip mode bits */\n+\told->file_valid = old->sha1_valid = 1;\n+\tnew->file_valid = new->sha1_valid = 1;\n+\n+\told->mode = new->mode = 0;\n+\twhile ((ch = *cp) && ('0' <= ch && ch <= '7')) {\n+\t\told->mode = (old->mode << 3) | (ch - '0');\n+\t\tcp++;\n+\t}\n \tif (strncmp(cp, \"->\", 2))\n \t\treturn -1;\n \tcp += 2;\n-\twhile ((ch = *cp) && ('0' <= ch && ch <= '7'))\n-\t\tcp++; /* skip mode bits */\n+\twhile ((ch = *cp) && ('0' <= ch && ch <= '7')) {\n+\t\tnew->mode = (new->mode << 3) | (ch - '0');\n+\t\tcp++;\n+\t}\n \tif (strncmp(cp, \"\\tblob\\t\", 6))\n \t\treturn -1;\n \tcp += 6;\n-\tif (get_sha1_hex(cp, old_sha1))\n+\tif (get_sha1_hex(cp, old->u.sha1))\n \t\treturn -1;\n \tcp += 40;\n \tif (strncmp(cp, \"->\", 2))\n \t\treturn -1;\n \tcp += 2;\n-\tif (get_sha1_hex(cp, new_sha1))\n+\tif (get_sha1_hex(cp, new->u.sha1))\n \t\treturn -1;\n \tcp += 40;\n \tif (*cp++ != '\\t')\n \t\treturn -1;\n \tstrcpy(path, cp);\n-\t*old_status = (memcmp(old_sha1, null_sha, sizeof(null_sha)) ?\n-\t\t       STATUS_CACHED : STATUS_UNCACHED);\n-\t*new_status = (memcmp(new_sha1, null_sha, sizeof(null_sha)) ?\n-\t\t       STATUS_CACHED : STATUS_UNCACHED);\n-\treturn 0;\n-}\n-\n-static int sha1err(const char *path, const unsigned char *sha1)\n-{\n-\treturn error(\"diff-tree-helper: unable to read sha1 file of %s (%s)\",\n-\t\t     path, sha1_to_hex(sha1));\n-}\n-\n-static int fserr(const char *path)\n-{\n-\treturn error(\"diff-tree-helper: unable to read file %s\", path);\n-}\n-\n-static char *map_whole_file(const char *path, unsigned long *size) {\n-\tint fd;\n-\tstruct stat st;\n-\tvoid *buf;\n-\n-\tif ((fd = open(path, O_RDONLY)) < 0) {\n-\t\terror(\"diff-tree-helper: unable to read file %s\", path);\n-\t\treturn 0;\n-\t}\n-\tif (fstat(fd, &st) < 0) {\n-\t\tclose(fd);\n-\t\terror(\"diff-tree-helper: unable to stat file %s\", path);\n-\t\treturn 0;\n-\t}\n-\t*size = st.st_size;\n-\tbuf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);\n-\tclose(fd);\n-\treturn buf;\n-}\n-\n-static int show_diff(const unsigned char *old_sha1, int old_status,\n-\t\t     const unsigned char *new_sha1, int new_status,\n-\t\t     const char *path, int reverse_diff)\n-{\n-\tchar other[PATH_MAX];\n-\tunsigned long size;\n-\tchar type[20];\n-\tint fd;\n-\tint reverse;\n-\tvoid *blob = 0;\n-\tconst char *fs = 0;\n-\tint need_unmap = 0;\n-\tint need_unlink = 0;\n-\n-\n-\tswitch (old_status) {\n-\tcase STATUS_CACHED:\n-\t\tblob = read_sha1_file(old_sha1, type, &size);\n-\t\tif (! blob)\n-\t\t\treturn sha1err(path, old_sha1);\n-\t\t\t\n-\t\tswitch (new_status) {\n-\t\tcase STATUS_CACHED:\n-\t\t\tstrcpy(other, \".diff_tree_helper_XXXXXX\");\n-\t\t\tfd = mkstemp(other);\n-\t\t\tif (fd < 0)\n-\t\t\t\tdie(\"unable to create temp-file\");\n-\t\t\tif (write(fd, blob, size) != size)\n-\t\t\t\tdie(\"unable to write temp-file\");\n-\t\t\tclose(fd);\n-\t\t\tfree(blob);\n-\n-\t\t\tblob = read_sha1_file(new_sha1, type, &size);\n-\t\t\tif (! blob)\n-\t\t\t\treturn sha1err(path, new_sha1);\n-\n-\t\t\tneed_unlink = 1;\n-\t\t\t/* new = blob, old = fs */\n-\t\t\treverse = !reverse_diff;\n-\t\t\tfs = other;\n-\t\t\tbreak;\n-\n-\t\tcase STATUS_ABSENT:\n-\t\tcase STATUS_UNCACHED:\n-\t\t\tfs = ((new_status == STATUS_ABSENT) ?\n-\t\t\t      \"/dev/null\" : path);\n-\t\t\treverse = reverse_diff;\n-\t\t\tbreak;\n-\n-\t\tdefault:\n- \t\t\treverse = reverse_diff;\n-\t\t}\n-\t\tbreak;\n-\n-\tcase STATUS_ABSENT:\n-\t\tswitch (new_status) {\n-\t\tcase STATUS_CACHED:\n-\t\t\tblob = read_sha1_file(new_sha1, type, &size);\n-\t\t\tif (! blob)\n-\t\t\t\treturn sha1err(path, new_sha1);\n-\t\t\t/* old = fs, new = blob */\n-\t\t\tfs = \"/dev/null\";\n-\t\t\treverse = !reverse_diff;\n-\t\t\tbreak;\n-\n-\t\tcase STATUS_ABSENT:\n-\t\t\treturn error(\"diff-tree-helper: absent from both old and new?\");\n-\t\tcase STATUS_UNCACHED:\n-\t\t\tfs = path;\n-\t\t\tblob = strdup(\"\");\n-\t\t\tsize = 0;\n-\t\t\t/* old = blob, new = fs */\n-\t\t\treverse = reverse_diff;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\treverse = reverse_diff;\n-\t\t}\n-\t\tbreak;\n-\n-\tcase STATUS_UNCACHED:\n-\t\tfs = path; /* old = fs, new = blob */\n-\t\treverse = !reverse_diff;\n-\n-\t\tswitch (new_status) {\n-\t\tcase STATUS_CACHED:\n-\t\t\tblob = read_sha1_file(new_sha1, type, &size);\n-\t\t\tif (! blob)\n-\t\t\t\treturn sha1err(path, new_sha1);\n-\t\t\tbreak;\n-\n-\t\tcase STATUS_ABSENT:\n-\t\t\tblob = strdup(\"\");\n-\t\t\tsize = 0;\n-\t\t\tbreak;\n-\n-\t\tcase STATUS_UNCACHED:\n-\t\t\t/* old = fs */\n-\t\t\tblob = map_whole_file(path, &size);\n-\t\t\tif (! blob)\n-\t\t\t\treturn fserr(path);\n-\t\t\tneed_unmap = 1;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\treverse = reverse_diff;\n-\t\t}\n-\t\tbreak;\n-\n-\tdefault:\n-\t\treverse = reverse_diff;\n-\t}\n-\t\n-\tif (fs)\n-\t\tshow_differences(fs,\n-\t\t\t\t path, /* label */\n-\t\t\t\t blob,\n-\t\t\t\t size,\n-\t\t\t\t reverse /* 0: diff blob fs\n-\t\t\t\t\t    1: diff fs blob */);\n-\n-\tif (need_unlink)\n-\t\tunlink(other);\n-\tif (need_unmap && blob)\n-\t\tmunmap(blob, size);\n-\telse\n-\t\tfree(blob);\n \treturn 0;\n }\n \n@@ -275,28 +119,20 @@ int main(int ac, char **av) {\n \t}\n \t/* the remaining parameters are paths patterns */\n \n-\tprepare_diff_cmd();\n-\n \twhile (1) {\n-\t\tint old_status, new_status;\n-\t\tunsigned char old_sha1[20], new_sha1[20];\n+\t\tstruct diff_spec old, new;\n \t\tchar path[PATH_MAX];\n \t\tread_line(&sb, stdin, line_termination);\n \t\tif (sb.eof)\n \t\t\tbreak;\n-\t\tif (parse_diff_tree_output(sb.buf,\n-\t\t\t\t\t   old_sha1, &old_status,\n-\t\t\t\t\t   new_sha1, &new_status,\n-\t\t\t\t\t   path)) {\n+\t\tif (parse_diff_tree_output(sb.buf, &old, &new, path)) { \n \t\t\tfprintf(stderr, \"cannot parse %s\\n\", sb.buf);\n \t\t\tcontinue;\n \t\t}\n-\t\tif (1 < ac && ! matches_pathspec(path, av+1, ac-1))\n+\t\tif (1 < ac && !matches_pathspec(path, av+1, ac-1))\n \t\t\tcontinue;\n \n-\t\tshow_diff(old_sha1, old_status,\n-\t\t\t  new_sha1, new_status,\n-\t\t\t  path, reverse_diff);\n+\t\trun_external_diff(path, &old, &new);\n \t}\n \treturn 0;\n }\n--- k/diff.c\n+++ l/diff.c\n@@ -1,13 +1,22 @@\n+/*\n+ * Copyright (C) 2005 Junio C Hamano\n+ */\n+#include <sys/types.h>\n+#include <sys/wait.h>\n #include \"cache.h\"\n #include \"diff.h\"\n \n-static char *diff_cmd = \"diff -L 'k/%s' -L 'l/%s' \";\n-static char *diff_opts = \"-p -u\";\n-static char *diff_arg_forward  = \" - '%s'\";\n-static char *diff_arg_reverse  = \" '%s' -\";\n+static char *diff_cmd = \"diff -L'k/%s' -L'l/%s'\";\n+static char *diff_opts = \"-pu\";\n \n-void prepare_diff_cmd(void)\n+static const char *external_diff(void)\n {\n+\tstatic char *external_diff_cmd = NULL;\n+\tstatic int done_preparing = 0;\n+\n+\tif (done_preparing)\n+\t\treturn external_diff_cmd;\n+\n \t/*\n \t * Default values above are meant to match the\n \t * Linux kernel development style.  Examples of\n@@ -17,8 +26,15 @@ void prepare_diff_cmd(void)\n \t * GIT_DIFF_CMD=\"diff -L '%s' -L '%s'\"\n \t * GIT_DIFF_OPTS=\"-c\";\n \t */\n+\tif (getenv(\"GIT_EXTERNAL_DIFF\"))\n+\t\texternal_diff_cmd = getenv(\"GIT_EXTERNAL_DIFF\");\n+\n+\t/* In case external diff fails... */\n \tdiff_cmd = getenv(\"GIT_DIFF_CMD\") ? : diff_cmd;\n \tdiff_opts = getenv(\"GIT_DIFF_OPTS\") ? : diff_opts;\n+\n+\tdone_preparing = 1;\n+\treturn external_diff_cmd;\n }\n \n /* Help to copy the thing properly quoted for the shell safety.\n@@ -58,49 +74,195 @@ static char *sq_expand(const char *src)\n \treturn buf;\n }\n \n-void show_differences(const char *name, /* filename on the filesystem */\n-\t\t      const char *label, /* diff label to use */\n-\t\t      void *old_contents, /* contents in core */\n-\t\t      unsigned long long old_size, /* size in core */\n-\t\t      int reverse /* 0: diff core file\n-\t\t\t\t     1: diff file core */)\n-{\n-\tFILE *f;\n-\tchar *name_sq = sq_expand(name);\n-\tconst char *label_sq = (name != label) ? sq_expand(label) : name_sq;\n-\tchar *diff_arg = reverse ? diff_arg_reverse : diff_arg_forward;\n-\tint cmd_size = strlen(name_sq) + strlen(label_sq) * 2 +\n-\t\tstrlen(diff_cmd) + strlen(diff_opts) + strlen(diff_arg);\n+static struct diff_tempfile {\n+\tconst char *name;\n+\tchar hex[41];\n+\tchar mode[10];\n+\tchar tmp_path[50];\n+} diff_temp[2];\n+\n+static void builtin_diff(const char *name,\n+\t\t\t struct diff_tempfile *temp)\n+{\n+\tstatic char *diff_arg  = \"'%s' '%s'\";\n+\tconst char *name_1_sq = sq_expand(temp[0].name);\n+\tconst char *name_2_sq = sq_expand(temp[1].name);\n+\tconst char *name_sq = sq_expand(name);\n+\n+\t/* diff_cmd and diff_arg have 4 %s in total which makes\n+\t * the sum of these strings 8 bytes larger than required.\n+\t * we use 2 spaces around diff-opts, and we need to count\n+\t * terminating NUL, so we subtract 5 here.\n+\t */\n+\tint cmd_size = (strlen(diff_cmd) + \n+\t\t\tstrlen(name_sq) * 2 +\n+\t\t\tstrlen(diff_opts) +\n+\t\t\tstrlen(diff_arg) +\n+\t\t\tstrlen(name_1_sq) + strlen(name_2_sq)\n+\t\t\t- 5);\n \tchar *cmd = malloc(cmd_size);\n-\tint next_at;\n+\tint next_at = 0;\n+\n+\tnext_at += snprintf(cmd+next_at, cmd_size-next_at,\n+\t\t\t    diff_cmd, name_sq, name_sq);\n+\tnext_at += snprintf(cmd+next_at, cmd_size-next_at,\n+\t\t\t    \" %s \", diff_opts);\n+\tnext_at += snprintf(cmd+next_at, cmd_size-next_at,\n+\t\t\t    diff_arg, name_1_sq, name_2_sq);\n+\texeclp(\"/bin/sh\",\"sh\", \"-c\", cmd, NULL);\n+}\n+\n+static void prepare_temp_file(const char *name,\n+\t\t\t      struct diff_tempfile *temp,\n+\t\t\t      struct diff_spec *one)\n+{\n+\tstatic unsigned char null_sha1[20] = { 0, };\n \n-\tfflush(stdout);\n-\tnext_at = snprintf(cmd, cmd_size, diff_cmd, label_sq, label_sq);\n-\tnext_at += snprintf(cmd+next_at, cmd_size-next_at, \"%s\", diff_opts);\n-\tnext_at += snprintf(cmd+next_at, cmd_size-next_at, diff_arg, name_sq);\n-\tf = popen(cmd, \"w\");\n-\tif (old_size)\n-\t\tfwrite(old_contents, old_size, 1, f);\n-\tpclose(f);\n-\tif (label_sq != name_sq)\n-\t\tfree((void*)label_sq); /* constness */\n-\tfree(name_sq);\n-\tfree(cmd);\n-}\n-\n-void show_diff_empty(const unsigned char *sha1,\n-\t\t     const char *name,\n-\t\t     int reverse)\n-{\n-\tchar *old;\n-\tunsigned long int size;\n-\tunsigned char type[20];\n-\n-\told = read_sha1_file(sha1, type, &size);\n-\tif (! old) {\n-\t\terror(\"unable to read blob object for %s (%s)\", name,\n-\t\t      sha1_to_hex(sha1));\n+\tif (!one->file_valid) {\n+\tnot_a_valid_file:\n+\t\ttemp->name = \"/dev/null\";\n+\t\tstrcpy(temp->hex, \".\");\n+\t\tstrcpy(temp->mode, \".\");\n \t\treturn;\n \t}\n-\tshow_differences(\"/dev/null\", name, old, size, reverse);\n+\n+\tif (one->sha1_valid &&\n+\t    !memcmp(one->u.sha1, null_sha1, sizeof(null_sha1))) {\n+\t\tone->sha1_valid = 0;\n+\t\tone->u.name = name;\n+\t}\n+\n+\tif (!one->sha1_valid) {\n+\t\tstruct stat st;\n+\t\ttemp->name = one->u.name;\n+\t\tif (stat(temp->name, &st) < 0) {\n+\t\t\tif (errno == ENOENT)\n+\t\t\t\tgoto not_a_valid_file;\n+\t\t\tdie(\"stat(%s): %s\", temp->name, strerror(errno));\n+\t\t}\n+\t\tstrcpy(temp->hex, \".\");\n+\t\tsprintf(temp->mode, \"%06o\",\n+\t\t\tS_IFREG |ce_permissions(st.st_mode));\n+\t}\n+\telse {\n+\t\tint fd;\n+\t\tvoid *blob;\n+\t\tchar type[20];\n+\t\tunsigned long size;\n+\n+\t\tblob = read_sha1_file(one->u.sha1, type, &size);\n+\t\tif (!blob || strcmp(type, \"blob\"))\n+\t\t\tdie(\"unable to read blob object for %s (%s)\",\n+\t\t\t    name, sha1_to_hex(one->u.sha1));\n+\n+\t\tstrcpy(temp->tmp_path, \".diff_XXXXXX\");\n+\t\tfd = mkstemp(temp->tmp_path);\n+\t\tif (fd < 0)\n+\t\t\tdie(\"unable to create temp-file\");\n+\t\tif (write(fd, blob, size) != size)\n+\t\t\tdie(\"unable to write temp-file\");\n+\t\tclose(fd);\n+\t\tfree(blob);\n+\t\ttemp->name = temp->tmp_path;\n+\t\tstrcpy(temp->hex, sha1_to_hex(one->u.sha1));\n+\t\ttemp->hex[40] = 0;\n+\t\tsprintf(temp->mode, \"%06o\", one->mode);\n+\t}\n+}\n+\n+static void remove_tempfile(void)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < 2; i++)\n+\t\tif (diff_temp[i].name == diff_temp[i].tmp_path) {\n+\t\t\tunlink(diff_temp[i].name);\n+\t\t\tdiff_temp[i].name = NULL;\n+\t\t}\n+}\n+\n+/* An external diff command takes:\n+ *\n+ * diff-cmd name infile1 infile1-sha1 infile1-mode \\\n+ *               infile2 infile2-sha1 infile2-mode.\n+ *\n+ */\n+void run_external_diff(const char *name,\n+\t\t       struct diff_spec *one,\n+\t\t       struct diff_spec *two)\n+{\n+\tstruct diff_tempfile *temp = diff_temp;\n+\tint pid, status;\n+\tstatic int atexit_asked = 0;\n+\n+\tprepare_temp_file(name, &temp[0], one);\n+\tprepare_temp_file(name, &temp[1], two);\n+\tif (! atexit_asked &&\n+\t    (temp[0].name == temp[0].tmp_path ||\n+\t     temp[1].name == temp[1].tmp_path)) {\n+\t\tatexit_asked = 1;\n+\t\tatexit(remove_tempfile);\n+\t}\n+\n+\tfflush(NULL);\n+\tpid = fork();\n+\tif (pid < 0)\n+\t\tdie(\"unable to fork\");\n+\tif (!pid) {\n+\t\tconst char *pgm = external_diff();\n+\t\tif (pgm)\n+\t\t\texeclp(pgm, pgm,\n+\t\t\t       name,\n+\t\t\t       temp[0].name, temp[0].hex, temp[0].mode,\n+\t\t\t       temp[1].name, temp[1].hex, temp[1].mode,\n+\t\t\t       NULL);\n+\t\t/*\n+\t\t * otherwise we use the built-in one.\n+\t\t */\n+\t\tbuiltin_diff(name, temp);\n+\t\texit(0);\n+\t}\n+\tif (waitpid(pid, &status, 0) < 0 || !WIFEXITED(status))\n+\t\tdie(\"diff program failed\");\n+\n+\tremove_tempfile();\n+}\n+\n+void show_diff_empty(const struct cache_entry *ce, int reverse)\n+{\n+\tstruct diff_spec spec[2], *one, *two;\n+\n+\tmemcpy(spec[0].u.sha1, ce->sha1, 20);\n+\tspec[0].mode = ntohl(ce->ce_mode);\n+\tspec[0].sha1_valid = spec[0].file_valid = 1;\n+\tspec[1].file_valid = 0;\n+\n+\tif (reverse) {\n+\t\tone = spec + 1; two = spec;\n+\t} else {\n+\t\tone = spec; two = one + 1;\n+\t}\n+\n+\trun_external_diff(ce->name, one, two);\n+}\n+\n+void show_differences(const struct cache_entry *ce, int reverse) \n+{\n+\tstruct diff_spec spec[2], *one, *two;\n+\n+\tmemcpy(spec[0].u.sha1, ce->sha1, 20);\n+\tspec[0].mode = ntohl(ce->ce_mode);\n+\tspec[0].sha1_valid = spec[0].file_valid = 1;\n+\n+\tspec[1].u.name = ce->name; /* the name we stated */\n+\tspec[1].sha1_valid = 0;\n+\tspec[1].file_valid = 1;\n+\n+\tif (reverse) {\n+\t\tone = spec + 1; two = spec;\n+\t} else {\n+\t\tone = spec; two = one + 1;\n+\t}\n+\n+\trun_external_diff(ce->name, one, two);\n }\n--- k/diff.h\n+++ l/diff.h\n@@ -1,17 +1,31 @@\n+/*\n+ * Copyright (C) 2005 Junio C Hamano\n+ */\n #ifndef DIFF_H\n #define DIFF_H\n \n-extern void prepare_diff_cmd(void);\n+/* These two are for backward compatibility with show-diff;\n+ * new users should not use them.\n+ */\n+extern void show_differences(const struct cache_entry *ce, int reverse);\n+extern void show_diff_empty(const struct cache_entry *ce, int reverse);\n \n-extern void show_differences(const char *name, /* filename on the filesystem */\n-\t\t\t     const char *label, /* diff label to use */\n-\t\t\t     void *old_contents, /* contents in core */\n-\t\t\t     unsigned long long old_size, /* size in core */\n-\t\t\t     int reverse /* 0: diff core file\n-\t\t\t\t\t    1: diff file core */);\n+struct diff_spec {\n+\tunion {\n+\t\tconst char *name;       /* path on the filesystem */\n+\t\tunsigned char sha1[20]; /* blob object ID */\n+\t} u;\n+\tunsigned short mode;\t /* file mode */\n+\tunsigned sha1_valid : 1; /* if true, use u.sha1 and trust mode.\n+\t\t\t\t  * (however with a NULL SHA1, read them\n+\t\t\t\t  * from the file!).\n+\t\t\t\t  * if false, use u.name and read mode from\n+\t\t\t\t  * the filesystem.\n+\t\t\t\t  */\n+\tunsigned file_valid : 1; /* if false the file does not even exist */\n+};\n \n-extern void show_diff_empty(const unsigned char *sha1,\n-\t\t\t    const char *name,\n-\t\t\t    int reverse);\n+extern void run_external_diff(const char *name,\n+\t\t\t      struct diff_spec *, struct diff_spec *);\n \n #endif /* DIFF_H */\n--- k/jit-external-diff-script\n+++ l/jit-external-diff-script\n@@ -0,0 +1,14 @@\n+#!/bin/sh\n+#\n+# Copyright (C) 2005 Junio C Hamano\n+#\n+\n+name=\"$1\" name1=\"$2\" sha11=\"$3\" mode1=\"$4\"\n+          name2=\"$5\" sha12=\"$6\" mode2=\"$7\"\n+\n+case \"$sha11\" in .) sha11=file-not-in-blob-but-in-the-working-tree ;; esac\n+case \"$sha12\" in .) sha12=file-not-in-blob-but-in-the-working-tree ;; esac\n+case \"$mode1\" in .) mode1=;; *) mode1=\" ($mode1)\" ;;esac\n+case \"$mode2\" in .) mode2=;; *) mode2=\" ($mode2)\" ;;esac\n+\n+diff -pu -L \"$sha11/$name$mode1\" -L \"$sha12/$name$mode2\" \"$name1\" \"$name2\"\n--- k/show-diff.c\n+++ l/show-diff.c\n@@ -53,14 +53,11 @@ int main(int argc, char **argv)\n \t\tperror(\"read_cache\");\n \t\texit(1);\n \t}\n-\tprepare_diff_cmd();\n+\n \tfor (i = 0; i < entries; i++) {\n \t\tstruct stat st;\n \t\tstruct cache_entry *ce = active_cache[i];\n \t\tint changed;\n-\t\tunsigned long size;\n-\t\tchar type[20];\n-\t\tvoid *old;\n \n \t\tif (1 < argc &&\n \t\t    ! matches_pathspec(ce, argv+1, argc-1))\n@@ -87,8 +84,7 @@ int main(int argc, char **argv)\n \t\t\telse {\n \t\t\t\tprintf(\"%s: %s\\n\", ce->name, strerror(errno));\n \t\t\t\tif (errno == ENOENT)\n-\t\t\t\t\tshow_diff_empty(ce->sha1, ce->name,\n-\t\t\t\t\t\t\treverse);\n+\t\t\t\t\tshow_diff_empty(ce, reverse);\n \t\t\t}\n \t\t\tcontinue;\n \t\t}\n@@ -104,14 +100,7 @@ int main(int argc, char **argv)\n \t\tif (silent)\n \t\t\tcontinue;\n \n-\t\told = read_sha1_file(ce->sha1, type, &size);\n-\t\tif (! old)\n-\t\t\terror(\"unable to read blob object for %s (%s)\",\n-\t\t\t      ce->name, sha1_to_hex(ce->sha1));\n-\t\telse\n-\t\t\tshow_differences(ce->name, ce->name, old, size,\n-\t\t\t\t\t reverse);\n-\t\tfree(old);\n+\t\tshow_differences(ce, reverse);\n \t}\n \treturn 0;\n }\n\n"},{"id":"1814","messageId":"7vy8b5mawy.fsf_-_@assigned-by-dhcp.cox.net","threadId":"284","inReplyTo":"Pine.LNX.4.58.0504251832480.18901@ppc970.osdl.org","subject":"[PATCH] Add -r flag to show-diff for diff-cache/diff-tree like output.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-26T22:27:09Z","receivedAt":"2005-04-26T22:27:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This adds a new option -r (rational) to show-diff command, to\nproduce diff-cache/diff-tree compatible output.  When -r is\nspecified, show-diff simply skips unmerged entries.  This makes\nthe following thee behave quite similarly: \n\n    show-diff  -r -z\n    diff-cache -r -z [--cached] <tree-or-commit>\n    diff-tree  -r -z <tree-or-commit> <tree-or-commit>\n\nWhen -z (machine readable) is used, it implies rational.  In\naddition to terminating each output record with NUL instead of\n'\\n', machine readable format also may output lines of the form:\n\n    U filename <NUL>\n\nto show that there are unmerged entries, once per path (this is\nto help scripts so that they do not have to run \"sed | uniq\" on\noutput from \"show-files --unmerged\", just to get the list of\nunmerged files).\n\nThe earlier machine readable output format had another form:\n\n    X filename <NUL>\n\nto show deleted files.  This has been removed; these paths now\ngive the diff-cache compatible \"-<mode> <sha1> <path>\" output.\n\nI resisted the temptation to change those tabs between columns\ninto spaces.  Linus, what do you think?  I do not think Cogito\ncares and changing them into spaces would certainly make them\nmore readable by humans.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\nshow-diff.c |   44 +++++++++++++++++++++++++++++++++-----------\n1 files changed, 33 insertions(+), 11 deletions(-)\n\n--- k/show-diff.c\n+++ l/show-diff.c\n@@ -6,7 +6,8 @@\n #include \"cache.h\"\n #include \"diff.h\"\n \n-static const char *show_diff_usage = \"show-diff [-q] [-s] [-z] [paths...]\";\n+static const char *show_diff_usage =\n+\"show-diff [-q] [-s] [-r] [-z] [paths...]\";\n \n static int matches_pathspec(struct cache_entry *ce, char **spec, int cnt)\n {\n@@ -23,10 +24,17 @@ static int matches_pathspec(struct cache\n \treturn 0;\n }\n \n+static void show_file(int pfx, struct cache_entry *ce, int NUL_terminate)\n+{\n+\tprintf(\"%c%o\\t%s\\t%s\\t%s%c\", pfx, ntohl(ce->ce_mode), \"blob\",\n+\t       sha1_to_hex(ce->sha1), ce->name, NUL_terminate ? 0 : '\\n');\n+}\n+\n int main(int argc, char **argv)\n {\n \tint silent = 0;\n \tint silent_on_nonexisting_files = 0;\n+\tint rational = 0;\n \tint machine_readable = 0;\n \tint reverse = 0;\n \tint entries = read_cache();\n@@ -39,8 +47,12 @@ int main(int argc, char **argv)\n \t\t\tsilent_on_nonexisting_files = silent = 1;\n \t\telse if (!strcmp(argv[1], \"-q\"))\n \t\t\tsilent_on_nonexisting_files = 1;\n+\t\telse if (!strcmp(argv[1], \"-r\"))\n+\t\t\t/* diff-cache and diff-tree compatible */\n+\t\t\trational = 1;\n \t\telse if (!strcmp(argv[1], \"-z\"))\n-\t\t\tmachine_readable = 1;\n+\t\t\t/* machine readable implies rational */\n+\t\t\trational = machine_readable = 1;\n \t\telse\n \t\t\tusage(show_diff_usage);\n \t\targv++; argc--;\n@@ -64,11 +76,16 @@ int main(int argc, char **argv)\n \t\t\tcontinue;\n \n \t\tif (ce_stage(ce)) {\n+\t\t\t/* machine-readble == rational in most cases,\n+\t\t\t * but rational does not care about unmerged.\n+\t\t\t * In some cases we want the list of unmerged\n+\t\t\t * files and running sort -u on show-files -z\n+\t\t\t * --unmerged for that is a pain.\n+\t\t\t */\n \t\t\tif (machine_readable)\n \t\t\t\tprintf(\"U %s%c\", ce->name, 0);\n-\t\t\telse\n-\t\t\t\tprintf(\"%s: Unmerged\\n\",\n-\t\t\t\t       ce->name);\n+\t\t\telse if (!rational)\n+\t\t\t\tprintf(\"%s: unmerged\\n\", ce->name);\n \t\t\twhile (i < entries &&\n \t\t\t       !strcmp(ce->name, active_cache[i]->name))\n \t\t\t\ti++;\n@@ -79,8 +96,10 @@ int main(int argc, char **argv)\n \t\tif (stat(ce->name, &st) < 0) {\n \t\t\tif (errno == ENOENT && silent_on_nonexisting_files)\n \t\t\t\tcontinue;\n-\t\t\tif (machine_readable)\n-\t\t\t\tprintf(\"X %s%c\", ce->name, 0);\n+\t\t\tif (rational) {\n+\t\t\t\t/* deleted */\n+\t\t\t\tshow_file('-', ce, machine_readable);\n+\t\t\t}\n \t\t\telse {\n \t\t\t\tprintf(\"%s: %s\\n\", ce->name, strerror(errno));\n \t\t\t\tif (errno == ENOENT)\n@@ -91,10 +110,13 @@ int main(int argc, char **argv)\n \t\tchanged = cache_match_stat(ce, &st);\n \t\tif (!changed)\n \t\t\tcontinue;\n-\t\tif (!machine_readable)\n-\t\t\tprintf(\"%s: %s\\n\", ce->name, sha1_to_hex(ce->sha1));\n-\t\telse {\n-\t\t\tprintf(\"%s %s%c\", sha1_to_hex(ce->sha1), ce->name, 0);\n+\t\tif (rational) {\n+\t\t\tstatic char *no_sha1_hex = \n+\t\t\t\t\"0000000000000000000000000000000000000000\";\n+\t\t\tprintf(\"*%o->%o\\t%s\\t%s->%s\\t%s%c\",\n+\t\t\t       ntohl(ce->ce_mode), st.st_mode,\n+\t\t\t       \"blob\", sha1_to_hex(ce->sha1), no_sha1_hex,\n+\t\t\t       ce->name, (machine_readable ? 0 : '\\n'));\n \t\t\tcontinue;\n \t\t}\n \t\tif (silent)\n\n"},{"id":"1817","messageId":"Pine.LNX.4.58.0504261534590.18901@ppc970.osdl.org","threadId":"284","inReplyTo":"7vy8b5mawy.fsf_-_@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Add -r flag to show-diff for diff-cache/diff-tree like output.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-04-26T22:40:37Z","receivedAt":"2005-04-26T22:40:37Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 26 Apr 2005, Junio C Hamano wrote:\n>\n> This adds a new option -r (rational) to show-diff command, to\n> produce diff-cache/diff-tree compatible output.\n\nWhy not just make this the default? Who really cares about show-diff? I \nsee that \"cg-merge\" uses it, but does so with the \"s\" flag, just to see \nwhether there are any changes at all.\n\nSo why not just make \"rational\" the standard format, and then make \n\"diff-tree-helper\" warn about unmerged (\"U\") files?\n\nAs far as I can tell, that is really what _everybody_ wants.\n\nAnd calling \"-r\" \"rational\", when it means \"recursive\" for diff-tree and \ndiff-cache doesn't sound rational to me. It _is_ rational to just silently \naccept it as \"recursive\", the same way diff-cache does.\n\n\t\tLinus\n"},{"id":"1826","messageId":"7vd5shm94l.fsf@assigned-by-dhcp.cox.net","threadId":"284","inReplyTo":"Pine.LNX.4.58.0504261534590.18901@ppc970.osdl.org","subject":"Re: [PATCH] Add -r flag to show-diff for diff-cache/diff-tree like output.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-26T23:05:46Z","receivedAt":"2005-04-26T23:05:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":">>>>> \"LT\" == Linus Torvalds <torvalds@osdl.org> writes:\n\nLT> Why not just make this the default? Who really cares about\nLT> show-diff?\n\nMe, to care enough about it to send patches in ;-).\n\nLT> So why not just make \"rational\" the standard format, and then make \nLT> \"diff-tree-helper\" warn about unmerged (\"U\") files?\n\nLT> As far as I can tell, that is really what _everybody_ wants.\n\nI do not think of a good reason to forbid people from getting a\npatch out of core GIT without going through the wrapper layer,\nand the code is already there.  That said, I agree that scripts\nusually do not use patch generating form.  I checked Cogito\nbefore doing the patch to make sure it is not affected by this,\nand my JIT core tools do not use it either.\n\nI think making the diff-tree/cache compatible output default\nwould be fine.  The current diff-producing behaviour can be made\ninto an option (yes, I want to keep it).\n\nLT> And calling \"-r\" \"rational\", when it means \"recursive\" for\nLT> diff-tree and diff-cache doesn't sound rational to me.\n\nWell, the truth is that -r does not stand for anything.  It just\nis there to match useless -r to diff-cache (the change you made\nto it to accept the same command line parameters -r (and\noptionally -z) people would always give diff-tree.  You can call\nit recursive if you want.\n\nHow about me doing the following and resubmitting?\n\n - Make this diff-tree/cache compatible output the default.\n\n - Take but ignore -r flag like diff-cache.\n\n - Add U warning to diff-tree-helper.\n\n - Add -p flag (patch) and have it cause the patch generating\n   behaviour. \n\nLater I'll add -p flag to diff-cache and diff-tree, so the usage\nof these three commands match.  That is:\n\n    show-diff  -r (useless) -z           | diff-tree-helper -z\n    diff-cache -r (useless) -z tree      | diff-tree-helper -z\n    diff-tree  -r           -z tree tree | diff-tree-helper -z\n\n    show-diff  -p [-r (useless)]\n    diff-cache -p [-r (useless)]\n    diff-tree  -p [-r]\n\nWith the GIT_EXTERNAL_DIFF envioronment variable, I suspect that\nwrapper scripts do not have to use the diff-tree-helper but\ndirectly use the -p form; but that will come later.  Thoughts?\n\n"},{"id":"1829","messageId":"Pine.LNX.4.58.0504261639420.18901@ppc970.osdl.org","threadId":"284","inReplyTo":"7vd5shm94l.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Add -r flag to show-diff for diff-cache/diff-tree like output.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-04-26T23:44:38Z","receivedAt":"2005-04-26T23:44:38Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 26 Apr 2005, Junio C Hamano wrote:\n>\n> >>>>> \"LT\" == Linus Torvalds <torvalds@osdl.org> writes:\n> \n> LT> Why not just make this the default? Who really cares about\n> LT> show-diff?\n> \n> Me, to care enough about it to send patches in ;-).\n\nWell, I actually care abotu \"show-diff\" too, in the sense that I actually \nuse it all the time.\n\nThe thing is, I just care about the format. To me, a \"diff-tree\" like\nformat is actually _better_ than the full diff, 99% of the time, since\nwhat I really want to know \"what state is my repository in\", I don't\nusually care about the details within the files.\n\nIe I want to know exactly the same thing that most scripts would want to \nknow: which files are dirty and need to be checked in, which ones are \nstill unmerged etc.\n\n> Later I'll add -p flag to diff-cache and diff-tree, so the usage\n> of these three commands match.\n\nI don't know why you're so dead set on creating the diff directly, when \nyou _don't_ actually create the diff directly anyway (ie you call out to a \nhelper process - \"diff\", regardless).\n\nThe thing is, \"-p\" is strictly weaker than doing the UNIX pipe way, since \nthe latter trivially does the same time (add a simple script if you don't \nwant to type it), but can also do things like \"grep the filenames going \npast\" or similar.\n\nBut hey, as long as the source code is clean, I don't care _that_ much. \n\n\t\tLinus\n"},{"id":"1831","messageId":"7vy8b5ksqi.fsf_-_@assigned-by-dhcp.cox.net","threadId":"284","inReplyTo":"7vd5shm94l.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] diff-cache/tree compatible output for show-diff (take 2).","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-26T23:45:09Z","receivedAt":"2005-04-26T23:45:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This patch changes the output format of the show-diff command to\nmatch that of the diff-cache/tree commands.  One type of record\nit can produce that diff-cache/tree do not is of this form:\n\n    U path <record-terminator>\n\nThis is emitted once per unmerged path, no matter how many\nunmerged stages there are.  The diff-tree-helper program is also\ntaught about this and warns about such input records.\n\nThe -z flag has the same meaning as diff-cache/tree commands;\nthe output records are terminated with a NUL instead of a '\\n'.\nJust like diff-cache takes a meaningless -r flag, it also\nignores a -r.\n\nThe previous default behaviour of getting patch output can be\nobtained by specifying a -p flag.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\ndiff-tree-helper.c |   27 ++++++++++++++++---------\nshow-diff.c        |   57 +++++++++++++++++++++++++++++++++++++----------------\n2 files changed, 58 insertions(+), 26 deletions(-)\n\n--- k/diff-tree-helper.c\n+++ l/diff-tree-helper.c\n@@ -44,6 +44,9 @@ static int parse_oneside_change(const ch\n \treturn 0;\n }\n \n+#define PLEASE_WARN -1\n+#define WARNED_OURSELVES -2\n+ \n static int parse_diff_tree_output(const char *buf,\n \t\t\t\t  struct diff_spec *old,\n \t\t\t\t  struct diff_spec *new,\n@@ -52,6 +55,9 @@ static int parse_diff_tree_output(const \n \tint ch;\n \n \tswitch (*cp++) {\n+\tcase 'U':\n+\t\tfprintf(stderr, \"warning: unmerged path %s\\n\", cp+1);\n+\t\treturn WARNED_OURSELVES;\n \tcase '+':\n \t\told->file_valid = 0;\n \t\treturn parse_oneside_change(cp, new, path);\n@@ -61,7 +67,7 @@ static int parse_diff_tree_output(const \n \tcase '*':\n \t\tbreak;\n \tdefault:\n-\t\treturn -1;\n+\t\treturn PLEASE_WARN;\n \t}\n \t\n \t/* This is for '*' entries */\n@@ -74,26 +80,26 @@ static int parse_diff_tree_output(const \n \t\tcp++;\n \t}\n \tif (strncmp(cp, \"->\", 2))\n-\t\treturn -1;\n+\t\treturn PLEASE_WARN;\n \tcp += 2;\n \twhile ((ch = *cp) && ('0' <= ch && ch <= '7')) {\n \t\tnew->mode = (new->mode << 3) | (ch - '0');\n \t\tcp++;\n \t}\n \tif (strncmp(cp, \"\\tblob\\t\", 6))\n-\t\treturn -1;\n+\t\treturn PLEASE_WARN;\n \tcp += 6;\n \tif (get_sha1_hex(cp, old->u.sha1))\n-\t\treturn -1;\n+\t\treturn PLEASE_WARN;\n \tcp += 40;\n \tif (strncmp(cp, \"->\", 2))\n-\t\treturn -1;\n+\t\treturn PLEASE_WARN;\n \tcp += 2;\n \tif (get_sha1_hex(cp, new->u.sha1))\n-\t\treturn -1;\n+\t\treturn PLEASE_WARN;\n \tcp += 40;\n \tif (*cp++ != '\\t')\n-\t\treturn -1;\n+\t\treturn PLEASE_WARN;\n \tstrcpy(path, cp);\n \treturn 0;\n }\n@@ -120,13 +126,16 @@ int main(int ac, char **av) {\n \t/* the remaining parameters are paths patterns */\n \n \twhile (1) {\n+\t\tint status;\n \t\tstruct diff_spec old, new;\n \t\tchar path[PATH_MAX];\n \t\tread_line(&sb, stdin, line_termination);\n \t\tif (sb.eof)\n \t\t\tbreak;\n-\t\tif (parse_diff_tree_output(sb.buf, &old, &new, path)) { \n-\t\t\tfprintf(stderr, \"cannot parse %s\\n\", sb.buf);\n+\t\tstatus = parse_diff_tree_output(sb.buf, &old, &new, path);\n+\t\tif (status) {\n+\t\t\tif (status == PLEASE_WARN)\n+\t\t\t\tfprintf(stderr, \"cannot parse %s\\n\", sb.buf);\n \t\t\tcontinue;\n \t\t}\n \t\tif (1 < ac && !matches_pathspec(path, av+1, ac-1))\n--- k/show-diff.c\n+++ l/show-diff.c\n@@ -6,7 +6,8 @@\n #include \"cache.h\"\n #include \"diff.h\"\n \n-static const char *show_diff_usage = \"show-diff [-q] [-s] [-z] [paths...]\";\n+static const char *show_diff_usage =\n+\"show-diff [-q] [-s] [-r] [-z] [-p] [paths...]\";\n \n static int matches_pathspec(struct cache_entry *ce, char **spec, int cnt)\n {\n@@ -23,24 +24,40 @@ static int matches_pathspec(struct cache\n \treturn 0;\n }\n \n+static void show_file(int pfx, struct cache_entry *ce, int line_termination)\n+{\n+\tprintf(\"%c%o\\t%s\\t%s\\t%s%c\", pfx, ntohl(ce->ce_mode), \"blob\",\n+\t       sha1_to_hex(ce->sha1), ce->name, line_termination);\n+}\n+\n int main(int argc, char **argv)\n {\n \tint silent = 0;\n \tint silent_on_nonexisting_files = 0;\n-\tint machine_readable = 0;\n+\tint patch = 0;\n+\tint line_termination = '\\n';\n \tint reverse = 0;\n \tint entries = read_cache();\n \tint i;\n \n \twhile (1 < argc && argv[1][0] == '-') {\n \t\tif  (!strcmp(argv[1], \"-R\"))\n-\t\t\treverse = 1;\n+\t\t\tpatch = reverse = 1; /* works only for patch */\n \t\telse if (!strcmp(argv[1], \"-s\"))\n-\t\t\tsilent_on_nonexisting_files = silent = 1;\n+\t\t\tpatch = silent_on_nonexisting_files = silent = 1;\n \t\telse if (!strcmp(argv[1], \"-q\"))\n-\t\t\tsilent_on_nonexisting_files = 1;\n+\t\t\tpatch = silent_on_nonexisting_files = 1;\n+\t\telse if (!strcmp(argv[1], \"-p\")) {\n+\t\t\tpatch = 1;\n+\t\t\tline_termination = '\\n';\n+\t\t}\n+\t\telse if (!strcmp(argv[1], \"-r\"))\n+\t\t\t; /* diff-cache and diff-tree compatible\n+\t\t\t   * is the default now.\n+\t\t\t   */\n \t\telse if (!strcmp(argv[1], \"-z\"))\n-\t\t\tmachine_readable = 1;\n+\t\t\t/* makes sense only non-patch */\n+\t\t\tpatch = line_termination = 0;\n \t\telse\n \t\t\tusage(show_diff_usage);\n \t\targv++; argc--;\n@@ -64,11 +81,10 @@ int main(int argc, char **argv)\n \t\t\tcontinue;\n \n \t\tif (ce_stage(ce)) {\n-\t\t\tif (machine_readable)\n-\t\t\t\tprintf(\"U %s%c\", ce->name, 0);\n+\t\t\tif (patch)\n+\t\t\t\tprintf(\"%s: unmerged\\n\", ce->name);\n \t\t\telse\n-\t\t\t\tprintf(\"%s: Unmerged\\n\",\n-\t\t\t\t       ce->name);\n+\t\t\t\tprintf(\"U %s%c\", ce->name, line_termination);\n \t\t\twhile (i < entries &&\n \t\t\t       !strcmp(ce->name, active_cache[i]->name))\n \t\t\t\ti++;\n@@ -77,26 +93,33 @@ int main(int argc, char **argv)\n \t\t}\n  \n \t\tif (stat(ce->name, &st) < 0) {\n+\t\t\t/* deleted */\n \t\t\tif (errno == ENOENT && silent_on_nonexisting_files)\n \t\t\t\tcontinue;\n-\t\t\tif (machine_readable)\n-\t\t\t\tprintf(\"X %s%c\", ce->name, 0);\n-\t\t\telse {\n+\t\t\tif (patch) {\n \t\t\t\tprintf(\"%s: %s\\n\", ce->name, strerror(errno));\n \t\t\t\tif (errno == ENOENT)\n \t\t\t\t\tshow_diff_empty(ce, reverse);\n \t\t\t}\n+\t\t\telse\n+\t\t\t\tshow_file('-', ce, line_termination);\n \t\t\tcontinue;\n \t\t}\n \t\tchanged = cache_match_stat(ce, &st);\n \t\tif (!changed)\n \t\t\tcontinue;\n-\t\tif (!machine_readable)\n-\t\t\tprintf(\"%s: %s\\n\", ce->name, sha1_to_hex(ce->sha1));\n-\t\telse {\n-\t\t\tprintf(\"%s %s%c\", sha1_to_hex(ce->sha1), ce->name, 0);\n+\t\tif (!patch) {\n+\t\t\tstatic char *no_sha1_hex = \n+\t\t\t\t\"0000000000000000000000000000000000000000\";\n+\t\t\tprintf(\"*%o->%o\\t%s\\t%s->%s\\t%s%c\",\n+\t\t\t       ntohl(ce->ce_mode), st.st_mode,\n+\t\t\t       \"blob\", sha1_to_hex(ce->sha1), no_sha1_hex,\n+\t\t\t       ce->name, line_termination);\n \t\t\tcontinue;\n \t\t}\n+\t\telse\n+\t\t\tprintf(\"%s %s%c\", sha1_to_hex(ce->sha1), ce->name,\n+\t\t\t       line_termination);\n \t\tif (silent)\n \t\t\tcontinue;\n \n\n"},{"id":"1833","messageId":"7vd5shkrs5.fsf@assigned-by-dhcp.cox.net","threadId":"284","inReplyTo":"Pine.LNX.4.58.0504261639420.18901@ppc970.osdl.org","subject":"Re: [PATCH] Add -r flag to show-diff for diff-cache/diff-tree like output.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-27T00:05:46Z","receivedAt":"2005-04-27T00:05:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":">>>>> \"LT\" == Linus Torvalds <torvalds@osdl.org> writes:\n\n>> Later I'll add -p flag to diff-cache and diff-tree, so the usage\n>> of these three commands match.\n\nLT> The thing is, \"-p\" is strictly weaker than doing the UNIX\nLT> pipe way, since the latter trivially does the same time (add\nLT> a simple script if you don't want to type it), but can also\nLT> do things like \"grep the filenames going past\" or similar.\n\nI do not disagree with that.  Having only \"-p\" and not having\ndiff-cache/tree output _is_ weaker, and I am _not_ advocating\nfor removing the diff-cache/tree like output format from these\nthree commands.\n\nWhat I _am_ advocating for is to obsolete the diff-tree-helper\nprogram.  What it does can be done, with the diff.[ch] change\nyou merged this morning, without going through a pipe to the\ndiff-tree-helper process but directly from these three commands,\nonce diff-cache/tree acquires the \"-p\" flag.\n\nBy the way, how about renaming show-diff to diff-file?\n\n    diff-tree  : compares two trees.\n    diff-cache : compares a tree and the cache, or a tree and files.\n    diff-file  : compares the cache and files.\n\n"},{"id":"1834","messageId":"Pine.LNX.4.58.0504261719230.18901@ppc970.osdl.org","threadId":"284","inReplyTo":"7vy8b5ksqi.fsf_-_@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] diff-cache/tree compatible output for show-diff (take 2).","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-04-27T00:20:45Z","receivedAt":"2005-04-27T00:20:45Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 26 Apr 2005, Junio C Hamano wrote:\n>\n> This patch changes the output format of the show-diff command to\n> match that of the diff-cache/tree commands.  One type of record\n> it can produce that diff-cache/tree do not is of this form:\n\nDang, I already did this in my tree. I pushed mine out, and I don't want \nto see the \"-p\" flag until the others also do it (ie diff-tree and \ndiff-cache ;).\n\nBtw, diff-cache definitely _can_ output this form, so we probably should \nmake diff-cache do so too, to match, no?\n\n\t\tLinus\n"},{"id":"1835","messageId":"Pine.LNX.4.58.0504261721550.18901@ppc970.osdl.org","threadId":"284","inReplyTo":"7vd5shkrs5.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Add -r flag to show-diff for diff-cache/diff-tree like output.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-04-27T00:22:29Z","receivedAt":"2005-04-27T00:22:29Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 26 Apr 2005, Junio C Hamano wrote:\n> \n> By the way, how about renaming show-diff to diff-file?\n> \n>     diff-tree  : compares two trees.\n>     diff-cache : compares a tree and the cache, or a tree and files.\n>     diff-file  : compares the cache and files.\n\nYes. Except I think that the \"big renaming\" is coming up, and we should \njust rename them to have a \"git-\" prefix too.\n\n\t\tLinus\n"},{"id":"1836","messageId":"Pine.LNX.4.58.0504261725470.18901@ppc970.osdl.org","threadId":"284","inReplyTo":"Pine.LNX.4.58.0504261719230.18901@ppc970.osdl.org","subject":"Re: [PATCH] diff-cache/tree compatible output for show-diff (take 2).","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-04-27T00:29:12Z","receivedAt":"2005-04-27T00:29:12Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 26 Apr 2005, Linus Torvalds wrote:\n>\n> [ \"U\" for \"unmerged\" ]\n> \n> Btw, diff-cache definitely _can_ output this form, so we probably should \n> make diff-cache do so too, to match, no?\n\nActually, we should decide on what diff-tree-helper does before that. \nRight now it always either calls out to the external diff program, or it \nsays \"cannot parse\".\n\nIt's possible that an external \"diff\" program might actually want to know\nabout unmerged files (maybe people don't actually do \"diff\", but something\nelse altogether), so one approach might be to just make that an option.\n\nThe other approach is to just have something like \"<pathname> is unmerged\"\nas output from diff-tree-helper. That isn't quite as flexible, but it sure \nis simpler..\n\n\t\tLinus\n"},{"id":"1838","messageId":"Pine.LNX.4.58.0504261805070.18901@ppc970.osdl.org","threadId":"284","inReplyTo":"Pine.LNX.4.58.0504261750030.18901@ppc970.osdl.org","subject":"Re: [PATCH] diff-cache/tree compatible output for show-diff (take 2).","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-04-27T01:09:57Z","receivedAt":"2005-04-27T01:09:57Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 26 Apr 2005, Linus Torvalds wrote:\n> \n> I'll need to fix that up, because right now it does the wrong thing (which\n> it has always done): since we _remove_ all the merge entries, we'll first\n> warn about them, but then we'll show the original file going away if there\n> was one. Which is bogus.\n\nFixed. I think. My solution is clever, but untested.\n\nWhat I do is that instead of _removing_ the unmerged entries (which we \ncan't do, or we'd later think that the file has gone away if we see that \nsame name in the tree we're comparing against), I make all unmerged \nentries be in \"stage 3\".\n\nThen, when we read in the tree to compare against into stage 1, we have a \nfew cases:\n\n - stage 0 only: new file\n - stage 0 and 1: modified file\n - stage 1 only: deleted file\n - stage 1 and 3: unmerged\n - stage 3 only: unmerged\n\nSee any problems with this? (a mix of 0 and 3 cannot happen - a file is\neither unmerged or it is ok, since inserting a stage 0 entry always\nremoves all unmerged entires).\n\n\t\tLinus\n"}]}