Skip to content

Commit 8e08668

Browse files
committed
Merge branch 'cw/worktree-relative'
An extra worktree attached to a repository points at each other to allow finding the repository from the worktree and vice versa possible. Turn this linkage to relative paths. * cw/worktree-relative: worktree: add test for path handling in linked worktrees worktree: link worktrees with relative paths worktree: refactor infer_backlink() to use *strbuf worktree: repair copied repository and linked worktrees
2 parents 6ca9a05 + 08830ac commit 8e08668

File tree

8 files changed

+312
-64
lines changed

8 files changed

+312
-64
lines changed

Documentation/git-worktree.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ will reestablish the connection. If multiple linked worktrees are moved,
157157
running `repair` from any worktree with each tree's new `<path>` as an
158158
argument, will reestablish the connection to all the specified paths.
159159
+
160-
If both the main worktree and linked worktrees have been moved manually,
160+
If both the main worktree and linked worktrees have been moved or copied manually,
161161
then running `repair` in the main worktree and specifying the new `<path>`
162162
of each linked worktree will reestablish all connections in both
163163
directions.

builtin/worktree.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,8 @@ static int add_worktree(const char *path, const char *refname,
414414
const struct add_opts *opts)
415415
{
416416
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
417-
struct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT;
417+
struct strbuf sb = STRBUF_INIT, sb_tmp = STRBUF_INIT;
418+
struct strbuf sb_path_realpath = STRBUF_INIT, sb_repo_realpath = STRBUF_INIT;
418419
const char *name;
419420
struct strvec child_env = STRVEC_INIT;
420421
unsigned int counter = 0;
@@ -490,11 +491,10 @@ static int add_worktree(const char *path, const char *refname,
490491

491492
strbuf_reset(&sb);
492493
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
493-
strbuf_realpath(&realpath, sb_git.buf, 1);
494-
write_file(sb.buf, "%s", realpath.buf);
495-
strbuf_realpath(&realpath, repo_get_common_dir(the_repository), 1);
496-
write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
497-
realpath.buf, name);
494+
strbuf_realpath(&sb_path_realpath, path, 1);
495+
strbuf_realpath(&sb_repo_realpath, sb_repo.buf, 1);
496+
write_file(sb.buf, "%s/.git", relative_path(sb_path_realpath.buf, sb_repo_realpath.buf, &sb_tmp));
497+
write_file(sb_git.buf, "gitdir: %s", relative_path(sb_repo_realpath.buf, sb_path_realpath.buf, &sb_tmp));
498498
strbuf_reset(&sb);
499499
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
500500
write_file(sb.buf, "../..");
@@ -578,11 +578,13 @@ static int add_worktree(const char *path, const char *refname,
578578

579579
strvec_clear(&child_env);
580580
strbuf_release(&sb);
581+
strbuf_release(&sb_tmp);
581582
strbuf_release(&symref);
582583
strbuf_release(&sb_repo);
584+
strbuf_release(&sb_repo_realpath);
583585
strbuf_release(&sb_git);
586+
strbuf_release(&sb_path_realpath);
584587
strbuf_release(&sb_name);
585-
strbuf_release(&realpath);
586588
free_worktree(wt);
587589
return ret;
588590
}

setup.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2420,7 +2420,7 @@ static void separate_git_dir(const char *git_dir, const char *git_link)
24202420

24212421
if (rename(src, git_dir))
24222422
die_errno(_("unable to move %s to %s"), src, git_dir);
2423-
repair_worktrees(NULL, NULL);
2423+
repair_worktrees_after_gitdir_move(src);
24242424
}
24252425

24262426
write_file(git_link, "gitdir: %s", git_dir);

t/t2401-worktree-prune.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,23 @@ test_expect_success 'prune duplicate (main/linked)' '
120120
! test -d .git/worktrees/wt
121121
'
122122

123+
test_expect_success 'not prune proper worktrees when run inside linked worktree' '
124+
test_when_finished rm -rf repo wt_ext &&
125+
git init repo &&
126+
(
127+
cd repo &&
128+
echo content >file &&
129+
git add file &&
130+
git commit -m msg &&
131+
git worktree add ../wt_ext &&
132+
git worktree add wt_int &&
133+
cd wt_int &&
134+
git worktree prune -v >out &&
135+
test_must_be_empty out &&
136+
cd ../../wt_ext &&
137+
git worktree prune -v >out &&
138+
test_must_be_empty out
139+
)
140+
'
141+
123142
test_done

t/t2406-worktree-repair.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,4 +197,23 @@ test_expect_success 'repair moved main and linked worktrees' '
197197
test_cmp expect-gitfile sidemoved/.git
198198
'
199199

200+
test_expect_success 'repair copied main and linked worktrees' '
201+
test_when_finished "rm -rf orig dup" &&
202+
mkdir -p orig &&
203+
git -C orig init main &&
204+
test_commit -C orig/main nothing &&
205+
git -C orig/main worktree add ../linked &&
206+
cp orig/main/.git/worktrees/linked/gitdir orig/main.expect &&
207+
cp orig/linked/.git orig/linked.expect &&
208+
cp -R orig dup &&
209+
sed "s,orig/linked/\.git$,dup/linked/.git," orig/main.expect >dup/main.expect &&
210+
sed "s,orig/main/\.git/worktrees/linked$,dup/main/.git/worktrees/linked," \
211+
orig/linked.expect >dup/linked.expect &&
212+
git -C dup/main worktree repair ../linked &&
213+
test_cmp orig/main.expect orig/main/.git/worktrees/linked/gitdir &&
214+
test_cmp orig/linked.expect orig/linked/.git &&
215+
test_cmp dup/main.expect dup/main/.git/worktrees/linked/gitdir &&
216+
test_cmp dup/linked.expect dup/linked/.git
217+
'
218+
200219
test_done

t/t2408-worktree-relative.sh

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/bin/sh
2+
3+
test_description='test worktrees linked with relative paths'
4+
5+
TEST_PASSES_SANITIZE_LEAK=true
6+
. ./test-lib.sh
7+
8+
test_expect_success 'links worktrees with relative paths' '
9+
test_when_finished rm -rf repo &&
10+
git init repo &&
11+
(
12+
cd repo &&
13+
test_commit initial &&
14+
git worktree add wt1 &&
15+
echo "../../../wt1/.git" >expected_gitdir &&
16+
cat .git/worktrees/wt1/gitdir >actual_gitdir &&
17+
echo "gitdir: ../.git/worktrees/wt1" >expected_git &&
18+
cat wt1/.git >actual_git &&
19+
test_cmp expected_gitdir actual_gitdir &&
20+
test_cmp expected_git actual_git
21+
)
22+
'
23+
24+
test_expect_success 'move repo without breaking relative internal links' '
25+
test_when_finished rm -rf repo moved &&
26+
git init repo &&
27+
(
28+
cd repo &&
29+
test_commit initial &&
30+
git worktree add wt1 &&
31+
cd .. &&
32+
mv repo moved &&
33+
cd moved/wt1 &&
34+
git status >out 2>err &&
35+
test_must_be_empty err
36+
)
37+
'
38+
39+
test_done

0 commit comments

Comments
 (0)