|
#! /usr/bin/env bash |
|
# Copyright (C) 2011 Sebastian Pipping <[email protected]> |
|
# 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 |