1

If I have multiple local branches tracking a remote branch foo, does

git fetch foo

fetch foo for all the local branches that track it or just the one I am in at the time of the fetch?

IOW, if I switch to another branch that tracks the same remote, do I still need to fetch the remote after I did it immediately before in the other branch?

I found this thread that is remotely related but I think it means that the --all in git fetch --all means fetch all remotes and not fetch the one remote the current local tracks for all the local branches it tracks.

Community
  • 1
  • 1
amphibient
  • 29,770
  • 54
  • 146
  • 240
  • @Andreas seems to have understood it well... – amphibient Apr 22 '14 at 18:51
  • right but that was not so clear. i needed an answer and Andreas provided it. – amphibient Apr 22 '14 at 19:03
  • 1
    `git fetch foo` fetches branches from the remote named `foo`... If you have one... Or if `foo` is a group of remotes, it fetches from all of the remotes in that group. Otherwise it prints an error message and exits.. – twalberg Apr 22 '14 at 20:06

2 Answers2

1

If you have several local branches tracking the same one then fetch will fetch for all of them, or the one, as it's really just one remote branch.

Say your remote branch is devel then it will be named origin/devel locally and all your local branches will track origin/devel, the one and only.

So for your local branches you only need to do git rebase origin/devel after a git fetch origin to have it updated. All local branches will have it's upstream at the exact same commit.

Andreas Wederbrand
  • 38,065
  • 11
  • 68
  • 78
0

This is already answered and accepted but I'll add this anyway: git fetch remote takes everything the named remote is willing to give you based on the "refspec" arguments. With no refspec, it uses the refspecs given in fetch = lines for that particular remote.

The default refspec, if you have not configured any, is:

fetch = +refs/heads/*:refs/remotes/origin/*

assuming the name of the remote is origin (which is also the default, usually).1

You can think of the two git sessions (yours, doing git fetch, and the one on the remote that supplies data) as having a sort of telephone conversation. Yours calls up theirs and asks it for a list of all its references, and the SHA-1 IDs that go with them. Theirs might say "I have branch master and branch devel" (with some SHA-1s) "and tags v1.0 and v1.1" (with more SHA-1s).

At this point, your fetch goes through the list they gave you and picks out the names and SHA-1s it wants. They will go through some more conversation as needed, to select all the underlying repository objects needed to complete the objects that go with those SHA-1s ("commit" SHA-1s need "tree" SHA-1s which need more trees and/or "blobs"; but you may already have some, most, or all of them). Then they send over all the SHA-1-identified repository objects, and your fetch stashes them in your repo.

Finally, your fetch updates your copy of their reference-names, using those same refspecs. With the standard one for origin, this means that each of their branches—each name under refs/heads/ in their repository—gets a corresponding name in your repository, but listed under refs/remotes/origin/ instead. So your repository now has every branch they had when the "phone conversation" started, but in your repo, these are listed as a "remote branch" under origin/.

If you already have the name, fetch needs to know what to do if the associated SHA-1 has changed. For instance, their refs/heads/master might point to a different commit SHA-1 now. There are special fast-forward rules for branches,2 but the main thing to know is that the + at the front of a refspec means "forced update": the + in +refs/heads/*:refs/remotes/origin/* means "update them all, no matter what". Without the +, some reference-names may be left pointing to the original reference.

If you add --tags to your git fetch, this has the effect of adding refs/tags/*:refs/tags/* to the refspec set. This brings over all tags—into your (single, global) tag namespace under refs/tags—but without forced-update, so that if you already have a tag like amphibient-save, their tag with the same name will be ignored. (If your Git is 2.19 or later, see VonC's footnote; I have not tested this yet.)

This boils down to: "by default, git fetch brings over all branches and all useful tags". However, the specifics are useful to know, especially in edge cases.


1There is a special hack for tags: if you have not specifically asked your fetch to bring over all tags, but you have asked for branches—again, this is the default—it looks to see which, if any, tag references go with branches you're bringing over, and your fetch then updates your tags with those tags, as if you'd listed refs/tags/tag:refs/tags/tag. As with --tags, this is a "non-forced" update.

2Non-forced tag updates used to follow the non-forced branch update rules of allowing the update if and only if the update is a fast-forward. This behavior changed as of git version 1.8.2; tags now update only if forced, regardless of fast-forward.

torek
  • 448,244
  • 59
  • 642
  • 775
  • "their tag with the same name will be ignored.": This will need to be re-evaluated with Git 2.19. See https://stackoverflow.com/a/51918981/6309 – VonC Aug 19 '18 at 15:06