Skip to content

Commit 7c78d81

Browse files
shejialuogitster
authored andcommitted
ref: support multiple worktrees check for refs
We have already set up the infrastructure to check the consistency for refs, but we do not support multiple worktrees. However, "git-fsck(1)" will check the refs of worktrees. As we decide to get feature parity with "git-fsck(1)", we need to set up support for multiple worktrees. Because each worktree has its own specific refs, instead of just showing the users "refs/worktree/foo", we need to display the full name such as "worktrees/<id>/refs/worktree/foo". So we should know the id of the worktree to get the full name. Add a new parameter "struct worktree *" for "refs-internal.h::fsck_fn". Then change the related functions to follow this new interface. The "packed-refs" only exists in the main worktree, so we should only check "packed-refs" in the main worktree. Use "is_main_worktree" method to skip checking "packed-refs" in "packed_fsck" function. Then, enhance the "files-backend.c::files_fsck_refs_dir" function to add "worktree/<id>/" prefix when we are not in the main worktree. Last, add a new test to check the refname when there are multiple worktrees to exercise the code. Mentored-by: Patrick Steinhardt <[email protected]> Mentored-by: Karthik Nayak <[email protected]> Signed-off-by: shejialuo <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 56ca603 commit 7c78d81

File tree

9 files changed

+90
-15
lines changed

9 files changed

+90
-15
lines changed

builtin/refs.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "parse-options.h"
66
#include "refs.h"
77
#include "strbuf.h"
8+
#include "worktree.h"
89

910
#define REFS_MIGRATE_USAGE \
1011
N_("git refs migrate --ref-format=<format> [--dry-run]")
@@ -66,6 +67,7 @@ static int cmd_refs_migrate(int argc, const char **argv, const char *prefix)
6667
static int cmd_refs_verify(int argc, const char **argv, const char *prefix)
6768
{
6869
struct fsck_options fsck_refs_options = FSCK_REFS_OPTIONS_DEFAULT;
70+
struct worktree **worktrees;
6971
const char * const verify_usage[] = {
7072
REFS_VERIFY_USAGE,
7173
NULL,
@@ -75,7 +77,7 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix)
7577
OPT_BOOL(0, "strict", &fsck_refs_options.strict, N_("enable strict checking")),
7678
OPT_END(),
7779
};
78-
int ret;
80+
int ret = 0;
7981

8082
argc = parse_options(argc, argv, prefix, options, verify_usage, 0);
8183
if (argc)
@@ -84,9 +86,13 @@ static int cmd_refs_verify(int argc, const char **argv, const char *prefix)
8486
git_config(git_fsck_config, &fsck_refs_options);
8587
prepare_repo_settings(the_repository);
8688

87-
ret = refs_fsck(get_main_ref_store(the_repository), &fsck_refs_options);
89+
worktrees = get_worktrees();
90+
for (size_t i = 0; worktrees[i]; i++)
91+
ret |= refs_fsck(get_worktree_ref_store(worktrees[i]),
92+
&fsck_refs_options, worktrees[i]);
8893

8994
fsck_options_clear(&fsck_refs_options);
95+
free_worktrees(worktrees);
9096
return ret;
9197
}
9298

refs.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,9 +318,10 @@ int check_refname_format(const char *refname, int flags)
318318
return check_or_sanitize_refname(refname, flags, NULL);
319319
}
320320

321-
int refs_fsck(struct ref_store *refs, struct fsck_options *o)
321+
int refs_fsck(struct ref_store *refs, struct fsck_options *o,
322+
struct worktree *wt)
322323
{
323-
return refs->be->fsck(refs, o);
324+
return refs->be->fsck(refs, o, wt);
324325
}
325326

326327
void sanitize_refname_component(const char *refname, struct strbuf *out)

