git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 5/5] worktree: add `relativeWorktrees` extension

From
Caleb White <cdwhite3@pm.me>
Date
Oct 25, 2024, 20:57 UTC
Message-ID
<20241025-wt_relative_paths-v3-5-8860a5321c01@pm.me>
In-Reply-To
<20241025-wt_relative_paths-v3-0-8860a5321c01@pm.me>

A new extension, `relativeWorktrees`, is added to indicate that at least one worktree in the repository has been linked with relative paths. This extension is automatically set when a worktree is created or repaired using the `--relative-paths` option, or when the `worktree.useRelativePaths` config is set to `true`.

The `relativeWorktrees` extension ensures older Git versions do not attempt to automatically prune worktrees with relative paths, as they would not not recognize the paths as being valid.

Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Caleb White <cdwhite3@pm.me>
---
 Documentation/config/extensions.txt |  6 ++++++
 repository.c                        |  1 +
 repository.h                        |  1 +
 setup.c                             |  7 +++++++
 setup.h                             |  1 +
 t/t2400-worktree-add.sh             | 13 +++++++++++++
 worktree.c                          |  8 ++++++++
 7 files changed, 37 insertions(+)
diff --git a/Documentation/config/extensions.txt b/Documentation/config/extensions.txt
index 5dc569d1c9c77c15e32441493289f9c9dd5e7f0b..5cb4721a0e0ae1ed64f90492c0dc18b96473cb33 100644
--- a/Documentation/config/extensions.txt
+++ b/Documentation/config/extensions.txt
@@ -63,6 +63,12 @@ Note that this setting should only be set by linkgit:git-init[1] or
 linkgit:git-clone[1]. Trying to change it after initialization will not
 work and will produce hard-to-diagnose issues.
 
+relativeWorktrees::
+	If enabled, indicates at least one worktree has been linked with
+	relative paths. Automatically set if a worktree has been created or
+	repaired with either the `--relative-paths` option or with the
+	`worktree.useRelativePaths` config set to `true`.
+
 worktreeConfig::
 	If enabled, then worktrees will load config settings from the
 	`$GIT_DIR/config.worktree` file in addition to the
diff --git a/repository.c b/repository.c
index f988b8ae68a6a29792e7f2c980a02bd0e388a3b9..1a6a62bbd03a5dc4fdade3eb45ea2696968abc23 100644
--- a/repository.c
+++ b/repository.c
@@ -283,6 +283,7 @@ int repo_init(struct repository *repo,
 	repo_set_compat_hash_algo(repo, format.compat_hash_algo);
 	repo_set_ref_storage_format(repo, format.ref_storage_format);
 	repo->repository_format_worktree_config = format.worktree_config;
+	repo->repository_format_relative_worktrees = format.relative_worktrees;
 
 	/* take ownership of format.partial_clone */
 	repo->repository_format_partial_clone = format.partial_clone;
diff --git a/repository.h b/repository.h
index 24a66a496a6ff516ce06d47b7329b3d36eb701ca..c4c92b2ab9c9e3b425dc2974636e33d1f4089c69 100644
--- a/repository.h
+++ b/repository.h
@@ -150,6 +150,7 @@ struct repository {
 
 	/* Configurations */
 	int repository_format_worktree_config;
+	int repository_format_relative_worktrees;
 
 	/* Indicate if a repository has a different 'commondir' from 'gitdir' */
 	unsigned different_commondir:1;
diff --git a/setup.c b/setup.c
index 7b648de0279116b381eea46800ad130606926103..6bf56cf72c4b46a95f46f9b3901f7e77d702cec7 100644
--- a/setup.c
+++ b/setup.c
@@ -683,6 +683,9 @@ static enum extension_result handle_extension(const char *var,
 				     "extensions.refstorage", value);
 		data->ref_storage_format = format;
 		return EXTENSION_OK;
+	} else if (!strcmp(ext, "relativeworktrees")) {
+		data->relative_worktrees = git_config_bool(var, value);
+		return EXTENSION_OK;
 	}
 	return EXTENSION_UNKNOWN;
 }
