lazygit
lazygit copied to clipboard
Initial addition of support for worktrees
-
PR Description Basic support for worktrees. Currently, only supporting listing and switching worktrees.
-
Please check if the PR fulfills these requirements
- [ ] Cheatsheets are up-to-date (run
go run scripts/cheatsheet/main.go generate) - [ ] Code has been formatted (see here)
- [ ] Tests have been added/updated (see here for the integration test guide)
- [ ] Text is internationalised (see here)
- [ ] Docs (specifically
docs/Config.md) have been updated if necessary - [ ] You've read through your own file changes for silly mistakes etc
Wow! Didn't expect that you'd pick up on all the current patterns. Code looks pretty good so far, I'll try to find time on the weekend to give it a more thorough review
Thanks! I have a few thoughts regarding worktree support
- Does it make sense for worktrees to be a separate tab in branches panel? It feels like it should, but I am unsure.
- In the branches list, I have filtered out branches that are checked out in a worktree that is not the current worktree.
- What other operations from https://git-scm.com/docs/git-worktree would we want to support? I'm thinking about add and remove, in addition to list and switch, being a good first step.
- We still need to handle worktrees which have been deleted from the filesystem, but not from git.
- How do we want to handle worktree which are on removable devices (see
git worktree lock ...)? - What information do we want to show on the right panel when a worktree is selected in the worktree list?
- How do we want to display the current repo/worktree in the status panel? Currently it displays
worktree_support -> worktree_supportfor the linked worktree. It would be better if it showed the repo, indicated we are in a worktree, and the branch.
I'll add my two cents.
- Does it make sense for worktrees to be a separate tab in branches panel? It feels like it should, but I am unsure.
It does, IMO it's at the same level as submodules, as far as functionality and options go.
- In the branches list, I have filtered out branches that are checked out in a worktree that is not the current worktree.
Maybe it would also be good to have them in the branches panel, but denote somehow that that branch is from a different worktree.
- What other operations from https://git-scm.com/docs/git-worktree would we want to support? I'm thinking about add and remove, in addition to list and switch, being a good first step.
Sounds like a big step forward having just those few commands. We could always add more later.
- We still need to handle worktrees which have been deleted from the filesystem, but not from git.
Just denote them somehow special and give the user an error when they try to switch to it?
- How do we want to handle worktree which are on removable devices (see
git worktree lock ...)?
Uhhh... how often is that used?
- What information do we want to show on the right panel when a worktree is selected in the worktree list?
I guess we could do the same as the recent repositores popup does: folder-name current-branch-name path/to/repo ? Seems reasonable.
Sorta kinda related question, since it looks like you've used worktrees before - should we warn users that it will not work with git-lfs?
- That was my thought as well
- I like the idea of using the branches panel. If we supported that, switching between branches that were checked out in different worktrees could etc worktree. Though, because linked worktrees can switch branches, we would need to support some way to checkout a branch into a worktree in addition to the current check out command. Lastly, we still would need the worktree panel, which means we would have multiple panels for managing worktrees. Sounds confusing…
- Agreed
- Another option is to just not show worktrees in the list if their target path does not exist
- No idea, I never do
- Good idea
- Looks like LFS has linked worktree support: https://github.com/git-lfs/git-lfs/blob/main/docs/man/git-lfs-install.adoc. Am I missing something?
- I like the idea of using the branches panel. If we supported that, switching between branches that were checked out in different worktrees could etc worktree. Though, because linked worktrees can switch branches, we would need to support some way to checkout a branch into a worktree in addition to the current check out command. Lastly, we still would need the worktree panel, which means we would have multiple panels for managing worktrees. Sounds confusing…
Well we can have both. Have the worktree panel for adding or removing worktrees, but still show all branches.
- Another option is to just not show worktrees in the list if their target path does not exist
Or that, yeah.
- Looks like LFS has linked worktree support: https://github.com/git-lfs/git-lfs/blob/main/docs/man/git-lfs-install.adoc. Am I missing something?
Huh, maybe it was a messup on my side. I tried using an additional worktree with several gigabytes of data in git-lfs and it didn't work out, I'll take a second look, thanks!
@mark2185 There are a few things I'd like feedback on in this image

