Search code examples
gitgit-worktree

git worktree with relative path?


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?


Solution

  • 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

    ...

    My solution

    • Bash script to replace the content of {worktree}/.git file and {repo}/.git/worktrees/{wtname}/gitdir
    • Why bash: almost everyone who use git will use it in some kind of bash-shell-like environment (ex: bash shell in linux, git bash in windows)
    • Requirements (should be available on every bash shell):
    • Another bash script to change it back to absolute path (since git worktree remove may refuse on relative path)

    Usage

    • Execute the script in your worktree (or supply the worktree directory path in -w options)
    • It will read path to repository from {worktree}/.git file
    • Options:
      • -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
    • This solution works for broken link (ex: worktree directory moved OR parent git directory moved): just supply the repository path in -r repositor_target flag
    • This solution works for worktree inside parent repository
    • example:
      • repository in /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
        
      • repository in /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
        
      • to detect if link is broken, run command 'git status' in worktree directory
    • Reversing relative worktree back to absolute: just change git-worktree-relative command with git-worktree-absolute (same command line argument)
      • command git worktree remove requires the path to be absolute: you can use this reverse script to revert it back to absolute path before removing

    Installation

    Automatic Installation

    • copy paste below command into your terminal:
    git clone https://github.com/Kristian-Tan/git-worktree-relative.git
    cd git-worktree-relative
    sudo bash install.sh
    
    • or this one-line: git clone https://github.com/Kristian-Tan/git-worktree-relative.git ; cd git-worktree-relative ; sudo bash install.sh
    • or another one-line: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Kristian-Tan/git-worktree-relative/HEAD/get)"

    Manual Installation

    • installation for all users:
      • copy git-worktree-relative.sh and git-worktree-absolute.sh to /usr/bin or /bin (you can also remove the extension)
      • give other user permission to execute it
      • example:
        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
      
    • installation for one user:
      • copy it to any directory that is added to your PATH variable

    Uninstallation

    • just remove copied files (or just use uninstall.sh script: git clone https://github.com/Kristian-Tan/git-worktree-relative.git ; sudo bash git-worktree-relative/uninstall.sh)
    • or another one-line: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Kristian-Tan/git-worktree-relative/HEAD/remove)"

    ...

    Credits