Danny
Danny

Reputation: 61

How do i check whether the curent branch is a tag release?

I am trying for automation in circleci. For that I need to check whether the current branch in master is a tag release or not.

git log -1 --pretty=%B | grep "Tag version release [0-9]\+\.[0-9]\+\.[0-9]_[0-9]\+\.[0-9]\+\.[0-9]\+"

Using the above command I am able to read the log.

But what i need is the tag: commit sld1kf3ja5ls6kj7gi8rogaeknvaerglreun (HEAD -> master, tag: v1.2.3_0.10.101, origin/master, origin/HEAD)

Upvotes: 0

Views: 159

Answers (1)

torek
torek

Reputation: 487755

TL;DR: consider using git tag --points-at, but be aware of its limitations.

Long

The current branch is never a tag, by definition.

In Git, the current branch is the branch name stored in the special name HEAD. Running git checkout or, since Git 2.23, git switch, allows you to pick a branch by name and set that branch as the current branch. To make branch B the current branch, Git will:

  • replace the current commit with the tip commit of branch B if necessary (or do nothing at all if the current commit is the tip comimt of branch B);1 then
  • write the branch's name into the name HEAD.

So now, after git checkout master or git checkout develop, the current branch is master or develop, respectively. The current commit is the last commit of the named branch.

If, however, you issue the command git checkout v1.2.3_0.10.101—or the equivalent git switch command—the name you requested is a tag name and not a branch name. Git will not write the tag name into HEAD. Instead, Git resolves the name into a commit hash ID. Then, Git detaches HEAD by making sure that HEAD no longer contains any name at all. Instead, Git will:

  • replace the current commit with the selected commit if necessary—as before, if the current commit is the selected commit, nothing is necessary here; then
  • write the raw commit hash ID into the name HEAD.

The effect is that you are no longer on any branch at all.

I need to check whether the current branch in master is a tag release or not.

The phrase current branch in master is simply meaningless.

Every commit has a unique hash ID (it's never sld1kf3j... as the set of letters and digits only includes 0-9 and a-f, so it's more like badf00d or cafebabe or deadbeef, but longer). That one hash ID means that commit, and no other commit, ever.

Meanwhile, every name holds one hash ID. Multiple names may hold the same hash ID. So if you are on a branch because you checked one out, there is a commit. If you checked out a tag, there is a commit, but you're no longer on a branch.

You can check whether the current commit has one or more names as well. That's what the decoration in git log does, for instance. But it may have many names:

$ git log -1
commit <hash> (master, develop, feature, tag: v1.0, tag: beta)

This tells you that the current commit is the given hash and that there are two tags and three branch names, all of which would select that commit. The lack of HEAD -> here implies that while this is the current commit, we probably did not select it via a branch name. (But git checkout --detach master or git checkout --detach develop would result in this same situation, so maybe we did use a branch name and simply also used the --detach option.)

The only really-sure-fire way to be sure that we arrived at this particular commit by some particular git checkout or git switch command is to remember the git checkout or git switch command we ran. If your system does that, use that. If it doesn't, there is no sure-fire way to deal with this.2

You can, however, check whether one or more tag names point directly to the current commit:

git tag --points-at HEAD

would, in the above example, spill out the two names v1.0 and beta. Note that it would do this even if we got here by running git checkout master, though.

If git tag --points-at prints no names, no tags point to the current commit.

To tell whether HEAD contains a branch name right now, consider using:

git symbolic-ref HEAD

which prints the full name of the branch if HEAD contains a branch name:

$ git symbolic-ref HEAD
refs/heads/master

or produces an error if HEAD is detached:

$ git checkout --detach master
[messages]
$ git symbolic-ref HEAD
fatal: ref HEAD is not a symbolic ref

Note that --points-at was new for git tag in Git version 1.7.10, so if your Git is older than this, you would need to upgrade.


1The replace the current commit step consists of, in effect:

  • removing the current commit's files from Git's index and your work-tree, then
  • copying to Git's index and your work-tree, the files from the selected commit.

The selected commit is now the current commit, thanks to this "rip out all the files from commit X and insert all the files from commit Y instead" action. Note that both git checkout and git switch are careful to rip out only files that are "cleanly saved" in the current commit: the checkout or switch will fail, with an error, if this would lose data. You can, of course, force the switch with -f / --force.

2If reflogs are enabled, the reflog has much of the information you might want. But the points-at method is probably better.

Upvotes: 3

Related Questions