0

I just did

get fetch origin feature/8067

and below it I got 3 columns:

 * branch                feature/8067 -> FETCH_HEAD
 * [new branch]          feature/8067 -> origin/feature/8067

Trying to process this...reading from here I just learned that FETCH_HEAD basically means the tip of where I last did a fetch. The file will contain a commit.

Does that [new branch] refer to the new branch created under my refs/remote?

I'm not sure if my reading of the following is correct: feature/8067 -> origin/feature/8067

Is the 2nd column the <nameOfBranchOnRemoteRepo> while the 3rd column is <repoName/nameOfBranchOnRemoteRepo> and it says my fetched remote branch in the refs is pointing to that in the remote?

mfaani
  • 33,269
  • 19
  • 164
  • 293

2 Answers2

2

The fetch output is confusing even to an old hand. Here's how I decode them:

 * branch                feature/8067 -> FETCH_HEAD
 * [new branch]          feature/8067 -> origin/feature/8067

Work each line from right to left:

  • The first line ends with FETCH_HEAD, which means that the reference was deposited into FETCH_HEAD. See the note about FETCH_HEAD below. The arrow is hardcoded (always appears and you can just sort of ignore it); the name feature/8067 is the name of the reference on the remote; and * branch tells you that it was really refs/heads/feature/8067 on the remote, i.e., was a branch. Because this was deposited into FETCH_HEAD there's no additional information available.

  • The second line ends with origin/feature/8067. Your remote-tracking name1 origin/feature/8067 (full name refs/remotes/origin/feature/8067) has been created or updated. As before, we have the arrow and the same name. Then we have * [new branch]: this tells us that origin/feature/8067 did not exist before, and that feature/8067 was—as we already know—a branch name on the remote.

Here's what I get updating a Git repository for Git:

   ab15ad1a3b..aa25c82427  master      -> origin/master
   ef7435264c..5a294203ad  next        -> origin/next
 + f98c0007ae...e49ac33073 pu          -> origin/pu  (forced update)
   0f4b6a451a..ff8db353a4  todo        -> origin/todo
 * [new tag]               v2.22.0-rc1 -> v2.22.0-rc1

