{"thread":{"id":"12910","subject":"Possible d/f conflict bug or regression","startedAt":"2008-03-29T07:13:08Z","lastAt":"2008-03-31T03:47:15Z","messageCount":11,"participants":["Christian Couder","Bryan Donlan","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"73300","messageId":"200803290813.08419.chriscool@tuxfamily.org","threadId":"12910","inReplyTo":null,"subject":"Possible d/f conflict bug or regression","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-03-29T07:13:08Z","receivedAt":"2008-03-29T07:13:08Z","isPatch":false,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Hi,\n\nWhen doing something like:\n\nmkdir testdir &&\n        cd testdir &&\n        touch foo &&\n        git init &&\n        git add . &&\n        git commit -m 'Initial commit.' &&\n        rm foo &&\n        mkdir foo &&\n        git commit -a -m 'Test.'\n\nI get:\n\nInitialized empty Git repository in .git/\nCreated initial commit 3f945ca: Initial commit.\n 0 files changed, 0 insertions(+), 0 deletions(-)\n create mode 100644 foo\nfatal: unable to index file foo\n\nI think it's quite bad that it doesn't work.\n\nIt seems it also doesn't work when adding \"touch foo/bar\" before \"git \ncommit -a -m 'Test.'\".\n\nI used:\n\n$ git --version\ngit version 1.5.5.rc2\n\nIt worked with 1.5.3 and I bisected it to the git commit port to C:\n\ncommit f5bbc3225c4b073a7ff3218164a0c820299bc9c6\nAuthor: Kristian H<C3><B8>gsberg <krh@redhat.com>\nDate:   Thu Nov 8 11:59:00 2007 -0500\n\n    Port git commit to C.\n\n    This makes git commit a builtin and moves git-commit.sh to\n    contrib/examples.  This also removes the git-runstatus\n    helper, which was mostly just a git-status.sh implementation detail.\n\n    Signed-off-by: Kristian H<C3><B8>gsberg <krh@redhat.com>\n    Signed-off-by: Junio C Hamano <gitster@pobox.com>\n\nThanks,\nChristian.\n"},{"id":"73303","messageId":"200803290901.19154.chriscool@tuxfamily.org","threadId":"12910","inReplyTo":"200803290813.08419.chriscool@tuxfamily.org","subject":"Re: Possible d/f conflict bug or regression","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-03-29T08:01:19Z","receivedAt":"2008-03-29T08:01:19Z","isPatch":false,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Le samedi 29 mars 2008, Christian Couder a écrit :\n>\n> mkdir testdir &&\n>         cd testdir &&\n>         touch foo &&\n>         git init &&\n>         git add . &&\n>         git commit -m 'Initial commit.' &&\n>         rm foo &&\n>         mkdir foo &&\n>         git commit -a -m 'Test.'\n\nI don't know if this helps but with \"git rm foo\" instead of \"rm foo\" it \nworks like this:\n\nInitialized empty Git repository in .git/\nCreated initial commit e784a71: Initial commit.\n 0 files changed, 0 insertions(+), 0 deletions(-)\n create mode 100644 foo\nrm 'foo'\nCreated commit 232e3ae: Test.\n 0 files changed, 0 insertions(+), 0 deletions(-)\n delete mode 100644 foo\n\nChristian.\n"},{"id":"73345","messageId":"3e8340490803291829h6f9c39a5uf4a1b2a4e52103ca@mail.gmail.com","threadId":"12910","inReplyTo":"200803290813.08419.chriscool@tuxfamily.org","subject":"Re: Possible d/f conflict bug or regression","fromName":"Bryan Donlan","fromEmail":"bdonlan@gmail.com","sentAt":"2008-03-30T01:29:23Z","receivedAt":"2008-03-30T01:29:23Z","isPatch":false,"sender":{"key":"bdonlan@gmail.com","avatar":null},"body":"On Sat, Mar 29, 2008 at 3:13 AM, Christian Couder\n<chriscool@tuxfamily.org> wrote:\n> Hi,\n>\n>  When doing something like:\n>\n>  mkdir testdir &&\n>         cd testdir &&\n>         touch foo &&\n>         git init &&\n>         git add . &&\n>         git commit -m 'Initial commit.' &&\n>         rm foo &&\n>         mkdir foo &&\n>         git commit -a -m 'Test.'\n>\n>  I get:\n>\n>  Initialized empty Git repository in .git/\n>  Created initial commit 3f945ca: Initial commit.\n>   0 files changed, 0 insertions(+), 0 deletions(-)\n>   create mode 100644 foo\n>  fatal: unable to index file foo\n>\n>  I think it's quite bad that it doesn't work.\n\nWhat behavior would you expect this to have? IMO, it's not entirely\nclear what the user means to do if they replace a file with an empty\ndirectory, as an empty directory cannot be added to the index. Even\nwith a directory with contents, some of the contents may be junk (.o\nfor example) as far as the user is concerned.\n\nWould a clearer diagnostic be a good solution? Something like:\nfatal: foo: file replaced by directory.\nUse git rm --cached or git add to specify how this should be handled.\n\nThanks,\n\nBryan\n"},{"id":"73351","messageId":"200803300644.15502.chriscool@tuxfamily.org","threadId":"12910","inReplyTo":"3e8340490803291829h6f9c39a5uf4a1b2a4e52103ca@mail.gmail.com","subject":"Re: Possible d/f conflict bug or regression","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-03-30T04:44:15Z","receivedAt":"2008-03-30T04:44:15Z","isPatch":false,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Le dimanche 30 mars 2008, Bryan Donlan a écrit :\n> On Sat, Mar 29, 2008 at 3:13 AM, Christian Couder\n> <chriscool@tuxfamily.org> wrote:\n> >\n> >  Initialized empty Git repository in .git/\n> >  Created initial commit 3f945ca: Initial commit.\n> >   0 files changed, 0 insertions(+), 0 deletions(-)\n> >   create mode 100644 foo\n> >  fatal: unable to index file foo\n> >\n> >  I think it's quite bad that it doesn't work.\n>\n> What behavior would you expect this to have? IMO, it's not entirely \n> clear what the user means to do if they replace a file with an empty\n> directory, as an empty directory cannot be added to the index. Even\n> with a directory with contents, some of the contents may be junk (.o\n> for example) as far as the user is concerned.\n\nI think Git should behave the same as when using \"git rm foo\" instead of \"rm \nfoo\", that is the file \"foo\" should be deleted without errors. That's what \nversion 1.5.3 did too.\n\n> Would a clearer diagnostic be a good solution? Something like:\n> fatal: foo: file replaced by directory.\n> Use git rm --cached or git add to specify how this should be handled.\n\nNo, I think we should fix the regression. Using \"git rm stuff\" instead \nof \"rm stuff\" should not be required.\n\nRegards,\nChristian.\n"},{"id":"73353","messageId":"3e8340490803292151o58186b18y487ac6fc6d4353b4@mail.gmail.com","threadId":"12910","inReplyTo":"200803300644.15502.chriscool@tuxfamily.org","subject":"Re: Possible d/f conflict bug or regression","fromName":"Bryan Donlan","fromEmail":"bdonlan@gmail.com","sentAt":"2008-03-30T04:51:26Z","receivedAt":"2008-03-30T04:51:26Z","isPatch":false,"sender":{"key":"bdonlan@gmail.com","avatar":null},"body":"On Sun, Mar 30, 2008 at 12:44 AM, Christian Couder\n<chriscool@tuxfamily.org> wrote:\n> Le dimanche 30 mars 2008, Bryan Donlan a écrit :\n>\n> > On Sat, Mar 29, 2008 at 3:13 AM, Christian Couder\n>  > <chriscool@tuxfamily.org> wrote:\n>  > >\n>\n> > >  Initialized empty Git repository in .git/\n>  > >  Created initial commit 3f945ca: Initial commit.\n>  > >   0 files changed, 0 insertions(+), 0 deletions(-)\n>  > >   create mode 100644 foo\n>  > >  fatal: unable to index file foo\n>  > >\n>  > >  I think it's quite bad that it doesn't work.\n>  >\n>  > What behavior would you expect this to have? IMO, it's not entirely\n>  > clear what the user means to do if they replace a file with an empty\n>  > directory, as an empty directory cannot be added to the index. Even\n>  > with a directory with contents, some of the contents may be junk (.o\n>  > for example) as far as the user is concerned.\n>\n>  I think Git should behave the same as when using \"git rm foo\" instead of \"rm\n>  foo\", that is the file \"foo\" should be deleted without errors. That's what\n>  version 1.5.3 did too.\n>\n>\n>  > Would a clearer diagnostic be a good solution? Something like:\n>  > fatal: foo: file replaced by directory.\n>  > Use git rm --cached or git add to specify how this should be handled.\n>\n>  No, I think we should fix the regression. Using \"git rm stuff\" instead\n>  of \"rm stuff\" should not be required.\n\nThis is inconsistent with git's behavior when replacing a file with a\nsymlink then - you can rm file; ln -s something file, and the symlink\nwill be checked in...\n\nAs-is, if you \"rm stuff\" but do not \"mkdir stuff\", you can commit\nwithout problems. Likewise, you can \"rm stuff\", and \"echo foo >\nstuff\", and the file will be updated. \"rm stuff\" -> \"mkdir stuff; vim\nstuff/bar.c\" could equally imply that the user wants to replace\n\"stuff\" with a directory, could it not?\n\nI don't think git should be inconsistent in this case, but equally\nit's difficult to know what the user wants to do if they put in an\nempty directory... That's why I think it'd be more sensible to let the\nuser know so they can decide which action they want to take. It\nshouldn't happen often anyway; I'd be interested in hearing about a\nuse-case that involves frequent replacement of files with directories,\nthough :)\n\nThanks,\n\nBryan\n"},{"id":"73380","messageId":"7v4panyduy.fsf@gitster.siamese.dyndns.org","threadId":"12910","inReplyTo":"200803290813.08419.chriscool@tuxfamily.org","subject":"Re: Possible d/f conflict bug or regression","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-30T23:46:29Z","receivedAt":"2008-03-30T23:46:29Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <chriscool@tuxfamily.org> writes:\n\n> mkdir testdir &&\n>         cd testdir &&\n>         touch foo &&\n>         git init &&\n>         git add . &&\n>         git commit -m 'Initial commit.' &&\n>         rm foo &&\n>         mkdir foo &&\n>         git commit -a -m 'Test.'\n>\n> I get:\n>\n> Initialized empty Git repository in .git/\n> Created initial commit 3f945ca: Initial commit.\n>  0 files changed, 0 insertions(+), 0 deletions(-)\n>  create mode 100644 foo\n> fatal: unable to index file foo\n\nI haven't had time to fully clean-up the patch series, but I have a fix\nfor this (and a bit broader set of cases).  \"git add -u\" shares the same\nissue as the \"git commit -a\" at the last step in your sequence.\n\n\"commit -a\" and \"add -u\" are about \"check the index and work tree to\nsee if anything that is in the index is changed in the work tree, and\nupdate the entry (either remove or add)\".  When we are looking at an\nexisting index entry \"foo\", possible cases include:\n\n - it has not been changed (=> do nothing);\n - it is not there anymore (=> do \"git update-index --add --remove foo\")\n - its contents or executableness changed (ditto);\n - its type changed (e.g. reg-to-symlink) (ditto);\n\nIf you did \"rm foo; mkdir foo\", then that is \"it is not there anymore\"\ncase.\n\nIf you did \"rm foo; mkdir foo; (cd foo && git init)\", and worked in this\nnew foo/ repository to cause its HEAD to point at a commit, then that is\n\"its type changed to a gitlink\" case (iow, you added a submodule).\n\nThe above two cases are not handled properly; the breakage is in\ndiff-files but non-cached diff-index shares the same issue.  The root\ncause is not Kristian's \"rewrite commit in C\", but is much more older\n\"gitlink to support submodules\" series, that started at f35a6d3 (Teach\ncore object handling functions about gitlinks, 2007-04-09).\n\nWill send the patches out tonight but I have to tend some other chores\nfirst.\n"},{"id":"73389","messageId":"7vzlsfu48a.fsf@gitster.siamese.dyndns.org","threadId":"12910","inReplyTo":"7v4panyduy.fsf@gitster.siamese.dyndns.org","subject":"[PATCH 1/3] Add corner case tests for diff-index and diff-files","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-31T00:28:05Z","receivedAt":"2008-03-31T00:28:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"diff-index and diff-files can get confused in corner cases when an indexed\nblob turns into something else in the work tree.  This patch adds tests to\nexpose such breakages.\n\nThe test is classified under t2XXX series instead of t4XXX series, because\nthe ultimate objective is to fix \"add -u\" (and \"commit -a\" that shares the\nsame issue).\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t2201-add-update-typechange.sh |  140 ++++++++++++++++++++++++++++++++++++++\n 1 files changed, 140 insertions(+), 0 deletions(-)\n create mode 100755 t/t2201-add-update-typechange.sh\n\ndiff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh\nnew file mode 100755\nindex 0000000..75c440c\n--- /dev/null\n+++ b/t/t2201-add-update-typechange.sh\n@@ -0,0 +1,140 @@\n+#!/bin/sh\n+\n+test_description='more git add -u'\n+\n+. ./test-lib.sh\n+\n+_z40=0000000000000000000000000000000000000000\n+\n+test_expect_success setup '\n+\t>xyzzy &&\n+\t_empty=$(git hash-object --stdin <xyzzy) &&\n+\t>yomin &&\n+\t>caskly &&\n+\tln -s frotz nitfol &&\n+\tmkdir rezrov &&\n+\t>rezrov/bozbar &&\n+\tgit add caskly xyzzy yomin nitfol rezrov/bozbar &&\n+\n+\ttest_tick &&\n+\tgit commit -m initial\n+\n+'\n+\n+test_expect_success modify '\n+\trm -f xyzzy yomin nitfol caskly &&\n+\t# caskly disappears (not a submodule)\n+\tmkdir caskly &&\n+\t# nitfol changes from symlink to regular\n+\t>nitfol &&\n+\t# rezrov/bozbar disappears\n+\trm -fr rezrov &&\n+\tln -s xyzzy rezrov &&\n+\t# xyzzy disappears (not a submodule)\n+\tmkdir xyzzy &&\n+\techo gnusto >xyzzy/bozbar &&\n+\t# yomin gets replaced with a submodule\n+\tmkdir yomin &&\n+\t>yomin/yomin &&\n+\t(\n+\t\tcd yomin &&\n+\t\tgit init &&\n+\t\tgit add yomin &&\n+\t\tgit commit -m \"sub initial\"\n+\t) &&\n+\tyomin=$(GIT_DIR=yomin/.git git rev-parse HEAD) &&\n+\t# yonk is added and then turned into a submodule\n+\t# this should appear as T in diff-files and as A in diff-index\n+\t>yonk &&\n+\tgit add yonk &&\n+\trm -f yonk &&\n+\tmkdir yonk &&\n+\t>yonk/yonk &&\n+\t(\n+\t\tcd yonk &&\n+\t\tgit init &&\n+\t\tgit add yonk &&\n+\t\tgit commit -m \"sub initial\"\n+\t) &&\n+\tyonk=$(GIT_DIR=yonk/.git git rev-parse HEAD) &&\n+\t# zifmia is added and then removed\n+\t# this should appear in diff-files but not in diff-index.\n+\t>zifmia &&\n+\tgit add zifmia &&\n+\trm -f zifmia &&\n+\tmkdir zifmia &&\n+\t{\n+\t\tgit ls-tree -r HEAD |\n+\t\tsed -e \"s/^/:/\" -e \"\n+\t\t\t/\tcaskly/{\n+\t\t\t\ts/\tcaskly/ $_z40 D&/\n+\t\t\t\ts/blob/000000/\n+\t\t\t}\n+\t\t\t/\tnitfol/{\n+\t\t\t\ts/\tnitfol/ $_z40 T&/\n+\t\t\t\ts/blob/100644/\n+\t\t\t}\n+\t\t\t/\trezrov.bozbar/{\n+\t\t\t\ts/\trezrov.bozbar/ $_z40 D&/\n+\t\t\t\ts/blob/000000/\n+\t\t\t}\n+\t\t\t/\txyzzy/{\n+\t\t\t\ts/\txyzzy/ $_z40 D&/\n+\t\t\t\ts/blob/000000/\n+\t\t\t}\n+\t\t\t/\tyomin/{\n+\t\t\t    s/\tyomin/ $_z40 T&/\n+\t\t\t\ts/blob/160000/\n+\t\t\t}\n+\t\t\"\n+\t} >expect &&\n+\t{\n+\t\tcat expect\n+\t\techo \":100644 160000 $_empty $_z40 T\tyonk\"\n+\t\techo \":100644 000000 $_empty $_z40 D\tzifmia\"\n+\t} >expect-files &&\n+\t{\n+\t\tcat expect\n+\t\techo \":000000 160000 $_z40 $_z40 A\tyonk\"\n+\t} >expect-index &&\n+\t{\n+\t\techo \"100644 $_empty 0\tnitfol\"\n+\t\techo \"160000 $yomin 0\tyomin\"\n+\t\techo \"160000 $yonk 0\tyonk\"\n+\t} >expect-final\n+'\n+\n+test_expect_failure diff-files '\n+\tgit diff-files --raw >actual &&\n+\tdiff -u expect-files actual\n+'\n+\n+test_expect_failure diff-index '\n+\tgit diff-index --raw HEAD -- >actual &&\n+\tdiff -u expect-index actual\n+'\n+\n+test_expect_failure 'add -u' '\n+\trm -f \".git/saved-index\" &&\n+\tcp -p \".git/index\" \".git/saved-index\" &&\n+\tgit add -u &&\n+\tgit ls-files -s >actual &&\n+\tdiff -u expect-final actual\n+'\n+\n+test_expect_failure 'commit -a' '\n+\tif test -f \".git/saved-index\"\n+\tthen\n+\t\trm -f \".git/index\" &&\n+\t\tmv \".git/saved-index\" \".git/index\"\n+\tfi &&\n+\tgit commit -m \"second\" -a &&\n+\tgit ls-files -s >actual &&\n+\tdiff -u expect-final actual &&\n+\trm -f .git/index &&\n+\tgit read-tree HEAD &&\n+\tgit ls-files -s >actual &&\n+\tdiff -u expect-final actual\n+'\n+\n+test_done\n-- \n1.5.5.rc2.131.g3d2f0\n"},{"id":"73390","messageId":"7vprtbu45f.fsf@gitster.siamese.dyndns.org","threadId":"12910","inReplyTo":"7v4panyduy.fsf@gitster.siamese.dyndns.org","subject":"[PATCH 2/3] diff-index: careful when inspecting work tree items","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-31T00:29:48Z","receivedAt":"2008-03-31T00:29:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Earlier, if you changed a staged path into a directory in the work tree,\nwe happily ran lstat(2) on it and found that it exists, and declared that\nthe user changed it to a gitlink.\n\nThis is wrong for two reasons:\n\n (1) It may be a directory, but it may not be a submodule, and in the\n     latter case, the change we need to report is \"the blob at the path\n     has disappeared\".  We need to check with resolve_gitlink_ref() to be\n     consistent with what \"git add\" and \"git update-index --add\" does.\n\n (2) lstat(2) may have succeeded only because a leading component of the\n     path was turned into a symbolic link that points at something that\n     exists in the work tree.  In such a case, the path itself does not\n     exist anymore, as far as the index is concerned.\n\nThis fixes these breakages in diff-index that the previous patch has\nexposed.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n diff-lib.c                       |   69 ++++++++++++++++++++++++++++++--------\n t/t2201-add-update-typechange.sh |    2 +-\n 2 files changed, 56 insertions(+), 15 deletions(-)\n\ndiff --git a/diff-lib.c b/diff-lib.c\nindex 52dbac3..a8e107a 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -10,6 +10,7 @@\n #include \"cache-tree.h\"\n #include \"path-list.h\"\n #include \"unpack-trees.h\"\n+#include \"refs.h\"\n \n /*\n  * diff-files\n@@ -333,6 +334,26 @@ int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)\n \t}\n \treturn run_diff_files(revs, options);\n }\n+/*\n+ * See if work tree has an entity that can be staged.  Return 0 if so,\n+ * return 1 if not and return -1 if error.\n+ */\n+static int check_work_tree_entity(const struct cache_entry *ce, struct stat *st, char *symcache)\n+{\n+\tif (lstat(ce->name, st) < 0) {\n+\t\tif (errno != ENOENT && errno != ENOTDIR)\n+\t\t\treturn -1;\n+\t\treturn 1;\n+\t}\n+\tif (has_symlink_leading_path(ce->name, symcache))\n+\t\treturn 1;\n+\tif (S_ISDIR(st->st_mode)) {\n+\t\tunsigned char sub[20];\n+\t\tif (resolve_gitlink_ref(ce->name, \"HEAD\", sub))\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n \n int run_diff_files(struct rev_info *revs, unsigned int option)\n {\n@@ -468,6 +489,11 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n  * diff-index\n  */\n \n+struct oneway_unpack_data {\n+\tstruct rev_info *revs;\n+\tchar symcache[PATH_MAX];\n+};\n+\n /* A file entry went away or appeared */\n static void diff_index_show_file(struct rev_info *revs,\n \t\t\t\t const char *prefix,\n@@ -481,7 +507,8 @@ static void diff_index_show_file(struct rev_info *revs,\n static int get_stat_data(struct cache_entry *ce,\n \t\t\t const unsigned char **sha1p,\n \t\t\t unsigned int *modep,\n-\t\t\t int cached, int match_missing)\n+\t\t\t int cached, int match_missing,\n+\t\t\t struct oneway_unpack_data *cbdata)\n {\n \tconst unsigned char *sha1 = ce->sha1;\n \tunsigned int mode = ce->ce_mode;\n@@ -489,8 +516,11 @@ static int get_stat_data(struct cache_entry *ce,\n \tif (!cached) {\n \t\tint changed;\n \t\tstruct stat st;\n-\t\tif (lstat(ce->name, &st) < 0) {\n-\t\t\tif (errno == ENOENT && match_missing) {\n+\t\tchanged = check_work_tree_entity(ce, &st, NULL);\n+\t\tif (changed < 0)\n+\t\t\treturn -1;\n+\t\telse if (changed) {\n+\t\t\tif (match_missing) {\n \t\t\t\t*sha1p = sha1;\n \t\t\t\t*modep = mode;\n \t\t\t\treturn 0;\n@@ -509,23 +539,25 @@ static int get_stat_data(struct cache_entry *ce,\n \treturn 0;\n }\n \n-static void show_new_file(struct rev_info *revs,\n+static void show_new_file(struct oneway_unpack_data *cbdata,\n \t\t\t  struct cache_entry *new,\n \t\t\t  int cached, int match_missing)\n {\n \tconst unsigned char *sha1;\n \tunsigned int mode;\n+\tstruct rev_info *revs = cbdata->revs;\n \n-\t/* New file in the index: it might actually be different in\n+\t/*\n+\t * New file in the index: it might actually be different in\n \t * the working copy.\n \t */\n-\tif (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0)\n+\tif (get_stat_data(new, &sha1, &mode, cached, match_missing, cbdata) < 0)\n \t\treturn;\n \n \tdiff_index_show_file(revs, \"+\", new, sha1, mode);\n }\n \n-static int show_modified(struct rev_info *revs,\n+static int show_modified(struct oneway_unpack_data *cbdata,\n \t\t\t struct cache_entry *old,\n \t\t\t struct cache_entry *new,\n \t\t\t int report_missing,\n@@ -533,8 +565,9 @@ static int show_modified(struct rev_info *revs,\n {\n \tunsigned int mode, oldmode;\n \tconst unsigned char *sha1;\n+\tstruct rev_info *revs = cbdata->revs;\n \n-\tif (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0) {\n+\tif (get_stat_data(new, &sha1, &mode, cached, match_missing, cbdata) < 0) {\n \t\tif (report_missing)\n \t\t\tdiff_index_show_file(revs, \"-\", old,\n \t\t\t\t\t     old->sha1, old->ce_mode);\n@@ -602,7 +635,8 @@ static void do_oneway_diff(struct unpack_trees_options *o,\n \tstruct cache_entry *idx,\n \tstruct cache_entry *tree)\n {\n-\tstruct rev_info *revs = o->unpack_data;\n+\tstruct oneway_unpack_data *cbdata = o->unpack_data;\n+\tstruct rev_info *revs = cbdata->revs;\n \tint match_missing, cached;\n \n \t/*\n@@ -625,7 +659,7 @@ static void do_oneway_diff(struct unpack_trees_options *o,\n \t * Something added to the tree?\n \t */\n \tif (!tree) {\n-\t\tshow_new_file(revs, idx, cached, match_missing);\n+\t\tshow_new_file(cbdata, idx, cached, match_missing);\n \t\treturn;\n \t}\n \n@@ -638,7 +672,7 @@ static void do_oneway_diff(struct unpack_trees_options *o,\n \t}\n \n \t/* Show difference between old and new */\n-\tshow_modified(revs, tree, idx, 1, cached, match_missing);\n+\tshow_modified(cbdata, tree, idx, 1, cached, match_missing);\n }\n \n static inline void skip_same_name(struct cache_entry *ce, struct unpack_trees_options *o)\n@@ -675,7 +709,8 @@ static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)\n {\n \tstruct cache_entry *idx = src[0];\n \tstruct cache_entry *tree = src[1];\n-\tstruct rev_info *revs = o->unpack_data;\n+\tstruct oneway_unpack_data *cbdata = o->unpack_data;\n+\tstruct rev_info *revs = cbdata->revs;\n \n \tif (idx && ce_stage(idx))\n \t\tskip_same_name(idx, o);\n@@ -702,6 +737,7 @@ int run_diff_index(struct rev_info *revs, int cached)\n \tconst char *tree_name;\n \tstruct unpack_trees_options opts;\n \tstruct tree_desc t;\n+\tstruct oneway_unpack_data unpack_cb;\n \n \tmark_merge_entries();\n \n@@ -711,12 +747,14 @@ int run_diff_index(struct rev_info *revs, int cached)\n \tif (!tree)\n \t\treturn error(\"bad tree object %s\", tree_name);\n \n+\tunpack_cb.revs = revs;\n+\tunpack_cb.symcache[0] = '\\0';\n \tmemset(&opts, 0, sizeof(opts));\n \topts.head_idx = 1;\n \topts.index_only = cached;\n \topts.merge = 1;\n \topts.fn = oneway_diff;\n-\topts.unpack_data = revs;\n+\topts.unpack_data = &unpack_cb;\n \topts.src_index = &the_index;\n \topts.dst_index = NULL;\n \n@@ -738,6 +776,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)\n \tstruct cache_entry *last = NULL;\n \tstruct unpack_trees_options opts;\n \tstruct tree_desc t;\n+\tstruct oneway_unpack_data unpack_cb;\n \n \t/*\n \t * This is used by git-blame to run diff-cache internally;\n@@ -766,12 +805,14 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)\n \tif (!tree)\n \t\tdie(\"bad tree object %s\", sha1_to_hex(tree_sha1));\n \n+\tunpack_cb.revs = &revs;\n+\tunpack_cb.symcache[0] = '\\0';\n \tmemset(&opts, 0, sizeof(opts));\n \topts.head_idx = 1;\n \topts.index_only = 1;\n \topts.merge = 1;\n \topts.fn = oneway_diff;\n-\topts.unpack_data = &revs;\n+\topts.unpack_data = &unpack_cb;\n \topts.src_index = &the_index;\n \topts.dst_index = &the_index;\n \ndiff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh\nindex 75c440c..469a8e0 100755\n--- a/t/t2201-add-update-typechange.sh\n+++ b/t/t2201-add-update-typechange.sh\n@@ -109,7 +109,7 @@ test_expect_failure diff-files '\n \tdiff -u expect-files actual\n '\n \n-test_expect_failure diff-index '\n+test_expect_success diff-index '\n \tgit diff-index --raw HEAD -- >actual &&\n \tdiff -u expect-index actual\n '\n-- \n1.5.5.rc2.131.g3d2f0\n"},{"id":"73391","messageId":"7viqz3u44v.fsf@gitster.siamese.dyndns.org","threadId":"12910","inReplyTo":"7v4panyduy.fsf@gitster.siamese.dyndns.org","subject":"[PATCH 3/3] diff-files: careful when inspecting work tree items","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-31T00:30:08Z","receivedAt":"2008-03-31T00:30:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This fixes the same breakage in diff-files.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n diff-lib.c                       |   17 +++++++++++------\n t/t2201-add-update-typechange.sh |    6 +++---\n 2 files changed, 14 insertions(+), 9 deletions(-)\n\ndiff --git a/diff-lib.c b/diff-lib.c\nindex a8e107a..d4ad6b6 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -362,10 +362,12 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \tint silent_on_removed = option & DIFF_SILENT_ON_REMOVED;\n \tunsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)\n \t\t\t      ? CE_MATCH_RACY_IS_DIRTY : 0);\n+\tchar symcache[PATH_MAX];\n \n \tif (diff_unmerged_stage < 0)\n \t\tdiff_unmerged_stage = 2;\n \tentries = active_nr;\n+\tsymcache[0] = '\\0';\n \tfor (i = 0; i < entries; i++) {\n \t\tstruct stat st;\n \t\tunsigned int oldmode, newmode;\n@@ -397,16 +399,17 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \t\t\tmemset(&(dpath->parent[0]), 0,\n \t\t\t       sizeof(struct combine_diff_parent)*5);\n \n-\t\t\tif (lstat(ce->name, &st) < 0) {\n-\t\t\t\tif (errno != ENOENT && errno != ENOTDIR) {\n+\t\t\tchanged = check_work_tree_entity(ce, &st, symcache);\n+\t\t\tif (!changed)\n+\t\t\t\tdpath->mode = ce_mode_from_stat(ce, st.st_mode);\n+\t\t\telse {\n+\t\t\t\tif (changed < 0) {\n \t\t\t\t\tperror(ce->name);\n \t\t\t\t\tcontinue;\n \t\t\t\t}\n \t\t\t\tif (silent_on_removed)\n \t\t\t\t\tcontinue;\n \t\t\t}\n-\t\t\telse\n-\t\t\t\tdpath->mode = ce_mode_from_stat(ce, st.st_mode);\n \n \t\t\twhile (i < entries) {\n \t\t\t\tstruct cache_entry *nce = active_cache[i];\n@@ -459,8 +462,10 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \n \t\tif (ce_uptodate(ce))\n \t\t\tcontinue;\n-\t\tif (lstat(ce->name, &st) < 0) {\n-\t\t\tif (errno != ENOENT && errno != ENOTDIR) {\n+\n+\t\tchanged = check_work_tree_entity(ce, &st, symcache);\n+\t\tif (changed) {\n+\t\t\tif (changed < 0) {\n \t\t\t\tperror(ce->name);\n \t\t\t\tcontinue;\n \t\t\t}\ndiff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh\nindex 469a8e0..e15e3eb 100755\n--- a/t/t2201-add-update-typechange.sh\n+++ b/t/t2201-add-update-typechange.sh\n@@ -104,7 +104,7 @@ test_expect_success modify '\n \t} >expect-final\n '\n \n-test_expect_failure diff-files '\n+test_expect_success diff-files '\n \tgit diff-files --raw >actual &&\n \tdiff -u expect-files actual\n '\n@@ -114,7 +114,7 @@ test_expect_success diff-index '\n \tdiff -u expect-index actual\n '\n \n-test_expect_failure 'add -u' '\n+test_expect_success 'add -u' '\n \trm -f \".git/saved-index\" &&\n \tcp -p \".git/index\" \".git/saved-index\" &&\n \tgit add -u &&\n@@ -122,7 +122,7 @@ test_expect_failure 'add -u' '\n \tdiff -u expect-final actual\n '\n \n-test_expect_failure 'commit -a' '\n+test_expect_success 'commit -a' '\n \tif test -f \".git/saved-index\"\n \tthen\n \t\trm -f \".git/index\" &&\n-- \n1.5.5.rc2.131.g3d2f0\n"},{"id":"73400","messageId":"7v7ifjsi2h.fsf@gitster.siamese.dyndns.org","threadId":"12910","inReplyTo":"7vprtbu45f.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 2/3] diff-index: careful when inspecting work tree items","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-03-31T03:12:06Z","receivedAt":"2008-03-31T03:12:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> diff --git a/diff-lib.c b/diff-lib.c\n> index 52dbac3..a8e107a 100644\n> --- a/diff-lib.c\n> +++ b/diff-lib.c\n> ...\n> @@ -489,8 +516,11 @@ static int get_stat_data(struct cache_entry *ce,\n>  \tif (!cached) {\n>  \t\tint changed;\n>  \t\tstruct stat st;\n> -\t\tif (lstat(ce->name, &st) < 0) {\n> -\t\t\tif (errno == ENOENT && match_missing) {\n> +\t\tchanged = check_work_tree_entity(ce, &st, NULL);\n\nThis \"NULL\" should be \"cbdata->symcache\".\n"},{"id":"73401","messageId":"200803310547.16053.chriscool@tuxfamily.org","threadId":"12910","inReplyTo":"7v7ifjsi2h.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 2/3] diff-index: careful when inspecting work tree items","fromName":"Christian Couder","fromEmail":"chriscool@tuxfamily.org","sentAt":"2008-03-31T03:47:15Z","receivedAt":"2008-03-31T03:47:15Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Le lundi 31 mars 2008, Junio C Hamano a écrit :\n> Junio C Hamano <gitster@pobox.com> writes:\n> > diff --git a/diff-lib.c b/diff-lib.c\n> > index 52dbac3..a8e107a 100644\n> > --- a/diff-lib.c\n> > +++ b/diff-lib.c\n> > ...\n> > @@ -489,8 +516,11 @@ static int get_stat_data(struct cache_entry *ce,\n> >  \tif (!cached) {\n> >  \t\tint changed;\n> >  \t\tstruct stat st;\n> > -\t\tif (lstat(ce->name, &st) < 0) {\n> > -\t\t\tif (errno == ENOENT && match_missing) {\n> > +\t\tchanged = check_work_tree_entity(ce, &st, NULL);\n>\n> This \"NULL\" should be \"cbdata->symcache\".\n\nTested-by: Christian Couder <chriscool@tuxfamily.org>\n\nYour patch series works fine for me.\n\nThanks,\nChristian.\n"}]}