[HN Gopher] Proper Use of Git Tags
___________________________________________________________________
Proper Use of Git Tags
Author : da-x
Score : 189 points
Date : 2022-05-23 15:30 UTC (7 hours ago)
(HTM) web link (blog.aloni.org)
(TXT) w3m dump (blog.aloni.org)
| bmon wrote:
| I can't agree with having a source file include the tag. It is an
| eternal source of merge conflicts and pain, unless you take steps
| to automate it. And in that case, does the file add much value
| anymore?
|
| My personal experience with go modules and versioning has been
| really positive. In that ecosystem - you only define your major
| version in the mod file and rely on the VCS for everything else.
| da-x wrote:
| I don't think that it poses an issue with merge conflicts. It
| is likely not an issue as long as the tagging is only made on
| the main branch by the release managers.
|
| I know it is working well for Linux kernel hackers. Linus does
| all the tagging, and I don't recall issues with merge conflicts
| on the top Makefile with the part that holds the version.
| zbuf wrote:
| I think you're assuming that all software results in a single
| "release manager".
|
| In many environments, multiple branches of software are
| deployed and maintained at the same time.
|
| Even your example with Linux; I don't think that is correct
| -- Linus doesn't tag the stable branches, and others. There
| is a centralised agreement of how the version numbers are
| maintained though.
| da-x wrote:
| My example is relevant to tagging in branches that may
| merge back into the main one. The stable branches in Linux
| are cherry-pick branches that don't get merged back and
| therefore creating tags there is harmless.
| WorldMaker wrote:
| Yeah, I often prefer, when possible, to automate in CI dumping
| the git describe output to a .gitignored source file and
| letting tags themselves be the "source of truth".
|
| Related to that "tags as source of truth" is using tags as a
| deployment trigger. A release manager applying a tag can be a
| signal or gate for a version to go to later environments. (For
| instance: CI builds from main branches stop at Dev
| environments, CI builds triggered from new tags automatically
| move on to UAT and Staging environments.)
|
| Also, another tip I've found useful for people with more
| "monorepos": tag name restrictions match branch name
| restrictions and you can use a "folder structure" of tags. You
| can name tags things like subcomponent/v1.0.2. Some git UIs
| even present such tags as a folder structure. Doing that can
| confuse git describe, of course, so finding an arrangement that
| works for your project may be a balancing act. I've used
| lightweight tags for subcomponents so that git describe doesn't
| "see them" by default and then you can use the git describe
| --tags that also takes lightweight tags into account if you
| need a "subcomponent version" for subcomponent tag triggered
| deployments (and then you just need to remove to remove the
| folder prefix).
| aarchi wrote:
| > you can use a "folder structure" of tags. You can name tags
| things like subcomponent/v1.0.2. [...] Doing that can confuse
| git describe
|
| Using the --match option, `git describe
| --match='subcomponent/*'` fixes this problem. It filters the
| tags that are considered to only those matching the pattern,
| so that a later tag for another subcomponent will not be
| used.
| zbuf wrote:
| Yes, having a version number centralised in source code is
| exactly the thing Git helped us many times to avoid.
|
| Also ties in with the author's recommendation to begin tags
| with "v". My experience is that excluding it is better. Then a
| simple "git describe" readily gives the version number in
| scripts with no sed or reprocessing.
|
| I've seen many conventions with Git. It's interesting to hear
| some rationale, but a stretch to describe these suggestions as
| the "proper" way.
| jonnycomputer wrote:
| How is the version information included in the software if
| you don't include it in the source? Do you have a deploy
| script that modifies source based on the git tag, or ?
| WorldMaker wrote:
| I sometimes dump git describe to a JSON file rather than
| modifying a source file and let the build bundle it as an
| embedded resource. You can .gitignore the JSON file to keep
| it from accidentally getting checked in (and causing merge
| conflicts).
|
| As also pointed out, many build tools that want or need
| version numbers often also have command line flags or can
| take environment variables instead of using source files.
| t0astbread wrote:
| Some languages and build systems also allow you to set
| constants from compiler flags (Go for example). Other
| systems make the entire build configuration an executable
| program (Gradle).
| CameronNemo wrote:
| The v prefix really helps us only run ci on version tags
| instead of random tags as well. If you are strict and always
| use semantic versions for tags, you can just keep doing what
| you are doing. But if you ever want to create some random tag
| later and don't want your automation to try to use it as a
| version number, the v prefix helps.
| howinteresting wrote:
| How does it work if a single repository contains more than one
| independently usable library?
| wnoise wrote:
| Well, if they're actually independent, clearly those
| shouldn't be in the same repository...
| howinteresting wrote:
| That doesn't follow. Why should they not be in the same
| repository? They may be related but independently usable.
| tricky777 wrote:
| mono repo approach (or something to that direction)
| t0astbread wrote:
| "Independently usable" does not have to mean "totally
| independent". The libraries could be related to the same
| product using the same infrastructure.
| WorldMaker wrote:
| Tags in git allow just about the same naming options as
| branches, and "v" prefix is just a convention not a
| requirement. So rather than applying a tag v1.3.2 you could
| use a "folder structure" such as library1/v1.3.2 and
| library2/v3.1.2. Today I learned that you can use `git
| describe --match="library1/v*"` to get the version relative
| to just "library1" if you are versioning this way (in a
| monorepo, for instance).
| TekMol wrote:
| What are the pros and cons of branches+merge-commits vs tags?
|
| So instead of a "v4.11-rc7-87" tag you would have a
| "v4.11-rc7-87" branch and a merge commit that holds the meta info
| about that branch.
| da-x wrote:
| These are not mutually exclusive. Tags relate to commits
| irrespective of the containing branch or the merge history.
| Hackbraten wrote:
| Branches are mutable, tags aren't. You can add a commit to
| `v4.11-rc7-87` anytime. Now your branch has grown past the
| merge commit. Confusion ensues.
|
| Compared to a tag, you'd have to deliberately go out of your
| way to move a tag (`git tag -f`). Generally, you should be able
| to trust your team members not to move a tag.
| ww520 wrote:
| They are for different purposes. Branch is for working on the
| code. Once done, use tag to snapshot a release. The branch can
| move forward as needed.
| WorldMaker wrote:
| Annotated Tags hold meta info for the tag. (git tag -a) That's
| why a lot of advice is to always use annotated tags. They look
| like a commit with an author, a message, and can be signed,
| etc.
|
| Branches can change over time, whereas tags are largely
| immutable. A change to a tag always requires a force push and
| if you've got branch protection tools in your repository host's
| arsenal you can often entirely prevent tag changes.
|
| I'd also like to point out that often if you are using merge
| commits as your "version management tool" there's a lot of
| people that use "branch per environment" strategies and need to
| merge between environments. There's a lot more risk in that
| approach than a tag-based approach: if a tag doesn't change
| after it is applied, then you don't need to rebuild binaries to
| deploy it again. If you don't rebuild binaries between
| environments you have to make sure the same binaries work in
| all environments, which is good practice. I've seen too many
| times "branch-per-environment" strategies wind up with per-
| environment code that is difficult to untangle and makes
| testing and debugging difficult and merge conflicts more likely
| and more complicated and increases the risk of per-environment
| bugs.
| da-x wrote:
| The tag in the repo is `v4.11-rc7` not `v4.11-rc7-87`. The
| `-87-g28cf22d0ba28` suffix is added by `git describe`.
| Robin_Message wrote:
| Since the OP is here, I am confused.
|
| In the first section, are you saying that:
|
| a) tags can and should be named to include the sha at the end;
| and
|
| b) git commands silently discard everything before "-g" if what
| follows is a sha?
|
| I feel like I've missed something as I find b) very surprising.
| (Consider giving someone the string
| $LATEST_VERSION_NUMBER-g$MALICIOUS_VERSION_SHA; I can't work out
| an exact exploit but it seems wrong to only process the SHA.)
| da-x wrote:
| I'll try to clarify. The `<tag>-g<hash>` string is _not_ the
| name of the tag, it's a string emitted by `git describe` based
| on the existence of `<tag>` in the history.
|
| Of course I'm not suggesting that tag names should include the
| hash. The existence of the tag `v4.11-rc7` allows other commits
| to have nicer derived names.
|
| EDIT:
|
| Also to your last inquiry, it may be indeed a surprise that Git
| resolves `<anystring>-g<githash>` to `<githash>`, but some may
| argue it's a feature, not a bug :)
| WorldMaker wrote:
| Also, git describe's output is not just <tag>-g<hash>, it is
| <tag>-<commitcount>-g<hash>. That number of commits since the
| tag counter can be handy in its own way (such as it is
| sometimes handy when trying to figure out which branch the
| <hash> is most likely from).
|
| I'm curious if the git resolution algorithm that accepts
| describe strings also verifies/checks the commit count
| matches. Glancing at the documentation [1] it says that it
| specifically matches describe output strings (the docs call
| it <describeOutput>) and not _just_ "<anything>-g<hash>", so
| it may actually check the tag existence and verify the commit
| count.
|
| [1] https://git-scm.com/docs/gitrevisions
| captn3m0 wrote:
| Another important reason to use annotated tags: Tags without
| annotation are just a reference to a commit and cannot contain
| any metadata, such as the release date or the release authorship
| information.
| globular-toast wrote:
| Lightweight tags are not supposed to be pushed. They are meant
| to be used to help with scripts and stuff. It's a great example
| of weird git UI that lightweight tags are the default when 99%
| of of users would never want to create one.
| unholiness wrote:
| Our company uses a tag, quite improperly, to indicate our "last
| successful build" on each branch, so our local builds can pull
| e.g. compiled .o files from that build and speed up the local
| build process. A tag is improper since it needs to move with
| every successful build. All relevant commands need --force to
| update it and it can rarely create headaches when machines
| disagree.
|
| I believe the right thing functionally is a child branch, updated
| automatically with either a merge or a force-push on new
| successful builds. But it feels not quite right conceptually, and
| it's harder to explain to new developers (who can already get
| overwhelmed with handling multiple branches). Is there a non-
| branch solution for having a moving unique label?
| avar wrote:
| Don't clobber the branch or tag, instead create dated tags with
| a name like built-YYYYMMDD-HHMMSS. Then have downstream systems
| pick whatever the latest tag is.
|
| You _can_ force push it, but why not keep a trail of what your
| past state was?
| azundo wrote:
| > The commit that changed the version in source is the one to be
| tagged
|
| I've never understood this practice of not immediately bumping
| the version in source after a release. We update the version in
| source to the next logical version (usually a patch bump with an
| alpha0 pre-release tag) immediately after tagging and publishing
| a release. This way you just need to look at the version in
| source to understand where you're at in a release process, and
| only a single commit has the full release version in source,
| which is also tagged as such. This doesn't seem to be a common
| pattern, so shat are the downsides of this approach? Am I missing
| something?
| epage wrote:
| This is what I was used to at a prior day job (another one just
| didn't keep a version in source). When I took over cargo-
| release [0], this was also the default though not anymore.
|
| Benefits of keeping the last version
|
| - Easier to detect when a change occurred since the last
| release
|
| - (Rust specific) It makes it harder to patch a registry
| dependency with a git dependency because the versions will
| never align [1]. This is why the default changed in cargo-
| release.
|
| - The "next version" is just speculation. Will the next release
| bump the pre-release version, patch, minor, or major?
|
| A downside to keeping either last version or next version is if
| someone builds from master, the bug report could be confusing
| unless you include the git hash (and whether the repo was
| dirty).
|
| I've seen some advocate for not keeping a version in source at
| all [2]. This article advocates against it but doesn't give the
| reason. I guess one is it requires you to have all tags locally
| which is a silent failure mode when you don't and disallows
| shallow clones.
|
| [0] https://github.com/crate-ci/cargo-release
|
| [1] https://github.com/crate-ci/cargo-release/issues/82
|
| [2] https://github.com/rust-lang/cargo/issues/6583
| js2 wrote:
| My repos have a `make_release {bump | tag}` script for this
| purpose. The repos have both a develop and a main branch. The
| develop branch always has the next version with a `-dev`
| suffix. e.g. `4.6.1-dev`.
|
| Then, running `make_release tag`:
|
| 1. Sets the version to `4.6.1`, commits it, tags it.
|
| 2. Sets the version to `4.6.2-dev`, commits it.
|
| I then merge the 4.6.1 tag to main and push main, develop, and
| the 4.6.1 tag to the repo.
|
| If development calls for a minor or major release, that's what
| the `bump` option is for. It prompts for which part of the
| version string should be incremented and creates a commit doing
| just that.
|
| Setting the version usually involves touching a couple of
| files. e.g. a source code constant and a podspec or some other
| metadata file. The script really helps preventing any mistakes.
| Symbiote wrote:
| This is more-or-less the default pattern with Java, completely
| automated by Maven.
| blibble wrote:
| maven's release plugin used to do this (and I think still does)
|
| it was a never ending source of merge conflicts
|
| branching also causes problems (and mistakes)
|
| vs. the build process deciding (possibly with some human input)
| what the tree's version is, then tagging it
| globular-toast wrote:
| Why have the version in the source code at all? A
| build/packaging process should query git at build/packaging
| time to get the version (using git describe) and produce
| versioned artifacts (which can be source code or binaries).
| grumbel wrote:
| Sometimes people don't use git to get the source. The
| "Download ZIP" function on Github for example includes no
| version number at all as far as I can tell, only the branch
| name in the filename.
|
| For GitLab there there exist a workaround by using
| .gitattributes to create a VERSION file with
| "$Format:%(describe:tags)$" which will get expanded to the
| git describe string on archive creation, so the version
| number even survives in a .zip. GitHub however ignores
| .gitattributes and so far I haven't seen another way to get a
| version number into the .zip other than just including it in
| the source.
| glacials wrote:
| I'm fine with this sacrifice -- if someone downloads HEAD,
| they are not running a "version", so it would be misleading
| to have the source think it's at 1.0 or 1.1 if really it's
| at a commit between those two versions. I have my build
| scripts call the version "develop" or similar if this is
| the case.
| DANK_YACHT wrote:
| Not related to your broader point, but you can download
| source from a release via
| https://github.com/<org>/<repo>/archive/refs/tags/<tag>.zip
| grumbel wrote:
| This works too:
| https://github.com/<org>/<repo>/archive/HEAD.zip
|
| Gives a HEAD.zip that contains a "<repo>-<sha1>/" folder
| and the latest source.
| da-x wrote:
| OP here. I agree with this as well, you are not missing
| anything. I was meaning to write another post about a similar
| approach.
|
| To illustrate to readers, let's say we are developing over a
| tag `v1.2-pre` in `main`, and now the code has stabilized. The
| idea is to release a tagged `v1.2`, then in the `main` branch
| immediately release a tagged `v1.3-pre` that follows it.
|
| We obtain the following:
|
| 1) `main` branch commits look like `v1.3-pre-<number>-g<hash>`
| in `git-describe`.
|
| 2) A maintenance branch may have been forked from the commit
| that was tagged with `v1.2`, so for the commits in that
| `release/1.2` branch you automatically get
| `v1.2-<number>-g<hash>` as output of `git describe`.
| Hackbraten wrote:
| I feel that both variants have their merits.
|
| One possible downside (of version bumping immediately after
| release) is that if you use the major/minor/patch scheme, you
| can never be sure that you're actually bumping the correct
| number. The upcoming release may be a major, a minor, or a
| patch release, and it might take you a while until you know
| enough about completed work items so you can make up your mind
| which one it's going to be.
| tjoff wrote:
| Not sure why that is a downside? Once you realize you need to
| update minor or whatever then update it, done. As a bonus you
| have great visibility into why and when the minor needed to
| update.
| OJFord wrote:
| One complexity with that that comes to mind is how do you
| then track whether you've already bumped minor/major since
| last release and so don't need to again? Maybe it's rare
| enough and quick enough to manually check that that's not a
| problem, depends on the project I suppose.
| [deleted]
| CameronNemo wrote:
| As opposed to having to track later when you bump the
| version whether you need a patch/minor/major bump?
|
| Seems like any way you do it you have to keep track. IMO
| version numbers are slightly easier to keep track of than
| breaking changes. Changelogs are not always structured.
| Vinnl wrote:
| If you do it at the time of bumping, you can just look at
| the then-current version number to decide what new
| version a major, minor or patch release will result in.
| If you do it the moment you introduce e.g. a breaking
| change, you'll have to check whether this is the first
| breaking change since the last release (i.e. keep the set
| version number as-is), or if the one that it's currently
| set to is what it should be.
|
| Minor annoyance, but still.
| CameronNemo wrote:
| Yes, but what I am saying it is way easier to go back and
| look at what the most recent release was (most SCMs have
| a page for all the tags, and there is git tag), but it is
| harder to go back and figure out if you had breaking
| changes (would need to use conventional commits or
| similar, then parse the gitlog or structured changelog).
| Vinnl wrote:
| You'll have to figure out if you had breaking changes
| regardless of when you change the version number, no? My
| strategy there is to add to the 'unreleased' section of
| the changelog as they are introduced.
| OJFord wrote:
| GP's point (I think I agree now, I was only saying it was
| a potential issue) being that that's a lot easier to do
| at the time - you know you've just made a breaking change
| (or you should do; as much/more than you ever will) so
| that's the easiest time to bump the version
| appropriately.
|
| An alternative model I suppose would immediately have
| major bump, minor bump, and patch bump branches; then you
| just commit to the appropriate one, and I suppose keep
| major rebased on minor rebased on patch. (And master =
| major I suppose.)
| azundo wrote:
| We do this by looking at the patch version. For example,
| current version in source is 2.2.1-alpha0. This means the
| last bump was a patch version from 2.2.0 to 2.2.1, so if
| you want a minor bump, then you need to bump to
| 2.3.0-alpha0. Now that the patch version is 0, it's that
| someone has already bumped the minor version since the
| last release, so no need to do so again. This would break
| down if someone bumps to 2.3.1-alpha0 unnecessarily but
| otherwise it's immediately obvious looking at the current
| version in source whether someone has already bumped the
| minor version.
| anonymous_sorry wrote:
| > One complexity with that that comes to mind is how do
| you then track whether you've already bumped minor/major
| since last release and so don't need to again?
|
| I wonder if it really matters that release version
| numbers only increment by one. If not, just bump anyway
| when appropriate change is made - no need to check.
|
| In practice I think the problems would be a) having to be
| very disciplined about this on every commit, rather than
| having a reminder to consider it as part of a release
| process, and b) ordering version numbers from different
| branches when merging to mainline
| OJFord wrote:
| True, that'd be a decent way to approach it. Though at
| that point perhaps you may as well actually release all
| the versions too.
|
| Or you could bump every time as you describe, but on
| every major/minor bump make sure the parent commit is
| released first (which would be >=1 commits since the last
| one and have at least a patch bump). And I suppose you'd
| never need to bump patch if that was just a lone thing
| that happened post-release in prep for the next.
| moron4hire wrote:
| I thought about doing that, but I realized that I have no way
| of knowing how pervasive my next set of changes will be,
| whether it will warrant a patch or a minor version bump. The
| major ones are much easier to predict; I don't go into them
| without prior planning. But sometimes, what I think are going
| to be bug fixes turn out to be API changes. So is 2.19.3 going
| to go to 2.19.4 or 2.20.0 next week? No clue.
| azundo wrote:
| Bump it in source to 2.19.4 immediately, and then to 2.20.0
| as soon as there is code that requires a minor version bump,
| then to 3.0.0 as soon as a major version bump is required.
| Then your version in source is always semver compatible vs by
| definition being off until you cut the next release as soon
| as you introduce a breaking change.
| Groxx wrote:
| > _Tag push permissions_
|
| Agreed entirely on restricting tags (they tend to have meaning
| and expected semantics outside the repo, which makes them risky),
| but also! Teach people more about git, or unix CLI patterns in
| general. `git log test` is ambiguous about it being a tag (or
| branch) or file/folder, but `git log -- test` is not. `--` as an
| ambiguity-preventer is a very common pattern, it works in many,
| many CLI tools.
|
| ---
|
| One that hasn't been included here: don't rely on tags for any
| kind of business logic, if you have literally any way to avoid
| it.
|
| Tags are _mutable_ , and do not have a history of when you
| changed them. They're plenty handy for "human, enter a thing to
| use" purposes, but you should _immediately_ turn that into a
| commit sha and then only use that commit sha.
| WorldMaker wrote:
| Annotated tags can be signed and you can check tag signatures
| in addition to commit hashes. Admittedly, if you don't trust
| the remote repo you don't trust the remote repo even with
| signatures.
|
| Similarly, many repository hosts can help you setup tag
| protection as a part of branch protection tools, but while that
| helps with your own repos it doesn't generally help with remote
| repos.
| Groxx wrote:
| Checking signatures will tell you that X created tag Y, but
| tells you nothing about "Y has not changed", regardless of
| how Y has changed. But yeah, I wish more setups would sign
| things.
|
| And agreed, tag protection rules do exist and are _fairly_
| common. Though by far the majority I run across do not
| protect tags or branches _by default_. And even if they do,
| external systems may or may not honor changes - that 's why
| dependency management lock-files exist, to detect changes
| like this where the "name" (i.e. tagged version) stayed the
| same but the content changed.
|
| Or in a different flavor, you have Go modules, where you
| cannot ever remove or mutate a tagged version in the main
| proxy... but you can change it in github, and now your web-
| UI-visible code differs from what people download. Which may
| be worse, because while go.sum will store the _go module
| checksums_ and can complain if you pull the wrong _contents_
| , that checksum doesn't match the sha it pulled. If you have
| a semver-compatible tag, the git sha isn't stored anywhere,
| you just have `require thing v1.2.3` and the go module
| content hashes. Trying to "recover" the sha from this can be
| rather painful, as you essentially have to check the module
| checksum for all shas in a repo... assuming it even still
| exists.
| WorldMaker wrote:
| Yeah, at the end of the day it is all about trust. If you
| trust that X creates tags that don't change, that signature
| is a trust document.
|
| Right, as with many things in computing often you want
| "trust, but verify". Trust a good tag by a good author not
| to change, but also go ahead and store a hash in a lockfile
| and verify it, just in case.
| avgcorrection wrote:
| Wait. Aren't tags immutable?
| colonwqbang wrote:
| Nope. A tag is just a file in the .git directory. Delete the
| file, delete the tag.
|
| $ rm .git/refs/tags/v1.0
|
| or in git syntax
|
| $ git tag -d v1.0
|
| For this reason one should never use tags when pulling code
| from untrusted repos, instead use the SHA1 hash which is much
| harder to forge.
| avgcorrection wrote:
| Um okay.
|
| That is not what anyone means when they talk about
| immutable objects or refs in Git. I can delete a commit
| from `.git` but they are still considered immutable.
|
| A branch is mutable since you can push it forward without
| `--force` as long as the current commit becomes an ancestor
| of the next tip. Can you change a remote tag without
| `--force`? I don't know off the top of my head. But I doubt
| it.
| TobTobXX wrote:
| Checked it for you: To /tmp/foo1/
| ! [rejected] ddd -> ddd (already exists)
| error: failed to push some refs to '/tmp/foo1/'
| hint: Updates were rejected because the tag already
| exists in the remote.
|
| I think any ref is 'mutable' by these standards, and any
| hash is immutable (that's the entire point of a hash).
| Groxx wrote:
| You can delete a random commit, but if anyone references
| it transitively, it'll immediately detect that breakage.
| E.g. you can't modify or remove commits "in the past" on
| your main branch. And "moving" a commit creates _a new
| commit_ , with a different sha.
|
| Tags do not do that. Moving or removing a tag retains no
| history about the move, nor is the old value left hanging
| around somewhere (after pruning), nor will anyone who had
| not yet pulled the tag notice the removal, as with
| branches. _Most_ configs will complain about the tag
| disappearing or moving, as with branches, but that
| depends on your config and the command you ran.
|
| (annotated tags _do_ have their own sha and creation date
| and whatnot, which is great, but next to nothing
| references them. and removing them from a commit leaves
| no evidence that it ever was on that commit, as the
| commit is unmodified)
| avgcorrection wrote:
| > Most configs will complain about the tag disappearing
| or moving, as with branches, but that depends on your
| config and the command you ran.
|
| Needing `--force` with a default setup is literally all I
| meant by "immutable", apparently a cursed word in this
| context (the tip of a branch is supposed to be able to
| move in that common-history sense of movement). Gawd.
| colonwqbang wrote:
| If you don't know, maybe you could give me the benefit of
| the doubt?
|
| In any case, the syntax to delete a remote tag is just
| e.g.
|
| $ git push origin :mytag
|
| After that you are free to push a new tag to replace the
| old, with no warnings or --force flags.
|
| When we use a tag to specify the version of a dependency,
| we trust the maintainer not to do this. If we don't have
| that level of trust we can use SHA1's instead. We should
| not pretend that there is anything in git that tries to
| prevent a tag from being rewritten by someone who wants
| to.
| [deleted]
| lamontcg wrote:
| annotated tags are immutable, they're part of the history
| that makes up the sha.
|
| normal tags are just labels that can be changed or deleted at
| will. removing a normal/lightweight tag from history doesn't
| change any commits and doesn't require a force push.
|
| that is why the article recommends annotated tags. you have
| to force push to rewrite those. then the git describe tags
| based on those will be immutable unless someone goes out of
| their way to rewrite history.
| [deleted]
| Groxx wrote:
| Annotated tags affect _their own_ sha (because they
| actually have one), but they don 't affect the commit you
| tag in any way. Otherwise you wouldn't be able to add them
| at a later date - it'd change that commit's sha.
|
| If you move a tag, annotated or no, the .git/refs/tags/x
| file will contain the new sha it points to... but the
| _history_ of that `x` is not stored anywhere. The fact that
| it used to point to [old sha] is gone for good, and the old
| sha will eventually get garbage collected (via pruning),
| just like if you remove a branch.
| lamontcg wrote:
| Oh that's weird, I always thought the next commit would
| have its gitsha affected by the annotated tag and you
| couldn't just delete it, but I just tried that and it
| deleted fine...
|
| Now I'm not sure what the point is of annotated tags
| other than the default git describe behavior.
|
| Everyone else can enjoy Cunningham's Law working like a
| charm.
| tome wrote:
| Yeah, the "tag called test" example is strange, given that
| "branch called test" has exactly the same problem.
| da-x wrote:
| Yes, but a pushed tag `test` pollutes a local `test` name for
| everybody, whereas `test` as a local branch is just a local
| branch. A remote `test` branch is only referred via `<remote-
| name>/test` from a local POV.
| avgcorrection wrote:
| It only pollutes the local repo if you pull it explicitly
| (or with `--all`) from the remote.
| da-x wrote:
| IIRC, in `git fetch` if a tag is contained in one of the
| updated branches, you get it automatically without
| specifying an additional flag. What you say is true for
| 'orphaned tags' which no remote branch contains.
| CamelRocketFish wrote:
| The author suggest prepending v to a tag name for the sake of
| shell completion. This assumes that everyone will be interacting
| with git tags using a shell. I disagree that a v should be
| prepended for that reason.
| Tyr42 wrote:
| GitHub let's you do a partial filter. So it helps there too.
| silverwind wrote:
| Yes, this practice of adding a v is common, yet pointless. I
| prefer my git tags to be valid semvers.
| wnoise wrote:
| This works iff you never want to tag anything but semvers.
| This is an unusual and strict policy. As soon as you want the
| ability to move outside this you need something like
| namespacing. Prepending v is a pretty lightweight way to do
| this.
| inetknght wrote:
| > _The author suggest prepending v to a tag name for the sake
| of shell completion. This assumes that everyone will be
| interacting with git tags using a shell._
|
| I would argue that any tool (such as a GUI app) which doesn't
| provide the depth of usability that a shell offers is, in fact,
| a deficiency in the GUI or tool. If your GUI doesn't offer
| completions similar to a shell then your GUI tool is inferior
| to a shell.
| V-2 wrote:
| This is usually the case. GUIs are superior in some aspects
| (eg. visualization of complex branch structures), inferior in
| others (eg. add more friction - many operations can be done
| faster from the console). As far as Git goes, I see GUI
| clients as complementary rather than full-scale substitute
| for the terminal.
| ed25519FUUU wrote:
| I don't like semantic versioning because it's difficult to sort.
| E.g. 1.2 is more than 1.100, and that doesn't even include fix
| versions.
|
| Has there been a better proposal to semantic tags which makes
| organizing and sorting them easier?
| paol wrote:
| Semantic versions can't be sorted trivially, it's true. For
| projects that benefit from the "semantic" part of semantic
| versioning the benefits outweigh that minor inconvenience. But
| not everything needs semantic versioning.
| ssully wrote:
| It's not semantic versioning, but a project I am on started
| using calendar versioning[1]. I was hesitant to try it at
| first, but it's kind of growing on me. It's really easy to
| organize and sort. We have a pretty regular release cadence so
| it was easy to implement, but I could see it being more
| complicated for certain projects.
|
| [1]: https://calver.org/
| klysm wrote:
| I think calver is good for things that don't really have an
| API per se. Stuff like GUI applications.
| jlokier wrote:
| In fact there are standard-ish sorting methods that work fine
| with mixed text and version numbers such that 1.100 is more
| than 1.2, and v1.100 is more than v1.2.
|
| Git has built in version sort, though it's not the default.
| GitHub shows tags in version sort order in the drop-down tag
| selection.
|
| Here are some commands that use that sort order:
| ls -v # Linux only. ls
| | sort -V # Most modern OSes.
| git tag | sort -V # Git tags in version
| order. git tag --sort=v:refname # Same as
| above, it's a git builtin. git config tag.sort
| v:refname # Set default sort order for `git tag`.
| git config versionsort.suffix -pre # Make 1.2-pre1 sort before
| 1.2. git config versionsort.suffix -rc # Now
| 1.2-pre1 < 1.2-rc1 < 1.2 < 1.2-patch1
| teddyh wrote:
| There's even a GNU C Library function: strverscmp():
|
| https://www.gnu.org/software/libc/manual/html_node/String_00.
| ..
| blibble wrote:
| git directly uses that function :)
|
| (... well, it's copied and pasted into the tree but close
| enough)
| pizza234 wrote:
| Sort in which context? Unix has `sort -V`. Of the other
| languages I use, they all have either built-in functionalities,
| or small libraries to do it.
| __david__ wrote:
| Ancient Perl started off encoding their version numbers as a
| float (you can see it in their old version numbers before
| 5.6.0, 5.005 for instance[1]). Integers were the major version,
| thousandths were minor, and millionths were patch. So 1.003004
| was 1.3.4. This makes them extremely easy to sort. At some
| point they decided that was too obscure and came up with
| "version strings". But the old way is (crazily) still supported
| and can cause pain if you forget since 1.2.0 is unambiguous,
| but 1.2 means 1.200000, ie 1.200.0.
|
| [1] https://en.wikipedia.org/wiki/Perl_5_version_history
|
| Just to be clear, I don't actually think this is a great
| solution, but is _is_ easy to sort.
| avar wrote:
| Perl still represents versions like that internally, the
| "pretty" v-prefixed variant is just some overload/OO magic.
| infogulch wrote:
| That's a good point. With the omnipresence of semver, you'd
| think that more interfaces would support sorting tags with a
| semver comparison instead of lexically.
|
| I searched for a bit and found that github does this ( e.g.
| https://github.com/TryGhost/Ghost/tags ). Also there is a git
| config that sets this globally for the git cli: `git config
| --global tag.sort version:refname` ( found here:
| https://gist.github.com/loisaidasam/b1e6879f3deb495c22cc ).
| That's another git config going onto every machine I use...
| CalChris wrote:
| How do I pull something like _LLVM 14.0.0_ by tag?
| abdusco wrote:
| git clone -b $tag $repo_url
| junon wrote:
| Or the longer way, if you're on a version of git without the
| -b option: git init ./repo cd
| ./repo git remote add origin $uri git fetch
| origin $tag git checkout FETCH_HEAD
| carlhjerpe wrote:
| Or what you would probably do using libgit(2?) :)
| AceJohnny2 wrote:
| Couple ways, for example on the github page [1] , click the
| "tags" link [2] above the file list, find the tag for release
| 14.0.0, which is _llvmorg-14.0.0_ , and now you can do any
| commit operation with that name instead of a commit.
|
| If you have a checkout, you can find the tag name by doing a
| _git tag -l *14*_ and looking through the output; I 'm
| intentionally providing a very general glob because one may not
| know beforehand their exact tag name conventions.
|
| [1] https://github.com/llvm/llvm-project
|
| [2] https://github.com/llvm/llvm-project/tags
| junon wrote:
| Please don't prefix version tags with "v"...
| recursive wrote:
| I'm not stopping until you give me a reason. So far it hasn't
| caused any problems.
| foobarbaz33 wrote:
| I guess it contributes to global warming. Not in a
| significant way. But it literally does take more energy to
| write an extra character to a disk.
| patmorgan23 wrote:
| Why?
| nickjj wrote:
| Annotated tags are a good idea, they also happen to be a
| requirement when signing tags. You can create empty message
| signed annotated tags with `git tag -sm "" v123-my-signed-tag`.
|
| I once made a blog post / video around signing and verifying your
| commits and tags at: https://nickjanetakis.com/blog/signing-and-
| verifying-git-com...
___________________________________________________________________
(page generated 2022-05-23 23:00 UTC)