{"thread":{"id":"40755","subject":"[RFD/WIP PATCH] rev-list: list all heads with --all","startedAt":"2015-11-09T15:24:11Z","lastAt":"2015-11-09T15:24:11Z","messageCount":1,"participants":["Michael J Gruber"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"273079","messageId":"c224529fd3d2651baa0f9232a842e4ae7dd788cb.1447082178.git.git@drmicha.warpmail.net","threadId":"40755","inReplyTo":null,"subject":"[RFD/WIP PATCH] rev-list: list all heads with --all","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2015-11-09T15:24:11Z","receivedAt":"2015-11-09T15:24:11Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"HEAD is a worktree specific sysmref, so that a repository with multiple\nworktrees can have multiple HEADs, or HEADs in a worktree different from\nthe current worktree.\n\nSo far, \"rev-parse --all\" adds only the HEAD from the current worktree\nto the list of refs (besides branches etc.). So, a detached HEAD from a\ndifferent checkout would be missed unless a shared ref (or current HEAD)\npoints to it (or descents from it). As a consequence, \"git prune\" can\nprune detached HEADs from worktrees and leave the repo in an\ninconsistent state.\n\nMake \"rev-parse --all\" add the HEADs from all worktrees. This results in\na non-worktree-specific ref list amd solves the pruning problem.\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\n\nThis patch solves the pruning problem with worktrees, but I feel quite\nuneasy about substituting the ref solving at the very heart of refs.c. So\nplease consider this a mere poc and a request for discussion/input\nabout how to do this the right way.\n\nI'll cook up a test in proper form, but all you have to do is \"worktree\nadd --detach new\" and build a new commit on top of the detached head in\nthe new worktree. Compare \"git prune -n\" in \"new\" and the main worktree...\n\nIn essence, I feel the worktree interface still has to evolve a bit: I'd\nrather for_each_worktree than loop myself, and if many call sites need to\nbe aware of multiple heads or worktrees than get_worktrees() should be\npart of our init stuff, not here.\n\n refs.c | 21 ++++++++++++++-------\n 1 file changed, 14 insertions(+), 7 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex bab92d7..c355171 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -5,6 +5,7 @@\n #include \"tag.h\"\n #include \"dir.h\"\n #include \"string-list.h\"\n+#include \"worktree.h\"\n \n struct ref_lock {\n \tchar *ref_name;\n@@ -2091,10 +2092,11 @@ static int do_for_each_ref(struct ref_cache *refs, const char *base,\n \treturn do_for_each_entry(refs, base, do_one_ref, &data);\n }\n \n-static int do_head_ref(const char *submodule, each_ref_fn fn, void *cb_data)\n+static int do_head_refs(const char *submodule, each_ref_fn fn, void *cb_data)\n {\n \tstruct object_id oid;\n-\tint flag;\n+\tstruct worktree **worktrees;\n+\tint i, retval;\n \n \tif (submodule) {\n \t\tif (resolve_gitlink_ref(submodule, \"HEAD\", oid.hash) == 0)\n@@ -2103,20 +2105,25 @@ static int do_head_ref(const char *submodule, each_ref_fn fn, void *cb_data)\n \t\treturn 0;\n \t}\n \n-\tif (!read_ref_full(\"HEAD\", RESOLVE_REF_READING, oid.hash, &flag))\n-\t\treturn fn(\"HEAD\", &oid, flag, cb_data);\n+\tworktrees = get_worktrees();\n+\tretval = 0;\n+\tfor (i=0; worktrees[i]; i++) {\n+\t\thashcpy(oid.hash, worktrees[i]->head_sha1);\n+\t\tretval = retval || fn(\"HEAD\", &oid, worktrees[i]->is_detached ? 0 : REF_ISSYMREF, cb_data);\n+\t}\n \n-\treturn 0;\n+\tfree_worktrees(worktrees);\n+\treturn retval;\n }\n \n int head_ref(each_ref_fn fn, void *cb_data)\n {\n-\treturn do_head_ref(NULL, fn, cb_data);\n+\treturn do_head_refs(NULL, fn, cb_data);\n }\n \n int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)\n {\n-\treturn do_head_ref(submodule, fn, cb_data);\n+\treturn do_head_refs(submodule, fn, cb_data);\n }\n \n int for_each_ref(each_ref_fn fn, void *cb_data)\n-- \n2.6.3.507.gca54332\n"}]}