1

I have a script that periodically compares a local branch with its remote counterpart to see if there's any update.

To do this I use the following:

  1. update the... remote references? with git remote update
  2. get the local commit with git rev-parse @
  3. get the corresponding remote (upstream) commit with git rev-parse @{u}
  4. compare the two hashes

and they appear quite efficient, especially git remote update which is very fast in retrieving information from the remote repository.

Now I want to do a similar thing with a tag (I'm evaluating the possibility to use them to mark special commits and be able to move that mark back and forth), and using a specific one, i.e. tagged, much like I was checking a specific branch in the first part.

But I did not find a similarly efficient sequence of commands. Let me be clear: I'm fine if a command takes several seconds to complete, I would just like to use the lightiest possible one. E.g. before finding git remote update, I was using fetch, which allowed me to accomplish the same result, but with much more burden (and network, repository, etc. load).

The tag is created and moved with these:

  1. git tag tagged <hash> -f
  2. git push --tags -f

While inspecting (obtaining the commit hash in) the working copy is as easy as before (with git rev-parse tagged), I don't know the command to check the same on the remote.

Since I'm using this in a script, a command with a single output would be the best.

The only one which seems to come closer is ls-remote, that I tried like this: git ls-remote --tags origin tagged; but it's a little slow and maybe it is doing more than I need.

The other command I tried is git rev-parse --tags, but it outputs a list, and doesn't seem to allow specifying to query the remote (of course with branches is easier, since they have an upstream associated).

watery
  • 5,026
  • 9
  • 52
  • 92
  • "*The other command I tried is `git rev-parse --tags`, but it…doesn't seem to allow specifying to query the remote…*" Git is intended to work only with the local repository. There're very few commands that query/exchange data with distant (I avoid the word "remote" here) repositories: `archive`, `clone`, `fetch`, `pull`, `push`, `ls-remote`, `remote update` are the only ones I remember. – phd Sep 10 '22 at 13:40
  • 2
    (This is not an answer to your question, it's a meta-comment on social norms.) Tags are *not supposed to move* and you should not force them to do so; this breaks human expectations. Branch names are expected to move and otherwise serve the same function, so use branch names, not tag names, here. (Or, as the old "doctor" joke has it, "doctor, it hurts when I do this (insert demonstration)" -- "well, don't do that!") – torek Sep 10 '22 at 16:14
  • This question appears to be a subset of [this question](https://stackoverflow.com/q/66212614/184546). – TTT Sep 10 '22 at 19:22
  • @torek (Thanks. Far be it from me to say this is the best approach, or even a good one. Given that branches [do not support partial merges](https://stackoverflow.com/q/4315948/3127111), I'm exploring an approach - that may fail of course. My tag is going to be called `deploy` and it is *expected* to always point at the commit that has been deployed - I got branches named *production* that weren't aligned to production. Plus, in case of emergency, the tag can be moved behind easier and faster than a branch) – watery Sep 17 '22 at 08:27
  • How about a tag `deploy-`, part of an ever growing list of tags? Once they're sufficiently "dead" (6 months? 2 years?) you can perhaps delete some of the "old" deploy tags. That way you don't violate the "tags should never move" rule, at the expense of generating what could be a lot of tags. – torek Sep 17 '22 at 09:22
  • @torek The tag will trigger the actual deploy, what if someone tags an old commit with `deploy-20230101T010000`? J/k, interesting suggestion, thank you. – watery Sep 17 '22 at 13:21

1 Answers1

1

Since you're scripting this, and it sounds like you want to loop over all the tags, I would run

git ls-remote --tags origin

once without specifying a tag, and loop over the output locally in your script.

The time to run that command and get all tag revs listed at once is only trivially longer than just getting one, so this approach should give you the optimization you're looking for. I just tested in a repo with 50 tags, and I fetched all 50 tags in 0.45s, while it took 0.37s to fetch just one tag, which would mean a total of 18.5s for all 50 tags.

The optimization most likely comes from establishing the connection to the server only once, as I'm sure that's the slowest part in all this.

joanis
  • 10,635
  • 14
  • 30
  • 40
  • And to make the comparison super easy, you can treat your own repo as a remote too, `git ls-remote --tags .` Something like `(git ls-remote --tags . & git ls-remote --tags origin)|sort -Vk2|uniq -u` – jthill Sep 10 '22 at 15:04
  • Yup, sorry, much like I was checking a specific branch before, I'm targeting a specific tag; will make it clearer in my question. – watery Sep 10 '22 at 15:48
  • ls-remote takes a pattern. – jthill Sep 10 '22 at 16:21
  • @watery If you're checking just one tag, I suspect your command was already the fastest you can do. Establishing the connection with the server requires all the secure handshaking and autheticating. Spending 0.3 to 0.4s on that does not seem unduly slow to me. How long does it take on your machine? – joanis Sep 10 '22 at 17:26
  • If you're doing frequent checks an ssh master connection can save loads of time. – jthill Oct 16 '22 at 14:30