`git describe` like attributes for flakes

Flakes already provide the attributes ref, lastModified and lastModifiedDate, which I already use to build the version.

Though I am used to development versioning buuilt from (annotated) tags using git describe.

Is there already an attribute that provides similar information?

What I miss currently is the “last” tag, as well the number of commits since then.

If there is currently no such attribute available, where could I propose it? Would the nix repo the correct place or nixpkgs?


hmm, semi-unrelated to your original topic, but doing git describe on master gives me:

[15:01:45] jon@nixos ~/projects/nixpkgs (master)
$ git pull
Already up to date.
[15:01:50] jon@nixos ~/projects/nixpkgs (master)
$ git describe

which is kind of sad, seeing as it should be 21.05-pre.

Guess I’ll add that to the release documentation.


Hmmm… I’m wondering where all the other tags are pointing to then…

As 19.xx and 20.xx tags exist, with and without alpha/beta modifiers.

Though a 21.05* does not exist at all.

I think in the current release documentation, you make the release branch, do the initial release metadata commit, then tag. So the release tag doesn’t actually end up in master. Which makes sense why we have a very old tag on master.

What doesn’t make since is that there’s no tag in master which really differentiates that it’s the rolling release for a given version.

Could the order be changed?

  1. Do initial metadata commit
  2. Tag the commit
  3. Make the release branch
  4. Do pre release meta commit

This way the release commit and tag will be in both branches. Im not sure what is involved in the metadata commit but I wonder if there is one for the pre release.

IIRC you need to do a git pull --tags

If you were creating the tag after git checkout -b release-XX.YY, before doing any other commit, it would be on master as well. That again would mean, that a git describe on master would itself also identify as “current alpha” of the stable release.

Therefore procedure should be roughly:

  1. git checkout master just to be sure
  2. preBranchOff=$(git rev-parse HEAD) to get current commit hash
  3. git checkout -b $newReleaseName
  4. do metadata commit
  5. tag the metadata commit as “-alpha”
  6. git checkout $preBranchOff to get back to the correct commit on master
  7. do a metadata commit that changes its versioning to -pre
  8. Tag that commit with -pre

Then it should be roughly like this:

  • A is git described as “20.03-pre-$refs-g$sha”
  • B is git described as “20.03-alpha-0-g$sha” (when forcing --long)
  • C is git described as “20.09-pre-0-g$sha” (when forcing long)

This tagging/branching approach seems sensible and should have correct version jumps on each branch.

Was my first thought as well, then I did that locally and saw that I get the exact same output as Jon.

The current release process is detailed here: https://github.com/NixOS/release-wiki/blob/aba19af148f9e11884a4e4e299bd989361c4a268/src/Release-Process-Walkthrough.md

PR to update release process https://github.com/NixOS/release-wiki/pull/7

1 Like

Hmmm… There is no alpha, where do those tags come from?

I used the term alpha when we first branched off 20.09 because we have ~500 largely untested staging commits dumped into the master branch. In fact, it was very broken. Gnome and plasma users couldn’t logout because systemd changed some visibility of needed dbus messages, and a whole host of other issues.

Sorry, I don’t know if a bump is the right thing to do, or if I should recreate?

I find myself really needing this, as I’m adding a flake to something that has an established versioning and I cannot just use shortRev etc because it needs the version format to be something like the output of git describe. I’ve managed a horrible hack:

      # Generate a user-friendly version number.
      # Sadly currently nix flakes don't support git-describe like versions
      # And yes, manually having to update `tagRevCount` and `tag` is very poor
      tagRevCount = 858;
      tag = "1.0.1";
      shortDate = builtins.substring 0 8 lastModifiedDate;
      shortRev = if self ? "shortRev" then "g${self.shortRev}" else "dirty";
      revCount = if self ? "revCount" then toString (self.revCount - tagRevCount) else "dirty";
      gitSuffix = if revCount == "0" then "" else "-${revCount}-${shortRev}+${shortDate}";
      gitVersion = "${tag}${gitSuffix}";

but it is as I said horrible, especially because of manually needing to update tagRevCount and tag, still at least there are no problems with having to create a fixed-point hash if I were to use rev. And assuming I’m going to tag the commit I’ve just updated the flake.nix values tag and tagRevCount in, it should be safe as any parent of the commit will have the old tagRevCount, and any child of the commit will have tagRevCount - revCount > 0.

I having a git describe-like output would be very useful, maybe it could be a function taking arguments like match, dirty and always? But some things do depend on a git-describe like version, in this case it’s Elixir Version — Elixir v1.12.3.

I have also done a slightly nicer thing, in the flake I’m pulling this from:

rec {
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.05";

  inputs.myflake.type = "git";
  inputs.myflake.url = "https://myflake.url/repo.git";
  inputs.myflake.ref = "refs/tags/release/1.0.1";

  outputs =
    { nixpkgs, myflake } @ flake-args: {
      nixosConfigurations.gitlab-runner = nixpkgs.lib.nixosSystem rec {
        system = "x86_64-linux";
        modules = [
          ({ pkgs, lib, ... }: {
            environment.systemPackages = [
              (myflake.packages.x86_64-linux.default.override {
                version = builtins.replaceStrings [ "refs/tags/release/" ] [ "" ] inputs.myflake.ref;

which doesn’t depend on the earlier hack, because it overwrites the version (the myflake has nixpkgs.lib.makeOverridable { version ? gitVersion }: <derivation> {}) but still, this is not nice. I would prefer it if flakes would support something like git describe even if it means a higher likelihood of cache misses.

In terms of implementing this, I’ve had a quick look, it looks like the rev is using getRev, which is just a string attribute. I think it is populated here for revCount but I’ll have to have more of a think/proper read of the code.

But it seems like only string attrs are supported, presumably can be extended reasonably easily to also include attrsets, but probably not easily to support functions. Plus I suspect the attrs need to be serialised to the lock-file. So maybe putting an attrset of tags to revs and revcounts is a way to go? Then could have a helper function to create something like the git-describe. Of course, this means that you can have a nix flake update that only updates the tags, but I think because the narHash could stay the same it should prevent another fetch of the repo (the sources anyway, it might do rebuild). And self isn’t in the lock file :slight_smile:

Anyway, sorry this is just my thoughts on it/quick look at how it could be done and it’s entirely possible I’ll not get around to implementing it, but who knows I might? And because it’s just a quick skim of the code, it’s possible I’ve misunderstood things. Any feedback?