From patchwork Fri Dec 29 07:26:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Steinhardt X-Patchwork-Id: 13506344 Received: from out2-smtp.messagingengine.com (out2-smtp.messagingengine.com [66.111.4.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2D6B76101 for ; Fri, 29 Dec 2023 07:26:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pks.im Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pks.im Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pks.im header.i=@pks.im header.b="xDgyQYi8"; dkim=pass (2048-bit key) header.d=messagingengine.com header.i=@messagingengine.com header.b="JrLYa0p/" Received: from compute6.internal (compute6.nyi.internal [10.202.2.47]) by mailout.nyi.internal (Postfix) with ESMTP id 35C6B5C0170; Fri, 29 Dec 2023 02:26:33 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute6.internal (MEProxy); Fri, 29 Dec 2023 02:26:33 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pks.im; h=cc:cc :content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm2; t=1703834793; x=1703921193; bh=YX/fIJsulC GsHREQlwvCUA7knnuDAm0AEgJgd5BhRZg=; b=xDgyQYi89rZWCTug+iLYvRjgs6 u+mRTSlXJa/M5Frz3oUBA6jLmtDgk81Hv0BMKcnB4KSAlFIvuOHxaIk9+/QtAQR0 wBaJVmE//SKDU67fbxQJnCi2VQFSl/4fiU3YXUjyJNpu9gvFGmwFLcRw+R0hGY6o 6sXcBSbPgjHaGJqpG5zn0iiIO/303wm2EX+CPZk8FBsuMMLv6pFf9tM012AAdbFm KYe2DIe+b1JcAVK/ReuuzBzwAXb4LQp/UdJBjIdQtMDdFejTY3VM5NRRmPwhWJ9C Q2iNK7Gaq4cXHwyWgS2Q9IICXHYHs4UnmB1HiaZq7dIx8AW3gyuaV0a2cfWQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; t=1703834793; x=1703921193; bh=YX/fIJsulCGsHREQlwvCUA7knnuD Am0AEgJgd5BhRZg=; b=JrLYa0p/a1qAYFQgsWKqU2dfhcESFBmSQQmZ6efp79Rv c5GiQr5WRHTIfG5656CC+ckJA3abtjOLjSn+CU3+TFul2Pj5U84WzV0TxX4YPmX8 MajSNGX14/p4+IH10N+H68jD+kkyA3a+KwkhJOIEQYZ+hB3DS8x5tRfI3CEP/sEV wJv/6op4t9oS4AfwFVgm+UlsEWR8xIZzfS57Z39TdinF9Hc5eeec5w4IEakO0V2r 1gW0x+5tyhKaVheB4KfdWgupw7Kl+2GCdPQ9LSP6jPExcYxgLV/w9dBikHq9Qv+R vACoHrG2MsUcm8fx2I03ERDj/jY+Z1dbcHA9cxJkYA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvkedrvdefvddguddutdcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpeffhffvvefukfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefrrght rhhitghkucfuthgvihhnhhgrrhguthcuoehpshesphhkshdrihhmqeenucggtffrrghtth gvrhhnpeeukedtvedtffevleejtefgheehieegkeeluddvfeefgeehgfeltddtheejleff teenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehpsh esphhkshdrihhm X-ME-Proxy: Feedback-ID: i197146af:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 29 Dec 2023 02:26:32 -0500 (EST) Received: by vm-mail (OpenSMTPD) with ESMTPSA id 4e7b3a98 (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO); Fri, 29 Dec 2023 07:24:16 +0000 (UTC) Date: Fri, 29 Dec 2023 08:26:30 +0100 From: Patrick Steinhardt To: git@vger.kernel.org Cc: Karthik Nayak , Junio C Hamano , Eric Sunshine Subject: [PATCH v3 02/12] worktree: skip reading HEAD when repairing worktrees Message-ID: <77c7213c66d6b5caf2c24e17578d3e42f7b745a7.1703833819.git.ps@pks.im> References: Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: When calling `git init --separate-git-dir=` on a preexisting repository, we move the Git directory of that repository to the new path specified by the user. If there are worktrees present in the repository, we need to repair the worktrees so that their gitlinks point to the new location of the repository. This repair logic will load repositories via `get_worktrees()`, which will enumerate up and initialize all worktrees. Part of initialization is logic that we resolve their respective worktree HEADs, even though that information may not actually be needed in the end by all callers. Although not a problem presently with the file-based reference backend, it will become a problem with the upcoming reftable backend. In the context of git-init(1) we do not have a fully-initialized repository set up via `setup_git_directory()` or friends. Consequently, we do not know about the repository format when `repair_worktrees()` is called, and properly setting up all parts of the repositroy in `init_db()` before we try to repair worktrees is not an easy task. With the introduction of the reftable backend, we would ultimately try to look up the worktree HEADs before we have figured out the reference format, which does not work. We do not require the worktree HEADs at all to repair worktrees. So let's fix this issue by skipping over the step that reads them. Signed-off-by: Patrick Steinhardt --- worktree.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/worktree.c b/worktree.c index a56a6c2a3d..cc34a3419b 100644 --- a/worktree.c +++ b/worktree.c @@ -51,7 +51,7 @@ static void add_head_info(struct worktree *wt) /** * get the main worktree */ -static struct worktree *get_main_worktree(void) +static struct worktree *get_main_worktree(int skip_reading_head) { struct worktree *worktree = NULL; struct strbuf worktree_path = STRBUF_INIT; @@ -70,11 +70,13 @@ static struct worktree *get_main_worktree(void) */ worktree->is_bare = (is_bare_repository_cfg == 1) || is_bare_repository(); - add_head_info(worktree); + if (!skip_reading_head) + add_head_info(worktree); return worktree; } -static struct worktree *get_linked_worktree(const char *id) +static struct worktree *get_linked_worktree(const char *id, + int skip_reading_head) { struct worktree *worktree = NULL; struct strbuf path = STRBUF_INIT; @@ -93,7 +95,8 @@ static struct worktree *get_linked_worktree(const char *id) CALLOC_ARRAY(worktree, 1); worktree->path = strbuf_detach(&worktree_path, NULL); worktree->id = xstrdup(id); - add_head_info(worktree); + if (!skip_reading_head) + add_head_info(worktree); done: strbuf_release(&path); @@ -118,7 +121,14 @@ static void mark_current_worktree(struct worktree **worktrees) free(git_dir); } -struct worktree **get_worktrees(void) +/* + * NEEDSWORK: This function exists so that we can look up metadata of a + * worktree without trying to access any of its internals like the refdb. It + * would be preferable to instead have a corruption-tolerant function for + * retrieving worktree metadata that could be used when the worktree is known + * to not be in a healthy state, e.g. when creating or repairing it. + */ +static struct worktree **get_worktrees_internal(int skip_reading_head) { struct worktree **list = NULL; struct strbuf path = STRBUF_INIT; @@ -128,7 +138,7 @@ struct worktree **get_worktrees(void) ALLOC_ARRAY(list, alloc); - list[counter++] = get_main_worktree(); + list[counter++] = get_main_worktree(skip_reading_head); strbuf_addf(&path, "%s/worktrees", get_git_common_dir()); dir = opendir(path.buf); @@ -137,7 +147,7 @@ struct worktree **get_worktrees(void) while ((d = readdir_skip_dot_and_dotdot(dir)) != NULL) { struct worktree *linked = NULL; - if ((linked = get_linked_worktree(d->d_name))) { + if ((linked = get_linked_worktree(d->d_name, skip_reading_head))) { ALLOC_GROW(list, counter + 1, alloc); list[counter++] = linked; } @@ -151,6 +161,11 @@ struct worktree **get_worktrees(void) return list; } +struct worktree **get_worktrees(void) +{ + return get_worktrees_internal(0); +} + const char *get_worktree_git_dir(const struct worktree *wt) { if (!wt) @@ -591,7 +606,7 @@ static void repair_noop(int iserr UNUSED, void repair_worktrees(worktree_repair_fn fn, void *cb_data) { - struct worktree **worktrees = get_worktrees(); + struct worktree **worktrees = get_worktrees_internal(1); struct worktree **wt = worktrees + 1; /* +1 skips main worktree */ if (!fn)