Working with Git Worktrees in Magit
Posted by srijan4 4 days ago
Comments
Comment by miggol 1 day ago
But when I want to checkout a branch that's already checked out in another worktree, Magit just plain refuses. I wish it would offer me to either:
1. Switch to that worktree instead
2. Detach head in the other worktree and checkout here
Would be such an improvement! No excuses though, I love magit and might as well hack this myself. I'm just bad at elisp.
Comment by svlasov 1 day ago
You can use `--force`:
> If <branch> does exist, it will be checked out in the new worktree, if it’s not checked out anywhere else, otherwise the command will refuse to create the worktree (unless --force is used).
Comment by dzaima 1 day ago
This leaves things in a weird state though, as modifying the branch from one of the worktrees will effectively change the ref the other is pointing to, but won't update the other's working tree, making it look like it's preparing to revert all the changes that the first worktree made.
(obligatory mention of jj, whose workspaces track what state they were snapshotted at, thus never losing what the true diff of a workspace should be, allowing a "jj workspace update-stale" to safely update the working copy with whatever the other workspaces changed (if you change the working copy and in parallel from another workspace change what that workspace points to, you'll get a saved commit of the working copy changes before being updated, which you'll need to squash/rebase wherever those changes were needed))
Comment by LeBit 1 day ago
Or you aren’t saying this is a wanted feature, simply that magit should switch to the worktree (like lazitgit behavior)?
Comment by rgoulter 14 hours ago
I've run into it when I've wanted to checkout that branch (to try running code there, or view a file, or rebase it, or whatever) and there's already a worktree checked out.
This is more like treating worktrees as "lightweight clone of the repo checkout out at some dir". (If it were a separate clone, it wouldn't be an issue to have the same branch checked out in two places).
Comment by simonhamp 1 day ago
I don't get spending all this time on tooling that tries to ease working with worktrees when they're just not the right abstraction for the way we're working now.
Comment by LeBit 1 day ago
You use your filesystem ability to perform a snapshot of your local git repo? Or you do a cp -reflink?
How do you handle the exposure of secrets to agents?
One thing I like about worktrees is that you get a clean copy (with share git objects though), so you have to copy over what the agent will need, not remove what you don’t want the agent to see.
Comment by JamesSwift 1 day ago
But yeah the filesystem cost is not ideal. I was just thinking about how to exclude my worktrees from timemachine backups automatically.
[1] https://lore.kernel.org/git/7c8b4673-37ac-45fa-ad8c-a1dc09af...
Comment by diath 22 hours ago
Comment by sebzim4500 1 day ago
Comment by drdexebtjl 1 day ago
cp -R --reflink=always /path/to/source /path/to/dest
On macOS with APFS: cp -R -c /path/to/source /path/to/dest
That's it. You get a copy that only stores additional space for metadata, not the files themselves.Comment by sandinmyjoints 22 hours ago
NAME
clonefile – create copy on write clones of files
SYNOPSIS
...
LIMITATIONS
Cloning directories with these functions is strongly discouraged. Use copyfile(3) to clone directories instead.
But no explanation of why strongly discouraged.Comment by codesnik 1 day ago
Comment by drdexebtjl 1 day ago
Also, it’s not really CoW. The immutable object store is hardlinked (since it’s immutable it doesn’t really CoW, but that’s not a very important distinction). But working files are full copies, and so is the rest of .git. With a CoW filesystem you can CoW everything, including node_modules and build artifacts.
Comment by chukar 14 hours ago
Comment by cdmckay 20 hours ago
It works better for me if I have multiple copies of the repo with their own supporting environment like repo-a, repo-b, etc. going to app-a.foo.localhost, app-b.foo.localhost, etc.
Comment by polishdude20 18 hours ago
Comment by brabel 1 day ago
Comment by chrizel 1 day ago
A couple of weeks ago I discovered Worktrunk. That's when my whole workflow flipped 180 degrees: I now always use worktrees, love it, will never go back. Worktrunk was the missing piece for me. Very recommended.
Comment by reddit_clone 19 hours ago
I just installed it and loving it so far.
Comment by LeBit 1 day ago
The hooks system is great.
The UX is great (wt list, wt switch —create …)
It is magnificent.
Comment by prima-facie 1 day ago
Comment by crabbone 1 day ago
Some things that the post indicates as the problems solved by worktrees to me feel like the (quite common) problems of development environment setup. For example, OP uses worktrees to prevent different tools from competing over files in the working directory of their development environment... Well, a better way to run tests is to not run them from the development environment at all: deploy them to wherever they are supposed to run, and run them there.
Unfortunately, a lot of tools are designed to run code from "dirty" environment by default, take for instance Python developer's love for "pip install -e" or pytest running code from the source directory by default. But, for one's own sanity, these practices are better avoided. Running from the working directory of the development environment means that you, as a developer, have to remember every detail of the state left by the previous run and reassure yourself that none of those changes matter to your next run... I don't trust myself to remember that.
Comment by anilakar 1 day ago
I've solved this by running thin bash script wrappers that keep the workflow SVN-like with a root directory that contains per-branch directories and a hidden bare repo).
Comment by black_knight 1 day ago
My branches end up in a tree structure (no shit!), and I rebase and merge up stream as changes land. I guess it could be more automated, but the only tedious part is remembering to remove old worktrees and prune the old branches
Comment by anilakar 1 day ago
worktree add: `git worktree add` that creates a local new branch and a directory with the same name and sets upstream to match; alternatively checks out an existing remote branch.
worktree rm: Removes worktree directory, first checking it is in porcelain state. Then prunes them and removes local branch pointers if they match the remote ones.
These all are handwritten and probably buggy, but still less prone to errors than typing out `git worktree add -b foo-123-fix-missing-semicolon foo-123-fix-missing-semicolon origin/develop` manually every time. One pass with Claude or Codex would probably do wonders.
Comment by zrg 1 day ago
Comment by keybored 1 day ago
https://stackoverflow.com/questions/31935776/what-would-i-us...
Comment by BoingBoomTschak 1 day ago
I just found https://github.com/josharian/git-cow-worktree that doesn't inspire confidence.
Comment by ajpaon 1 day ago
Comment by masklinn 1 day ago
Comment by HNIsUnusable 1 day ago
Comment by hyfgfh 1 day ago
Comment by menaerus 1 day ago
Comment by masklinn 1 day ago
The rest I agree with, that objects and branches are shared between worktrees, as well as the repository configuration (e.g. remotes) is why I use worktrees, having to move things around and losing the content when I’d delete the wrong clone is why I stopped using them.
Comment by drdexebtjl 1 day ago
edit: spellchecker corrected reflinks, this is what I meant.
Comment by jmholla 1 day ago
``` cd $(mktemp -d) git init test ( cd test; touch README.md; git add README.md; git commit -m "Test"; ) git clone test/.git test_clone find test_clone/.git/objects test/.git/objects -type f -printf "%i\t%p\n" | sort ```
You'll see the same inodes used in both clones.
Comment by drdexebtjl 1 day ago
CoW and reflinks let you share everything, including the non-immutable paths, and even stuff like node_modules.
Comment by masklinn 22 hours ago
Comment by koiueo 1 day ago
// Didn't double-check, but I've held this belief for over decade now, would be surprised to be proven wrong
Comment by drdexebtjl 1 day ago
echo old > a
ln a b
echo new > a
cat a b # prints "new" and "new"
Some programs like GNU sed [1] do create new inodes, but that is a property of the application, not the filesystem: echo old > a
ln a b
sed -i 'c new' a
cat a b # prints "new" and "old"
With reflinks in a CoW filesystem the inodes are different from the start, but share the same underlying blocks: echo old > a
cp --reflink=always a b
ls -i a b # prints different inodes
echo new > a
cat a b # prints "new" and "old"
[1] https://www.gnu.org/software/sed/manual/html_node/Command_00...Comment by koiueo 21 hours ago
Thanks for examples and especially the doc link. I don't normally use hard links, and for some reason was sure that's how they behave.
Maybe my belief indeed stemmed from observing software which overwrites opened file with a new copy.
Comment by epcoa 1 day ago
Comment by dreamcompiler 1 day ago
CoW is similar except the new inode is created by the file system itself and is independent of the editor.
Comment by Groxx 23 hours ago
Comment by dv_dt 1 day ago
For my purposes, the alternative with just switching branches or if parallelism is needed, full repos and remotes (including local path remotes) is just much more flexible. Clone local, branch it, optionally do anything later: push a branch back to the local repo, push it to a remote, delete local repo done.
The actual code and clean merges is much more significant than worktrees vs full clones
Comment by layer8 1 day ago
Isn’t this unsafe and can cause corruption? https://github.com/kaeawc/auto-worktree/issues/176
Comment by riedel 1 day ago
https://gist.github.com/ruvnet/60e5749c934077c7040ab32b54253...
Comment by ragall 18 hours ago