Reputation: 834
I have a master
and a setup
branch in my repo. I'm keeping the setup
branch checked out as a worktree inside the main repo folder via
git worktree add ./local/setup
echo '/local' > .gitignore
So the main repo folder is on master
, and the local/setup
folder is on setup
. Everything is fine and dandy, I can work on my setup
files without having to switch branches, I can commit from within local/setup
etc.
But if I try to move the entire repo, or access it from a different Linux boot (/home/myrepo
becomes /mnt/ubu/home/myrepo
), things break. The problem seems to be that git
's worktree functionality records absolute paths, in
myrepo/.git/worktrees/setup/gitdir
myrepo/local/setup/.git
Can I convert these to relative paths to make the repo + embedded worktree relocatable? I'm not sure what the paths in those files should be relative to, but I can experiment. Is this setup dangerous?
Upvotes: 18
Views: 3808
Reputation: 1324218
Can I convert these to relative paths to make the repo + embedded worktree relocatable?
Yes, with git worktree repair
and a recent enough Git.
Git 2.48 (Q1 2025), batch 16, introduces a new repository extension to prevent older Git versions from mis-interpreting worktrees created with relative paths.
See commit 2037ca8, commit e6df1ee, commit 298d291, commit b701634, commit 4dac9e3, commit 5976310, commit 1860ba1, commit d897f2c (29 Nov 2024) by Caleb White (calebdw
).
(Merged by Junio C Hamano -- gitster
-- in commit 3b11c91, 13 Dec 2024)
worktree
: add relative cli/config options torepair
commandSigned-off-by: Caleb White
This teaches the
worktree repair
command to respect the--[no-]relative-paths
CLI option andworktree.useRelativePaths
config setting.
If an existing worktree with an absolute path is repaired with--relative-paths
, the links will be replaced with relative paths, even if the original path was correct.
This allows a user to covert existing worktrees between absolute/relative as desired.To simplify things, both linking files are written when one of the files needs to be repaired.
In some cases, this fixes the other file before it is checked, in other cases this results in a correct file being written with the same contents.
git worktree
now includes in its man page:
With
repair
, the linking files will be updated if there's an absolute/relative mismatch, even if the links are correct.
Upvotes: 1
Reputation: 54869
Relative paths can be specified in the worktree '.git' file by replacing the absolute path with a relative one.
Below is an example for the typical case where the gitdir
is under ../.git
(includes optional sed
scripting):
$ sed 's/ \/.*\/.git/ ..\/.git/' .git
gitdir: ../.git/worktrees/mybranch
Use sed --in-place
to modify the '.git' file in place or sed --in-place=.old
to also save the original.
To use git worktree
commands, you need to be concerned about the paths indicated by git worktree list
. In some cases, these may need to be absolute paths. To update these paths, you can manually modify the associated 'gitdir' files (under '.git/worktree/mybranch').
Introduced in Git 2.29, there is also a handy option called git worktree repair
(docs):
Repair working tree administrative files, if possible, if they have become corrupted or outdated due to external factors.
For instance, if the main working tree (or bare repository) is moved, linked working trees will be unable to locate it. Running repair in the main working tree will reestablish the connection from linked working trees back to the main working tree.
Upvotes: 0
Reputation: 27201
Create a .bare
repo:
mkdir repo
cd repo
git clone --bare [email protected]:user/repo.git .bare
echo "gitdir: ./.bare" > .git
Add some worktree branches:
$ git worktree add master
$ git worktree add branch_dir branch/subbranch
List the worktrees:
$ git worktree list
/home/username/repo/.bare (bare)
/home/username/repo/master e4e5d4d [master]
/home/username/repo/branch_dir 6ed5ed5 [branch/subbranch]
$ ls .bare/worktrees
branch_dir
master
Set the relative paths:
echo "gitdir: ../.bare/worktrees/master" > master/.git
echo "gitdir: ../.bare/worktrees/branch_dir" > branch_dir/.git
Optionally (error prone):
echo "../../../master/.git" > .bare/worktrees/master/gitdir
echo "../../../branch_dir/.git" > .bare/worktrees/branch_dir/gitdir
Upvotes: 1
Reputation: 2505
I make a simple bash script for my personal use here:
https://github.com/Kristian-Tan/git-worktree-relative
Note that this answer is just a copy-paste from my README.md
...
{worktree}/.git file
and {repo}/.git/worktrees/{wtname}/gitdir
cat
echo
readlink
realpath
(GNU utility since 2012, might not be preinstalled in very old linux system like debian wheezy)sed
pwd
${parameter/pattern/string}
and ${parameter%%word}
https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansiongit worktree remove
may refuse on relative path){worktree}/.git
file-v
= verbose (not implemented yet)-w worktree_target
= directory of worktree to be made relative (will default to current directory if not supplied)-r repository_target
= directory of repository (including worktree directory inside .git, will be read from {worktree_target}/.git file if not supplied)-h
= show help-r repositor_target
flag/home/myuser/repo/myproject
; worktree in /home/myuser/www/myproject
; worktree is connected with repository (link is not broken)
cd /home/myuser/www/myproject
git-worktree-relative
# OR
git-worktree-relative -w /home/myuser/www/myproject
/home/myuser/repo/myproject
; worktree in /home/myuser/www/myproject
; worktree is NOT connected with repository (link broken)
cd /home/myuser/www/myproject
git-worktree-relative -r /home/myuser/repo/myproject/.git/worktrees/myproject
# OR
git-worktree-relative -w /home/myuser/www/myproject -r /home/myuser/repo/myproject/.git/worktrees/myproject
git-worktree-relative
command with git-worktree-absolute
(same command line argument)
git worktree remove
requires the path to be absolute: you can use this reverse script to revert it back to absolute path before removinggit clone https://github.com/Kristian-Tan/git-worktree-relative.git
cd git-worktree-relative
sudo bash install.sh
git clone https://github.com/Kristian-Tan/git-worktree-relative.git ; cd git-worktree-relative ; sudo bash install.sh
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Kristian-Tan/git-worktree-relative/HEAD/get)"
git-worktree-relative.sh
and git-worktree-absolute.sh
to /usr/bin
or /bin
(you can also remove the extension) cp git-worktree-relative.sh /usr/bin/git-worktree-relative
cp git-worktree-absolute.sh /usr/bin/git-worktree-absolute
chown root:root /usr/bin/git-worktree-relative
chown root:root /usr/bin/git-worktree-absolute
chmod 0755 /usr/bin/git-worktree-relative
chmod 0755 /usr/bin/git-worktree-absolute
git clone https://github.com/Kristian-Tan/git-worktree-relative.git ; sudo bash git-worktree-relative/uninstall.sh
)/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Kristian-Tan/git-worktree-relative/HEAD/remove)"
...
usretc
for advise in git worktree with relative path?Upvotes: 10
Reputation: 834
I rolled out my own git-worktree-path. It's minimally hackish (no messing with internal git
paths, almost everything goes through git rev-parse
) and maximally DRY-ish
Upvotes: 0
Reputation: 37742
You are not the first to ask this question, see this feature-request from 2016
Relative paths seem to complicate things:
So it seems this never got implemented...
Upvotes: 4