0

I'm learning to contribute to open-source projects on Github. I want to try fixing an issue that applies to the 3.x branch, but I'm confused why Github Desktop is showing me branches from both origin and upstream:

enter image description here

How is it possible that I could switch to a branch on the upstream repo if I'm working on a fork? That doesn't make sense to me (but bear in mind I come from a Mercurial background so maybe I'm not fully understanding Git's branches - I think they exist outside the version control somehow?).

If the upstream repo has some commits ahead of my fork on the 3.x branch and I click on upstream/3.x, does my working directory somehow gain the changes from those upstream commits? I don't think that makes sense but I can't understand why else it would offer to switch to an upstream branch.

Clonkex
  • 1,067
  • 3
  • 13
  • 23

1 Answers1

1

(but bear in mind I come from a Mercurial background so maybe I'm not fully understanding Git's branches - I think they exist outside the version control somehow?).

Git branches work like Mercurial's bookmarks. They're not immutably attached to commits but act as flexible pointers to some commit ID (see Mercurial's Bookmarks docs), so it is entirely possible for several repositories to have their own bookmarks pointing to the same commit.

(In fact, that's what happens when you push to GitHub – first the commits are uploaded, and then the remote repository's "main" or "master" bookmark (i.e. branch) is updated to point to them, so now both the local and remote bookmarks independently point to the same commit. And similarly, when you create a new local branch off "master", it's just creating a second bookmark that points to the same commit as "master".

Though it seems that Git branches aren't kept as strictly in sync with the remote repository as Hg bookmarks are. Diverging is expected, so the branches downloaded from a remote repository are always namespaced with "reponame/", while Hg's docs imply that a diverged "foo@reponame" bookmark is supposed to be dealt with quickly.)

How is it possible that I could switch to a branch on the upstream repo if I'm working on a fork?

You're not only working on a fork; you're working on a fork of the fork. The cloned repository that you have on your desktop is fully separate from the fork that you have on GitHub – it has its own branches and everything. (Neither the "origin/" branches nor "upstream/" ones are actually local to the repo that GH Desktop is showing; they're only locally cached copies of remote branches.)

Git repositories aren't limited to having a single URL to push/pull from – it is very common to have two when working with forks, and to directly fetch commits and branches from both. For example, you might integrate the newest upstream changes by merging "upstream/3.x" into your local "3.x", then push to your GitHub fork's "origin/3.x".

If the upstream repo has some commits ahead of my fork on the 3.x branch and I click on upstream/3.x, does my working directory somehow gain the changes from those upstream commits?

Yes, it does. Your desktop repo has full copies of all branches from the upstream repo (as of the last fetch) and you can check out their commits, create local branches off them, merge or cherry-pick individual commits into a local branch, etc. (This is more general than just "upstream", you can configure any number of remotes, e.g. to track someone else's development fork.)

However, at least using the command-line git tools, checking out a remote branch (whether it's "origin/3.x" or "upstream/3.x") is a temporary operation – it doesn't automatically create a local branch that you can work on, it only checks out a "detached" commit. You can still create a branch off it, it's just not automatic.

(Though if you try to check out a non-existent local "3.x" branch, Git magically creates it from "origin/3.x".)

I haven't used GitHub Desktop for a very long time, so I don't know exactly what happens if you check out a remote branch through the GUI – it may offer to create a local branch "3.x" named after the remote one, or it might not.

u1686_grawity
  • 426,297
  • 64
  • 894
  • 966
  • Ok, so where Mercurial branches are tags permanently attached to commits, Git branches are more like collections of named commits, independent of said commits. When you checkout a branch, you get the commits but not necessarily the branch. So if my fork on Github is up to date with the upstream repo, it doesn't matter whether I choose `upstream/3.x` or `origin/3.x`, right? _"I don't know exactly what happens if you check out a remote branch through the GUI"_ Assuming I'm reading it right, it appears to just automatically create the local branch without asking if you select one from the list. – Clonkex Apr 30 '22 at 09:22
  • 1
    Yes, if they both point to the same commit, you get the same result, you end up checking out the same files, and in both cases you either get a new _local_ branch named `3.x` or end up not on a branch at all (detached)... Usually those forked branches end up being out of date though. (Often I push --delete all unnecessary branches as soon as I fork – there's no need for _me_ to have a "3.x" branch, neither locally nor in my github; I can just start my local feature branches directly off the "upstream/3.x" branch every time.) – u1686_grawity Apr 30 '22 at 10:45
  • 1
    _(That said, there may be a *small* difference between checking out `origin/foo` vs `upstream/foo`. Each local branch can be configured to "track" a specific remote branch, so that e.g. `git pull` can be run without parameters and will automatically know what to merge – so when you branch off upstream/foo, Git will by default assign upstream/foo as the remote tracking branch. But that's purely local configuration in .git/config and isn't actually part of the local branch/bookmark as such; the `git branch -u` command is used to change the tracked remote branch.)_ – u1686_grawity Apr 30 '22 at 10:47