[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)