@@ -1854,6 +1857,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
 						    repo_fmt.ref_storage_format);
 			the_repository->repository_format_worktree_config =
 				repo_fmt.worktree_config;
+			the_repository->repository_format_relative_worktrees =
+				repo_fmt.relative_worktrees;
 			/* take ownership of repo_fmt.partial_clone */
 			the_repository->repository_format_partial_clone =
 				repo_fmt.partial_clone;
@@ -1950,6 +1955,8 @@ void check_repository_format(struct repository_format *fmt)
 				    fmt->ref_storage_format);
 	the_repository->repository_format_worktree_config =
 		fmt->worktree_config;
+	the_repository->repository_format_relative_worktrees =
+		fmt->relative_worktrees;
 	the_repository->repository_format_partial_clone =
 		xstrdup_or_null(fmt->partial_clone);
 	clear_repository_format(&repo_fmt);
diff --git a/setup.h b/setup.h
index e496ab3e4de580c2d9f95a7ea0eaf90e0d41b070..18dc3b73686ce28fac2fe04282ce95f8bf3e6b74 100644
--- a/setup.h
+++ b/setup.h
@@ -129,6 +129,7 @@ struct repository_format {
 	int precious_objects;
 	char *partial_clone; /* value of extensions.partialclone */
 	int worktree_config;
+	int relative_worktrees;
 	int is_bare;
 	int hash_algo;
 	int compat_hash_algo;
diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh
index 630c13230b3cc762ce8d943e22be8891aa2b1871..d36d8a4db0e924877787697579544f10f92dc0cf 100755
--- a/t/t2400-worktree-add.sh
+++ b/t/t2400-worktree-add.sh
@@ -1248,4 +1248,17 @@ test_expect_success 'move repo without breaking relative internal links' '
 	)
 '
 
+test_expect_success 'relative worktree sets extension config' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	git -C repo commit --allow-empty -m base &&
+	git -C repo worktree add --relative-paths ./foo &&
+	git -C repo config get core.repositoryformatversion >actual &&
+	echo 1 >expected &&
+	test_cmp expected actual &&
+	git -C repo config get extensions.relativeworktrees >actual &&
+	echo true >expected &&
+	test_cmp expected actual
+'
+
 test_done
diff --git a/worktree.c b/worktree.c
index 0d1685b892fcddf74a91304424a94e5ee847388b..41ebddb495d146e302fedefdb03e0d2637fb2831 100644
--- a/worktree.c
+++ b/worktree.c
@@ -1025,6 +1025,14 @@ void write_worktree_linking_files(struct strbuf dotgit, struct strbuf gitdir)
 	strbuf_strip_suffix(&repo, "/gitdir");
 	strbuf_realpath(&repo, repo.buf, 1);
 
+	if (use_relative_paths && !the_repository->repository_format_relative_worktrees) {
+		if (upgrade_repository_format(1) < 0)
+			die(_("unable to upgrade repository format to support relative worktrees"));
+		if (git_config_set_gently("extensions.relativeWorktrees", "true"))
+			die(_("unable to set extensions.relativeWorktrees setting"));
+		the_repository->repository_format_relative_worktrees = 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));
-- 
2.47.0
Previous: Caleb WhiteNext: Caleb White
Message 6 of 11 in “Optionally link worktrees with relative paths”
  1. 0/5 Optionally link worktrees with relative pathsCaleb White, Oct 25, 2024
  2. 1/5 worktree: refactor infer_backlink() to use strbuf*Caleb White, Oct 25, 2024
  3. 2/5 worktree: support worktrees linked with relative pathsCaleb White, Oct 25, 2024
  4. 4/5 worktree: add test for path handling in linked worktreesCaleb White, Oct 25, 2024
  5. 3/5 worktree: optionally link worktrees with relative pathsCaleb White, Oct 25, 2024
  6. 5/5 worktree: add `relativeWorktrees` extensionCaleb White, Oct 25, 2024
  7. Caleb WhiteOct 25, 2024
  8. Taylor BlauOct 25, 2024
  9. Caleb WhiteOct 25, 2024
  10. Taylor BlauOct 25, 2024
  11. Caleb WhiteOct 25, 2024

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.