Support relative worktree paths (git 2.48+ worktree.useRelativePaths)#2151
Support relative worktree paths (git 2.48+ worktree.useRelativePaths)#2151elovelan wants to merge 2 commits into
Conversation
Git 2.48 introduced the `worktree.useRelativePaths` config option, which causes `git worktree add` to write a relative `gitdir` into the worktree's `.git` file. Resolve the relative `gitdir` against the worktree directory before before expanding it. Absolute paths are unaffected because `os.path.join` ignores the prefix when joined with an absolute path.
There was a problem hiding this comment.
Pull request overview
This PR updates GitPython’s worktree discovery to correctly resolve relative gitdir: paths written into worktree .git files when Git 2.48+ is configured with worktree.useRelativePaths.
Changes:
- Resolve worktree
.gitfilegitdir:entries relative to the directory containing the.gitfile before expanding/normalizing. - Add a new test that exercises
git worktree add --relative-pathson Git 2.48+. - Fix a command-construction example in
Git._call_processdocstring.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
git/repo/base.py |
Resolves worktree gitdir: paths relative to the worktree directory to support Git 2.48+ relative paths. |
test/test_repo.py |
Adds coverage for relative worktree gitdir: behavior via git worktree add --relative-paths. |
git/cmd.py |
Corrects a docstring example of how kwargs map to CLI flags. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # worktrees can use relative paths as of Git 2.48, so we join to curpath | ||
| git_dir = expand_path(osp.join(curpath, sm_gitpath), expand_vars) |
There was a problem hiding this comment.
This fix won't work because it's doing the same thing as the original code (because expand_path calls osp.abspath). To do this properly, I'd have to create a copy of expand_path that doesn't call osp.abspath, or add a flag to the existing function.
@Byron, I was double checking how Git handles this and it turns out it doesn't do ~ and env var expansion, it only does the equivalent of osp.normpath via strbuf_realpath. I'm wondering if GitPython should match, which means my existing code will work by replacing the call to expand_path with osp.normpath. Or should I do what I mentioned above and use expand_path (without its call to osp.abspath) just in case Git decides to support expansions of the gitdir in the future?
| @skipIf( | ||
| Git().version_info[:3] < (2, 48, 0), | ||
| reason="relative worktree feature unsupported (needs git 2.48.0 or later)", | ||
| ) |
There was a problem hiding this comment.
this is a good suggestion. It's also done at test_index_mutation so I'll open a separate PR to fix that as well.
Byron
left a comment
There was a problem hiding this comment.
Thanks a lot, looks good to me!
Could you take a look at the co-pilot suggestions though?
Once resolved, this PR can be merged.
Summary
Git 2.48 introduced the
worktree.useRelativePathsconfig option. When enabled,git worktree addwrites a relativegitdir:into the worktree's.gitfile — relative to the directory containing that.gitfile.GitPython's
Repo.__init__previously passed the value of thatgitdir:line straight throughexpand_path, which callsos.path.abspathagainst the process's current working directory rather than against the worktree. Using the library when the cwd was not the worktree root therefore failed.This change resolves the relative
gitdiragainstcurpath(the directory containing the.gitfile) before expanding. Absolute paths — i.e. the pre-2.48 default — are unaffected, becauseos.path.joinignores its first argument when the second is absolute.This change also includes a minor doc fix that I came across when trying to better understand how git is called.
Test plan
TestRepo.test_git_work_tree_dotgit_relative, which delegates totest_git_work_tree_dotgitbut runsgit worktree add --relative-paths. I verified that the test failed before implementation and now passes.test_git_work_tree_dotgitstill passes, confirming absolute-path worktrees are unaffected.AI disclosure
Per
CONTRIBUTING.md: this PR description and the commit message were drafted by Claude Code on behalf of @elovelan; though the final versions were manually reworded for clarity. All code was written without AI (didn't start that way but I didn't like its test implementation, and the actual implementation was trivial).