1

If I'm in the master branch, and I create a new branch, will the new branch have the contents of master? Is this the case every time? For example, what if I then go to my feature branch and create a new one while in there, will it contain the contents of the feature branch but be a new one?

  • Creating a Git branch, by itself, really just creates a pointer to a certain commit. Assuming you create a `feature` branch from `master`, it would just point to the HEAD commit of the current `master` branch. – Tim Biegeleisen Dec 09 '20 at 04:53

1 Answers1

2

The tricky part here is that the basic question is not well formed. The problem here is actually the word branch, which has more than one meaning. See What exactly do we mean by "branch"?

If and when you mean branch name, well, each branch's name has one value: a commit hash ID. So if you're on master, and master has, say, hash ID a123456..., and you run:

git branch newname

(successfully), you've just created a new branch name newname that also has hash ID a123456.... In that sense, you could claim to have copied branch master.

But the word branch also means a collection of commits ending at the designated tip commit. You have not copied any commits, so by the same logic, you have not copied anything at all.

I think that for many people, a picture helps. Imagine a Git branch this way: it's a series of commits. Each commit has some unique hash ID: a big ugly string of letters and digits—technically, a number expressed in hexadecimal—that Git uses to find that particular commit, in the big database that Git has that holds all the internal Git objects, including the commit objects. Rather than writing down those hash IDs, though, we'll just use single uppercase letters to stand in for each one, like this:

... <-F <-G <-H

Here, H stands in for the hash ID of the last commit in this sequence. (Obviously then, older commits are on the left, and newer commits are on the right.) Commit H has two parts: data (a snapshot) and metadata (information about the commit), and the metadata include the hash ID of the previous commit in the chain: the hash ID G. So commit H points to commit G.

Commit G itself also has two parts, snapshot and metadata, and its metadata contain the raw hash ID of earlier commit F. G, then, points to F.

This means the commits themselves, in a Git repository, form a backwards-looking chain. All we need to do is find the last commit in the chain, and point Git to that particular commit. From there, Git can zip along, backwards, through the history—the commits in the chain—to find earlier versions. Each commit has a full snapshot of every file, so comparing the earlier files to the later files—a git diff—tells us what changed.

We do, however, need a way to find these last or tip commits. The tip commit of any particular chain is where we start: at the end. To find these tip commits, Git allows us to use names. The names can be any kind of name, not just a branch name, but branch names have one special property: using those names with git checkout or git switch, we get "on the branch".

So, if we have a chain like this:

...--F--G--H   <-- master

then the branch name master identifies commit H. To make a new branch, we simply pick one of these commits and tell Git: make a new branch name and point it at that commit. If we don't pick one, Git picks the current commit; if we do pick one we can get, e.g.:

...--F--G   <-- previous
         \
          H   <-- master

We'd get this with git branch previous hash-id, where hash-id is the hash ID of commit G. We could find that particular hash ID using, e.g., git log.1 Of course, now that we have two branch names, we need a way to indicate which name we're actually using:

...--F--G   <-- previous
         \
          H   <-- master (HEAD)

Here, the special name HEAD is attached to the branch name master, indicating that we're still on master and hence still using commit H. If we run git checkout previous or git switch previous, we'll get:

...--F--G   <-- previous (HEAD)
         \
          H   <-- master

which means we will be using the name previous and commit G.

Whenever we make a new commit, Git:

  1. writes out a snapshot of all files;
  2. gathers and writes out the appropriate metadata, to produce the new commit, with its new unique hash ID; and
  3. writes the new commit's hash ID into the current branch name.

The appropriate metadata, in step 2, includes the current commit as the parent of the new commit. So in the state in the last drawing, if we make a new commit on previous, we get:

          I   <-- previous (HEAD)
         /
...--F--G
         \
          H   <-- master

and now our branches have diverged. If we go back to master:

          I   <-- previous
         /
...--F--G
         \
          H   <-- master (HEAD)

and then make a new name feature pointing to commit H, get on feature, and make one new commit on feature, we get:

          I   <-- previous
         /
...--F--G
         \
          H   <-- master
           \
            J   <-- feature (HEAD)

You can create and delete branch names at any time you like. There are just two rules:

  1. A branch name must point to some existing commit (always).
  2. You cannot delete the branch name you have HEAD attached to.

There's a third thing you should watch out for, but it's not a hard and fast rule:

  1. It's a bad idea to delete the only name that lets you find a commit.

In our example above, if you now delete the name previous, you get:

          I   ???
         /
...--F--G
         \
          H   <-- master
           \
            J   <-- feature (HEAD)

Hash IDs look random (though they actually aren't random at all). How will you ever find commit I again? It would be easy if you could see its hash ID, but if you can't ... well, there are some clues in the gitrevisions documentation, but we'll leave this all for later.


1There are many ways to name a commit. The gitrevisions documentation covers this. Note that it is full of jargon, and condenses a lot of information into a very small space, so you'll likely have to re-read it many times.

torek
  • 448,244
  • 59
  • 642
  • 775