Home > Net >  git: How do I "see" a remote branch?
git: How do I "see" a remote branch?

Time:04-22

On Azure, I've created a new branch based on a master branch.

From my desktop I then ran:

git fetch

I expected to see the remote branch when I run:

git branch -l

...but I don't. I then tried:

git branch -r

... to see remote branches. My branch is still not listed.

I'm really not understanding why the above commands don't work, what command should I be using?

CodePudding user response:

Git overuses the word branch so heavily that it largely loses all meaning. It's like being at a party where everyone is named Bruce. We have to be super-careful with this word.

Now, the thing to know about Git is that a Git repository is, at its heart, a collection of commits. The commits are what Git is all about. They're numbered, and each one has two things:

  • a snapshot of all files, frozen for all time; and
  • some metadata (information about the commit), also frozen for all time.

The numbers are big, ugly, random-looking things (hash IDs or OIDs) that are impossible for humans to remember or deal with sensibly. So a repository also comes with a names database. That means a repository can be viewed as two databases. Both are simple key-value stores, with the commits being in the "object database" and found by hash IDs, and the names being in the "names database" and found by their name. The value you get when you look up a name is a hash ID; looking up a commit hash ID gets Git the commit; and that's how you get a commit.

The names in the names database include branch names, tag names, and other such names. These aren't branches, unless by branch you mean the things that these are, and then they are branches. So the word branch, by itself, means these, except when it doesn't mean these. (This is why I recommend being careful with the word branch.)

So, with that mess temporarily out of the way, let's just concentrate on the raw hash IDs. When you have two repositories, these two repositories can connect to each other. They can then share their commits (using git fetch and git push for instance), and when they do so, they will all use the same hash IDs for the shared commits. Different commits must have different hash IDs. The same commits, once shared across two separate Git repositories, must have the same hash IDs.

What this all means is that the hash ID of any given commit is not just big and ugly, it's also unique to that one particular commit. If you make a new commit, your Git software has to give that Git a unique hash ID, never used before and never to be used again, anywhere, in any Git repository, ever. If you then have your Git software send that commit to some other Git software managing some other Git repository, that other Git software must use the same hash ID your Git just gave to your new commit.

So, it's the hash IDs that matter. Two Git repositories, managed by two different Git software implementations, connect to each other and exchange commits, by raw hash ID.

But here's the problem: humans can't deal with the raw hash IDs. We like names! We think main and dev and feature/short are keen. But which commit is main? Well, my main is my latest commit. Your main is your latest commit. If we've both made new commits, my main and your main have to translate to different hash IDs.

The result is that no Git repository can ever trust any other Git repository's names. Each repository has its own private names database, in other words. But I can connect my Git software to your Git software and get your commits from you, and when I do that, I would like to know which commit hash ID represents your latest main commit.

My Git will store this for me, but it won't use the name main to do that. Instead, I'll define what Git calls a remote, using git remote add:

git remote add origin ssh://[email protected]/you/yourrepo.git

for instance. I can use any name, not just origin, and any URL that works for me, so this is just an example; but if I use git clone to copy all of your commits, my Git software will automatically save the URL under the name origin by doing this git remote add for me, after it creates a new repository. So origin is a pretty common name here.

Anyway, after my Git software connects to yours, I'll get all your commits that are new to me—any that we both already have, I already have, and my Git knows this because you and I have the same hash IDs here—and my Git software will save them away in my objects database. Then my Git software will take your branch names and change them into my remote-tracking names: your main will become my origin/main, your dev will become my origin/dev, and so on. Basically my Git sticks my remote name, origin, and a slash, in front of your branch names.

So once this is all done, I'll have your latest commits, and my Git will turn your branch names into my remote-tracking names. To have my Git list out my remote-tracking names, I run git branch -r. This lists them as, e.g., origin/main. Or, I use git branch -a, which has my Git list out my branch names and my remote-tracking names; for no obvious reason, Git now lists my remote-tracking names as remotes/origin/main and so on.1

For all this to work, though, I must run git fetch. That's because my clone of your repository just sits here on my laptop, until I actually do run git fetch. There's no reason for my Git to reach out to yours all the time: I have a full copy of every version of every file you've ever had in my clone, or at least, as of the last time I ran git fetch. All we ever do is add commits to a repository, so when you add new commits, I have to run git fetch to obtain those new commits.

If your Azure setup has yet another clone—if there's a Git repository over on GitHub, for instance, and then you had Azure clone that Git repository to Azure and you've made a new branch name in the Azure clone—well, that didn't affect the GitHub clone. The GitHub clone is its own repository, with its own set of branch names. You have to get the GitHub clone to fetch from the Azure repository—except that GitHub won't fetch. Instead, you'll have to get the Azure clone to push to the GitHub repository.

Pushing is like fetching in that it transfers new commits, but it's also unlike fetching. That is, if I have my own pair of repositories, one on my laptop and one on GitHub, and I make a new commit on my laptop:

<edit some files>
git add -u
git commit -m "some terrible commit message"

I now have to send my new commit to my GitHub clone, using git push for instance:

git push origin main

Here origin is the name of the remote, as before, and main is the name I use to identify the most recent commit I just made, which is the one I want to send. My Git software calls up GitHub's Git software and ends up connected to my repository on GitHub, and my software hands over the hash ID of my latest commit. The GitHub software sees that it does not have that commit—there's nothing in the GitHub repository with that hash ID—so they grab that commit from my Git. But now the different thing happens:

  • My Git software now asks their Git software: Please, if it's OK, create or update the name main in your repository to record this latest commit.
  • They check to see whether it's OK. It probably is, and if so, they create or update their main.

The result is that I've made GitHub update (in this case) their main branch-name. If I make a totally new name in my repository:

git branch newname

I have to run git push such that I ask GitHub to (please, if it's OK) create the new name newname over there:

git push origin newname

This time they'll have the latest commit, so the send new commits phase of this whole operation does nothing. But the please if it's OK create or update a name phase creates the new branch name in the GitHub repository.

Note that I do not have to use the same names in my laptop clone that I use in my GitHub clone. Each repository has its own names database, and if I want, I can create a new branch name hello and then have GitHub create instead the name world. I don't normally want to do that because it makes things complicated; our feeble human brains can't handle hash IDs and don't do well with using different names on the two sides; we want to just call everything Bruce, to avoid confusion.

  • Related