summaryrefslogtreecommitdiffstats
path: root/worktree.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2024-10-08 20:49:13 +0200
committerJunio C Hamano <gitster@pobox.com>2024-10-08 20:49:13 +0200
commit58d8805de246352b41ca7bfd6cd70078b94ff1f1 (patch)
tree746687410532de23d6182c39012518a396b68369 /worktree.c
parentGit 2.47 (diff)
parentworktree: repair copied repository and linked worktrees (diff)
downloadgit-58d8805de246352b41ca7bfd6cd70078b94ff1f1.tar.xz
git-58d8805de246352b41ca7bfd6cd70078b94ff1f1.zip
Merge branch 'es/worktree-repair-copied' into cw/worktrees-relative
* es/worktree-repair-copied: worktree: repair copied repository and linked worktrees
Diffstat (limited to 'worktree.c')
-rw-r--r--worktree.c40
1 files changed, 39 insertions, 1 deletions
diff --git a/worktree.c b/worktree.c
index 0f032ccedf..ec95ea2986 100644
--- a/worktree.c
+++ b/worktree.c
@@ -683,6 +683,7 @@ void repair_worktree_at_path(const char *path,
struct strbuf gitdir = STRBUF_INIT;
struct strbuf olddotgit = STRBUF_INIT;
char *backlink = NULL;
+ char *inferred_backlink = NULL;
const char *repair = NULL;
int err;
@@ -698,12 +699,24 @@ void repair_worktree_at_path(const char *path,
goto done;
}
+ inferred_backlink = infer_backlink(realdotgit.buf);
backlink = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err));
if (err == READ_GITFILE_ERR_NOT_A_FILE) {
fn(1, realdotgit.buf, _("unable to locate repository; .git is not a file"), cb_data);
goto done;
} else if (err == READ_GITFILE_ERR_NOT_A_REPO) {
- if (!(backlink = infer_backlink(realdotgit.buf))) {
+ if (inferred_backlink) {
+ /*
+ * Worktree's .git file does not point at a repository
+ * but we found a .git/worktrees/<id> in this
+ * repository with the same <id> as recorded in the
+ * worktree's .git file so make the worktree point at
+ * the discovered .git/worktrees/<id>. (Note: backlink
+ * is already NULL, so no need to free it first.)
+ */
+ backlink = inferred_backlink;
+ inferred_backlink = NULL;
+ } else {
fn(1, realdotgit.buf, _("unable to locate repository; .git file does not reference a repository"), cb_data);
goto done;
}
@@ -712,6 +725,30 @@ void repair_worktree_at_path(const char *path,
goto done;
}
+ /*
+ * If we got this far, either the worktree's .git file pointed at a
+ * valid repository (i.e. read_gitfile_gently() returned success) or
+ * the .git file did not point at a repository but we were able to
+ * infer a suitable new value for the .git file by locating a
+ * .git/worktrees/<id> in *this* repository corresponding to the <id>
+ * recorded in the worktree's .git file.
+ *
+ * However, if, at this point, inferred_backlink is non-NULL (i.e. we
+ * found a suitable .git/worktrees/<id> in *this* repository) *and* the
+ * worktree's .git file points at a valid repository *and* those two
+ * paths differ, then that indicates that the user probably *copied*
+ * the main and linked worktrees to a new location as a unit rather
+ * than *moving* them. Thus, the copied worktree's .git file actually
+ * points at the .git/worktrees/<id> in the *original* repository, not
+ * in the "copy" repository. In this case, point the "copy" worktree's
+ * .git file at the "copy" repository.
+ */
+ if (inferred_backlink && fspathcmp(backlink, inferred_backlink)) {
+ free(backlink);
+ backlink = inferred_backlink;
+ inferred_backlink = NULL;
+ }
+
strbuf_addf(&gitdir, "%s/gitdir", backlink);
if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)
repair = _("gitdir unreadable");
@@ -727,6 +764,7 @@ void repair_worktree_at_path(const char *path,
}
done:
free(backlink);
+ free(inferred_backlink);
strbuf_release(&olddotgit);
strbuf_release(&gitdir);
strbuf_release(&realdotgit);