I am writing a script to update all of our repositories to the latest code on our main develop branch. It's basically:
git -C ./$project pull origin develop:develop
I cannot be sure that the person running the script isn't actively working on a feature branch, nor can I guarantee that the branch they are on is branched from develop. Therefore I wish to ONLY pull origin/develop into develop and nothing else. No more actions.
Currently when doing this, git pulls develop into develop and then tries to merge develop into the current branch. I don't want this last step. I scoured the docs for pull and fetch and didn't find anything that could help. Is there a way to do this without having to manually check if theres changes, stash, pop, etc.
CodePudding user response:
TL;DR
Don't do this at all. Have people use origin/develop
directly. Teach them how and why. All they need to do then is use git fetch
.
Failing that, use git fetch origin develop:develop
and be prepared for some people to have a problem.
Long
git pull
literally means:
- run
git fetch
; then - run a second Git command.
You can choose whether the second command is git merge
or git rebase
but either way you'll affect the current branch based on what you git fetch
-ed in step 1.
Based on your comment here:
... what i've got,
git pull origin develop:develop
and that does in fact pull develop into develop while i'm onfeature/something
. However, git THEN tries to merge develop intofeature/something
...
Technically, git pull origin develop:develop
does not pull
their (origin's) develop
into your (local) develop
, because pull
means fetch second command
. All it does is fetch their develop
into your develop
—and that gives you an answer:
git fetch origin develop:develop
Remember that most1 git pull
arguments are passed directly to git fetch
. It's that first command that is doing all the work here! So just invoke it. But there are some issues here, so read on.
1The exceptions here are:
- options that are specific to the second command, and
- options that are "eaten" by
git pull
itself, such as the one to specify which second command to use.
What could go wrong?
The git fetch
command means:
Call up some other Git repository (in this case
origin
), using the URL stored under a remote: a short name for some other Git repository. A remote, likeorigin
, is just a name under which Git can store some information:- a URL for fetch and/or push (you can have a different push URL);
- some defaults and/or magic for fetch and/or push;
- other (unspecified: Git reserves the right to add new stuff in the future).
Have them list out their branch and tag names and the commits that go with these;
download new commits if / as needed / desired; and
based on the earlier steps, update any remote-tracking names (
origin/*
names in this case) as directed by some of the magic settings stored in under the remote's name.
To do this, git fetch
needs the name of a remote, like origin
. You can run it with one:
git fetch origin
or without:
git fetch
If you run it without one, Git will guess which remote to use. If you have only one remote—which is the typical case; most repositories just have one remote named origin
—that's the one Git will guess and therefore use, so you can run git fetch
with no arguments at all.
Having added a remote name, however, as in git fetch origin
, you can then go on to list branch names as they're seen in the remote:
git fetch origin develop
for instance. When you do this, you're telling your Git software that, although their Git may list out a dozen, or a million, branch names, you're only interested in updating one, namely develop
. That is, you want your origin/develop
updated, based on their develop
, and you're willing to skip updating all other origin/*
names.2 Or you could run:
git fetch origin br1 br2 br7
and thereby update your origin/br1
, your origin/br2
, and your origin/br7
.
Each of these additional arguments—which absolutely require the origin
in front because they have to come after a remote; the first argument will be assumed to be a remote: git fetch br1 develop
means "fetch develop
from remote br1
" whether or not br1
is a branch name—is what git fetch
calls a refspec. It's a very simple kind of refspec, because a full refspec is made up of four parts:
- an optional leading plus sign
- a left hand name, such as
develop
; - a right hand name, such as
develop
; and - a separator colon (
:
) character that splits the left and right sides.
You get to omit the separator when you're writing just a left-side name, hence git fetch origin develop
works fine. If you're going to provide a right-side name, though, you must include the colon.
When we do use the colon here, that tells git fetch
that it should attempt to create or update one of our names, in our repository. This may fail. In particular it will fail if develop
is the current branch, and in several other cases. Hence:
git fetch origin develop
will work,3 but:
git fetch origin develop:develop
might fail. So we need to handle the failure cases, or find an even-better way to deal with this.
There's another problem that occurs when develop
is the current branch in any added working tree from git worktree add
, and many versions of Git (from the point git worktree add
was added in Git 2.5 until Git 2.35 was released) fail to detect this. We'll touch on this later, but let's look at the issues with updating the local branch name develop
in the normal (main) working tree first.
2The usual reason to do this here is to make this git fetch
go faster. This will probably make the next git fetch
that fetches everything—the default—slower, since that one now has more to fetch. So it's a "pay me now or pay me later" situation, and, as it turns out, paying now is often actually cheaper than paying later, as the total cost is often lower (reduced overhead plus, sometimes, better compression). But not always—and "when to pay" is something you get to decide for yourself.
3If your network is down, or there's no develop
on origin
, git fetch origin
can fail too. But in these two cases we can't get anything at all done here, so we don't have to worry about them.