blob: f08fceed23d84cb8b37d755932b0824a58948c39 [file] [log] [blame]
#!/bin/bash
# Copyright 2023 Fairphone B.V.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Git helper to compare logs of local vs upstream histories
#
# This tool is meant during git merge, rebase or cherry-picking longer histories. It will list out
# (non-merge) commits unique to the local vs. the upstream history. Depending on the state of the
# repository, it will automatically figure out which "upstream history" to compare to: Current
# MERGE_HEAD, REBASE_HEAD, CHERRY_PICK_HEAD, or an already merged upstream history.
# Environment variables:
# MERGE_LOG_LENGTH: Set the maximum number of commits to list out. Defaults to 10.
set -e
set -u
_shortened_logs() {
local length="${MERGE_LOG_LENGTH:-10}"
local logs
logs="$(git --no-pager log --color=always "$@")"
local lines
lines=$(echo "$logs" | wc -l)
echo "$logs" | head -n"${length}"
if [ "$lines" -gt "${length}" ]; then
echo " ($lines lines in total)"
fi
}
_is_merge_commit() {
local sha1="$1"
local num_parents
num_parents=$(git log -1 --format=%P "${sha1}" | wc -w)
if [ "${num_parents}" -gt 2 ]; then
echo >&2 "ERROR: Cannot handle n-way merge: ${sha1}. Project: ${PWD}"
return 1
fi
[ "${num_parents}" -eq 2 ]
}
_compare_histories() {
local file_params=()
if [ $# -ge 0 ]; then
file_params+=(--)
for param in "$@"; do
file_params+=("${param}")
done
fi
local current_head=HEAD
local new_head
if git rev-parse -q MERGE_HEAD >/dev/null 2>/dev/null; then
new_head=MERGE_HEAD
elif git rev-parse -q CHERRY_PICK_HEAD >/dev/null 2>/dev/null; then
new_head=CHERRY_PICK_HEAD
elif git rev-parse -q REBASE_HEAD >/dev/null 2>/dev/null; then
new_head=REBASE_HEAD
elif _is_merge_commit HEAD; then
current_head=HEAD^1
new_head=HEAD^2
else
echo >&2 "Having neither MERGE_HEAD no CHERRY_PICK_HEAD. Failing."
return 1
fi
echo "New on ${new_head}:"
_shortened_logs "${current_head}..${new_head}" --no-merges --oneline "${file_params[@]}"
echo ""
echo "New on ${current_head} compared to ${new_head}:"
_shortened_logs "${new_head}..${current_head}" --no-merges --oneline "${file_params[@]}"
}
_compare_histories "$@"