Skip to content

Instantly share code, notes, and snippets.

@socketbox
Last active August 14, 2026 14:46
Show Gist options
  • Select an option

  • Save socketbox/7f2dcc68fda4885f3265e7bf85828b27 to your computer and use it in GitHub Desktop.

Select an option

Save socketbox/7f2dcc68fda4885f3265e7bf85828b27 to your computer and use it in GitHub Desktop.
Start a new git worktree from an existing branch other than the default

Starting out

mkdir project_foo
cd project_foo
git clone --bare git@github.com:yourorg/project_foo.git .bare
echo "gitdir: ./.bare" > .git

Now edit .bare/config, adding fetch = +refs/heads/*:refs/remotes/origin/* below [remote "origin"]

[remote "origin"]                               
  url = git@github.com:yourorg/project_foo.git 
  fetch = +refs/heads/*:refs/remotes/origin/*  

Branches

Create main/master

git worktree add <default branch name> <default branch name>

To create a branch and a worktree that is based off of main:

  1. Go to the main worktree.
  2. git pull origin main #get latest from upstream
  3. cd .. #get out of the main worktree and branch
  4. git worktree add -b my-new-branch ./my-new-branch main #creates a my-new-branch directory, as well as a branch of the same name, which is based off of main

The -b is required: git worktree add accepts at most <path> [<commit-ish>], so passing both a path and a branch name as positional arguments is a usage error. Dropping -b and running git worktree add ./my-new-branch main doesn't work either, because main is already checked out in the main worktree and git refuses to check out the same branch twice.

To create a worktree based off of an existing branch present in the local repository

  1. Go the worktree root of the repository (where the .bare directory is located)
  2. git worktree add ./existing-branch-name existing-branch-name

Because the local branch already exists, that command shows you the following, and it leaves the branch's upstream configuration exactly as it was:

Preparing worktree (checking out 'existing-branch-name')                                       
HEAD is now at cf5bfce6b creating the foobaz                                                                  

If the local branch isn't tracking the remote branch of the same name, do the following:

cd existing-branch-name  
git branch --set-upstream-to=origin/existing-branch-name  

In response, you should see the following:

branch 'existing-branch-name' set up to track 'origin/existing-branch-name'

Run git status to confirm this.

To create a worktree for a branch that exists only on the remote

Run the same command as above. When there is no local branch of that name but origin/existing-branch-name exists, git DWIMs: it creates the local branch and sets up tracking for you, so no --set-upstream-to is needed.

git fetch --all --prune
git worktree add ./existing-branch-name existing-branch-name
Preparing worktree (new branch 'existing-branch-name')
branch 'existing-branch-name' set up to track 'origin/existing-branch-name'.
HEAD is now at cf5bfce6b creating the foobaz

Hints

It might be helpful to first push a locally created branch to the remote and then create a worktree based on that remote rather than attempt to create a worktree on a locally created branch that's not tracking a remote branch.

To add a worktree whose local branch name differs from the remote branch it should track: git fetch --all --prune git worktree add --track -b new_worktree_branch ./new_worktree_path remote_name/existing_branch

Branch names containing a slash need no special handling — the DWIM above works on them as-is: git fetch --all --prune git worktree add ./local-dir-name "branch/name-with-slash"

Note that --guess-remote is not a solution here. It only takes effect when no <commit-ish> is given, in which case it guesses the branch from the last path component only. So git worktree add --guess-remote feat/slashy looks for a remote branch named slashy, fails to find one, and silently creates an untracked branch off of HEAD. Passing --guess-remote alongside a <commit-ish> is simply a no-op.

To add a worktree whose branch exists on the remote only, using an explicit remote-tracking ref:

[2023-06-01 14:51:38]>> git fetch origin dockerfile-updates
From github.com:yourorg/project_foo
 * branch              dockerfile-updates -> FETCH_HEAD
[ main][🅰 ][project_foo]
[2023-06-01 14:52:00]>> git worktree add ./dockerfile-updates dockerfile-updates

The fetch refspec added during setup means git fetch origin dockerfile-updates also updates refs/remotes/origin/dockerfile-updates, which is what lets the DWIM above find it. Avoid git worktree add ./dockerfile-updates FETCH_HEAD: that leaves the new worktree on a detached HEAD with no branch and no upstream.

Credit

Much of this was borrowed from Alex Russell's https://infrequently.org/2021/07/worktrees-step-by-step/.

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