- In the top left status panel, that is my quick attempt to differentiate being in a linked worktree vs the main work tree. Any other thoughts on how to do it?
- In the worktrees panel, what should we call the main worktree. Initially, I chose "main", but the problem is I can create a worktree via
git worktree add .worktrees/mainwhich will then also be called "main".
Also, I can create a worktree via git worktree add -b worktree_tests2 .worktrees2/worktree_testswhich will be pointed at a new branch (two worktrees cannot check out the same branch), but will have the same final segment in the path. As you can see in the following gif, there are two worktrees and they have the same "name" in the worktrees panel because their final path segment is the same.
When icons are enabled, it helps differentiate the main and linked worktrees if they share a "name", but it can still get pretty confusing. - When icons are enabled I think it would be good to include a "link" icon for the linked worktrees in the worktree panel.

- On the right status panel, I'm currently showing what we have decided it the "name" of the worktree and the path. Seems like the only things missing are the current branch name and maybe some indication that selected item is a main or linked worktree.
- In the top left status panel, that is my quick attempt to differentiate being in a linked worktree vs the main work tree. Any other thoughts on how to do it?
That seems good enough, I've used that panel exactly 0 times so I'm fine either way.
- In the worktrees panel, what should we call the main worktree. Initially, I chose "main", but the problem is I can create a worktree via
git worktree add .worktrees/mainwhich will then also be called "main".
Could we use the current working directory as it's name? As in, if the user just clones a repo, it'll be called e.g. lazygit?
Also, I can create a worktree via
git worktree add -b worktree_tests2 .worktrees2/worktree_testswhich will be pointed at a new branch (two worktrees cannot check out the same branch), but will have the same final segment in the path. As you can see in the following gif, there are two worktrees and they have the same "name" in the worktrees panel because their final path segment is the same.
That doesn't seem like a big issue. I don't know many people who use multiple worktrees so I don't have anyone to ask, but if I were creating multiple trees, I'd make sure they are not in folders of the same name.
- When icons are enabled I think it would be good to include a "link" icon for the linked worktrees in the worktree panel.
Seems reasonable.
- On the right status panel, I'm currently showing what we have decided it the "name" of the worktree and the path. Seems like the only things missing are the current branch name and maybe some indication that selected item is a main or linked worktree.
* is okay for the current worktree, the link icon is okay for the linked one, maybe we could use something tree-like for the main tree?
Also, I wouldn't hide invalid worktrees, I'd just mark them red or something. That way, the user can still delete them from within lazygit.
Good points.
I have already added filtering out of the worktree, but I can add them back, style them red, and then check on enter to ensure the target location exists.
Also, I had to add back the check you called out in the Branches loader as it is needed to not filter out branches which are not checked out.

Looks good! Does it also handle out-of-source worktrees just as well?
What do you mean by "out of source"?
What do you mean by "out of source"?
All of these worktrees were created within your lazygit clone, right? What if you create one outside of it? I.e. git worktree add -b stable ../otherfolder or something similar.
Yup, that works

Also, added a call out for missing worktrees on the right status panel

I think the look of the top left status is a lot better like this

Things remaining:
- [x] Support add worktree where branch name is worktree name
- [ ] Support add worktree where branch name is different than worktree name
- [x] Add branch to worktree main panel display
- [ ] Add option when deleting the worktree to delete the branch
- [ ] Tests, tests, tests
Basic add support is in:

