Skip to content

Add "Detach worktree" option when checking out a branch occupied by another worktree#5341

Open
ruudk wants to merge 1 commit intojesseduffield:masterfrom
ruudk:force-worktree-checkout
Open

Add "Detach worktree" option when checking out a branch occupied by another worktree#5341
ruudk wants to merge 1 commit intojesseduffield:masterfrom
ruudk:force-worktree-checkout

Conversation

@ruudk
Copy link
Copy Markdown
Contributor

@ruudk ruudk commented Mar 5, 2026

PR Description

Please check if the PR fulfills these requirements

  • Cheatsheets are up-to-date (run 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)
  • If a new UserConfig entry was added, make sure it can be hot-reloaded (see here)
  • Docs have been updated if necessary
  • You've read through your own file changes for silly mistakes etc

When working with worktrees it's common to have a main project installation (e.g. running your database and services) alongside several worktrees for feature work. Previously, checking out a branch occupied by another worktree only offered "Switch to worktree", forcing you to switch to that worktree, detach it, then navigate back and check out the branch: a tedious round-trip.

This is the current behavior:
Screenshot 2026-03-05 at 12 57 33@2x

Now the prompt shows a menu with two options: "Switch to worktree" and "Detach worktree". The detach option runs git checkout --detach on the other worktree and then checks out the branch in one step.
Screenshot 2026-03-05 at 12 57 43@2x
Screenshot 2026-03-05 at 12 57 47@2x

The detach option is disabled when the other worktree has uncommitted changes, to prevent accidental loss of work.
Screenshot 2026-03-05 at 12 57 06@2x

@stefanhaller
Copy link
Copy Markdown
Collaborator

Makes some sense, but I'm curious why you want this, rather than just switch to the worktree that has the branch already checked out.

One reason that I could imagine: when I watch people use git (or lazygit), and they want to create a new branch from main, I often see them check out main first, pull it, and then create a new branch from it. So if main is checked out in a worktree, this would explain why you want your new feature. Note that this is unnecessary though: to create a new branch from main, simply select it in the branches list and press n; no need to check it out first.

Any other reasons?

@ruudk
Copy link
Copy Markdown
Contributor Author

ruudk commented Mar 8, 2026

I have my application and services booted in my main repository.

The worktrees don't have that because it would eat resources.

Occasionally I want to bring some of these features to my main repository and run it functionally.

Does that make sense?

@stefanhaller
Copy link
Copy Markdown
Collaborator

Yes, thanks.

I'm out of time today, so this PR probably won't make it for the release tomorrow; hope that's ok.

@ruudk
Copy link
Copy Markdown
Contributor Author

ruudk commented Mar 8, 2026

Sure, no rush! Thanks for taking the time to review it

…nother worktree

When working with worktrees it's common to have a main project installation
(e.g. running your database and services) alongside several worktrees for
feature work. Previously, checking out a branch occupied by another worktree
only offered "Switch to worktree", forcing you to switch to that worktree,
detach it, then navigate back and check out the branch — a tedious round-trip.

Now the prompt shows a menu with two options: "Switch to worktree" and
"Detach worktree". The detach option runs `git checkout --detach` on the
other worktree and then checks out the branch in one step.

The detach option is disabled when the other worktree has uncommitted changes,
to prevent accidental loss of work.
Copy link
Copy Markdown
Collaborator

@stefanhaller stefanhaller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks mostly good; a few things below.

func (self *BranchesController) promptToCheckoutWorktree(worktree *models.Worktree) error {
prompt := utils.ResolvePlaceholderString(self.c.Tr.AlreadyCheckedOutByWorktree, map[string]string{
func (self *BranchesController) promptToCheckoutWorktree(worktree *models.Worktree, branchName string) error {
title := utils.ResolvePlaceholderString(self.c.Tr.BranchCheckedOutByWorktree, map[string]string{
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of putting this text in the title. Branch names can be very long, so this might get truncated. I see that we are doing the same thing already when deleting branches, but it's not good there, either. :)

I'd suggest to use a shorter title and put the longer text in a menu prompt (see CreateMenuOptions.Prompt), something like

Branch 'xyz' is checked out by worktree 'abc'. How would you like to proceed?

Switch to worktree
Detach worktree and checkout branch here
Cancel


func (self *BranchesController) promptToCheckoutWorktree(worktree *models.Worktree) error {
prompt := utils.ResolvePlaceholderString(self.c.Tr.AlreadyCheckedOutByWorktree, map[string]string{
func (self *BranchesController) promptToCheckoutWorktree(worktree *models.Worktree, branchName string) error {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a pretty long function; would be good to move it to BranchesHelper.

Comment on lines +425 to +427
if !worktree.IsPathMissing && !self.c.Git().Worktree.IsWorktreeClean(worktree.Path) {
detachDisabledReason = &types.DisabledReason{Text: self.c.Tr.DetachWorktreeHasUncommittedChanges}
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this. Detaching a worktree when there are modified files doesn't lose data, the modifications will stay the same. And we don't guard against this when detaching a worktree in response to deleting a branch, either.

},
{
Label: self.c.Tr.DetachWorktree,
Tooltip: self.c.Tr.DetachWorktreeTooltip,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tooltip sounds as if detaching the worktree is the only thing that will happen. It should also mention that the branch is going to be checked out in the current worktree afterwards.

@stefanhaller stefanhaller force-pushed the force-worktree-checkout branch from 7e7fa96 to b66e3fa Compare April 2, 2026 16:52
@stefanhaller
Copy link
Copy Markdown
Collaborator

Oh, and I force-pushed the branch because it had conflicts with master.

@stefanhaller stefanhaller added the enhancement New feature or request label Apr 2, 2026
@codacy-production
Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 0 complexity · -3 duplication

Metric Results
Complexity 0
Duplication -3

View in Codacy

TIP This summary will be updated as you push new changes. Give us feedback

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants