{"thread":{"id":"62258","subject":"[PATCH 0/4] Link worktrees with relative paths","startedAt":"2024-10-06T04:59:15Z","lastAt":"2024-10-06T22:32:46Z","messageCount":23,"participants":["Caleb White","Eric Sunshine","Kristoffer Haugsbakk"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"504139","messageId":"20241006045847.159937-1-cdwhite3@pm.me","threadId":"62258","inReplyTo":null,"subject":"[PATCH 0/4] Link worktrees with relative paths","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-10-06T04:59:02Z","receivedAt":"2024-10-06T04:59:15Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"Hello,\n\nThis patch series modifies Git's handling of worktree linking to use\nrelative paths instead of absolute paths. The motivation behind this\nchange is to enhance the robustness of worktree links when the main\nrepository is moved, or when used in environments like containerized\ndevelopment where absolute paths differ across systems.\n\nCurrently, Git stores absolute paths to both the main repository and\nthe linked worktrees. This causes issues when the repository is moved\nbecause the hardcoded paths become invalid, leading to broken worktree\nlinks. Developers are then required to manually repair the links by\nrunning `git worktree repair`, which can be cumbersome.\n\nBy switching to relative paths for worktrees, this patch improves the\nresilience of worktree links. For self-contained repositories (e.g.,\nbare repositories with worktrees), the links will continue to function\nproperly when the repository is moved or mapped inside a containerized\nenvironment. While relativ\ne paths do not completely eliminate the need\nfor repairs (as links external to the repository can still break), the\nlikelihood is reduced, and Git continues to provide mechanisms to repair\nbroken links when needed.\n\nI have included tests to verify that:\n- worktree links are created with relative paths.\n- moving the repository does not break worktree links.\n\nNote that absolute paths are still supported, and the code handles both\ntypes of paths. There should be no breaking changes introduced with this\npatch. I considered adding a configuration option\n(e.g., `worktree.useRelativePaths`) to control path type, but decided to\nkeep it simple. However, if there is interest, I can add this feature.\n\nThis series is based on top of 111e864d69.\n\nThanks!\n\nCaleb\n\nCaleb White (4):\n  worktree: refactor infer_backlink() to use *strbuf\n  worktree: link worktrees with relative paths\n  worktree: sync worktree paths after gitdir move\n  worktree: prevent null pointer dereference\n\n\n builtin/worktree.c           |  17 +--\n setup.c                      |   2 +-\n t/t2408-worktree-relative.sh |  39 ++++++\n worktree.c                   | 235 +++++++++++++++++++++++++++--------\n worktree.h                   |  10 ++\n 5 files changed, 240 insertions(+), 63 deletions(-)\n create mode 100755 t/t2408-worktree-relative.sh\n\n-- \n2.46.2\n\n"},{"id":"504140","messageId":"20241006045847.159937-2-cdwhite3@pm.me","threadId":"62258","inReplyTo":"20241006045847.159937-1-cdwhite3@pm.me","subject":"[PATCH 1/4] worktree: refactor infer_backlink() to use *strbuf","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-10-06T04:59:21Z","receivedAt":"2024-10-06T04:59:35Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"This refactors the `infer_backlink` function to return an integer\nresult and use a pre-allocated `strbuf` for the inferred backlink\npath, replacing the previous `char*` return type.\n\nThis lays the groundwork for the next patch, which needs the\nresultant backlink as a `strbuf`. There was no need to go from\n`strbuf -> char* -> strbuf` again. This change also aligns the\nfunction's signature with other `strbuf`-based functions.\n\nSigned-off-by: Caleb White <cdwhite3@pm.me>\n---\n worktree.c | 26 ++++++++++++++------------\n 1 file changed, 14 insertions(+), 12 deletions(-)\n\ndiff --git a/worktree.c b/worktree.c\nindex 0f032cc..c6d2ede 100644\n--- a/worktree.c\n+++ b/worktree.c\n@@ -642,10 +642,9 @@ static int is_main_worktree_path(const char *path)\n  * be able to infer the gitdir by manually reading /path/to/worktree/.git,\n  * extracting the <id>, and checking if <repo>/worktrees/<id> exists.\n  */\n-static char *infer_backlink(const char *gitfile)\n+static int infer_backlink(st\nruct strbuf *inferred, const char *gitfile)\n {\n \tstruct strbuf actual = STRBUF_INIT;\n-\tstruct strbuf inferred = STRBUF_INIT;\n \tconst char *id;\n \n \tif (strbuf_read_file(&actual, gitfile, 0) < 0)\n@@ -658,17 +657,16 @@ static char *infer_backlink(const char *gitfile)\n \tid++; /* advance past '/' to point at <id> */\n \tif (!*id)\n \t\tgoto error;\n-\tstrbuf_git_common_path(&inferred, the_repository, \"worktrees/%s\", id);\n-\tif (!is_directory(inferred.buf))\n+\tstrbuf_git_common_path(inferred, the_repository, \"worktrees/%s\", id);\n+\tif (!is_directory(inferred->buf))\n \t\tgoto error;\n \n \tstrbuf_release(&actual);\n-\treturn strbuf_detach(&inferred, NULL);\n+\treturn 0;\n \n error:\n \tstrbuf_release(&actual);\n-\tstrbuf_release(&inferred);\n-\treturn NULL;\n+\treturn 1;\n }\n \n /*\n@@ -680,9 +678,10 @@ void repair_worktree_at_path(const char *path,\n {\n \tstruct strbuf dotgit = STRBUF_INIT;\n \tstruct strbuf realdotgit = STRBUF_INIT;\n+\tstruct strbuf backlink = STRBUF_INIT;\n \tstruct strbuf gitd\nir = STRBUF_INIT;\n \tstruct strbuf olddotgit = STRBUF_INIT;\n-\tchar *backlink = NULL;\n+\tchar *git_contents = NULL;\n \tconst char *repair = NULL;\n \tint err;\n \n@@ -698,21 +697,23 @@ void repair_worktree_at_path(const char *path,\n \t\tgoto done;\n \t}\n \n-\tbacklink = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err));\n+\tgit_contents = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err));\n \tif (err == READ_GITFILE_ERR_NOT_A_FILE) {\n \t\tfn(1, realdotgit.buf, _(\"unable to locate repository; .git is not a file\"), cb_data);\n \t\tgoto done;\n \t} else if (err == READ_GITFILE_ERR_NOT_A_REPO) {\n-\t\tif (!(backlink = infer_backlink(realdotgit.buf))) {\n+\t\tif (infer_backlink(&backlink, realdotgit.buf)) {\n \t\t\tfn(1, realdotgit.buf, _(\"unable to locate repository; .git file does not reference a repository\"), cb_data);\n \t\t\tgoto done;\n \t\t}\n \t} else if (err) {\n \t\tfn(1, realdotgit.buf, _(\"unable to locate repository; .git file broken\"), cb_data);\n \t\tgoto done;\n+\t} else if (git_conte\nnts) {\n+\t\tstrbuf_addstr(&backlink, git_contents);\n \t}\n \n-\tstrbuf_addf(&gitdir, \"%s/gitdir\", backlink);\n+\tstrbuf_addf(&gitdir, \"%s/gitdir\", backlink.buf);\n \tif (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)\n \t\trepair = _(\"gitdir unreadable\");\n \telse {\n@@ -726,8 +727,9 @@ void repair_worktree_at_path(const char *path,\n \t\twrite_file(gitdir.buf, \"%s\", realdotgit.buf);\n \t}\n done:\n-\tfree(backlink);\n+\tfree(git_contents);\n \tstrbuf_release(&olddotgit);\n+\tstrbuf_release(&backlink);\n \tstrbuf_release(&gitdir);\n \tstrbuf_release(&realdotgit);\n \tstrbuf_release(&dotgit);\n-- \n2.46.2\n\n"},{"id":"504142","messageId":"20241006045847.159937-3-cdwhite3@pm.me","threadId":"62258","inReplyTo":"20241006045847.159937-1-cdwhite3@pm.me","subject":"[PATCH 2/4] worktree: link worktrees with relative paths","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-10-06T04:59:30Z","receivedAt":"2024-10-06T04:59:43Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"This modifies Git’s handling of worktree linking to use relative\npaths instead of absolute paths. Previously, when creating a worktree,\nGit would store the absolute paths to both the main repository and the\nlinked worktrees. These hardcoded absolute paths cause breakages such\nas when the repository is moved to a different directory or during\ncontainerized development where the absolute differs between systems.\n\nBy switching to relative paths, we help ensure that worktree links are\nmore resilient when the repository is moved. While links external to the\nrepository may still break, Git still automatically handles many common\nscenarios, reducing the need for manual repair. This is particularly\nuseful in containerized or portable development environments, where the\nabsolute path to the repository can differ between systems. Developers\nno longer need to reinitialize or repair worktrees after relocating the\nrepository, improving workflow efficiency and reducing breakages.\n\nFor self-contained repositories (such as using a bare repository with\nworktrees), where both the repository and its worktrees are located\nwithin the same directory structure, using relative paths guarantees all\nlinks remain functional regardless of where the directory is located.\n\nSigned-off-by: Caleb White <cdwhite3@pm.me>\n---\n builtin/worktree.c           |  17 ++--\n t/t2408-worktree-relative.sh |  39 +++++++++\n worktree.c                   | 152 +++++++++++++++++++++++++----------\n 3 files changed, 159 insertions(+), 49 deletions(-)\n create mode 100755 t/t2408-worktree-relative.sh\n\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex fc31d07..99cee56 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -414,7 +414,8 @@ static int add_worktree(const char *path, const char *refname,\n \t\t\tconst struct add_opts *opts)\n {\n \tstruct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;\n-\tstruct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT;\n+\tstruct strbuf sb = STRBUF_INIT, sb_tmp = STRBUF_INIT;\n+\tstruct strbuf sb_path_realpath = STRBUF_INIT, sb_repo_realpath = STRBUF_INIT;\n \tconst char *name;\n \tstruct strvec child_env = STRVEC_INIT;\n \tunsigned int counter = 0;\n@@ -490,11 +491,11 @@ static int add_worktree(const char *path, const char *refname,\n \n \tstrbuf_reset(&sb);\n \tstrbuf_addf(&sb, \"%s/gitdir\", sb_repo.buf);\n-\tstrbuf_realpath(&realpath, sb_git.buf, 1);\n-\twrite_file(sb.buf, \"%s\", realpath.buf);\n-\tstrbuf_realpath(&realpath, repo_get_common_dir(the_repository), 1);\n-\twrite_file(sb_git.buf, \"gitdir: %s/worktrees/%s\",\n-\t\t   realpath.buf, name);\n+\tstrbuf_realpath(&sb_path_realpath, path, 1);\n+\tstrbuf_realpath(&sb_repo_realpath, sb_repo.buf, 1);\n+\twrite_file(sb.buf, \"%s/.git\", relative_path(sb_path_realpath.buf, sb_repo_realpath.buf, &sb_tmp));\n+\tstrbuf_reset(&sb_tmp);\n+\twrite_file(sb_git.buf, \"gitdir: %s\", relative_path(sb_repo_realpath.buf, sb_path_realpath.buf, &sb_tmp));\n \tstrbuf_reset(&sb);\n \tstrbuf_addf(&sb, \"%s/commondir\", sb_repo.buf);\n \twrite_file(sb.buf, \"../..\");\n@@ -578,11 +579,13 @@ static int add_worktree(const char *path, const char *refname,\n \n \tstrvec_clear(&child_env);\n \tstrbuf_release(&sb);\n+\tstrbuf_release(&sb_tmp);\n \tstrbuf_release(&symref);\n \tstrbuf_release(&sb_repo);\n+\tstrbuf_release(&sb_repo_realpath);\n \tstrbuf_release(&sb_git);\n+\tstrbuf_release(&sb_path_realpath);\n \tstrbuf_release(&sb_name);\n-\tstrbuf_release(&realpath);\n \tfree_worktree(wt);\n \treturn ret;\n }\ndiff --git a/t/t2408-worktree-relative.sh b/t/t2408-worktree-relative.sh\nnew file mode 100755\nindex 0000000..a3136db\n--- /dev/null\n+++ b/t/t2408-worktree-relative.sh\n@@ -0,0 +1,39 @@\n+#!/bin/sh\n+\n+test_description='test worktrees linked with relative paths'\n+\n+TEST_PASSES_SANITIZE_LEAK=true\n+. ./test-lib.sh\n+\n+test_expect_success 'links worktrees with relative paths' '\n+\ttest_when_finished rm -rf repo &&\n+\tgit init repo &&\n+\t(\n+\t\tcd repo &&\n+\t\ttest_commit initial &&\n+\t\tgit worktree add wt1 &&\n+\t\techo \"../../../wt1/.git\" >expected_gitdir &&\n+\t\tcat .git/worktrees/wt1/gitdir >actual_gitdir &&\n+\t\techo \"gitdir: ../.git/worktrees/wt1\" >expected_git &&\n+\t\tcat wt1/.git >actual_git &&\n+\t\ttest_cmp expected_gitdir actual_gitdir &&\n+\t\ttest_cmp expected_git actual_git\n+\t)\n+'\n+\n+test_expect_success 'move repo without breaking relative internal links' '\n+\ttest_when_finished rm -rf repo moved &&\n+\tgit init repo &&\n+\t(\n+\t\tcd repo &&\n+\t\ttest_commit initial &&\n+\t\tgit worktree add wt1 &&\n+\t\tcd .. &&\n+\t\tmv repo moved &&\n+\t\tcd moved/wt1 &&\n+\t\tgit status >out 2>err &&\n+\t\ttest_must_be_empty err\n+\t)\n+'\n+\n+test_done\ndiff --git a/worktree.c b/worktree.c\nindex c6d2ede..fc14e9a 100644\n--- a/worktree.c\n+++ b/worktree.c\n@@ -110,6 +110,12 @@ struct worktree *get_linked_worktree(const char *id,\n \tstrbuf_rtrim(&worktree_path);\n \tstrbuf_strip_suffix(&worktree_path, \"/.git\");\n \n+\tif (!is_absolute_path(worktree_path.buf)) {\n+\t    strbuf_strip_suffix(&path, \"gitdir\");\n+\t    strbuf_addbuf(&path, &worktree_path);\n+\t    strbuf_realpath_forgiving(&worktree_path, path.buf, 0);\n+\t}\n+\n \tCALLOC_ARRAY(worktree, 1);\n \tworktree->repo = the_repository;\n \tworktree->path = strbuf_detach(&worktree_path, NULL);\n@@ -373,18 +379,30 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,\n void update_worktree_location(struct worktree *wt, const char *path_)\n {\n \tstruct strbuf path = STRBUF_INIT;\n+\tstruct strbuf repo = STRBUF_INIT;\n+\tstruct strbuf tmp = STRBUF_INIT;\n+\tchar *file = NULL;\n \n \tif (is_main_worktree(wt))\n \t\tBUG(\"can't relocate main worktree\");\n \n+\tstrbuf_realpath(&repo, git_common_path(\"worktrees/%s\", wt->id), 1);\n \tstrbuf_realpath(&path, path_, 1);\n \tif (fspathcmp(wt->path, path.buf)) {\n-\t\twrite_file(git_common_path(\"worktrees/%s/gitdir\", wt->id),\n-\t\t\t   \"%s/.git\", path.buf);\n+\t\tfile = xstrfmt(\"%s/gitdir\", repo.buf);\n+\t\twrite_file(file, \"%s/.git\", relative_path(path.buf, repo.buf, &tmp));\n+\t\tfree(file);\n+\t\tstrbuf_reset(&tmp);\n+\t\tfile = xstrfmt(\"%s/.git\", path.buf);\n+\t\twrite_file(file, \"gitdir: %s\", relative_path(repo.buf, path.buf, &tmp));\n+\n \t\tfree(wt->path);\n \t\twt->path = strbuf_detach(&path, NULL);\n \t}\n+\tfree(file);\n \tstrbuf_release(&path);\n+\tstrbuf_release(&repo);\n+\tstrbuf_release(&tmp);\n }\n \n int is_worktree_being_rebased(const struct worktree *wt,\n@@ -564,38 +582,52 @@ static void repair_gitfile(struct worktree *wt,\n {\n \tstruct strbuf dotgit = STRBUF_INIT;\n \tstruct strbuf repo = STRBUF_INIT;\n-\tchar *backlink;\n+\tstruct strbuf backlink = STRBUF_INIT;\n+\tstruct strbuf tmp = STRBUF_INIT;\n+\tchar *git_contents = NULL;\n \tconst char *repair = NULL;\n \tint err;\n \n \t/* missing worktree can't be repaired */\n \tif (!file_exists(wt->path))\n-\t\treturn;\n+\t\tgoto done;\n \n \tif (!is_directory(wt->path)) {\n \t\tfn(1, wt->path, _(\"not a directory\"), cb_data);\n-\t\treturn;\n+\t\tgoto done;\n \t}\n \n \tstrbuf_realpath(&repo, git_common_path(\"worktrees/%s\", wt->id), 1);\n \tstrbuf_addf(&dotgit, \"%s/.git\", wt->path);\n-\tbacklink = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));\n+\tgit_contents = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));\n+\n+\tif (git_contents) {\n+\t\tif (is_absolute_path(git_contents)) {\n+\t\t\tstrbuf_addstr(&backlink, git_contents);\n+\t\t} else {\n+\t\t\tstrbuf_addf(&backlink, \"%s/%s\", wt->path, git_contents);\n+\t\t\tstrbuf_realpath_forgiving(&backlink, backlink.buf, 0);\n+\t\t}\n+\t}\n \n \tif (err == READ_GITFILE_ERR_NOT_A_FILE)\n \t\tfn(1, wt->path, _(\".git is not a file\"), cb_data);\n \telse if (err)\n \t\trepair = _(\".git file broken\");\n-\telse if (fspathcmp(backlink, repo.buf))\n+\telse if (fspathcmp(backlink.buf, repo.buf))\n \t\trepair = _(\".git file incorrect\");\n \n \tif (repair) {\n \t\tfn(0, wt->path, repair, cb_data);\n-\t\twrite_file(dotgit.buf, \"gitdir: %s\", repo.buf);\n+\t\twrite_file(dotgit.buf, \"gitdir: %s\", relative_path(repo.buf, wt->path, &tmp));\n \t}\n \n-\tfree(backlink);\n+done:\n+\tfree(git_contents);\n \tstrbuf_release(&repo);\n \tstrbuf_release(&dotgit);\n+\tstrbuf_release(&backlink);\n+\tstrbuf_release(&tmp);\n }\n \n static void repair_noop(int iserr UNUSED,\n@@ -681,6 +713,8 @@ void repair_worktree_at_path(const char *path,\n \tstruct strbuf backlink = STRBUF_INIT;\n \tstruct strbuf gitdir = STRBUF_INIT;\n \tstruct strbuf olddotgit = STRBUF_INIT;\n+\tstruct strbuf realolddotgit = STRBUF_INIT;\n+\tstruct strbuf tmp = STRBUF_INIT;\n \tchar *git_contents = NULL;\n \tconst char *repair = NULL;\n \tint err;\n@@ -710,97 +744,131 @@ void repair_worktree_at_path(const char *path,\n \t\tfn(1, realdotgit.buf, _(\"unable to locate repository; .git file broken\"), cb_data);\n \t\tgoto done;\n \t} else if (git_contents) {\n-\t\tstrbuf_addstr(&backlink, git_contents);\n+\t\tif (is_absolute_path(git_contents)) {\n+\t\t\tstrbuf_addstr(&backlink, git_contents);\n+\t\t} else {\n+\t\t\tstrbuf_addbuf(&backlink, &realdotgit);\n+\t\t\tstrbuf_strip_suffix(&backlink, \".git\");\n+\t\t\tstrbuf_addstr(&backlink, git_contents);\n+\t\t}\n \t}\n \n+\tstrbuf_realpath_forgiving(&backlink, backlink.buf, 0);\n \tstrbuf_addf(&gitdir, \"%s/gitdir\", backlink.buf);\n \tif (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)\n \t\trepair = _(\"gitdir unreadable\");\n \telse {\n \t\tstrbuf_rtrim(&olddotgit);\n-\t\tif (fspathcmp(olddotgit.buf, realdotgit.buf))\n+\t\tif (is_absolute_path(olddotgit.buf)) {\n+\t\t\tstrbuf_addbuf(&realolddotgit, &olddotgit);\n+\t\t} else {\n+\t\t\tstrbuf_addf(&realolddotgit, \"%s/%s\", backlink.buf, olddotgit.buf);\n+\t\t\tstrbuf_realpath_forgiving(&realolddotgit, realolddotgit.buf, 0);\n+\t\t}\n+\t\tif (fspathcmp(realolddotgit.buf, realdotgit.buf))\n \t\t\trepair = _(\"gitdir incorrect\");\n \t}\n \n \tif (repair) {\n \t\tfn(0, gitdir.buf, repair, cb_data);\n-\t\twrite_file(gitdir.buf, \"%s\", realdotgit.buf);\n+\t\twrite_file(gitdir.buf, \"%s\", relative_path(realdotgit.buf, backlink.buf, &tmp));\n \t}\n done:\n \tfree(git_contents);\n \tstrbuf_release(&olddotgit);\n+\tstrbuf_release(&realolddotgit);\n \tstrbuf_release(&backlink);\n \tstrbuf_release(&gitdir);\n \tstrbuf_release(&realdotgit);\n \tstrbuf_release(&dotgit);\n+\tstrbuf_release(&tmp);\n }\n \n int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath, timestamp_t expire)\n {\n \tstruct stat st;\n-\tchar *path;\n+\tstruct strbuf dotgit = STRBUF_INIT;\n+\tstruct strbuf gitdir = STRBUF_INIT;\n+\tstruct strbuf repo = STRBUF_INIT;\n+\tchar *path = NULL;\n+\tchar *file = NULL;\n+\tint rc = 0;\n \tint fd;\n \tsize_t len;\n \tssize_t read_result;\n \n \t*wtpath = NULL;\n-\tif (!is_directory(git_path(\"worktrees/%s\", id))) {\n+\tstrbuf_realpath(&repo, git_common_path(\"worktrees/%s\", id), 1);\n+\tstrbuf_addf(&gitdir, \"%s/gitdir\", repo.buf);\n+\tif (!is_directory(repo.buf)) {\n \t\tstrbuf_addstr(reason, _(\"not a valid directory\"));\n-\t\treturn 1;\n+\t\trc = 1;\n+\t\tgoto done;\n \t}\n-\tif (file_exists(git_path(\"worktrees/%s/locked\", id)))\n-\t\treturn 0;\n-\tif (stat(git_path(\"worktrees/%s/gitdir\", id), &st)) {\n+\tfile = xstrfmt(\"%s/locked\", repo.buf);\n+\tif (file_exists(file)) {\n+\t\tgoto done;\n+\t}\n+\tif (stat(gitdir.buf, &st)) {\n \t\tstrbuf_addstr(reason, _(\"gitdir file does not exist\"));\n-\t\treturn 1;\n+\t\trc = 1;\n+\t\tgoto done;\n \t}\n-\tfd = open(git_path(\"worktrees/%s/gitdir\", id), O_RDONLY);\n+\tfd = open(gitdir.buf, O_RDONLY);\n \tif (fd < 0) {\n \t\tstrbuf_addf(reason, _(\"unable to read gitdir file (%s)\"),\n \t\t\t    strerror(errno));\n-\t\treturn 1;\n+\t\trc = 1;\n+\t\tgoto done;\n \t}\n \tlen = xsize_t(st.st_size);\n \tpath = xmallocz(len);\n \n \tread_result = read_in_full(fd, path, len);\n+\tclose(fd);\n \tif (read_result < 0) {\n \t\tstrbuf_addf(reason, _(\"unable to read gitdir file (%s)\"),\n \t\t\t    strerror(errno));\n-\t\tclose(fd);\n-\t\tfree(path);\n-\t\treturn 1;\n-\t}\n-\tclose(fd);\n-\n-\tif (read_result != len) {\n+\t\trc = 1;\n+\t\tgoto done;\n+\t} else if (read_result != len) {\n \t\tstrbuf_addf(reason,\n \t\t\t    _(\"short read (expected %\"PRIuMAX\" bytes, read %\"PRIuMAX\")\"),\n \t\t\t    (uintmax_t)len, (uintmax_t)read_result);\n-\t\tfree(path);\n-\t\treturn 1;\n+\t\trc = 1;\n+\t\tgoto done;\n \t}\n \twhile (len && (path[len - 1] == '\\n' || path[len - 1] == '\\r'))\n \t\tlen--;\n \tif (!len) {\n \t\tstrbuf_addstr(reason, _(\"invalid gitdir file\"));\n-\t\tfree(path);\n-\t\treturn 1;\n+\t\trc = 1;\n+\t\tgoto done;\n \t}\n \tpath[len] = '\\0';\n-\tif (!file_exists(path)) {\n-\t\tif (stat(git_path(\"worktrees/%s/index\", id), &st) ||\n-\t\t    st.st_mtime <= expire) {\n+\tif (is_absolute_path(path)) {\n+\t\tstrbuf_addstr(&dotgit, path);\n+\t} else {\n+\t\tstrbuf_addf(&dotgit, \"%s/%s\", repo.buf, path);\n+\t\tstrbuf_realpath_forgiving(&dotgit, dotgit.buf, 0);\n+\t}\n+\tif (!file_exists(dotgit.buf)) {\n+\t\tfree(file);\n+\t\tfile = xstrfmt(\"%s/index\", repo.buf);\n+\t\tif (stat(file, &st) || st.st_mtime <= expire) {\n \t\t\tstrbuf_addstr(reason, _(\"gitdir file points to non-existent location\"));\n-\t\t\tfree(path);\n-\t\t\treturn 1;\n-\t\t} else {\n-\t\t\t*wtpath = path;\n-\t\t\treturn 0;\n+\t\t\trc = 1;\n+\t\t\tgoto done;\n \t\t}\n \t}\n-\t*wtpath = path;\n-\treturn 0;\n+\t*wtpath = strbuf_detach(&dotgit, NULL);\n+done:\n+\tfree(path);\n+\tfree(file);\n+\tstrbuf_release(&dotgit);\n+\tstrbuf_release(&gitdir);\n+\tstrbuf_release(&repo);\n+\treturn rc;\n }\n \n static int move_config_setting(const char *key, const char *value,\n-- \n2.46.2\n\n"},{"id":"504141","messageId":"20241006045847.159937-4-cdwhite3@pm.me","threadId":"62258","inReplyTo":"20241006045847.159937-1-cdwhite3@pm.me","subject":"[PATCH 3/4] worktree: sync worktree paths after gitdir move","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-10-06T04:59:38Z","receivedAt":"2024-10-06T04:59:45Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"When re-initializing a repository with a separate gitdir (the original\ngitdir is moved to a new location), any linked worktrees become broken\nand must be repaired to reflect the new gitdir location. For absolute\npaths, this breakage is one-way, but is both ways for relative paths\n(the `<worktree>/.git` and the `<repo>/worktrees/<id>/gitdir`).\n\nPreviously, `repair_worktrees` was being called which loops through all\nthe worktrees in the repository and updates the `<worktree>/.git` files\nto point to the new gitdir. However, when both sides of the worktrees\nare broken, the previous gitdir location is required to reestablish the\nlink.\n\nTo fix this, the function `repair_worktrees_after_gitdir_move` is\nintroduced. It takes the old gitdir path as an argument and repairs both\nsides of the worktree.\n\nThis change fixes the following test cases in t0001-init.sh:\n- re-init to move gitdir with linked worktrees\n- re-init to move gitdir within linked worktree\n\nSigned-off-by: Caleb \nWhite <cdwhite3@pm.me>\n---\n setup.c    |  2 +-\n worktree.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n worktree.h | 10 ++++++++++\n 3 files changed, 65 insertions(+), 1 deletion(-)\n\ndiff --git a/setup.c b/setup.c\nindex 94e79b2..7b648de 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -2420,7 +2420,7 @@ static void separate_git_dir(const char *git_dir, const char *git_link)\n \n \t\tif (rename(src, git_dir))\n \t\t\tdie_errno(_(\"unable to move %s to %s\"), src, git_dir);\n-\t\trepair_worktrees(NULL, NULL);\n+\t\trepair_worktrees_after_gitdir_move(src);\n \t}\n \n \twrite_file(git_link, \"gitdir: %s\", git_dir);\ndiff --git a/worktree.c b/worktree.c\nindex fc14e9a..b08ecce 100644\n--- a/worktree.c\n+++ b/worktree.c\n@@ -650,6 +650,60 @@ void repair_worktrees(worktree_repair_fn fn, void *cb_data)\n \tfree_worktrees(worktrees);\n }\n \n+void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path)\n+{\n+\tstruct strbuf path = STRBUF_INIT;\n+\tstruct strbuf repo = STRBUF_\nINIT;\n+\tstruct strbuf gitdir = STRBUF_INIT;\n+\tstruct strbuf dotgit = STRBUF_INIT;\n+\tstruct strbuf olddotgit = STRBUF_INIT;\n+\tstruct strbuf tmp = STRBUF_INIT;\n+\n+\tif (is_main_worktree(wt))\n+\t\tgoto done;\n+\n+\tstrbuf_realpath(&repo, git_common_path(\"worktrees/%s\", wt->id), 1);\n+\tstrbuf_addf(&gitdir, \"%s/gitdir\", repo.buf);\n+\n+\tif (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)\n+\t\tgoto done;\n+\n+\tstrbuf_rtrim(&olddotgit);\n+\tif (is_absolute_path(olddotgit.buf)) {\n+\t\tstrbuf_addbuf(&dotgit, &olddotgit);\n+\t} else {\n+\t\tstrbuf_addf(&dotgit, \"%s/worktrees/%s/%s\", old_path, wt->id, olddotgit.buf);\n+\t\tstrbuf_realpath_forgiving(&dotgit, dotgit.buf, 0);\n+\t}\n+\n+\tif (!file_exists(dotgit.buf))\n+\t\tgoto done;\n+\n+\tstrbuf_addbuf(&path, &dotgit);\n+\tstrbuf_strip_suffix(&path, \"/.git\");\n+\n+\twrite_file(dotgit.buf, \"gitdir: %s\", relative_path(repo.buf, path.buf, &tmp));\n+\tstrbuf_reset(&tmp);\n+\twrite_file(gitdir.buf, \"%s\", relative_path(dotgit.buf, repo.buf, &tmp));\n+done:\n+\tstrbu\nf_release(&path);\n+\tstrbuf_release(&repo);\n+\tstrbuf_release(&gitdir);\n+\tstrbuf_release(&dotgit);\n+\tstrbuf_release(&olddotgit);\n+\tstrbuf_release(&tmp);\n+}\n+\n+void repair_worktrees_after_gitdir_move(const char *old_path)\n+{\n+\tstruct worktree **worktrees = get_worktrees_internal(1);\n+\tstruct worktree **wt = worktrees + 1; /* +1 skips main worktree */\n+\n+\tfor (; *wt; wt++)\n+\t\trepair_worktree_after_gitdir_move(*wt, old_path);\n+\tfree_worktrees(worktrees);\n+}\n+\n static int is_main_worktree_path(const char *path)\n {\n \tstruct strbuf target = STRBUF_INIT;\ndiff --git a/worktree.h b/worktree.h\nindex 11279d0..e961186 100644\n--- a/worktree.h\n+++ b/worktree.h\n@@ -131,6 +131,16 @@ typedef void (* worktree_repair_fn)(int iserr, const char *path,\n  */\n void repair_worktrees(worktree_repair_fn, void *cb_data);\n \n+/*\n+ * Repair the linked worktrees after the gitdir has been moved.\n+ */\n+void repair_worktrees_after_gitdir_move(const char *old_path);\n+\n+/*\n+ * Repair the l\ninked worktree after the gitdir has been moved.\n+ */\n+void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path);\n+\n /*\n  * Repair administrative files corresponding to the worktree at the given path.\n  * The worktree's .git file pointing at the repository must be intact for the\n-- \n2.46.2\n\n"},{"id":"504143","messageId":"20241006045847.159937-5-cdwhite3@pm.me","threadId":"62258","inReplyTo":"20241006045847.159937-1-cdwhite3@pm.me","subject":"[PATCH 4/4] worktree: prevent null pointer dereference","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-10-06T04:59:46Z","receivedAt":"2024-10-06T04:59:54Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"If worktrees is NULL, free_worktrees() should return immediately to\nprevent a null pointer dereference.\n\nSigned-off-by: Caleb White <cdwhite3@pm.me>\n---\n worktree.c | 5 +++--\n 1 file changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/worktree.c b/worktree.c\nindex b08ecce..1cf15b0 100644\n--- a/worktree.c\n+++ b/worktree.c\n@@ -28,8 +28,9 @@ void free_worktree(struct worktree *worktree)\n \n void free_worktrees(struct worktree **worktrees)\n {\n-\tint i = 0;\n-\tfor (i = 0; worktrees[i]; i++)\n+\tif  (!worktrees)\n+\t\treturn;\n+\tfor (int i = 0; worktrees[i]; i++)\n \t\tfree_worktree(worktrees[i]);\n \tfree (worktrees);\n }\n-- \n2.46.2\n\n"},{"id":"504144","messageId":"CAPig+cTB-sA-g4cdhfEjWwY1mnbWJ41e=bOCNwp=Y8JKvpmpRg@mail.gmail.com","threadId":"62258","inReplyTo":"20241006045847.159937-1-cdwhite3@pm.me","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2024-10-06T05:04:46Z","receivedAt":"2024-10-06T05:04:58Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Oct 6, 2024 at 12:59 AM Caleb White <cdwhite3@pm.me> wrote:\n> This patch series modifies Git's handling of worktree linking to use\n> relative paths instead of absolute paths. The motivation behind this\n> change is to enhance the robustness of worktree links when the main\n> repository is moved, or when used in environments like containerized\n> development where absolute paths differ across systems.\n> [...]\n> Caleb White (4):\n>   worktree: refactor infer_backlink() to use *strbuf\n>   worktree: link worktrees with relative paths\n>   worktree: sync worktree paths after gitdir move\n>   worktree: prevent null pointer dereference\n\nUnfortunately, these patches are whitespace-damaged. Can you please\nresubmit using either `git send-email` or GitGitGadget[1]?\n\n[1]: https://gitgitgadget.github.io/\n"},{"id":"504145","messageId":"zKUnWY8u1SJNeS4oLK85znjacgYJJeN8HefenwaJ9B9Q1YrQAumpAxWos4svaawkTfQZ_HaS3yp6WrOQQI7yt3ZO0UMCfkM0lJDDnMD-Lno=@pm.me","threadId":"62258","inReplyTo":"CAPig+cTB-sA-g4cdhfEjWwY1mnbWJ41e=bOCNwp=Y8JKvpmpRg@mail.gmail.com","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-10-06T05:11:28Z","receivedAt":"2024-10-06T05:11:34Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"On Sunday, October 6th, 2024 at 00:04, Eric Sunshine <sunshine@sunshineco.com> wrote:\n\n> On Sun, Oct 6, 2024 at 12:59 AM Caleb White cdwhite3@pm.me wrote:\n> \n\n> > This patch series modifies Git's handling of worktree linking to use\n> > relative paths instead of absolute paths. The motivation behind this\n> > change is to enhance the robustness of worktree links when the main\n> > repository is moved, or when used in environments like containerized\n> > development where absolute paths differ across systems.\n> > [...]\n> > Caleb White (4):\n> > worktree: refactor infer_backlink() to use *strbuf\n> > worktree: link worktrees with relative paths\n> > worktree: sync worktree paths after gitdir move\n> > worktree: prevent null pointer dereference\n> \n\n> \n\n> Unfortunately, these patches are whitespace-damaged. Can you please\n> resubmit using either `git send-email` or GitGitGadget[1]?\n> \n\n> [1]: https://gitgitgadget.github.io/\n\nI sent them with `git send-email`, let me try again and then if that\ndoesn't work then I'll try GitGitGadget. Just out of curiosity, how\ncould you tell that they are whitespaced-damaged (so I know what to\nlook for)?\n\nThanks,"},{"id":"504146","messageId":"CAPig+cTVbXVffSeyNAV3c0zuSUozY7giWtMw3GpHs+xVEpaNvA@mail.gmail.com","threadId":"62258","inReplyTo":"CAPig+cTB-sA-g4cdhfEjWwY1mnbWJ41e=bOCNwp=Y8JKvpmpRg@mail.gmail.com","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2024-10-06T05:11:35Z","receivedAt":"2024-10-06T05:11:46Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Oct 6, 2024 at 1:04 AM Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Sun, Oct 6, 2024 at 12:59 AM Caleb White <cdwhite3@pm.me> wrote:\n> > This patch series modifies Git's handling of worktree linking to use\n> > relative paths instead of absolute paths. The motivation behind this\n> > change is to enhance the robustness of worktree links when the main\n> > repository is moved, or when used in environments like containerized\n> > development where absolute paths differ across systems.\n>\n> Unfortunately, these patches are whitespace-damaged. Can you please\n> resubmit using either `git send-email` or GitGitGadget[1]?\n\nAlso, since you're touching infer_backlink(), see [1] which makes some\nchanges nearby.\n\nAnd you might be interested in [2] which may indicate that there are\nsome holes in the tests around worktrees which might need filling.\n(Since your patches are whitespace-damaged, I haven't checked whether\nyour series succeeds or fails in the way the series to which [2] is a\nresponse fails.)\n\n[1]: https://lore.kernel.org/git/20240923075416.54289-1-ericsunshine@charter.net/\n[2]: https://lore.kernel.org/git/CAPig+cQXFy=xPVpoSq6Wq0pxMRCjS=WbkgdO+3LySPX=q0nPCw@mail.gmail.com/\n"},{"id":"504147","messageId":"CAPig+cT6LALKjEappB7QkB7oc88NyMcr40T_qJGL2mPA77K7XQ@mail.gmail.com","threadId":"62258","inReplyTo":"zKUnWY8u1SJNeS4oLK85znjacgYJJeN8HefenwaJ9B9Q1YrQAumpAxWos4svaawkTfQZ_HaS3yp6WrOQQI7yt3ZO0UMCfkM0lJDDnMD-Lno=@pm.me","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2024-10-06T05:14:43Z","receivedAt":"2024-10-06T05:14:54Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Oct 6, 2024 at 1:11 AM Caleb White <cdwhite3@pm.me> wrote:\n> On Sunday, October 6th, 2024 at 00:04, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> > Unfortunately, these patches are whitespace-damaged. Can you please\n> > resubmit using either `git send-email` or GitGitGadget[1]?\n>\n> I sent them with `git send-email`, let me try again and then if that\n> doesn't work then I'll try GitGitGadget. Just out of curiosity, how\n> could you tell that they are whitespaced-damaged (so I know what to\n> look for)?\n\nHmm, that's very strange; git-send-email shouldn't be damaging them like that.\n\nI noticed the whitespace-damage just by visual inspection as I quickly\nscanned my eyes over the patches. For instance, in patch [1/4], I see:\n\n    + struct strbuf backlink = STRBUF_INIT;\n       struct strbuf gitd\n    ir = STRBUF_INIT;\n\nThe \"gitdir\" variable got split.\n"},{"id":"504148","messageId":"CAPig+cT7CEnb6cQmAOMbD82wxkg=7T0MMW=QNUSPU62a0rEGLA@mail.gmail.com","threadId":"62258","inReplyTo":"CAPig+cT6LALKjEappB7QkB7oc88NyMcr40T_qJGL2mPA77K7XQ@mail.gmail.com","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2024-10-06T05:16:21Z","receivedAt":"2024-10-06T05:16:33Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Oct 6, 2024 at 1:14 AM Eric Sunshine <sunshine@sunshineco.com> wrote:\n> I noticed the whitespace-damage just by visual inspection as I quickly\n> scanned my eyes over the patches. For instance, in patch [1/4], I see:\n>\n>     + struct strbuf backlink = STRBUF_INIT;\n>        struct strbuf gitd\n>     ir = STRBUF_INIT;\n>\n> The \"gitdir\" variable got split.\n\nMaybe \"whitespace-damaged\" was the wrong terminology. They are\nincorrectly wrapped/line-split.\n"},{"id":"504152","messageId":"K1lpl_AWj4xpiHLG9AloFDP7hkJ7Ysf-LA5H-OeP6suaBcES3WS6NTYZGX96oQuNQ3x36eEOxGdqlj3fG3ybrn5y3LRPfCNqC7yqTyvqVrk=@pm.me","threadId":"62258","inReplyTo":"CAPig+cTE0gaD=7dwSqY4S+7AqRoU9yOrS4sdBoybj0Pfyk9vxA@mail.gmail.com","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-10-06T05:41:25Z","receivedAt":"2024-10-06T05:41:35Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"On Sunday, October 6th, 2024 at 00:32, Eric Sunshine <sunshine@sunshineco.com> wrote:\n\n> On Sun, Oct 6, 2024 at 1:21 AM Caleb White cdwhite3@pm.me wrote:\n> \n\n> > On Sunday, October 6th, 2024 at 00:16, Eric Sunshine sunshine@sunshineco.com wrote:\n> > \n\n> > > > + struct strbuf backlink = STRBUF_INIT;\n> > > > struct strbuf gitd\n> > > > ir = STRBUF_INIT;\n> > \n\n> > That's strange, the code came through just fine on my end:\n> \n\n> \n\n> It's broken in the Git mailing list archive, as well. If you search\n> for \"mbox.gz\" at [], you can download this email thread. The patches\n> in that mbox file have the same damage as I'm seeing.\n> \n\n> [] https://lore.kernel.org/git/CAPig+cTVbXVffSeyNAV3c0zuSUozY7giWtMw3GpHs+xVEpaNvA@mail.gmail.com/T/\n\nThat's interesting...what's the best way to try and resubmit? As\na new thread or as a v2?"},{"id":"504154","messageId":"CAPig+cQE0RNLhktuja-BbF8WwZmKC3cox_GUC-o4w87PadDpgw@mail.gmail.com","threadId":"62258","inReplyTo":"K1lpl_AWj4xpiHLG9AloFDP7hkJ7Ysf-LA5H-OeP6suaBcES3WS6NTYZGX96oQuNQ3x36eEOxGdqlj3fG3ybrn5y3LRPfCNqC7yqTyvqVrk=@pm.me","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2024-10-06T05:50:54Z","receivedAt":"2024-10-06T05:51:06Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Oct 6, 2024 at 1:41 AM Caleb White <cdwhite3@pm.me> wrote:\n> On Sunday, October 6th, 2024 at 00:32, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> > It's broken in the Git mailing list archive, as well. If you search\n> > for \"mbox.gz\" at [], you can download this email thread. The patches\n> > in that mbox file have the same damage as I'm seeing.\n>\n> That's interesting...what's the best way to try and resubmit? As\n> a new thread or as a v2?\n\nFor continuity in the archive, probably best to submit it as v2 as a\nreply to the original cover letter:\n\n    git send-email -v2 --reply-to='20241006045847.159937-1-cdwhite3@pm.me' ...\n"},{"id":"504161","messageId":"gX8RNUg1e1FCYFS1vP-uT4rbMpg21Ax07CZm5Ha7Dsk93EN6CTuXiLr3boTaoNEi71O1rDoUxhTs6KQt7Cvfz7B3KlbpZzis5b05KW7ARls=@pm.me","threadId":"62258","inReplyTo":"CAPig+cQE0RNLhktuja-BbF8WwZmKC3cox_GUC-o4w87PadDpgw@mail.gmail.com","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-10-06T06:05:25Z","receivedAt":"2024-10-06T06:05:29Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"On Sunday, October 6th, 2024 at 00:50, Eric Sunshine <sunshine@sunshineco.com> wrote:\n\n> On Sun, Oct 6, 2024 at 1:41 AM Caleb White cdwhite3@pm.me wrote:\n> \n\n> > On Sunday, October 6th, 2024 at 00:32, Eric Sunshine sunshine@sunshineco.com wrote:\n> > \n\n> > > It's broken in the Git mailing list archive, as well. If you search\n> > > for \"mbox.gz\" at [], you can download this email thread. The patches\n> > > in that mbox file have the same damage as I'm seeing.\n> > \n\n> > That's interesting...what's the best way to try and resubmit? As\n> > a new thread or as a v2?\n> \n\n> \n\n> For continuity in the archive, probably best to submit it as v2 as a\n> reply to the original cover letter:\n> \n\n> git send-email -v2 --reply-to='20241006045847.159937-1-cdwhite3@pm.me' ...\n\nThanks, I regenerated v2 patches with `format-patch` and then sent with\n`send-email`. However, the issue seems to have persisted (at least it's\nconsistent?). I looked through the the patches on the listserv and that\nseems to be the only location where this occurs."},{"id":"504162","messageId":"CAPig+cR4FXsGDE9Uu04EjK+vOo-Pi_VwOub8+Dy3r9t7z8GdkQ@mail.gmail.com","threadId":"62258","inReplyTo":"gX8RNUg1e1FCYFS1vP-uT4rbMpg21Ax07CZm5Ha7Dsk93EN6CTuXiLr3boTaoNEi71O1rDoUxhTs6KQt7Cvfz7B3KlbpZzis5b05KW7ARls=@pm.me","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2024-10-06T06:16:56Z","receivedAt":"2024-10-06T06:17:07Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Oct 6, 2024 at 2:05 AM Caleb White <cdwhite3@pm.me> wrote:\n> On Sunday, October 6th, 2024 at 00:50, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> > For continuity in the archive, probably best to submit it as v2 as a\n> > reply to the original cover letter:\n> > git send-email -v2 --reply-to='20241006045847.159937-1-cdwhite3@pm.me' ...\n>\n> Thanks, I regenerated v2 patches with `format-patch` and then sent with\n> `send-email`. However, the issue seems to have persisted (at least it's\n> consistent?). I looked through the the patches on the listserv and that\n> seems to be the only location where this occurs.\n\nIndeed, I'm seeing the same line-wrapping breakage in the mailing list\narchive and in my Inbox for v2.\n\nI presume that you've verified that the raw patches are not broken\nlike that, and that the problem is happening at email time?\n"},{"id":"504164","messageId":"AtSpzKynOkmMPZ3bR4qx-eA93Xo-1miPCIQSxIKP534tD-qpDU1AI74vqB78RsukQ0XP5eKdvzHcwy_lf8lpL9wAoHoom-koo5GKcbrcuX0=@pm.me","threadId":"62258","inReplyTo":"CAPig+cR4FXsGDE9Uu04EjK+vOo-Pi_VwOub8+Dy3r9t7z8GdkQ@mail.gmail.com","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-10-06T06:23:12Z","receivedAt":"2024-10-06T06:23:18Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"On 10/6/24 01:16, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>  Indeed, I'm seeing the same line-wrapping breakage in the mailing list\n>  archive and in my Inbox for v2.\n>  \n>  I presume that you've verified that the raw patches are not broken\n>  like that, and that the problem is happening at email time?\n\nYes, I've checked the patch files and they are good. I'm also not seeing any breakages in my inbox which is strange.\n"},{"id":"504168","messageId":"CAPig+cQZmEdx1Th9VAHbEkJ=zm73TP7Wuda_G5CzFw7j9HTFQQ@mail.gmail.com","threadId":"62258","inReplyTo":"AtSpzKynOkmMPZ3bR4qx-eA93Xo-1miPCIQSxIKP534tD-qpDU1AI74vqB78RsukQ0XP5eKdvzHcwy_lf8lpL9wAoHoom-koo5GKcbrcuX0=@pm.me","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2024-10-06T07:45:13Z","receivedAt":"2024-10-06T07:45:25Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Oct 6, 2024 at 2:23 AM Caleb White <cdwhite3@pm.me> wrote:\n> On 10/6/24 01:16, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> >  Indeed, I'm seeing the same line-wrapping breakage in the mailing list\n> >  archive and in my Inbox for v2.\n> >\n> >  I presume that you've verified that the raw patches are not broken\n> >  like that, and that the problem is happening at email time?\n>\n> Yes, I've checked the patch files and they are good. I'm also not seeing any breakages in my inbox which is strange.\n\nI've been trying to hand-edit v2 to fix the breakage in order to get\nit applied, but I'm not having much success. I did manage to get patch\n[1/4] applied, but patch [2/4] is base64-encoded for some reason (you\ncan see it here[*]), so I haven't been able to edit it easily in order\nto fix the breakage. `git am` isn't particularly happy with it either;\nit complains:\n\n    % git am PATCH-v2-0-4-Link-worktrees-with-relative-paths.mbox\n    Applying: worktree: refactor infer_backlink() to use *strbuf\n    warning: quoted CRLF detected\n    Applying: worktree: link worktrees with relative paths\n    .git/rebase-apply/patch:60: trailing whitespace.\n    #!/bin/sh\n    .git/rebase-apply/patch:61: trailing whitespace.\n    .git/rebase-apply/patch:62: trailing whitespace.\n    test_description='test worktrees linked with relative paths'\n    .git/rebase-apply/patch:63: trailing whitespace.\n    .git/rebase-apply/patch:64: trailing whitespace.\n    TEST_PASSES_SANITIZE_LEAK=true\n    error: patch failed: builtin/worktree.c:414\n    error: builtin/worktree.c: patch does not apply\n    error: patch failed: worktree.c:110\n    error: worktree.c: patch does not apply\n    Patch failed at 0002 worktree: link worktrees with relative paths\n\nCan you try GitGitGadget instead (preferable) or perhaps publish this\nseries somewhere (less preferable).\n\n[*]: https://lore.kernel.org/git/20241006060017.171788-3-cdwhite3@pm.me/raw\n"},{"id":"504171","messageId":"4bbe8ceb-2e72-463a-81a0-138815a1cf8c@app.fastmail.com","threadId":"62258","inReplyTo":"CAPig+cQZmEdx1Th9VAHbEkJ=zm73TP7Wuda_G5CzFw7j9HTFQQ@mail.gmail.com","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Kristoffer Haugsbakk","fromEmail":"kristofferhaugsbakk@fastmail.com","sentAt":"2024-10-06T09:00:43Z","receivedAt":"2024-10-06T09:01:04Z","isPatch":true,"sender":{"key":"kristofferhaugsbakk@fastmail.com","avatar":null},"body":"On Sun, Oct 6, 2024, at 09:45, EricSunshine wrote:\n> Can you try GitGitGadget instead (preferable) or perhaps publish this\n> series somewhere (less preferable).\n>\n> [*]: https://lore.kernel.org/git/20241006060017.171788-3-cdwhite3@pm.me/raw\n\nIf Caleb gives us a clone link then I could try to send.\n"},{"id":"504206","messageId":"gZ9_OcXpHKqABP0c_FH7EVpjzCD92RASyYoDkrhhrxzrbKvx5duIaXIrVOK45bmglyrLHrQ6SR4YVtMwU6BGqw1_TWs7rHk_lNderVONljY=@pm.me","threadId":"62258","inReplyTo":"CAPig+cTVbXVffSeyNAV3c0zuSUozY7giWtMw3GpHs+xVEpaNvA@mail.gmail.com","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-10-06T22:01:41Z","receivedAt":"2024-10-06T22:01:52Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"On Sunday, October 6th, 2024 at 00:11, Eric Sunshine <sunshine@sunshineco.com> wrote:\n \n\n> Also, since you're touching infer_backlink(), see [1] which makes some\n> changes nearby.\n> [1]: https://lore.kernel.org/git/20240923075416.54289-1-ericsunshine@charter.net/\n\n\nThanks for the heads up, what is the best way to move forward on this?\nShould I base my patch series on that topic branch or bring in that\nparticular patch?\n\n> And you might be interested in [2] which may indicate that there are\n> some holes in the tests around worktrees which might need filling.\n> (Since your patches are whitespace-damaged, I haven't checked whether\n> your series succeeds or fails in the way the series to which [2] is a\n> response fails.)\n> [2]: https://lore.kernel.org/git/CAPig+cQXFy=xPVpoSq6Wq0pxMRCjS=WbkgdO+3LySPX=q0nPCw@mail.gmail.com/\n\nI just ran through the scenarios you described and everything works as\nyou would expect. This is because internally the code handles both\nabsolute and relative paths, and the worktree.path has been updated to\nalways be the absolute path. I will make this clear when I rewrite that\npatch's commit message."},{"id":"504207","messageId":"w7hncKNNAlJFs7fyi_ZzMj8iNF-GMgbm3E-7Wit9qUey2FDVTwj0CKg_Youi3mPpOcBvDEWyVEaeryeL10LqAY002FdBxBpi7zTQervXgyM=@pm.me","threadId":"62258","inReplyTo":"CAPig+cQZmEdx1Th9VAHbEkJ=zm73TP7Wuda_G5CzFw7j9HTFQQ@mail.gmail.com","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-10-06T22:08:34Z","receivedAt":"2024-10-06T22:08:41Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"On Sunday, October 6th, 2024 at 02:45, Eric Sunshine <sunshine@sunshineco.com> wrote:\n\n> Can you try GitGitGadget instead (preferable) or perhaps publish this\n> series somewhere (less preferable).\n\nI just created a GGG PR [1], can someone please give me /access? I will\nintegrate the changes requested before I send out the v3 series through GGG.\n\nSpeaking of which, is there a way to tell GGG that I want to start on v3 to\nkeep the continuity? I suppose I could always just reference the other versions\nin the PR body but I wasn't sure if there were other commands available besides\njust `/submit`.\n\n[1]: https://github.com/gitgitgadget/git/pull/1808"},{"id":"504208","messageId":"HQHFMbnFwMCxJ6lusWsy7qEnWtEwYovUv7x59Jh0BmuSjJyKiM7IbPOivNmLvA_9mm_YqxDfVfzqf2rUeixky-XApO2FdVeo48YR8O1_8WI=@pm.me","threadId":"62258","inReplyTo":"4bbe8ceb-2e72-463a-81a0-138815a1cf8c@app.fastmail.com","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-10-06T22:10:05Z","receivedAt":"2024-10-06T22:10:12Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"On Sunday, October 6th, 2024 at 04:00, Kristoffer Haugsbakk <kristofferhaugsbakk@fastmail.com> wrote:\n\n> If Caleb gives us a clone link then I could try to send.\n\nHere it is!\n\n[1]: https://github.com/gitgitgadget/git/pull/1808"},{"id":"504209","messageId":"CAPig+cS06E1xjM6asqF9-5KSSgGaVQgF2_QdYSziSPJ-5mRSBg@mail.gmail.com","threadId":"62258","inReplyTo":"gZ9_OcXpHKqABP0c_FH7EVpjzCD92RASyYoDkrhhrxzrbKvx5duIaXIrVOK45bmglyrLHrQ6SR4YVtMwU6BGqw1_TWs7rHk_lNderVONljY=@pm.me","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2024-10-06T22:19:34Z","receivedAt":"2024-10-06T22:19:46Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Oct 6, 2024 at 6:01 PM Caleb White <cdwhite3@pm.me> wrote:\n> On Sunday, October 6th, 2024 at 00:11, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> > Also, since you're touching infer_backlink(), see [1] which makes some\n> > changes nearby.\n> > [1]: https://lore.kernel.org/git/20240923075416.54289-1-ericsunshine@charter.net/\n>\n> Thanks for the heads up, what is the best way to move forward on this?\n> Should I base my patch series on that topic branch or bring in that\n> particular patch?\n\nIf that particular patch impacts your patch series in a way which\nwould require Junio (or any reviewer who wants to test your series) to\nmake non-trivial changes to resolve merge conflicts, then it would\nprobably be best to base your series atop that one (rather than\nbringing that patch into your series). When composing the cover\nmaterial for your series, be sure to mention that you have based your\nseries atop that patch.\n\n> > And you might be interested in [2] which may indicate that there are\n> > some holes in the tests around worktrees which might need filling.\n> > (Since your patches are whitespace-damaged, I haven't checked whether\n> > your series succeeds or fails in the way the series to which [2] is a\n> > response fails.)\n> > [2]: https://lore.kernel.org/git/CAPig+cQXFy=xPVpoSq6Wq0pxMRCjS=WbkgdO+3LySPX=q0nPCw@mail.gmail.com/\n>\n> I just ran through the scenarios you described and everything works as\n> you would expect. This is because internally the code handles both\n> absolute and relative paths, and the worktree.path has been updated to\n> always be the absolute path. I will make this clear when I rewrite that\n> patch's commit message.\n\nThanks.\n"},{"id":"504210","messageId":"CAPig+cRzvKddHsqahndU-pnScqNB9tL1KR-XBBGB6wx6U9v40w@mail.gmail.com","threadId":"62258","inReplyTo":"w7hncKNNAlJFs7fyi_ZzMj8iNF-GMgbm3E-7Wit9qUey2FDVTwj0CKg_Youi3mPpOcBvDEWyVEaeryeL10LqAY002FdBxBpi7zTQervXgyM=@pm.me","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2024-10-06T22:24:56Z","receivedAt":"2024-10-06T22:25:08Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Oct 6, 2024 at 6:08 PM Caleb White <cdwhite3@pm.me> wrote:\n> On Sunday, October 6th, 2024 at 02:45, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> > Can you try GitGitGadget instead (preferable) or perhaps publish this\n> > series somewhere (less preferable).\n>\n> I just created a GGG PR [1], can someone please give me /access?\n\nDone.\n\n> Speaking of which, is there a way to tell GGG that I want to start on v3 to\n> keep the continuity? I suppose I could always just reference the other versions\n> in the PR body but I wasn't sure if there were other commands available besides\n> just `/submit`.\n\nUm, I'm not a GitGitGadget user, so I can't say definitively, but I\ndon't believe there is a way to do that.\n\nReferencing the previous versions is always appreciated by reviewers\nanyhow since it makes their task simpler. In particular, in the cover\ncommentary for any given version, reviewers like to see an explanation\nof the series, references to previous versions, and a prose\ndescription of what has changed in the current version as compared\nwith the previous version. Reviewers also really appreciate seeing a\nmechanically-generated difference between versions, such as generated\nby `git format-patch --cover-letter --range-diff=...`, or generated\nautomatically by GitGitGadget.\n"},{"id":"504211","messageId":"ybfcgODkgeT2Oad2eQmXxyDtJEE04nlFjlM42VdfDgPbgHJc6FAEeOHcYNDmdyaN0H5YtnTD_tCq77m690t0WYbpSzUe3OcFnFAAY-2sKWA=@pm.me","threadId":"62258","inReplyTo":"CAPig+cRzvKddHsqahndU-pnScqNB9tL1KR-XBBGB6wx6U9v40w@mail.gmail.com","subject":"Re: [PATCH 0/4] Link worktrees with relative paths","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-10-06T22:32:39Z","receivedAt":"2024-10-06T22:32:46Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"On Sunday, October 6th, 2024 at 17:24, Eric Sunshine <sunshine@sunshineco.com> wrote:\n\n> On Sun, Oct 6, 2024 at 6:08 PM Caleb White cdwhite3@pm.me wrote:\n> > I just created a GGG PR [1], can someone please give me /access?\n> \n\n> Done.\n\nThank you!\n\n> Referencing the previous versions is always appreciated by reviewers\n> anyhow since it makes their task simpler. In particular, in the cover\n> commentary for any given version, reviewers like to see an explanation\n> of the series, references to previous versions, and a prose\n> description of what has changed in the current version as compared\n> with the previous version. Reviewers also really appreciate seeing a\n> mechanically-generated difference between versions, such as generated\n> by `git format-patch --cover-letter --range-diff=...`, or generated\n> automatically by GitGitGadget.\n\nThanks for the info, I'll make sure to include that in the PR."}]}