37

I do not want to fetch every branch from origin because there are many. I just want to track a few (e.g., master) and my branches (organized under my_name sub-directory). I can do the following:

$ git fetch origin refs/heads/my_name/*:refs/remotes/origin/my_name/* refs/heads/master:refs/remotes/origin/master refs/heads/some_branch:refs/remotes/origin/some_branch

I want to specify the above "set" of refspecs to be the default of git fetch. I have tried

$ git config remote.origin.fetch refs/heads/my_name/*:refs/remotes/origin/my_name/*
$ git config --add remote.origin.fetch refs/heads/master:refs/remotes/origin/master

It fails:

$ git config remote.origin.fetch
refs/heads/my_name/*:refs/remotes/origin/my_name/*
error: More than one value for the key remote.origin.fetch: refs/heads/master:refs/remotes/origin/master

I also try the following but it also fails:

$ git config remote.origin.fetch 'refs/heads/my_name/*:refs/remotes/origin/my_name/* refs/heads/master:refs/remotes/origin/master refs/heads/some_branch:refs/remotes/origin/some_branch'
$ git fetch
fatal: Invalid refspec 'refs/heads/my_name/*:refs/remotes/origin/my_name/* refs/heads/master:refs/remotes/origin/master refs/heads/some_branch:refs/remotes/origin/some_branch'

Note: Git 1.7.11

user716468
  • 1,282
  • 2
  • 11
  • 18
  • 1
    Note: since Git 2.1 (August 2014), you can override the fetch refspec on a per-invocation basis (meaning just for one command), with the new fetch option `--refmap=`: see [my answer below](http://stackoverflow.com/a/25098004/6309) – VonC Aug 02 '14 at 18:13

4 Answers4

41

You can add the following lines in your .git/config to specify multiple refspecs for fetch:

[remote "origin"]
       fetch = refs/heads/my_name/*:refs/remotes/origin/my_name/*
       fetch = refs/heads/master:refs/remotes/origin/master
       fetch = refs/heads/some_branch:refs/remotes/origin/some_branch

You can add the prefix + before the refspec, if you would like to override fetching non-fast-forward references as well, like this:

[remote "origin"]
       fetch = +refs/heads/my_name/*:refs/remotes/origin/my_name/*
       fetch = +refs/heads/master:refs/remotes/origin/master
       fetch = +refs/heads/some_branch:refs/remotes/origin/some_branch

Note that partial globbing is not supported (i.e. a/b/ca* is not supported, but a/b/* is).

10.5 Git Internals - The Refspec

Nemo
  • 2,356
  • 2
  • 26
  • 57
Tuxdude
  • 40,779
  • 13
  • 96
  • 102
  • 1
    I realize that the error reported by "git config remote.origin.fetch" does not mean it could not work with multiple values. I just have to query it differently using "git config --get-all remote.origin.fetch" – user716468 Mar 22 '13 at 09:59
  • 2
    @Tuxdude Thanks for that. Is there a single command that could achieve the above? I'm trying to keep my documentation concise for new developers, I'd prefer they could specify multiple refspecs via "git config remote.origin.fetch" rather than editing their git config file. – danjah Nov 05 '14 at 22:04
  • @Danjah something like "+refs/heads/master:refs/remotes/origin/master'" would work – jmnas Jun 24 '15 at 13:39
21

To overwrite the existing fetch refspec(s), without having to manually edit .git/config, you can use --unset-all followed by as many --add as needed.

For the example desired refspecs in the question, it would be:

git config --unset-all remote.origin.fetch
git config --add remote.origin.fetch +refs/heads/my_name/*:refs/remotes/origin/my_name/*
git config --add remote.origin.fetch +refs/heads/master:refs/remotes/origin/master

Then use git config --get-all remote.origin.fetch to verify the result.

Rafa
  • 8,431
  • 4
  • 35
  • 58
Shaun
  • 221
  • 2
  • 7
  • Exactly what I needed! Essentially, when the version tag is updated, this prevents the old tag from being in the way and updates (and caches) without any penalty to the new tag. You can even go back to the old tag without a problem. – taranaki May 19 '17 at 20:13
4

Note: if you want to fetch from a different refspec on a single invocation (overriding temporarily the fetch refspec registered in the config), you can do so since Git 2.1 (August 2014).

See commit c5558f8 by Junio C Hamano (gitster):

Since the introduction of opportunistic updates of remote-tracking branches, started at around f269048 (fetch: opportunistically update tracking refs, 2013-05-11) with a few updates in v1.8.4 era, the remote.*.fetch configuration always kicks in even when a refspec to specify what to fetch is given on the command line, and there is no way to disable or override it per-invocation.

Teach the command to pay attention to the --refmap=<lhs>:<rhs> command-line options that can be used to override the use of configured remote.*.fetch as the refmap.

That gives you the new option:

--refmap=<refspec>

When fetching refs listed on the command line, use the specified refspec (can be given more than once) to map the refs to remote-tracking branches, instead of the values of remote.*.fetch configuration variables for the remote repository.
See section on "Configured Remote-tracking Branches" for details.

(That Git "Configured Remote-tracking Branches" section also dates from Git 2.1: see "Having a hard time understanding git fetch")


With Git 2.25.1 (Feb. 2020), "git fetch --refmap=" option has got a better documentation.

See commit b40a502 (21 Jan 2020) by Derrick Stolee (derrickstolee).
(Merged by Junio C Hamano -- gitster -- in commit 4b69f29, 30 Jan 2020)

fetch: document and test --refmap=""

Signed-off-by: Derrick Stolee

To prevent long blocking time during a 'git fetch' call, a user may want to set up a schedule for background 'git fetch' processes.
However, these runs will update the refs/remotes branches due to the default refspec set in the config when Git adds a remote.
Hence the user will not notice when remote refs are updated during their foreground fetches. In fact, they may want those refs to stay put so they can work with the refs from their last foreground fetch call.

This can be accomplished by overriding the configured refspec using '--refmap=' along with a custom refspec:

git fetch --refmap='' <remote> +refs/heads/*:refs/hidden/<remote>/*

to populate a custom ref space and download a pack of the new reachable objects.
This kind of call allows a few things to happen:

  1. We download a new pack if refs have updated. 2. Since the refs/hidden branches exist, GC will not remove the newly-downloaded data.
  2. With fetch.writeCommitGraph enabled, the refs/hidden refs are used to update the commit-graph file.

To avoid the refs/hidden directory from filling without bound, the --prune option can be included. When providing a refspec like this, the --prune option does not delete remote refs and instead only deletes refs in the target refspace.

Update the documentation to clarify how '--refmap=""' works and create tests to guarantee this behavior remains in the future.

So the git fetch option man page now includes:

--refmap=<refspec>:

When fetching refs listed on the command line, use the specified refspec (can be given more than once) to map the refs to remote-tracking branches, instead of the values of remote.*.fetch configuration variables for the remote repository.

Providing an empty <refspec> to the --refmap option causes Git to ignore the configured refspecs and rely entirely on the refspecs supplied as command-line arguments.
See section on "Configured Remote-tracking Branches" for details.


Note that the more aggressive updates to remote-tracking branches we had for the past 7 years or so were not reflected in the documentation, which has been corrected with Git 2.27 (Q2 2020).

See commit a440884, commit f6a65de (05 Apr 2020) by Philippe Blain (phil-blain).
(Merged by Junio C Hamano -- gitster -- in commit fdee8b1, 22 Apr 2020)

pull doc: correct outdated description of an example

Signed-off-by: Philippe Blain

Since f269048754 ("fetch: opportunistically update tracking refs", 2013-05-11, Git v1.8.4-rc0 -- merge listed in batch #0), the underlying git fetch in [git pull](https://git-scm.com/docs/git-pull) <remote> <branch> updates the configured remote-tracking branch for .

However, an example in the 'Examples' section of the git pull documentation still states that this is not the case.

Correct the description of this example.

So instead of, for git pull origin next:

This leaves a copy of next temporarily in FETCH_HEAD, but does not update any remote-tracking branches.
Using remote-tracking branches, the same can be done by invoking fetch and merge:

You now have:

This leaves a copy of next temporarily in FETCH_HEAD, and updates the remote-tracking branch origin/next.
The same can be done by invoking fetch and merge:

VonC
  • 1,042,979
  • 435
  • 3,649
  • 4,283
  • An actual *real* example of using --refmap would be useful here. I'm not sure a single clear example exists anywhere on the internet. – Paul Mar 14 '18 at 01:33
1

Answering my own complaint about lack of examples for refmap. Here's an example of checking out a pull request from VSO (Visual Studio Online) without interacting with the config.

$ git fetch --refmap='+refs/pull/*/merge:refs/remotes/origin/pr/*' origin refs/pull/1415/merge $ git checkout pr/1415

Paul
  • 567
  • 6
  • 6