{"thread":{"id":"43368","subject":"Re: Combined diff format documentation","startedAt":"2006-10-25T22:22:49Z","lastAt":"2006-10-26T07:10:06Z","messageCount":10,"participants":["Junio C Hamano","Jakub Narebski"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"294766","messageId":"ehoo2k$1g6$1@sea.gmane.org","threadId":"43368","inReplyTo":null,"subject":"Combined diff format documentation","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-10-25T22:22:49Z","receivedAt":"2006-10-25T22:22:49Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"In Documentation/diff-format.txt we can find the following information about\ncombined diff format:\n\n combined diff format\n --------------------\n \n git-diff-tree and git-diff-files can take '-c' or '--cc' option\n to produce 'combined diff', which looks like this: \n\n ------------\n diff --combined describe.c\n @@@ +98,7 @@@\n    return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;\n   }\n \n - static void describe(char *arg)\n  -static void describe(struct commit *cmit, int last_one)\n ++static void describe(char *arg, int last_one)\n   {\n  +     unsigned char sha1[20];\n  +     struct commit *cmit;\n ------------\n\nAnd it further goes how to read combined diff format, and how --cc\n(condensed combined) differs from --combined.\n\nThere is no note about which of extended headers functions with combined\ndiff format, how they change, how chunk header changes.\n\nFrom what I gathered, there are the following differences as compared to\nordinary (diff --git) git extended headers:\n\n1. \"git diff\" header which looked like this\n\n      diff --git a/file1 b/file2\n\n    is now\n\n      diff --combined file2\n\n    (where instead of --combined we might have --cc). Not described in\n    documentation.\n\n2. the \"index\" extended header line changes from\n\n     index <hash>..<hash> <mode>\n\n   to\n   \n     index <hash>,<hash>..<hash>\n\n   Mode information is put in separate line, only if mode changes, for\n   example\n\n     mode <mode>,<mode>..<mode>\n\n   <mode> can be 000000 if file didn't exist in particular parent; if file\n   was cerated by merge we have\n\n     new file mode <mode>\n\n   I haven't checked what happens if file is deleted, either by branch or by\n   merge commit itself. Not described in documentation, I'm not sure about\n   how this (wrt modes) works.\n\n3. The \"rename/copy\" headers seems to be never present; see below.\n\n4. From file/to file header _seems_ to function exactly like in ordinary\n   diff format, namely\n\n     --- a/file1\n     +++ b/file2\n\n   But it seems to function rather like in ordinary \"git diff\" header,\n   i.e. we have a/file1 instead of /dev/null even for files created by\n   merge. I have not checked if and how rename detection work here.\n\n5. Hunk header is also modified: in ordinary diff we have\n\n     @@ <from range> <to range> @@\n\n   where <from range> is -<start line>,<number of lines>, and <to range>\n   is +<start line>,<number of lines>. In combined diff format it changes\n   similarly to \"index\" extended header, namely\n\n     @@@ <from range> <from range> <to range> @@@\n\n   It might be not obvoious that we have (number of parents + 1) '@'\n   characters in chunk header for combined dif format.\n\n   BTW. it is not mentioned in documentation that git diff uses hunk section\n   indicator, and what regexp/expression it uses (and is it configurable).\n   Not described in documentation.\n\n6. Documentation/diff-format.txt explains combined and condensed combined\n   format quite well, although it doesn't tell us if we can have plusses and\n   minuses together in one line...\n\n\n=====================================================================\n\nCombined diff format an renames detection\n-----------------------------------------\n\nWe have the following situation:\n$ git ls-tree -r --abbrev HEAD\n100644 blob 1ce3f81     greetings/goodbye.txt\n100644 blob 980a0d5     greetings/hello.txt\n$ git ls-tree -r --abbrev HEAD^1\n100644 blob 980a0d5     greetings/hello.txt\n$ git ls-tree -r --abbrev HEAD^2\n100644 blob 1ce3f81     data/goodbye.txt\n100644 blob 980a0d5     data/hello.txt\n\nBelow there are following diffs: with first parent, merge (with all parents)\nwith renames detection, combined, combined with rename detection. Is it all\nexpected?\n\n$ git diff-tree -p HEAD^1 HEAD\ndiff --git a/greetings/goodbye.txt b/greetings/goodbye.txt\nnew file mode 100644\nindex 0000000..1ce3f81\n--- /dev/null\n+++ b/greetings/goodbye.txt\n@@ -0,0 +1 @@\n+Goodbye World!\n\n$ git diff-tree -p -M -m HEAD\nd0fdd886e3b768678832c8d826bb8b70f2ef7b8e\ndiff --git a/greetings/goodbye.txt b/greetings/goodbye.txt\nnew file mode 100644\nindex 0000000..1ce3f81\n--- /dev/null\n+++ b/greetings/goodbye.txt\n@@ -0,0 +1 @@\n+Goodbye World!\nd0fdd886e3b768678832c8d826bb8b70f2ef7b8e\ndiff --git a/data/goodbye.txt b/greetings/goodbye.txt\nsimilarity index 100%\nrename from data/goodbye.txt\nrename to greetings/goodbye.txt\ndiff --git a/data/hello.txt b/greetings/hello.txt\nsimilarity index 100%\nrename from data/hello.txt\nrename to greetings/hello.txt\n\n$ git diff-tree -p -c HEAD\nd0fdd886e3b768678832c8d826bb8b70f2ef7b8e\ndiff --combined greetings/goodbye.txt\nindex 0000000,0000000..1ce3f81\nnew file mode 100644\n--- a/greetings/goodbye.txt\n+++ b/greetings/goodbye.txt\n@@@ -1,0 -1,0 +1,1 @@@\n++Goodbye World!\n\n$ git diff-tree -p -c -M HEAD\nd0fdd886e3b768678832c8d826bb8b70f2ef7b8e\ndiff --combined greetings/goodbye.txt\nindex 0000000,1ce3f81..1ce3f81\nmode 000000,100644..100644\n--- a/greetings/goodbye.txt\n+++ b/greetings/goodbye.txt\n@@@ -1,0 -1,1 +1,1 @@@\n+ Goodbye World!\n\nAnd to compare, latest with --cc (condensed combined) instead of -c:\n$ git diff-tree -p --cc -M HEAD\nd0fdd886e3b768678832c8d826bb8b70f2ef7b8e\ndiff --cc greetings/goodbye.txt\nindex 0000000,1ce3f81..1ce3f81\nmode 000000,100644..100644\n--- a/greetings/goodbye.txt\n+++ b/greetings/goodbye.txt\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n\n"},{"id":"297038","messageId":"7vejswkoi4.fsf@assigned-by-dhcp.cox.net","threadId":"43368","inReplyTo":"ehoo2k$1g6$1@sea.gmane.org","subject":"Re: Combined diff format documentation","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-10-25T22:40:51Z","receivedAt":"2006-10-25T22:40:51Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n> 1. \"git diff\" header which looked like this\n> 2. the \"index\" extended header line changes from\n> 3. The \"rename/copy\" headers seems to be never present; see below.\n>...\n\nThanks for starting this.  Your observation is correct.  It was\npretty much designed for quick _content_ inspection and renames\nwould work correctly to pick which blobs from each tree to\ncompare but otherwise not reflected in the output (the pathnames\nare not shown as far as I know).  We could probably add it if\nsome users need it.\n\n> 5. Hunk header is also modified: in ordinary diff we have\n> ...\n>    It might be not obvoious that we have (number of parents + 1) '@'\n>    characters in chunk header for combined dif format.\n\nCorrect.  This was done to prevent people from accidentally\nfeeding it to \"patch -p1\".  In other words, we wanted to make it\nso obvious that it is _not_ a patch.\n\nThere may be more information in \"git log -- combine-diff.c\"\noutput that ought to be collected into the documentation, and\nnow might be a good time to do so, given that that part of the\nsystem is fairly stable and has not changed for quite some time\nin git timescale.\n\n>    BTW. it is not mentioned in documentation that git diff uses hunk section\n>    indicator, and what regexp/expression it uses (and is it configurable).\n>    Not described in documentation.\n\nIf you mean by \"hunk section indicator\" the output similar to\nGNU diff -p option, I think it is not worth mentioning and we\nare not ready to mention it yet (we have not etched the\nexpression in stone).  Nobody jumped up and down to say it needs\nto be configurable, so it is left undocumented more or less\ndeliberately.\n\n> 6. Documentation/diff-format.txt explains combined and condensed combined\n>    format quite well, although it doesn't tell us if we can have plusses and\n>    minuses together in one line...\n\nBut you already know the answer to that question, since you\nasked me a few days ago ;-).\n\nPatches to documentation would be easier to comment on and more\nproductive, I guess.\n\n> Below there are following diffs: with first parent, merge (with all parents)\n> with renames detection, combined, combined with rename detection. Is it all\n> expected?\n\nYes.  I do not see anything obviously unexpected in your output.\n\n"},{"id":"297579","messageId":"ehoq5r$8h5$1@sea.gmane.org","threadId":"43368","inReplyTo":"7vejswkoi4.fsf@assigned-by-dhcp.cox.net","subject":"Re: Combined diff format documentation","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-10-25T22:58:39Z","receivedAt":"2006-10-25T22:58:39Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Junio C Hamano wrote:\n> Jakub Narebski <jnareb@gmail.com> writes:\n>\n>> 6. Documentation/diff-format.txt explains combined and condensed combined\n>>    format quite well, although it doesn't tell us if we can have plusses and\n>>    minuses together in one line...\n> \n> But you already know the answer to that question, since you\n> asked me a few days ago ;-).\n\nYes, in \"[RFC] Syntax highlighting for combined diff\" thread\nhttp://permalink.gmane.org/gmane.comp.version-control.git/29566\n\nWell, the _documentation_ doesn't tell. I haven't fully grokked the code\nfor generating and coloring combined diff output besides the fact that\nI think it uses last indicator ('+' or '-') to chose color for the rest\nof line. You said that even if the possibility exist, it is extreme\nunlikely.\n\n> Patches to documentation would be easier to comment on and more\n> productive, I guess.\n\nI was not sure about output. All conclusions about combined diff output\nare from examples; I've planned to send patch to documentation when I'll\nbe sure that at least _most_ of what I've added is correct.\n\nWill do.\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n\n"},{"id":"294519","messageId":"7vy7r4j8dy.fsf@assigned-by-dhcp.cox.net","threadId":"43368","inReplyTo":"ehoq5r$8h5$1@sea.gmane.org","subject":"Re: Combined diff format documentation","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-10-25T23:14:17Z","receivedAt":"2006-10-25T23:14:17Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n> I was not sure about output. All conclusions about combined diff output\n> are from examples; I've planned to send patch to documentation when I'll\n> be sure that at least _most_ of what I've added is correct.\n>\n> Will do.\n\nThanks.\n"},{"id":"298259","messageId":"7vslhcj7x8.fsf@assigned-by-dhcp.cox.net","threadId":"43368","inReplyTo":"ehoq5r$8h5$1@sea.gmane.org","subject":"Re: Combined diff format documentation","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-10-25T23:24:19Z","receivedAt":"2006-10-25T23:24:19Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n> Well, the _documentation_ doesn't tell. I haven't fully grokked the code\n> for generating and coloring combined diff output besides the fact that\n> I think it uses last indicator ('+' or '-') to chose color for the rest\n> of line. You said that even if the possibility exist, it is extreme\n> unlikely.\n\nWell if I said that I must have been on booze ;-).\n\nA '-' in the nth column means that the line is from the nth\nparent and does _not_ appear in the merge result.  A '+' in the\nnth column means that the line _appears_ in the merge result,\nand the nth parent does not have that line (i.e. added by the\nmerge itself, or inherited from other parents).\n\nHence, by definition, you cannot have '-' and '+' on the same\nline (otherwise the line has to exist and not exist in the merge\nresult at the same time).\n\nA ' ' is a bit tricky to interpret.  A ' ' on a line _without_\nany '-' means the line is the same as in that parent and the\nmerge result (i.e. the result inherited the line from that\nparent).  A ' ' on a line that has '-' talks nothing about the\nmerge result (because by definition '-' lines do not exist in\nthe merge result) nor the parent that has ' '; in other words,\nit is a \"don't care\" bit.  In the example you quoted from the\ncommit log of af3feefa:\n\n         - static void describe(char *arg)\n          -static void describe(struct commit *cmit, int last_one)\n         ++static void describe(char *arg, int last_one)\n           {\n\nThe first parent had it as one-arg function, and the second one\ntwo-arg but the first parameter was of type \"struct commit *\";\nthe merge result has it as two-arg with the first parameter of\ntype \"char *\".  The second parent does not know about the\none-arg form of the function so it has ' ' in its column for the\nfirst line.\n\nAll versions start the function with an opening brace '{' so the\nline has two ' ' prefixed, which is an example of ' ' on a line\nwithout any '-'.\n\n\n"},{"id":"295456","messageId":"ehost8$go7$1@sea.gmane.org","threadId":"43368","inReplyTo":"7vejswkoi4.fsf@assigned-by-dhcp.cox.net","subject":"Re: Combined diff format documentation","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-10-25T23:45:16Z","receivedAt":"2006-10-25T23:45:16Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Junio C Hamano wrote:\n\n>>    BTW. it is not mentioned in documentation that git diff uses hunk section\n>>    indicator, and what regexp/expression it uses (and is it configurable).\n>>    Not described in documentation.\n> \n> If you mean by \"hunk section indicator\" the output similar to\n> GNU diff -p option, I think it is not worth mentioning and we\n> are not ready to mention it yet (we have not etched the\n> expression in stone).  Nobody jumped up and down to say it needs\n> to be configurable, so it is left undocumented more or less\n> deliberately.\n\nBy the way, I have just checked that combined diff format doesn't have\n(for unknown reason) \"which section\" indicator in chunk header.\nCompare\n$ git diff-tree -p -m fec9ebf16c948bcb4a8b88d0173ee63584bcde76\nand\n$ git diff-tree -p -c fec9ebf16c948bcb4a8b88d0173ee63584bcde76\n(this is the source of example combined diff format in diff-formats.txt\nwhich I've found via\n$ git rev-list --parents HEAD -- describe.c | grep \" .* \"\ni.e. finding all merges which included changes to describe.c; there\nare only two such commits).\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n\n"},{"id":"298243","messageId":"200610260544.50614.jnareb@gmail.com","threadId":"43368","inReplyTo":"7vejswkoi4.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] diff-format.txt: Combined diff format documentation supplement","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-10-26T03:44:49Z","receivedAt":"2006-10-26T03:44:49Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Update example combined diff format to the current version\n$ git diff-tree -p -c fec9ebf16c948bcb4a8b88d0173ee63584bcde76\nand provide complete first chunk in example.\n\nDocument combined diff format headers: how \"diff header\" look like,\nwhich of \"extended diff headers\" are used with combined diff and how\nthey look like, differences in two-line from-file/to-file header from\nnon-combined diff format, chunk header format.\n\nIt should be noted that combined diff format was designed for quick\n_content_ inspection and renames would work correctly to pick which\nblobs from each tree to compare but otherwise not reflected in the\noutput (the pathnames are not shown).\n\nSigned-off-by: Jakub Narebski <jnareb@gmail.com>\n---\nJunio C Hamano napisał:\n> Patches to documentation would be easier to comment on and more\n> productive, I guess.\n\nSo here you have. It should perhaps get review on validity by someone\nwell versed in the combined diff generation code. There are some guesses\nhere...\n\nIt compiles, but the output was not inspected.\n\n\n Documentation/diff-format.txt |   70 ++++++++++++++++++++++++++++++++++++++---\n 1 files changed, 65 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/diff-format.txt b/Documentation/diff-format.txt\nindex 617d8f5..0d04b03 100644\n--- a/Documentation/diff-format.txt\n+++ b/Documentation/diff-format.txt\n@@ -156,18 +156,78 @@ to produce 'combined diff', which looks \n \n ------------\n diff --combined describe.c\n-@@@ +98,7 @@@\n-   return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;\n+index fabadb8,cc95eb0..4866510\n+--- a/describe.c\n++++ b/describe.c\n+@@@ -98,20 -98,12 +98,20 @@@\n+  \treturn (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;\n   }\n-\n+  \n - static void describe(char *arg)\n  -static void describe(struct commit *cmit, int last_one)\n ++static void describe(char *arg, int last_one)\n   {\n- +     unsigned char sha1[20];\n- +     struct commit *cmit;\n+ +\tunsigned char sha1[20];\n+ +\tstruct commit *cmit;\n+  \tstruct commit_list *list;\n+  \tstatic int initialized = 0;\n+  \tstruct commit_name *n;\n+  \n+ +\tif (get_sha1(arg, sha1) < 0)\n+ +\t\tusage(describe_usage);\n+ +\tcmit = lookup_commit_reference(sha1);\n+ +\tif (!cmit)\n+ +\t\tusage(describe_usage);\n+ +\n+  \tif (!initialized) {\n+  \t\tinitialized = 1;\n+  \t\tfor_each_ref(get_name);\n ------------\n \n+1.   It is preceded with a \"git diff\" header, that looks like\n+     this (when '-c' option is used):\n+\n+       diff --combined fileM\n+\n+     or like this (when '--cc' option is used):\n+\n+       diff --c fileM\n+\n+2.   It is followed by one or more extended header lines\n+     (we assume here that we have merge with two parents):\n+\n+       index <hash>,<hash>..<hash>\n+       mode <mode>,<mode>..<mode>\n+       new file mode <mode>\n+\n+     The \"mode <mode>,<mode>..<mode>\" appears only if at least\n+     one of the <mode> is diferent from the rest. Extended headers\n+     with information about detected contents movement (renames\n+     and copying detection) are designed to work with diff of two\n+     <tree-ish> and are not used by combined diff format. Currently\n+     combined diff format cannot show files which were removed\n+     by merge, so \"deleted file mode <mode>,<mode>\" is never used.\n+\n+3.   It is followed by two-line from-file/to-file header\n+\n+       --- a/fileM\n+       +++ b/fileM\n+\n+     Contrary to two-line header for traditional 'unified' diff\n+     format, and similar to filenames in ordinary \"diff header\",\n+     /dev/null is not used for creation combined diff.\n+\n+4.   Chunk header format is modified to prevent people from\n+     accidentally feeding it to 'patch -p1'. Combined diff format\n+     was created for review of merge commit changes, and was not\n+     meant for apply. The change is similar to the change in the\n+     extended 'index' header\n+\n+       @@@ <from-file-range> <from-file-range> <to-file-range> @@@\n+\n+     It might be not obvious that we have number of parents + 1\n+     '@' characters in chunk header for combined diff format.\n+\n Unlike the traditional 'unified' diff format, which shows two\n files A and B with a single column that has `-` (minus --\n appears in A but removed in B), `+` (plus -- missing in A but\n-- \n1.4.2.1\n\n\n\n-- \nJakub Narebski\n"},{"id":"294801","messageId":"7vac3jk3g7.fsf@assigned-by-dhcp.cox.net","threadId":"43368","inReplyTo":"200610260544.50614.jnareb@gmail.com","subject":"Re: [PATCH] diff-format.txt: Combined diff format documentation supplement","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-10-26T06:15:36Z","receivedAt":"2006-10-26T06:15:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n> So here you have. It should perhaps get review on validity by someone\n> well versed in the combined diff generation code. There are some guesses\n> here...\n\nThanks.\n\nI guess review by the original author would be good enough;\nthis is entirely my code -- it was done while Linus and gang\nwas having fun in NZ, if I recall correctly ;-).\n\n> It compiles, but the output was not inspected.\n\nI've done minimal asciidoc mark-up fixes.  Troff man output look\nhorrible but that is not limited to this man page -- it looks\nquite wrong whenever numbered list with displayed examples are\nused.\n"},{"id":"296441","messageId":"7v1wovsgkf.fsf@assigned-by-dhcp.cox.net","threadId":"43368","inReplyTo":"7vac3jk3g7.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] diff-format.txt: Combined diff format documentation supplement","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-10-26T07:05:04Z","receivedAt":"2006-10-26T07:05:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"By the way, this is only minimally tested, but this patch fills\nthe blanks in your documentation.\n\nThe combine_diff_path structure _does_ keep track of the\noriginal path in each parent, so renames _could_ be shown (we do\nnot keep the score, though), but the question is how.  \"rename to\"\nwould obviously be \"the path in the merge result\", but \"rename from\"\nneeds to be shown for all parents when we have rename from any\nof the parents.  \"rename from\" line as in the usual one parent diff\ndoes not have any place to say \"which parent\" (because there is\nno need), so showing the usual \"rename from\" for only parents\nthat the result has rename from makes the output useless -- we\ncannot tell \"from which parent\" from such an output.  I feel\nthat an evil merge is rare enough that worrying about showing\nrename line is probably not worth the effort.\n\n-- >8 --\n[PATCH] combine-diff: a few more finishing touches.\n\n\"new file\" and \"deleted file\" were already reported in the\noriginal code, but the logic was not as transparent as it could\nhave.  This uses a few variables and more comments to clarify\nthe flow.  The rule is: (1) if a path exists in the merge result\nwhen no parent had it, we report \"new\" (otherwise it came from\nthe parents, as opposed to have added by the evil merge). (2) if\nthe path does not exist in the merge result, it is \"deleted\".\n\nSince we can say \"new\" and \"deleted\", there is no reason not to\nfollow the /dev/null convention.  This fixes it.\n\nAppending function name after @@@ ... @@@ is trivial, so\nimplement it.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n combine-diff.c |   48 +++++++++++++++++++++++++++++++++++++++++++-----\n 1 files changed, 43 insertions(+), 5 deletions(-)\n\ndiff --git a/combine-diff.c b/combine-diff.c\nindex 46d9121..01a8437 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -489,6 +489,12 @@ static void show_parent_lno(struct sline\n \tprintf(\" -%lu,%lu\", l0, l1-l0);\n }\n \n+static int hunk_comment_line(const char *bol)\n+{\n+\tint ch = *bol & 0xff;\n+\treturn (isalpha(ch) || ch == '_' || ch == '$');\n+}\n+\n static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,\n \t\t       int use_color)\n {\n@@ -508,8 +514,13 @@ static void dump_sline(struct sline *sli\n \t\tstruct sline *sl = &sline[lno];\n \t\tunsigned long hunk_end;\n \t\tunsigned long rlines;\n-\t\twhile (lno <= cnt && !(sline[lno].flag & mark))\n+\t\tconst char *hunk_comment = NULL;\n+\n+\t\twhile (lno <= cnt && !(sline[lno].flag & mark)) {\n+\t\t\tif (hunk_comment_line(sline[lno].bol))\n+\t\t\t\thunk_comment = sline[lno].bol;\n \t\t\tlno++;\n+\t\t}\n \t\tif (cnt < lno)\n \t\t\tbreak;\n \t\telse {\n@@ -526,6 +537,22 @@ static void dump_sline(struct sline *sli\n \t\t\tshow_parent_lno(sline, lno, hunk_end, i);\n \t\tprintf(\" +%lu,%lu \", lno+1, rlines);\n \t\tfor (i = 0; i <= num_parent; i++) putchar(combine_marker);\n+\n+\t\tif (hunk_comment) {\n+\t\t\tint comment_end = 0;\n+\t\t\tfor (i = 0; i < 40; i++) {\n+\t\t\t\tint ch = hunk_comment[i] & 0xff;\n+\t\t\t\tif (!ch || ch == '\\n')\n+\t\t\t\t\tbreak;\n+\t\t\t\tif (!isspace(ch))\n+\t\t\t\t    comment_end = i;\n+\t\t\t}\n+\t\t\tif (comment_end)\n+\t\t\t\tputchar(' ');\n+\t\t\tfor (i = 0; i < comment_end; i++)\n+\t\t\t\tputchar(hunk_comment[i]);\n+\t\t}\n+\n \t\tprintf(\"%s\\n\", c_reset);\n \t\twhile (lno < hunk_end) {\n \t\t\tstruct lline *ll;\n@@ -707,6 +734,8 @@ static void show_patch_diff(struct combi\n \t\tint use_color = opt->color_diff;\n \t\tconst char *c_meta = diff_get_color(use_color, DIFF_METAINFO);\n \t\tconst char *c_reset = diff_get_color(use_color, DIFF_RESET);\n+\t\tint added = 0;\n+\t\tint deleted = 0;\n \n \t\tif (rev->loginfo)\n \t\t\tshow_log(rev, opt->msg_sep);\n@@ -722,7 +751,10 @@ static void show_patch_diff(struct combi\n \t\tprintf(\"..%s%s\\n\", abb, c_reset);\n \n \t\tif (mode_differs) {\n-\t\t\tint added = !!elem->mode;\n+\t\t\tdeleted = !elem->mode;\n+\n+\t\t\t/* We say it was added if nobody had it */\n+\t\t\tadded = !deleted;\n \t\t\tfor (i = 0; added && i < num_parent; i++)\n \t\t\t\tif (elem->parent[i].status !=\n \t\t\t\t    DIFF_STATUS_ADDED)\n@@ -731,7 +763,7 @@ static void show_patch_diff(struct combi\n \t\t\t\tprintf(\"%snew file mode %06o\",\n \t\t\t\t       c_meta, elem->mode);\n \t\t\telse {\n-\t\t\t\tif (!elem->mode)\n+\t\t\t\tif (deleted)\n \t\t\t\t\tprintf(\"%sdeleted file \", c_meta);\n \t\t\t\tprintf(\"mode \");\n \t\t\t\tfor (i = 0; i < num_parent; i++) {\n@@ -743,8 +775,14 @@ static void show_patch_diff(struct combi\n \t\t\t}\n \t\t\tprintf(\"%s\\n\", c_reset);\n \t\t}\n-\t\tdump_quoted_path(\"--- a/\", elem->path, c_meta, c_reset);\n-\t\tdump_quoted_path(\"+++ b/\", elem->path, c_meta, c_reset);\n+\t\tif (added)\n+\t\t\tdump_quoted_path(\"--- /dev/\", \"null\", c_meta, c_reset);\n+\t\telse\n+\t\t\tdump_quoted_path(\"--- a/\", elem->path, c_meta, c_reset);\n+\t\tif (deleted)\n+\t\t\tdump_quoted_path(\"+++ /dev/\", \"null\", c_meta, c_reset);\n+\t\telse\n+\t\t\tdump_quoted_path(\"+++ b/\", elem->path, c_meta, c_reset);\n \t\tdump_sline(sline, cnt, num_parent, opt->color_diff);\n \t}\n \tfree(result);\n"},{"id":"296932","messageId":"7vvem7r1rl.fsf@assigned-by-dhcp.cox.net","threadId":"43368","inReplyTo":"7v1wovsgkf.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] diff-format.txt: Combined diff format documentation supplement","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-10-26T07:10:06Z","receivedAt":"2006-10-26T07:10:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This script minimally demonstrates a few interesting things an\nevil merge can do.  Run it in a throw-away directory and view\nthe resulting merge with \"git-show\" with or without the patch I\nsent out earlier.\n\nOne thing that you would notice is that the combined-diff code\nchooses not to show the original contents of a deleted\nfile. while showing the whole result of a new file.  Strictly\nspeaking, this is inconsistent, but an evil merge is rare and\nwhat ended up getting removed is not as interesting as what\nremains as the result.\n\n-- >8 --\n#!/bin/sh\n\ntest -d .git && {\n\techo Run me in an empty directory please\n\texit 1\n}\n\ngit init-db\n\necho one >file1.txt\ngit add file1.txt\ngit commit -m initial\n\ngit branch side\n\necho two >file2.txt\ngit add file2.txt\ngit commit -m second\n\ngit checkout side\necho uno >file1.txt\ngit commit -a -m side\n\ngit merge \"Evil merge\" HEAD master\nrm -f file1.txt\necho added by the evil merge >file3.txt\necho modified by the evil merge >file2.txt\ngit update-index --add --remove file1.txt file2.txt file3.txt\nEDITOR=: VISUAL=: git commit --amend\n\n\n\n"}]}