From: Caleb White <cdwhite3@pm.me>
To: git@vger.kernel.org
Cc: Caleb White <cdwhite3@pm.me>
Subject: [PATCH 3/4] worktree: sync worktree paths after gitdir move
Date: Sun, 06 Oct 2024 04:59:38 +0000 [thread overview]
Message-ID: <20241006045847.159937-4-cdwhite3@pm.me> (raw)
In-Reply-To: <20241006045847.159937-1-cdwhite3@pm.me>
[-- Attachment #1: Type: text/plain, Size: 4200 bytes --]
When re-initializing a repository with a separate gitdir (the original
gitdir is moved to a new location), any linked worktrees become broken
and must be repaired to reflect the new gitdir location. For absolute
paths, this breakage is one-way, but is both ways for relative paths
(the `<worktree>/.git` and the `<repo>/worktrees/<id>/gitdir`).
Previously, `repair_worktrees` was being called which loops through all
the worktrees in the repository and updates the `<worktree>/.git` files
to point to the new gitdir. However, when both sides of the worktrees
are broken, the previous gitdir location is required to reestablish the
link.
To fix this, the function `repair_worktrees_after_gitdir_move` is
introduced. It takes the old gitdir path as an argument and repairs both
sides of the worktree.
This change fixes the following test cases in t0001-init.sh:
- re-init to move gitdir with linked worktrees
- re-init to move gitdir within linked worktree
Signed-off-by: Caleb
White <cdwhite3@pm.me>
---
setup.c | 2 +-
worktree.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
worktree.h | 10 ++++++++++
3 files changed, 65 insertions(+), 1 deletion(-)
diff --git a/setup.c b/setup.c
index 94e79b2..7b648de 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/worktree.c b/worktree.c
index fc14e9a..b08ecce 100644
--- a/worktree.c
+++ b/worktree.c
@@ -650,6 +650,60 @@ 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 path = STRBUF_INIT;
+ struct strbuf repo = STRBUF_
INIT;
+ struct strbuf gitdir = STRBUF_INIT;
+ struct strbuf dotgit = STRBUF_INIT;
+ struct strbuf olddotgit = STRBUF_INIT;
+ struct strbuf tmp = STRBUF_INIT;
+
+ if (is_main_worktree(wt))
+ goto done;
+
+ strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
+ strbuf_addf(&gitdir, "%s/gitdir", repo.buf);
+
+ if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)
+ goto done;
+
+ strbuf_rtrim(&olddotgit);
+ if (is_absolute_path(olddotgit.buf)) {
+ strbuf_addbuf(&dotgit, &olddotgit);
+ } else {
+ strbuf_addf(&dotgit, "%s/worktrees/%s/%s", old_path, wt->id, olddotgit.buf);
+ strbuf_realpath_forgiving(&dotgit, dotgit.buf, 0);
+ }
+
+ if (!file_exists(dotgit.buf))
+ goto done;
+
+ strbuf_addbuf(&path, &dotgit);
+ strbuf_strip_suffix(&path, "/.git");
+
+ write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp));
+ strbuf_reset(&tmp);
+ write_file(gitdir.buf, "%s", relative_path(dotgit.buf, repo.buf, &tmp));
+done:
+ strbu
f_release(&path);
+ strbuf_release(&repo);
+ strbuf_release(&gitdir);
+ strbuf_release(&dotgit);
+ strbuf_release(&olddotgit);
+ strbuf_release(&tmp);
+}
+
+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;
diff --git a/worktree.h b/worktree.h
index 11279d0..e961186 100644
--- a/worktree.h
+++ b/worktree.h
@@ -131,6 +131,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 l
inked 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
--
2.46.2
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 509 bytes --]
next prev parent reply other threads:[~2024-10-06 4:59 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-06 4:59 [PATCH 0/4] Link worktrees with relative paths Caleb White
2024-10-06 4:59 ` [PATCH 1/4] worktree: refactor infer_backlink() to use *strbuf Caleb White
2024-10-06 4:59 ` [PATCH 2/4] worktree: link worktrees with relative paths Caleb White
2024-10-06 4:59 ` Caleb White [this message]
2024-10-06 4:59 ` [PATCH 4/4] worktree: prevent null pointer dereference Caleb White
2024-10-06 5:04 ` [PATCH 0/4] Link worktrees with relative paths Eric Sunshine
2024-10-06 5:11 ` Caleb White
2024-10-06 5:14 ` Eric Sunshine
2024-10-06 5:16 ` Eric Sunshine
[not found] ` <TEfKiit-RYyr0ZuiQszaKaM64iSonfaQwWRqExOgXyPR1tVWyAzR3kVKmCd3aREZwDGuS5VXcHjCvneY-gCg2OuZyv2N2EkfARlZu4AVSsU=@pm.me>
[not found] ` <CAPig+cTE0gaD=7dwSqY4S+7AqRoU9yOrS4sdBoybj0Pfyk9vxA@mail.gmail.com>
2024-10-06 5:41 ` Caleb White
2024-10-06 5:50 ` Eric Sunshine
2024-10-06 6:05 ` Caleb White
2024-10-06 6:16 ` Eric Sunshine
2024-10-06 6:23 ` Caleb White
2024-10-06 7:45 ` Eric Sunshine
2024-10-06 9:00 ` Kristoffer Haugsbakk
2024-10-06 22:10 ` Caleb White
2024-10-06 22:08 ` Caleb White
2024-10-06 22:24 ` Eric Sunshine
2024-10-06 22:32 ` Caleb White
2024-10-06 5:11 ` Eric Sunshine
2024-10-06 22:01 ` Caleb White
2024-10-06 22:19 ` Eric Sunshine
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241006045847.159937-4-cdwhite3@pm.me \
--to=cdwhite3@pm.me \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).