diff --git a/scripts/checkout.sh b/scripts/checkout.sh index e53a9e4b..baa8f593 100755 --- a/scripts/checkout.sh +++ b/scripts/checkout.sh @@ -19,8 +19,30 @@ checkout() ( SRC="$1" REF="$2" REF_FETCH="$REF" + + # git ls-remote's argument [1] is a glob [2], and matches anything + # ending with the given string. This is problematic if multiple tags or + # branches end with the given pattern. In containerd's case, this returns + # both tags for the main module ("refs/tags/v1.7.19") and # the API module + # ("refs/tags/api/v1.7.19"). + # + # To prevent both of those being found, we check if the given reference starts + # with a "v"; if it does, we can assume it's a tag, and prefix the pattern with + # "refs/tags/" to make it less ambiguous. + # + # We're using a case statement here to avoid introducing Bashisms. + # + # [1]: https://git-scm.com/docs/git-ls-remote#Documentation/git-ls-remote.txt-ltpatternsgt82308203 + # [2]: https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-glob + ref_glob="$REF" + case $ref_glob in + "v"*) + ref_glob="refs/tags/$ref_glob" + ;; + esac + # if ref is branch or tag, retrieve its canonical form - REF=$(git -C "$SRC" ls-remote --refs --heads --tags origin "$REF" | awk '{print $2}') + REF=$(git -C "$SRC" ls-remote --refs --heads --tags origin "$ref_glob" | awk '{print $2}') if [ -n "$REF" ]; then # if branch or tag then create it locally too REF_FETCH="$REF:$REF" @@ -31,7 +53,6 @@ checkout() ( git -C "$SRC" checkout -q "$REF" ) - # Only execute checkout function above if this file is executed, not sourced from another script prog=checkout.sh # needs to be in sync with this file's name if [ "$(basename -- $0)" = "$prog" ]; then