Again we can work right to left:

  • My origin/master got created-or-updated, from their master. The value of my origin/master was ab15ad1a3b but is now aa25c82427. Since there was a value, it's been updated, not created.

  • My origin/next has been created-or-updated, with everything else basically the same as above (modulo the obvious differences).

  • My origin/pu has been updated by force, i.e., this is not a fast-forward and some commits have been deleted. The source was their pu branch and my origin/pu used to be f98c0007ae but is now ff8db353a4. The fact that there are three dots between the two hash IDs—the other lines have only two dots—means that the update was forced, hence not a fast-forward. The plus sign at the very front means that the update was forced. (Clearly, it's pretty important that the update was forced: I have three announcements to that effect!)

  • My origin/todo has been created-or-updated, and by the time we get to the left side, it's obviously an update.

  • My v2.22.0-rc1 has been created-or-updated, from their v2.22.0-rc1; this is a new tag.

Any time you have a new name (branch, tag, or any other reference), it's by definition a regular non-forced creation and there's no old..new hash available, so the left edge will read * [new whatever].

FETCH_HEAD is special: all updates get written to .git/FETCH_HEAD, usually wiping out whatever was in it before (but with -a or --append, git fetch will append instead). Each fetched reference results in one line appearing in FETCH_HEAD, giving:

  • the hash ID
  • an optional not-for-merge string
  • the type and name of the reference and its source:

    $ cat .git/FETCH_HEAD
    aa25c82427ae70aebf3b8f970f2afd54e9a2a8c6        branch 'master' of git://...
    [snipped for length]
    

The one line that is not marked not-for-merge is suitable for the git pull script2 to fish out and pass that hash ID to git merge or git rebase.


1A remote-tracking name, which most of Git calls a remote-tracking branch, is a reference in your repository whose full name starts with refs/remotes/ and goes on to include the name of the remote, in this case origin, and another slash, and then normally holds the rest of the branch name as seen on that remote.

A reference is just the generalized name for things that are branches, tags, remote-tracking names, refs/stash, and so on: a string-format name, generally starting with refs/, that remembers one hash ID. For a branch, the one hash ID the name remembers is the commit that Git should consider to be the tip of that branch. For a tag, the one hash ID the name remembers is either the hash ID of the commit, or the hash ID of an annotated tag object that contains additional information (perhaps including a signing key), plus the hash ID of the tagged object (typically a commit though any tag can point to any one of Git's internal object types).

Git builds remote-tracking names through a refspec. You can supply a refspec when you run git fetch. If you do not supply a refspec, but do supply a remote name like origin, Git fishes the correct refspec from your configuration:

$ git config --get-all remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*

A standard configuration for origin always has this exact default refspec, but there are some useful nonstandard configurations, such as the one created by git clone --single-branch. You can also make your own totally bizarre refspecs, though depending on how twisted you get, some combinations will result in a non-functioning git fetch.

2Well, back when when git pull was a script, anyway. It's been re-coded in C for speed on Windows.

torek
  • 448,244
  • 59
  • 642
  • 775
  • WOW. Super thanks. This is too much to digest all at once while at work. To fully process your answer, there's a lot I need to look into. I'll get back to you soon – mfaani May 30 '19 at 19:18
  • _`* branch` tells you that it was really `refs/heads/feature/8067` on the remote, i.e., was a branch_ other than `* branch` & `* [new branch]` what kind of indicator exists? – mfaani May 30 '19 at 21:45
  • _Here's what I get updating a Git repository for Git:_ you must just doing `git fetch origin` on any branch with nothing after it ? – mfaani May 30 '19 at 21:54
  • Besides `* branch` or `* [new branch]` you can see `* tag` or `* [new tag]`. My `git fetch` output displays the last of these—and yes, I ran `git fetch` (which translated into the same as `git fetch origin`). – torek May 30 '19 at 22:25
  • Thanks. I get the 2nd line. We created a new branch. About the first line. 1) What’s the purpose of depositing info to `FETCH_HEAD` what happens if that was not done? 2) “on the remote” what part of the 1st line has a mention of ‘remote’? – mfaani May 30 '19 at 23:49
  • (1) The purpose of writing to `FETCH_HEAD` is two-fold: (1a) That's what `git fetch` originally did, before remote-tracking names were invented. In ancient Git (pre-1.5?) `FETCH_HEAD` is the *only* place these hashes went. That old behavior remains available today for those who still depend on it. (1b) Until `git pull` was rewritten in C, the `git pull` script depended on it. (2) Nothing in the first line *explicitly* says anything about the remote, but the remote *is* another Git repository. Being a Git repository, it has branches and tags. Your Git has called up the other Git. [continued] – torek May 30 '19 at 23:55
  • 1
    The other Git has listed, for your Git, its branch and tag and other reference names (and their hash IDs). Your Git has chosen some or all of those references, to copy to your own Git somewhere (and to `FETCH_HEAD`). So `git fetch` shows you the names it saw in the *other* Git, such as `feature/8067`. It abbreviates them, but using the information towards the left, such as `* branch`, we can figure out what they got abbreviated from. – torek May 30 '19 at 23:57
  • To see how this works, run `git ls-remote origin` and observe the output. That's the first data `git fetch` gets. – torek May 30 '19 at 23:57
1

The first line tells you that the fetch yielded a new branch on your local repo, and that you have its HEAD. The second says that the new branch is set up to track the remote branch. (You can have a local branch with the same name as a remote branch, but not be tracking the remote.)

The remote branch wasn't created there necessarily, but may have been pushed up from another developer, for example.

isherwood
  • 58,414
  • 16
  • 114
  • 157
  • Thanks. 1) _The first line tells you that the fetch yielded a new branch on your local repo_ After I did that, I did `git branch`. It wasn't among my local branches. 2) What does tracking a remote mean? I suppose it means if I just do `git fetch` without mentioning what branch to fetch from then it will fetch from the branch its set to track from – mfaani May 30 '19 at 18:26