4 ms·
>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
by Groxx 4y ago
>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.
- avgcorrection 4y agoWait. Aren't tags immutable?
- colonwqbang 4y agoNope. 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 4y agoUm 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 4y agoChecked 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).
- colonwqbang 4y agoIf 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 4y ago[deleted]
- Groxx 4y agoYou 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 4y ago> 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.
- lamontcg 4y agoannotated 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 4y ago[deleted]
- Groxx 4y agoAnnotated tags affect their own sha (because they actually have one, non-annotated tags do not), 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 4y agoOh 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.
- Groxx 4y agoI think it's at least partly for providing a storage location for after-commit release signatures. You can't modify the commit to add the release-signer signature, and many things will want direct access to it, so you need/want a publicly-identifiable commit-pointer of some kind: tags. Off at the less-structured side of things though, have you seen git notes? You can add notes to any commit: https://git-scm.com/docs/git-notes https://git-scm.com/docs/git-notes . Tags are kinda just notes with a display name. At times I've wished that code review feedback were just stored in notes, so it'd survive changing hosting systems... but they're not quite reasonable for that :| What I think I really want is a notes tree under any commit, which kinda exists since you can add notes to notes, but there isn't really enough structure or tooling to support that kind of use out-of-the-box.
- tome 4y agoYeah, the "tag called test" example is strange, given that "branch called test" has exactly the same problem.
- da-x 4y agoYes, 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 4y agoIt only pollutes the local repo if you pull it explicitly (or with `--all`) from the remote.
- da-x 4y agoIIRC, 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.
- WorldMaker 4y agoAnnotated 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 4y agoChecking 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 module-compatible tagged version, 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 4y agoYeah, 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.
- deleted 4y ago[deleted]