Сквош два Git фиксируются в середине истории без интерактивной перестановки
Я собираюсь преобразовать старый SVN-репозиторий в Git, который включает попытку получить все ветки/теги во всех правильных местах. Эта часть идет неплохо, но есть моменты, когда я хочу добавить фиксацию в истории в свой script, который позже мне нужно сквош со следующей фиксацией. Проблема в том, что я не хватаю коммиты один за другим, но как большую группу, поэтому я не могу раздавить их, когда вытаскиваю их из репозитория SVN. В конце концов, мой репозиторий выглядит следующим образом:
* (branch_2, HEAD) commit 5
* commit 4
* commit 3
* SQUASH ME!
* (branch_1) commit 2
* commit 1
Я хочу иметь возможность скворовать commit 3
с помощью SQUASH ME!
, что, очевидно, легко с интерактивной перестановкой, но более сложной из script. Основная проблема, которая, как мне кажется, заключается в том, что, хотя она легко проверяется branch_1
или какой-либо фиксацией до нее, сложно запрограммировать запрос после нее, и мне сложно предсказать, сколько из них возвращается из branch_2
Мне нужно идти. Я действительно хочу иметь возможность сделать что-то вроде:
git checkout branch_1+2
Любые указатели?
Ответы
Ответ 1
То, о чем вы говорите, это не сквош, а fixup, потому что сквош запросит у вас сообщение commit в интерактивном режиме, тогда как используется fixup сообщение фиксации из сообщения HEAD.
Здесь script, который делает это без вмешательства.
script: /usr/bin/git-fixup
#/bin/bash
# This command fixesup one commit onto his parent
set -e
# We need a commit from the first argument of that command
commit=${1:?No commit given as first argument}
startingbranch=$(git rev-parse --abbrev-ref HEAD)
# Checkout the parent of the asked commit
git checkout "$commit"
git checkout HEAD~
# Merge the commit into it parent, keeping the commit message of the parent
git merge --squash "$commit"
git add .
git add --update
git commit --amend --no-edit
# Store the current commit
newcommit=$(git rev-parse HEAD)
# Rebase the starting branch onto the new commit
git checkout "$startingbranch"
git rebase "$newcommit"
Используйте его с
git fixup <commit-id>
Например, если ваша история:
ce0e2fd (master, HEAD) commit 4
72ab3c4 commit 3
8150939 commit 2
301c1e1 commit 1
Вы можете сделать git fixup 72ab3c4
, который объединит "commit 3" и "commit 2" в качестве фиксации с сообщением "commit 2" и поместит вас обратно на главную ветку.
Ответ 2
От git rebase --help
:
- autosquash
Когда сообщение журнала фиксации начинается с "squash!..." (или "fixup!..." ), и есть фиксация, чье название начинается с того же..., автоматически изменяет список задач rebase -i так что фиксация, помеченная для раздавливания, появляется сразу после фиксации, которая будет изменена, и изменит действие перемещенного фиксации от выбора до сквоша (или исправления).
Эта опция действительна только при использовании опции -interactive.
Похоже, что он сделает половину того, что вы хотите, если вход находится в правильной форме.
Другая половина препятствует запуску интерактивного редактора. К счастью, редактор настраивается, поэтому мы можем просто установить его на что-то безопасное.
Попробуйте следующее:
env EDITOR=true git rebase -i --autosquash <from-here>
Настройка редактора на true
(инструмент, который просто успешно завершается) достаточно, чтобы убедить git выполнить настройки переустановки по умолчанию, которые автокартф должен был установить на что-то полезное.
В качестве альтернативы, если --autosquash
не делает то, что вам нужно, вы можете установить EDITOR
на любой script, который вам нравится:
env EDITOR=mysquasher.sh git rebase -i <from-here>
script может делать все, что вам нужно, но в вашем случае ему нужно найти только каждую строку, содержащую "SQUASHME!"
, и изменить "pick"
на следующую строку, чтобы прочитать "fixup"
. Скорее всего, это может быть достигнуто с помощью awk:
#!/bin/bash -e
awk -- 'BEGIN {dosquash=0}
dosquash==1 {gsub(/^pick/, "fixup"); dosquash=0}
/SQUASHME/ {dosquash=1}
{print}' "$1" > /tmp/tmp.$$
mv /tmp/tmp.$$ "$1"