{"thread":{"id":"25590","subject":"[PATCH] diff: support --root --cached combination","startedAt":"2010-10-29T09:54:47Z","lastAt":"2011-02-03T06:23:34Z","messageCount":9,"participants":["Nguyễn Thái Ngọc Duy","Jonathan Nieder","Nguyen Thai Ngoc Duy","Jeff King","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"154775","messageId":"1288346087-20263-1-git-send-email-pclouds@gmail.com","threadId":"25590","inReplyTo":null,"subject":"[PATCH] diff: support --root --cached combination","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-10-29T09:54:47Z","receivedAt":"2010-10-29T09:54:47Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n I have a ritual of doing \"git dic\" (short for diff --cached) before\n committing and does not want to break it, even on new repos.\n\n Looks like a good thing and no harm to the rest of the world.\n\n builtin/diff.c              |    9 +++++++--\n t/t4046-diff-cached-root.sh |   31 +++++++++++++++++++++++++++++++\n 2 files changed, 38 insertions(+), 2 deletions(-)\n create mode 100755 t/t4046-diff-cached-root.sh\n\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex a43d326..45be6f3 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -330,8 +330,13 @@ int cmd_diff(int argc, const char **argv, const char *prefix)\n \t\t\telse if (!strcmp(arg, \"--cached\") ||\n \t\t\t\t !strcmp(arg, \"--staged\")) {\n \t\t\t\tadd_head_to_pending(&rev);\n-\t\t\t\tif (!rev.pending.nr)\n-\t\t\t\t\tdie(\"No HEAD commit to compare with (yet)\");\n+\t\t\t\tif (!rev.pending.nr) {\n+\t\t\t\t\tstruct object *obj;\n+\t\t\t\t\tif (!rev.show_root_diff)\n+\t\t\t\t\t\tdie(\"No HEAD commit to compare with (yet)\");\n+\t\t\t\t\tobj = (struct object*)lookup_tree((unsigned char*)EMPTY_TREE_SHA1_BIN);\n+\t\t\t\t\tadd_pending_object(&rev, obj, \"HEAD\");\n+\t\t\t\t}\n \t\t\t\tbreak;\n \t\t\t}\n \t\t}\ndiff --git a/t/t4046-diff-cached-root.sh b/t/t4046-diff-cached-root.sh\nnew file mode 100755\nindex 0000000..82e3ad8\n--- /dev/null\n+++ b/t/t4046-diff-cached-root.sh\n@@ -0,0 +1,31 @@\n+#!/bin/sh\n+\n+test_description='git diff --cached --root test'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\techo cached >file &&\n+\tgit add file &&\n+\techo not-cached >>file\n+'\n+\n+test_expect_success 'diff --cached' '\n+\ttest_must_fail git diff --cached\n+'\n+\n+test_expect_success 'diff --cached --root' '\n+\tgit diff --cached --root >result &&\n+\tcat >expected <<\\EOF &&\n+diff --git a/file b/file\n+new file mode 100644\n+index 0000000..ec9a961\n+--- /dev/null\n++++ b/file\n+@@ -0,0 +1 @@\n++cached\n+EOF\n+\ttest_cmp expected result\n+'\n+\n+test_done\n-- \n1.7.0.2.445.gcbdb3\n"},{"id":"154776","messageId":"20101029101959.GA27662@burratino","threadId":"25590","inReplyTo":"1288346087-20263-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH] diff: support --root --cached combination","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2010-10-29T10:19:59Z","receivedAt":"2010-10-29T10:19:59Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Nguyễn Thái Ngọc Duy wrote:\n\n>  I have a ritual of doing \"git dic\" (short for diff --cached) before\n>  committing and does not want to break it, even on new repos.\n> \n>  Looks like a good thing and no harm to the rest of the world.\n\nThis explanation belongs in the commit message, methinks.\n\n> --- a/builtin/diff.c\n> +++ b/builtin/diff.c\n> @@ -330,8 +330,13 @@ int cmd_diff(int argc, const char **argv, const char *prefix)\n>  \t\t\telse if (!strcmp(arg, \"--cached\") ||\n>  \t\t\t\t !strcmp(arg, \"--staged\")) {\n>  \t\t\t\tadd_head_to_pending(&rev);\n> -\t\t\t\tif (!rev.pending.nr)\n> -\t\t\t\t\tdie(\"No HEAD commit to compare with (yet)\");\n> +\t\t\t\tif (!rev.pending.nr) {\n> +\t\t\t\t\tstruct object *obj;\n> +\t\t\t\t\tif (!rev.show_root_diff)\n> +\t\t\t\t\t\tdie(\"No HEAD commit to compare with (yet)\");\n\nHow does this condition get tripped?  The code allowing \"[log]\nshowroot\" to be set to false is only invoked by the log family of\ncommands.\n\nUsing --root as the backward-compatibility option seems like\nan abuse of language, anyway.  \"git diff --cached\" has two\nmeanings:\n\n 1. show changes to be committed\n\n    1b. show what git show --format=\" \" would say after a commit\n\n 2. show differences between the index and the commit named by the\n    (implicit) HEAD argument\n\nWith interpretation (1b), --root should be respected, and the output\nshould be empty (!), not an error, when \"[log] showroot\" is false.\n\nWith interpretation (2), --root should not be respected, and an\nattempt to diff --cached in an unborn branch should be an error.\n\n(1a) and (1b) are the only useful interpretations.  So for simplicity,\nwould it make sense to drop the \"if ()\" for --root and make\n\n> +test_expect_success 'diff --cached' '\n> +\ttest_must_fail git diff --cached\n> +'\n\nfail?\n\n> +\t\t\t\t\tobj = (struct object*)lookup_tree((unsigned char*)EMPTY_TREE_SHA1_BIN);\n\n\tstruct tree *tree = lookup_tree((const unsigned char *) ...\n\tobj = &tree->object;\n\nmight be more clear (and robust against future layout changes).\n"},{"id":"154779","messageId":"AANLkTikDhABbnT-tV-5WnUk1HaTzOfEywM1C0gJZ=bhk@mail.gmail.com","threadId":"25590","inReplyTo":"20101029101959.GA27662@burratino","subject":"Re: [PATCH] diff: support --root --cached combination","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-10-29T11:00:32Z","receivedAt":"2010-10-29T11:00:32Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"2010/10/29 Jonathan Nieder <jrnieder@gmail.com>:\n>> --- a/builtin/diff.c\n>> +++ b/builtin/diff.c\n>> @@ -330,8 +330,13 @@ int cmd_diff(int argc, const char **argv, const char *prefix)\n>>                       else if (!strcmp(arg, \"--cached\") ||\n>>                                !strcmp(arg, \"--staged\")) {\n>>                               add_head_to_pending(&rev);\n>> -                             if (!rev.pending.nr)\n>> -                                     die(\"No HEAD commit to compare with (yet)\");\n>> +                             if (!rev.pending.nr) {\n>> +                                     struct object *obj;\n>> +                                     if (!rev.show_root_diff)\n>> +                                             die(\"No HEAD commit to compare with (yet)\");\n>\n> How does this condition get tripped?  The code allowing \"[log]\n> showroot\" to be set to false is only invoked by the log family of\n> commands.\n>\n> Using --root as the backward-compatibility option seems like\n> an abuse of language, anyway.\n\nHmm.. I thought --root was supported by all diff command family. Now I\nthink of it, only \"diff-tree --root\" makes sense.\n\n>  \"git diff --cached\" has two meanings:\n>\n>  1. show changes to be committed\n>\n>    1b. show what git show --format=\" \" would say after a commit\n>\n>  2. show differences between the index and the commit named by the\n>    (implicit) HEAD argument\n>\n> With interpretation (1b), --root should be respected, and the output\n> should be empty (!), not an error, when \"[log] showroot\" is false.\n>\n> With interpretation (2), --root should not be respected, and an\n> attempt to diff --cached in an unborn branch should be an error.\n\nIf you commit to an unborn branch, it would become the first commit of\nthat branch. So by (1a), it should show what is to be commited, isn't\nit?\n\n>\n> (1a) and (1b) are the only useful interpretations.  So for simplicity,\n> would it make sense to drop the \"if ()\" for --root and make\n>\n>> +test_expect_success 'diff --cached' '\n>> +     test_must_fail git diff --cached\n>> +'\n>\n> fail?\n\nAll for simpler, yes.\n\n>\n>> +                                     obj = (struct object*)lookup_tree((unsigned char*)EMPTY_TREE_SHA1_BIN);\n>\n>        struct tree *tree = lookup_tree((const unsigned char *) ...\n>        obj = &tree->object;\n>\n> might be more clear (and robust against future layout changes).\n>\n\nOK\n\n-- \nDuy\n"},{"id":"154784","messageId":"20101029154051.GA3022@sigill.intra.peff.net","threadId":"25590","inReplyTo":"1288346087-20263-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH] diff: support --root --cached combination","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2010-10-29T15:40:51Z","receivedAt":"2010-10-29T15:40:51Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Oct 29, 2010 at 04:54:47PM +0700, Nguyễn Thái Ngọc Duy wrote:\n\n> \n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  I have a ritual of doing \"git dic\" (short for diff --cached) before\n>  committing and does not want to break it, even on new repos.\n> \n>  Looks like a good thing and no harm to the rest of the world.\n\nHmm. What's new is old, I suppose. You might want to read the comments\non my very similar patch here:\n\n  http://thread.gmane.org/gmane.comp.version-control.git/95935/focus=96187\n\n-Peff\n"},{"id":"154792","messageId":"7vhbg56i9s.fsf@alter.siamese.dyndns.org","threadId":"25590","inReplyTo":"20101029101959.GA27662@burratino","subject":"Re: [PATCH] diff: support --root --cached combination","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-10-29T17:06:07Z","receivedAt":"2010-10-29T17:06:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> Using --root as the backward-compatibility option seems like\n> an abuse of language, anyway.  \"git diff --cached\" has two\n> meanings:\n>\n>  1. show changes to be committed\n>\n>     1b. show what git show --format=\" \" would say after a commit\n>\n>  2. show differences between the index and the commit named by the\n>     (implicit) HEAD argument\n>\n> With interpretation (1b), --root should be respected, and the output\n> should be empty (!), not an error, when \"[log] showroot\" is false.\n>\n> With interpretation (2), --root should not be respected, and an\n> attempt to diff --cached in an unborn branch should be an error.\n>\n> (1a) and (1b) are the only useful interpretations.  So for simplicity,\n> would it make sense to drop the \"if ()\" for --root and make\n>\n>> +test_expect_success 'diff --cached' '\n>> +\ttest_must_fail git diff --cached\n>> +'\n>\n> fail?\n\nI don't see 1a up above, but I agree.\n\nLet's explain the patch this way (yes, I am writing a proposed commit log\nmessage Duy should have written):\n\n    \"git diff --cached\" (without revision) used to mean \"git diff --cached\n    HEAD\" (i.e. the user was too lazy to type HEAD).  This \"correctly\"\n    failed when there was no commit yet.  But was that correctness useful?\n\n    This patch changes the definition of what particular command means.\n    It is a request to show what _would_ be committed without further \"git\n    add\".  The internal implementation is still the same \"git diff\n    --cached HEAD\" when HEAD exists, but when there is no commit yet, it\n    compares the index with an empty tree object to achieve the desired\n    result.\n\nUnlike \"diff-index --cached HEAD\" that must fail when HEAD does not name a\nvalid rev, we do not have to be so strict in \"git diff\" Porcelain,\nespecially when the end user does not even explicitly say HEAD.\n\nTo put it in another way, we should strive to define the behaviour of the\nplumbing precisely in terms of the mechanism and machinery (e.g. if you\nask for an operation between a tree and the index, and if you incorrectly\nspecified the tree, you _should_ get an error, instead of a result that\nsomebody randomly chose, saying \"we thought it would be more useful for\nyou this way\").  But we should try to define the behaviour of the\nPorcelain commands in terms of the use case and the workflow we try to\nencourage and support.\n"},{"id":"154849","messageId":"1288437377-30405-1-git-send-email-pclouds@gmail.com","threadId":"25590","inReplyTo":"7vhbg56i9s.fsf@alter.siamese.dyndns.org","subject":"[PATCH v2] diff: support --cached on unborn branches","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-10-30T11:16:17Z","receivedAt":"2010-10-30T11:16:17Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\"git diff --cached\" (without revision) used to mean \"git diff --cached\nHEAD\" (i.e. the user was too lazy to type HEAD). This \"correctly\"\nfailed when there was no commit yet. But was that correctness useful?\n\nThis patch changes the definition of what particular command means.\nIt is a request to show what _would_ be committed without further \"git\nadd\". The internal implementation is still the same \"git diff\n--cached HEAD\" when HEAD exists, but when there is no commit yet, it\ncompares the index with an empty tree object to achieve the desired\nresult.\n\n(Written by Junio)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n \"git diff --cached HEAD\" does fail, but I don't really care.\n\n builtin/diff.c                      |    7 ++++-\n t/t4013-diff-various.sh             |   11 ++++++++++\n t/t4013/diff.diff_--cached          |   38 +++++++++++++++++++++++++++++++++++\n t/t4013/diff.diff_--cached_--_file0 |   15 +++++++++++++\n 4 files changed, 69 insertions(+), 2 deletions(-)\n create mode 100644 t/t4013/diff.diff_--cached\n create mode 100644 t/t4013/diff.diff_--cached_--_file0\n\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex a43d326..d8db957 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -330,8 +330,11 @@ int cmd_diff(int argc, const char **argv, const char *prefix)\n \t\t\telse if (!strcmp(arg, \"--cached\") ||\n \t\t\t\t !strcmp(arg, \"--staged\")) {\n \t\t\t\tadd_head_to_pending(&rev);\n-\t\t\t\tif (!rev.pending.nr)\n-\t\t\t\t\tdie(\"No HEAD commit to compare with (yet)\");\n+\t\t\t\tif (!rev.pending.nr) {\n+\t\t\t\t\tstruct tree *tree;\n+\t\t\t\t\ttree = lookup_tree((const unsigned char*)EMPTY_TREE_SHA1_BIN);\n+\t\t\t\t\tadd_pending_object(&rev, &tree->object, \"HEAD\");\n+\t\t\t\t}\n \t\t\t\tbreak;\n \t\t\t}\n \t\t}\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 9a66520..b8f81d0 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -290,4 +290,15 @@ test_expect_success 'log -S requires an argument' '\n \ttest_must_fail git log -S\n '\n \n+test_expect_success 'diff --cached on unborn branch' '\n+\techo ref: refs/heads/unborn >.git/HEAD &&\n+\tgit diff --cached >result &&\n+\ttest_cmp \"$TEST_DIRECTORY/t4013/diff.diff_--cached\" result\n+'\n+\n+test_expect_success 'diff --cached -- file on unborn branch' '\n+\tgit diff --cached -- file0 >result &&\n+\ttest_cmp \"$TEST_DIRECTORY/t4013/diff.diff_--cached_--_file0\" result\n+'\n+\n test_done\ndiff --git a/t/t4013/diff.diff_--cached b/t/t4013/diff.diff_--cached\nnew file mode 100644\nindex 0000000..ff16e83\n--- /dev/null\n+++ b/t/t4013/diff.diff_--cached\n@@ -0,0 +1,38 @@\n+diff --git a/dir/sub b/dir/sub\n+new file mode 100644\n+index 0000000..992913c\n+--- /dev/null\n++++ b/dir/sub\n+@@ -0,0 +1,8 @@\n++A\n++B\n++C\n++D\n++E\n++F\n++1\n++2\n+diff --git a/file0 b/file0\n+new file mode 100644\n+index 0000000..10a8a9f\n+--- /dev/null\n++++ b/file0\n+@@ -0,0 +1,9 @@\n++1\n++2\n++3\n++4\n++5\n++6\n++A\n++B\n++C\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\ndiff --git a/t/t4013/diff.diff_--cached_--_file0 b/t/t4013/diff.diff_--cached_--_file0\nnew file mode 100644\nindex 0000000..b9bb858\n--- /dev/null\n+++ b/t/t4013/diff.diff_--cached_--_file0\n@@ -0,0 +1,15 @@\n+diff --git a/file0 b/file0\n+new file mode 100644\n+index 0000000..10a8a9f\n+--- /dev/null\n++++ b/file0\n+@@ -0,0 +1,9 @@\n++1\n++2\n++3\n++4\n++5\n++6\n++A\n++B\n++C\n-- \n1.7.0.2.445.gcbdb3\n"},{"id":"154859","messageId":"7vwroz3vj8.fsf@alter.siamese.dyndns.org","threadId":"25590","inReplyTo":"1288437377-30405-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v2] diff: support --cached on unborn branches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-10-31T03:12:27Z","receivedAt":"2010-10-31T03:12:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> \"git diff --cached\" (without revision) used to mean \"git diff --cached\n> HEAD\" (i.e. the user was too lazy to type HEAD). This \"correctly\"\n> failed when there was no commit yet. But was that correctness useful?\n>\n> This patch changes the definition of what particular command means.\n> It is a request to show what _would_ be committed without further \"git\n> add\". The internal implementation is still the same \"git diff\n> --cached HEAD\" when HEAD exists, but when there is no commit yet, it\n> compares the index with an empty tree object to achieve the desired\n> result.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n\nWill take a look at it, and queue.  Thanks.\n\n>  \"git diff --cached HEAD\" does fail, but I don't really care.\n\nI _do_ care, and so should you.  And I think it _should_ fail, if the user\nexplicitly asked to compare the index with HEAD that does not exist yet.\n\nAs we are updating the semantics of a Porcelain command, there should be\nan update that explains the new usage in the documentation, no?\n"},{"id":"154860","messageId":"20101031032413.GA27346@do","threadId":"25590","inReplyTo":"7vwroz3vj8.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2] diff: support --cached on unborn branches","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-10-31T03:24:13Z","receivedAt":"2010-10-31T03:24:13Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sat, Oct 30, 2010 at 08:12:27PM -0700, Junio C Hamano wrote:\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n> \n> > \"git diff --cached\" (without revision) used to mean \"git diff --cached\n> > HEAD\" (i.e. the user was too lazy to type HEAD). This \"correctly\"\n> > failed when there was no commit yet. But was that correctness useful?\n> >\n> > This patch changes the definition of what particular command means.\n> > It is a request to show what _would_ be committed without further \"git\n> > add\". The internal implementation is still the same \"git diff\n> > --cached HEAD\" when HEAD exists, but when there is no commit yet, it\n> > compares the index with an empty tree object to achieve the desired\n> > result.\n> >\n> > Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> \n> Will take a look at it, and queue.  Thanks.\n> \n> >  \"git diff --cached HEAD\" does fail, but I don't really care.\n> \n> I _do_ care, and so should you.  And I think it _should_ fail, if the user\n> explicitly asked to compare the index with HEAD that does not exist yet.\n> \n> As we are updating the semantics of a Porcelain command, there should be\n> an update that explains the new usage in the documentation, no?\n\nYes.\n\n--8<--\ndiff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt\nindex dd1fb32..518e46b 100644\n--- a/Documentation/git-diff.txt\n+++ b/Documentation/git-diff.txt\n@@ -32,7 +32,9 @@ directories. This behavior can be forced by --no-index.\n \tThis form is to view the changes you staged for the next\n \tcommit relative to the named <commit>.  Typically you\n \twould want comparison with the latest commit, so if you\n-\tdo not give <commit>, it defaults to HEAD.\n+\tdo not give <commit>, it defaults to HEAD. If HEAD does\n+\tnot exist (e.g. unborn branches) and <commit> is not\n+\tgiven, it shows all staged changes.\n \t--staged is a synonym of --cached.\n \n 'git diff' [--options] <commit> [--] [<path>...]::\n--8<--\n-- \nDuy\n"},{"id":"160316","messageId":"1296714214-5165-1-git-send-email-pclouds@gmail.com","threadId":"25590","inReplyTo":"20101031032413.GA27346@do","subject":"[PATCH] diff: support --cached on unborn branches","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-02-03T06:23:34Z","receivedAt":"2011-02-03T06:23:34Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\"git diff --cached\" (without revision) used to mean \"git diff --cached\nHEAD\" (i.e. the user was too lazy to type HEAD). This \"correctly\"\nfailed when there was no commit yet. But was that correctness useful?\n\nThis patch changes the definition of what particular command means.\nIt is a request to show what _would_ be committed without further \"git\nadd\". The internal implementation is still the same \"git diff\n--cached HEAD\" when HEAD exists, but when there is no commit yet, it\ncompares the index with an empty tree object to achieve the desired\nresult.\n\n(Written by Junio)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n (Good) old stuff. I think it wasn't accepted because I was lazy in\n updating docs. Resend (with doc updates).\n\n Documentation/git-diff.txt          |    2 +\n builtin/diff.c                      |    7 ++++-\n t/t4013-diff-various.sh             |   11 ++++++++++\n t/t4013/diff.diff_--cached          |   38 +++++++++++++++++++++++++++++++++++\n t/t4013/diff.diff_--cached_--_file0 |   15 +++++++++++++\n 5 files changed, 71 insertions(+), 2 deletions(-)\n create mode 100644 t/t4013/diff.diff_--cached\n create mode 100644 t/t4013/diff.diff_--cached_--_file0\n\ndiff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt\nindex f6ac847..4910510 100644\n--- a/Documentation/git-diff.txt\n+++ b/Documentation/git-diff.txt\n@@ -38,6 +38,8 @@ directories. This behavior can be forced by --no-index.\n \tcommit relative to the named <commit>.  Typically you\n \twould want comparison with the latest commit, so if you\n \tdo not give <commit>, it defaults to HEAD.\n+\tIf HEAD does not exist (e.g. unborned branches) and\n+\t<commit> is not given, it shows all staged changes.\n \t--staged is a synonym of --cached.\n \n 'git diff' [--options] <commit> [--] [<path>...]::\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex 945e758..42822cd 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -330,8 +330,11 @@ int cmd_diff(int argc, const char **argv, const char *prefix)\n \t\t\telse if (!strcmp(arg, \"--cached\") ||\n \t\t\t\t !strcmp(arg, \"--staged\")) {\n \t\t\t\tadd_head_to_pending(&rev);\n-\t\t\t\tif (!rev.pending.nr)\n-\t\t\t\t\tdie(\"No HEAD commit to compare with (yet)\");\n+\t\t\t\tif (!rev.pending.nr) {\n+\t\t\t\t\tstruct tree *tree;\n+\t\t\t\t\ttree = lookup_tree((const unsigned char*)EMPTY_TREE_SHA1_BIN);\n+\t\t\t\t\tadd_pending_object(&rev, &tree->object, \"HEAD\");\n+\t\t\t\t}\n \t\t\t\tbreak;\n \t\t\t}\n \t\t}\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 9a66520..b8f81d0 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -290,4 +290,15 @@ test_expect_success 'log -S requires an argument' '\n \ttest_must_fail git log -S\n '\n \n+test_expect_success 'diff --cached on unborn branch' '\n+\techo ref: refs/heads/unborn >.git/HEAD &&\n+\tgit diff --cached >result &&\n+\ttest_cmp \"$TEST_DIRECTORY/t4013/diff.diff_--cached\" result\n+'\n+\n+test_expect_success 'diff --cached -- file on unborn branch' '\n+\tgit diff --cached -- file0 >result &&\n+\ttest_cmp \"$TEST_DIRECTORY/t4013/diff.diff_--cached_--_file0\" result\n+'\n+\n test_done\ndiff --git a/t/t4013/diff.diff_--cached b/t/t4013/diff.diff_--cached\nnew file mode 100644\nindex 0000000..ff16e83\n--- /dev/null\n+++ b/t/t4013/diff.diff_--cached\n@@ -0,0 +1,38 @@\n+diff --git a/dir/sub b/dir/sub\n+new file mode 100644\n+index 0000000..992913c\n+--- /dev/null\n++++ b/dir/sub\n+@@ -0,0 +1,8 @@\n++A\n++B\n++C\n++D\n++E\n++F\n++1\n++2\n+diff --git a/file0 b/file0\n+new file mode 100644\n+index 0000000..10a8a9f\n+--- /dev/null\n++++ b/file0\n+@@ -0,0 +1,9 @@\n++1\n++2\n++3\n++4\n++5\n++6\n++A\n++B\n++C\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\ndiff --git a/t/t4013/diff.diff_--cached_--_file0 b/t/t4013/diff.diff_--cached_--_file0\nnew file mode 100644\nindex 0000000..b9bb858\n--- /dev/null\n+++ b/t/t4013/diff.diff_--cached_--_file0\n@@ -0,0 +1,15 @@\n+diff --git a/file0 b/file0\n+new file mode 100644\n+index 0000000..10a8a9f\n+--- /dev/null\n++++ b/file0\n+@@ -0,0 +1,9 @@\n++1\n++2\n++3\n++4\n++5\n++6\n++A\n++B\n++C\n-- \n1.7.3.4.878.g439c7\n"}]}