Unless single_worktree is set, --all now adds HEAD from all worktrees.
Since reachable.c code does not use setup_revisions(), we need to call
other_head_refs_submodule() explicitly there to have the same effect on
"git prune", so that we won't accidentally delete objects needed by some
other HEADs.
A new FIXME is added because we would need something like
int refs_other_head_refs(struct ref_store *, each_ref_fn, cb_data);
in addition to other_head_refs() to handle it, which might require
int get_submodule_worktrees(const char *submodule, int flags);
It could be a separate topic to reduce the scope of this one.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
#include "cache-tree.h"
#include "progress.h"
#include "list-objects.h"
+#include "worktree.h"
struct connectivity_progress {
struct progress *progress;
/* detached HEAD is not included in the list above */
head_ref(add_one_ref, revs);
+ other_head_refs(add_one_ref, revs);
/* Add all reflog info */
if (mark_reflog)
int argcount;
if (submodule) {
+ /*
+ * We need some something like get_submodule_worktrees()
+ * before we can go through all worktrees of a submodule,
+ * .e.g with adding all HEADs from --all, which is not
+ * supported right now, so stick to single worktree.
+ */
+ if (!revs->single_worktree)
+ die("BUG: --single-worktree cannot be used together with submodule");
refs = get_submodule_ref_store(submodule);
} else
refs = get_main_ref_store();
if (!strcmp(arg, "--all")) {
handle_refs(refs, revs, *flags, refs_for_each_ref);
handle_refs(refs, revs, *flags, refs_head_ref);
+ if (!revs->single_worktree) {
+ struct all_refs_cb cb;
+
+ init_all_refs_cb(&cb, revs, *flags);
+ other_head_refs(handle_one_ref, &cb);
+ }
clear_ref_exclusion(&revs->ref_excludes);
} else if (!strcmp(arg, "--branches")) {
handle_refs(refs, revs, *flags, refs_for_each_branch_ref);
oid_to_hex(&a->object.oid));
init_revisions(&revs, NULL);
rev_opts.submodule = path;
+ /* FIXME: can't handle linked worktrees in submodules yet */
+ revs.single_worktree = path != NULL;
setup_revisions(ARRAY_SIZE(rev_args)-1, rev_args, &revs, &rev_opts);
/* save all revisions from the above list that contain b */
test_cmp second-worktree/blob actual
'
+test_expect_success 'prune: handle HEAD in multiple worktrees' '
+ git worktree add --detach third-worktree &&
+ echo "new blob for third-worktree" >third-worktree/blob &&
+ git -C third-worktree add blob &&
+ git -C third-worktree commit -m "third" &&
+ rm .git/worktrees/third-worktree/index &&
+ test_must_fail git -C third-worktree show :blob &&
+ git prune --expire=now &&
+ git -C third-worktree show HEAD:blob >actual &&
+ test_cmp third-worktree/blob actual
+'
+
test_done
closedir(dir);
return ret;
}
+
+int other_head_refs(each_ref_fn fn, void *cb_data)
+{
+ struct worktree **worktrees, **p;
+ int ret = 0;
+
+ worktrees = get_worktrees(0);
+ for (p = worktrees; *p; p++) {
+ struct worktree *wt = *p;
+ struct ref_store *refs;
+
+ if (wt->is_current)
+ continue;
+
+ refs = get_worktree_ref_store(wt);
+ ret = refs_head_ref(refs, fn, cb_data);
+ if (ret)
+ break;
+ }
+ free_worktrees(worktrees);
+ return ret;
+}
#ifndef WORKTREE_H
#define WORKTREE_H
+#include "refs.h"
+
struct worktree {
char *path;
char *id;
extern const struct worktree *find_shared_symref(const char *symref,
const char *target);
+/*
+ * Similar to head_ref() for all HEADs _except_ one from the current
+ * worktree, which is covered by head_ref().
+ */
+int other_head_refs(each_ref_fn fn, void *cb_data);
+
int is_worktree_being_rebased(const struct worktree *wt, const char *target);
int is_worktree_being_bisected(const struct worktree *wt, const char *target);