Reputation: 269
I made a new repository in github and named it as try
.The folder is empty,and i made two new branches :
ashwin
anil
When I try to list these branches,it is not listing me the branches.The image contains the commands i runned:
The folder try is completely empty with .git
folder
Upvotes: 1
Views: 1346
Reputation: 487865
I made a new repository ... and i made two new branches
The thing is, you did not make two new branches. You simply switched the name of the branch that you were on, twice, without creating anything. This requires some fancy explaining.
A new repository is, initially, completely and totally empty.1 It has no branches and no commits. Nevertheless, you are on branch master
, as git status
will tell you. There is something fundamentally weird about this.
The problem here is that the way Git handles branch names like master
is that for them to exist, they must contain the raw hash ID of some existing, valid Git commit. If your Git repository has one commit, or two, or thousands, you can have branch names. Even if you have only one commit, your Git repository can now have ten thousand branch names. But if you have no commits, your Git repository cannot have any branch names, because with no commits, there are no valid commit hash IDs.
The hash ID of each commit springs into being at the time you—or whoever is creating the commit—create the commit. Until that moment, its hash ID does not exist. After that, its unique-to-that-one-commit hash ID exists. It remains valid for as long as that commit itself also exists. And, now that this commit hash ID exists, you can store this hash ID in any number of branch names. You can now create as many branch names as you like, all of which can contain this hash ID, or of course any other valid, existing commit hash ID.
Git needs to know which branch name to create, when you create that first commit. This peculiar state of being on a branch that doesn't actually exist yet is there so that the first commit you create will create the branch name for you.2 That is, your initial, totally-empty repository has no commits and no branches can exist. Then you use git commit
to create the very first commit. Now some branches can exist. One will exist, because git commit
will create it. The name that git commit
will create is the name you told Git to store as your current branch.
When you're in this funny state, git checkout -b asdf
doesn't create branch asdf
, it just changes the name of the non-existent branch that you're on. Later—after one or more commits do exist—running git checkout -b
does create additional branches. This all might make more sense if git checkout -b
refused to do anything in this funny state. You can also use git checkout --orphan
when you are in this funny state, so there would be no loss of functionality. But git checkout --orphan
is an option that was new in Git 1.7.2, so git checkout -b
has to continue to work to be backwards-compatible with older versions.
1When using GitHub's "create new repository" feature, they offer you the ability to immediately add one commit containing a README
file, and optionally, .gitignore
and/or LICENSE
files. When using the git init
command to create a new repository, it is empty: you must add this first commit yourself. It's clear that whichever method you used, you did not have any commits yet.
2That branch name is stored in the file .git/HEAD
. You're not supposed to use this directly, but it helps, I think, to actually look at what's in that file. Don't edit the file yourself directly; just take a quick peek at it to get an idea of how Git uses it. Always use Git commands to change its contents, so that you don't break things. If you get the .git/HEAD
file wrong, Git will actually stop believing that the repository is a repository at all. Note also that if you start using git worktree add
, that HEAD
file stops being the only HEAD
, and you can't rely on it after all—but it's still OK to look in the .git
directory now and then, as long as you remember that Git itself reserves the right to change how everything works internally. Git only promises that all the user commands will still work, in the next version of Git.
Consider the case of a new, totally-empty repository with no commits. You write some files, run git add
on them, and run git commit
, and now the first commit does exist. It gets a new and unique hash ID—we can't predict what it will be,3 we only know that it will be new and unique—but let's just call it commit A
, and draw it like this:
A
Git will write the actual hash ID, which is probably more like 7c20df84bd21ec0215358381844274fa10515017
, into whatever branch name you choose, but if you haven't chosen one yourself, the default name will be master
. We then say that the name master
points to this commit, and we can draw it:
A <-- master
The special name HEAD
, written in all capitals, contains the name of the branch; we say that HEAD
is attached to this branch name, and we can draw that too:
A <-- master (HEAD)
You can find the actual hash ID of this commit using git rev-parse
:
git rev-parse HEAD
or:
git rev-parse master
will print out the actual hash ID of the (one and only) commit A
. You will also see this hash ID printed when you run git log
.
When we then create a new commit, it gets a new big ugly hash ID, which again we can't predict, but we'll just call it B
for short. Commit B
will contain, as part of B
's information, the actual raw hash ID of commit A
. We therefore say that B
points to A
, and we can draw that too:
A <-B
Having just created B
, Git now writes B
's hash ID into the name to which HEAD
is attached:
A--B <-- master (HEAD)
That is, master
now points to B
, and B
points to A
. We can create a third commit C
, and master
will now point to C
:
A--B--C <-- master (HEAD)
Let's now create a new branch name dev
without switching to it:
git branch dev
The picture now looks like this:
A--B--C <-- master (HEAD), dev
Now let's switch to dev
, using git checkout dev
. The current commit remains commit C
, and both names master
and dev
continue to point to commit C
, but now HEAD
is attachd to dev
instead of master
:
A--B--C <-- master, dev (HEAD)
Now let's create a new commit, which gets a new unique big ugly hash ID, but let's just call it D
. Git updates the name to which HEAD
is attached, too, so let's draw the result:
A--B--C <-- master
\
D <-- dev (HEAD)
Note that commits A
through C
are on both branches, but commit D
is only on branch dev
.
If we now switch back to master
(using git checkout master
, which selects commit C
again) and make another commit E
, the picture becomes:
E <-- master (HEAD)
/
A--B--C
\
D <-- dev
The names master
and dev
each hold just one hash ID, but we can find all the commits by starting at E
and D
and working backwards. Three of the five commits are on two branches right now. We can, if we like, create a new branch name at any time, pointing to any of these five commits. For instance, if we find the raw hash ID for commit C
and run:
git branch feature <hash>
we get:
E <-- master (HEAD)
/
A--B--C <-- feature
\
D <-- dev
The commits, A-B-C-D
on dev
, A-B-C
on feature
, and A-B-C-E
on master
, are also called branches. It's very important, in Git, to keep in mind that when someone says branch X, they might mean branch name X, which identifies one particular commit. Or they might mean the commit identified by branch name X, plus the commit that comes before it, plus all other earlier commits. Or—because people are human—they might even mean something else. It's up to you to figure out exactly what they really mean.
What someone means is often reasonably clear from context: the phrase the master
commits means commit E
and zero or more of the earlier ones, rather than the name master
itself. But just saying master
is ambiguous, and when it matters, it can matter a lot. You might need to ask someone to be more explicit.
3The reasons for this are a bit complicated but one part is quite clear. The new commit has a date-and-time stamp—actually two date-and-time stamps, but one suffices here—and the date and time in it are the moment that you actually create the commit, as shown on your computer's clock. Since we don't know at what exact second you will create the commit in the future, we can't tell you what your new commit's hash ID will be.
Upvotes: 1