blob: c07c056fd3d37b52611fb16d63461d493616483f [file] [log] [blame]
#!/bin/bash
# Copyright 2022 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
HELP_TEXT="USAGE: git-clean-refs [flags]
repo forall -v -c git clean-refs [flags]
This script can be used to restore ChromiumOS projects which have broken git
refs, allowing repo to subsequently sync the project without errors.
You can save this file anywhere in your \$PATH, or run the \`repo forall\`
command from the directory where this script lives (assuming repo is installed).
OPTIONS:
-w Run git fsck and delete the refs that are missing
from the repository's history. NB: This can be an
expensive operation in some projects, specifically
the Linux kernel repos.
"
WIPE_HISTORY=0
while getopts "hw" OPT; do
case "${OPT}" in
h)
echo "${HELP_TEXT}"
exit
;;
w)
WIPE_HISTORY=1
;;
*)
;;
esac
done
set -eu -o pipefail
echo "Working on repository: $(git rev-parse --show-toplevel)"
# We first need to clear out any refs that point to a missing commit
# otherwise `git for-each-ref` will error out.
while ! MSG="$(git show-ref 2>&1 1>/dev/null)"; do
REF="$(sed -En -e 's/^fatal: git show-ref: bad ref ([^ ]+).*/\1/p' <<<"${MSG}")"
echo "Deleting stale ref: ${REF}"
git update-ref -d "${REF}"
done
# We can then verify each ref contains a complete history.
# If we are missing a commit in the history, we need to trash the ref
# so that `git fetch` will send the missing commit.
if [[ "${WIPE_HISTORY}" -eq 1 ]]; then
while read -r HASH TYPE REF; do
echo "Checking ref: ${REF}"
if ! git fsck --connectivity-only --no-dangling "${HASH}"; then
echo "Deleting broken ref: ${REF}"
git update-ref -d "${REF}"
fi
: "${TYPE}" # Keep shellcheck happy
done < <(git for-each-ref)
fi
git reflog expire --all --expire=now