Skip to content

Commit d0c39a4

Browse files
pcloudsgitster
authored andcommitted
revision.c: --all adds HEAD from all worktrees
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>
1 parent 419221c commit d0c39a4

6 files changed

Lines changed: 60 additions & 0 deletions

File tree

reachable.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "cache-tree.h"
1010
#include "progress.h"
1111
#include "list-objects.h"
12+
#include "worktree.h"
1213

1314
struct connectivity_progress {
1415
struct progress *progress;
@@ -176,6 +177,7 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog,
176177

177178
/* detached HEAD is not included in the list above */
178179
head_ref(add_one_ref, revs);
180+
other_head_refs(add_one_ref, revs);
179181

180182
/* Add all reflog info */
181183
if (mark_reflog)

revision.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2133,6 +2133,14 @@ static int handle_revision_pseudo_opt(const char *submodule,
21332133
int argcount;
21342134

21352135
if (submodule) {
2136+
/*
2137+
* We need some something like get_submodule_worktrees()
2138+
* before we can go through all worktrees of a submodule,
2139+
* .e.g with adding all HEADs from --all, which is not
2140+
* supported right now, so stick to single worktree.
2141+
*/
2142+
if (!revs->single_worktree)
2143+
die("BUG: --single-worktree cannot be used together with submodule");
21362144
refs = get_submodule_ref_store(submodule);
21372145
} else
21382146
refs = get_main_ref_store();
@@ -2150,6 +2158,12 @@ static int handle_revision_pseudo_opt(const char *submodule,
21502158
if (!strcmp(arg, "--all")) {
21512159
handle_refs(refs, revs, *flags, refs_for_each_ref);
21522160
handle_refs(refs, revs, *flags, refs_head_ref);
2161+
if (!revs->single_worktree) {
2162+
struct all_refs_cb cb;
2163+
2164+
init_all_refs_cb(&cb, revs, *flags);
2165+
other_head_refs(handle_one_ref, &cb);
2166+
}
21532167
clear_ref_exclusion(&revs->ref_excludes);
21542168
} else if (!strcmp(arg, "--branches")) {
21552169
handle_refs(refs, revs, *flags, refs_for_each_branch_ref);

submodule.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,6 +1685,8 @@ static int find_first_merges(struct object_array *result, const char *path,
16851685
oid_to_hex(&a->object.oid));
16861686
init_revisions(&revs, NULL);
16871687
rev_opts.submodule = path;
1688+
/* FIXME: can't handle linked worktrees in submodules yet */
1689+
revs.single_worktree = path != NULL;
16881690
setup_revisions(ARRAY_SIZE(rev_args)-1, rev_args, &revs, &rev_opts);
16891691

16901692
/* save all revisions from the above list that contain b */

t/t5304-prune.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,4 +292,16 @@ test_expect_success 'prune: handle index in multiple worktrees' '
292292
test_cmp second-worktree/blob actual
293293
'
294294

295+
test_expect_success 'prune: handle HEAD in multiple worktrees' '
296+
git worktree add --detach third-worktree &&
297+
echo "new blob for third-worktree" >third-worktree/blob &&
298+
git -C third-worktree add blob &&
299+
git -C third-worktree commit -m "third" &&
300+
rm .git/worktrees/third-worktree/index &&
301+
test_must_fail git -C third-worktree show :blob &&
302+
git prune --expire=now &&
303+
git -C third-worktree show HEAD:blob >actual &&
304+
test_cmp third-worktree/blob actual
305+
'
306+
295307
test_done

worktree.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,3 +386,25 @@ int submodule_uses_worktrees(const char *path)
386386
closedir(dir);
387387
return ret;
388388
}
389+
390+
int other_head_refs(each_ref_fn fn, void *cb_data)
391+
{
392+
struct worktree **worktrees, **p;
393+
int ret = 0;
394+
395+
worktrees = get_worktrees(0);
396+
for (p = worktrees; *p; p++) {
397+
struct worktree *wt = *p;
398+
struct ref_store *refs;
399+
400+
if (wt->is_current)
401+
continue;
402+
403+
refs = get_worktree_ref_store(wt);
404+
ret = refs_head_ref(refs, fn, cb_data);
405+
if (ret)
406+
break;
407+
}
408+
free_worktrees(worktrees);
409+
return ret;
410+
}

worktree.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#ifndef WORKTREE_H
22
#define WORKTREE_H
33

4+
#include "refs.h"
5+
46
struct worktree {
57
char *path;
68
char *id;
@@ -70,6 +72,12 @@ extern void free_worktrees(struct worktree **);
7072
extern const struct worktree *find_shared_symref(const char *symref,
7173
const char *target);
7274

75+
/*
76+
* Similar to head_ref() for all HEADs _except_ one from the current
77+
* worktree, which is covered by head_ref().
78+
*/
79+
int other_head_refs(each_ref_fn fn, void *cb_data);
80+
7381
int is_worktree_being_rebased(const struct worktree *wt, const char *target);
7482
int is_worktree_being_bisected(const struct worktree *wt, const char *target);
7583

0 commit comments

Comments
 (0)