So, I tried to search for an answer but all I find is different schemes of version control but not the difference.
2 Answers
Sounds like you are coming from svn.... trunk would be just another branch... just like any other that you might create. What is generally called trunk in svn is called master on git, but actually, that's a convention because there is no mandate to have a master branch on a repo, it's just that most repos do have it.... and you might have a branch called trunk in git, if so you like.

- 26,375
- 3
- 36
- 60
Git does not have a "trunk" (though you can pretend that any particular branch is your "trunk" if you like).
For that matter, in one sense, Git doesn't have branches either. It really all depends on how you define branch. See What exactly do we mean by "branch"? Of course, if we define the word branch in a more useful way, Git does have branches. They are just very different from SVN branches.
Interestingly, SVN itself also doesn't have branches, in some sense. Here is a quote from the Red Bean book:
You should remember two important lessons from this section. First, Subversion has no internal concept of a branch—it knows only how to make copies. When you copy a directory, the resultant directory is only a “branch” because you attach that meaning to it. You may think of the directory differently, or treat it differently, but to Subversion it's just an ordinary directory that happens to carry some extra historical information.
As for Git, the important thing to remember is that Git is all about commits. The commit is a major leitmotif of Git. Every commit carries a full snapshot of your source code, plus some metadata: information about the commit. Every commit has a unique hash ID,1 reserved to that commit and only that commit. For instance, b697d92f56511e804b8ba20ccbe7bdc85dc66810
is the commit that is Git 2.22 in any clone of the Git repository for Git itself. No other commit anywhere will have that hash ID.2
Because each commit has a unique hash ID, we—or at least Git—can talk about or find the commit given just the hash ID. So in general, each commit stores, in its metadata, the hash ID of some other earlier commit. Specifically, the earlier commit that we—or Git—care about most is the hash ID of the immediate parent of the commit: the one that comes right before the commit.
Note that when we make a new commit, we know exactly which commit should come before the new commit we're making now. That's because we make a new commit by checking out, with git checkout
, some existing commit. Then we work on that commit and do our git add
commands and run git commit
. The new commit should have, as its parent, the hash ID of the commit we checked out.
Let's take a quick look at how this works. But commit hash IDs are big and ugly and impossible for mere humans to work with (except via cut and paste), so let's use single uppercase letters to stand in for these commits. Let's take a simple, tiny repository with three commits in it, and call them A
, B
, and C
as we made them in that order. Each commit stores the hash ID of its parent, which makes up a backwards-pointing chain of commits:
A <-B <-C
That is, commit C
says my parent is B
, and B
says my parent is A
. A
has no parents—it can't, it was the first commit. The technical term for this is that A
is a root commit, and you'll see [root commit]
printed by Git when you make the very first commit in a new repository.3
If we check out commit C
, do some work on it, and then run git commit
, Git will:
- package up our updated files to go into the new snapshot;
- collect our metadata: name and email address, the date-and-time of this new commit, and so on, and our log message to remind us later why we made this new commit;
- put the hash ID of commit
C
in as this new commit's parent into the metadata too; and - write out a new commit, obtaining a new and unique big ugly hash ID.
Because new commit D
's parent is C
, this automatically extends the chain:
A <-B <-C <-D
Of course, D
gets a commit hash ID, which is big and ugly and unique to D
and there is no way we could ever remember it. But we don't need to remember it: that's what the computer is for. Let's have the computer remember it, by storing the actual hash ID in some name.
That name is—usually—a branch name like master
. That is, before we make D
, the picture really looks like this:
A--B--C <-- master
The name master
remembers the actual hash ID of commit C
. We run git checkout master
and Git uses the name to find the ID, and the ID to find the commit, which gets us the content into our work-tree so that we can work on it.4
We do our work and run git add
and git commit
and make new commit D
. The last step of git commit
is that Git writes D
's actual hash ID—whatever it is—into the name master
:
A--B--C--D <-- master
master
no longer remembers C
, but rather D
; but that's OK, because D
remembers C
. At one point earlier, master
remembered A
; then it remembered B
, which remembered A
; then it remembered C
. Now it remembers D
.
To create a new branch in Git, you just tell it to make a new name, pointing to some existing commit, like this:
A--B--C--D <-- master, feature
The trick now is to have Git remember which branch name to update when you run git commit
, and that's where the special name HEAD
, in all capital letters, comes in. When you run git checkout master
, Git attaches the name HEAD
to the name master
:
A--B--C--D <-- master (HEAD), feature
When you run git checkout feature
, Git attaches HEAD
to feature
instead:
A--B--C--D <-- master, feature (HEAD)
Both checkout commands extract commit D
, which is where all your files are stored. And both branches have all four commits, at this point—but if you're on feature
and make a new commit now, that new commit gets a new big ugly hash ID, which we'll call E
. The new commit has D
as its parent, and as the last step of git commit
, Git writes E
's hash ID into feature
because that's where HEAD
is attached:
A--B--C--D <-- master
\
E <-- feature (HEAD)
If we now run git checkout master
, Git puts commit D
back into our work-tree and attaches HEAD
to master
. If we now make another new commit, the new commit's parent is D
again, and master
gets updated this time:
F <-- master (HEAD)
/
A--B--C--D
\
E <-- feature
These commits—these backwards-looking chains—form a graph, technically a Directed Acyclic Graph. Branch names like master
and feature
are, in effect, just labels pointing to particular nodes within the graph. When you say "branch feature", be careful about whether you mean the name feature
, or commit E
, or commits E
+D
+C
+B
+A
, or whatever.
Summary
In Git, a branch name is just a label pointing to one specific commit. The branch itself is found by starting at that commit and working backwards through the graph. The graph is composed of the commits and their parent linkages.
In SVN, as the Red Bean book says, a branch is a copy of a directory (plus some metadata). That's not true for Git—the word branch is ambiguous, and sometimes means the name, the short label holding a commit hash ID, and sometimes means some subset of the overall commit graph as found by starting with the hash ID in the name. When by "branch" we mean "some set of commits", it's those commits, not some directory.
1These hash IDs are actually cryptographic checksums of the commit data (the snapshot and metadata). Because of this, no commit can ever be changed. If you actually take the raw commit data—which you can via git cat-file -p
; try git cat-file -p HEAD
some time—and make some change to it and store it back into Git, what you get is a new and different commit with its own new, unique hash ID. You can think of Git as an append-only database containing commits. That's not strictly true, but it's a good first approximation.
2Technically, this just means no Git-repository-of-Git can re-use that hash ID. Your own project, if it is not the source for Git and is never connected to a Git repository for Git, could use that hash ID. Chances are very good that it never will: each commit you make has only a 1 out of 2160 chance to us that hash ID. 2160 is a very big number: 1,461,501,637,330,902,918,203,684,832,716,283,019,655,932,542,976, or about one and a half quindecillion in the short scale.
3A branch name has to point to some existing commit. This gives rise to a problem: in a new and totally-empty repository, there are no commits, so there can be no branches. It's the act of making the first commit—the root commit of the new repository—that creates the initial branch name, usually master
. You can make new root commits later, by using git checkout --orphan
or by using git fetch
to another Git repository that has an unrelated history, but a typical Git repository tends to have only one root commit. That one root commit is on every branch!
4Because of the cryptographic checksum hash ID, every commit is frozen for all time. But this is also true of the snapshot that each commit saves. The files "inside" a commit—which are technically just more objects in the Git object database—are also frozen for all time, and are kept in a special, read-only, Git-only, compressed format. Because they're read-only, they can be shared across different commits, which saves a lot of space: you might have a project with 4000 files, and you change 2 and make a new commit. Git re-saves every file in the new commit, but 3998 of them are actually just re-using the previous snapshot: there are only 2 new snapshots.
This is great for archival, but useless for doing actual work. These files are all in this freeze-dried Git-only form, and your computer needs its files in their normal everyday form. So Git has to unpackage the freeze-dried files, rehydrating them. Those rehydrated copies go into your work-tree, where you can see and work on them. You're never working directly on the in-Git copies.
This process of freeze-drying files and rehydrating them uses an in-between area that Git sometimes calls the staging area, or sometimes calls the index. These two words are terms for the same thing. It's important to realize that the index / staging area has copies of every file from the current commit, and that Git makes new commits from the index / staging-area rather than from the work-tree, but we won't go any further into that here.

- 448,244
- 59
- 642
- 775