refs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,8 @@ int check_refname_format(const char *refname, int flags);
549549
* reflogs are consistent, and non-zero otherwise. The errors will be
550550
* written to stderr.
551551
*/
552-
int refs_fsck(struct ref_store *refs, struct fsck_options *o);
552+
int refs_fsck(struct ref_store *refs, struct fsck_options *o,
553+
struct worktree *wt);
553554

554555
/*
555556
* Apply the rules from check_refname_format, but mutate the result until it

refs/debug.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -420,10 +420,11 @@ static int debug_reflog_expire(struct ref_store *ref_store, const char *refname,
420420
}
421421

422422
static int debug_fsck(struct ref_store *ref_store,
423-
struct fsck_options *o)
423+
struct fsck_options *o,
424+
struct worktree *wt)
424425
{
425426
struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
426-
int res = drefs->refs->be->fsck(drefs->refs, o);
427+
int res = drefs->refs->be->fsck(drefs->refs, o, wt);
427428
trace_printf_key(&trace_refs, "fsck: %d\n", res);
428429
return res;
429430
}

refs/files-backend.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "../dir.h"
2424
#include "../chdir-notify.h"
2525
#include "../setup.h"
26+
#include "../worktree.h"
2627
#include "../wrapper.h"
2728
#include "../write-or-die.h"
2829
#include "../revision.h"
@@ -3539,6 +3540,7 @@ static int files_fsck_refs_name(struct ref_store *ref_store UNUSED,
35393540
static int files_fsck_refs_dir(struct ref_store *ref_store,
35403541
struct fsck_options *o,
35413542
const char *refs_check_dir,
3543+
struct worktree *wt,
35423544
files_fsck_refs_fn *fsck_refs_fn)
35433545
{
35443546
struct strbuf refname = STRBUF_INIT;
@@ -3561,6 +3563,9 @@ static int files_fsck_refs_dir(struct ref_store *ref_store,
35613563
} else if (S_ISREG(iter->st.st_mode) ||
35623564
S_ISLNK(iter->st.st_mode)) {
35633565
strbuf_reset(&refname);
3566+
3567+
if (!is_main_worktree(wt))
3568+
strbuf_addf(&refname, "worktrees/%s/", wt->id);
35643569
strbuf_addf(&refname, "%s/%s", refs_check_dir,
35653570
iter->relative_path);
35663571

@@ -3590,7 +3595,8 @@ static int files_fsck_refs_dir(struct ref_store *ref_store,
35903595
}
35913596

35923597
static int files_fsck_refs(struct ref_store *ref_store,
3593-
struct fsck_options *o)
3598+
struct fsck_options *o,
3599+
struct worktree *wt)
35943600
{
35953601
files_fsck_refs_fn fsck_refs_fn[]= {
35963602
files_fsck_refs_name,
@@ -3599,17 +3605,18 @@ static int files_fsck_refs(struct ref_store *ref_store,
35993605

36003606
if (o->verbose)
36013607
fprintf_ln(stderr, _("Checking references consistency"));
3602-
return files_fsck_refs_dir(ref_store, o, "refs", fsck_refs_fn);
3608+
return files_fsck_refs_dir(ref_store, o, "refs", wt, fsck_refs_fn);
36033609
}
36043610

36053611
static int files_fsck(struct ref_store *ref_store,
3606-
struct fsck_options *o)
3612+
struct fsck_options *o,
3613+
struct worktree *wt)
36073614
{
36083615
struct files_ref_store *refs =
36093616
files_downcast(ref_store, REF_STORE_READ, "fsck");
36103617

3611-
return files_fsck_refs(ref_store, o) |
3612-
refs->packed_ref_store->be->fsck(refs->packed_ref_store, o);
3618+
return files_fsck_refs(ref_store, o, wt) |
3619+
refs->packed_ref_store->be->fsck(refs->packed_ref_store, o, wt);
36133620
}
36143621

36153622
struct ref_storage_be refs_be_files = {

refs/packed-backend.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "../lockfile.h"
1414
#include "../chdir-notify.h"
1515
#include "../statinfo.h"
16+
#include "../worktree.h"
1617
#include "../wrapper.h"
1718
#include "../write-or-die.h"
1819
#include "../trace2.h"
@@ -1754,8 +1755,13 @@ static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_s
17541755
}
17551756

17561757
static int packed_fsck(struct ref_store *ref_store UNUSED,
1757-
struct fsck_options *o UNUSED)
1758+
struct fsck_options *o UNUSED,
1759+
struct worktree *wt)
17581760
{
1761+
1762+
if (!is_main_worktree(wt))
1763+
return 0;
1764+
17591765
return 0;
17601766
}
17611767

refs/refs-internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,8 @@ typedef int read_symbolic_ref_fn(struct ref_store *ref_store, const char *refnam
653653
struct strbuf *referent);
654654

655655
typedef int fsck_fn(struct ref_store *ref_store,
656-
struct fsck_options *o);
656+
struct fsck_options *o,
657+
struct worktree *wt);
657658

658659
struct ref_storage_be {
659660
const char *name;

refs/reftable-backend.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2475,7 +2475,8 @@ static int reftable_be_reflog_expire(struct ref_store *ref_store,
24752475
}
24762476

24772477
static int reftable_be_fsck(struct ref_store *ref_store UNUSED,
2478-
struct fsck_options *o UNUSED)
2478+
struct fsck_options *o UNUSED,
2479+
struct worktree *wt UNUSED)
24792480
{
24802481
return 0;
24812482
}

t/t0602-reffiles-fsck.sh

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,55 @@ test_expect_success 'ref name check should be adapted into fsck messages' '
107107
test_must_be_empty err
108108
'
109109

110+
test_expect_success 'ref name check should work for multiple worktrees' '
111+
test_when_finished "rm -rf repo" &&
112+
git init repo &&
113+
114+
cd repo &&
115+
test_commit initial &&
116+
git checkout -b branch-1 &&
117+
test_commit second &&
118+
git checkout -b branch-2 &&
119+
test_commit third &&
120+
git checkout -b branch-3 &&
121+
git worktree add ./worktree-1 branch-1 &&
122+
git worktree add ./worktree-2 branch-2 &&
123+
worktree1_refdir_prefix=.git/worktrees/worktree-1/refs/worktree &&
124+
worktree2_refdir_prefix=.git/worktrees/worktree-2/refs/worktree &&
125+
126+
(
127+
cd worktree-1 &&
128+
git update-ref refs/worktree/branch-4 refs/heads/branch-3
129+
) &&
130+
(
131+
cd worktree-2 &&
132+
git update-ref refs/worktree/branch-4 refs/heads/branch-3
133+
) &&
134+
135+
cp $worktree1_refdir_prefix/branch-4 $worktree1_refdir_prefix/'\'' branch-5'\'' &&
136+
cp $worktree2_refdir_prefix/branch-4 $worktree2_refdir_prefix/'\''~branch-6'\'' &&
137+
138+
test_must_fail git refs verify 2>err &&
139+
cat >expect <<-EOF &&
140+
error: worktrees/worktree-1/refs/worktree/ branch-5: badRefName: invalid refname format
141+
error: worktrees/worktree-2/refs/worktree/~branch-6: badRefName: invalid refname format
142+
EOF
143+
sort err >sorted_err &&
144+
test_cmp expect sorted_err &&
145+
146+
for worktree in "worktree-1" "worktree-2"
147+
do
148+
(
149+
cd $worktree &&
150+
test_must_fail git refs verify 2>err &&
151+
cat >expect <<-EOF &&
152+
error: worktrees/worktree-1/refs/worktree/ branch-5: badRefName: invalid refname format
153+
error: worktrees/worktree-2/refs/worktree/~branch-6: badRefName: invalid refname format
154+
EOF
155+
sort err >sorted_err &&
156+
test_cmp expect sorted_err || return 1
157+
)
158+
done
159+
'
160+
110161
test_done

0 commit comments

Comments
 (0)