Мне нравятся ответы от Каскабель и Стюарта, потому что они показывают, как написать сценарий для обложки, которая выполняет желаемую задачу.Они используют git add
вместо git add --patch
в качестве поставленного вопроса, но все еще в духе вопроса.Другой альтернативой является использование git add --edit
, которое имеет то преимущество, что ему вообще не нужно изменять рабочее дерево.Мой ответ логически - небольшое изменение в сценарии Стюарта.
Проблема, с которой я сталкиваюсь в git add --patch
, заключается в том, что он по своей сути интерактивен, поэтому его трудно покрыть сценарием.Подход Стюарта состоит в том, чтобы использовать инструмент diff для определения желаемого полного содержимого индекса, а затем использовать git add
, чтобы сделать это.Мой подход отличается тем, что вместо изменения рабочего дерева до и после вызова git add
я беру желаемый полный контент и превращаю его в патч, который можно применить к индексу, чтобы сделать его таким.Тогда EDITOR="mv \"$PATCH\"" git add --edit
можно использовать для этого.Это позволяет избежать изменений в рабочем дереве.
Чтобы использовать этот подход, начните со сценария Стюарта и замените определение patch_file_and_add
следующим:
patch_file_and_add() {
f="$1"
base=$(basename "$f")
dir=$(mktemp -d)
mkdir "$dir/working"
mkdir "$dir/index"
mkdir "$dir/merged"
LOCAL="$dir/working/$base"
REMOTE="$dir/index/$base"
MERGED="$dir/merged/$base"
PATCH1="$dir/head.patch"
PATCH="$dir/full.patch"
git show :"$f" > "$REMOTE" # Copy from the index
(
set -e
trap "echo && exit 130" INT # Ctrl+C should trigger abnormal exit
# Execute 2-file merge
echo "Launching ${MERGETOOL} for '$f'."
cp "$f" "$LOCAL"
eval "${MERGECMD}"
if [[ -e "$MERGED" ]]; then
git diff -- "$f" > "$PATCH1" 2> /dev/null
git diff --staged -- "$f" >> "$PATCH1" 2> /dev/null
# We need both of the above in case one is empty.
head -4 "$PATCH1" > "$PATCH"
diff --unified=7 "$REMOTE" "$MERGED" | tail -n +3 >> "$PATCH"
# Now we have the patch we want to apply to the index.
EDITOR="mv \"$PATCH\"" git add -e -- "$f"
fi
rm -rf "$dir"
)
status=$?
if [ $status == 130 ]; then
echo "User interrupted." 1>&2
exit $status
elif [ $status != 0 ]; then
echo "Error: Interactive add-patch stopped early!" 1>&2
exit $status
fi
}
Строго говоря, LOCAL
может бытьустановите $f
вместо использования mv
, чтобы поместить его рядом с остальными.Но я помню, что некоторые сторонние программы сравнения позволяют скрывать общую начальную часть пути, поэтому этот подход может воспользоваться этой возможностью.
Спасибо Cascabel и Stuart за отличные ответы, а HaxElit заотличный вопрос.