{"thread":{"id":"45162","subject":"[PATCH/RFC 00/15] Fix git-gc losing objects in multi worktree","startedAt":"2017-02-17T14:19:33Z","lastAt":"2017-04-20T02:21:10Z","messageCount":33,"participants":["Nguyễn Thái Ngọc Duy","Johannes Schindelin","Junio C Hamano","Duy Nguyen"],"isPatch":true,"patchVersion":1,"patchTotal":15},"messages":[{"id":"311879","messageId":"20170217141908.18012-1-pclouds@gmail.com","threadId":"45162","inReplyTo":null,"subject":"[PATCH/RFC 00/15] Fix git-gc losing objects in multi worktree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:18:53Z","receivedAt":"2017-02-17T14:19:33Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"So here is my latest attempt on fixing this issue. For people who are\nnot aware of it, git-gc does not take per-worktree refs, reflogs and\nindexes into account. An odb prune may leave HEAD and references in other\nworktrees pointing to nowhere.\n\nThis series is based on my \"kill parse_ref()\" series [1], which is\nbased on yet another one, which is on top of mh/submodule-hash. But\nyou can get everything from my github [2].\n\nThe series introduces a new set of refs_* API and replaces the old\n*_submodule() one, opening up the opportunity to access refs from\nanother worktree. rev-list learns a new option, --single-worktree, to\ncontrol the new behavior.\n\nreflog iterator from files-backend.c does not support per-worktree\nitems, so it's updated here to do that. It still looks ugly, but I\nthink this is a good \"middle ground\" until compound ref store comes.\nAt that point we can separate \"single worktree\" ref store vs \"linked\nworktree\" one.\n\nI'm adding Stefan here as well since I added a new FIXME in\nsubmodule.c in 11/15. I think it's ok (again, for now). But another\nlook from submodule people would be much better.\n\n[1] http://public-inbox.org/git/%3C20170216120302.5302-1-pclouds@gmail.com%3E/\n[2] https://github.com/pclouds/git/commits/prune-in-worktrees-2\n\nNguyễn Thái Ngọc Duy (15):\n  revision.h: new flag in struct rev_info wrt. worktree-related refs\n  revision.c: refactor add_index_objects_to_pending()\n  revision.c: --indexed-objects add objects from all worktrees\n  refs: move submodule slash stripping code to get_submodule_ref_store\n  refs: add refs_read_ref[_full]()\n  refs: add refs_head_ref()\n  refs: add refs_for_each_ref()\n  refs: add a refs_for_each_in() and friends\n  revision.c: use refs_for_each*() instead of for_each_*_submodule()\n  refs: remove dead for_each_*_submodule()\n  revision.c: --all adds HEAD from all worktrees\n  refs: add refs_for_each_reflog[_ent]()\n  files-backend: make reflog iterator go through per-worktree reflog\n  revision.c: --reflog add HEAD reflog from all worktrees\n  rev-list: expose and document --single-worktree\n\n Documentation/rev-list-options.txt |   8 ++\n reachable.c                        |   1 +\n refs.c                             | 171 ++++++++++++++++++++++++-------------\n refs.h                             |  25 ++++--\n refs/files-backend.c               |  24 +++++-\n revision.c                         | 130 +++++++++++++++++++++++-----\n revision.h                         |   1 +\n submodule.c                        |   2 +\n t/t5304-prune.sh                   |  37 ++++++++\n 9 files changed, 305 insertions(+), 94 deletions(-)\n\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311880","messageId":"20170217141908.18012-2-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH 01/15] revision.h: new flag in struct rev_info wrt. worktree-related refs","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:18:54Z","receivedAt":"2017-02-17T14:19:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The revision walker can walk through per-worktree refs like HEAD or\nSHA-1 references in the index. These currently are from the current\nworktree only. This new flag is added to change rev-list behavior in\nthis regard:\n\nWhen single_worktree is set, only current worktree is considered. When\nit is not set (which is the default), all worktrees are considered.\n\nThe default is chosen so because the two big components that rev-list\nworks with are object database (entirely shared between worktrees) and\nrefs (mostly shared). It makes sense that default behavior goes per-repo\ntoo instead of per-worktree.\n\nThe flag will eventually be exposed as a rev-list argument with\ndocuments. For now it stays internal until the new behavior is fully\nimplemented.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n revision.h | 1 +\n 1 file changed, 1 insertion(+)\n\ndiff --git a/revision.h b/revision.h\nindex 9fac1a607..c851b94ad 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -88,6 +88,7 @@ struct rev_info {\n \t\t\ttopo_order:1,\n \t\t\tsimplify_merges:1,\n \t\t\tsimplify_by_decoration:1,\n+\t\t\tsingle_worktree:1,\n \t\t\ttag_objects:1,\n \t\t\ttree_objects:1,\n \t\t\tblob_objects:1,\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311881","messageId":"20170217141908.18012-3-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH 02/15] revision.c: refactor add_index_objects_to_pending()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:18:55Z","receivedAt":"2017-02-17T14:19:54Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The core code is factored out and take 'struct index_state *' instead so\nthat we can reuse it to add objects from index files other than .git/index\nin the next patch.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n revision.c | 18 ++++++++++++------\n 1 file changed, 12 insertions(+), 6 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex b37dbec37..ece868a25 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1263,13 +1263,13 @@ static void add_cache_tree(struct cache_tree *it, struct rev_info *revs,\n \n }\n \n-void add_index_objects_to_pending(struct rev_info *revs, unsigned flags)\n+static void do_add_index_objects_to_pending(struct rev_info *revs,\n+\t\t\t\t\t    struct index_state *istate)\n {\n \tint i;\n \n-\tread_cache();\n-\tfor (i = 0; i < active_nr; i++) {\n-\t\tstruct cache_entry *ce = active_cache[i];\n+\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\tstruct cache_entry *ce = istate->cache[i];\n \t\tstruct blob *blob;\n \n \t\tif (S_ISGITLINK(ce->ce_mode))\n@@ -1282,13 +1282,19 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned flags)\n \t\t\t\t\t     ce->ce_mode, ce->name);\n \t}\n \n-\tif (active_cache_tree) {\n+\tif (istate->cache_tree) {\n \t\tstruct strbuf path = STRBUF_INIT;\n-\t\tadd_cache_tree(active_cache_tree, revs, &path);\n+\t\tadd_cache_tree(istate->cache_tree, revs, &path);\n \t\tstrbuf_release(&path);\n \t}\n }\n \n+void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)\n+{\n+\tread_cache();\n+\tdo_add_index_objects_to_pending(revs, &the_index);\n+}\n+\n static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,\n \t\t\t    int exclude_parent)\n {\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311882","messageId":"20170217141908.18012-4-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH 03/15] revision.c: --indexed-objects add objects from all worktrees","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:18:56Z","receivedAt":"2017-02-17T14:19:57Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is the result of single_worktree flag never being set (no way to up\nuntil now). To get objects from current index only, set single_worktree.\n\nThe other add_index_objects_to_pending's caller is mark_reachable_objects()\n(e.g. \"git prune\") which also mark objects from all indexes.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n revision.c       | 21 +++++++++++++++++++++\n t/t5304-prune.sh |  9 +++++++++\n 2 files changed, 30 insertions(+)\n\ndiff --git a/revision.c b/revision.c\nindex ece868a25..d82f72ff3 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -19,6 +19,7 @@\n #include \"dir.h\"\n #include \"cache-tree.h\"\n #include \"bisect.h\"\n+#include \"worktree.h\"\n \n volatile show_early_output_fn_t show_early_output;\n \n@@ -1291,8 +1292,28 @@ static void do_add_index_objects_to_pending(struct rev_info *revs,\n \n void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)\n {\n+\tstruct worktree **worktrees, **p;\n+\n \tread_cache();\n \tdo_add_index_objects_to_pending(revs, &the_index);\n+\n+\tif (revs->single_worktree)\n+\t\treturn;\n+\n+\tworktrees = get_worktrees(0);\n+\tfor (p = worktrees; *p; p++) {\n+\t\tstruct worktree *wt = *p;\n+\t\tstruct index_state istate = {0};\n+\n+\t\tif (wt->is_current)\n+\t\t\tcontinue; /* current index already taken care of */\n+\n+\t\tif (read_index_from(&istate,\n+\t\t\t\t    worktree_git_path(wt, \"index\")) > 0)\n+\t\t\tdo_add_index_objects_to_pending(revs, &istate);\n+\t\tdiscard_index(&istate);\n+\t}\n+\tfree_worktrees(worktrees);\n }\n \n static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,\ndiff --git a/t/t5304-prune.sh b/t/t5304-prune.sh\nindex 133b5842b..cba45c7be 100755\n--- a/t/t5304-prune.sh\n+++ b/t/t5304-prune.sh\n@@ -283,4 +283,13 @@ test_expect_success 'prune: handle alternate object database' '\n \tgit -C B prune\n '\n \n+test_expect_success 'prune: handle index in multiple worktrees' '\n+\tgit worktree add second-worktree &&\n+\techo \"new blob for second-worktree\" >second-worktree/blob &&\n+\tgit -C second-worktree add blob &&\n+\tgit prune --expire=now &&\n+\tgit -C second-worktree show :blob >actual &&\n+\ttest_cmp second-worktree/blob actual\n+'\n+\n test_done\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311883","messageId":"20170217141908.18012-5-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH 04/15] refs: move submodule slash stripping code to get_submodule_ref_store","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:18:57Z","receivedAt":"2017-02-17T14:20:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is a better place that will benefit all submodule callers instead\nof just resolve_gitlink_ref()\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n refs.c | 38 ++++++++++++++++++++------------------\n 1 file changed, 20 insertions(+), 18 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 23e0a8eda..9c86c44b8 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1321,25 +1321,10 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n int resolve_gitlink_ref(const char *submodule, const char *refname,\n \t\t\tunsigned char *sha1)\n {\n-\tsize_t len = strlen(submodule);\n \tstruct ref_store *refs;\n \tint flags;\n \n-\twhile (len && submodule[len - 1] == '/')\n-\t\tlen--;\n-\n-\tif (!len)\n-\t\treturn -1;\n-\n-\tif (submodule[len]) {\n-\t\t/* We need to strip off one or more trailing slashes */\n-\t\tchar *stripped = xmemdupz(submodule, len);\n-\n-\t\trefs = get_submodule_ref_store(stripped);\n-\t\tfree(stripped);\n-\t} else {\n-\t\trefs = get_submodule_ref_store(submodule);\n-\t}\n+\trefs = get_submodule_ref_store(submodule);\n \n \tif (!refs)\n \t\treturn -1;\n@@ -1458,7 +1443,17 @@ struct ref_store *get_submodule_ref_store(const char *submodule)\n {\n \tstruct strbuf submodule_sb = STRBUF_INIT;\n \tstruct ref_store *refs;\n+\tchar *to_free = NULL;\n \tint ret;\n+\tsize_t len;\n+\n+\tif (submodule) {\n+\t\tlen = strlen(submodule);\n+\t\twhile (len && submodule[len - 1] == '/')\n+\t\t\tlen--;\n+\t\tif (!len)\n+\t\t\tsubmodule = NULL;\n+\t}\n \n \tif (!submodule || !*submodule) {\n \t\t/*\n@@ -1468,15 +1463,19 @@ struct ref_store *get_submodule_ref_store(const char *submodule)\n \t\treturn get_main_ref_store();\n \t}\n \n+\tif (submodule[len])\n+\t\t/* We need to strip off one or more trailing slashes */\n+\t\tsubmodule = to_free = xmemdupz(submodule, len);\n+\n \trefs = lookup_submodule_ref_store(submodule);\n \tif (refs)\n-\t\treturn refs;\n+\t\tgoto done;\n \n \tstrbuf_addstr(&submodule_sb, submodule);\n \tret = is_nonbare_repository_dir(&submodule_sb);\n \tstrbuf_release(&submodule_sb);\n \tif (!ret)\n-\t\treturn refs;\n+\t\tgoto done;\n \n \tret = submodule_to_gitdir(&submodule_sb, submodule);\n \tif (!ret)\n@@ -1485,6 +1484,9 @@ struct ref_store *get_submodule_ref_store(const char *submodule)\n \n \tif (refs)\n \t\tregister_submodule_ref_store(refs, submodule);\n+\n+done:\n+\tfree(to_free);\n \treturn refs;\n }\n \n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311884","messageId":"20170217141908.18012-7-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH 06/15] refs: add refs_head_ref()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:18:59Z","receivedAt":"2017-02-17T14:20:06Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n refs.c | 19 +++++++++----------\n refs.h |  1 +\n 2 files changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 06890db5d..26758b8cf 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1139,27 +1139,26 @@ int rename_ref_available(const char *old_refname, const char *new_refname)\n \treturn ok;\n }\n \n-int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n+int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n {\n \tstruct object_id oid;\n \tint flag;\n \n-\tif (submodule) {\n-\t\tif (resolve_gitlink_ref(submodule, \"HEAD\", oid.hash) == 0)\n-\t\t\treturn fn(\"HEAD\", &oid, 0, cb_data);\n-\n-\t\treturn 0;\n-\t}\n-\n-\tif (!read_ref_full(\"HEAD\", RESOLVE_REF_READING, oid.hash, &flag))\n+\tif (!refs_read_ref_full(refs, \"HEAD\", RESOLVE_REF_READING,\n+\t\t\t\toid.hash, &flag))\n \t\treturn fn(\"HEAD\", &oid, flag, cb_data);\n \n \treturn 0;\n }\n \n+int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n+{\n+\treturn refs_head_ref(get_submodule_ref_store(submodule), fn, cb_data);\n+}\n+\n int head_ref(each_ref_fn fn, void *cb_data)\n {\n-\treturn head_ref_submodule(NULL, fn, cb_data);\n+\treturn refs_head_ref(get_main_ref_store(), fn, cb_data);\n }\n \n /*\ndiff --git a/refs.h b/refs.h\nindex 229a97f59..54c038e3c 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -573,5 +573,6 @@ int refs_read_ref_full(struct ref_store *refs,\n \t\t       unsigned char *sha1, int *flags);\n int refs_read_ref(struct ref_store *refs,\n \t\t  const char *refname, unsigned char *sha1);\n+int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data);\n \n #endif /* REFS_H */\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311885","messageId":"20170217141908.18012-6-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH 05/15] refs: add refs_read_ref[_full]()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:18:58Z","receivedAt":"2017-02-17T14:20:11Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n refs.c | 19 ++++++++++++++++---\n refs.h |  5 +++++\n 2 files changed, 21 insertions(+), 3 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 9c86c44b8..06890db5d 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -186,16 +186,29 @@ struct ref_filter {\n \tvoid *cb_data;\n };\n \n-int read_ref_full(const char *refname, int resolve_flags, unsigned char *sha1, int *flags)\n+int refs_read_ref_full(struct ref_store *refs,\n+\t\t       const char *refname, int resolve_flags,\n+\t\t       unsigned char *sha1, int *flags)\n {\n-\tif (resolve_ref_unsafe(refname, resolve_flags, sha1, flags))\n+\tif (refs_resolve_ref_unsafe(refs, refname, resolve_flags, sha1, flags))\n \t\treturn 0;\n \treturn -1;\n }\n \n+int read_ref_full(const char *refname, int resolve_flags, unsigned char *sha1, int *flags)\n+{\n+\treturn refs_read_ref_full(get_main_ref_store(), refname,\n+\t\t\t\t  resolve_flags, sha1, flags);\n+}\n+\n+int refs_read_ref(struct ref_store *refs, const char *refname, unsigned char *sha1)\n+{\n+\treturn refs_read_ref_full(refs, refname, RESOLVE_REF_READING, sha1, NULL);\n+}\n+\n int read_ref(const char *refname, unsigned char *sha1)\n {\n-\treturn read_ref_full(refname, RESOLVE_REF_READING, sha1, NULL);\n+\treturn refs_read_ref(get_main_ref_store(), refname, sha1);\n }\n \n int ref_exists(const char *refname)\ndiff --git a/refs.h b/refs.h\nindex bce77891a..229a97f59 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -568,5 +568,10 @@ int refs_create_symref(struct ref_store *refs,\n \t\t       const char *refname,\n \t\t       const char *target,\n \t\t       const char *logmsg);\n+int refs_read_ref_full(struct ref_store *refs,\n+\t\t       const char *refname, int resolve_flags,\n+\t\t       unsigned char *sha1, int *flags);\n+int refs_read_ref(struct ref_store *refs,\n+\t\t  const char *refname, unsigned char *sha1);\n \n #endif /* REFS_H */\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311886","messageId":"20170217141908.18012-8-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH 07/15] refs: add refs_for_each_ref()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:19:00Z","receivedAt":"2017-02-17T14:20:14Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n refs.c | 33 ++++++++++++++++++++++-----------\n refs.h |  1 +\n 2 files changed, 23 insertions(+), 11 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 26758b8cf..fc6cca3db 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1170,10 +1170,9 @@ int head_ref(each_ref_fn fn, void *cb_data)\n  * non-zero value, stop the iteration and return that value;\n  * otherwise, return 0.\n  */\n-static int do_for_each_ref(const char *submodule, const char *prefix,\n+static int do_for_each_ref(struct ref_store *refs, const char *prefix,\n \t\t\t   each_ref_fn fn, int trim, int flags, void *cb_data)\n {\n-\tstruct ref_store *refs = get_submodule_ref_store(submodule);\n \tstruct ref_iterator *iter;\n \n \tif (!refs)\n@@ -1185,19 +1184,26 @@ static int do_for_each_ref(const char *submodule, const char *prefix,\n \treturn do_for_each_ref_iterator(iter, fn, cb_data);\n }\n \n+int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n+{\n+\treturn do_for_each_ref(refs, \"\", fn, 0, 0, cb_data);\n+}\n+\n int for_each_ref(each_ref_fn fn, void *cb_data)\n {\n-\treturn do_for_each_ref(NULL, \"\", fn, 0, 0, cb_data);\n+\treturn do_for_each_ref(get_main_ref_store(), \"\", fn, 0, 0, cb_data);\n }\n \n int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n {\n-\treturn do_for_each_ref(submodule, \"\", fn, 0, 0, cb_data);\n+\treturn do_for_each_ref(get_submodule_ref_store(submodule),\n+\t\t\t       \"\", fn, 0, 0, cb_data);\n }\n \n int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)\n {\n-\treturn do_for_each_ref(NULL, prefix, fn, strlen(prefix), 0, cb_data);\n+\treturn do_for_each_ref(get_main_ref_store(),\n+\t\t\t       prefix, fn, strlen(prefix), 0, cb_data);\n }\n \n int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsigned int broken)\n@@ -1206,19 +1212,23 @@ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsig\n \n \tif (broken)\n \t\tflag = DO_FOR_EACH_INCLUDE_BROKEN;\n-\treturn do_for_each_ref(NULL, prefix, fn, 0, flag, cb_data);\n+\treturn do_for_each_ref(get_main_ref_store(),\n+\t\t\t       prefix, fn, 0, flag, cb_data);\n }\n \n int for_each_ref_in_submodule(const char *submodule, const char *prefix,\n \t\teach_ref_fn fn, void *cb_data)\n {\n-\treturn do_for_each_ref(submodule, prefix, fn, strlen(prefix), 0, cb_data);\n+\treturn do_for_each_ref(get_submodule_ref_store(submodule),\n+\t\t\t       prefix, fn, strlen(prefix), 0, cb_data);\n }\n \n int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n {\n-\treturn do_for_each_ref(NULL, git_replace_ref_base, fn,\n-\t\t\t       strlen(git_replace_ref_base), 0, cb_data);\n+\treturn do_for_each_ref(get_main_ref_store(),\n+\t\t\t       git_replace_ref_base, fn,\n+\t\t\t       strlen(git_replace_ref_base),\n+\t\t\t       0, cb_data);\n }\n \n int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)\n@@ -1226,14 +1236,15 @@ int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)\n \tstruct strbuf buf = STRBUF_INIT;\n \tint ret;\n \tstrbuf_addf(&buf, \"%srefs/\", get_git_namespace());\n-\tret = do_for_each_ref(NULL, buf.buf, fn, 0, 0, cb_data);\n+\tret = do_for_each_ref(get_main_ref_store(),\n+\t\t\t      buf.buf, fn, 0, 0, cb_data);\n \tstrbuf_release(&buf);\n \treturn ret;\n }\n \n int for_each_rawref(each_ref_fn fn, void *cb_data)\n {\n-\treturn do_for_each_ref(NULL, \"\", fn, 0,\n+\treturn do_for_each_ref(get_main_ref_store(), \"\", fn, 0,\n \t\t\t       DO_FOR_EACH_INCLUDE_BROKEN, cb_data);\n }\n \ndiff --git a/refs.h b/refs.h\nindex 54c038e3c..8e3b4e839 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -574,5 +574,6 @@ int refs_read_ref_full(struct ref_store *refs,\n int refs_read_ref(struct ref_store *refs,\n \t\t  const char *refname, unsigned char *sha1);\n int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data);\n+int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data);\n \n #endif /* REFS_H */\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311887","messageId":"20170217141908.18012-9-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH 08/15] refs: add a refs_for_each_in() and friends","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:19:01Z","receivedAt":"2017-02-17T14:20:19Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n refs.c | 39 +++++++++++++++++++++++++++++++--------\n refs.h |  5 +++++\n 2 files changed, 36 insertions(+), 8 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex fc6cca3db..37b03d4ff 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -300,34 +300,52 @@ void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_li\n \tfor_each_rawref(warn_if_dangling_symref, &data);\n }\n \n+int refs_for_each_tag_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n+{\n+\treturn refs_for_each_ref_in(refs, \"refs/tags/\", fn, cb_data);\n+}\n+\n int for_each_tag_ref(each_ref_fn fn, void *cb_data)\n {\n-\treturn for_each_ref_in(\"refs/tags/\", fn, cb_data);\n+\treturn refs_for_each_tag_ref(get_main_ref_store(), fn, cb_data);\n }\n \n int for_each_tag_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n {\n-\treturn for_each_ref_in_submodule(submodule, \"refs/tags/\", fn, cb_data);\n+\treturn refs_for_each_tag_ref(get_submodule_ref_store(submodule),\n+\t\t\t\t     fn, cb_data);\n+}\n+\n+int refs_for_each_branch_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n+{\n+\treturn refs_for_each_ref_in(refs, \"refs/heads/\", fn, cb_data);\n }\n \n int for_each_branch_ref(each_ref_fn fn, void *cb_data)\n {\n-\treturn for_each_ref_in(\"refs/heads/\", fn, cb_data);\n+\treturn refs_for_each_branch_ref(get_main_ref_store(), fn, cb_data);\n }\n \n int for_each_branch_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n {\n-\treturn for_each_ref_in_submodule(submodule, \"refs/heads/\", fn, cb_data);\n+\treturn refs_for_each_branch_ref(get_submodule_ref_store(submodule),\n+\t\t\t\t\tfn, cb_data);\n+}\n+\n+int refs_for_each_remote_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n+{\n+\treturn refs_for_each_ref_in(refs, \"refs/remotes/\", fn, cb_data);\n }\n \n int for_each_remote_ref(each_ref_fn fn, void *cb_data)\n {\n-\treturn for_each_ref_in(\"refs/remotes/\", fn, cb_data);\n+\treturn refs_for_each_remote_ref(get_main_ref_store(), fn, cb_data);\n }\n \n int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n {\n-\treturn for_each_ref_in_submodule(submodule, \"refs/remotes/\", fn, cb_data);\n+\treturn refs_for_each_remote_ref(get_submodule_ref_store(submodule),\n+\t\t\t\t\tfn, cb_data);\n }\n \n int head_ref_namespaced(each_ref_fn fn, void *cb_data)\n@@ -1200,10 +1218,15 @@ int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n \t\t\t       \"\", fn, 0, 0, cb_data);\n }\n \n+int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,\n+\t\t\t each_ref_fn fn, void *cb_data)\n+{\n+\treturn do_for_each_ref(refs, prefix, fn, strlen(prefix), 0, cb_data);\n+}\n+\n int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)\n {\n-\treturn do_for_each_ref(get_main_ref_store(),\n-\t\t\t       prefix, fn, strlen(prefix), 0, cb_data);\n+\treturn refs_for_each_ref_in(get_main_ref_store(), prefix, fn, cb_data);\n }\n \n int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsigned int broken)\ndiff --git a/refs.h b/refs.h\nindex 8e3b4e839..8fc82deda 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -575,5 +575,10 @@ int refs_read_ref(struct ref_store *refs,\n \t\t  const char *refname, unsigned char *sha1);\n int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data);\n int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data);\n+int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,\n+\t\t\t each_ref_fn fn, void *cb_data);\n+int refs_for_each_tag_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data);\n+int refs_for_each_branch_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data);\n+int refs_for_each_remote_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data);\n \n #endif /* REFS_H */\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311888","messageId":"20170217141908.18012-10-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH 09/15] revision.c: use refs_for_each*() instead of for_each_*_submodule()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:19:02Z","receivedAt":"2017-02-17T14:20:25Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n revision.c | 48 ++++++++++++++++++++++++++++++++----------------\n 1 file changed, 32 insertions(+), 16 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex d82f72ff3..d82c37b44 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1189,12 +1189,19 @@ void add_ref_exclusion(struct string_list **ref_excludes_p, const char *exclude)\n \tstring_list_append(*ref_excludes_p, exclude);\n }\n \n-static void handle_refs(const char *submodule, struct rev_info *revs, unsigned flags,\n-\t\tint (*for_each)(const char *, each_ref_fn, void *))\n+static void handle_refs(struct ref_store *refs,\n+\t\t\tstruct rev_info *revs, unsigned flags,\n+\t\t\tint (*for_each)(struct ref_store *, each_ref_fn, void *))\n {\n \tstruct all_refs_cb cb;\n+\n+\tif (!refs) {\n+\t\t/* this could happen with uninitialized submodules */\n+\t\treturn;\n+\t}\n+\n \tinit_all_refs_cb(&cb, revs, flags);\n-\tfor_each(submodule, handle_one_ref, &cb);\n+\tfor_each(refs, handle_one_ref, &cb);\n }\n \n static void handle_one_reflog_commit(unsigned char *sha1, void *cb_data)\n@@ -2067,23 +2074,25 @@ void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,\n \tctx->argc -= n;\n }\n \n-static int for_each_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data, const char *term) {\n+static int for_each_bisect_ref(struct ref_store *refs, each_ref_fn fn,\n+\t\t\t       void *cb_data, const char *term)\n+{\n \tstruct strbuf bisect_refs = STRBUF_INIT;\n \tint status;\n \tstrbuf_addf(&bisect_refs, \"refs/bisect/%s\", term);\n-\tstatus = for_each_ref_in_submodule(submodule, bisect_refs.buf, fn, cb_data);\n+\tstatus = refs_for_each_ref_in(refs, bisect_refs.buf, fn, cb_data);\n \tstrbuf_release(&bisect_refs);\n \treturn status;\n }\n \n-static int for_each_bad_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data)\n+static int for_each_bad_bisect_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n {\n-\treturn for_each_bisect_ref(submodule, fn, cb_data, term_bad);\n+\treturn for_each_bisect_ref(refs, fn, cb_data, term_bad);\n }\n \n-static int for_each_good_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data)\n+static int for_each_good_bisect_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n {\n-\treturn for_each_bisect_ref(submodule, fn, cb_data, term_good);\n+\treturn for_each_bisect_ref(refs, fn, cb_data, term_good);\n }\n \n static int handle_revision_pseudo_opt(const char *submodule,\n@@ -2092,8 +2101,14 @@ static int handle_revision_pseudo_opt(const char *submodule,\n {\n \tconst char *arg = argv[0];\n \tconst char *optarg;\n+\tstruct ref_store *refs;\n \tint argcount;\n \n+\tif (submodule) {\n+\t\trefs = get_submodule_ref_store(submodule);\n+\t} else\n+\t\trefs = get_main_ref_store();\n+\n \t/*\n \t * NOTE!\n \t *\n@@ -2105,22 +2120,23 @@ static int handle_revision_pseudo_opt(const char *submodule,\n \t * register it in the list at the top of handle_revision_opt.\n \t */\n \tif (!strcmp(arg, \"--all\")) {\n-\t\thandle_refs(submodule, revs, *flags, for_each_ref_submodule);\n-\t\thandle_refs(submodule, revs, *flags, head_ref_submodule);\n+\t\thandle_refs(refs, revs, *flags, refs_for_each_ref);\n+\t\thandle_refs(refs, revs, *flags, refs_head_ref);\n \t\tclear_ref_exclusion(&revs->ref_excludes);\n \t} else if (!strcmp(arg, \"--branches\")) {\n-\t\thandle_refs(submodule, revs, *flags, for_each_branch_ref_submodule);\n+\t\thandle_refs(refs, revs, *flags, refs_for_each_branch_ref);\n \t\tclear_ref_exclusion(&revs->ref_excludes);\n \t} else if (!strcmp(arg, \"--bisect\")) {\n \t\tread_bisect_terms(&term_bad, &term_good);\n-\t\thandle_refs(submodule, revs, *flags, for_each_bad_bisect_ref);\n-\t\thandle_refs(submodule, revs, *flags ^ (UNINTERESTING | BOTTOM), for_each_good_bisect_ref);\n+\t\thandle_refs(refs, revs, *flags, for_each_bad_bisect_ref);\n+\t\thandle_refs(refs, revs, *flags ^ (UNINTERESTING | BOTTOM),\n+\t\t\t    for_each_good_bisect_ref);\n \t\trevs->bisect = 1;\n \t} else if (!strcmp(arg, \"--tags\")) {\n-\t\thandle_refs(submodule, revs, *flags, for_each_tag_ref_submodule);\n+\t\thandle_refs(refs, revs, *flags, refs_for_each_tag_ref);\n \t\tclear_ref_exclusion(&revs->ref_excludes);\n \t} else if (!strcmp(arg, \"--remotes\")) {\n-\t\thandle_refs(submodule, revs, *flags, for_each_remote_ref_submodule);\n+\t\thandle_refs(refs, revs, *flags, refs_for_each_remote_ref);\n \t\tclear_ref_exclusion(&revs->ref_excludes);\n \t} else if ((argcount = parse_long_opt(\"glob\", argv, &optarg))) {\n \t\tstruct all_refs_cb cb;\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311889","messageId":"20170217141908.18012-11-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH 10/15] refs: remove dead for_each_*_submodule()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:19:03Z","receivedAt":"2017-02-17T14:20:29Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"These are used in revision.c. After the last patch they are replaced\nwith the refs_ version. Delete them (except for_each_remote_ref_submodule\nwhich is still used by submodule.c)\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n refs.c | 30 ------------------------------\n refs.h |  9 ---------\n 2 files changed, 39 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 37b03d4ff..fa2df7a1d 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -310,12 +310,6 @@ int for_each_tag_ref(each_ref_fn fn, void *cb_data)\n \treturn refs_for_each_tag_ref(get_main_ref_store(), fn, cb_data);\n }\n \n-int for_each_tag_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n-{\n-\treturn refs_for_each_tag_ref(get_submodule_ref_store(submodule),\n-\t\t\t\t     fn, cb_data);\n-}\n-\n int refs_for_each_branch_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n {\n \treturn refs_for_each_ref_in(refs, \"refs/heads/\", fn, cb_data);\n@@ -326,12 +320,6 @@ int for_each_branch_ref(each_ref_fn fn, void *cb_data)\n \treturn refs_for_each_branch_ref(get_main_ref_store(), fn, cb_data);\n }\n \n-int for_each_branch_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n-{\n-\treturn refs_for_each_branch_ref(get_submodule_ref_store(submodule),\n-\t\t\t\t\tfn, cb_data);\n-}\n-\n int refs_for_each_remote_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n {\n \treturn refs_for_each_ref_in(refs, \"refs/remotes/\", fn, cb_data);\n@@ -1169,11 +1157,6 @@ int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n \treturn 0;\n }\n \n-int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n-{\n-\treturn refs_head_ref(get_submodule_ref_store(submodule), fn, cb_data);\n-}\n-\n int head_ref(each_ref_fn fn, void *cb_data)\n {\n \treturn refs_head_ref(get_main_ref_store(), fn, cb_data);\n@@ -1212,12 +1195,6 @@ int for_each_ref(each_ref_fn fn, void *cb_data)\n \treturn do_for_each_ref(get_main_ref_store(), \"\", fn, 0, 0, cb_data);\n }\n \n-int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n-{\n-\treturn do_for_each_ref(get_submodule_ref_store(submodule),\n-\t\t\t       \"\", fn, 0, 0, cb_data);\n-}\n-\n int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,\n \t\t\t each_ref_fn fn, void *cb_data)\n {\n@@ -1239,13 +1216,6 @@ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsig\n \t\t\t       prefix, fn, 0, flag, cb_data);\n }\n \n-int for_each_ref_in_submodule(const char *submodule, const char *prefix,\n-\t\teach_ref_fn fn, void *cb_data)\n-{\n-\treturn do_for_each_ref(get_submodule_ref_store(submodule),\n-\t\t\t       prefix, fn, strlen(prefix), 0, cb_data);\n-}\n-\n int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n {\n \treturn do_for_each_ref(get_main_ref_store(),\ndiff --git a/refs.h b/refs.h\nindex 8fc82deda..986d408bd 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -202,15 +202,6 @@ int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);\n int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,\n \t\t\t const char *prefix, void *cb_data);\n \n-int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);\n-int for_each_ref_submodule(const char *submodule,\n-\t\t\t   each_ref_fn fn, void *cb_data);\n-int for_each_ref_in_submodule(const char *submodule, const char *prefix,\n-\t\teach_ref_fn fn, void *cb_data);\n-int for_each_tag_ref_submodule(const char *submodule,\n-\t\t\t       each_ref_fn fn, void *cb_data);\n-int for_each_branch_ref_submodule(const char *submodule,\n-\t\t\t\t  each_ref_fn fn, void *cb_data);\n int for_each_remote_ref_submodule(const char *submodule,\n \t\t\t\t  each_ref_fn fn, void *cb_data);\n \n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311890","messageId":"20170217141908.18012-13-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH 12/15] refs: add refs_for_each_reflog[_ent]()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:19:05Z","receivedAt":"2017-02-17T14:20:46Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n refs.c | 19 ++++++++++++++-----\n refs.h |  3 +++\n 2 files changed, 17 insertions(+), 5 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex ce165c0ea..622c6b669 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1592,9 +1592,8 @@ int verify_refname_available(const char *refname,\n \treturn refs->be->verify_refname_available(refs, refname, extra, skip, err);\n }\n \n-int for_each_reflog(each_ref_fn fn, void *cb_data)\n+int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n {\n-\tstruct ref_store *refs = get_main_ref_store();\n \tstruct ref_iterator *iter;\n \n \titer = refs->be->reflog_iterator_begin(refs);\n@@ -1602,6 +1601,11 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)\n \treturn do_for_each_ref_iterator(iter, fn, cb_data);\n }\n \n+int for_each_reflog(each_ref_fn fn, void *cb_data)\n+{\n+\treturn refs_for_each_reflog(get_main_ref_store(), fn, cb_data);\n+}\n+\n int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn,\n \t\t\t\tvoid *cb_data)\n {\n@@ -1611,12 +1615,17 @@ int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn,\n \t\t\t\t\t\t     fn, cb_data);\n }\n \n+int refs_for_each_reflog_ent(struct ref_store *refs, const char *refname,\n+\t\t\t     each_reflog_ent_fn fn, void *cb_data)\n+{\n+\treturn refs->be->for_each_reflog_ent(refs, refname, fn, cb_data);\n+}\n+\n int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn,\n \t\t\tvoid *cb_data)\n {\n-\tstruct ref_store *refs = get_main_ref_store();\n-\n-\treturn refs->be->for_each_reflog_ent(refs, refname, fn, cb_data);\n+\treturn refs_for_each_reflog_ent(get_main_ref_store(),\n+\t\t\t\t\trefname, fn, cb_data);\n }\n \n int reflog_exists(const char *refname)\ndiff --git a/refs.h b/refs.h\nindex 6665e5c57..5c1b99596 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -572,5 +572,8 @@ int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,\n int refs_for_each_tag_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data);\n int refs_for_each_branch_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data);\n int refs_for_each_remote_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data);\n+int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data);\n+int refs_for_each_reflog_ent(struct ref_store *refs, const char *refname,\n+\t\t\t     each_reflog_ent_fn fn, void *cb_data);\n \n #endif /* REFS_H */\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311891","messageId":"20170217141908.18012-12-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH 11/15] revision.c: --all adds HEAD from all worktrees","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:19:04Z","receivedAt":"2017-02-17T14:20:57Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Unless single_worktree is set, --all now adds HEAD from all worktrees.\n\nSince reachable.c code does not use setup_revisions(), we need to call\nother_head_refs_submodule() explicitly there to have the same effect on\n\"git prune\", so that we won't accidentally delete objects needed by some\nother HEADs.\n\nA new FIXME is added because we would need something like\n\n    int refs_other_head_refs(struct ref_store *, each_ref_fn, cb_data);\n\nin addition to other_head_refs() to handle it, which might require\n\n    int get_submodule_worktrees(const char *submodule, int flags);\n\nIt could be a separate topic to reduce the scope of this one.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n reachable.c      |  1 +\n refs.c           | 22 ++++++++++++++++++++++\n refs.h           |  1 +\n revision.c       | 13 +++++++++++++\n submodule.c      |  2 ++\n t/t5304-prune.sh | 12 ++++++++++++\n 6 files changed, 51 insertions(+)\n\ndiff --git a/reachable.c b/reachable.c\nindex d0199cace..61a6ec05c 100644\n--- a/reachable.c\n+++ b/reachable.c\n@@ -177,6 +177,7 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n \n \t/* detached HEAD is not included in the list above */\n \thead_ref(add_one_ref, revs);\n+\tother_head_refs(add_one_ref, revs);\n \n \t/* Add all reflog info */\n \tif (mark_reflog)\ndiff --git a/refs.c b/refs.c\nindex fa2df7a1d..ce165c0ea 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1676,3 +1676,25 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)\n \n \treturn refs->be->rename_ref(refs, oldref, newref, logmsg);\n }\n+\n+int other_head_refs(each_ref_fn fn, void *cb_data)\n+{\n+\tstruct worktree **worktrees, **p;\n+\tint ret = 0;\n+\n+\tworktrees = get_worktrees(0);\n+\tfor (p = worktrees; *p; p++) {\n+\t\tstruct worktree *wt = *p;\n+\t\tstruct ref_store *refs;\n+\n+\t\tif (wt->is_current)\n+\t\t\tcontinue;\n+\n+\t\trefs = get_worktree_ref_store(wt);\n+\t\tret = refs_head_ref(refs, fn, cb_data);\n+\t\tif (ret)\n+\t\t\tbreak;\n+\t}\n+\tfree_worktrees(worktrees);\n+\treturn ret;\n+}\ndiff --git a/refs.h b/refs.h\nindex 986d408bd..6665e5c57 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -190,6 +190,7 @@ typedef int each_ref_fn(const char *refname,\n  * stop the iteration.\n  */\n int head_ref(each_ref_fn fn, void *cb_data);\n+int other_head_refs(each_ref_fn fn, void *cb_data);\n int for_each_ref(each_ref_fn fn, void *cb_data);\n int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data);\n int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data,\ndiff --git a/revision.c b/revision.c\nindex d82c37b44..8ee929cef 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2105,6 +2105,13 @@ static int handle_revision_pseudo_opt(const char *submodule,\n \tint argcount;\n \n \tif (submodule) {\n+\t\t/*\n+\t\t * We need some something like get_submodule_worktrees()\n+\t\t * before we can go through all worktrees of a submodule,\n+\t\t * .e.g with adding all HEADs from --all, which is not\n+\t\t * supported right now, so stick to single worktree.\n+\t\t */\n+\t\tassert(revs->single_worktree != 0);\n \t\trefs = get_submodule_ref_store(submodule);\n \t} else\n \t\trefs = get_main_ref_store();\n@@ -2122,6 +2129,12 @@ static int handle_revision_pseudo_opt(const char *submodule,\n \tif (!strcmp(arg, \"--all\")) {\n \t\thandle_refs(refs, revs, *flags, refs_for_each_ref);\n \t\thandle_refs(refs, revs, *flags, refs_head_ref);\n+\t\tif (!revs->single_worktree) {\n+\t\t\tstruct all_refs_cb cb;\n+\n+\t\t\tinit_all_refs_cb(&cb, revs, *flags);\n+\t\t\tother_head_refs(handle_one_ref, &cb);\n+\t\t}\n \t\tclear_ref_exclusion(&revs->ref_excludes);\n \t} else if (!strcmp(arg, \"--branches\")) {\n \t\thandle_refs(refs, revs, *flags, refs_for_each_branch_ref);\ndiff --git a/submodule.c b/submodule.c\nindex 3ce589d55..aed47baaf 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1155,6 +1155,8 @@ static int find_first_merges(struct object_array *result, const char *path,\n \t\t\toid_to_hex(&a->object.oid));\n \tinit_revisions(&revs, NULL);\n \trev_opts.submodule = path;\n+\t/* FIXME: can't handle linked worktrees in submodules yet */\n+\trevs.single_worktree = path != NULL;\n \tsetup_revisions(ARRAY_SIZE(rev_args)-1, rev_args, &revs, &rev_opts);\n \n \t/* save all revisions from the above list that contain b */\ndiff --git a/t/t5304-prune.sh b/t/t5304-prune.sh\nindex cba45c7be..683bdb031 100755\n--- a/t/t5304-prune.sh\n+++ b/t/t5304-prune.sh\n@@ -292,4 +292,16 @@ test_expect_success 'prune: handle index in multiple worktrees' '\n \ttest_cmp second-worktree/blob actual\n '\n \n+test_expect_success 'prune: handle HEAD in multiple worktrees' '\n+\tgit worktree add --detach third-worktree &&\n+\techo \"new blob for third-worktree\" >third-worktree/blob &&\n+\tgit -C third-worktree add blob &&\n+\tgit -C third-worktree commit -m \"third\" &&\n+\trm .git/worktrees/third-worktree/index &&\n+\ttest_must_fail git -C third-worktree show :blob &&\n+\tgit prune --expire=now &&\n+\tgit -C third-worktree show HEAD:blob >actual &&\n+\ttest_cmp third-worktree/blob actual\n+'\n+\n test_done\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311892","messageId":"20170217141908.18012-14-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH 13/15] files-backend: make reflog iterator go through per-worktree reflog","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:19:06Z","receivedAt":"2017-02-17T14:21:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n refs/files-backend.c | 24 +++++++++++++++++++++++-\n 1 file changed, 23 insertions(+), 1 deletion(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 011a7e256..d429f8713 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -3314,6 +3314,7 @@ struct files_reflog_iterator {\n \tstruct ref_iterator base;\n \n \tstruct dir_iterator *dir_iterator;\n+\tstruct dir_iterator *dir_iterator2;\n \tstruct object_id oid;\n };\n \n@@ -3334,6 +3335,10 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)\n \t\tif (ends_with(diter->basename, \".lock\"))\n \t\t\tcontinue;\n \n+\t\tif (iter->dir_iterator2 &&\n+\t\t    starts_with(diter->relative_path, \"refs/bisect/\"))\n+\t\t\tcontinue;\n+\n \t\tif (read_ref_full(diter->relative_path, 0,\n \t\t\t\t  iter->oid.hash, &flags)) {\n \t\t\terror(\"bad ref for %s\", diter->path.buf);\n@@ -3346,7 +3351,11 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)\n \t\treturn ITER_OK;\n \t}\n \n-\titer->dir_iterator = NULL;\n+\titer->dir_iterator = iter->dir_iterator2;\n+\tif (iter->dir_iterator2) {\n+\t\titer->dir_iterator2 = NULL;\n+\t\treturn files_reflog_iterator_advance(ref_iterator);\n+\t}\n \tif (ref_iterator_abort(ref_iterator) == ITER_ERROR)\n \t\tok = ITER_ERROR;\n \treturn ok;\n@@ -3367,6 +3376,12 @@ static int files_reflog_iterator_abort(struct ref_iterator *ref_iterator)\n \tif (iter->dir_iterator)\n \t\tok = dir_iterator_abort(iter->dir_iterator);\n \n+\tif (iter->dir_iterator2) {\n+\t\tint ok2 = dir_iterator_abort(iter->dir_iterator2);\n+\t\tif (ok2 == ITER_ERROR)\n+\t\t\tok = ok2;\n+\t}\n+\n \tbase_ref_iterator_free(ref_iterator);\n \treturn ok;\n }\n@@ -3389,6 +3404,13 @@ static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_st\n \tfiles_path(refs, &sb, \"logs\");\n \titer->dir_iterator = dir_iterator_begin(sb.buf);\n \tstrbuf_release(&sb);\n+\n+\tif (strcmp(refs->gitdir.buf, refs->gitcommondir.buf)) {\n+\t\tstrbuf_addf(&sb, \"%s/logs\", refs->gitdir.buf);\n+\t\titer->dir_iterator2 = dir_iterator_begin(sb.buf);\n+\t\tstrbuf_release(&sb);\n+\t}\n+\n \treturn ref_iterator;\n }\n \n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311893","messageId":"20170217141908.18012-15-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH 14/15] revision.c: --reflog add HEAD reflog from all worktrees","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:19:07Z","receivedAt":"2017-02-17T14:21:01Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Note that add_other_reflogs_to_pending() is a bit inefficient, since\nit scans reflog for all refs of each worktree, including shared refs,\nso the shared ref's reflog is scanned over and over again.\n\nWe could update refs API to pass \"per-worktree only\" flag to avoid\nthat. But long term we should be able to obtain a \"per-worktree only\"\nref store and would need to revert the changes in reflog iteration\nAPI. So let's just wait until then.\n\nadd_reflogs_to_pending() is called by reachable.c so by default \"git\nprune\" will examine reflog from all worktrees.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n revision.c       | 28 +++++++++++++++++++++++++++-\n t/t5304-prune.sh | 16 ++++++++++++++++\n 2 files changed, 43 insertions(+), 1 deletion(-)\n\ndiff --git a/revision.c b/revision.c\nindex 8ee929cef..ecfd6fea6 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1134,6 +1134,7 @@ struct all_refs_cb {\n \tint warned_bad_reflog;\n \tstruct rev_info *all_revs;\n \tconst char *name_for_errormsg;\n+\tstruct ref_store *refs;\n };\n \n int ref_excluded(struct string_list *ref_excludes, const char *path)\n@@ -1169,6 +1170,7 @@ static void init_all_refs_cb(struct all_refs_cb *cb, struct rev_info *revs,\n {\n \tcb->all_revs = revs;\n \tcb->all_flags = flags;\n+\tcb->refs = NULL;\n }\n \n void clear_ref_exclusion(struct string_list **ref_excludes_p)\n@@ -1237,17 +1239,41 @@ static int handle_one_reflog(const char *path, const struct object_id *oid,\n \tstruct all_refs_cb *cb = cb_data;\n \tcb->warned_bad_reflog = 0;\n \tcb->name_for_errormsg = path;\n-\tfor_each_reflog_ent(path, handle_one_reflog_ent, cb_data);\n+\trefs_for_each_reflog_ent(cb->refs, path,\n+\t\t\t\t handle_one_reflog_ent, cb_data);\n \treturn 0;\n }\n \n+static void add_other_reflogs_to_pending(struct all_refs_cb *cb)\n+{\n+\tstruct worktree **worktrees, **p;\n+\n+\tworktrees = get_worktrees(0);\n+\tfor (p = worktrees; *p; p++) {\n+\t\tstruct worktree *wt = *p;\n+\n+\t\tif (wt->is_current)\n+\t\t\tcontinue;\n+\n+\t\tcb->refs = get_worktree_ref_store(wt);\n+\t\trefs_for_each_reflog(cb->refs,\n+\t\t\t\t     handle_one_reflog,\n+\t\t\t\t     cb);\n+\t}\n+\tfree_worktrees(worktrees);\n+}\n+\n void add_reflogs_to_pending(struct rev_info *revs, unsigned flags)\n {\n \tstruct all_refs_cb cb;\n \n \tcb.all_revs = revs;\n \tcb.all_flags = flags;\n+\tcb.refs = get_main_ref_store();\n \tfor_each_reflog(handle_one_reflog, &cb);\n+\n+\tif (!revs->single_worktree)\n+\t\tadd_other_reflogs_to_pending(&cb);\n }\n \n static void add_cache_tree(struct cache_tree *it, struct rev_info *revs,\ndiff --git a/t/t5304-prune.sh b/t/t5304-prune.sh\nindex 683bdb031..6694c19a1 100755\n--- a/t/t5304-prune.sh\n+++ b/t/t5304-prune.sh\n@@ -304,4 +304,20 @@ test_expect_success 'prune: handle HEAD in multiple worktrees' '\n \ttest_cmp third-worktree/blob actual\n '\n \n+test_expect_success 'prune: handle HEAD reflog in multiple worktrees' '\n+\tgit config core.logAllRefUpdates true &&\n+\techo \"lost blob for third-worktree\" >expected &&\n+\t(\n+\t\tcd third-worktree &&\n+\t\tcat ../expected >blob &&\n+\t\tgit add blob &&\n+\t\tgit commit -m \"second commit in third\" &&\n+\t\tgit reset --hard HEAD^\n+\t) &&\n+\tgit prune --expire=now &&\n+\tSHA1=`git hash-object expected` &&\n+\tgit -C third-worktree show \"$SHA1\" >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311894","messageId":"20170217141908.18012-16-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH 15/15] rev-list: expose and document --single-worktree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-02-17T14:19:08Z","receivedAt":"2017-02-17T14:21:04Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/rev-list-options.txt | 8 ++++++++\n revision.c                         | 2 ++\n 2 files changed, 10 insertions(+)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 5da7cf5a8..dd773f97c 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -179,6 +179,14 @@ explicitly.\n \tPretend as if all objects mentioned by reflogs are listed on the\n \tcommand line as `<commit>`.\n \n+--single-worktree::\n+\tBy default, all working trees will be examined by the\n+\tfollowing options when there are more than one (see\n+\tlinkgit:git-worktree[1]): `--all`, `--reflog` and\n+\t`--indexed-objects`.\n+\tThis option forces them to examine the current working tree\n+\tonly.\n+\n --ignore-missing::\n \tUpon seeing an invalid object name in the input, pretend as if\n \tthe bad input was not given.\ndiff --git a/revision.c b/revision.c\nindex ecfd6fea6..2a27e55fe 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2222,6 +2222,8 @@ static int handle_revision_pseudo_opt(const char *submodule,\n \t\t\treturn error(\"invalid argument to --no-walk\");\n \t} else if (!strcmp(arg, \"--do-walk\")) {\n \t\trevs->no_walk = 0;\n+\t} else if (!strcmp(arg, \"--single-worktree\")) {\n+\t\trevs->single_worktree = 1;\n \t} else {\n \t\treturn 0;\n \t}\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"311909","messageId":"alpine.DEB.2.20.1702171808460.3496@virtualbox","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"Re: [PATCH/RFC 00/15] Fix git-gc losing objects in multi worktree","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2017-02-17T17:09:41Z","receivedAt":"2017-02-17T17:10:07Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Duy,\n\nOn Fri, 17 Feb 2017, Nguyễn Thái Ngọc Duy wrote:\n\n> So here is my latest attempt on fixing this issue. For people who are\n> not aware of it, git-gc does not take per-worktree refs, reflogs and\n> indexes into account. An odb prune may leave HEAD and references in\n> other worktrees pointing to nowhere.\n\nThank you so much for working on this. The bug really affects my daily\nwork very, very negatively.\n\nWill try to review as soon as possible.\n\nCiao,\nDscho"},{"id":"314471","messageId":"20170318101153.6901-1-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170217141908.18012-1-pclouds@gmail.com","subject":"[PATCH v2 00/12] Fix git-gc losing objects in multi worktree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-03-18T10:11:41Z","receivedAt":"2017-03-18T10:12:34Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is basically a rebased version after a lot of changes in\nnd/files-backend-git-dir. Thanks to test-ref-store.c, I found and\nfixed a bug in for_each_reflog in v1 code.\n\nThis series needs latest nd/worktree-kill-parse-ref [1]. But you can\nget everything on my github fork, branch prune-in-worktrees-2.\n\n[1] http://public-inbox.org/git/%3C20170318100206.5980-1-pclouds@gmail.com%3E/\n\nNguyễn Thái Ngọc Duy (12):\n  revision.h: new flag in struct rev_info wrt. worktree-related refs\n  revision.c: refactor add_index_objects_to_pending()\n  revision.c: --indexed-objects add objects from all worktrees\n  refs.c: refactor get_submodule_ref_store(), share common free block\n  refs: move submodule slash stripping code to get_submodule_ref_store\n  refs: add refs_head_ref()\n  revision.c: use refs_for_each*() instead of for_each_*_submodule()\n  refs: remove dead for_each_*_submodule()\n  revision.c: --all adds HEAD from all worktrees\n  files-backend: make reflog iterator go through per-worktree reflog\n  revision.c: --reflog add HEAD reflog from all worktrees\n  rev-list: expose and document --single-worktree\n\n Documentation/rev-list-options.txt |   8 +++\n reachable.c                        |   1 +\n refs.c                             | 110 +++++++++++++++----------------\n refs.h                             |  12 +---\n refs/files-backend.c               |  46 +++++++++----\n revision.c                         | 130 ++++++++++++++++++++++++++++++-------\n revision.h                         |   1 +\n submodule.c                        |   2 +\n t/t1407-worktree-ref-store.sh      |  30 +++++++++\n t/t5304-prune.sh                   |  37 +++++++++++\n 10 files changed, 277 insertions(+), 100 deletions(-)\n\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"314472","messageId":"20170318101153.6901-4-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170318101153.6901-1-pclouds@gmail.com","subject":"[PATCH v2 03/12] revision.c: --indexed-objects add objects from all worktrees","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-03-18T10:11:44Z","receivedAt":"2017-03-18T10:12:40Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is the result of single_worktree flag never being set (no way to up\nuntil now). To get objects from current index only, set single_worktree.\n\nThe other add_index_objects_to_pending's caller is mark_reachable_objects()\n(e.g. \"git prune\") which also mark objects from all indexes.\n---\n revision.c       | 21 +++++++++++++++++++++\n t/t5304-prune.sh |  9 +++++++++\n 2 files changed, 30 insertions(+)\n\ndiff --git a/revision.c b/revision.c\nindex 98146f179f..db8021ed26 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -19,6 +19,7 @@\n #include \"dir.h\"\n #include \"cache-tree.h\"\n #include \"bisect.h\"\n+#include \"worktree.h\"\n \n volatile show_early_output_fn_t show_early_output;\n \n@@ -1291,8 +1292,28 @@ static void do_add_index_objects_to_pending(struct rev_info *revs,\n \n void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)\n {\n+\tstruct worktree **worktrees, **p;\n+\n \tread_cache();\n \tdo_add_index_objects_to_pending(revs, &the_index);\n+\n+\tif (revs->single_worktree)\n+\t\treturn;\n+\n+\tworktrees = get_worktrees(0);\n+\tfor (p = worktrees; *p; p++) {\n+\t\tstruct worktree *wt = *p;\n+\t\tstruct index_state istate = {0};\n+\n+\t\tif (wt->is_current)\n+\t\t\tcontinue; /* current index already taken care of */\n+\n+\t\tif (read_index_from(&istate,\n+\t\t\t\t    worktree_git_path(wt, \"index\")) > 0)\n+\t\t\tdo_add_index_objects_to_pending(revs, &istate);\n+\t\tdiscard_index(&istate);\n+\t}\n+\tfree_worktrees(worktrees);\n }\n \n static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,\ndiff --git a/t/t5304-prune.sh b/t/t5304-prune.sh\nindex 133b5842b1..cba45c7be9 100755\n--- a/t/t5304-prune.sh\n+++ b/t/t5304-prune.sh\n@@ -283,4 +283,13 @@ test_expect_success 'prune: handle alternate object database' '\n \tgit -C B prune\n '\n \n+test_expect_success 'prune: handle index in multiple worktrees' '\n+\tgit worktree add second-worktree &&\n+\techo \"new blob for second-worktree\" >second-worktree/blob &&\n+\tgit -C second-worktree add blob &&\n+\tgit prune --expire=now &&\n+\tgit -C second-worktree show :blob >actual &&\n+\ttest_cmp second-worktree/blob actual\n+'\n+\n test_done\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"314473","messageId":"20170318101153.6901-5-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170318101153.6901-1-pclouds@gmail.com","subject":"[PATCH v2 04/12] refs.c: refactor get_submodule_ref_store(), share common free block","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-03-18T10:11:45Z","receivedAt":"2017-03-18T10:12:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"---\n refs.c | 12 +++++-------\n 1 file changed, 5 insertions(+), 7 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 6695140cfe..8912798c1d 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1571,25 +1571,23 @@ struct ref_store *get_submodule_ref_store(const char *submodule)\n \n \trefs = lookup_submodule_ref_store(submodule);\n \tif (refs)\n-\t\treturn refs;\n+\t\tgoto done;\n \n \tstrbuf_addstr(&submodule_sb, submodule);\n \tret = is_nonbare_repository_dir(&submodule_sb);\n-\tstrbuf_release(&submodule_sb);\n \tif (!ret)\n-\t\treturn NULL;\n+\t\tgoto done;\n \n \tret = submodule_to_gitdir(&submodule_sb, submodule);\n-\tif (ret) {\n-\t\tstrbuf_release(&submodule_sb);\n-\t\treturn NULL;\n-\t}\n+\tif (ret)\n+\t\tgoto done;\n \n \t/* pretend that add_submodule_odb() has been called */\n \trefs = ref_store_init(submodule_sb.buf,\n \t\t\t      REF_STORE_READ | REF_STORE_ODB);\n \tregister_submodule_ref_store(refs, submodule);\n \n+done:\n \tstrbuf_release(&submodule_sb);\n \treturn refs;\n }\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"314474","messageId":"20170318101153.6901-2-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170318101153.6901-1-pclouds@gmail.com","subject":"[PATCH v2 01/12] revision.h: new flag in struct rev_info wrt. worktree-related refs","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-03-18T10:11:42Z","receivedAt":"2017-03-18T10:12:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The revision walker can walk through per-worktree refs like HEAD or\nSHA-1 references in the index. These currently are from the current\nworktree only. This new flag is added to change rev-list behavior in\nthis regard:\n\nWhen single_worktree is set, only current worktree is considered. When\nit is not set (which is the default), all worktrees are considered.\n\nThe default is chosen so because the two big components that rev-list\nworks with are object database (entirely shared between worktrees) and\nrefs (mostly shared). It makes sense that default behavior goes per-repo\ntoo instead of per-worktree.\n\nThe flag will eventually be exposed as a rev-list argument with\ndocuments. For now it stays internal until the new behavior is fully\nimplemented.\n---\n revision.h | 1 +\n 1 file changed, 1 insertion(+)\n\ndiff --git a/revision.h b/revision.h\nindex 9fac1a607d..c851b94ad8 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -88,6 +88,7 @@ struct rev_info {\n \t\t\ttopo_order:1,\n \t\t\tsimplify_merges:1,\n \t\t\tsimplify_by_decoration:1,\n+\t\t\tsingle_worktree:1,\n \t\t\ttag_objects:1,\n \t\t\ttree_objects:1,\n \t\t\tblob_objects:1,\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"314475","messageId":"20170318101153.6901-7-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170318101153.6901-1-pclouds@gmail.com","subject":"[PATCH v2 06/12] refs: add refs_head_ref()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-03-18T10:11:47Z","receivedAt":"2017-03-18T10:12:48Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"---\n refs.c | 19 +++++++++----------\n refs.h |  2 ++\n 2 files changed, 11 insertions(+), 10 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex a38149d84a..5fc47ff5f0 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1208,27 +1208,26 @@ int refs_rename_ref_available(struct ref_store *refs,\n \treturn ok;\n }\n \n-int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n+int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n {\n \tstruct object_id oid;\n \tint flag;\n \n-\tif (submodule) {\n-\t\tif (resolve_gitlink_ref(submodule, \"HEAD\", oid.hash) == 0)\n-\t\t\treturn fn(\"HEAD\", &oid, 0, cb_data);\n-\n-\t\treturn 0;\n-\t}\n-\n-\tif (!read_ref_full(\"HEAD\", RESOLVE_REF_READING, oid.hash, &flag))\n+\tif (!refs_read_ref_full(refs, \"HEAD\", RESOLVE_REF_READING,\n+\t\t\t\toid.hash, &flag))\n \t\treturn fn(\"HEAD\", &oid, flag, cb_data);\n \n \treturn 0;\n }\n \n+int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n+{\n+\treturn refs_head_ref(get_submodule_ref_store(submodule), fn, cb_data);\n+}\n+\n int head_ref(each_ref_fn fn, void *cb_data)\n {\n-\treturn head_ref_submodule(NULL, fn, cb_data);\n+\treturn refs_head_ref(get_main_ref_store(), fn, cb_data);\n }\n \n /*\ndiff --git a/refs.h b/refs.h\nindex 447381d378..0572473ef7 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -233,6 +233,8 @@ typedef int each_ref_fn(const char *refname,\n  * modifies the reference also returns a nonzero value to immediately\n  * stop the iteration. Returned references are sorted.\n  */\n+int refs_head_ref(struct ref_store *refs,\n+\t\t  each_ref_fn fn, void *cb_data);\n int refs_for_each_ref(struct ref_store *refs,\n \t\t      each_ref_fn fn, void *cb_data);\n int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"314476","messageId":"20170318101153.6901-3-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170318101153.6901-1-pclouds@gmail.com","subject":"[PATCH v2 02/12] revision.c: refactor add_index_objects_to_pending()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-03-18T10:11:43Z","receivedAt":"2017-03-18T10:12:50Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The core code is factored out and take 'struct index_state *' instead so\nthat we can reuse it to add objects from index files other than .git/index\nin the next patch.\n---\n revision.c | 18 ++++++++++++------\n 1 file changed, 12 insertions(+), 6 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 7ff61ff5f7..98146f179f 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1263,13 +1263,13 @@ static void add_cache_tree(struct cache_tree *it, struct rev_info *revs,\n \n }\n \n-void add_index_objects_to_pending(struct rev_info *revs, unsigned flags)\n+static void do_add_index_objects_to_pending(struct rev_info *revs,\n+\t\t\t\t\t    struct index_state *istate)\n {\n \tint i;\n \n-\tread_cache();\n-\tfor (i = 0; i < active_nr; i++) {\n-\t\tstruct cache_entry *ce = active_cache[i];\n+\tfor (i = 0; i < istate->cache_nr; i++) {\n+\t\tstruct cache_entry *ce = istate->cache[i];\n \t\tstruct blob *blob;\n \n \t\tif (S_ISGITLINK(ce->ce_mode))\n@@ -1282,13 +1282,19 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned flags)\n \t\t\t\t\t     ce->ce_mode, ce->name);\n \t}\n \n-\tif (active_cache_tree) {\n+\tif (istate->cache_tree) {\n \t\tstruct strbuf path = STRBUF_INIT;\n-\t\tadd_cache_tree(active_cache_tree, revs, &path);\n+\t\tadd_cache_tree(istate->cache_tree, revs, &path);\n \t\tstrbuf_release(&path);\n \t}\n }\n \n+void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)\n+{\n+\tread_cache();\n+\tdo_add_index_objects_to_pending(revs, &the_index);\n+}\n+\n static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,\n \t\t\t    int exclude_parent)\n {\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"314477","messageId":"20170318101153.6901-6-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170318101153.6901-1-pclouds@gmail.com","subject":"[PATCH v2 05/12] refs: move submodule slash stripping code to get_submodule_ref_store","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-03-18T10:11:46Z","receivedAt":"2017-03-18T10:13:13Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is a better place that will benefit all submodule callers instead\nof just resolve_gitlink_ref()\n---\n refs.c | 33 +++++++++++++++++----------------\n 1 file changed, 17 insertions(+), 16 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 8912798c1d..a38149d84a 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1422,25 +1422,10 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,\n int resolve_gitlink_ref(const char *submodule, const char *refname,\n \t\t\tunsigned char *sha1)\n {\n-\tsize_t len = strlen(submodule);\n \tstruct ref_store *refs;\n \tint flags;\n \n-\twhile (len && submodule[len - 1] == '/')\n-\t\tlen--;\n-\n-\tif (!len)\n-\t\treturn -1;\n-\n-\tif (submodule[len]) {\n-\t\t/* We need to strip off one or more trailing slashes */\n-\t\tchar *stripped = xmemdupz(submodule, len);\n-\n-\t\trefs = get_submodule_ref_store(stripped);\n-\t\tfree(stripped);\n-\t} else {\n-\t\trefs = get_submodule_ref_store(submodule);\n-\t}\n+\trefs = get_submodule_ref_store(submodule);\n \n \tif (!refs)\n \t\treturn -1;\n@@ -1559,7 +1544,17 @@ struct ref_store *get_submodule_ref_store(const char *submodule)\n {\n \tstruct strbuf submodule_sb = STRBUF_INIT;\n \tstruct ref_store *refs;\n+\tchar *to_free = NULL;\n \tint ret;\n+\tsize_t len;\n+\n+\tif (submodule) {\n+\t\tlen = strlen(submodule);\n+\t\twhile (len && submodule[len - 1] == '/')\n+\t\t\tlen--;\n+\t\tif (!len)\n+\t\t\tsubmodule = NULL;\n+\t}\n \n \tif (!submodule || !*submodule) {\n \t\t/*\n@@ -1569,6 +1564,10 @@ struct ref_store *get_submodule_ref_store(const char *submodule)\n \t\treturn get_main_ref_store();\n \t}\n \n+\tif (submodule[len])\n+\t\t/* We need to strip off one or more trailing slashes */\n+\t\tsubmodule = to_free = xmemdupz(submodule, len);\n+\n \trefs = lookup_submodule_ref_store(submodule);\n \tif (refs)\n \t\tgoto done;\n@@ -1589,6 +1588,8 @@ struct ref_store *get_submodule_ref_store(const char *submodule)\n \n done:\n \tstrbuf_release(&submodule_sb);\n+\tfree(to_free);\n+\n \treturn refs;\n }\n \n-- \n2.11.0.157.gd943d85\n\n"},{"id":"314478","messageId":"20170318101153.6901-13-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170318101153.6901-1-pclouds@gmail.com","subject":"[PATCH v2 12/12] rev-list: expose and document --single-worktree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-03-18T10:11:53Z","receivedAt":"2017-03-18T10:14:19Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"---\n Documentation/rev-list-options.txt | 8 ++++++++\n revision.c                         | 2 ++\n 2 files changed, 10 insertions(+)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex a02f7324c0..c71e94b2d0 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -179,6 +179,14 @@ explicitly.\n \tPretend as if all objects mentioned by reflogs are listed on the\n \tcommand line as `<commit>`.\n \n+--single-worktree::\n+\tBy default, all working trees will be examined by the\n+\tfollowing options when there are more than one (see\n+\tlinkgit:git-worktree[1]): `--all`, `--reflog` and\n+\t`--indexed-objects`.\n+\tThis option forces them to examine the current working tree\n+\tonly.\n+\n --ignore-missing::\n \tUpon seeing an invalid object name in the input, pretend as if\n \tthe bad input was not given.\ndiff --git a/revision.c b/revision.c\nindex fcf165bd76..dc32e99c54 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2222,6 +2222,8 @@ static int handle_revision_pseudo_opt(const char *submodule,\n \t\t\treturn error(\"invalid argument to --no-walk\");\n \t} else if (!strcmp(arg, \"--do-walk\")) {\n \t\trevs->no_walk = 0;\n+\t} else if (!strcmp(arg, \"--single-worktree\")) {\n+\t\trevs->single_worktree = 1;\n \t} else {\n \t\treturn 0;\n \t}\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"314479","messageId":"20170318101153.6901-11-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170318101153.6901-1-pclouds@gmail.com","subject":"[PATCH v2 10/12] files-backend: make reflog iterator go through per-worktree reflog","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-03-18T10:11:51Z","receivedAt":"2017-03-18T10:14:21Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"refs/bisect is unfortunately per-worktree, so we need to look in\nper-worktree logs/refs/bisect in addition to per-repo logs/refs. The\ncurrent iterator only goes through per-repo logs/refs.\n\nIdeally we should have something like merge_ref_iterator_begin (and\nmaybe with a predicate), but for dir_iterator. Since there's only one\nuse case for this pattern, let's not add a bunch more code for\nmerge_dir_iterator_begin just yet.\n\nPS. Note the unsorted order of for_each_reflog in the test. This is\nsupposed to be OK, for now. If we enforce order on for_each_reflog()\nthen some more work will be required.\n---\n refs/files-backend.c          | 46 ++++++++++++++++++++++++++++++++-----------\n t/t1407-worktree-ref-store.sh | 30 ++++++++++++++++++++++++++++\n 2 files changed, 65 insertions(+), 11 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 62d8e0713a..0f423be185 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -1172,15 +1172,6 @@ static void files_reflog_path(struct files_ref_store *refs,\n \t\t\t      struct strbuf *sb,\n \t\t\t      const char *refname)\n {\n-\tif (!refname) {\n-\t\t/*\n-\t\t * FIXME: of course this is wrong in multi worktree\n-\t\t * setting. To be fixed real soon.\n-\t\t */\n-\t\tstrbuf_addf(sb, \"%s/logs\", refs->gitcommondir);\n-\t\treturn;\n-\t}\n-\n \tswitch (ref_type(refname)) {\n \tcase REF_TYPE_PER_WORKTREE:\n \tcase REF_TYPE_PSEUDOREF:\n@@ -3371,6 +3362,7 @@ struct files_reflog_iterator {\n \n \tstruct ref_store *ref_store;\n \tstruct dir_iterator *dir_iterator;\n+\tstruct dir_iterator *worktree_dir_iterator;\n \tstruct object_id oid;\n };\n \n@@ -3391,6 +3383,21 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)\n \t\tif (ends_with(diter->basename, \".lock\"))\n \t\t\tcontinue;\n \n+\t\tif (iter->worktree_dir_iterator) {\n+\t\t\tconst char *refname = diter->relative_path;\n+\n+\t\t\tswitch (ref_type(refname)) {\n+\t\t\tcase REF_TYPE_PER_WORKTREE:\n+\t\t\tcase REF_TYPE_PSEUDOREF:\n+\t\t\t\tcontinue;\n+\t\t\tcase REF_TYPE_NORMAL:\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tdie(\"BUG: unknown ref type %d of ref %s\",\n+\t\t\t\t    ref_type(refname), refname);\n+\t\t\t}\n+\t\t}\n+\n \t\tif (refs_read_ref_full(iter->ref_store,\n \t\t\t\t       diter->relative_path, 0,\n \t\t\t\t       iter->oid.hash, &flags)) {\n@@ -3404,7 +3411,11 @@ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)\n \t\treturn ITER_OK;\n \t}\n \n-\titer->dir_iterator = NULL;\n+\titer->dir_iterator = iter->worktree_dir_iterator;\n+\tif (iter->worktree_dir_iterator) {\n+\t\titer->worktree_dir_iterator = NULL;\n+\t\treturn files_reflog_iterator_advance(ref_iterator);\n+\t}\n \tif (ref_iterator_abort(ref_iterator) == ITER_ERROR)\n \t\tok = ITER_ERROR;\n \treturn ok;\n@@ -3425,6 +3436,12 @@ static int files_reflog_iterator_abort(struct ref_iterator *ref_iterator)\n \tif (iter->dir_iterator)\n \t\tok = dir_iterator_abort(iter->dir_iterator);\n \n+\tif (iter->worktree_dir_iterator) {\n+\t\tint ok2 = dir_iterator_abort(iter->worktree_dir_iterator);\n+\t\tif (ok2 == ITER_ERROR)\n+\t\t\tok = ok2;\n+\t}\n+\n \tbase_ref_iterator_free(ref_iterator);\n \treturn ok;\n }\n@@ -3445,10 +3462,17 @@ static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_st\n \tstruct strbuf sb = STRBUF_INIT;\n \n \tbase_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable);\n-\tfiles_reflog_path(refs, &sb, NULL);\n+\tstrbuf_addf(&sb, \"%s/logs\", refs->gitcommondir);\n \titer->dir_iterator = dir_iterator_begin(sb.buf);\n \titer->ref_store = ref_store;\n \tstrbuf_release(&sb);\n+\n+\tif (strcmp(refs->gitdir, refs->gitcommondir)) {\n+\t\tstrbuf_addf(&sb, \"%s/logs\", refs->gitdir);\n+\t\titer->worktree_dir_iterator = dir_iterator_begin(sb.buf);\n+\t\tstrbuf_release(&sb);\n+\t}\n+\n \treturn ref_iterator;\n }\n \ndiff --git a/t/t1407-worktree-ref-store.sh b/t/t1407-worktree-ref-store.sh\nindex 5df06f3556..8842d0329f 100755\n--- a/t/t1407-worktree-ref-store.sh\n+++ b/t/t1407-worktree-ref-store.sh\n@@ -49,4 +49,34 @@ test_expect_success 'create_symref(FOO, refs/heads/master)' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'for_each_reflog()' '\n+\techo $_z40 > .git/logs/PSEUDO-MAIN &&\n+\tmkdir -p     .git/logs/refs/bisect &&\n+\techo $_z40 > .git/logs/refs/bisect/random &&\n+\n+\techo $_z40 > .git/worktrees/wt/logs/PSEUDO-WT &&\n+\tmkdir -p     .git/worktrees/wt/logs/refs/bisect &&\n+\techo $_z40 > .git/worktrees/wt/logs/refs/bisect/wt-random &&\n+\n+\t$RWT for-each-reflog | cut -c 42- | sort >actual &&\n+\tcat >expected <<-\\EOF &&\n+\tHEAD 0x1\n+\tPSEUDO-WT 0x0\n+\trefs/bisect/wt-random 0x0\n+\trefs/heads/master 0x0\n+\trefs/heads/wt-master 0x0\n+\tEOF\n+\ttest_cmp expected actual &&\n+\n+\t$RMAIN for-each-reflog | cut -c 42- | sort >actual &&\n+\tcat >expected <<-\\EOF &&\n+\tHEAD 0x1\n+\tPSEUDO-MAIN 0x0\n+\trefs/bisect/random 0x0\n+\trefs/heads/master 0x0\n+\trefs/heads/wt-master 0x0\n+\tEOF\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"314480","messageId":"20170318101153.6901-10-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170318101153.6901-1-pclouds@gmail.com","subject":"[PATCH v2 09/12] revision.c: --all adds HEAD from all worktrees","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-03-18T10:11:50Z","receivedAt":"2017-03-18T10:14:22Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Unless single_worktree is set, --all now adds HEAD from all worktrees.\n\nSince reachable.c code does not use setup_revisions(), we need to call\nother_head_refs_submodule() explicitly there to have the same effect on\n\"git prune\", so that we won't accidentally delete objects needed by some\nother HEADs.\n\nA new FIXME is added because we would need something like\n\n    int refs_other_head_refs(struct ref_store *, each_ref_fn, cb_data);\n\nin addition to other_head_refs() to handle it, which might require\n\n    int get_submodule_worktrees(const char *submodule, int flags);\n\nIt could be a separate topic to reduce the scope of this one.\n---\n reachable.c      |  1 +\n refs.c           | 22 ++++++++++++++++++++++\n refs.h           |  1 +\n revision.c       | 13 +++++++++++++\n submodule.c      |  2 ++\n t/t5304-prune.sh | 12 ++++++++++++\n 6 files changed, 51 insertions(+)\n\ndiff --git a/reachable.c b/reachable.c\nindex a8a979bd4f..a3b938b46c 100644\n--- a/reachable.c\n+++ b/reachable.c\n@@ -177,6 +177,7 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog,\n \n \t/* detached HEAD is not included in the list above */\n \thead_ref(add_one_ref, revs);\n+\tother_head_refs(add_one_ref, revs);\n \n \t/* Add all reflog info */\n \tif (mark_reflog)\ndiff --git a/refs.c b/refs.c\nindex 1f2f870084..6006d4fdbc 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1787,3 +1787,25 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)\n {\n \treturn refs_rename_ref(get_main_ref_store(), oldref, newref, logmsg);\n }\n+\n+int other_head_refs(each_ref_fn fn, void *cb_data)\n+{\n+\tstruct worktree **worktrees, **p;\n+\tint ret = 0;\n+\n+\tworktrees = get_worktrees(0);\n+\tfor (p = worktrees; *p; p++) {\n+\t\tstruct worktree *wt = *p;\n+\t\tstruct ref_store *refs;\n+\n+\t\tif (wt->is_current)\n+\t\t\tcontinue;\n+\n+\t\trefs = get_worktree_ref_store(wt);\n+\t\tret = refs_head_ref(refs, fn, cb_data);\n+\t\tif (ret)\n+\t\t\tbreak;\n+\t}\n+\tfree_worktrees(worktrees);\n+\treturn ret;\n+}\ndiff --git a/refs.h b/refs.h\nindex e06db37118..cc71b6c7a0 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -247,6 +247,7 @@ int refs_for_each_remote_ref(struct ref_store *refs,\n \t\t\t     each_ref_fn fn, void *cb_data);\n \n int head_ref(each_ref_fn fn, void *cb_data);\n+int other_head_refs(each_ref_fn fn, void *cb_data);\n int for_each_ref(each_ref_fn fn, void *cb_data);\n int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data);\n int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data,\ndiff --git a/revision.c b/revision.c\nindex da19071960..e5d2913b5c 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2105,6 +2105,13 @@ static int handle_revision_pseudo_opt(const char *submodule,\n \tint argcount;\n \n \tif (submodule) {\n+\t\t/*\n+\t\t * We need some something like get_submodule_worktrees()\n+\t\t * before we can go through all worktrees of a submodule,\n+\t\t * .e.g with adding all HEADs from --all, which is not\n+\t\t * supported right now, so stick to single worktree.\n+\t\t */\n+\t\tassert(revs->single_worktree != 0);\n \t\trefs = get_submodule_ref_store(submodule);\n \t} else\n \t\trefs = get_main_ref_store();\n@@ -2122,6 +2129,12 @@ static int handle_revision_pseudo_opt(const char *submodule,\n \tif (!strcmp(arg, \"--all\")) {\n \t\thandle_refs(refs, revs, *flags, refs_for_each_ref);\n \t\thandle_refs(refs, revs, *flags, refs_head_ref);\n+\t\tif (!revs->single_worktree) {\n+\t\t\tstruct all_refs_cb cb;\n+\n+\t\t\tinit_all_refs_cb(&cb, revs, *flags);\n+\t\t\tother_head_refs(handle_one_ref, &cb);\n+\t\t}\n \t\tclear_ref_exclusion(&revs->ref_excludes);\n \t} else if (!strcmp(arg, \"--branches\")) {\n \t\thandle_refs(refs, revs, *flags, refs_for_each_branch_ref);\ndiff --git a/submodule.c b/submodule.c\nindex 3c445f274e..63a190f0f6 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -1225,6 +1225,8 @@ static int find_first_merges(struct object_array *result, const char *path,\n \t\t\toid_to_hex(&a->object.oid));\n \tinit_revisions(&revs, NULL);\n \trev_opts.submodule = path;\n+\t/* FIXME: can't handle linked worktrees in submodules yet */\n+\trevs.single_worktree = path != NULL;\n \tsetup_revisions(ARRAY_SIZE(rev_args)-1, rev_args, &revs, &rev_opts);\n \n \t/* save all revisions from the above list that contain b */\ndiff --git a/t/t5304-prune.sh b/t/t5304-prune.sh\nindex cba45c7be9..683bdb031c 100755\n--- a/t/t5304-prune.sh\n+++ b/t/t5304-prune.sh\n@@ -292,4 +292,16 @@ test_expect_success 'prune: handle index in multiple worktrees' '\n \ttest_cmp second-worktree/blob actual\n '\n \n+test_expect_success 'prune: handle HEAD in multiple worktrees' '\n+\tgit worktree add --detach third-worktree &&\n+\techo \"new blob for third-worktree\" >third-worktree/blob &&\n+\tgit -C third-worktree add blob &&\n+\tgit -C third-worktree commit -m \"third\" &&\n+\trm .git/worktrees/third-worktree/index &&\n+\ttest_must_fail git -C third-worktree show :blob &&\n+\tgit prune --expire=now &&\n+\tgit -C third-worktree show HEAD:blob >actual &&\n+\ttest_cmp third-worktree/blob actual\n+'\n+\n test_done\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"314481","messageId":"20170318101153.6901-12-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170318101153.6901-1-pclouds@gmail.com","subject":"[PATCH v2 11/12] revision.c: --reflog add HEAD reflog from all worktrees","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-03-18T10:11:52Z","receivedAt":"2017-03-18T10:14:26Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Note that add_other_reflogs_to_pending() is a bit inefficient, since\nit scans reflog for all refs of each worktree, including shared refs,\nso the shared ref's reflog is scanned over and over again.\n\nWe could update refs API to pass \"per-worktree only\" flag to avoid\nthat. But long term we should be able to obtain a \"per-worktree only\"\nref store and would need to revert the changes in reflog iteration\nAPI. So let's just wait until then.\n\nadd_reflogs_to_pending() is called by reachable.c so by default \"git\nprune\" will examine reflog from all worktrees.\n---\n revision.c       | 28 +++++++++++++++++++++++++++-\n t/t5304-prune.sh | 16 ++++++++++++++++\n 2 files changed, 43 insertions(+), 1 deletion(-)\n\ndiff --git a/revision.c b/revision.c\nindex e5d2913b5c..fcf165bd76 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1134,6 +1134,7 @@ struct all_refs_cb {\n \tint warned_bad_reflog;\n \tstruct rev_info *all_revs;\n \tconst char *name_for_errormsg;\n+\tstruct ref_store *refs;\n };\n \n int ref_excluded(struct string_list *ref_excludes, const char *path)\n@@ -1169,6 +1170,7 @@ static void init_all_refs_cb(struct all_refs_cb *cb, struct rev_info *revs,\n {\n \tcb->all_revs = revs;\n \tcb->all_flags = flags;\n+\tcb->refs = NULL;\n }\n \n void clear_ref_exclusion(struct string_list **ref_excludes_p)\n@@ -1237,17 +1239,41 @@ static int handle_one_reflog(const char *path, const struct object_id *oid,\n \tstruct all_refs_cb *cb = cb_data;\n \tcb->warned_bad_reflog = 0;\n \tcb->name_for_errormsg = path;\n-\tfor_each_reflog_ent(path, handle_one_reflog_ent, cb_data);\n+\trefs_for_each_reflog_ent(cb->refs, path,\n+\t\t\t\t handle_one_reflog_ent, cb_data);\n \treturn 0;\n }\n \n+static void add_other_reflogs_to_pending(struct all_refs_cb *cb)\n+{\n+\tstruct worktree **worktrees, **p;\n+\n+\tworktrees = get_worktrees(0);\n+\tfor (p = worktrees; *p; p++) {\n+\t\tstruct worktree *wt = *p;\n+\n+\t\tif (wt->is_current)\n+\t\t\tcontinue;\n+\n+\t\tcb->refs = get_worktree_ref_store(wt);\n+\t\trefs_for_each_reflog(cb->refs,\n+\t\t\t\t     handle_one_reflog,\n+\t\t\t\t     cb);\n+\t}\n+\tfree_worktrees(worktrees);\n+}\n+\n void add_reflogs_to_pending(struct rev_info *revs, unsigned flags)\n {\n \tstruct all_refs_cb cb;\n \n \tcb.all_revs = revs;\n \tcb.all_flags = flags;\n+\tcb.refs = get_main_ref_store();\n \tfor_each_reflog(handle_one_reflog, &cb);\n+\n+\tif (!revs->single_worktree)\n+\t\tadd_other_reflogs_to_pending(&cb);\n }\n \n static void add_cache_tree(struct cache_tree *it, struct rev_info *revs,\ndiff --git a/t/t5304-prune.sh b/t/t5304-prune.sh\nindex 683bdb031c..6694c19a1e 100755\n--- a/t/t5304-prune.sh\n+++ b/t/t5304-prune.sh\n@@ -304,4 +304,20 @@ test_expect_success 'prune: handle HEAD in multiple worktrees' '\n \ttest_cmp third-worktree/blob actual\n '\n \n+test_expect_success 'prune: handle HEAD reflog in multiple worktrees' '\n+\tgit config core.logAllRefUpdates true &&\n+\techo \"lost blob for third-worktree\" >expected &&\n+\t(\n+\t\tcd third-worktree &&\n+\t\tcat ../expected >blob &&\n+\t\tgit add blob &&\n+\t\tgit commit -m \"second commit in third\" &&\n+\t\tgit reset --hard HEAD^\n+\t) &&\n+\tgit prune --expire=now &&\n+\tSHA1=`git hash-object expected` &&\n+\tgit -C third-worktree show \"$SHA1\" >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"314482","messageId":"20170318101153.6901-9-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170318101153.6901-1-pclouds@gmail.com","subject":"[PATCH v2 08/12] refs: remove dead for_each_*_submodule()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-03-18T10:11:49Z","receivedAt":"2017-03-18T10:22:07Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"These are used in revision.c. After the last patch they are replaced\nwith the refs_ version. Delete them (except for_each_remote_ref_submodule\nwhich is still used by submodule.c)\n---\n refs.c | 24 ------------------------\n refs.h |  9 ---------\n 2 files changed, 33 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 5fc47ff5f0..1f2f870084 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -316,12 +316,6 @@ int for_each_tag_ref(each_ref_fn fn, void *cb_data)\n \treturn refs_for_each_tag_ref(get_main_ref_store(), fn, cb_data);\n }\n \n-int for_each_tag_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n-{\n-\treturn refs_for_each_tag_ref(get_submodule_ref_store(submodule),\n-\t\t\t\t     fn, cb_data);\n-}\n-\n int refs_for_each_branch_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n {\n \treturn refs_for_each_ref_in(refs, \"refs/heads/\", fn, cb_data);\n@@ -332,12 +326,6 @@ int for_each_branch_ref(each_ref_fn fn, void *cb_data)\n \treturn refs_for_each_branch_ref(get_main_ref_store(), fn, cb_data);\n }\n \n-int for_each_branch_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n-{\n-\treturn refs_for_each_branch_ref(get_submodule_ref_store(submodule),\n-\t\t\t\t\tfn, cb_data);\n-}\n-\n int refs_for_each_remote_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n {\n \treturn refs_for_each_ref_in(refs, \"refs/remotes/\", fn, cb_data);\n@@ -1263,11 +1251,6 @@ int for_each_ref(each_ref_fn fn, void *cb_data)\n \treturn refs_for_each_ref(get_main_ref_store(), fn, cb_data);\n }\n \n-int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n-{\n-\treturn refs_for_each_ref(get_submodule_ref_store(submodule), fn, cb_data);\n-}\n-\n int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,\n \t\t\t each_ref_fn fn, void *cb_data)\n {\n@@ -1289,13 +1272,6 @@ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsig\n \t\t\t       prefix, fn, 0, flag, cb_data);\n }\n \n-int for_each_ref_in_submodule(const char *submodule, const char *prefix,\n-\t\t\t      each_ref_fn fn, void *cb_data)\n-{\n-\treturn refs_for_each_ref_in(get_submodule_ref_store(submodule),\n-\t\t\t\t    prefix, fn, cb_data);\n-}\n-\n int for_each_replace_ref(each_ref_fn fn, void *cb_data)\n {\n \treturn do_for_each_ref(get_main_ref_store(),\ndiff --git a/refs.h b/refs.h\nindex 0572473ef7..e06db37118 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -259,15 +259,6 @@ int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);\n int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,\n \t\t\t const char *prefix, void *cb_data);\n \n-int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);\n-int for_each_ref_submodule(const char *submodule,\n-\t\t\t   each_ref_fn fn, void *cb_data);\n-int for_each_ref_in_submodule(const char *submodule, const char *prefix,\n-\t\teach_ref_fn fn, void *cb_data);\n-int for_each_tag_ref_submodule(const char *submodule,\n-\t\t\t       each_ref_fn fn, void *cb_data);\n-int for_each_branch_ref_submodule(const char *submodule,\n-\t\t\t\t  each_ref_fn fn, void *cb_data);\n int for_each_remote_ref_submodule(const char *submodule,\n \t\t\t\t  each_ref_fn fn, void *cb_data);\n \n-- \n2.11.0.157.gd943d85\n\n"},{"id":"314492","messageId":"20170318101153.6901-8-pclouds@gmail.com","threadId":"45162","inReplyTo":"20170318101153.6901-1-pclouds@gmail.com","subject":"[PATCH v2 07/12] revision.c: use refs_for_each*() instead of for_each_*_submodule()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2017-03-18T10:11:48Z","receivedAt":"2017-03-18T10:43:22Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"---\n revision.c | 48 ++++++++++++++++++++++++++++++++----------------\n 1 file changed, 32 insertions(+), 16 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex db8021ed26..da19071960 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1189,12 +1189,19 @@ void add_ref_exclusion(struct string_list **ref_excludes_p, const char *exclude)\n \tstring_list_append(*ref_excludes_p, exclude);\n }\n \n-static void handle_refs(const char *submodule, struct rev_info *revs, unsigned flags,\n-\t\tint (*for_each)(const char *, each_ref_fn, void *))\n+static void handle_refs(struct ref_store *refs,\n+\t\t\tstruct rev_info *revs, unsigned flags,\n+\t\t\tint (*for_each)(struct ref_store *, each_ref_fn, void *))\n {\n \tstruct all_refs_cb cb;\n+\n+\tif (!refs) {\n+\t\t/* this could happen with uninitialized submodules */\n+\t\treturn;\n+\t}\n+\n \tinit_all_refs_cb(&cb, revs, flags);\n-\tfor_each(submodule, handle_one_ref, &cb);\n+\tfor_each(refs, handle_one_ref, &cb);\n }\n \n static void handle_one_reflog_commit(struct object_id *oid, void *cb_data)\n@@ -2067,23 +2074,25 @@ void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,\n \tctx->argc -= n;\n }\n \n-static int for_each_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data, const char *term) {\n+static int for_each_bisect_ref(struct ref_store *refs, each_ref_fn fn,\n+\t\t\t       void *cb_data, const char *term)\n+{\n \tstruct strbuf bisect_refs = STRBUF_INIT;\n \tint status;\n \tstrbuf_addf(&bisect_refs, \"refs/bisect/%s\", term);\n-\tstatus = for_each_ref_in_submodule(submodule, bisect_refs.buf, fn, cb_data);\n+\tstatus = refs_for_each_ref_in(refs, bisect_refs.buf, fn, cb_data);\n \tstrbuf_release(&bisect_refs);\n \treturn status;\n }\n \n-static int for_each_bad_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data)\n+static int for_each_bad_bisect_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n {\n-\treturn for_each_bisect_ref(submodule, fn, cb_data, term_bad);\n+\treturn for_each_bisect_ref(refs, fn, cb_data, term_bad);\n }\n \n-static int for_each_good_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data)\n+static int for_each_good_bisect_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)\n {\n-\treturn for_each_bisect_ref(submodule, fn, cb_data, term_good);\n+\treturn for_each_bisect_ref(refs, fn, cb_data, term_good);\n }\n \n static int handle_revision_pseudo_opt(const char *submodule,\n@@ -2092,8 +2101,14 @@ static int handle_revision_pseudo_opt(const char *submodule,\n {\n \tconst char *arg = argv[0];\n \tconst char *optarg;\n+\tstruct ref_store *refs;\n \tint argcount;\n \n+\tif (submodule) {\n+\t\trefs = get_submodule_ref_store(submodule);\n+\t} else\n+\t\trefs = get_main_ref_store();\n+\n \t/*\n \t * NOTE!\n \t *\n@@ -2105,22 +2120,23 @@ static int handle_revision_pseudo_opt(const char *submodule,\n \t * register it in the list at the top of handle_revision_opt.\n \t */\n \tif (!strcmp(arg, \"--all\")) {\n-\t\thandle_refs(submodule, revs, *flags, for_each_ref_submodule);\n-\t\thandle_refs(submodule, revs, *flags, head_ref_submodule);\n+\t\thandle_refs(refs, revs, *flags, refs_for_each_ref);\n+\t\thandle_refs(refs, revs, *flags, refs_head_ref);\n \t\tclear_ref_exclusion(&revs->ref_excludes);\n \t} else if (!strcmp(arg, \"--branches\")) {\n-\t\thandle_refs(submodule, revs, *flags, for_each_branch_ref_submodule);\n+\t\thandle_refs(refs, revs, *flags, refs_for_each_branch_ref);\n \t\tclear_ref_exclusion(&revs->ref_excludes);\n \t} else if (!strcmp(arg, \"--bisect\")) {\n \t\tread_bisect_terms(&term_bad, &term_good);\n-\t\thandle_refs(submodule, revs, *flags, for_each_bad_bisect_ref);\n-\t\thandle_refs(submodule, revs, *flags ^ (UNINTERESTING | BOTTOM), for_each_good_bisect_ref);\n+\t\thandle_refs(refs, revs, *flags, for_each_bad_bisect_ref);\n+\t\thandle_refs(refs, revs, *flags ^ (UNINTERESTING | BOTTOM),\n+\t\t\t    for_each_good_bisect_ref);\n \t\trevs->bisect = 1;\n \t} else if (!strcmp(arg, \"--tags\")) {\n-\t\thandle_refs(submodule, revs, *flags, for_each_tag_ref_submodule);\n+\t\thandle_refs(refs, revs, *flags, refs_for_each_tag_ref);\n \t\tclear_ref_exclusion(&revs->ref_excludes);\n \t} else if (!strcmp(arg, \"--remotes\")) {\n-\t\thandle_refs(submodule, revs, *flags, for_each_remote_ref_submodule);\n+\t\thandle_refs(refs, revs, *flags, refs_for_each_remote_ref);\n \t\tclear_ref_exclusion(&revs->ref_excludes);\n \t} else if ((argcount = parse_long_opt(\"glob\", argv, &optarg))) {\n \t\tstruct all_refs_cb cb;\n-- \n2.11.0.157.gd943d85\n\n"},{"id":"314516","messageId":"xmqq4lyq4g92.fsf@gitster.mtv.corp.google.com","threadId":"45162","inReplyTo":"20170318101153.6901-13-pclouds@gmail.com","subject":"Re: [PATCH v2 12/12] rev-list: expose and document --single-worktree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-18T18:00:25Z","receivedAt":"2017-03-18T18:00:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> ---\n\nMissing sign-off.\n\n>  Documentation/rev-list-options.txt | 8 ++++++++\n>  revision.c                         | 2 ++\n>  2 files changed, 10 insertions(+)\n>\n> diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\n> index a02f7324c0..c71e94b2d0 100644\n> --- a/Documentation/rev-list-options.txt\n> +++ b/Documentation/rev-list-options.txt\n> @@ -179,6 +179,14 @@ explicitly.\n>  \tPretend as if all objects mentioned by reflogs are listed on the\n>  \tcommand line as `<commit>`.\n>  \n> +--single-worktree::\n> +\tBy default, all working trees will be examined by the\n\ns/working tree/worktree/?\n\n> +\tfollowing options when there are more than one (see\n> +\tlinkgit:git-worktree[1]): `--all`, `--reflog` and\n> +\t`--indexed-objects`.\n> +\tThis option forces them to examine the current working tree\n> +\tonly.\n> +\n>  --ignore-missing::\n>  \tUpon seeing an invalid object name in the input, pretend as if\n>  \tthe bad input was not given.\n> diff --git a/revision.c b/revision.c\n> index fcf165bd76..dc32e99c54 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -2222,6 +2222,8 @@ static int handle_revision_pseudo_opt(const char *submodule,\n>  \t\t\treturn error(\"invalid argument to --no-walk\");\n>  \t} else if (!strcmp(arg, \"--do-walk\")) {\n>  \t\trevs->no_walk = 0;\n> +\t} else if (!strcmp(arg, \"--single-worktree\")) {\n> +\t\trevs->single_worktree = 1;\n>  \t} else {\n>  \t\treturn 0;\n>  \t}\n"},{"id":"317210","messageId":"CACsJy8B5r9qPd9iNZnX4KG_-1WdL+LF+bSOy-zZnwiryQqRWKQ@mail.gmail.com","threadId":"45162","inReplyTo":"xmqq4lyq4g92.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 12/12] rev-list: expose and document --single-worktree","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2017-04-19T10:52:36Z","receivedAt":"2017-04-19T10:53:12Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Mar 19, 2017 at 1:00 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\n>> index a02f7324c0..c71e94b2d0 100644\n>> --- a/Documentation/rev-list-options.txt\n>> +++ b/Documentation/rev-list-options.txt\n>> @@ -179,6 +179,14 @@ explicitly.\n>>       Pretend as if all objects mentioned by reflogs are listed on the\n>>       command line as `<commit>`.\n>>\n>> +--single-worktree::\n>> +     By default, all working trees will be examined by the\n>\n> s/working tree/worktree/?\n\nNope. It's the \"working tree\" that we consistently use throughout\ngit-worktree.txt\n-- \nDuy\n"},{"id":"317305","messageId":"xmqqshl3akfm.fsf@gitster.mtv.corp.google.com","threadId":"45162","inReplyTo":"CACsJy8B5r9qPd9iNZnX4KG_-1WdL+LF+bSOy-zZnwiryQqRWKQ@mail.gmail.com","subject":"Re: [PATCH v2 12/12] rev-list: expose and document --single-worktree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-04-20T02:21:01Z","receivedAt":"2017-04-20T02:21:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> On Sun, Mar 19, 2017 at 1:00 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>>> diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\n>>> index a02f7324c0..c71e94b2d0 100644\n>>> --- a/Documentation/rev-list-options.txt\n>>> +++ b/Documentation/rev-list-options.txt\n>>> @@ -179,6 +179,14 @@ explicitly.\n>>>       Pretend as if all objects mentioned by reflogs are listed on the\n>>>       command line as `<commit>`.\n>>>\n>>> +--single-worktree::\n>>> +     By default, all working trees will be examined by the\n>>\n>> s/working tree/worktree/?\n>\n> Nope. It's the \"working tree\" that we consistently use throughout\n> git-worktree.txt\n\nOK.\n"}]}