{"thread":{"id":"32669","subject":"[PATCH] unpack-trees: do not abort when overwriting an existing file with the same content","startedAt":"2013-01-19T11:24:08Z","lastAt":"2013-01-22T20:19:29Z","messageCount":9,"participants":["Nguyễn Thái Ngọc Duy","Junio C Hamano","Duy Nguyen","Jeff King"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"207257","messageId":"1358594648-26851-1-git-send-email-pclouds@gmail.com","threadId":"32669","inReplyTo":null,"subject":"[PATCH] unpack-trees: do not abort when overwriting an existing file with the same content","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-01-19T11:24:08Z","receivedAt":"2013-01-19T11:24:08Z","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 The \"git reset\" as illustrated in the test case is one case people\n may be hit by this. We can also do the same for \"uptodate\" check, but\n I'm not sure how that could happen.\n\n t/t1011-read-tree-sparse-checkout.sh |  3 ++-\n t/t2021-checkout-overwrite.sh        |  8 ++++++++\n unpack-trees.c                       | 27 +++++++++++++++++++++++++++\n 3 files changed, 37 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh\nindex 5c0053a..38f9899 100755\n--- a/t/t1011-read-tree-sparse-checkout.sh\n+++ b/t/t1011-read-tree-sparse-checkout.sh\n@@ -238,7 +238,8 @@ test_expect_success 'print errors when failed to update worktree' '\n \techo sub >.git/info/sparse-checkout &&\n \tgit checkout -f init &&\n \tmkdir sub &&\n-\ttouch sub/added sub/addedtoo &&\n+\techo modified >sub/added &&\n+\techo modified >sub/addedtoo &&\n \ttest_must_fail git checkout top 2>actual &&\n \tcat >expected <<\\EOF &&\n error: The following untracked working tree files would be overwritten by checkout:\ndiff --git a/t/t2021-checkout-overwrite.sh b/t/t2021-checkout-overwrite.sh\nindex 5da63e9..4163449 100755\n--- a/t/t2021-checkout-overwrite.sh\n+++ b/t/t2021-checkout-overwrite.sh\n@@ -47,4 +47,12 @@ test_expect_success SYMLINKS 'checkout commit with dir must not remove untracked\n \ttest -h a/b\n '\n \n+test_expect_success 'do not abort on overwriting an existing file with the same content' '\n+\techo abc >bar &&\n+\tgit add bar &&\n+\tgit commit -m \"new file\" &&\n+\tgit reset HEAD^ &&\n+\tgit checkout HEAD@{1}\n+'\n+\n test_done\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 0e1a196..16adc03 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -1363,6 +1363,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,\n \t\t\t      struct unpack_trees_options *o)\n {\n \tstruct cache_entry *result;\n+\tunsigned long ce_size;\n \n \t/*\n \t * It may be that the 'lstat()' succeeded even though\n@@ -1405,6 +1406,32 @@ static int check_ok_to_remove(const char *name, int len, int dtype,\n \t\t\treturn 0;\n \t}\n \n+\t/*\n+\t * If it has the same content that we are going to write down,\n+\t * there's no point in complaining. We still overwrite it in the\n+\t * end though. Permission is not checked so it may be lost.\n+\t */\n+\tif (ce &&\n+\t    S_ISREG(st->st_mode) && S_ISREG(ce->ce_mode) &&\n+\t    st->st_size < 1024 * 1024 && /* should be configurable */\n+\t    sha1_object_info(ce->sha1, &ce_size) == OBJ_BLOB &&\n+\t    ce_size == st->st_size) {\n+\t\tvoid *buffer = NULL;\n+\t\tunsigned long size;\n+\t\tenum object_type type;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\tint matched =\n+\t\t\tstrbuf_read_file(&sb, ce->name, ce_size) == ce_size &&\n+\t\t\t(buffer = read_sha1_file(ce->sha1, &type, &size)) != NULL &&\n+\t\t\ttype == OBJ_BLOB &&\n+\t\t\tsize == ce_size &&\n+\t\t\t!memcmp(buffer, sb.buf, size);\n+\t\tfree(buffer);\n+\t\tstrbuf_release(&sb);\n+\t\tif (matched)\n+\t\t\treturn 0;\n+\t}\n+\n \treturn o->gently ? -1 :\n \t\tadd_rejected_path(o, error_type, name);\n }\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"207312","messageId":"7va9s3n1my.fsf@alter.siamese.dyndns.org","threadId":"32669","inReplyTo":"1358594648-26851-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH] unpack-trees: do not abort when overwriting an existing file with the same content","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-20T18:35:33Z","receivedAt":"2013-01-20T18:35:33Z","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> +\t/*\n> +\t * If it has the same content that we are going to write down,\n\nwrite down???\n\n> +\t * there's no point in complaining. We still overwrite it in the\n> +\t * end though. Permission is not checked so it may be lost.\n> +\t */\n\nThat is a regression, isn't it?  Is it too cumbersome to avoid\nlosing the permission bits by stopping in that case?\n\n> +\tif (ce &&\n> +\t    S_ISREG(st->st_mode) && S_ISREG(ce->ce_mode) &&\n> +\t    st->st_size < 1024 * 1024 && /* should be configurable */\n> +\t    sha1_object_info(ce->sha1, &ce_size) == OBJ_BLOB &&\n> +\t    ce_size == st->st_size) {\n> +\t\tvoid *buffer = NULL;\n> +\t\tunsigned long size;\n> +\t\tenum object_type type;\n> +\t\tstruct strbuf sb = STRBUF_INIT;\n> +\t\tint matched =\n> +\t\t\tstrbuf_read_file(&sb, ce->name, ce_size) == ce_size &&\n> +\t\t\t(buffer = read_sha1_file(ce->sha1, &type, &size)) != NULL &&\n> +\t\t\ttype == OBJ_BLOB &&\n> +\t\t\tsize == ce_size &&\n> +\t\t\t!memcmp(buffer, sb.buf, size);\n> +\t\tfree(buffer);\n> +\t\tstrbuf_release(&sb);\n> +\t\tif (matched)\n> +\t\t\treturn 0;\n> +\t}\n> +\n>  \treturn o->gently ? -1 :\n>  \t\tadd_rejected_path(o, error_type, name);\n>  }\n"},{"id":"207353","messageId":"CACsJy8C-vRVsC5uj8xqucwMBZ2TEtwSF-58xM2oTSp6RtNAWMg@mail.gmail.com","threadId":"32669","inReplyTo":"7va9s3n1my.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] unpack-trees: do not abort when overwriting an existing file with the same content","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-01-21T01:35:44Z","receivedAt":"2013-01-21T01:35:44Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Jan 21, 2013 at 1:35 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n>\n>> +     /*\n>> +      * If it has the same content that we are going to write down,\n>\n> write down???\n\nhmm.. \"overwrite\" then.\n\n>> +      * there's no point in complaining. We still overwrite it in the\n>> +      * end though. Permission is not checked so it may be lost.\n>> +      */\n>\n> That is a regression, isn't it?  Is it too cumbersome to avoid\n> losing the permission bits by stopping in that case?\n\nI'm not sure how to deal with this case. (Lack of) Executable bit can\nbe easily restored (unlike file content) if we give the user the list\nof changed files. On the other hand, not everybody runs git with a\nhuge scrollback buffer and warnings can be lost. I guess abort is a\nsafe choice.\n-- \nDuy\n"},{"id":"207390","messageId":"1358768433-26096-1-git-send-email-pclouds@gmail.com","threadId":"32669","inReplyTo":"1358594648-26851-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2] unpack-trees: do not abort when overwriting an existing file with the same content","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-01-21T11:40:33Z","receivedAt":"2013-01-21T11:40:33Z","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 Changes: do not lose worktree's executable permission.\n\n t/t1011-read-tree-sparse-checkout.sh |  3 ++-\n t/t2021-checkout-overwrite.sh        | 18 ++++++++++++++++++\n unpack-trees.c                       | 31 +++++++++++++++++++++++++++++++\n 3 files changed, 51 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh\nindex 5c0053a..38f9899 100755\n--- a/t/t1011-read-tree-sparse-checkout.sh\n+++ b/t/t1011-read-tree-sparse-checkout.sh\n@@ -238,7 +238,8 @@ test_expect_success 'print errors when failed to update worktree' '\n \techo sub >.git/info/sparse-checkout &&\n \tgit checkout -f init &&\n \tmkdir sub &&\n-\ttouch sub/added sub/addedtoo &&\n+\techo modified >sub/added &&\n+\techo modified >sub/addedtoo &&\n \ttest_must_fail git checkout top 2>actual &&\n \tcat >expected <<\\EOF &&\n error: The following untracked working tree files would be overwritten by checkout:\ndiff --git a/t/t2021-checkout-overwrite.sh b/t/t2021-checkout-overwrite.sh\nindex 5da63e9..bb1696d 100755\n--- a/t/t2021-checkout-overwrite.sh\n+++ b/t/t2021-checkout-overwrite.sh\n@@ -47,4 +47,22 @@ test_expect_success SYMLINKS 'checkout commit with dir must not remove untracked\n \ttest -h a/b\n '\n \n+test_expect_success 'do not abort on overwriting an existing file with the same content' '\n+\techo abc >bar &&\n+\tgit add bar &&\n+\tgit commit -m \"new file\" &&\n+\tgit reset HEAD^ &&\n+\tgit checkout HEAD@{1}\n+'\n+\n+test_expect_success POSIXPERM 'do abort on an existing file, same content but different permission' '\n+\tgit checkout -f HEAD^ &&\n+\techo abc >bar &&\n+\tgit add bar &&\n+\tgit commit -m \"new file\" &&\n+\tgit reset HEAD^ &&\n+\tchmod a+x bar &&\n+\ttest_must_fail git checkout HEAD@{1}\n+'\n+\n test_done\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 0e1a196..ea204ae 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -9,6 +9,8 @@\n #include \"refs.h\"\n #include \"attr.h\"\n \n+#define SAME_CONTENT_SIZE_LIMIT (1024 * 1024)\n+\n /*\n  * Error messages expected by scripts out of plumbing commands such as\n  * read-tree.  Non-scripted Porcelain is not required to use these messages\n@@ -1363,6 +1365,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,\n \t\t\t      struct unpack_trees_options *o)\n {\n \tstruct cache_entry *result;\n+\tunsigned long ce_size;\n \n \t/*\n \t * It may be that the 'lstat()' succeeded even though\n@@ -1405,6 +1408,34 @@ static int check_ok_to_remove(const char *name, int len, int dtype,\n \t\t\treturn 0;\n \t}\n \n+\t/*\n+\t * If it has the same content that we are going to overwrite,\n+\t * there's no point in complaining. We still overwrite it in\n+\t * the end though.\n+\t */\n+\tif (ce &&\n+\t    S_ISREG(st->st_mode) && S_ISREG(ce->ce_mode) &&\n+\t    (!trust_executable_bit ||\n+\t     (0100 & (ce->ce_mode ^ st->st_mode)) == 0) &&\n+\t    st->st_size < SAME_CONTENT_SIZE_LIMIT &&\n+\t    sha1_object_info(ce->sha1, &ce_size) == OBJ_BLOB &&\n+\t    ce_size == st->st_size) {\n+\t\tvoid *buffer = NULL;\n+\t\tunsigned long size;\n+\t\tenum object_type type;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\tint matched =\n+\t\t\tstrbuf_read_file(&sb, ce->name, ce_size) == ce_size &&\n+\t\t\t(buffer = read_sha1_file(ce->sha1, &type, &size)) != NULL &&\n+\t\t\ttype == OBJ_BLOB &&\n+\t\t\tsize == ce_size &&\n+\t\t\t!memcmp(buffer, sb.buf, size);\n+\t\tfree(buffer);\n+\t\tstrbuf_release(&sb);\n+\t\tif (matched)\n+\t\t\treturn 0;\n+\t}\n+\n \treturn o->gently ? -1 :\n \t\tadd_rejected_path(o, error_type, name);\n }\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"207451","messageId":"20130121231515.GD17156@sigill.intra.peff.net","threadId":"32669","inReplyTo":"1358768433-26096-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH v2] unpack-trees: do not abort when overwriting an existing file with the same content","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2013-01-21T23:15:15Z","receivedAt":"2013-01-21T23:15:15Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jan 21, 2013 at 06:40:33PM +0700, Nguyen Thai Ngoc Duy wrote:\n\n> +\t/*\n> +\t * If it has the same content that we are going to overwrite,\n> +\t * there's no point in complaining. We still overwrite it in\n> +\t * the end though.\n> +\t */\n> +\tif (ce &&\n> +\t    S_ISREG(st->st_mode) && S_ISREG(ce->ce_mode) &&\n> +\t    (!trust_executable_bit ||\n> +\t     (0100 & (ce->ce_mode ^ st->st_mode)) == 0) &&\n> +\t    st->st_size < SAME_CONTENT_SIZE_LIMIT &&\n> +\t    sha1_object_info(ce->sha1, &ce_size) == OBJ_BLOB &&\n> +\t    ce_size == st->st_size) {\n> +\t\tvoid *buffer = NULL;\n> +\t\tunsigned long size;\n> +\t\tenum object_type type;\n> +\t\tstruct strbuf sb = STRBUF_INIT;\n> +\t\tint matched =\n> +\t\t\tstrbuf_read_file(&sb, ce->name, ce_size) == ce_size &&\n> +\t\t\t(buffer = read_sha1_file(ce->sha1, &type, &size)) != NULL &&\n> +\t\t\ttype == OBJ_BLOB &&\n> +\t\t\tsize == ce_size &&\n> +\t\t\t!memcmp(buffer, sb.buf, size);\n> +\t\tfree(buffer);\n> +\t\tstrbuf_release(&sb);\n> +\t\tif (matched)\n> +\t\t\treturn 0;\n> +\t}\n\nCan you elaborate on when this code is triggered?\n\nIn the general case, shouldn't we already know the sha1 of what's on\ndisk in the index, and be able to just compare the hashes? And if we\ndon't, because the entry is start-dirty, should we be updating it\n(possibly earlier, so we do not even get into the \"need to write\" code\npath) instead of doing this ad-hoc byte comparison?\n\nConfused...\n\n-Peff\n"},{"id":"207461","messageId":"CACsJy8AFKXYkHbUf4aqBpCg+v06oFsvHq_zxQFE4BOCzTDAqtg@mail.gmail.com","threadId":"32669","inReplyTo":"20130121231515.GD17156@sigill.intra.peff.net","subject":"Re: [PATCH v2] unpack-trees: do not abort when overwriting an existing file with the same content","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-01-22T00:59:01Z","receivedAt":"2013-01-22T00:59:01Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Jan 22, 2013 at 6:15 AM, Jeff King <peff@peff.net> wrote:\n> Can you elaborate on when this code is triggered?\n>\n> In the general case, shouldn't we already know the sha1 of what's on\n> disk in the index, and be able to just compare the hashes? And if we\n> don't, because the entry is start-dirty, should we be updating it\n> (possibly earlier, so we do not even get into the \"need to write\" code\n> path) instead of doing this ad-hoc byte comparison?\n>\n> Confused...\n\ngit reset HEAD~10\n# blah that was a mistake, undo it\ngit checkout HEAD@{1}\n\nI hit it a few times, probably not with the exact recipe above though.\n-- \nDuy\n"},{"id":"207463","messageId":"7vwqv6c7oe.fsf@alter.siamese.dyndns.org","threadId":"32669","inReplyTo":"CACsJy8AFKXYkHbUf4aqBpCg+v06oFsvHq_zxQFE4BOCzTDAqtg@mail.gmail.com","subject":"Re: [PATCH v2] unpack-trees: do not abort when overwriting an existing file with the same content","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-22T01:45:05Z","receivedAt":"2013-01-22T01:45:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> On Tue, Jan 22, 2013 at 6:15 AM, Jeff King <peff@peff.net> wrote:\n>> Can you elaborate on when this code is triggered?\n>>\n>> In the general case, shouldn't we already know the sha1 of what's on\n>> disk in the index, and be able to just compare the hashes? And if we\n>> don't, because the entry is start-dirty, should we be updating it\n>> (possibly earlier, so we do not even get into the \"need to write\" code\n>> path) instead of doing this ad-hoc byte comparison?\n\nIf the index knows what is in the working tree, I think I agree.\n\n>> Confused...\n>\n> git reset HEAD~10\n> # blah that was a mistake, undo it\n> git checkout HEAD@{1}\n>\n> I hit it a few times, probably not with the exact recipe above though.\n\nI've seen myself doing \"git reset HEAD~10\" by mistake (I wanted \"--hard\"),\nbut the recovery is to do \"git reset --hard @{1}\" and then come back\nwith \"git reset --hard HEAD~10\", so it hasn't been a real problem\nfor me.\n\nA case similar to this is already covered by a special case of\ntwo-tree read-tree where the index already matches the tree we are\nchecking out even though it is different from HEAD; in other words,\nif you did this:\n\n        git init\n        date >file\n        git add file; git commit -m 'has a file'\n        git checkout -b side\n        git rm file; git commit -m 'does not have the file'\n        git checkout master file\n\t: now index has the file from 'master' and worktree is clean\n        git checkout master\n\nyou shouldn't get any complaint, I think.\n\nIf you did \"git rm --cached file\" to lose it from the index,\nimmediately after \"git checkout master file\", then we wouldn't know\nwhat we may be losing.  If the file in the working tree happens to\nmatch the index and the HEAD after checking out the other branch\n('master' in this case), it is _not_ losing information, so we might\nbe able to treat it as an extension of the existing special case.\n\nI haven't thought things through to see if in a more general case\nthat this codepath triggers we might be losing a local changes that\nwe should be carrying forward while checking out a new branch,\nthough.\n"},{"id":"207465","messageId":"CACsJy8CwkKyCLefrghVbq74FmeP7bPZAML-P=9s5PoPuNyT2Yg@mail.gmail.com","threadId":"32669","inReplyTo":"7vwqv6c7oe.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2] unpack-trees: do not abort when overwriting an existing file with the same content","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-01-22T01:55:01Z","receivedAt":"2013-01-22T01:55:01Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Jan 22, 2013 at 8:45 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Duy Nguyen <pclouds@gmail.com> writes:\n>\n>> On Tue, Jan 22, 2013 at 6:15 AM, Jeff King <peff@peff.net> wrote:\n>>> Can you elaborate on when this code is triggered?\n>>>\n>>> In the general case, shouldn't we already know the sha1 of what's on\n>>> disk in the index, and be able to just compare the hashes? And if we\n>>> don't, because the entry is start-dirty, should we be updating it\n>>> (possibly earlier, so we do not even get into the \"need to write\" code\n>>> path) instead of doing this ad-hoc byte comparison?\n>\n> If the index knows what is in the working tree, I think I agree.\n>\n>>> Confused...\n>>\n>> git reset HEAD~10\n>> # blah that was a mistake, undo it\n>> git checkout HEAD@{1}\n>>\n>> I hit it a few times, probably not with the exact recipe above though.\n>\n> I've seen myself doing \"git reset HEAD~10\" by mistake (I wanted \"--hard\"),\n> but the recovery is to do \"git reset --hard @{1}\" and then come back\n> with \"git reset --hard HEAD~10\", so it hasn't been a real problem\n> for me.\n\nExcept when you already make some changes elsewhere and you don't want --hard.\n-- \nDuy\n"},{"id":"207523","messageId":"20130122201929.GB23521@sigill.intra.peff.net","threadId":"32669","inReplyTo":"7vwqv6c7oe.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2] unpack-trees: do not abort when overwriting an existing file with the same content","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2013-01-22T20:19:29Z","receivedAt":"2013-01-22T20:19:29Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jan 21, 2013 at 05:45:05PM -0800, Junio C Hamano wrote:\n\n> Duy Nguyen <pclouds@gmail.com> writes:\n> \n> > On Tue, Jan 22, 2013 at 6:15 AM, Jeff King <peff@peff.net> wrote:\n> >> Can you elaborate on when this code is triggered?\n> >>\n> >> In the general case, shouldn't we already know the sha1 of what's on\n> >> disk in the index, and be able to just compare the hashes? And if we\n> >> don't, because the entry is start-dirty, should we be updating it\n> >> (possibly earlier, so we do not even get into the \"need to write\" code\n> >> path) instead of doing this ad-hoc byte comparison?\n> \n> If the index knows what is in the working tree, I think I agree.\n\nRight. I was wondering why it didn't (and if it doesn't, why we are not\nsaving the information there).\n\nBut I think I was letting my inaccurate mental model of the index get in\nthe way. I tend to think of the stat information as \"if the file matches\nthis stat info, then it has sha1 X\". But that is not true. The sha1 we\nstore is the actual index entry, and if it does not match what is in the\nworking tree, we do not know or store the sha1 of what is in the working\ntree. We cannot just \"refresh\" that value and compare it, which is what\nI was implying.\n\nSo I think I was just confused. That is what I get for not actually\ndoing low-level index stuff enough.\n\n> > git reset HEAD~10\n> > # blah that was a mistake, undo it\n> > git checkout HEAD@{1}\n\nIt seems like\n\n  git reset HEAD@{1}\n\nwould be the correct undo, as the original never touched the working\ntree.\n\n-Peff\n"}]}