Search code examples
gitgit-pushgit-tag

Will tag referencing commits unreachable from any branch be lost?


I worked on my project, on branch branch. Then I reverted using

git revert tag-name

Then I did some progress and committed. When I try to push I get this error:

Updates were rejected because the remote contains work that you do not have locally

I do not want to lose my progress before the revert, but want to remove from branch the commits made after, keeping them available for future reference just under the 1.00.00rcXX tag.

I created a clone of the repository, tagged head of branch there, and rewound branch to the revert commit:

git tag -a 1.00.00rcXX -m message
git reset --hard HEAD~1 # remove last commit from current branch

Now I want to force push my changes back to my original repository, so all the commit ahead of branch will be lost.

Will my tag be lost too, as it is based on commits unreachable from branch?


Solution

  • Unreachability and garbage collection

    Only really unreachable commits can be garbage-collected, and thus lost forever.

    Quoting man gitglossary:

    unreachable object

    An object which is not reachable from a branch, tag, or any other reference.

    As long as the tag exists, the part of history it links to is considered reachable and thus not garbage-collected. The tag keeps those commits “alive”.

    Pushing the tag and force-pushing the branch is safe

    Git tries to prevent you from making non-fast-forward changes in any branch. You have to pass the -f option to git push to perform push after resetting (rewinding) the branch. If you keep in mind the implications of overwriting history, you can push both the tag referencing original state of the branch and the new head of the branch and you will lose nothing.

    Just run this:

    git push --tags
    git push -f origin your-rewound-branch
    

    Better use branch instead of a tag

    By the way, using tag for such a thing is probably not a good idea. Probably you will want to delete that dead-end part of development history someday, which you should not do with tags. Using a branch (head) instead of a tag is more suitable for such a purpose. Just use (maybe with a more descriptive name)

    git branch 1.00.00rcXX
    

    instead of

    git tag -a 1.00.00rcXX -m message