How to reliably pass options to git rev-parse

Viewed 24

I have a tool that runs this command:

git rev-parse --path-format=absolute --git-common-dir

However its output is different depending on the git version! On older versions of git (e.g. 2.26) there is no --path-format option so it just prints out that option, like this:

$ git rev-parse --path-format=absolute --git-common-dir
--path-format=absolute
/path/to/repo/.git

On versions of git that support --path-format it works fine and only prints the second line.

How can I tell git "this is an option; please print an error if you don't understand it"? Is there something similar to how well-designed CLI tools let you do foo --option -- file.

1 Answers

Given that you want the effect of the option, you have no real choices here. Well, you have two or three, but none of them are what I would call "real" choices:

  1. Assume that all Git versions are recent (or force this to be the case) and just use the option.
  2. Assume that all Git versions are old and avoid the option: use a workaround, such as running realpath, assuming that's suitable.
  3. Check the version, and use the option when available and a workaround otherwise.

The check version step method is also your choice: see if git rev-parse spits the option back out, or run git --version first. In shell scripts, here is a way to use git --version:

# Returns true if Git version is at least x and y
# ($1 and $2 respectively).  Returns false otherwise.
git_version_atleast() {
    local major="$1" minor="$2" saveIFS="$IFS"
    IFS=" ." # split words at space and dot
    set -- $(git --version)
    IFS="$saveIFS"
    shift 2 # discard "git" and "version"
    test "$1" -gt "$major" -o "$1" -eq "$major" -a "$2" -ge "$minor"
}

Use as, e.g.:

if git_version_atleast 2 31; then
    # git rev-parse behaves
else
    # use workaround
fi

This could be fancied up a bit to set "$@" after modifying IFS, before creating major and minor from $1 and $2, so that you can invoke it as if git_version_atleast 2.31. Note that this depends on -a having higher precedence than -o in test (which it does, but you might want to parenthesize).

Given that you need a workaround for old versions, I'd go with either #1 or #2 myself: use #2 until #1 is possible. Use #3 only if the workaround has issues.

Related