Reputation:
I want to generically fetch the current branch only:
git fetch origin HEAD
but how do I determine the default remote?
git fetch DEFAULT_REMOTE HEAD
I assume HEAD is the most generic way to refer to the current branch, but I also need a generic way to refer to the default remote for the current branch?
Note that doing this:
git fetch HEAD
give me this problem:
fatal: 'HEAD' does not appear to be a git repository
fatal: Could not read from remote repository.
Upvotes: 1
Views: 486
Reputation: 4264
git fetch origin $(git rev-parse --abbrev-ref HEAD)
git fetch $(git config --local branch.$(git rev-parse --abbrev-ref HEAD).remote) $(git rev-parse --abbrev-ref HEAD)
As per the docs you can issue git fetch from a specific refspec.
Using the following format of git fetch
, you can ask for a specific ref:
git fetch [<options>] [<repository> [<refspec>…]]
< refspec >
Specifies which refs to fetch and which local refs to update.
This subshell $(git rev-parse --abbrev-ref HEAD)
comes from this answer.
The other one I've wrote myself and it's the following $(git config --local branch.$(git rev-parse --abbrev-ref HEAD).remote)
, it uses the first one to increase generalization, but what it does is to return the name of the remote associated with the branch in your local config, following this pattern git config --local branch.<branch_name>.remote
.
Upvotes: 1
Reputation: 489828
I assume HEAD is the most generic way to refer to the current branch ...
It is, yes. There's a pitfall here though, as we will see in a moment.
but I also need a generic way to refer to the default remote for the current branch?
There are a lot of ways to do this, and each has its own possible pitfalls, but I think the simplest is to use git config
to read back half of the current branch's upstream setting.
The obvious pitfall here is that the current branch may not have an upstream.
If you have a modern Git, git rev-parse
can return information about the upstream of any branch, including the current branch:
$ git rev-parse --symbolic-full-name HEAD
refs/heads/master
$ git rev-parse --symbolic-full-name HEAD@{u}
refs/remotes/origin/master
Here, the current branch is master
and its upstream is origin/master
. These use the full spelling of each ref, which is a good idea if you're writing scripts, since the abbreviated names (master
and origin/master
) could mis-parse: e.g., master
might turn into refs/tags/master
, if someone has created a tag named master
.
The upstream, if there is one—git branch --unset-upstream master
will remove the upstream for master
, for instance—is set as two parts:
$ git config --get branch.master.remote
origin
$ git config --get branch.master.merge
refs/heads/master
The branch.master.remote
setting is precisely what you want here: the name of the remote, or in this case, origin
. So if you first find the current branch name:
$ git symbolic-ref --short HEAD
master
you can use that to grab the appropriate remote name:
branch=$(git symbolic-ref --short HEAD) || die ...
remote=$(git config --get branch.$branch.remote) || die ...
You can now run:
$ git fetch $remote HEAD
But now we hit the first pitfall I mentioned:
remote: Enumerating objects: 928, done.
remote: Counting objects: 100% (928/928), done.
remote: Compressing objects: 100% (401/401), done.
remote: Total 928 (delta 601), reused 809 (delta 526)
Receiving objects: 100% (928/928), 843.84 KiB | 1.62 MiB/s, done.
Resolving deltas: 100% (601/601), completed with 74 local objects.
From [url]
* branch HEAD -> FETCH_HEAD
Note that, although I have a modern(ish) Git here (2.24.0), I did not get my origin/master
updated. To do that I must use instead:
$ git fetch $remote $branch
From [url]
* branch master -> FETCH_HEAD
c7a6207591..51ebf55b93 master -> origin/master
This time, my origin/master
got updated appropriately.
Edit: I didn't mention it originally, but we can see here that my Git asked their Git for their HEAD
. Their HEAD
is their master
; had I been on some other branch, I would have still gotten their HEAD
, i.e., their master
, in my .git/FETCH_HEAD
. So this is not merely cosmetic: you must feed your own Git a branch name here, rather than the symbolic name HEAD
. Compare with git push
, where you can safely use HEAD
for your side, because with git push
it is your Git, not theirs, that resolves the symbolic name HEAD
to a branch name.
You should first obtain the current branch name. Remember that this may fail: there may be no current branch name. Then, use git config --get
to get the remote part of the upstream setting. (The remaining part requires mapping through the remote's default fetch refspec mapping, but we don't need it—git fetch
will handle this—so don't bother picking up branch.$branch.merge
at all.)
The last pitfall that is worth mention here is this: the sample code above uses git config --get ... || die ...
, where die
is (presumably) a shell function to quit the script entirely. However, if you don't have an upstream set for the current branch, git fetch
itself won't quit at this point. It will simply use the hardcoded name origin
. So, depending on how slavishly you want to imitate raw git fetch
, you might want:
remote=$(git config --get branch.$branch.remote) || remote=origin
instead. Since you are writing the script, you get to control the edge and error cases here.
Upvotes: 0