Search code examples
gitgit-taggit-describe

When and why exactly does git describe not show the latest tag?


I have three branches: dev, staging and master. When I do git describe the result is v0.1 no matter which branch is checked out.

Following I will describe a workflow of making changed to dev adding a version tag and merging to staging and to master this new version.

  1. git checkout dev
  2. make some changes
  3. git add --all && git commit -m 'just some testing'
  4. git tag -a v0.19.0
  5. git push && git push --tags
  6. git checkout staging
  7. git merge dev
  8. git push
  9. git checkout master
  10. git merge staging
  11. git push

And now I run describe on every branch:

- git checkout dev && git describe && git describe --abbrev=0

Result:

v0.19.0-1-ge147b2d
v0.19.0

What I expected:

v0.19.0-1-ge147b2d
v0.19.0
  • git checkout staging && git describe && git describe --abbrev=0

Result:

v0.17.0-3-g684216f
v0.17.0

What I expected:

v0.19.0-xxxxx
v0.19.0
  • git checkout master && git describe && git describe --abbrev=0

Result:

v0.17.0-16-g99c19c9
v0.17.0

What I expected:

v0.19.0-xxxxx
v0.19.0

enter image description here

Why is that? And how can I have such a process where I make some changes in dev then add a new tag and then propagate those changes with the tag to all the other branches?


Solution

  • You should write all the commands you actually run instead of trying to use English because it doesn't seem to explain the situation accurately enough. For example, your wording uses "merge into" and "merge to" which may or may not describe the same thing for you. For a merge, you usually do something like git checkout some-local-branch && git fetch && git merge origin/some-other-branch. All the details may be important if you don't understand the whole situation yourself for sure. And if you run some commands on e.g. remote machine over ssh connection, make sure to point this out, too.

    From the question (as worded 2021-04-27T14:24:13+00:00) it appears that your Process 2 is missing git push --tags (or maybe git fetch) and if you try to run git describe somewhere else but the original repository (that is, your working directory in practise) you'll not see the new tag at all.

    I'd suggest starting with git show NEWTAG in all workspaces (or "branches") you're trying to use. You should get the same SHA-1 on every workspace. You could also run git show HEAD to verify that the current HEAD actually matches what you think it should match. Also, if you can run gitk you can try running gitk NEWTAG HEAD to get visual repsentation of the problem or even gitk --all -n 10000 to show all branches up to 10000 latest commits.

    If you cannot use gitk, you can also try running e.g. git log --oneline --graph --decorate -n 50. As an alternative, you can also run git log --oneline --graph --decorate -n 50 --format=%h%d to list the latest 50 commits from the DAG without titles so that you can share the results here in SO if you need more assistance.

    Update after seeing the screenshot

    Your branch master is not at the same position as any of your tags so git describe should not emit any given tag name as the sole output. Instead, it should say something like v0.2-4-gf5d6ced which basically means "v0.2 plus 4 patches with the HEAD pointing to SHA-1 starting with f5d6ced". The four patches for this example are a5312dc, 7dceb15, b4cd4f6 and f5d6ced which are not included in v0.2 below.

    Here's an example I created:

    *   f5d6ced (HEAD -> master) Merge branch 'staging'
    |\  
    | *   b4cd4f6 (staging) Merge branch 'dev' into staging
    | |\  
    | | * 1fa7a37 (tag: v0.2, dev) Updated testfile yet again in branch dev
    * | |   7dceb15 (tag: test) Merge branch 'staging'
    |\ \ \  
    | |/ /  
    | * |   a5312dc Merge branch 'dev' into staging
    | |\ \  
    |/ / /  
    | | _   
    | * 96cd0ac (tag: v0.1) Updated testfile in branch dev
    |/  
    * d626941 Added testfile in branch dev
    

    Screenshot of the above textual repsentation

    The v0.1 and v0.2 are annotated tags and the test is a non-annotated tag.

    $ git checkout dev && git describe
    Switched to branch 'dev'
    v0.2
    
    $ git checkout staging && git describe
    Switched to branch 'staging'
    v0.2-2-gb4cd4f6
    
    $ git checkout master && git describe
    Switched to branch 'master'
    v0.2-4-gf5d6ced
    
    $ git checkout master && git describe --tags
    Already on 'master'
    test-3-gf5d6ced
    

    This is caused by the fact that when you create a merge, you create a new commit which obviously will have its own SHA-1 identifier and the existing tag does not point to the merge because tags always refer to specific versions.

    Are you sure you're not actually running e.g. git describe --abbrev=0 which selects just one tag from the most recent tags and may prefer the first parent for any given merge?

    If you're actually trying to figure which tags your given branch already includes, you can run something like this:

    $ git checkout master && git tag --merged
    Switched to branch 'master'
    test
    v0.1
    v0.2
    

    or sorted by the time tags were created, latest first:

    $ git checkout master && git tag --sort=-authordate --merged
    Already on 'master'
    test
    v0.2
    v0.1
    

    And if you want just the latest tag, you can run

    git tag --list --sort=-authordate --merged | head -n1
    

    See git help tag for more details. For this case, the latest means authoring timestamp of given tag. For tags the author timestamp and commit timestamp are equal but this is not forced anywhere as far as I know. If the difference matters to you, only you decide which timestamp you need.

    Further explanation for your specific "error" case: you didn't actually run git describe as you claimed but git describe --abbrev=0 which lists the closest tag. Note that this is in DAG topology and it may be totally different from latest or newest tag. For your example case, both v0.17 and v0.19 have distance 1 from the HEAD of branch staging and 2 from the HEAD of master. In addition, the older tag comes from the first parent which is why you get v0.17 as the response. I'd recommend using git tag --list --sort=-authordate --merged | head -n1 instead if you want the latest tag that's included in given branch. However, I'd strongly recommend tagging master branch releases instead of random patches in development or staging branches. Then you could use just git describe without any flags