Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Post-process Git tags (Bash)
#! /usr/bin/env bash
# Copyright (C) 2011 Sebastian Pipping <sebastian@pipping.org>
# Licensed under GPL v3 or later
#
# 2011-04-01
GIT='git --no-pager'
# Require Git repository in reach
${GIT} show --oneline >/dev/null || exit 1
# Command line parameters
[[ $# == 0 ]] && tags=$(git tag -l) || tags=$@
abbrev() {
sha1=$1
${GIT} show -s --format=%h "${sha1}"
}
is_tag_object() {
tag=$1
[ $(${GIT} cat-file -t "${tag}") == tag ] && echo true || echo false
}
main() {
for tag in ${tags}; do
tag_ref=refs/tags/"${tag}"
# Valid tag?
${GIT} rev-parse "${tag_ref}" &>/dev/null || {
echo "Tag '${tag}' not found, skipping" 1>&2
continue
}
# Plain tag or tag object?
tag_object=$(is_tag_object "${tag_ref}")
if ${tag_object}; then
cat_file_output=$(${GIT} cat-file tag "${tag}")
commit_sha1=$(head -n 1 <<<"${cat_file_output}")
commit_sha1=${commit_sha1##object }
original_commit=${commit_sha1}
else
original_commit=$(${GIT} rev-parse ${tag_ref})
fi
# Get contained tree SHA1
tree_sha1=$(${GIT} show -s '--format=%T' "${original_commit}")
# Get earliest commit with same tree SHA1
earliest_commit=$(${GIT} rev-list --all --topo-order \
'--format=%H %T' \
| fgrep "${tree_sha1}" | tail -n 1 | cut -f 1)
if [[ -z "${earliest_commit}" ]]; then
echo "Sanity check failed, internal error" 1>&2
exit 1
fi
# Work to do?
if [[ "${earliest_commit}" == "${original_commit}" ]]; then
printf "Tag '%s' (%s) already at earliest commit (%s), skipping\n" \
"${tag}" \
$(${tag_object} && echo object || echo plain) \
$(abbrev "${original_commit}")
continue
fi
if ${tag_object}; then
tagger_line=$(tail -n +4 <<<"${cat_file_output}" | head -n 1)
tagger_line=${tagger_line##tagger }
tag_message=$(tail -n +6 <<<"${cat_file_output}")
committer_name=$(sed 's/^\(.\+\) <\([^>]\+\)\+> \([0-9]\+ [+-][0-9]\{4\}\)$/\1/' <<<"${tagger_line}")
committer_email=$(sed 's/^\(.\+\) <\([^>]\+\)\+> \([0-9]\+ [+-][0-9]\{4\}\)$/\2/' <<<"${tagger_line}")
committer_date=$(sed 's/^\(.\+\) <\([^>]\+\)\+> \([0-9]\+ [+-][0-9]\{4\}\)$/\3/' <<<"${tagger_line}")
GIT_COMMITTER_NAME="${committer_name}" \
GIT_COMMITTER_EMAIL="${committer_email}" \
GIT_COMMITTER_DATE="${committer_date}" \
${GIT} tag -f -a -m "${tag_message}" "${tag}" "${earliest_commit}"
else
${GIT} tag -f "${tag}" "${earliest_commit}"
fi
done
}
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment