I don't know if I have a fundamental misundertanding about what a worktree is or what, but, I have tried fixing some bugs on a worktree. Used the git worktree add
command to make it. I navigated to the folder it created, made my changes, made a commit, and now I am ready to push to the commit to a remote branch so I can create a Pull Request.
This is my workflow when doing good old fashioned git branches. I will:
With my worktree I am stuck on step 5.
git worktree add <path>
When I try to push with --set-upstream
I get the src refspec <branch> does not match any
error. I then looked for the .git folder to find that there wasnt one, just a .git file with the path to that worktree.
There are a lot of tutorials out there on worktrees, and every one I have tried to read/watch has skipped this crucial detail. They tend to just cover the add/remove commands.
Is a worktree even considered a branch? I didnt think so at first but git branch
now shows me as being on a branch with the name of my worktree, interstingly, and unexpectedly it also shows that branch as being under another branch I was working on as if it were a sub branch of some kind
$ git branch
+ 371601_TLS_Certificates
* 395275_396239_MVPbugs
aspire-dev-shell-baseurl
ls
+ main
users/rrhughes/US/371601_TLS_Certificates
users/rrhughes/US/383751_resolve_URL
users/rrhughes/US/383751_settings_NXupdate
users/rrhughes/US/383751_settingsui
users/rrhughes/US/settings_devops
Later via brute force attempting to find a solution I tried a bare git push
and git told me it was not tracking a remote branch (as expected). It then provided me with this command
git push --set-upstream origin <my branch name>
I copy pasted it and it worked. However, this is nearly identical to the command I was trying before, and the command that I use to set upstream from regular git branches. the only difference was the name of my branch. It is a standardization on my dev team to make remote branches under a file structure for easy navigation and organization, so my command usually looks like this.
git push --set-upstream origin users/username/bugs/<my branch name>
Updated Question(s): So I am still confused why this did not work. Do I need to name my local worktree exactly what I will name it in the remote? If I want to name my local branch something simple, how do I set it to track a remote with a different name that meets my teams remote branch naming standard?
-Original Question: how do I get these changes on this worktree into my remote repo so I can create a PR?-
You need to --set-upstream
with a refspec:
git checkout -b branch-name
# Assuming remote is `origin`
git push --set-upstream origin branch-name:users/rrhughes/US/branch-name
Or using this shortcut as LeGEC suggested for pushing the currently checked out branch:
git push -u origin $(git branch --show-current):users/rrhughes/US/$(git branch --show-current)
Now the easiest thing to do if you’re using git-pull(1) is to use git pull origin
while you are checked out on that branch:
$ git pull origin
Already up to date.
Because note that the following will not work as you probably intend/expect:
$ git pull origin branch-name
fatal: couldn't find remote ref branch-name
Switch to a new worktree and create branch
users/kristoffer/demo/update-readme
(note the git worktree
command):
$ git worktree add ../demo -b users/kristoffer/demo/update-readme
Preparing worktree (new branch 'users/kristoffer/demo/update-readme')
HEAD is now at a1e8606 init
$ cd ../demo
$ # Assumes `origin` exists already
$ git push -u origin users/kristoffer/demo/update-readme
Password for 'https://LemmingAvalanche@github.com':
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'users/kristoffer/demo/update-readme' on GitHub by visiting:
remote: https://github.com/LemmingAvalanche/test-worktree/pull/new/users/kristoffer/demo/update-readme
remote:
To https://github.com/LemmingAvalanche/test-worktree.git
* [new branch] users/kristoffer/demo/update-readme -> users/kristoffer/demo/update-readme
branch 'users/kristoffer/demo/update-readme' set up to track 'origin/users/kristoffer/demo/update-readme'.
This worked.
(See section “Annex: git-worktrees/remote demonstration” for a full script that you can try on your machine.)
What branch am I on?
$ # We’re in the `demo` worktree
$ pwd
/home/kristoffer/programming/demo
$ git branch
+ main
* users/kristoffer/demo/update-readme
*
is the currently checked out branch. What’s the +
in front of
main
?
According to man git-branch
:[1]
Any branches checked out in linked worktrees will be highlighted in cyan and marked with a plus sign.
So what happens if I change back to the directory I was in before I changed directory into the worktree?
$ cd -
/home/kristoffer/programming/test-worktree
$ git branch
* main
+ users/kristoffer/demo/update-readme
Makes sense:
main
is the checked-out branch since this is the branch that this
worktree is ondemo
) is marked with +
(the
mark for a branch checked out in another worktree)First you need to understand what a “working tree” is:[2]
The tree of actual checked out files.
A “worktree” is a working tree plus repository metadata, with the repository metadata mostly “shared among other worktrees of a single repository”[3] [4].
Also:
A repository can have zero (i.e. bare repository) or one or more worktrees attached to it.
When you did git init
, you made a repository with one worktree. When you did git worktree add
you created the second worktree (more on this in the section “Back to basics (init)”).
No, and these things have nothing to do with each other.
A branch was created for you with the base name of the worktree since you gave:
$ git worktree add ../some-name
Preparing worktree (new branch 'some-name')
HEAD is now at a1e8606 init
I.e. you didn’t provide the optional commit-ish
after the branch:[5]
$ # Assuming that `branch-name` exists
$ git worktree add ../some-name branch-name
When you push a branch to a remote repository, you are pushing a ref. A ref doesn’t care what your working tree looks like (e.g it could be “dirty” but that doesn’t affect the ref). In fact a remote repository is likely to be “bare”, which means that it doesn’t have a working tree.
So the sentence by itself does not make sense.
But what was clearly meant was:
Push the branch that is checked out in this work tree
Which does make sense if you are using something like git push
without explicitly giving the branch name, since then you want whatever
branch is checked out to be pushed.
Then the standard troubleshooting applies:
git config
) allow me to say git push origin
(note: no branch)?Given this blank slate:
mkdir a-new-start
cd a-new-start
git init
What’s the worktree and branch in this case?
The exact same principles apply since a non-bare repository like this
one has one worktree, i.e. the one where you are right now; this is the
“main worktree”.[6] If you started using git worktree add
then you would
be creating “linked worktrees”.[6]
So then we can ask ourselves again:
git config
) allow me to say git push origin
?And these questions turn out to be much more elementary since the worktree is in fact mostly a distraction from the real problem.
On git version 2.40.0
man gitglossary
, entry “working tree”
man gitglossary
, entry “worktree”
The non-shared metadata “are maintained separately per worktree (e.g. the index, HEAD […]” (ibid)
From man git worktree
, under subcommand add
:
If
<commit-ish>
is omitted and neither-b
nor-B
nor--detach
used, then, as a convenience, the new worktree is associated with a branch (call it<branch>
) named after$(basename <path>)
.
man git worktree
This shell script demonstrates how branches, worktrees, and remotes can interact:
# Make a `temp` directory in your home directory (but change to
# e.g. `/tmp` if you prefer)
cd
mkdir -p temp
cd ~/temp/
mkdir demo
cd demo
mkdir local-repo
mkdir remote-repo
cd remote-repo
git init --bare
cd ../local-repo
git init
# Make an initial commit so that Git won’t freak out when
# we try to make the next branch for the worktree
git commit --allow-empty --message=Init
git remote add origin ../remote-repo
# Make the branch `worktree-branch` and check it out
# in `worktree`
git worktree add ../worktree -b worktree-branch
git push --set-upstream origin worktree-branch:users/rrhughes/US/worktree-branch
git worktree list
cd ..
mkdir local-repo-2
cd local-repo-2
git init
git remote add origin ../remote-repo
# This will fetch the branch as `users/rrhughes/US/worktree-branch`;
# we didn’t give an explicit refspec and this is the name that we gave it
# on the remote
git fetch origin
# Now you should get a message that the branch is set
# up to track the remote branch of that name
git checkout users/rrhughes/US/worktree-branch
# Make a commit for the remote
git commit --allow-empty --message='Second commit'
git push origin users/rrhughes/US/worktree-branch
# Back to the worktree where `worktree-branch` is set up
cd ../worktree
# This should update the branch in this worktree with the
# second commit
git pull --ff-only origin