How to get the default for the master branch in Git?

余生颓废 提交于 2021-01-23 06:37:08

问题


Since short, GitHub proposes to use main instead of master for the default branch.

How can we get that name, for writing resilient Git aliases? How to get the default for the "master" branch in Git?

I've searched on SO, but none of the solutions in git - how to get default branch? does work reliably for me...

If I'm in branch feature, forked from develop, it will return me develop and not master (or main, from which develop is a fork)...

How to get that "master" branch name, then?

NOTE -- The question could be: why is git remote show origin not showing me master, but develop instead, as the HEAD branch?


回答1:


There are two problems with answering your question

You mention main vs master. Now, the first problem here is that there isn't really any default branch at the moment. There sort of is, but there's no guaranteed way to query it, because the "sort of" part is because there's no common agreement on this yet: not everyone has Git version 2.28 or later installed.

That said, running:

git config --get init.defaultBranch

may produce something in your own Git repository, and if it does and if your Git is 2.28 or later, your Git will use that as the default name for the unborn branch when running git init. (See also commit 8747ebb7cde9e90d20794c06e6806f75cd540142.)

Note that if someone runs:

git init --initial-branch=xyzzy

to create a new, empty repository, the name of the unborn branch in this new, empty repository will be xyzzy, regardless of whether there is an init.defaultBranch setting, and regardless of what might be in it. The --initial-branch option also first appears in Git 2.28.

HEAD

You also asked, regarding answers to git - how to get default branch?:

The question could be: why is git remote show origin not showing me master, but develop instead, as the HEAD branch?

The git remote show command, and the git ls-remote command (try it), work by calling up some other Git repository and getting information from it. Before we discuss this information, let's take a look at how HEAD works in your repository.

A Git repository is, at its heart, a collection of commits. Each commit is numbered with a unique hash ID. All Git systems everywhere use a particular algorithm—currently SHA-1, but there are plans to switch to SHA-256—to compute the hash ID of a commit based on the commit's content, so that all Git systems will come up with the same hash ID for the same commit.

This is how Git works in term of distributing commits. Each repository has a full collection of its own commits. When you cross-connect a pair of Git repositories, such as your own and one over on a system your Git calls origin, they exchange hash IDs. Since the hash IDs uniquely identify the commits, the sender can list a hash ID, and the receiver can immediately tell from that whether he has the commit, or needs the commit. Add in some optimizations based on the commit graph structure and we have most of what we need for the have/want protocol exchange.

Each Git, though, finds commits in its own repository using names: branch names, tag names, and other such names. These come with hash IDs, which find some particular commit. Those commits then find any earlier commits as well.

For the purpose of sending commits, the sending Git in a git fetch pair-up lists out his branch and tag and other such names, so that the receiving Git can figure out which commits to ask for, if any. You can list out your own names—all of them or some selected subset—using git for-each-ref. The default is to list all names that start with refs/.

There is one piece missing from the above picture, and that's the special name HEAD. This special name—it doesn't start with refs/ and Git uses it internally all over the place in various special ways—is normally what Git calls a symbolic ref, and we can read it with git symbolic-ref:

$ git symbolic-ref HEAD
refs/heads/master

This tells us that in this particular Git repository, the current branch is the one named master. (Branch names all start with refs/heads/; other names start with other refs/-based prefixes.) In a non-bare Git repository—the kind that we normally work with—this means someone has run git checkout master or git switch master.

When we use git ls-remote to connect to some other Git, their Git will run git for-each-ref for us, to list out their names. But they prefix their list with the value in HEAD, and if we add the --symref option,1 we get their HEAD in two ways:

ref: refs/heads/master  HEAD
72c4083ddf91b489b7b7b812df67ee8842177d98        HEAD
71ca53e8125e36efbda17293c50027d31681a41f        refs/heads/maint
72c4083ddf91b489b7b7b812df67ee8842177d98        refs/heads/master
a3ce27912f980d787926b113d17f1f532e50162a        refs/heads/next
[snip]

So this tells me that their Git repository has master as their HEAD. The first output line makes this clear directly; the next few lines show me that their HEAD and their refs/heads/master both refer to commit 72c4083ddf91b489b7b7b812df67ee8842177d98, which is less direct.2

The git remote show command has the ability to call up the other Git.3 This means they can have them list out which branch they have as their HEAD. When you see:

  HEAD branch: develop

this merely means that their Git has their HEAD attached to their branch name develop. If their repository is non-bare, this means they ran git checkout develop or git switch develop.

If they have a bare repository, they can still get the same effect, using git --work-tree=... checkout, or GIT_WORK_TREE=... git checkout, or by running git symbolic-ref directly. The branch name to which their HEAD is attached is not necessarily their master or their main, if they have one: they control which branch name, if any, is stored in their HEAD.

There is very little significance attached to this. If their HEAD names their develop, that just means that their HEAD is attached to their develop. Since their branch names are theirs—not yours—this shouldn't matter to you.

There is one place where it does matter, though. If you run:

git clone <url>

instead of, say:

git clone -b somebranch <url>

then you're asking your Git to call up their Git and ask them which branch name they recommend. When you supply -b branch, you're choosing the branch; when you don't, you're telling your Git to follow their recommendation. The recommended branch name is the one to which their HEAD is attached. So they—whoever they are, in control of this other Git repository—should use whatever means they have at their disposal to connect their HEAD to the branch name they personally recommend.

There's no need for you to follow their recommendations. Your clone has your branch names in it. You do not need to use the same names they are using. That's up to you. Most people do mostly use the same names, to make things easier to think about.


1This --symref option is not supported in older versions of Git. When a newer Git is talking to an old Git that can't do symbolic ref transfers, the newer Git has to guess about the older Git's HEAD. This is a somewhat ugly situation and we will just assume that you're using all-newer-Git-versions here.

2This shows you how older Gits can guess: if the hash ID from HEAD matches exactly one branch name, that tells us that this is the branch name. But what if the hash ID from HEAD matches two, or three, or more, branch name hash IDs? That's where the situation becomes ugly.

3In modern Git, that's the default for the way you are using git remote show. I'm not sure if this was ever not the default. The git remote command has a lot of sub-commands though, and many of them don't bother calling up some other Git.



来源:https://stackoverflow.com/questions/65703168/how-to-get-the-default-for-the-master-branch-in-git

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!