简体   繁体   中英

What does checkout tag mean in git

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

  1. git pull
  2. Find commit hash of that tag
  3. git reset --hard hashcode

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

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. (Eg 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:

  • You were at the commit, but git also knew you were working on the branch 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.
  • He was at the same commit, but on no particular branch (no commit was possible). Also, 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.

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 , ie, 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", ie, 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.)

1 Actually, 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.

2 Or, 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.

3 Or, 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM