Reputation: 8001
I'm debugging a script which wraps several Git operations, the most significant of which is running git checkout <specifier>
As you know git checkout
accepts either a commit-ish or a branch name:
The script was written based on the "flexibility" (though I now have to say it was an awful idea but anyways...). Due to the "flexibility", the upstream stage sends <specifier>
without any metadata on what it means; it can either be a SHA-1 shorthand like 8e13bb8
or a (remote) branch name such as feature/optimize-foo
. In the latter case, it might not exist as a local branch name at the point of receiving it; git checkout
is so flexible that it can create a local tracking branch automatically (see the command reference above, a paragraph which begins with "If <branch>
is not found but there does exist a tracking branch in exactly one remote")
Now I need to insert some extra operations only when <specifier>
was a (remote) branch name but I'm struggling to find a way to do so. Something along the lines of
if git this-is-branch-name $specifier; then
git checkout $specifier
git pull
else
git checkout --detach $specifier
fi
(The above example does not reflect the complexity of the actual script I'm dealing with, so please don't "recommend" me nicer ways to write it)
git switch
which is meant to partly replace git checkout
does not (immediately) help me as the original script already conflated several different operations under a single git checkout
Upvotes: 5
Views: 749
Reputation: 60255
Now I need to insert some extra operations only when <specifier> was a (remote) branch name
The usual full spelling of remote branch names beginsrefs/remotes/
(nobody sane ever changes that, I'm just pointing out that it can be done), and the full spelling of all local branch names begins refs/heads
.
So
fullspell=`git rev-parse --symbolic-full-name $specifier --`
will set fullspell
to the full symbolic name of $specifier
if it's purely a symbolic ref, or empty if it's a valid ref but not just a name. case
has some useful syntax if you want the same code for multiple cases,
if fullspell=`git rev-parse --symbolic-full-name $specifier --`; then
case $fullspell in
refs/heads/* | refs/remotes/*)
# it's a remote-tracking branch or a local branch
;;
?*)
# it's something else, but it's a legit refname
;;
*)
# there's no full spelling but the command succeeded. It's not a bare refname,
# but it does resolve to something (so e.g. master~3 would get here)
;;
esac
fi
Upvotes: 3
Reputation: 8001
Based on @VonC's answer https://stackoverflow.com/a/62338364
I'll probably go with something like
rp=$(git rev-parse --verify -q "$specifier" || true)
if [[ -n "$rp" ]]; then # if rp is non-empty
if [[ "$rp" = "specifier"* ]]; then # if specifier is a prefix of rp
echo "'${specifier}' is a commit"
else
echo "'${specifier}' is a branch"
fi
else
echo "'${specifier}' is NEITHER a branch or a commit"
fi
Upvotes: 1
Reputation: 1323313
There are way to check if a local or remote branch exists
git rev-parse -q --verify <abranch>
The --verify
option, combined with -q, will exit with non-zero status silently if the branch does not exist.
So instead of:
if git this-is-branch-name $specifier; then
use:
if git rev-parse --verify -q $specifier >/dev/null; then
I want to take different actions depending on whether is 1) a commit-ish such as
8e13bb8
or 2) a (remote) branch name such asfeature/optimize-foo
That would be:
if git cat-file -e "${specifier}"; then
echo "'${specifier}' is either a branch or a commit"
rp=$(git rev-parse ${specifier})
if [[ "${rp#${specifier}}" != "${rp}" ]]; then
echo "'${specifier}' is a commit"
else
echo "'${specifier}' is a branch"
fi
else
echo "'${specifier}' is NEITHER a branch or a commit"
fi
Upvotes: 2