Search code examples
git

Is it possible to `git fetch` only specific branches without specifying a full refspec on each invocation?


Scenario 1

Suppose I have the following stanza in .git/config:

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

With this configuration:

  1. Running git fetch origin will fetch all branches.
  2. Running git fetch origin my_branch will fetch origin's copy of my_branch and update the tracking branch at refs/remotes/origin/my_branch.

Scenario 2

Now suppose I have the following stanza instead, which names two explicit branches that are not my_branch.

[remote "origin"]
    fetch = +refs/heads/master:refs/remotes/origin/master
    fetch = +refs/heads/all-green:refs/remotes/origin/all-green

With this configuration:

  1. Running git fetch origin will only fetch master and all-green.
  2. Running git fetch origin my_branch will fetch the branch, but not update any tracking branch. If I want to update the tracking branch, I must explicitly say git fetch origin my_branch:refs/remotes/origin/my_branch.

Question

Is it possible to configure git in such a way that the following two statements are true?

  1. git fetch origin my_branch will update local tracking branches according to the refspec in Scenario 1 for all possible values of my_branch.
  2. git fetch origin fetches only those branches that have previously been explicitly fetched (e.g. they already have a remote-tracking branch) rather than all branches that match the refspec.

In other words, I would like to use the refspec to determine the branch mapping automatically when I give a remote branch name to fetch, but not to determine the set of branches that is fetched when I merely say git fetch origin without a branch name.

My current approach is to just edit the git config (manually or using a script) for every remote branch I want to track, but I ask this question to see if there's a more direct way to get the behavior I want.


Solution

  • It's very easy to write a ~update the factory-default tracking branches even for branches I'm not usually tracking~ convenience, the payload is just

    awk '$2=="branch" { print "git update-ref refs/remotes/origin/"$3,$1 }' \
            $(git rev-parse --git-dir)/FETCH_HEAD | sh -x
    

    and you can invoke that however you want. It might be your best option, because I think this in the fetch refspec docs

    Unlike when pushing with git-push[1], there is no configuration which’ll amend these rules, and nothing like a pre-fetch hook analogous to the pre-receive hook.

    means "no." Which does make sense, fetching is often scripted for custom workflows already, some of them so common support has been provided in a factory-supplied convenience: git pull does any of several really common fetch-plus-custom-followup sequences.

    For another option, you could also customize an alternate remote,

    git config remote.onebranch.url $(git config remote.origin.url)
    git config remote.onebranch.fetch +refs/heads/*:refs/remotes/origin/*
    

    after which git fetch onebranch my_branch will update the origin tracking branch if needed.