Skip to content

Commit

Permalink
Merge branch 'cw/worktree-relative'
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ttaylorr committed Oct 22, 2024
2 parents 6ca9a05 + 08830ac commit 8e08668
Show file tree
Hide file tree
Showing 8 changed files with 312 additions and 64 deletions.
2 changes: 1 addition & 1 deletion Documentation/git-worktree.txt
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ will reestablish the connection. If multiple linked worktrees are moved,
running `repair` from any worktree with each tree's new `<path>` as an
argument, will reestablish the connection to all the specified paths.
+
If both the main worktree and linked worktrees have been moved manually,
If both the main worktree and linked worktrees have been moved or copied manually,
then running `repair` in the main worktree and specifying the new `<path>`
of each linked worktree will reestablish all connections in both
directions.
Expand Down
16 changes: 9 additions & 7 deletions builtin/worktree.c
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,8 @@ static int add_worktree(const char *path, const char *refname,
const struct add_opts *opts)
{
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
struct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT;
struct strbuf sb = STRBUF_INIT, sb_tmp = STRBUF_INIT;
struct strbuf sb_path_realpath = STRBUF_INIT, sb_repo_realpath = STRBUF_INIT;
const char *name;
struct strvec child_env = STRVEC_INIT;
unsigned int counter = 0;
Expand Down Expand Up @@ -490,11 +491,10 @@ static int add_worktree(const char *path, const char *refname,

strbuf_reset(&sb);
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
strbuf_realpath(&realpath, sb_git.buf, 1);
write_file(sb.buf, "%s", realpath.buf);
strbuf_realpath(&realpath, repo_get_common_dir(the_repository), 1);
write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
realpath.buf, name);
strbuf_realpath(&sb_path_realpath, path, 1);
strbuf_realpath(&sb_repo_realpath, sb_repo.buf, 1);
write_file(sb.buf, "%s/.git", relative_path(sb_path_realpath.buf, sb_repo_realpath.buf, &sb_tmp));
write_file(sb_git.buf, "gitdir: %s", relative_path(sb_repo_realpath.buf, sb_path_realpath.buf, &sb_tmp));
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
Expand Down Expand Up @@ -578,11 +578,13 @@ static int add_worktree(const char *path, const char *refname,

strvec_clear(&child_env);
strbuf_release(&sb);
strbuf_release(&sb_tmp);
strbuf_release(&symref);
strbuf_release(&sb_repo);
strbuf_release(&sb_repo_realpath);
strbuf_release(&sb_git);
strbuf_release(&sb_path_realpath);
strbuf_release(&sb_name);
strbuf_release(&realpath);
free_worktree(wt);
return ret;
}
Expand Down
2 changes: 1 addition & 1 deletion setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -2420,7 +2420,7 @@ static void separate_git_dir(const char *git_dir, const char *git_link)

if (rename(src, git_dir))
die_errno(_("unable to move %s to %s"), src, git_dir);
repair_worktrees(NULL, NULL);
repair_worktrees_after_gitdir_move(src);
}

write_file(git_link, "gitdir: %s", git_dir);
Expand Down
19 changes: 19 additions & 0 deletions t/t2401-worktree-prune.sh
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,23 @@ test_expect_success 'prune duplicate (main/linked)' '
! test -d .git/worktrees/wt
'

test_expect_success 'not prune proper worktrees when run inside linked worktree' '
test_when_finished rm -rf repo wt_ext &&
git init repo &&
(
cd repo &&
echo content >file &&
git add file &&
git commit -m msg &&
git worktree add ../wt_ext &&
git worktree add wt_int &&
cd wt_int &&
git worktree prune -v >out &&
test_must_be_empty out &&
cd ../../wt_ext &&
git worktree prune -v >out &&
test_must_be_empty out
)
'

test_done
19 changes: 19 additions & 0 deletions t/t2406-worktree-repair.sh
Original file line number Diff line number Diff line change
Expand Up @@ -197,4 +197,23 @@ test_expect_success 'repair moved main and linked worktrees' '
test_cmp expect-gitfile sidemoved/.git
'

test_expect_success 'repair copied main and linked worktrees' '
test_when_finished "rm -rf orig dup" &&
mkdir -p orig &&
git -C orig init main &&
test_commit -C orig/main nothing &&
git -C orig/main worktree add ../linked &&
cp orig/main/.git/worktrees/linked/gitdir orig/main.expect &&
cp orig/linked/.git orig/linked.expect &&
cp -R orig dup &&
sed "s,orig/linked/\.git$,dup/linked/.git," orig/main.expect >dup/main.expect &&
sed "s,orig/main/\.git/worktrees/linked$,dup/main/.git/worktrees/linked," \
orig/linked.expect >dup/linked.expect &&
git -C dup/main worktree repair ../linked &&
test_cmp orig/main.expect orig/main/.git/worktrees/linked/gitdir &&
test_cmp orig/linked.expect orig/linked/.git &&
test_cmp dup/main.expect dup/main/.git/worktrees/linked/gitdir &&
test_cmp dup/linked.expect dup/linked/.git
'

test_done
39 changes: 39 additions & 0 deletions t/t2408-worktree-relative.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/bin/sh

test_description='test worktrees linked with relative paths'

TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh

test_expect_success 'links worktrees with relative paths' '
test_when_finished rm -rf repo &&
git init repo &&
(
cd repo &&
test_commit initial &&
git worktree add wt1 &&
echo "../../../wt1/.git" >expected_gitdir &&
cat .git/worktrees/wt1/gitdir >actual_gitdir &&
echo "gitdir: ../.git/worktrees/wt1" >expected_git &&
cat wt1/.git >actual_git &&
test_cmp expected_gitdir actual_gitdir &&
test_cmp expected_git actual_git
)
'

test_expect_success 'move repo without breaking relative internal links' '
test_when_finished rm -rf repo moved &&
git init repo &&
(
cd repo &&
test_commit initial &&
git worktree add wt1 &&
cd .. &&
mv repo moved &&
cd moved/wt1 &&
git status >out 2>err &&
test_must_be_empty err
)
'

test_done
Loading

0 comments on commit 8e08668

Please sign in to comment.