mirror of https://github.com/ArduPilot/ardupilot
Tools: gittools: add git-commit-subsystems
A git extension for committing multiple subsystems.
This commit is contained in:
parent
c2a940ddea
commit
fea8299ff3
|
@ -0,0 +1,202 @@
|
|||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR=$(dirname $(realpath ${BASH_SOURCE[0]}))
|
||||
GIT_DIR=$(git rev-parse --git-dir)
|
||||
GIT_ROOT=$(git rev-parse --show-toplevel)
|
||||
|
||||
usage() {
|
||||
cat >&$1 <<EOF
|
||||
Usage: git commit-subsystems [OPTIONS]
|
||||
|
||||
Ardupilot's git extension.
|
||||
|
||||
Create a different commit for each ardupilot's subsystem (vehicles, libraries
|
||||
and folders in the project's root). The items in OPTIONS are passed down to the
|
||||
original git commit command with exception of options --message and --file (and
|
||||
their short versions). Boths are related to the commit message:
|
||||
commit-subsystems will treat the commit message from one of those two options
|
||||
as a template such that occurrences of \$subsystem are replaced with the
|
||||
subsystem being currently committed.
|
||||
|
||||
If neither --message or --file are passed, then the first commit's message will
|
||||
be used as a template for the other messages and option --edit will be used for
|
||||
the next commits. To avoid that behavior use --naive.
|
||||
|
||||
Another custom option is --raw: don't use commit message as a template.
|
||||
EOF
|
||||
}
|
||||
|
||||
MSG_FILE="$GIT_DIR/COMMIT_SUBSYSTEM_MSG"
|
||||
extra_options=
|
||||
|
||||
process_msg() {
|
||||
local subsystem=$1
|
||||
local prev_subsystem=$2
|
||||
if [[ -n "$option_m" || -n "$option_F" ]]; then
|
||||
if [[ $option_F == - ]]; then
|
||||
echo "Please, type the commits message template:"
|
||||
option_F="$GIT_DIR/COMMIT_SUBSYSTEM_TEMPLATE"
|
||||
cat - > "$option_F"
|
||||
fi
|
||||
|
||||
if [[ -n "$option_m" ]]; then
|
||||
echo "$option_m"
|
||||
else
|
||||
cat "$option_F"
|
||||
fi | if $option_raw; then
|
||||
cat
|
||||
else
|
||||
sed "s,\$subsystem,$cur_subsystem,g"
|
||||
fi > "$MSG_FILE"
|
||||
|
||||
|
||||
extra_options=(-F "$MSG_FILE")
|
||||
elif [[ -n $prev_subsystem ]] && ! $option_naive; then # try to be "smart"
|
||||
cat $GIT_DIR/COMMIT_EDITMSG \
|
||||
| sed -e "/^\s*#/d" \
|
||||
-e "s/.*\<$prev_subsystem\>.*/\0\n#\0/" \
|
||||
| sed "/^[^#]/ s/\<$prev_subsystem\>/$subsystem/g" > "$MSG_FILE"
|
||||
echo >> "$MSG_FILE"
|
||||
echo "# This commit message was adapted by commit-subsystems" >> "$MSG_FILE"
|
||||
extra_options=(-F "$MSG_FILE" --edit)
|
||||
fi
|
||||
}
|
||||
|
||||
commit_subsystem() {
|
||||
local subsystem=$1
|
||||
local prev_subsystem=$2
|
||||
shift 2
|
||||
process_msg $subsystem $prev_subsystem
|
||||
if ! git commit ${extra_options[*]} "$@"; then
|
||||
echo "Couldn't commit subsystem $subsystem, aborting..." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
args=()
|
||||
|
||||
option_m=
|
||||
option_F=
|
||||
option_naive=false
|
||||
option_raw=false
|
||||
|
||||
while [[ -n "$1" ]]; do
|
||||
opt="$1"
|
||||
case "$opt" in
|
||||
-h|--help)
|
||||
usage 1
|
||||
exit 0
|
||||
;;
|
||||
-m|--message)
|
||||
shift
|
||||
if [[ -z "$1" ]]; then
|
||||
echo "Option $opt requires a commit message." >&2
|
||||
exit 1
|
||||
fi
|
||||
option_m="$1"
|
||||
;;
|
||||
-F|--file)
|
||||
shift
|
||||
if [[ -z "$1" ]]; then
|
||||
echo "Option $opt requires a file name." >&2
|
||||
exit 1
|
||||
fi
|
||||
option_F="$1"
|
||||
;;
|
||||
--naive)
|
||||
option_naive=true
|
||||
;;
|
||||
--raw)
|
||||
option_raw=true
|
||||
;;
|
||||
*)
|
||||
args+=("$1")
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [[ -n $option_m && -n $option_F ]]; then
|
||||
echo "Options -m and -F can't be combined." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -- "${args[@]}"
|
||||
|
||||
LIST=$GIT_DIR/COMMIT_SUBSYSTEMS_LIST
|
||||
|
||||
git diff --name-only --staged | $SCRIPT_DIR/path-libraries.sh -p > $LIST
|
||||
git diff --name-only --staged | $SCRIPT_DIR/path-nonlibraries.sh -p >> $LIST
|
||||
|
||||
if [[ $(cat "$LIST" | wc -l) -eq 0 ]]; then
|
||||
echo "Nothing to commit." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Reseting changes in order to add files separately..."
|
||||
git reset >/dev/null
|
||||
|
||||
# head before commits - for recovery
|
||||
RECOVERY_HEAD=$(git log -n 1 --format=%H)
|
||||
exit_hook() {
|
||||
local last_error=$?
|
||||
|
||||
set +e
|
||||
|
||||
[[ -a /dev/fd/3 ]] && exec 3<&-
|
||||
|
||||
[[ $last_error -eq 0 ]] && return 0
|
||||
|
||||
echo
|
||||
echo "Program interrupted or finished with error(s), reseting head..." >&2
|
||||
git reset $RECOVERY_HEAD >/dev/null
|
||||
echo "Trying to re-add files..." >&2
|
||||
if [[ ! -f $LIST ]]; then
|
||||
echo "File with list of added files not found..." >&2
|
||||
else
|
||||
error=false
|
||||
cat $LIST | while read subsystem path; do
|
||||
if ! git add -- "$GIT_ROOT/$path"; then
|
||||
echo "Couldn't add \"$path\"..." >&2
|
||||
error=true
|
||||
fi
|
||||
done
|
||||
|
||||
if $error; then
|
||||
echo "This is embarrassing, couldn't re-add all files. Sorry." >&2
|
||||
else
|
||||
echo "Files re-added." >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
set -e
|
||||
trap "exit 1" SIGINT
|
||||
trap exit_hook EXIT
|
||||
|
||||
echo "Adding and committing subsystems..."
|
||||
exec 3< $LIST
|
||||
cur_subsystem=
|
||||
prev_subsystem=
|
||||
empty=true
|
||||
while read -u 3 subsystem path; do
|
||||
empty=false
|
||||
if [[ $cur_subsystem != $subsystem ]]; then
|
||||
if [[ -n $cur_subsystem ]]; then
|
||||
commit_subsystem "$cur_subsystem" "$prev_subsystem" "$@"
|
||||
echo
|
||||
fi
|
||||
prev_subsystem=$cur_subsystem
|
||||
cur_subsystem=$subsystem
|
||||
fi
|
||||
if ! git add -- "$GIT_ROOT/$path"; then
|
||||
echo "Couldn't add \"$path\", aborting..." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# the last one
|
||||
commit_subsystem "$cur_subsystem" "$prev_subsystem" "$@"
|
||||
echo
|
Loading…
Reference in New Issue