{"thread":{"id":"349","subject":"[PATCH 0/6] External diff interface for diff-cache and friends.","startedAt":"2005-04-27T06:19:48Z","lastAt":"2005-04-27T17:37:11Z","messageCount":9,"participants":["Junio C Hamano","Linus Torvalds"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"1848","messageId":"7vekcwkagr.fsf@assigned-by-dhcp.cox.net","threadId":"349","inReplyTo":null,"subject":"[PATCH 0/6] External diff interface for diff-cache and friends.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-27T06:19:48Z","receivedAt":"2005-04-27T06:19:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"As discussed earlier, I am sending a series of patches to take\nadvantage of the simplified external diff interface you have\nalready merged.  This series consists of the following:\n\n[PATCH 1/6] Reworked external diff interface.\n\n    This patch introduces three public functions for diff-cache\n    and friends can use to call out to the GIT_EXTERNAL_DIFF\n    program when they wish to.  A normal \"add/remove/change\"\n    entry is turned into 7-parameter process invocation of\n    GIT_EXTERNAL_DIFF program as before.  In addition, the\n    program can now be called with a single parameter when\n    diff-cache and friends want to report an unmerged path.\n\n[PATCH 2/6] Reactivate show-diff patch generation\n\n    This patch uses the reworked diff interface to generate\n    patches directly out of show-diff when -p is specified.\n\n[PATCH 3/6] Add -p (patch) to diff-tree.\n\n    This patch uses the reworked diff interface to generate\n    patches directly out of diff-tree when -p is specified.\n\n[PATCH 4/6] Add -p (patch) to diff-cache.\n\n    This patch uses the reworked diff interface to generate\n    patches directly out of diff-cache when -p is specified.\n\n[PATCH 5/6] Teach diff-tree-helper to handle unmerged paths.\n\n    This patch teaches diff-tree-helper to call diff_unmreged()\n    so that it can report unmerged paths to GIT_EXTERNAL_DIFF.\n\n[PATCH 6/6] Alternative patch to diff-cache.c\n\n    This is a replacement of PATCH 4, in case you have already\n    applied the \"non-cached still looks only at cache\" fix I\n    sent you earlier.  If you took it, PATCH 4 may not apply\n    cleanly, in which case this should be easier to work with.\n\n"},{"id":"1849","messageId":"7vacnkka94.fsf@assigned-by-dhcp.cox.net","threadId":"349","inReplyTo":"7vekcwkagr.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 1/6] Reworked external diff interface.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-27T06:24:23Z","receivedAt":"2005-04-27T06:24:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This patch introduces three public functions for diff-cache and\nfriends can use to call out to the GIT_EXTERNAL_DIFF program\nwhen they wish to.  A normal \"add/remove/change\" entry is turned\ninto 7-parameter process invocation of GIT_EXTERNAL_DIFF program\nas before.  In addition, the program can now be called with a\nsingle parameter when diff-cache and friends want to report an\nunmerged path.\n\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\ndiff.c |   93 ++++++++++++++++++++++++++++++++++++++++-------------------------\ndiff.h |   19 +++++++++----\n2 files changed, 72 insertions(+), 40 deletions(-)\n\nTo be tested with the following:\n\n    GIT_INDEX_FILE=junk\n    export GIT_INDEX_FILE\n    read-tree $(cat .git/HEAD)\n    t1=$(write-tree)\n    date >trash ; update-cache --add trash\n    t2=$(write-tree)\n    read-tree -m $(cat .git/HEAD) $t1 $t2\n    update-cache --refresh\n    ./show-diff | GIT_EXTERNAL_DIFF=echo ./diff-tree-helper\n\n--- k/diff.c\n+++ l/diff.c\n@@ -194,13 +194,15 @@ void run_external_diff(const char *name,\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+\tif (one && two) {\n+\t\tprepare_temp_file(name, &temp[0], one);\n+\t\tprepare_temp_file(name, &temp[1], two);\n+\t\tif (! atexit_asked &&\n+\t\t    (temp[0].name == temp[0].tmp_path ||\n+\t\t     temp[1].name == temp[1].tmp_path)) {\n+\t\t\tatexit_asked = 1;\n+\t\t\tatexit(remove_tempfile);\n+\t\t}\n \t}\n \n \tfflush(NULL);\n@@ -209,16 +211,23 @@ void run_external_diff(const char *name,\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\tif (pgm) {\n+\t\t\tif (one && two)\n+\t\t\t\texeclp(pgm, pgm,\n+\t\t\t\t       name,\n+\t\t\t\t       temp[0].name, temp[0].hex, temp[0].mode,\n+\t\t\t\t       temp[1].name, temp[1].hex, temp[1].mode,\n+\t\t\t\t       NULL);\n+\t\t\telse\n+\t\t\t\texeclp(pgm, pgm, name, NULL);\n+\t\t}\n \t\t/*\n \t\t * otherwise we use the built-in one.\n \t\t */\n-\t\tbuiltin_diff(name, temp);\n+\t\tif (one && two)\n+\t\t\tbuiltin_diff(name, temp);\n+\t\telse\n+\t\t\tprintf(\"* Unmerged path %s\\n\", name);\n \t\texit(0);\n \t}\n \tif (waitpid(pid, &status, 0) < 0 || !WIFEXITED(status))\n@@ -227,41 +236,55 @@ void run_external_diff(const char *name,\n \tremove_tempfile();\n }\n \n-void show_diff_empty(const struct cache_entry *ce, int reverse)\n+void diff_addremove(int addremove, unsigned mode,\n+\t\t    const unsigned char *sha1,\n+\t\t    const char *base, const char *path)\n {\n+\tchar concatpath[PATH_MAX];\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+\tmemcpy(spec[0].u.sha1, sha1, 20);\n+\tspec[0].mode = mode;\n \tspec[0].sha1_valid = spec[0].file_valid = 1;\n \tspec[1].file_valid = 0;\n \n-\tif (reverse) {\n+\tif (addremove == '+') {\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+\t\n+\tif (path) {\n+\t\tstrcpy(concatpath, base);\n+\t\tstrcat(concatpath, \"/\");\n+\t\tstrcat(concatpath, path);\n+\t}\n+\trun_external_diff(path ? concatpath : base, 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+void diff_change(unsigned old_mode, unsigned new_mode,\n+\t\t const unsigned char *old_sha1,\n+\t\t const unsigned char *new_sha1,\n+\t\t const char *base, const char *path) {\n+\tchar concatpath[PATH_MAX];\n+\tstruct diff_spec spec[2];\n+\n+\tmemcpy(spec[0].u.sha1, old_sha1, 20);\n+\tspec[0].mode = old_mode;\n+\tmemcpy(spec[1].u.sha1, new_sha1, 20);\n+\tspec[1].mode = new_mode;\n \tspec[0].sha1_valid = spec[0].file_valid = 1;\n+\tspec[1].sha1_valid = spec[1].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+\tif (path) {\n+\t\tstrcpy(concatpath, base);\n+\t\tstrcat(concatpath, \"/\");\n+\t\tstrcat(concatpath, path);\n \t}\n+\trun_external_diff(path ? concatpath : base, &spec[0], &spec[1]);\n+}\n \n-\trun_external_diff(ce->name, one, two);\n+void diff_unmerge(const char *path)\n+{\n+\trun_external_diff(path, NULL, NULL);\n }\n--- k/diff.h\n+++ l/diff.h\n@@ -4,11 +4,20 @@\n #ifndef DIFF_H\n #define DIFF_H\n \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+extern void diff_addremove(int addremove,\n+\t\t\t   unsigned mode,\n+\t\t\t   const unsigned char *sha1,\n+\t\t\t   const char *base,\n+\t\t\t   const char *path);\n+\n+extern void diff_change(unsigned mode1, unsigned mode2,\n+\t\t\t     const unsigned char *sha1,\n+\t\t\t     const unsigned char *sha2,\n+\t\t\t     const char *base, const char *path);\n+\n+extern void diff_unmerge(const char *path);\n+\n+/* These are for diff-tree-helper */\n \n struct diff_spec {\n \tunion {\n\n"},{"id":"1850","messageId":"7v4qdska7r.fsf@assigned-by-dhcp.cox.net","threadId":"349","inReplyTo":"7vekcwkagr.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 2/6] Reactivate show-diff patch generation","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-27T06:25:12Z","receivedAt":"2005-04-27T06:25:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This patch uses the reworked diff interface to generate patches\ndirectly out of show-diff when -p is specified.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\nshow-diff.c |   56 ++++++++++++++++++++++++++++++++++++++++++--------------\n1 files changed, 42 insertions(+), 14 deletions(-)\n\nTo be tested with the following:\n\n    GIT_INDEX_FILE=junk\n    export GIT_INDEX_FILE\n    rm -f junk\n    date >trash ; update-cache --add trash\n    date >>trash;\n    GIT_EXTERNAL_DIFF=echo ./show-diff -p\n    update-cache --refresh\n    GIT_EXTERNAL_DIFF=echo ./show-diff -p\n\n--- k/show-diff.c\n+++ l/show-diff.c\n@@ -4,10 +4,11 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\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 = \"show-diff [-q] [-s] [-z] [-p] [paths...]\";\n \n-static int recursive = 0;\n+static int generate_patch = 0;\n static int line_termination = '\\n';\n static int silent = 0;\n static int silent_on_nonexisting_files = 0;\n@@ -27,27 +28,57 @@ static int matches_pathspec(struct cache\n \treturn 0;\n }\n \n-static void show_file(const char *prefix, struct cache_entry *ce)\n+static void show_unmerge(const char *path)\n {\n-\tprintf(\"%s%o\\t%s\\t%s\\t%s%c\", prefix, ntohl(ce->ce_mode), \"blob\",\n-\t\tsha1_to_hex(ce->sha1), ce->name, line_termination);\n+\tif (generate_patch)\n+\t\tdiff_unmerge(path);\n+\telse\n+\t\tprintf(\"U %s%c\", path, line_termination);\n+}\n+\n+static void show_file(int pfx, struct cache_entry *ce)\n+{\n+\tif (generate_patch)\n+\t\tdiff_addremove(pfx, ntohl(ce->ce_mode), ce->sha1,\n+\t\t\t       ce->name, NULL);\n+\telse\n+\t\tprintf(\"%c%06o\\t%s\\t%s\\t%s%c\",\n+\t\t       pfx, ntohl(ce->ce_mode), \"blob\",\n+\t\t       sha1_to_hex(ce->sha1), ce->name, line_termination);\n+}\n+\n+static void show_modified(int oldmode, int mode,\n+\t\t\t  const char *old_sha1, const char *sha1,\n+\t\t\t  char *path)\n+{\n+\tchar old_sha1_hex[41];\n+\tstrcpy(old_sha1_hex, sha1_to_hex(old_sha1));\n+\n+\tif (generate_patch)\n+\t\tdiff_change(oldmode, mode, old_sha1, sha1, path, NULL);\n+\telse\n+\t\tprintf(\"*%06o->%06o\\tblob\\t%s->%s\\t%s%c\",\n+\t\t       oldmode, mode, old_sha1_hex, sha1_to_hex(sha1), path,\n+\t\t       line_termination);\n }\n \n int main(int argc, char **argv)\n {\n-\tstatic const char null_sha1_hex[] = \"0000000000000000000000000000000000000000\";\n+\tstatic const char null_sha1[20] = { 0, };\n \tint entries = read_cache();\n \tint i;\n \n \twhile (1 < argc && argv[1][0] == '-') {\n \t\tif (!strcmp(argv[1], \"-s\"))\n \t\t\tsilent_on_nonexisting_files = silent = 1;\n+\t\telse if (!strcmp(argv[1], \"-p\"))\n+\t\t\tgenerate_patch = 1;\n \t\telse if (!strcmp(argv[1], \"-q\"))\n \t\t\tsilent_on_nonexisting_files = 1;\n \t\telse if (!strcmp(argv[1], \"-z\"))\n \t\t\tline_termination = 0;\n \t\telse if (!strcmp(argv[1], \"-r\"))\n-\t\t\trecursive = 1;\t\t/* No-op */\n+\t\t\t; /* no-op */\n \t\telse\n \t\t\tusage(show_diff_usage);\n \t\targv++; argc--;\n@@ -72,8 +103,7 @@ int main(int argc, char **argv)\n \t\t\tcontinue;\n \n \t\tif (ce_stage(ce)) {\n-\t\t\tprintf(\"U %s%c\", ce->name, line_termination);\n-\n+\t\t\tshow_unmerge(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@@ -88,7 +118,7 @@ int main(int argc, char **argv)\n \t\t\t}\t\n \t\t\tif (silent_on_nonexisting_files)\n \t\t\t\tcontinue;\n-\t\t\tshow_file(\"-\", ce);\n+\t\t\tshow_file('-', ce);\n \t\t\tcontinue;\n \t\t}\n \t\tchanged = cache_match_stat(ce, &st);\n@@ -98,10 +128,8 @@ int main(int argc, char **argv)\n \t\toldmode = ntohl(ce->ce_mode);\n \t\tmode = S_IFREG | ce_permissions(st.st_mode);\n \n-\t\tprintf(\"*%o->%o\\t%s\\t%s->%s\\t%s%c\",\n-\t\t\toldmode, mode, \"blob\",\n-\t\t\tsha1_to_hex(ce->sha1), null_sha1_hex,\n-\t\t\tce->name, line_termination);\n+\t\tshow_modified(oldmode, mode, ce->sha1, null_sha1,\n+\t\t\t      ce->name);\n \t}\n \treturn 0;\n }\n\n"},{"id":"1852","messageId":"7vy8b4ivmi.fsf@assigned-by-dhcp.cox.net","threadId":"349","inReplyTo":"7vekcwkagr.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 3/6] Add -p (patch) to diff-tree.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-27T06:25:41Z","receivedAt":"2005-04-27T06:25:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This patch uses the reworked diff interface to generate patches\ndirectly out of diff-tree when -p is specified.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\ndiff-tree.c |   35 ++++++++++++++++++++++++++---------\n1 files changed, 26 insertions(+), 9 deletions(-)\n\nTo be tested with the following:\n\n    GIT_INDEX_FILE=junk\n    export GIT_INDEX_FILE\n    rm -f junk\n    date >trash ; update-cache --add trash\n    t1=$(write-tree)\n    date >>trash; update-cache trash\n    t2=$(write-tree)    \n    GIT_EXTERNAL_DIFF=echo ./diff-tree -p $t1 $t2\n\n--- k/diff-tree.c\n+++ l/diff-tree.c\n@@ -1,7 +1,9 @@\n #include \"cache.h\"\n+#include \"diff.h\"\n \n static int recursive = 0;\n static int line_termination = '\\n';\n+static int generate_patch = 0;\n \n // What paths are we interested in?\n static int nr_paths = 0;\n@@ -79,10 +81,15 @@ static void show_file(const char *prefix\n \t\treturn;\n \t}\n \n-\tprintf(\"%s%o\\t%s\\t%s\\t%s%s%c\", prefix, mode,\n-\t       S_ISDIR(mode) ? \"tree\" : \"blob\",\n-\t       sha1_to_hex(sha1), base, path,\n-\t       line_termination);\n+\tif (generate_patch) {\n+\t\tif (!S_ISDIR(mode))\n+\t\t\tdiff_addremove(prefix[0], mode, sha1, base, path);\n+\t}\n+\telse\n+\t\tprintf(\"%s%06o\\t%s\\t%s\\t%s%s%c\", prefix, mode,\n+\t\t       S_ISDIR(mode) ? \"tree\" : \"blob\",\n+\t\t       sha1_to_hex(sha1), base, path,\n+\t\t       line_termination);\n }\n \n static int compare_tree_entry(void *tree1, unsigned long size1, void *tree2, unsigned long size2, const char *base)\n@@ -128,11 +135,17 @@ static int compare_tree_entry(void *tree\n \t\treturn retval;\n \t}\n \n-\tstrcpy(old_sha1_hex, sha1_to_hex(sha1));\n-\tprintf(\"*%o->%o\\t%s\\t%s->%s\\t%s%s%c\", mode1, mode2,\n-\t       S_ISDIR(mode1) ? \"tree\" : \"blob\",\n-\t       old_sha1_hex, sha1_to_hex(sha2), base, path1,\n-\t       line_termination);\n+\tif (generate_patch) {\n+\t\tif (!S_ISDIR(mode1))\n+\t\t\tdiff_change(mode1, mode2, sha1, sha2, base, path1);\n+\t}\n+\telse {\n+\t\tstrcpy(old_sha1_hex, sha1_to_hex(sha1));\n+\t\tprintf(\"*%06o->%06o\\t%s\\t%s->%s\\t%s%s%c\", mode1, mode2,\n+\t\t       S_ISDIR(mode1) ? \"tree\" : \"blob\",\n+\t\t       old_sha1_hex, sha1_to_hex(sha2), base, path1,\n+\t\t       line_termination);\n+\t}\n \treturn 0;\n }\n \n@@ -255,6 +268,10 @@ int main(int argc, char **argv)\n \t\t\trecursive = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"-p\")) {\n+\t\t\tgenerate_patch = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"-z\")) {\n \t\t\tline_termination = '\\0';\n \t\t\tcontinue;\n\n"},{"id":"1851","messageId":"7vr7gwivli.fsf@assigned-by-dhcp.cox.net","threadId":"349","inReplyTo":"7vekcwkagr.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 4/6] Add -p (patch) to diff-cache.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-27T06:26:17Z","receivedAt":"2005-04-27T06:26:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This patch uses the reworked diff interface to generate patches\ndirectly out of diff-cache when -p is specified.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\ndiff-cache.c |   37 ++++++++++++++++++++++++++++---------\n1 files changed, 28 insertions(+), 9 deletions(-)\n\nTo be tested with the following:\n\n    GIT_INDEX_FILE=junk\n    export GIT_INDEX_FILE\n    rm -f junk\n    date >trash ; update-cache --add trash\n    t1=$(write-tree)\n    date >>trash;\n    GIT_EXTERNAL_DIFF=echo ./diff-cache -p $t1\n    GIT_EXTERNAL_DIFF=echo ./diff-cache -p --cached $t1\n    update-cache trash\n    GIT_EXTERNAL_DIFF=echo ./diff-cache -p --cached $t1\n\n./diff-cache -p $(cat .git/HEAD) | filterdiff -i ?/diff-cache.c\n--- k/diff-cache.c\n+++ l/diff-cache.c\n@@ -1,13 +1,20 @@\n #include \"cache.h\"\n+#include \"diff.h\"\n \n static int cached_only = 0;\n+static int generate_patch = 0;\n static int line_termination = '\\n';\n \n /* A file entry went away or appeared */\n static void show_file(const char *prefix, struct cache_entry *ce)\n {\n-\tprintf(\"%s%o\\t%s\\t%s\\t%s%c\", prefix, ntohl(ce->ce_mode), \"blob\",\n-\t       sha1_to_hex(ce->sha1), ce->name, line_termination);\n+\tif (generate_patch)\n+\t\tdiff_addremove(prefix[0], ntohl(ce->ce_mode),\n+\t\t\t       ce->sha1, ce->name, NULL);\n+\telse\n+\t\tprintf(\"%s%06o\\tblob\\t%s\\t%s%c\", prefix, ntohl(ce->ce_mode),\n+\t\t       sha1_to_hex(ce->sha1), ce->name,\n+\t\t       line_termination);\n }\n \n static int show_modified(struct cache_entry *old, struct cache_entry *new)\n@@ -35,11 +42,15 @@ static int show_modified(struct cache_en\n \tif (mode == oldmode && !memcmp(sha1, old->sha1, 20))\n \t\treturn 0;\n \n-\tstrcpy(old_sha1_hex, sha1_to_hex(old->sha1));\n-\tprintf(\"*%o->%o\\t%s\\t%s->%s\\t%s%c\", oldmode, mode,\n-\t       \"blob\",\n-\t       old_sha1_hex, sha1_to_hex(sha1),\n-\t       old->name, line_termination);\n+\tif (generate_patch)\n+\t\tdiff_change(oldmode, mode,\n+\t\t\t    old->sha1, sha1, old->name, NULL);\n+\telse {\n+\t\tstrcpy(old_sha1_hex, sha1_to_hex(old->sha1));\n+\t\tprintf(\"*%06o->%06o\\tblob\\t%s->%s\\t%s%c\", oldmode, mode,\n+\t\t       old_sha1_hex, sha1_to_hex(sha1),\n+\t\t       old->name, line_termination);\n+\t}\n \treturn 0;\n }\n \n@@ -67,7 +78,10 @@ static int diff_cache(struct cache_entry\n \t\t\t}\n \t\t\t/* Otherwise we fall through to the \"unmerged\" case */\n \t\tcase 3:\n-\t\t\tprintf(\"U %s%c\", ce->name, line_termination);\n+\t\t\tif (generate_patch)\n+\t\t\t\tdiff_unmerge(ce->name);\n+\t\t\telse\n+\t\t\t\tprintf(\"U %s%c\", ce->name, line_termination);\n \t\t\tbreak;\n \n \t\tdefault:\n@@ -102,7 +116,8 @@ static void mark_merge_entries(void)\n \t}\n }\n \n-static char *diff_cache_usage = \"diff-cache [-r] [-z] [--cached] <tree sha1>\";\n+static char *diff_cache_usage =\n+\"diff-cache [-r] [-z] [-p] [--cached] <tree sha1>\";\n \n int main(int argc, char **argv)\n {\n@@ -119,6 +134,10 @@ int main(int argc, char **argv)\n \t\t\t/* We accept the -r flag just to look like diff-tree */\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"-p\")) {\n+\t\t\tgenerate_patch = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"-z\")) {\n \t\t\tline_termination = '\\0';\n \t\t\tcontinue;\n\n\n"},{"id":"1853","messageId":"7vk6moivjj.fsf@assigned-by-dhcp.cox.net","threadId":"349","inReplyTo":"7vekcwkagr.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 5/6] Teach diff-tree-helper to handle unmerged paths.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-27T06:27:28Z","receivedAt":"2005-04-27T06:27:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This patch teaches diff-tree-helper to call diff_unmrege() so\nthat it can report unmerged paths to GIT_EXTERNAL_DIFF, instead\nof consuming it on its own.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\ndiff-tree-helper.c |    2 +-\n1 files changed, 1 insertion(+), 1 deletion(-)\n\nTo be tested with the following:\n\n    GIT_INDEX_FILE=junk\n    export GIT_INDEX_FILE\n    read-tree $(cat .git/HEAD)\n    t1=$(write-tree)\n    date >trash ; update-cache --add trash\n    t2=$(write-tree)\n    read-tree -m $(cat .git/HEAD) $t1 $t2\n    update-cache --refresh\n    ./show-diff | GIT_EXTERNAL_DIFF=echo ./diff-tree-helper\n\n--- k/diff-tree-helper.c\n+++ l/diff-tree-helper.c\n@@ -56,7 +56,7 @@ static int parse_diff_tree_output(const \n \n \tswitch (*cp++) {\n \tcase 'U':\n-\t\tfprintf(stderr, \"warning: unmerged path %s\\n\", cp+1);\n+\t\tdiff_unmerge(cp + 1);\n \t\treturn WARNED_OURSELVES;\n \tcase '+':\n \t\told->file_valid = 0;\n\n"},{"id":"1854","messageId":"7vekcwivhe.fsf@assigned-by-dhcp.cox.net","threadId":"349","inReplyTo":"7vekcwkagr.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 6/6] Alternative patch to diff-cache.c","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-27T06:28:45Z","receivedAt":"2005-04-27T06:28:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This is a replacement of PATCH 4, in case you have already\napplied the \"non-cached still looks only at cache\" fix I\nsent you earlier.  If you took it, PATCH 4 may not apply\ncleanly, in which case this should be easier to work with.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\ndiff-cache.c |   73 ++++++++++++++++++++++++++++++++++++++++++++++++++---------\n1 files changed, 63 insertions(+), 10 deletions(-)\n\n--- k/diff-cache.c\n+++ l/diff-cache.c\n@@ -1,13 +1,41 @@\n #include \"cache.h\"\n+#include \"diff.h\"\n \n static int cached_only = 0;\n+static int generate_patch = 0;\n static int line_termination = '\\n';\n \n /* A file entry went away or appeared */\n static void show_file(const char *prefix, struct cache_entry *ce)\n {\n-\tprintf(\"%s%o\\t%s\\t%s\\t%s%c\", prefix, ntohl(ce->ce_mode), \"blob\",\n-\t       sha1_to_hex(ce->sha1), ce->name, line_termination);\n+\tif (generate_patch)\n+\t\tdiff_addremove(prefix[0], ntohl(ce->ce_mode),\n+\t\t\t       ce->sha1, ce->name, NULL);\n+\telse\n+\t\tprintf(\"%s%06o\\tblob\\t%s\\t%s%c\", prefix, ntohl(ce->ce_mode),\n+\t\t       sha1_to_hex(ce->sha1), ce->name,\n+\t\t       line_termination);\n+}\n+\n+/* A file *may* have been added to the working tree */\n+static void show_possible_local_add(struct cache_entry *new)\n+{\n+\tstatic unsigned char no_sha1[20];\n+\tstruct stat st;\n+\tif (stat(new->name, &st) < 0)\n+\t\t/* We signal the missing file by special mode 0 and\n+\t\t * let diff-tree-helper notice the missing file when it\n+\t\t * tries to open it by path.  Sneaky but works.\n+\t\t */\n+\t\tst.st_mode = 0;\n+\telse if (cache_match_stat(new, &st))\n+\t\treturn show_file(\"+\", new);\n+\n+\tif (generate_patch)\n+\t\tdiff_addremove('+', st.st_mode, no_sha1, new->name, NULL);\n+\telse\n+\t\tprintf(\"+%06o\\tblob\\t%s\\t%s%c\", st.st_mode,\n+\t\t       sha1_to_hex(no_sha1), new->name, line_termination);\n }\n \n static int show_modified(struct cache_entry *old, struct cache_entry *new)\n@@ -35,11 +63,15 @@ static int show_modified(struct cache_en\n \tif (mode == oldmode && !memcmp(sha1, old->sha1, 20))\n \t\treturn 0;\n \n-\tstrcpy(old_sha1_hex, sha1_to_hex(old->sha1));\n-\tprintf(\"*%o->%o\\t%s\\t%s->%s\\t%s%c\", oldmode, mode,\n-\t       \"blob\",\n-\t       old_sha1_hex, sha1_to_hex(sha1),\n-\t       old->name, line_termination);\n+\tif (generate_patch)\n+\t\tdiff_change(oldmode, mode,\n+\t\t\t    old->sha1, sha1, old->name, NULL);\n+\telse {\n+\t\tstrcpy(old_sha1_hex, sha1_to_hex(old->sha1));\n+\t\tprintf(\"*%06o->%06o\\tblob\\t%s->%s\\t%s%c\", oldmode, mode,\n+\t\t       old_sha1_hex, sha1_to_hex(sha1),\n+\t\t       old->name, line_termination);\n+\t}\n \treturn 0;\n }\n \n@@ -54,20 +86,36 @@ static int diff_cache(struct cache_entry\n \t\t\t/* No stage 1 entry? That means it's a new file */\n \t\t\tif (!same) {\n \t\t\t\tshow_file(\"+\", ce);\n+\t\t\t\t/* ... not so fast.  The working tree may\n+\t\t\t\t * also not have it anymore.\n+\t\t\t\t */\n+\t\t\t\tif (cached_only)\n+\t\t\t\t\tshow_file(\"+\", ce);\n+\t\t\t\telse\n+\t\t\t\t\tshow_possible_local_add(ce);\n \t\t\t\tbreak;\n \t\t\t}\n \t\t\t/* Show difference between old and new */\n \t\t\tshow_modified(ac[1], ce);\n \t\t\tbreak;\n \t\tcase 1:\n-\t\t\t/* No stage 3 (merge) entry? That means it's been deleted */\n+\t\t\t/* No stage 3 (merge) entry? That means it's been\n+\t\t\t * deleted.\n+\t\t\t */\n \t\t\tif (!same) {\n+\t\t\t\t/* The working tree may have it, but it does\n+\t\t\t\t * not matter.  If you write-tree and commit\n+\t\t\t\t * you would lose that file, so take notice.\n+\t\t\t\t */\n \t\t\t\tshow_file(\"-\", ce);\n \t\t\t\tbreak;\n \t\t\t}\n \t\t\t/* Otherwise we fall through to the \"unmerged\" case */\n \t\tcase 3:\n-\t\t\tprintf(\"U %s%c\", ce->name, line_termination);\n+\t\t\tif (generate_patch)\n+\t\t\t\tdiff_unmerge(ce->name);\n+\t\t\telse\n+\t\t\t\tprintf(\"U %s%c\", ce->name, line_termination);\n \t\t\tbreak;\n \n \t\tdefault:\n@@ -102,7 +150,8 @@ static void mark_merge_entries(void)\n \t}\n }\n \n-static char *diff_cache_usage = \"diff-cache [-r] [-z] [--cached] <tree sha1>\";\n+static char *diff_cache_usage =\n+\"diff-cache [-r] [-z] [-p] [--cached] <tree sha1>\";\n \n int main(int argc, char **argv)\n {\n@@ -119,6 +168,10 @@ int main(int argc, char **argv)\n \t\t\t/* We accept the -r flag just to look like diff-tree */\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"-p\")) {\n+\t\t\tgenerate_patch = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"-z\")) {\n \t\t\tline_termination = '\\0';\n \t\t\tcontinue;\n\n"},{"id":"1857","messageId":"7v4qdsiqgl.fsf@assigned-by-dhcp.cox.net","threadId":"349","inReplyTo":"7vekcwkagr.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 7/6] Leftover bits.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-27T08:17:14Z","receivedAt":"2005-04-27T08:17:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This is a minor cleanup to be applied on top of the last 6\npatches (the 6th is an alternate so the count actually is five).\n\nIt makes sure that external diff interface functions are called\neven when diff-tree detects directory changes.  Since it is not\nclear what to pass GIT_EXTERNAL_DIFF when we do see directory\nchanges, such calls are still currently dropped at the diff.c\ninterface function level, but whatever we will decide to do\nlater, the interface users should be cleaned up first anyway,\nand that is primarily what this patch is about.\n\nIt also adds code to unlink temporary files used to call the\nexternal diff command upon SIGNIT.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\ndiff-tree.c |    9 +++------\ndiff.c      |   14 ++++++++++++++\n2 files changed, 17 insertions(+), 6 deletions(-)\n\n# - 04/26 23:58 Mark the last of '-p' (patch) work.\n# + working tree\n--- k/diff-tree.c\n+++ l/diff-tree.c\n@@ -82,8 +82,7 @@ static void show_file(const char *prefix\n \t}\n \n \tif (generate_patch) {\n-\t\tif (!S_ISDIR(mode))\n-\t\t\tdiff_addremove(prefix[0], mode, sha1, base, path);\n+\t\tdiff_addremove(prefix[0], mode, sha1, base, path);\n \t}\n \telse\n \t\tprintf(\"%s%06o\\t%s\\t%s\\t%s%s%c\", prefix, mode,\n@@ -135,10 +134,8 @@ static int compare_tree_entry(void *tree\n \t\treturn retval;\n \t}\n \n-\tif (generate_patch) {\n-\t\tif (!S_ISDIR(mode1))\n-\t\t\tdiff_change(mode1, mode2, sha1, sha2, base, path1);\n-\t}\n+\tif (generate_patch)\n+\t\tdiff_change(mode1, mode2, sha1, sha2, base, path1);\n \telse {\n \t\tstrcpy(old_sha1_hex, sha1_to_hex(sha1));\n \t\tprintf(\"*%06o->%06o\\t%s\\t%s->%s\\t%s%s%c\", mode1, mode2,\n--- k/diff.c\n+++ l/diff.c\n@@ -127,6 +127,7 @@ static void prepare_temp_file(const char\n \n \tif (one->sha1_valid &&\n \t    !memcmp(one->u.sha1, null_sha1, sizeof(null_sha1))) {\n+\t\t/* \"It is valid but please go to the filesystem.\" */\n \t\tone->sha1_valid = 0;\n \t\tone->u.name = name;\n \t}\n@@ -180,6 +181,11 @@ static void remove_tempfile(void)\n \t\t}\n }\n \n+static void remove_tempfile_on_signal(int signo)\n+{\n+\tremove_tempfile();\n+}\n+\n /* An external diff command takes:\n  *\n  * diff-cmd name infile1 infile1-sha1 infile1-mode \\\n@@ -202,6 +208,7 @@ void run_external_diff(const char *name,\n \t\t     temp[1].name == temp[1].tmp_path)) {\n \t\t\tatexit_asked = 1;\n \t\t\tatexit(remove_tempfile);\n+\t\t\tsignal(SIGINT, remove_tempfile_on_signal);\n \t\t}\n \t}\n \n@@ -211,6 +218,7 @@ void run_external_diff(const char *name,\n \t\tdie(\"unable to fork\");\n \tif (!pid) {\n \t\tconst char *pgm = external_diff();\n+\n \t\tif (pgm) {\n \t\t\tif (one && two)\n \t\t\t\texeclp(pgm, pgm,\n@@ -243,6 +251,9 @@ void diff_addremove(int addremove, unsig\n \tchar concatpath[PATH_MAX];\n \tstruct diff_spec spec[2], *one, *two;\n \n+\tif (S_ISDIR(mode))\n+\t\treturn;\n+\n \tmemcpy(spec[0].u.sha1, sha1, 20);\n \tspec[0].mode = mode;\n \tspec[0].sha1_valid = spec[0].file_valid = 1;\n@@ -269,6 +280,9 @@ void diff_change(unsigned old_mode, unsi\n \tchar concatpath[PATH_MAX];\n \tstruct diff_spec spec[2];\n \n+\tif (S_ISDIR(old_mode) || S_ISDIR(new_mode))\n+\t\treturn;\n+\n \tmemcpy(spec[0].u.sha1, old_sha1, 20);\n \tspec[0].mode = old_mode;\n \tmemcpy(spec[1].u.sha1, new_sha1, 20);\n\n"},{"id":"1879","messageId":"Pine.LNX.4.58.0504271036150.18901@ppc970.osdl.org","threadId":"349","inReplyTo":"7v4qdsiqgl.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 7/6] Leftover bits.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-04-27T17:37:11Z","receivedAt":"2005-04-27T17:37:11Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 27 Apr 2005, Junio C Hamano wrote:\n> \n> It also adds code to unlink temporary files used to call the\n> external diff command upon SIGNIT.\n\nActually, you should probably do SIGPIPE too. I suspect that's the much\nmore common case (somebody does a \"diff-tree | less\", and then quits).\n\n\t\tLinus\n"}]}