5

I have a Git command alias to checkout the latest tag from a repository:

~/.gitconfig:

checkout-latest = !git checkout $(git describe --tags `git rev-list --tags --max-count=1`)

So I can use it in properly tagged repositories like this:

$ git checkout-latest

I have command aliases for the checkout command:

~/.gitconfig:

co = checkout

The checkout-latest does not work with the command aliases for checkout:

$ git co-latest
git: 'co-latest' is not a git command. See 'git --help'.

How can I configure Git so that I can use latest as a tag alias that points to the programmatically determined latest tag? I would like to use it like this:

$ git checkout latest

and

$ git co latest

Note that there is no dash between the subcommand and the tag in my desired variants.

Bengt
  • 14,011
  • 7
  • 48
  • 66
  • If you want `co-latest` to work just add it: `co-latest = !git checkout-latest`. I don't think you can do what you want without maintaining an actual tag `latest`. – Etan Reisner Dec 17 '14 at 18:44
  • Yes, that would work. But I want to neither maintain a `latest` tag in every repo nor mix up the syntax of subcommands and tags. – Bengt Dec 17 '14 at 20:40
  • I don't understand that "mix up" comment but yeah maintaining a `latest` tag was not a recommendation just a comment that I don't know how else you could do it. – Etan Reisner Dec 17 '14 at 20:46
  • `co-latest` is a subcommand to `git`, while `git checkout latest` would be a command, subcommand and tag alias. I think it is ugly to have something that refers to a tag on the subcommand level. – Bengt Dec 17 '14 at 20:50
  • I see. I think that's an arbitrary distinction you've drawn and one that severely limits what you can do with aliases but that's not my call. I don't believe you can do what you want here (not unless you wrap `git` itself in a shell function and do dispatch based on the subcommand and "tag/ref" arguments. – Etan Reisner Dec 17 '14 at 20:57
  • If it can't be done with Git, posting a wrapper script would be a valid answer. – Bengt Dec 17 '14 at 21:51

3 Answers3

2

The only solution to this sort of thing I can think of is a git shell function that does "dispatch" based on arguments.

Something like this:

git() {
    if [ "$1" != checkout ] || [ "$#" -ne 2 ]; then
        git "$@"
        return
    fi

    local lastrev lasttag

    case $2 in
        :latest)
            lastrev=$(git rev-list --tags --max-count=1)
            set -- checkout "$(git describe --tags "$lastrev")"
        ;;
    esac

    git "$@"
}

The tag aliases need to be invalid as normal refs to be safe for hence the use of check-ref-format.

This construct allows for arbitrary tag "aliases" to be added via the case statement.

This function is very limited in terms of what arguments can be used if you want to use the tag "alias". Specifically you cannot pass any. The command must be git checkout <alias>. Parsing all valid git checkout combinations is simply too hard to bother with for this now (though it could probably be done).

Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
2

Git can already alias tags in the sense that you can make a new tag which points to the same commit as another tag.

What you seem to want is a macro alias; for Git to recognize a special word like latest and dynamically substitute that with a tag.

Since that probably isn't going to happen without modifying Git, you can make the shell do it, and interpolate via $(...) command substitution:

git checkout $(latest)

latest is just a shell script or function that dynamically computes the tag and prints it on its standard output.

Another idea is to just have an actual latest tag installed as an alias in the repo. When a new change is tagged, latest is pushed forward to that (via git tag -F). Such tagging is a non-fast-forward change, of course, so the upstream repo has to allow that.

Kaz
  • 55,781
  • 9
  • 100
  • 149
0

Git aliases cannot reference other aliases.

You can accomplish this with another layer of indirection, however:

co-latest = !git checkout-latest "$@"
Kevin M Granger
  • 2,375
  • 23
  • 28
  • While interesting, this does not answer my question. I do not want to create more subommand aliases. I want to get rid of the one I have and get even better functionality with an alias on the tag level. – Bengt Dec 17 '14 at 20:47