{"thread":{"id":"35727","subject":"[PATCH/RFC 0/3] merge-recursive: Avoid diagnostic on empty work tree","startedAt":"2014-01-24T15:01:00Z","lastAt":"2014-01-27T17:39:46Z","messageCount":21,"participants":["Brad King","Jonathan Nieder","newren","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"233692","messageId":"cover.1390574980.git.brad.king@kitware.com","threadId":"35727","inReplyTo":"CABPp-BGAsrrjcZxVirzKU_VEyUM1U=4TFj18CieKKE7==c7v2A@mail.gmail.com","subject":"[PATCH/RFC 0/3] merge-recursive: Avoid diagnostic on empty work tree","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-24T15:01:00Z","receivedAt":"2014-01-24T15:01:00Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"On 01/23/2014 07:24 PM, Elijah Newren wrote:\n> Two options are just doing a stat to determine whether the file\n> is present (which means we'll be stat'ing the file multiple times\n> in these cases, which feels wasteful), or perhaps writing a\n> modified make_cache_entry() with the behavior we want\n> (seems like ugly code duplication).  Suggestions?\n\nPerhaps we can thread enough information through the make_cache_entry\nsignature to allow the caller to know when lstat reported ENOENT.\nHere is a series that takes such an approach.\n\n* Patch 1 is the original test case from $gmane/240853.\n\n* Patch 2 extends the make_cache_entry signature to return lstat errno.\n\n* Patch 3 uses this information to silence the add_cacheinfo diagnostic\n\n-Brad\n\nBrad King (3):\n  t3030-merge-recursive: Test known breakage with empty work tree\n  read-cache.c: Thread lstat error through make_cache_entry signature\n  merge-recursive: Tolerate missing file when HEAD is up to date\n\n builtin/apply.c            |  2 +-\n builtin/checkout.c         |  2 +-\n builtin/reset.c            |  2 +-\n cache.h                    |  2 +-\n merge-recursive.c          | 22 ++++++++++++++--------\n read-cache.c               | 12 +++++++-----\n resolve-undo.c             |  2 +-\n t/t3030-merge-recursive.sh | 47 ++++++++++++++++++++++++++++++++++++++++++++++\n 8 files changed, 73 insertions(+), 18 deletions(-)\n\n-- \n1.8.5.2\n"},{"id":"233694","messageId":"bee33fbfe83408a69085d58db302b3e72edf16a4.1390574981.git.brad.king@kitware.com","threadId":"35727","inReplyTo":"cover.1390574980.git.brad.king@kitware.com","subject":"[PATCH/RFC 1/3] t3030-merge-recursive: Test known breakage with empty work tree","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-24T15:01:01Z","receivedAt":"2014-01-24T15:01:01Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"Add test cases that use 'merge-recursive' plumbing with a temporary\nindex and empty work tree.  Populate the index using 'read-tree' and\n'update-index --ignore-missing --refresh' to prepare for merge without\nactually checking all files out to disk.  Verify that each merge\nproduces its expected tree while displaying no error diagnostics.\n\nThis approach can be used to compute tree merges while checking out only\nconflicting files to disk (which is useful for server-side scripts).\nPrior to commit 5b448b85 (merge-recursive: When we detect we can skip an\nupdate, actually skip it, 2011-08-11) this worked cleanly in all cases.\nSince that commit, merge-recursive displays a diagnostic such as\n\n error: addinfo_cache failed for path 'e'\n\nwhen \"our\" side has a rename (to 'e').  The diagnostic does not\ninfluence the return code and the merge appears to succeed, but it\ncauses this test case to fail.\n\nSigned-off-by: Brad King <brad.king@kitware.com>\n---\n t/t3030-merge-recursive.sh | 47 ++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 47 insertions(+)\n\ndiff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh\nindex 2f96100..b6d3ed0 100755\n--- a/t/t3030-merge-recursive.sh\n+++ b/t/t3030-merge-recursive.sh\n@@ -257,6 +257,7 @@ test_expect_success 'setup 8' '\n \tgit add e &&\n \ttest_tick &&\n \tgit commit -m \"rename a->e\" &&\n+\tc7=$(git rev-parse --verify HEAD) &&\n \tgit checkout rename-ln &&\n \tgit mv a e &&\n \ttest_ln_s_add e a &&\n@@ -517,6 +518,52 @@ test_expect_success 'reset and bind merge' '\n \n '\n \n+test_expect_failure 'merge-recursive w/ empty work tree - ours has rename' '\n+\t(\n+\t GIT_WORK_TREE=\"$PWD/ours-has-rename-work\" &&\n+\t export GIT_WORK_TREE &&\n+\t GIT_INDEX_FILE=\"$PWD/ours-has-rename-index\" &&\n+\t export GIT_INDEX_FILE &&\n+\t mkdir \"$GIT_WORK_TREE\" &&\n+\t git read-tree -i -m $c7 &&\n+\t git update-index --ignore-missing --refresh &&\n+\t git merge-recursive $c0 -- $c7 $c3 &&\n+\t git ls-files -s >actual-files\n+\t) 2>actual-err &&\n+\t>expected-err &&\n+\tcat >expected-files <<-EOF &&\n+\t100644 $o3 0\tb/c\n+\t100644 $o0 0\tc\n+\t100644 $o0 0\td/e\n+\t100644 $o0 0\te\n+\tEOF\n+\ttest_cmp expected-files actual-files &&\n+\ttest_cmp expected-err actual-err\n+'\n+\n+test_expect_success 'merge-recursive w/ empty work tree - theirs has rename' '\n+\t(\n+\t GIT_WORK_TREE=\"$PWD/theirs-has-rename-work\" &&\n+\t export GIT_WORK_TREE &&\n+\t GIT_INDEX_FILE=\"$PWD/theirs-has-rename-index\" &&\n+\t export GIT_INDEX_FILE &&\n+\t mkdir \"$GIT_WORK_TREE\" &&\n+\t git read-tree -i -m $c3 &&\n+\t git update-index --ignore-missing --refresh &&\n+\t git merge-recursive $c0 -- $c3 $c7 &&\n+\t git ls-files -s >actual-files\n+\t) 2>actual-err &&\n+\t>expected-err &&\n+\tcat >expected-files <<-EOF &&\n+\t100644 $o3 0\tb/c\n+\t100644 $o0 0\tc\n+\t100644 $o0 0\td/e\n+\t100644 $o0 0\te\n+\tEOF\n+\ttest_cmp expected-files actual-files &&\n+\ttest_cmp expected-err actual-err\n+'\n+\n test_expect_success 'merge removes empty directories' '\n \n \tgit reset --hard master &&\n-- \n1.8.5.2\n"},{"id":"233695","messageId":"6694dc55c558c4705c6b37d4dd7703aa04788fd7.1390574981.git.brad.king@kitware.com","threadId":"35727","inReplyTo":"cover.1390574980.git.brad.king@kitware.com","subject":"[PATCH/RFC 2/3] read-cache.c: Thread lstat error through make_cache_entry signature","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-24T15:01:02Z","receivedAt":"2014-01-24T15:01:02Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"Add an 'int *err' argument to make_cache_entry to receive any error\nthat occurred when matching stat information for a file on disk.\nThread it through to the same argument of refresh_cache_ent.\nThis will allow callers of make_cache_entry to determine whether\nfailure was due to a missing file on disk.\n\nSigned-off-by: Brad King <brad.king@kitware.com>\n---\n builtin/apply.c    |  2 +-\n builtin/checkout.c |  2 +-\n builtin/reset.c    |  2 +-\n cache.h            |  2 +-\n merge-recursive.c  |  3 ++-\n read-cache.c       | 12 +++++++-----\n resolve-undo.c     |  2 +-\n 7 files changed, 14 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex b0d0986..15e14ce 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3675,7 +3675,7 @@ static void build_fake_ancestor(struct patch *list, const char *filename)\n \t\t\tdie(\"sha1 information is lacking or useless \"\n \t\t\t    \"(%s).\", name);\n \n-\t\tce = make_cache_entry(patch->old_mode, sha1, name, 0, 0);\n+\t\tce = make_cache_entry(patch->old_mode, sha1, name, 0, 0, NULL);\n \t\tif (!ce)\n \t\t\tdie(_(\"make_cache_entry failed for path '%s'\"), name);\n \t\tif (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD))\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 5df3837..c7338bb 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -208,7 +208,7 @@ static int checkout_merged(int pos, struct checkout *state)\n \tif (write_sha1_file(result_buf.ptr, result_buf.size,\n \t\t\t    blob_type, sha1))\n \t\tdie(_(\"Unable to add merge result for '%s'\"), path);\n-\tce = make_cache_entry(mode, sha1, path, 2, 0);\n+\tce = make_cache_entry(mode, sha1, path, 2, 0, NULL);\n \tif (!ce)\n \t\tdie(_(\"make_cache_entry failed for path '%s'\"), path);\n \tstatus = checkout_entry(ce, state, NULL);\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 6004803..8e0375d 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -122,7 +122,7 @@ static void update_index_from_diff(struct diff_queue_struct *q,\n \t\tif (one->mode && !is_null_sha1(one->sha1)) {\n \t\t\tstruct cache_entry *ce;\n \t\t\tce = make_cache_entry(one->mode, one->sha1, one->path,\n-\t\t\t\t0, 0);\n+\t\t\t\t\t      0, 0, NULL);\n \t\t\tif (!ce)\n \t\t\t\tdie(_(\"make_cache_entry failed for path '%s'\"),\n \t\t\t\t    one->path);\ndiff --git a/cache.h b/cache.h\nindex c9efe88..8e4f17d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -487,7 +487,7 @@ extern int remove_file_from_index(struct index_state *, const char *path);\n #define ADD_CACHE_IMPLICIT_DOT 32\t/* internal to \"git add -u/-A\" */\n extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);\n extern int add_file_to_index(struct index_state *, const char *path, int flags);\n-extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);\n+extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh, int *err);\n extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);\n extern int index_name_is_other(const struct index_state *, const char *, int);\n extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex a18bd15..4394c44 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -201,7 +201,8 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,\n \t\tconst char *path, int stage, int refresh, int options)\n {\n \tstruct cache_entry *ce;\n-\tce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh);\n+\tce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path,\n+\t\t\t      stage, refresh, NULL);\n \tif (!ce)\n \t\treturn error(_(\"addinfo_cache failed for path '%s'\"), path);\n \treturn add_cache_entry(ce, options);\ndiff --git a/read-cache.c b/read-cache.c\nindex 33dd676..8f16cee 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -15,7 +15,8 @@\n #include \"strbuf.h\"\n #include \"varint.h\"\n \n-static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);\n+static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,\n+\t\t\t\t\t       int really, int* err);\n \n /* Mask for the name length in ce_flags in the on-disk index */\n \n@@ -696,7 +697,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int flags)\n \n struct cache_entry *make_cache_entry(unsigned int mode,\n \t\tconst unsigned char *sha1, const char *path, int stage,\n-\t\tint refresh)\n+\t\tint refresh, int* err)\n {\n \tint size, len;\n \tstruct cache_entry *ce;\n@@ -717,7 +718,7 @@ struct cache_entry *make_cache_entry(unsigned int mode,\n \tce->ce_mode = create_ce_mode(mode);\n \n \tif (refresh)\n-\t\treturn refresh_cache_entry(ce, 0);\n+\t\treturn refresh_cache_entry(ce, 0, err);\n \n \treturn ce;\n }\n@@ -1207,9 +1208,10 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n \treturn has_errors;\n }\n \n-static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)\n+static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,\n+\t\t\t\t\t       int really, int* err)\n {\n-\treturn refresh_cache_ent(&the_index, ce, really, NULL, NULL);\n+\treturn refresh_cache_ent(&the_index, ce, really, err, NULL);\n }\n \n \ndiff --git a/resolve-undo.c b/resolve-undo.c\nindex c09b006..2b7a937 100644\n--- a/resolve-undo.c\n+++ b/resolve-undo.c\n@@ -144,7 +144,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)\n \t\tif (!ru->mode[i])\n \t\t\tcontinue;\n \t\tnce = make_cache_entry(ru->mode[i], ru->sha1[i],\n-\t\t\t\t       ce->name, i + 1, 0);\n+\t\t\t\t       ce->name, i + 1, 0, NULL);\n \t\tif (matched)\n \t\t\tnce->ce_flags |= CE_MATCHED;\n \t\tif (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {\n-- \n1.8.5.2\n"},{"id":"233693","messageId":"5e5bfe752655c39fca626811972af9d0a90ddab9.1390574981.git.brad.king@kitware.com","threadId":"35727","inReplyTo":"cover.1390574980.git.brad.king@kitware.com","subject":"[PATCH/RFC 3/3] merge-recursive: Tolerate missing file when HEAD is up to date","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-24T15:01:03Z","receivedAt":"2014-01-24T15:01:03Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"Teach add_cacheinfo to optionally tolerate make_cache_entry failure when\nthe reason is ENOENT from lstat.  Tell it to do so in the call path when\nthe entry from HEAD is known to be up to date.\n\nThis fixes the 'merge-recursive w/ empty work tree - ours has rename'\ncase in t3030-merge-recursive.\n\nSigned-off-by: Brad King <brad.king@kitware.com>\n---\n merge-recursive.c          | 21 +++++++++++++--------\n t/t3030-merge-recursive.sh |  2 +-\n 2 files changed, 14 insertions(+), 9 deletions(-)\n\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 4394c44..6a2b962 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -198,13 +198,18 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)\n }\n \n static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,\n-\t\tconst char *path, int stage, int refresh, int options)\n+\t\t\t const char *path, int stage, int refresh,\n+\t\t\t int options, int noent_okay)\n {\n \tstruct cache_entry *ce;\n+\tint cache_errno = 0;\n \tce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path,\n-\t\t\t      stage, refresh, NULL);\n-\tif (!ce)\n+\t\t\t      stage, refresh, &cache_errno);\n+\tif (!ce) {\n+\t\tif(cache_errno == ENOENT && noent_okay)\n+\t\t\treturn 0;\n \t\treturn error(_(\"addinfo_cache failed for path '%s'\"), path);\n+\t}\n \treturn add_cache_entry(ce, options);\n }\n \n@@ -552,13 +557,13 @@ static int update_stages(const char *path, const struct diff_filespec *o,\n \t\tif (remove_file_from_cache(path))\n \t\t\treturn -1;\n \tif (o)\n-\t\tif (add_cacheinfo(o->mode, o->sha1, path, 1, 0, options))\n+\t\tif (add_cacheinfo(o->mode, o->sha1, path, 1, 0, options, 0))\n \t\t\treturn -1;\n \tif (a)\n-\t\tif (add_cacheinfo(a->mode, a->sha1, path, 2, 0, options))\n+\t\tif (add_cacheinfo(a->mode, a->sha1, path, 2, 0, options, 0))\n \t\t\treturn -1;\n \tif (b)\n-\t\tif (add_cacheinfo(b->mode, b->sha1, path, 3, 0, options))\n+\t\tif (add_cacheinfo(b->mode, b->sha1, path, 3, 0, options, 0))\n \t\t\treturn -1;\n \treturn 0;\n }\n@@ -789,7 +794,7 @@ static void update_file_flags(struct merge_options *o,\n \t}\n  update_index:\n \tif (update_cache)\n-\t\tadd_cacheinfo(mode, sha, path, 0, update_wd, ADD_CACHE_OK_TO_ADD);\n+\t\tadd_cacheinfo(mode, sha, path, 0, update_wd, ADD_CACHE_OK_TO_ADD, 0);\n }\n \n static void update_file(struct merge_options *o,\n@@ -1624,7 +1629,7 @@ static int merge_content(struct merge_options *o,\n \t\tpath_renamed_outside_HEAD = !path2 || !strcmp(path, path2);\n \t\tif (!path_renamed_outside_HEAD) {\n \t\t\tadd_cacheinfo(mfi.mode, mfi.sha, path,\n-\t\t\t\t      0, (!o->call_depth), 0);\n+\t\t\t\t      0, (!o->call_depth), 0, 1);\n \t\t\treturn mfi.clean;\n \t\t}\n \t} else\ndiff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh\nindex b6d3ed0..c8ba895 100755\n--- a/t/t3030-merge-recursive.sh\n+++ b/t/t3030-merge-recursive.sh\n@@ -518,7 +518,7 @@ test_expect_success 'reset and bind merge' '\n \n '\n \n-test_expect_failure 'merge-recursive w/ empty work tree - ours has rename' '\n+test_expect_success 'merge-recursive w/ empty work tree - ours has rename' '\n \t(\n \t GIT_WORK_TREE=\"$PWD/ours-has-rename-work\" &&\n \t export GIT_WORK_TREE &&\n-- \n1.8.5.2\n"},{"id":"233697","messageId":"20140124165112.GK18964@google.com","threadId":"35727","inReplyTo":"bee33fbfe83408a69085d58db302b3e72edf16a4.1390574981.git.brad.king@kitware.com","subject":"Re: [PATCH/RFC 1/3] t3030-merge-recursive: Test known breakage with empty work tree","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2014-01-24T16:51:12Z","receivedAt":"2014-01-24T16:51:12Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nBrad King wrote:\n\n> Add test cases that use 'merge-recursive' plumbing with a temporary\n> index and empty work tree.  Populate the index using 'read-tree' and\n> 'update-index --ignore-missing --refresh' to prepare for merge without\n> actually checking all files out to disk.  Verify that each merge\n> produces its expected tree while displaying no error diagnostics.\n\nFollowing my usual review practice of lazy reading for the sake of\nreaders in the future who might be in a hurry, it's not clear what\nproblem these tests are solving or trying to detect.  Could you start\nwith a quick summary of the symptoms and when it came up?\n\nThe commit message doesn't need to paraphrase the actual code, since\nanyone curious about the details can always look at the code.  It's\nmore important to explain the motivation and intended effect so people\ncan understand what went wrong if something ends up being broken by a\nlater patch.\n\n> This approach can be used to compute tree merges while checking out only\n> conflicting files to disk (which is useful for server-side scripts).\n> Prior to commit 5b448b85 (merge-recursive: When we detect we can skip an\n> update, actually skip it, 2011-08-11) this worked cleanly in all cases.\n\nDo you mean something like the following?\n\n\tSometimes when working with a large repository it can be useful to\n\ttry out a merge and only check out conflicting files to disk (for\n\texample as a speed optimization on a server).  Until v1.7.7-rc1~28^2~20\n\t(merge-recursive: When we detect we can skip an update, actually\n\tskip it, 2011-08-11), it was possible to do so with the following\n\tidiom:\n\n\t\t... summary of commands here ...\n\n\tNowadays, that still works and the exit status is the same,\n\tbut merge-recursive produces a diagnostic if \"our\" side renamed\n\ta file:\n\n\t\terror: addinfo_cache failed for path 'dst'\n\n\tAdd a test to document this regression.\n\n[...]\n> +++ b/t/t3030-merge-recursive.sh\n[...]\n> @@ -517,6 +518,52 @@ test_expect_success 'reset and bind merge' '\n>  \n>  '\n>  \n> +test_expect_failure 'merge-recursive w/ empty work tree - ours has rename' '\n> +\t(\n> +\t GIT_WORK_TREE=\"$PWD/ours-has-rename-work\" &&\n\nElsewhere in the test, commands in a subshell are indented by another\ntab, so these new tests should probably follow suit.  As a side\neffect, that makes the indentation easier to see.\n\nHope that helps,\nJonathan\n"},{"id":"233700","messageId":"52E2A7FA.10307@kitware.com","threadId":"35727","inReplyTo":"20140124165112.GK18964@google.com","subject":"Re: [PATCH/RFC 1/3] t3030-merge-recursive: Test known breakage with empty work tree","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-24T17:50:50Z","receivedAt":"2014-01-24T17:50:50Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"On 01/24/2014 11:51 AM, Jonathan Nieder wrote:\n> a quick summary of the symptoms and when it came up?\n\nYou're suggested commit message correctly explains it:\n\n> Do you mean something like the following?\n> \n> \tSometimes when working with a large repository it can be useful to\n> \ttry out a merge and only check out conflicting files to disk (for\n> \texample as a speed optimization on a server).  Until v1.7.7-rc1~28^2~20\n> \t(merge-recursive: When we detect we can skip an update, actually\n> \tskip it, 2011-08-11), it was possible to do so with the following\n> \tidiom:\n> \n> \t\t... summary of commands here ...\n> \n> \tNowadays, that still works and the exit status is the same,\n> \tbut merge-recursive produces a diagnostic if \"our\" side renamed\n> \ta file:\n> \n> \t\terror: addinfo_cache failed for path 'dst'\n> \n> \tAdd a test to document this regression.\n\nYes, thanks.\n\n> Elsewhere in the test, commands in a subshell are indented by another\n> tab, so these new tests should probably follow suit.\n\nGreat.  I'll fold both of the above into the next revision of the series.\n\nThanks,\n-Brad\n"},{"id":"233705","messageId":"CABPp-BE-p=FfJRtTXjoRhfSt2JwxniNdda-5=CvGN3cBXU15MA@mail.gmail.com","threadId":"35727","inReplyTo":"CABPp-BEK9+_ebRiodCp59DHJZExYn3N1jjtBsikSmwt-s_v_0A@mail.gmail.com","subject":"Fwd: [PATCH/RFC 3/3] merge-recursive: Tolerate missing file when HEAD is up to date","fromName":"newren","fromEmail":"newren@gmail.com","sentAt":"2014-01-24T19:37:12Z","receivedAt":"2014-01-24T19:37:12Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"[The copy of my message to the list bounced; trying to resend...]\n\nHi,\n\nThanks for flagging this problem, providing a clear testcase, and working on it.\n\nOn Fri, Jan 24, 2014 at 7:01 AM, Brad King <brad.king@kitware.com> wrote:\n>\n> Teach add_cacheinfo to optionally tolerate make_cache_entry failure when\n> the reason is ENOENT from lstat.  Tell it to do so in the call path when\n> the entry from HEAD is known to be up to date.\n>\n> This fixes the 'merge-recursive w/ empty work tree - ours has rename'\n> case in t3030-merge-recursive.\n\nWhile this change does work for the particular new testcase you\nprovided, there's a more complex case where merge-recursive is failing\nthat is not yet found in the testsuite and not fully reflected with\nyour new test.  In particular, if you combine your special case of an\nempty work tree with other special cases such as renames across a D/F\nconflict, then git merge will fail and your change would merely\nsuppress part of the error messages.\n\nTo make this concrete, try modifying the 'merging with triple rename\nacross D/F conflict'  testcase in t6031-merge-recursive.sh (an example\nthat should merge cleanly) to remove all files from the working tree\nright before the merge (which shoudln't affect whether the merge is\nclean).  Currently, git merge will fail with:\n\nerror: addinfo_cache failed for path 'sub1/file3'\nerror: addinfo_cache failed for path 'sub1/file2'\nerror: addinfo_cache failed for path 'sub1/file1'\nsub1/file1: unmerged (ac3e272b72bbf89def8657766b855d0656630ed4)\nsub1/file2: unmerged (637f0347d31dad180d6fc7f6720c187b05a8754c)\nsub1/file3: unmerged (27d10cc8d0f10540c1fce1aa6de5e8f3e6b655ba)\nfatal: git write-tree failed to write a tree\n\nYour patch would remove the first 3 error messages, but leave the\ndeeper problem.\n\n> diff --git a/merge-recursive.c b/merge-recursive.c\n> index 4394c44..6a2b962 100644\n> --- a/merge-recursive.c\n> +++ b/merge-recursive.c\n> @@ -198,13 +198,18 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)\n>  }\n>\n>  static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,\n> -               const char *path, int stage, int refresh, int options)\n> +                        const char *path, int stage, int refresh,\n> +                        int options, int noent_okay)\n>  {\n>         struct cache_entry *ce;\n> +       int cache_errno = 0;\n>         ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path,\n> -                             stage, refresh, NULL);\n> -       if (!ce)\n> +                             stage, refresh, &cache_errno);\n> +       if (!ce) {\n> +               if(cache_errno == ENOENT && noent_okay)\n> +                       return 0;\n>                 return error(_(\"addinfo_cache failed for path '%s'\"), path);\n> +       }\n>         return add_cache_entry(ce, options);\n>  }\n\n\nThis is the crux of the change and the one you referred to in the\ncommit message.  However, we don't really want add_cacheinfo to\ntolerate failure to create a cache entry; we need one.  We just want\nadd_cacheinfo to be tolerant of failure to refresh the stat-timestamp\nfor the new cache entry if there is no associated file on disk.  Said\nanother way, we need a new cache entry back from make_cache_entry() in\nall cases, it's just that we want the stat information refreshed if\nand only if the file happens to exist in the working tree.  (We could\njust stat the file in the working tree, but that seems a waste since\nmake_cache_entry() will stat it again when it exists.  In fact, the\nstat in make_cache_entry() is also a bit of a waste because this is\nthe case when we know that before the merge started the file already\nhad the right contents and thus we ought to be able to get the right\ntimestamp for that particular file from the cache entry of the index\nfrom before the merge even began.  But I don't know how to access\nthat.)\n\nElijah\n"},{"id":"233707","messageId":"52E2C2F6.2030909@kitware.com","threadId":"35727","inReplyTo":"CABPp-BEK9+_ebRiodCp59DHJZExYn3N1jjtBsikSmwt-s_v_0A@mail.gmail.com","subject":"Re: [PATCH/RFC 3/3] merge-recursive: Tolerate missing file when HEAD is up to date","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-24T19:45:58Z","receivedAt":"2014-01-24T19:45:58Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"On 01/24/2014 01:42 PM, Elijah Newren wrote:\n> While this change does work for the particular new testcase you provided,\n> there's a more complex case where merge-recursive is failing\n\nI'm not surprised.  The change felt much like covering a symptom.\n\n> it's just that we want the stat information refreshed if and only\n> if the file happens to exist in the working tree.\n\nWe can add a refresh_flags argument to make_cache_entry to request\nthis behavior.  I'll send an updated series soon.\n\nThanks,\n-Brad\n"},{"id":"233706","messageId":"xmqq8uu5rwfk.fsf@gitster.dls.corp.google.com","threadId":"35727","inReplyTo":"5e5bfe752655c39fca626811972af9d0a90ddab9.1390574981.git.brad.king@kitware.com","subject":"Re: [PATCH/RFC 3/3] merge-recursive: Tolerate missing file when HEAD is up to date","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-01-24T19:50:39Z","receivedAt":"2014-01-24T19:50:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Brad King <brad.king@kitware.com> writes:\n\n> Teach add_cacheinfo to optionally tolerate make_cache_entry failure when\n> the reason is ENOENT from lstat.  Tell it to do so in the call path when\n> the entry from HEAD is known to be up to date.\n\nIt somehow feels wrong to force callers of make_cache_entry() to be\nso intimate with the implementation details of refresh_cache_ent()\nby having them inspect the errno from lstat(2) so deep in the\ncallchain, and to force callers of make_cache_entry() that says\nrefresh=NoThanks to pass a useless NULL.\n\nLooking at refresh_cache_ent(), I notice that we already have cases\nwhere we do not bother to lstat and instead say \"Yeah, the cache\nentry you have is good\", and have to wonder if this new feature\nshould be modeled after them instead, namely, by introducing a new\noption bit CE_MATCH_MISSING_OK that asks it to treat a path that is\nmissing from the working tree as if it is checked out unmodified.\n"},{"id":"233709","messageId":"CA+gQCGGRw7cTKH3zgPrsCWzMOs+FQZwt2xHU8FV-0s5x3QNZUw@mail.gmail.com","threadId":"35727","inReplyTo":"xmqq8uu5rwfk.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH/RFC 3/3] merge-recursive: Tolerate missing file when HEAD is up to date","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-24T20:02:34Z","receivedAt":"2014-01-24T20:02:34Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"On Fri, Jan 24, 2014 at 2:50 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> It somehow feels wrong to force callers of make_cache_entry() to be\n> so intimate with the implementation details of refresh_cache_ent()\n[snip]\n> option bit CE_MATCH_MISSING_OK that asks it to treat a path that is\n> missing from the working tree as if it is checked out unmodified.\n\nI came to the same conclusion after reading Elijah's last response.\nMy next series revision adds an argument to make_cache_entry to\nspecify the refresh flags and honors REFRESH_IGNORE_MISSING.\n\nThanks,\n-Brad\n"},{"id":"233712","messageId":"cover.1390592626.git.brad.king@kitware.com","threadId":"35727","inReplyTo":"cover.1390574980.git.brad.king@kitware.com","subject":"[PATCH v2 0/3] merge-recursive: Avoid diagnostic on empty work tree","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-24T20:10:46Z","receivedAt":"2014-01-24T20:10:46Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"Hi Folks,\n\nHere is the second revision of this series.  The previous\nrevision can be found at $gmane/241009.\n\nUpdates since the previous revision of the series:\n\n* Patch 1 test indentation and commit message updated thanks to\n  comments from Jonathan.\n\n* Patch 2 now adds a different new argument to make_cache_entry.\n  This one is to request certain refresh behavior instead of just\n  to get an error value back.\n\n* Patch 3 uses the new make_cache_entry feature in patch 2\n  to fix the test case.  This approach is based on suggestions\n  from Elijah and Junio.\n\nThanks,\n-Brad\n\nBrad King (3):\n  t3030-merge-recursive: Test known breakage with empty work tree\n  read-cache.c: Optionally tolerate missing files in make_cache_entry\n  merge-recursive.c: Tolerate missing files while refreshing index\n\n builtin/apply.c            |  2 +-\n builtin/checkout.c         |  2 +-\n builtin/reset.c            |  2 +-\n cache.h                    |  2 +-\n merge-recursive.c          |  3 ++-\n read-cache.c               | 21 ++++++++++++++++-----\n resolve-undo.c             |  2 +-\n t/t3030-merge-recursive.sh | 47 ++++++++++++++++++++++++++++++++++++++++++++++\n 8 files changed, 70 insertions(+), 11 deletions(-)\n\n-- \n1.8.5.2\n"},{"id":"233713","messageId":"bc20dc0a791ac6441fa564ed5df469e43376ab87.1390592626.git.brad.king@kitware.com","threadId":"35727","inReplyTo":"cover.1390592626.git.brad.king@kitware.com","subject":"[PATCH v2 1/3] t3030-merge-recursive: Test known breakage with empty work tree","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-24T20:10:47Z","receivedAt":"2014-01-24T20:10:47Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"Sometimes when working with a large repository it can be useful to try\nout a merge and only check out conflicting files to disk (for example as\na speed optimization on a server).  Until v1.7.7-rc1~28^2~20\n(merge-recursive: When we detect we can skip an update, actually skip\nit, 2011-08-11), it was possible to do so with the following idiom:\n\n\t# Prepare a temporary index and empty work tree.\n\tGIT_INDEX_FILE=\"$PWD/tmp-$$-index\" &&\n\texport GIT_INDEX_FILE &&\n\tGIT_WORK_TREE=\"$PWD/tmp-$$-work\" &&\n\texport GIT_WORK_TREE &&\n\tmkdir \"$GIT_WORK_TREE\" &&\n\n\t# Convince the index that our side is on disk.\n\tgit read-tree -i -m $ours &&\n\tgit update-index --ignore-missing --refresh &&\n\n\t# Merge their side into our side.\n\tbases=$(git merge-base --all $ours $theirs) &&\n\tgit merge-recursive $bases -- $ours $theirs &&\n\ttree=$(git write-tree)\n\nNowadays, that still works and the exit status is the same, but\nmerge-recursive produces a diagnostic if \"our\" side renamed a file:\n\n\terror: addinfo_cache failed for path 'dst'\n\nAdd a test to document this regression.\n\nSigned-off-by: Brad King <brad.king@kitware.com>\n---\n t/t3030-merge-recursive.sh | 47 ++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 47 insertions(+)\n\ndiff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh\nindex 2f96100..3db3bf6 100755\n--- a/t/t3030-merge-recursive.sh\n+++ b/t/t3030-merge-recursive.sh\n@@ -257,6 +257,7 @@ test_expect_success 'setup 8' '\n \tgit add e &&\n \ttest_tick &&\n \tgit commit -m \"rename a->e\" &&\n+\tc7=$(git rev-parse --verify HEAD) &&\n \tgit checkout rename-ln &&\n \tgit mv a e &&\n \ttest_ln_s_add e a &&\n@@ -517,6 +518,52 @@ test_expect_success 'reset and bind merge' '\n \n '\n \n+test_expect_failure 'merge-recursive w/ empty work tree - ours has rename' '\n+\t(\n+\t\tGIT_WORK_TREE=\"$PWD/ours-has-rename-work\" &&\n+\t\texport GIT_WORK_TREE &&\n+\t\tGIT_INDEX_FILE=\"$PWD/ours-has-rename-index\" &&\n+\t\texport GIT_INDEX_FILE &&\n+\t\tmkdir \"$GIT_WORK_TREE\" &&\n+\t\tgit read-tree -i -m $c7 &&\n+\t\tgit update-index --ignore-missing --refresh &&\n+\t\tgit merge-recursive $c0 -- $c7 $c3 &&\n+\t\tgit ls-files -s >actual-files\n+\t) 2>actual-err &&\n+\t>expected-err &&\n+\tcat >expected-files <<-EOF &&\n+\t100644 $o3 0\tb/c\n+\t100644 $o0 0\tc\n+\t100644 $o0 0\td/e\n+\t100644 $o0 0\te\n+\tEOF\n+\ttest_cmp expected-files actual-files &&\n+\ttest_cmp expected-err actual-err\n+'\n+\n+test_expect_success 'merge-recursive w/ empty work tree - theirs has rename' '\n+\t(\n+\t\tGIT_WORK_TREE=\"$PWD/theirs-has-rename-work\" &&\n+\t\texport GIT_WORK_TREE &&\n+\t\tGIT_INDEX_FILE=\"$PWD/theirs-has-rename-index\" &&\n+\t\texport GIT_INDEX_FILE &&\n+\t\tmkdir \"$GIT_WORK_TREE\" &&\n+\t\tgit read-tree -i -m $c3 &&\n+\t\tgit update-index --ignore-missing --refresh &&\n+\t\tgit merge-recursive $c0 -- $c3 $c7 &&\n+\t\tgit ls-files -s >actual-files\n+\t) 2>actual-err &&\n+\t>expected-err &&\n+\tcat >expected-files <<-EOF &&\n+\t100644 $o3 0\tb/c\n+\t100644 $o0 0\tc\n+\t100644 $o0 0\td/e\n+\t100644 $o0 0\te\n+\tEOF\n+\ttest_cmp expected-files actual-files &&\n+\ttest_cmp expected-err actual-err\n+'\n+\n test_expect_success 'merge removes empty directories' '\n \n \tgit reset --hard master &&\n-- \n1.8.5.2\n"},{"id":"233714","messageId":"197b46e792c8640d19580f282834052a660d2c05.1390592626.git.brad.king@kitware.com","threadId":"35727","inReplyTo":"cover.1390592626.git.brad.king@kitware.com","subject":"[PATCH v2 2/3] read-cache.c: Optionally tolerate missing files in make_cache_entry","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-24T20:10:48Z","receivedAt":"2014-01-24T20:10:48Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"Add an 'int refresh_flags' argument to make_cache_entry to tell the\nrefresh step about caller preferences.  Teach it to honor the\nREFRESH_IGNORE_MISSING flag to skip refreshing stat information when a\nfile is missing from the work tree on disk.\n\nSigned-off-by: Brad King <brad.king@kitware.com>\n---\n builtin/apply.c    |  2 +-\n builtin/checkout.c |  2 +-\n builtin/reset.c    |  2 +-\n cache.h            |  2 +-\n merge-recursive.c  |  2 +-\n read-cache.c       | 21 ++++++++++++++++-----\n resolve-undo.c     |  2 +-\n 7 files changed, 22 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex b0d0986..64c04ec 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3675,7 +3675,7 @@ static void build_fake_ancestor(struct patch *list, const char *filename)\n \t\t\tdie(\"sha1 information is lacking or useless \"\n \t\t\t    \"(%s).\", name);\n \n-\t\tce = make_cache_entry(patch->old_mode, sha1, name, 0, 0);\n+\t\tce = make_cache_entry(patch->old_mode, sha1, name, 0, 0, 0);\n \t\tif (!ce)\n \t\t\tdie(_(\"make_cache_entry failed for path '%s'\"), name);\n \t\tif (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD))\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 5df3837..d3d8640 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -208,7 +208,7 @@ static int checkout_merged(int pos, struct checkout *state)\n \tif (write_sha1_file(result_buf.ptr, result_buf.size,\n \t\t\t    blob_type, sha1))\n \t\tdie(_(\"Unable to add merge result for '%s'\"), path);\n-\tce = make_cache_entry(mode, sha1, path, 2, 0);\n+\tce = make_cache_entry(mode, sha1, path, 2, 0, 0);\n \tif (!ce)\n \t\tdie(_(\"make_cache_entry failed for path '%s'\"), path);\n \tstatus = checkout_entry(ce, state, NULL);\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 6004803..ac45056 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -122,7 +122,7 @@ static void update_index_from_diff(struct diff_queue_struct *q,\n \t\tif (one->mode && !is_null_sha1(one->sha1)) {\n \t\t\tstruct cache_entry *ce;\n \t\t\tce = make_cache_entry(one->mode, one->sha1, one->path,\n-\t\t\t\t0, 0);\n+\t\t\t\t\t      0, 0, 0);\n \t\t\tif (!ce)\n \t\t\t\tdie(_(\"make_cache_entry failed for path '%s'\"),\n \t\t\t\t    one->path);\ndiff --git a/cache.h b/cache.h\nindex c9efe88..653ede4 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -487,7 +487,7 @@ extern int remove_file_from_index(struct index_state *, const char *path);\n #define ADD_CACHE_IMPLICIT_DOT 32\t/* internal to \"git add -u/-A\" */\n extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);\n extern int add_file_to_index(struct index_state *, const char *path, int flags);\n-extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);\n+extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh, int refresh_flags);\n extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);\n extern int index_name_is_other(const struct index_state *, const char *, int);\n extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex a18bd15..a6fe7f9 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -201,7 +201,7 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,\n \t\tconst char *path, int stage, int refresh, int options)\n {\n \tstruct cache_entry *ce;\n-\tce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh);\n+\tce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh, 0);\n \tif (!ce)\n \t\treturn error(_(\"addinfo_cache failed for path '%s'\"), path);\n \treturn add_cache_entry(ce, options);\ndiff --git a/read-cache.c b/read-cache.c\nindex 33dd676..9ce7a9f 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -15,7 +15,8 @@\n #include \"strbuf.h\"\n #include \"varint.h\"\n \n-static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);\n+static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really,\n+\t\t\t\t\t       int flags);\n \n /* Mask for the name length in ce_flags in the on-disk index */\n \n@@ -696,7 +697,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int flags)\n \n struct cache_entry *make_cache_entry(unsigned int mode,\n \t\tconst unsigned char *sha1, const char *path, int stage,\n-\t\tint refresh)\n+\t\tint refresh, int refresh_flags)\n {\n \tint size, len;\n \tstruct cache_entry *ce;\n@@ -717,7 +718,7 @@ struct cache_entry *make_cache_entry(unsigned int mode,\n \tce->ce_mode = create_ce_mode(mode);\n \n \tif (refresh)\n-\t\treturn refresh_cache_entry(ce, 0);\n+\t\treturn refresh_cache_entry(ce, 0, refresh_flags);\n \n \treturn ce;\n }\n@@ -1207,9 +1208,19 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n \treturn has_errors;\n }\n \n-static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)\n+static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really,\n+\t\t\t\t\t       int flags)\n {\n-\treturn refresh_cache_ent(&the_index, ce, really, NULL, NULL);\n+\tint not_new = (flags & REFRESH_IGNORE_MISSING) != 0;\n+\tint cache_errno = 0;\n+\tstruct cache_entry *new;\n+\n+\tnew = refresh_cache_ent(&the_index, ce, really, &cache_errno, NULL);\n+\n+\tif(!new && not_new && cache_errno == ENOENT)\n+\t\treturn ce;\n+\n+\treturn new;\n }\n \n \ndiff --git a/resolve-undo.c b/resolve-undo.c\nindex c09b006..d4faff0 100644\n--- a/resolve-undo.c\n+++ b/resolve-undo.c\n@@ -144,7 +144,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)\n \t\tif (!ru->mode[i])\n \t\t\tcontinue;\n \t\tnce = make_cache_entry(ru->mode[i], ru->sha1[i],\n-\t\t\t\t       ce->name, i + 1, 0);\n+\t\t\t\t       ce->name, i + 1, 0, 0);\n \t\tif (matched)\n \t\t\tnce->ce_flags |= CE_MATCHED;\n \t\tif (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {\n-- \n1.8.5.2\n"},{"id":"233711","messageId":"92b0b0310b762276db23161d34ba94a86fd67139.1390592626.git.brad.king@kitware.com","threadId":"35727","inReplyTo":"cover.1390592626.git.brad.king@kitware.com","subject":"[PATCH v2 3/3] merge-recursive.c: Tolerate missing files while refreshing index","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-24T20:10:49Z","receivedAt":"2014-01-24T20:10:49Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"Teach add_cacheinfo to tell make_cache_entry to skip refreshing stat\ninformation when a file is missing from the work tree.  We do not want\nthe index to be stat-dirty after the merge but also do not want to fail\nwhen a file happens to be missing.\n\nThis fixes the 'merge-recursive w/ empty work tree - ours has rename'\ncase in t3030-merge-recursive.\n\nSuggested-by: Elijah Newren <newren@gmail.com>\nSigned-off-by: Brad King <brad.king@kitware.com>\n---\n merge-recursive.c          | 3 ++-\n t/t3030-merge-recursive.sh | 2 +-\n 2 files changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex a6fe7f9..35935c5 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -201,7 +201,8 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,\n \t\tconst char *path, int stage, int refresh, int options)\n {\n \tstruct cache_entry *ce;\n-\tce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh, 0);\n+\tce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage,\n+\t\t\t      refresh, REFRESH_IGNORE_MISSING);\n \tif (!ce)\n \t\treturn error(_(\"addinfo_cache failed for path '%s'\"), path);\n \treturn add_cache_entry(ce, options);\ndiff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh\nindex 3db3bf6..82e1854 100755\n--- a/t/t3030-merge-recursive.sh\n+++ b/t/t3030-merge-recursive.sh\n@@ -518,7 +518,7 @@ test_expect_success 'reset and bind merge' '\n \n '\n \n-test_expect_failure 'merge-recursive w/ empty work tree - ours has rename' '\n+test_expect_success 'merge-recursive w/ empty work tree - ours has rename' '\n \t(\n \t\tGIT_WORK_TREE=\"$PWD/ours-has-rename-work\" &&\n \t\texport GIT_WORK_TREE &&\n-- \n1.8.5.2\n"},{"id":"233717","messageId":"xmqqr47xqflf.fsf@gitster.dls.corp.google.com","threadId":"35727","inReplyTo":"197b46e792c8640d19580f282834052a660d2c05.1390592626.git.brad.king@kitware.com","subject":"Re: [PATCH v2 2/3] read-cache.c: Optionally tolerate missing files in make_cache_entry","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-01-24T20:39:40Z","receivedAt":"2014-01-24T20:39:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Brad King <brad.king@kitware.com> writes:\n\n> +extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh, int refresh_flags);\n\nWhy a new parameter?  If refresh_flags can be ANY when refresh=NoThanks,\nshouldn't they be a single variable that tells the callee how the entry\nshould be refreshed (e.g. \"not at all\", \"normally\", \"missing is ok\", etc.)?\n\n> +static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really,\n> +\t\t\t\t\t       int flags)\n>  {\n> -\treturn refresh_cache_ent(&the_index, ce, really, NULL, NULL);\n> +\tint not_new = (flags & REFRESH_IGNORE_MISSING) != 0;\n> +\tint cache_errno = 0;\n> +\tstruct cache_entry *new;\n> +\n> +\tnew = refresh_cache_ent(&the_index, ce, really, &cache_errno, NULL);\n> +\n> +\tif(!new && not_new && cache_errno == ENOENT)\n> +\t\treturn ce;\n\nI think this is still one level too high in the abstraction chain.\n\"int really\" might be of type signed int by historical accidents,\nbut it is \"unsigned int options\" for the underlying\nrefresh_cache_ent().  I'd suggest renaming this to \"unsigned int\nrefresh_options\" or something, and then define a new constatnt\nsimilar to the existing CE_MATCH_IGNORE_*.\n"},{"id":"233821","messageId":"cover.1390833624.git.brad.king@kitware.com","threadId":"35727","inReplyTo":"cover.1390592626.git.brad.king@kitware.com","subject":"[PATCH v3 0/3] merge-recursive: Avoid diagnostic on empty work tree","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-27T14:45:05Z","receivedAt":"2014-01-27T14:45:05Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"Hi Folks,\n\nHere is the third revision of this series.  The previous\nrevisions can be found at $gmane/241009 and $gmane/241030.\n\nUpdates since the previous revision of the series:\n\n* Handling of lstat ENOENT has been moved down into refresh_cache_ent\n  and activated by a new CE_MATCH_IGNORE_MISSING option.\n\n* Rather than adding a new argument to make_cache_entry, the existing\n  'refresh' boolean argument has been generalized to a set of options.\n  This required the addition of a new CE_MATCH_REFRESH option to\n  enable refresh with no other options.\n\nThanks,\n-Brad\n\nBrad King (4):\n  t3030-merge-recursive: Test known breakage with empty work tree\n  read-cache.c: Refactor --ignore-missing implementation\n  read-cache.c: Extend make_cache_entry refresh flag with options\n  merge-recursive.c: Tolerate missing files while refreshing index\n\n cache.h                    |  6 +++++-\n merge-recursive.c          |  4 +++-\n read-cache.c               | 27 ++++++++++++++------------\n t/t3030-merge-recursive.sh | 47 ++++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 70 insertions(+), 14 deletions(-)\n\n-- \n1.8.5.2\n"},{"id":"233820","messageId":"bc20dc0a791ac6441fa564ed5df469e43376ab87.1390833624.git.brad.king@kitware.com","threadId":"35727","inReplyTo":"cover.1390833624.git.brad.king@kitware.com","subject":"[PATCH v3 1/4] t3030-merge-recursive: Test known breakage with empty work tree","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-27T14:45:06Z","receivedAt":"2014-01-27T14:45:06Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"Sometimes when working with a large repository it can be useful to try\nout a merge and only check out conflicting files to disk (for example as\na speed optimization on a server).  Until v1.7.7-rc1~28^2~20\n(merge-recursive: When we detect we can skip an update, actually skip\nit, 2011-08-11), it was possible to do so with the following idiom:\n\n\t# Prepare a temporary index and empty work tree.\n\tGIT_INDEX_FILE=\"$PWD/tmp-$$-index\" &&\n\texport GIT_INDEX_FILE &&\n\tGIT_WORK_TREE=\"$PWD/tmp-$$-work\" &&\n\texport GIT_WORK_TREE &&\n\tmkdir \"$GIT_WORK_TREE\" &&\n\n\t# Convince the index that our side is on disk.\n\tgit read-tree -i -m $ours &&\n\tgit update-index --ignore-missing --refresh &&\n\n\t# Merge their side into our side.\n\tbases=$(git merge-base --all $ours $theirs) &&\n\tgit merge-recursive $bases -- $ours $theirs &&\n\ttree=$(git write-tree)\n\nNowadays, that still works and the exit status is the same, but\nmerge-recursive produces a diagnostic if \"our\" side renamed a file:\n\n\terror: addinfo_cache failed for path 'dst'\n\nAdd a test to document this regression.\n\nSigned-off-by: Brad King <brad.king@kitware.com>\n---\n t/t3030-merge-recursive.sh | 47 ++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 47 insertions(+)\n\ndiff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh\nindex 2f96100..3db3bf6 100755\n--- a/t/t3030-merge-recursive.sh\n+++ b/t/t3030-merge-recursive.sh\n@@ -257,6 +257,7 @@ test_expect_success 'setup 8' '\n \tgit add e &&\n \ttest_tick &&\n \tgit commit -m \"rename a->e\" &&\n+\tc7=$(git rev-parse --verify HEAD) &&\n \tgit checkout rename-ln &&\n \tgit mv a e &&\n \ttest_ln_s_add e a &&\n@@ -517,6 +518,52 @@ test_expect_success 'reset and bind merge' '\n \n '\n \n+test_expect_failure 'merge-recursive w/ empty work tree - ours has rename' '\n+\t(\n+\t\tGIT_WORK_TREE=\"$PWD/ours-has-rename-work\" &&\n+\t\texport GIT_WORK_TREE &&\n+\t\tGIT_INDEX_FILE=\"$PWD/ours-has-rename-index\" &&\n+\t\texport GIT_INDEX_FILE &&\n+\t\tmkdir \"$GIT_WORK_TREE\" &&\n+\t\tgit read-tree -i -m $c7 &&\n+\t\tgit update-index --ignore-missing --refresh &&\n+\t\tgit merge-recursive $c0 -- $c7 $c3 &&\n+\t\tgit ls-files -s >actual-files\n+\t) 2>actual-err &&\n+\t>expected-err &&\n+\tcat >expected-files <<-EOF &&\n+\t100644 $o3 0\tb/c\n+\t100644 $o0 0\tc\n+\t100644 $o0 0\td/e\n+\t100644 $o0 0\te\n+\tEOF\n+\ttest_cmp expected-files actual-files &&\n+\ttest_cmp expected-err actual-err\n+'\n+\n+test_expect_success 'merge-recursive w/ empty work tree - theirs has rename' '\n+\t(\n+\t\tGIT_WORK_TREE=\"$PWD/theirs-has-rename-work\" &&\n+\t\texport GIT_WORK_TREE &&\n+\t\tGIT_INDEX_FILE=\"$PWD/theirs-has-rename-index\" &&\n+\t\texport GIT_INDEX_FILE &&\n+\t\tmkdir \"$GIT_WORK_TREE\" &&\n+\t\tgit read-tree -i -m $c3 &&\n+\t\tgit update-index --ignore-missing --refresh &&\n+\t\tgit merge-recursive $c0 -- $c3 $c7 &&\n+\t\tgit ls-files -s >actual-files\n+\t) 2>actual-err &&\n+\t>expected-err &&\n+\tcat >expected-files <<-EOF &&\n+\t100644 $o3 0\tb/c\n+\t100644 $o0 0\tc\n+\t100644 $o0 0\td/e\n+\t100644 $o0 0\te\n+\tEOF\n+\ttest_cmp expected-files actual-files &&\n+\ttest_cmp expected-err actual-err\n+'\n+\n test_expect_success 'merge removes empty directories' '\n \n \tgit reset --hard master &&\n-- \n1.8.5.2\n"},{"id":"233823","messageId":"e8a33f2e20e9f2041bf5f0fa952536755dbdf34c.1390833624.git.brad.king@kitware.com","threadId":"35727","inReplyTo":"cover.1390833624.git.brad.king@kitware.com","subject":"[PATCH v3 2/4] read-cache.c: Refactor --ignore-missing implementation","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-27T14:45:07Z","receivedAt":"2014-01-27T14:45:07Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"Move lstat ENOENT handling from refresh_index to refresh_cache_ent and\nactivate it with a new CE_MATCH_IGNORE_MISSING option.  This will allow\nother call paths into refresh_cache_ent to use the feature.\n\nSigned-off-by: Brad King <brad.king@kitware.com>\n---\n cache.h      | 2 ++\n read-cache.c | 8 +++++---\n 2 files changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex c9efe88..c96ada7 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -498,6 +498,8 @@ extern void *read_blob_data_from_index(struct index_state *, const char *, unsig\n #define CE_MATCH_RACY_IS_DIRTY\t\t02\n /* do stat comparison even if CE_SKIP_WORKTREE is true */\n #define CE_MATCH_IGNORE_SKIP_WORKTREE\t04\n+/* ignore non-existent files during stat update  */\n+#define CE_MATCH_IGNORE_MISSING\t\t0x08\n extern int ie_match_stat(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);\n extern int ie_modified(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);\n \ndiff --git a/read-cache.c b/read-cache.c\nindex 33dd676..d61846c 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -1031,6 +1031,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,\n \tint changed, size;\n \tint ignore_valid = options & CE_MATCH_IGNORE_VALID;\n \tint ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;\n+\tint ignore_missing = options & CE_MATCH_IGNORE_MISSING;\n \n \tif (ce_uptodate(ce))\n \t\treturn ce;\n@@ -1050,6 +1051,8 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,\n \t}\n \n \tif (lstat(ce->name, &st) < 0) {\n+\t\tif (ignore_missing && errno == ENOENT)\n+\t\t\treturn ce;\n \t\tif (err)\n \t\t\t*err = errno;\n \t\treturn NULL;\n@@ -1127,7 +1130,8 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n \tint ignore_submodules = (flags & REFRESH_IGNORE_SUBMODULES) != 0;\n \tint first = 1;\n \tint in_porcelain = (flags & REFRESH_IN_PORCELAIN);\n-\tunsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;\n+\tunsigned int options = ((really ? CE_MATCH_IGNORE_VALID : 0) |\n+\t\t\t\t(not_new ? CE_MATCH_IGNORE_MISSING : 0));\n \tconst char *modified_fmt;\n \tconst char *deleted_fmt;\n \tconst char *typechange_fmt;\n@@ -1176,8 +1180,6 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n \t\tif (!new) {\n \t\t\tconst char *fmt;\n \n-\t\t\tif (not_new && cache_errno == ENOENT)\n-\t\t\t\tcontinue;\n \t\t\tif (really && cache_errno == EINVAL) {\n \t\t\t\t/* If we are doing --really-refresh that\n \t\t\t\t * means the index is not valid anymore.\n-- \n1.8.5.2\n"},{"id":"233822","messageId":"75285192b54cc1fab5daeef39d399d164efbca40.1390833624.git.brad.king@kitware.com","threadId":"35727","inReplyTo":"cover.1390833624.git.brad.king@kitware.com","subject":"[PATCH v3 3/4] read-cache.c: Extend make_cache_entry refresh flag with options","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-27T14:45:08Z","receivedAt":"2014-01-27T14:45:08Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"Convert the make_cache_entry boolean 'refresh' argument to a more\ngeneral 'refresh_options' argument.  Pass the value through to the\nunderlying refresh_cache_ent call.  Add option CE_MATCH_REFRESH to\nenable stat refresh.  Update call sites to use the new signature.\n\nSigned-off-by: Brad King <brad.king@kitware.com>\n---\n cache.h           |  4 +++-\n merge-recursive.c |  3 ++-\n read-cache.c      | 21 +++++++++++----------\n 3 files changed, 16 insertions(+), 12 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex c96ada7..e8820e1 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -487,7 +487,7 @@ extern int remove_file_from_index(struct index_state *, const char *path);\n #define ADD_CACHE_IMPLICIT_DOT 32\t/* internal to \"git add -u/-A\" */\n extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);\n extern int add_file_to_index(struct index_state *, const char *path, int flags);\n-extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);\n+extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);\n extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);\n extern int index_name_is_other(const struct index_state *, const char *, int);\n extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);\n@@ -500,6 +500,8 @@ extern void *read_blob_data_from_index(struct index_state *, const char *, unsig\n #define CE_MATCH_IGNORE_SKIP_WORKTREE\t04\n /* ignore non-existent files during stat update  */\n #define CE_MATCH_IGNORE_MISSING\t\t0x08\n+/* enable stat refresh */\n+#define CE_MATCH_REFRESH\t\t0x10\n extern int ie_match_stat(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);\n extern int ie_modified(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);\n \ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex a18bd15..c3753c8 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -201,7 +201,8 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,\n \t\tconst char *path, int stage, int refresh, int options)\n {\n \tstruct cache_entry *ce;\n-\tce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh);\n+\tce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage,\n+\t\t\t      (refresh ? CE_MATCH_REFRESH : 0 ));\n \tif (!ce)\n \t\treturn error(_(\"addinfo_cache failed for path '%s'\"), path);\n \treturn add_cache_entry(ce, options);\ndiff --git a/read-cache.c b/read-cache.c\nindex d61846c..db3902e 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -15,7 +15,8 @@\n #include \"strbuf.h\"\n #include \"varint.h\"\n \n-static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);\n+static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,\n+\t\t\t\t\t       unsigned int options);\n \n /* Mask for the name length in ce_flags in the on-disk index */\n \n@@ -696,7 +697,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int flags)\n \n struct cache_entry *make_cache_entry(unsigned int mode,\n \t\tconst unsigned char *sha1, const char *path, int stage,\n-\t\tint refresh)\n+\t\tunsigned int refresh_options)\n {\n \tint size, len;\n \tstruct cache_entry *ce;\n@@ -716,10 +717,7 @@ struct cache_entry *make_cache_entry(unsigned int mode,\n \tce->ce_namelen = len;\n \tce->ce_mode = create_ce_mode(mode);\n \n-\tif (refresh)\n-\t\treturn refresh_cache_entry(ce, 0);\n-\n-\treturn ce;\n+\treturn refresh_cache_entry(ce, refresh_options);\n }\n \n int ce_same_name(const struct cache_entry *a, const struct cache_entry *b)\n@@ -1029,11 +1027,12 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,\n \tstruct stat st;\n \tstruct cache_entry *updated;\n \tint changed, size;\n+\tint refresh = options & CE_MATCH_REFRESH;\n \tint ignore_valid = options & CE_MATCH_IGNORE_VALID;\n \tint ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;\n \tint ignore_missing = options & CE_MATCH_IGNORE_MISSING;\n \n-\tif (ce_uptodate(ce))\n+\tif (!refresh || ce_uptodate(ce))\n \t\treturn ce;\n \n \t/*\n@@ -1130,7 +1129,8 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n \tint ignore_submodules = (flags & REFRESH_IGNORE_SUBMODULES) != 0;\n \tint first = 1;\n \tint in_porcelain = (flags & REFRESH_IN_PORCELAIN);\n-\tunsigned int options = ((really ? CE_MATCH_IGNORE_VALID : 0) |\n+\tunsigned int options = (CE_MATCH_REFRESH |\n+\t\t\t\t(really ? CE_MATCH_IGNORE_VALID : 0) |\n \t\t\t\t(not_new ? CE_MATCH_IGNORE_MISSING : 0));\n \tconst char *modified_fmt;\n \tconst char *deleted_fmt;\n@@ -1209,9 +1209,10 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n \treturn has_errors;\n }\n \n-static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)\n+static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,\n+\t\t\t\t\t       unsigned int options)\n {\n-\treturn refresh_cache_ent(&the_index, ce, really, NULL, NULL);\n+\treturn refresh_cache_ent(&the_index, ce, options, NULL, NULL);\n }\n \n \n-- \n1.8.5.2\n"},{"id":"233819","messageId":"8438a8b04676baa25e39bed68c553ecb9f4dfec5.1390833624.git.brad.king@kitware.com","threadId":"35727","inReplyTo":"cover.1390833624.git.brad.king@kitware.com","subject":"[PATCH v3 4/4] merge-recursive.c: Tolerate missing files while refreshing index","fromName":"Brad King","fromEmail":"brad.king@kitware.com","sentAt":"2014-01-27T14:45:09Z","receivedAt":"2014-01-27T14:45:09Z","isPatch":true,"sender":{"key":"brad.king@kitware.com","avatar":"https://avatars.githubusercontent.com/u/87268?v=4"},"body":"Teach add_cacheinfo to tell make_cache_entry to skip refreshing stat\ninformation when a file is missing from the work tree.  We do not want\nthe index to be stat-dirty after the merge but also do not want to fail\nwhen a file happens to be missing.\n\nThis fixes the 'merge-recursive w/ empty work tree - ours has rename'\ncase in t3030-merge-recursive.\n\nSuggested-by: Elijah Newren <newren@gmail.com>\nSigned-off-by: Brad King <brad.king@kitware.com>\n---\n merge-recursive.c          | 3 ++-\n t/t3030-merge-recursive.sh | 2 +-\n 2 files changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex c3753c8..b8ea172 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -202,7 +202,8 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,\n {\n \tstruct cache_entry *ce;\n \tce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage,\n-\t\t\t      (refresh ? CE_MATCH_REFRESH : 0 ));\n+\t\t\t      (refresh ? (CE_MATCH_REFRESH |\n+\t\t\t\t\t  CE_MATCH_IGNORE_MISSING) : 0 ));\n \tif (!ce)\n \t\treturn error(_(\"addinfo_cache failed for path '%s'\"), path);\n \treturn add_cache_entry(ce, options);\ndiff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh\nindex 3db3bf6..82e1854 100755\n--- a/t/t3030-merge-recursive.sh\n+++ b/t/t3030-merge-recursive.sh\n@@ -518,7 +518,7 @@ test_expect_success 'reset and bind merge' '\n \n '\n \n-test_expect_failure 'merge-recursive w/ empty work tree - ours has rename' '\n+test_expect_success 'merge-recursive w/ empty work tree - ours has rename' '\n \t(\n \t\tGIT_WORK_TREE=\"$PWD/ours-has-rename-work\" &&\n \t\texport GIT_WORK_TREE &&\n-- \n1.8.5.2\n"},{"id":"233832","messageId":"xmqqy521nx25.fsf@gitster.dls.corp.google.com","threadId":"35727","inReplyTo":"e8a33f2e20e9f2041bf5f0fa952536755dbdf34c.1390833624.git.brad.king@kitware.com","subject":"Re: [PATCH v3 2/4] read-cache.c: Refactor --ignore-missing implementation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-01-27T17:39:46Z","receivedAt":"2014-01-27T17:39:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Brad King <brad.king@kitware.com> writes:\n\n> Move lstat ENOENT handling from refresh_index to refresh_cache_ent and\n> activate it with a new CE_MATCH_IGNORE_MISSING option.  This will allow\n> other call paths into refresh_cache_ent to use the feature.\n>\n> Signed-off-by: Brad King <brad.king@kitware.com>\n> ---\n\nGood!\n\nI forgot that we had \"update-index --ignore-missing --refresh\", and\nthat is conceptually the thing you want to use in your \"perform\nmerge-recursive in an empty tree while pretending that the working\ntree is fully populated and up-to-date\" scenario.\n\n>  cache.h      | 2 ++\n>  read-cache.c | 8 +++++---\n>  2 files changed, 7 insertions(+), 3 deletions(-)\n>\n> diff --git a/cache.h b/cache.h\n> index c9efe88..c96ada7 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -498,6 +498,8 @@ extern void *read_blob_data_from_index(struct index_state *, const char *, unsig\n>  #define CE_MATCH_RACY_IS_DIRTY\t\t02\n>  /* do stat comparison even if CE_SKIP_WORKTREE is true */\n>  #define CE_MATCH_IGNORE_SKIP_WORKTREE\t04\n> +/* ignore non-existent files during stat update  */\n> +#define CE_MATCH_IGNORE_MISSING\t\t0x08\n>  extern int ie_match_stat(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);\n>  extern int ie_modified(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);\n>  \n> diff --git a/read-cache.c b/read-cache.c\n> index 33dd676..d61846c 100644\n> --- a/read-cache.c\n> +++ b/read-cache.c\n> @@ -1031,6 +1031,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,\n>  \tint changed, size;\n>  \tint ignore_valid = options & CE_MATCH_IGNORE_VALID;\n>  \tint ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;\n> +\tint ignore_missing = options & CE_MATCH_IGNORE_MISSING;\n>  \n>  \tif (ce_uptodate(ce))\n>  \t\treturn ce;\n> @@ -1050,6 +1051,8 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,\n>  \t}\n>  \n>  \tif (lstat(ce->name, &st) < 0) {\n> +\t\tif (ignore_missing && errno == ENOENT)\n> +\t\t\treturn ce;\n>  \t\tif (err)\n>  \t\t\t*err = errno;\n>  \t\treturn NULL;\n> @@ -1127,7 +1130,8 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n>  \tint ignore_submodules = (flags & REFRESH_IGNORE_SUBMODULES) != 0;\n>  \tint first = 1;\n>  \tint in_porcelain = (flags & REFRESH_IN_PORCELAIN);\n> -\tunsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;\n> +\tunsigned int options = ((really ? CE_MATCH_IGNORE_VALID : 0) |\n> +\t\t\t\t(not_new ? CE_MATCH_IGNORE_MISSING : 0));\n>  \tconst char *modified_fmt;\n>  \tconst char *deleted_fmt;\n>  \tconst char *typechange_fmt;\n> @@ -1176,8 +1180,6 @@ int refresh_index(struct index_state *istate, unsigned int flags,\n>  \t\tif (!new) {\n>  \t\t\tconst char *fmt;\n>  \n> -\t\t\tif (not_new && cache_errno == ENOENT)\n> -\t\t\t\tcontinue;\n>  \t\t\tif (really && cache_errno == EINVAL) {\n>  \t\t\t\t/* If we are doing --really-refresh that\n>  \t\t\t\t * means the index is not valid anymore.\n"}]}