Show changes to 11 files +270 −35
Documentation/config/worktree.txt, Documentation/git-worktree.txt, builtin/worktree.c, setup.c, t/t0001-init.sh, t/t2400-worktree-add.sh, t/t2402-worktree-list.sh, t/t2403-worktree-move.sh, t/t2406-worktree-repair.sh, worktree.c, worktree.h
diff --git a/Documentation/config/worktree.txt b/Documentation/config/worktree.txt
index 048e349482df6c892055720eb53cdcd6c327b6ed..d0589c21d034f07f70ca172947520d7d78720cca 100644
--- a/Documentation/config/worktree.txt
+++ b/Documentation/config/worktree.txt
@@ -7,3 +7,8 @@ worktree.guessRemote::
such a branch exists, it is checked out and set as "upstream"
for the new branch. If no such match can be found, it falls
back to creating a new branch from the current HEAD.
+worktree.useRelativePaths::
+ If set to `true`, the worktree paths will be stored relative to the
+ repository’s top-level directory, rather than using absolute paths.
+ This is particularly useful for setups where the repository may be moved
+ between different locations or environments.
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 70437c815f13852bd2eb862176b8b933e6de0acf..4a6ad481ee1d44b43683bd67881a2771e2b090c7 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -216,6 +216,15 @@ To remove a locked worktree, specify `--force` twice.
This can also be set up as the default behaviour by using the
`worktree.guessRemote` config option.
+--[no-]relative-paths::
+ The worktree paths will be stored relative to the repository’s
+ top-level directory, rather than using absolute paths.
+ This is particularly useful for setups where the repository may be moved
+ between different locations or environments.
++
+This can also be set up as the default behaviour by using the
+`worktree.useRelativePaths` config option.
+
--[no-]track::
When creating a new branch, if `<commit-ish>` is a branch,
mark it as "upstream" from the new branch. This is the
diff --git a/builtin/worktree.c b/builtin/worktree.c
index fc31d072a620d7b455d7f150bd3a9e773ee9d4ed..bb06830d6fe82aa97833c6e87f034115dfaa23bd 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -134,6 +134,9 @@ static int git_worktree_config(const char *var, const char *value,
if (!strcmp(var, "worktree.guessremote")) {
guess_remote = git_config_bool(var, value);
return 0;
+ } else if (!strcmp(var, "worktree.userelativepaths")) {
+ use_relative_paths = git_config_bool(var, value);
+ return 0;
}
return git_default_config(var, value, ctx, cb);
@@ -414,7 +417,7 @@ 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;
const char *name;
struct strvec child_env = STRVEC_INIT;
unsigned int counter = 0;
@@ -490,11 +493,7 @@ 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);
+ write_worktree_linking_files(sb_git, sb);
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
@@ -582,7 +581,6 @@ static int add_worktree(const char *path, const char *refname,
strbuf_release(&sb_repo);
strbuf_release(&sb_git);
strbuf_release(&sb_name);
- strbuf_release(&realpath);
free_worktree(wt);
return ret;
}
@@ -794,6 +792,8 @@ static int add(int ac, const char **av, const char *prefix)
PARSE_OPT_NOARG | PARSE_OPT_OPTARG),
OPT_BOOL(0, "guess-remote", &guess_remote,
N_("try to match the new branch name with a remote-tracking branch")),
+ OPT_BOOL(0, "relative-paths", &use_relative_paths,
+ N_("use relative paths for worktrees")),
OPT_END()
};
int ret;
@@ -1187,6 +1187,8 @@ static int move_worktree(int ac, const char **av, const char *prefix)
OPT__FORCE(&force,
N_("force move even if worktree is dirty or locked"),
PARSE_OPT_NOCOMPLETE),
+ OPT_BOOL(0, "relative-paths", &use_relative_paths,
+ N_("use relative paths for worktrees")),
OPT_END()
};
struct worktree **worktrees, *wt;
@@ -1380,6 +1382,8 @@ static int repair(int ac, const char **av, const char *prefix)
const char **p;
const char *self[] = { ".", NULL };
struct option options[] = {
+ OPT_BOOL(0, "relative-paths", &use_relative_paths,
+ N_("use relative paths for worktrees")),
OPT_END()
};
int rc = 0;
diff --git a/setup.c b/setup.c
index 94e79b2e487f3faa537547e190acf9b7ea0be3b5..7b648de0279116b381eea46800ad130606926103 100644
--- a/setup.c
+++ b/setup.c
@@ -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);
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index 0178aa62a41f1606f2382a4a10ab593ccf11e0e8..03ac9624cb418d05adb8dfb786c31b809c73efec 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -435,19 +435,27 @@ sep_git_dir_worktree () {
test_when_finished "rm -rf mainwt linkwt seprepo" &&
git init mainwt &&
test_commit -C mainwt gumby &&
- git -C mainwt worktree add --detach ../linkwt &&
- git -C "$1" init --separate-git-dir ../seprepo &&
+ git -C mainwt worktree add $1 --detach ../linkwt &&
+ git -C "$2" init --separate-git-dir ../seprepo &&
git -C mainwt rev-parse --git-common-dir >expect &&
git -C linkwt rev-parse --git-common-dir >actual &&
test_cmp expect actual
}
-test_expect_success 're-init to move gitdir with linked worktrees' '
- sep_git_dir_worktree mainwt
+test_expect_success 're-init to move gitdir with linked worktrees (absolute)' '
+ sep_git_dir_worktree --no-relative-paths mainwt
'
-test_expect_success 're-init to move gitdir within linked worktree' '
- sep_git_dir_worktree linkwt
+test_expect_success 're-init to move gitdir within linked worktree (absolute)' '
+ sep_git_dir_worktree --no-relative-paths linkwt
+'
+
+test_expect_success 're-init to move gitdir with linked worktrees (relative)' '
+ sep_git_dir_worktree --relative-paths mainwt
+'
+
+test_expect_success 're-init to move gitdir within linked worktree (relative)' '
+ sep_git_dir_worktree --relative-paths linkwt
'
test_expect_success MINGW '.git hidden' '
diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh
index cfc4aeb1798c6d023909cec771e5b74e983af5ea..630c13230b3cc762ce8d943e22be8891aa2b1871 100755
--- a/t/t2400-worktree-add.sh
+++ b/t/t2400-worktree-add.sh
@@ -1207,4 +1207,45 @@ test_expect_success '"add" with initialized submodule, with submodule.recurse se
git -C project-clone -c submodule.recurse worktree add ../project-5
'
+test_expect_success 'can create worktrees with relative paths' '
+ test_when_finished "git worktree remove relative" &&
+ git config worktree.useRelativePaths false &&
+ git worktree add --relative-paths ./relative &&
+ cat relative/.git >actual &&
+ echo "gitdir: ../.git/worktrees/relative" >expect &&
+ test_cmp expect actual &&
+ cat .git/worktrees/relative/gitdir >actual &&
+ echo "../../../relative/.git" >expect &&
+ test_cmp expect actual
+
+'
+
+test_expect_success 'can create worktrees with absolute paths' '
+ git config worktree.useRelativePaths true &&
+ git worktree add ./relative &&
+ cat relative/.git >actual &&
+ echo "gitdir: ../.git/worktrees/relative" >expect &&
+ test_cmp expect actual &&
+ git worktree add --no-relative-paths ./absolute &&
+ cat absolute/.git >actual &&
+ echo "gitdir: $(pwd)/.git/worktrees/absolute" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'move repo without breaking relative internal links' '
+ test_when_finished rm -rf repo moved &&
+ git init repo &&
+ (
+ cd repo &&
+ git config worktree.useRelativePaths true &&
+ 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
diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh
index 33ea9cb21ba07c9563530b54da06753eaa993fe2..780daa6cd6351f8fa9434619cc212aade8f01420 100755
--- a/t/t2402-worktree-list.sh
+++ b/t/t2402-worktree-list.sh
@@ -261,6 +261,7 @@ test_expect_success 'broken main worktree still at the top' '
'
test_expect_success 'linked worktrees are sorted' '
+ test_when_finished "rm -rf sorted" &&
mkdir sorted &&
git init sorted/main &&
(
@@ -280,6 +281,27 @@ test_expect_success 'linked worktrees are sorted' '
test_cmp expected sorted/main/actual
'
+test_expect_success 'linked worktrees with relative paths are shown with absolute paths' '
+ test_when_finished "rm -rf sorted" &&
+ mkdir sorted &&
+ git init sorted/main &&
+ (
+ cd sorted/main &&
+ test_tick &&
+ test_commit new &&
+ git worktree add --relative-paths ../first &&
+ git worktree add ../second &&
+ git worktree list --porcelain >out &&
+ grep ^worktree out >actual
+ ) &&
+ cat >expected <<-EOF &&
+ worktree $(pwd)/sorted/main
+ worktree $(pwd)/sorted/first
+ worktree $(pwd)/sorted/second
+ EOF
+ test_cmp expected sorted/main/actual
+'
+
test_expect_success 'worktree path when called in .git directory' '
git worktree list >list1 &&
git -C .git worktree list >list2 &&
diff --git a/t/t2403-worktree-move.sh b/t/t2403-worktree-move.sh
index 901342ea09b51a8e832f1109fbb737df84283aa2..6ce9ed3f1e6b3f73d2a290e770233eec30221fe5 100755
--- a/t/t2403-worktree-move.sh
+++ b/t/t2403-worktree-move.sh
@@ -247,4 +247,26 @@ test_expect_success 'not remove a repo with initialized submodule' '
)
'
+test_expect_success 'move worktree with absolute path to relative path' '
+ git config worktree.useRelativePaths false &&
+ git worktree add ./absolute &&
+ git worktree move --relative-paths absolute relative &&
+ cat relative/.git >actual &&
+ echo "gitdir: ../.git/worktrees/absolute" >expect &&
+ test_cmp expect actual &&
+ git config worktree.useRelativePaths true &&
+ git worktree move relative relative2 &&
+ cat relative2/.git >actual &&
+ echo "gitdir: ../.git/worktrees/absolute" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'move worktree with relative path to absolute path' '
+ git config worktree.useRelativePaths true &&
+ git worktree move --no-relative-paths relative2 absolute &&
+ cat absolute/.git >actual &&
+ echo "gitdir: $(pwd)/.git/worktrees/absolute" >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t2406-worktree-repair.sh b/t/t2406-worktree-repair.sh
index 7686e60f6ad186519b275f11a5e14064c905b207..84451e903b2ef3c645c0311faf055c846588baf6 100755
--- a/t/t2406-worktree-repair.sh
+++ b/t/t2406-worktree-repair.sh
@@ -216,4 +216,30 @@ test_expect_success 'repair copied main and linked worktrees' '
test_cmp dup/linked.expect dup/linked/.git
'
+test_expect_success 'repair absolute worktree to use relative paths' '
+ test_when_finished "rm -rf main side sidemoved" &&
+ test_create_repo main &&
+ test_commit -C main init &&
+ git -C main worktree add --detach ../side &&
+ echo "../../../../sidemoved/.git" >expect-gitdir &&
+ echo "gitdir: ../main/.git/worktrees/side" >expect-gitfile &&
+ mv side sidemoved &&
+ git -C main worktree repair --relative-paths ../sidemoved &&
+ test_cmp expect-gitdir main/.git/worktrees/side/gitdir &&
+ test_cmp expect-gitfile sidemoved/.git
+'
+
+test_expect_success 'repair relative worktree to use absolute paths' '
+ test_when_finished "rm -rf main side sidemoved" &&
+ test_create_repo main &&
+ test_commit -C main init &&
+ git -C main worktree add --relative-paths --detach ../side &&
+ echo "$(pwd)/sidemoved/.git" >expect-gitdir &&
+ echo "gitdir: $(pwd)/main/.git/worktrees/side" >expect-gitfile &&
+ mv side sidemoved &&
+ git -C main worktree repair ../sidemoved &&
+ test_cmp expect-gitdir main/.git/worktrees/side/gitdir &&
+ test_cmp expect-gitfile sidemoved/.git
+'
+
test_done
diff --git a/worktree.c b/worktree.c
index cf578c447589425d642fc8aa7a7fa07600e60a70..0d1685b892fcddf74a91304424a94e5ee847388b 100644
--- a/worktree.c
+++ b/worktree.c
@@ -14,6 +14,8 @@
#include "wt-status.h"
#include "config.h"
+int use_relative_paths = 0;
+
void free_worktree(struct worktree *worktree)
{
if (!worktree)
@@ -379,18 +381,24 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
void update_worktree_location(struct worktree *wt, const char *path_)
{
struct strbuf path = STRBUF_INIT;
+ struct strbuf dotgit = STRBUF_INIT;
+ struct strbuf gitdir = STRBUF_INIT;
if (is_main_worktree(wt))
BUG("can't relocate main worktree");
+ strbuf_realpath(&gitdir, git_common_path("worktrees/%s/gitdir", wt->id), 1);
strbuf_realpath(&path, path_, 1);
+ strbuf_addf(&dotgit, "%s/.git", path.buf);
if (fspathcmp(wt->path, path.buf)) {
- write_file(git_common_path("worktrees/%s/gitdir", wt->id),
- "%s/.git", path.buf);
+ write_worktree_linking_files(dotgit, gitdir);
+
free(wt->path);
wt->path = strbuf_detach(&path, NULL);
}
strbuf_release(&path);
+ strbuf_release(&dotgit);
+ strbuf_release(&gitdir);
}
int is_worktree_being_rebased(const struct worktree *wt,
@@ -569,6 +577,7 @@ static void repair_gitfile(struct worktree *wt,
worktree_repair_fn fn, void *cb_data)
{
struct strbuf dotgit = STRBUF_INIT;
+ struct strbuf gitdir = STRBUF_INIT;
struct strbuf repo = STRBUF_INIT;
struct strbuf backlink = STRBUF_INIT;
char *dotgit_contents = NULL;
@@ -586,6 +595,7 @@ static void repair_gitfile(struct worktree *wt,
strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
strbuf_addf(&dotgit, "%s/.git", wt->path);
+ strbuf_addf(&gitdir, "%s/gitdir", repo.buf);
dotgit_contents = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));
if (dotgit_contents) {
@@ -603,16 +613,19 @@ static void repair_gitfile(struct worktree *wt,
repair = _(".git file broken");
else if (fspathcmp(backlink.buf, repo.buf))
repair = _(".git file incorrect");
+ else if (use_relative_paths == is_absolute_path(dotgit_contents))
+ repair = _(".git file absolute/relative path mismatch");
if (repair) {
fn(0, wt->path, repair, cb_data);
- write_file(dotgit.buf, "gitdir: %s", repo.buf);
+ write_worktree_linking_files(dotgit, gitdir);
}
done:
free(dotgit_contents);
strbuf_release(&repo);
strbuf_release(&dotgit);
+ strbuf_release(&gitdir);
strbuf_release(&backlink);
}
@@ -636,6 +649,45 @@ void repair_worktrees(worktree_repair_fn fn, void *cb_data)
free_worktrees(worktrees);
}
+void repair_worktree_after_gitdir_move(struct worktree *wt,
+ const char *old_path)
+{
+ struct strbuf gitdir = STRBUF_INIT;
+ struct strbuf dotgit = STRBUF_INIT;
+
+ if (is_main_worktree(wt))
+ goto done;
+
+ strbuf_realpath(&gitdir, git_common_path("worktrees/%s/gitdir", wt->id), 1);
+
+ if (strbuf_read_file(&dotgit, gitdir.buf, 0) < 0)
+ goto done;
+
+ strbuf_rtrim(&dotgit);
+ if (!is_absolute_path(dotgit.buf)) {
+ strbuf_insertf(&dotgit, 0, "%s/worktrees/%s/", old_path, wt->id);
+ strbuf_realpath_forgiving(&dotgit, dotgit.buf, 0);
+ }
+
+ if (!file_exists(dotgit.buf))
+ goto done;
+
+ write_worktree_linking_files(dotgit, gitdir);
+done:
+ strbuf_release(&gitdir);
+ strbuf_release(&dotgit);
+}
+
+void repair_worktrees_after_gitdir_move(const char *old_path)
+{
+ struct worktree **worktrees = get_worktrees_internal(1);
+ struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
+
+ for (; *wt; wt++)
+ repair_worktree_after_gitdir_move(*wt, old_path);
+ free_worktrees(worktrees);
+}
+
static int is_main_worktree_path(const char *path)
{
struct strbuf target = STRBUF_INIT;
@@ -698,12 +750,10 @@ void repair_worktree_at_path(const char *path,
worktree_repair_fn fn, void *cb_data)
{
struct strbuf dotgit = STRBUF_INIT;
- struct strbuf realdotgit = STRBUF_INIT;
struct strbuf backlink = STRBUF_INIT;
struct strbuf inferred_backlink = STRBUF_INIT;
struct strbuf gitdir = STRBUF_INIT;
struct strbuf olddotgit = STRBUF_INIT;
- struct strbuf realolddotgit = STRBUF_INIT;
char *dotgit_contents = NULL;
const char *repair = NULL;
int err;
@@ -715,25 +765,25 @@ void repair_worktree_at_path(const char *path,
goto done;
strbuf_addf(&dotgit, "%s/.git", path);
- if (!strbuf_realpath(&realdotgit, dotgit.buf, 0)) {
+ if (!strbuf_realpath(&dotgit, dotgit.buf, 0)) {
fn(1, path, _("not a valid path"), cb_data);
goto done;
}
- infer_backlink(realdotgit.buf, &inferred_backlink);
+ infer_backlink(dotgit.buf, &inferred_backlink);
strbuf_realpath_forgiving(&inferred_backlink, inferred_backlink.buf, 0);
- dotgit_contents = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err));
+ dotgit_contents = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));
if (dotgit_contents) {
if (is_absolute_path(dotgit_contents)) {
strbuf_addstr(&backlink, dotgit_contents);
} else {
- strbuf_addbuf(&backlink, &realdotgit);
+ strbuf_addbuf(&backlink, &dotgit);
strbuf_strip_suffix(&backlink, ".git");
strbuf_addstr(&backlink, dotgit_contents);
strbuf_realpath_forgiving(&backlink, backlink.buf, 0);
}
} else if (err == READ_GITFILE_ERR_NOT_A_FILE) {
- fn(1, realdotgit.buf, _("unable to locate repository; .git is not a file"), cb_data);
+ fn(1, dotgit.buf, _("unable to locate repository; .git is not a file"), cb_data);
goto done;
} else if (err == READ_GITFILE_ERR_NOT_A_REPO) {
if (inferred_backlink.len) {
@@ -746,11 +796,11 @@ void repair_worktree_at_path(const char *path,
*/
strbuf_swap(&backlink, &inferred_backlink);
} else {
- fn(1, realdotgit.buf, _("unable to locate repository; .git file does not reference a repository"), cb_data);
+ fn(1, dotgit.buf, _("unable to locate repository; .git file does not reference a repository"), cb_data);
goto done;
}
} else {
- fn(1, realdotgit.buf, _("unable to locate repository; .git file broken"), cb_data);
+ fn(1, dotgit.buf, _("unable to locate repository; .git file broken"), cb_data);
goto done;
}
@@ -778,30 +828,28 @@ void repair_worktree_at_path(const char *path,
strbuf_addf(&gitdir, "%s/gitdir", backlink.buf);
if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)
repair = _("gitdir unreadable");
+ else if (use_relative_paths == is_absolute_path(olddotgit.buf))
+ repair = _("gitdir absolute/relative path mismatch");
else {
strbuf_rtrim(&olddotgit);
- if (is_absolute_path(olddotgit.buf)) {
- strbuf_addbuf(&realolddotgit, &olddotgit);
- } else {
- strbuf_addf(&realolddotgit, "%s/%s", backlink.buf, olddotgit.buf);
- strbuf_realpath_forgiving(&realolddotgit, realolddotgit.buf, 0);
+ if (!is_absolute_path(olddotgit.buf)) {
+ strbuf_insertf(&olddotgit, 0, "%s/", backlink.buf);
+ strbuf_realpath_forgiving(&olddotgit, olddotgit.buf, 0);
}
- if (fspathcmp(realolddotgit.buf, realdotgit.buf))
+ if (fspathcmp(olddotgit.buf, dotgit.buf))
repair = _("gitdir incorrect");
}
if (repair) {
fn(0, gitdir.buf, repair, cb_data);
- write_file(gitdir.buf, "%s", realdotgit.buf);
+ write_worktree_linking_files(dotgit, gitdir);
}
done:
free(dotgit_contents);
strbuf_release(&olddotgit);
- strbuf_release(&realolddotgit);
strbuf_release(&backlink);
strbuf_release(&inferred_backlink);
strbuf_release(&gitdir);
- strbuf_release(&realdotgit);
strbuf_release(&dotgit);
}
@@ -963,3 +1011,29 @@ int init_worktree_config(struct repository *r)
free(main_worktree_file);
return res;
}
+
+void write_worktree_linking_files(struct strbuf dotgit, struct strbuf gitdir)
+{
+ struct strbuf path = STRBUF_INIT;
+ struct strbuf repo = STRBUF_INIT;
+ struct strbuf tmp = STRBUF_INIT;
+
+ strbuf_addbuf(&path, &dotgit);
+ strbuf_strip_suffix(&path, "/.git");
+ strbuf_realpath(&path, path.buf, 1);
+ strbuf_addbuf(&repo, &gitdir);
+ strbuf_strip_suffix(&repo, "/gitdir");
+ strbuf_realpath(&repo, repo.buf, 1);
+
+ if (use_relative_paths) {
+ write_file(gitdir.buf, "%s/.git", relative_path(path.buf, repo.buf, &tmp));
+ write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp));
+ } else {
+ write_file(gitdir.buf, "%s/.git", path.buf);
+ write_file(dotgit.buf, "gitdir: %s", repo.buf);
+ }
+
+ strbuf_release(&path);
+ strbuf_release(&repo);
+ strbuf_release(&tmp);
+}
diff --git a/worktree.h b/worktree.h
index 11279d0c8fe249bb30642563bf221a8de7f3b0a3..5929089891c97318a8f5329f7938264c717050d5 100644
--- a/worktree.h
+++ b/worktree.h
@@ -5,6 +5,8 @@
struct strbuf;
+extern int use_relative_paths;
+
struct worktree {
/* The repository this worktree belongs to. */
struct repository *repo;
@@ -131,6 +133,16 @@ typedef void (* worktree_repair_fn)(int iserr, const char *path,
*/
void repair_worktrees(worktree_repair_fn, void *cb_data);
+/*
+ * Repair the linked worktrees after the gitdir has been moved.
+ */
+void repair_worktrees_after_gitdir_move(const char *old_path);
+
+/*
+ * Repair the linked worktree after the gitdir has been moved.
+ */
+void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path);
+
/*
* Repair administrative files corresponding to the worktree at the given path.
* The worktree's .git file pointing at the repository must be intact for the
@@ -205,4 +217,16 @@ void strbuf_worktree_ref(const struct worktree *wt,
*/
int init_worktree_config(struct repository *r);
+/**
+ * Write the .git file and gitdir file that links the worktree to the repository.
+ *
+ * The `dotgit` parameter is the path to the worktree's .git file, and `gitdir`
+ * is the path to the repository's `gitdir` file.
+ *
+ * Example
+ * dotgit: "/path/to/foo/.git"
+ * gitdir: "/path/to/repo/worktrees/foo/gitdir"
+ */
+void write_worktree_linking_files(struct strbuf dotgit, struct strbuf gitdir);
+
#endif