Reputation: 5643
My senoir coder wanted me to checkout tags for release each week on dev server
I didn't get that before so all i was doing was
git pull
so i was always on master branch
Now he did that and he was not on any branch when i checked.
when i asked him why code is on no branch
and he told me that thats what it should be.
I didn't understand that. can anyone please explain what he does and he wanted and what i was doing wrong
Upvotes: 0
Views: 520
Reputation: 490038
To understand this properly, start with this: those hash codes (SHA-1 values like 5f95c9f...
) are the "true names" of commits. All other names—branches and tags—are just aliases, but of course much easier to remember and relate-to. Let's call these "user friendly names". For instance, the tag v1.9.0
tells you that this is the commit that is git version 1.9.0, while 5f95c9f850b19b368c43ae399cc831b17a26a5ac
1 does not mean anything obvious. Branches have one more special property, too.
Each commit records the (raw) SHA-1 of its previous (parent) commit, as well.2 This means we can draw commits as a chain, with the newest on the right and each one pointing leftward to its parent:
A <- B <- C
(Each letter here represents some SHA-1.) A branch label "points to" the tip-most commit on that branch, by containing the raw SHA-1 of the commit. For instance if branch label dev
contains the SHA-1 of commit C
, then branch dev
is commit C
. Meanwhile C
lets git find B
, and B
lets git find A
, so that A <- B <- C
is also "the branch"—this is confusing, to be sure: git calls both the whole sequence "the branch" and also the tip-most commit "the branch". (However, it's usually clear from context whether "branch foo
" means "the tip-most commit" or "the branch formed by starting at the tip-most commit and working backwards.)
In addition, git reset
is not the command you want to use here; we'll get to that in a moment.
Now, if you create a tag name, the convention—which git will help you enforce—is that the tag name points to one particular commit,3 and never moves. In other words the commit SHA-1 for a given tag name is always the "true name" of one particular commit.
If you create a branch name, however, the convention is that the branch name does move. A branch name like master
resolves to the current tip of that branch, so master
might resolve to 5f95c9f...
. Whenever you add a new commit to a branch (by running git commit
or git merge
, usually, though there are a few more cases that also add new commits), the branch name is updated to point to the new commit you just added. That is, it now resolves to the new branch tip. You did a git commit
, so you got a new commit, so the branch label is "moved" to the new commit.
This is where git reset
comes in. The reset
command is how you make a "non-standard" move. In particular, it lets you move a branch name "backwards".
Suppose you have this series of commits:
... <- E <- F <- G <- H <-- master
where commit H
is the current tip of branch master
. When commit H
was made, commit G
had been the tip of master
, i.e., master
resolved to something like 9c8ce73...
. But then git commit
created 5f95c9f...
so master
now resolves to that.
If, for some reason, you want to remove commit H
from branch master
, you can use git reset
to "move the label backwards", i.e., to point it at commit G
instead:
git reset --hard 9c8ce73
This makes the branch label master
resolve to commit G
. Commit H
is effectively removed (it's not really deleted just yet—git keeps things so you can "unremove" them for a while—but it will look like it's gone), and if you make a new commit now, you get a new, different commit with a new, different SHA-1. That's certainly not what you want here.
If you already have some tag name(s), you can do git checkout tagname
. This tells git to get "off" the current branch, resulting in what git calls a "detached HEAD". When you're in this state, if you make new commits, git will add them as usual, but there is no "user friendly name" for these: You're not "on a branch", so git will not move the branch to the new tip. It can't: there's no branch to move. But if you don't make new commits, this doesn't matter anyway. You can just get back "on" a branch with git checkout branchname
.
So:
git checkout tagname
takes you off branches, into "detached HEAD" state. Here you can look at the tree as it is for the raw SHA-1 that tagname
is an alias for. (If you just want to see that SHA-1, use git rev-parse tagname
.)git checkout branchname
puts you on the given branch, checking out the branch-tip. (If you just want to see the SHA-1 of the branch-tip, use git rev-parse branchname
.)git checkout SHA-1
works exactly like git checkout tagname
. In fact, that's how git checkout tagname
works: it resolves the tag-name to a raw SHA-1, and checks out that commit. That's also how git checkout branchname
works, except that git recognizes that branchname
is a branch-name, so it puts you "on the branch" so that a future git commit
will move the branch tip for you.But:
git reset --hard commit
takes whatever branch you're on and makes the branch-name point to the commit you supply. To put it another way, it "peels off" the branch label from the current branch-tip-commit and "pastes it on" to whatever SHA-1 you gave to git. If you gave git another tag or branch name, it simply resolves the name to the correct raw SHA-1, and then makes that be the new branch-tip for your current branch. (And it also checks out the tree that goes with that commit, of course.)1Actually, the tag v1.9.0
points to an annotated tag object, but that in turn points to the commit I was quoting above. The principle is the same, though.
2Or, in the case of a merge commit, it records all its parent commit IDs. However, none of that matters for the rest of this discussion.
3Or, as in git itself, some annotated tag, which in turn points to a commit. And of course, that commit points to its parent commit, which points to its parent, and so on; so the tag is "just as good" as a branch, in one sense.
Upvotes: 2
Reputation: 83411
Background
A tag is just a label corresponding to a commit.
A branch is similar to a tag, but it moves from commit to commit as your work progresses. Often a branch is referred to as the commit it points to, and all ancestor commits.
Multiple branches can have the same commit in their history. (E.g. master
and branch-a
both have commit with hash abcdef123456
.)
Answer
Assuming the commit hash was on the master
branch, and that you don't have any non-pushed changes, there isn't a huge difference between what you and your friend did, other than is way was easier.
The difference:
master
(so if you made a commit, is would be on the branch master
). Additionally, if you had changes on master
since the tag, --hard
would remove those changes from master
. If you hadn't pushed them, you risk losing them forever.checkout
does not change history.Thus, checking out the tag is easier, cleaner, and less prone to error (losing any current work, accidentally committing, etc.), but for your purposes, essentially the same.
Upvotes: 2
Reputation:
It sounds like your senior developer wanted you to do this:
git checkout <tag>
You see no branch
when you do that, because you're checking out a tag reference, instead of a branch reference.
What you were doing before is probably not what your senior dev wanted you to do. git reset
is used to move your current branch reference to other commits, and when you use --hard
, it can actually cause you to lose work.
The reason why you don't see no branch
when you use git reset --hard
is because the reset moves the branch around with your checkout. Contrast that with git checkout <tag>
, which doesn't move the branch with your checkout, but checks-out a tag instead.
Upvotes: 0