@jesseduffield Addressed all open comments
@kadaan thanks for waiting, I'm gonna give this another review this weekend
Some more things I noted from locally testing:
- interestingly, a worktree named 'foo' will appear in
git status --shortas 'foo/'. Lazygit expects all status changes to be files, meaning it renders the workspace in the files view as a folder that has a file with no name. It would be good if we could actually signify that it's a worktree in the files panel, similar to what we do with submodules. Both when staged and unstaged it should appear as a single 'file' (right now it shows as a folder + file when unstaged and as a file when staged) - deleting a file that contains a worktree should refresh the worktree panel
- When hiting space on a worktree, things get a bit weird: initially I'm taken to the files window, and then upon switching to the branches window again I'm kicked out of the Worktrees tab and put in the Local Branches tab. Then if I go back to the Worktrees and hit space on other worktrees some more, eventually it keeps me in the Worktrees tab but moves my cursor down by one item. We should be consistent in what happens. I think we should stay in the Worktrees tab and the cursor should remain on the item we just hit space on.
- deleting worktree should also use a loader
- hitting enter on a worktree should also make you enter it (not just space)
@jesseduffield Sorry, lots of stuff going on with the paying job and at home, so I haven't been able to devote time to this. I will get back to it...
All good @kadaan, no rush from my end :)
nice work being done here, can't wait for this to be added in
Looking forward to this feature as well!
I'm picking up this PR because I reckon it's not gonna take much more work to get across the line :)
Some things I've got sorted out:
- disambiguating worktree names by including more of the path in the name if needed
- when switching to a worktree, you land in the same panel you started in
Things I'm yet to work out:
- a good UX for creating a new worktree, given there's various ways you can do it (create new branch, use existing branch, detached head). It might be simple enough to just prompt the user for the branch and have the basename of the worktree as the default value but I don't know if that misses things
- If a branch is associated to a worktree and you try to check it out, you'll be prompted to instead switch to that worktree. BUT if the worktree started a rebase on the branch, I have no idea how to know it's still associated to the branch. Git itself somehow knows because it gives you an error upon switching
- Do we want to be able to create a worktree from a commit? From a tag? (all as detached heads). I think so. You could be asked to create a new worktree or branch when you press 'n' on one of these things. One more key to press unfortunately, not sure if it should be a separate key.
- We don't have an icon for worktrees. We have a link icon for linked worktrees but it feels awkward to use that on the main worktree. This is important when displaying in the branches view whether a branch is associated with a worktree.
- Need to ensure all our rebasing stuff still works. We're directly checking some files, and we'll need to confirm if those files exist in each worktree (I assume they do)
- Need to handle relative paths
- Probably more stuff
Okay so turns out git is checking lazygit/.git/worktrees/my-worktree/rebase-merge/head-name to know that the my-worktree branch has ownership of the branch. I don't know how to check that via the git CLI and using the direct path seems a little too implementation-specific (though that's just based on recently reading git docs telling me not to depend much on worktree implementation details)
Things are moving along. Things yet to go:
- i18n (and just better wording on things in general)
- ensuring things make sense for those without nerd fonts
- ensuring that worktrees mid-rebase are still considered associated with their branch
- each worktree has its own reflog and we depend on the reflog for sorting the branches view. Not sure how to get around this: if you don't have many branches, it hopefully doesn't matter.
- ensuring relative paths work
- getting some feedback on the UX side
- tests
- hiding functionality for users on old git versions
- properly representing worktrees in the files view (if a worktree shows up in the files panel the user probably made a mistake but we gotta represent it properly anyway)
- testing how this plays with the --work-tree arg that lazygit currently supports
- allowing worktree to be opened in new editor window
Something that's especially tricky is that there's many ways you might want to create a worktree. You might want it detached, on a new branch, or on an existing branch, and you need to specify the path of the worktree and the base branch. So there's a lot that the user needs to specify and I'm open to ideas on how to make the current flow less clunky.
Reading up on how people use worktrees online, many of them give each branch its own worktree, and for many of those people they'll have a simple flow where they want to branch off master and create a branch called my-branch with corresponding worktree at '.worktrees/my-branch'. For those people (with a good script/tool) it's a matter of just typing in 'my-branch' and they're good to go but our UX isn't that straightforward. My hope is that those people can get by with a custom command, unless some standard appears for where people put their worktrees and what the flow looks like.
Some people (especially those with large repos) re-use worktrees given the time it takes to create a new one. We do not currently allow selecting a branch and saying 'checkout in worktree X', because:
- it adds more permutations to the already clunky above UX
- we'd need to add a check for when the worktree is dirty and provide the user with some way to deal with that (we could just throw an error but I like the idea of offering to stash the worktree's changes and hard resetting like we do with submodules)
- it is possible to just checkout the worktree and then checkout the branch from there
So I'm leaving that use case out of scope and we'll see if people want it.
Also out of scope for this PR is:
- allow locking/unlocking worktrees
- support repairing worktrees
- prune worktrees
- move worktrees
Looking at this for the first time; to be honest, I'm mainly looking at it to see if it gets in the way for people who don't use worktrees. 😄
One thing that (slightly) bothers me is that I now need one extra key press to get to the submodules tab, which I use fairly frequently (we use submodules heavily at work). Have you considered providing a config such as "showWorktreesTab" which would be true by default but can be set to false for people who never want to see it?
Re: submodules, the tabs cycle so you can use '[' to go from the files tab to the submodules tab. Though perhaps the worktrees view could come after submodules. My hope is that you can do enough with worktrees from the branches panel that you shouldn't need to spend much time in the worktree view itself.
I'm open to making it configurable, though I know over in the UX discussion thread somebody wants to have the tab show up first in the branches window:
I did not test your implementation but in terms of UX maybe a tab after local branches would be nice (and btw it may be a good idea to be able to reorder tabs ? In my case I would rather have ['Worktrees', 'Local branches', 'Tags', 'Remotes'] but this is another feature)
So perhaps we ought to support configurable tabs in general. But I'm happy to just have worktrees as the third tab in the submodules panel for now given how few people seem to use them.