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/*
git worktree add <default branch name> <default branch name>
- Go to the
mainworktree. git pull origin main #get latest from upstreamcd .. #get out of the main worktree and branchgit 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.
- Go the worktree root of the repository (where the
.baredirectory is located) 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.
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
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.
Much of this was borrowed from Alex Russell's https://infrequently.org/2021/07/worktrees-step-by-step/.