Я пытаюсь раздавить ряд коммитов — от HEAD до HEAD~3. Есть ли быстрый способ сделать это или мне нужно использовать rebase --interactive?
Есть ли способ раздавить количество коммитов не в интерактивном режиме?
Ответы (8)
Убедитесь, что ваше рабочее дерево чистое, затем
git reset --soft HEAD~3
git commit -m 'new commit message'
git reset --soft HEAD~3 && git commit -m "my message"
- person KingCrunch; 02.09.2011
git config alias.mysquash '!f(){ git reset --soft HEAD~$1 && git commit ${2:+-m "$2"}; };f'
. git mysquash 3 'some message'
будет работать, но я также настроил его так, чтобы git musquash 3
полностью опускал флаг -m, поэтому в этом случае вы получите интерактивный git commit
пользовательский интерфейс.
- person Lily Ballard; 02.09.2011
mu
вы имели в виду my
.
- person Acumenus; 22.04.2014
HEAD~3
, чтобы отразить последний отправленный коммит? Я не хочу вводить 3
и т. д.
- person Acumenus; 22.04.2014
Мне лично нравится решение wilhelmtell:
git reset --soft HEAD~3
git commit -m 'new commit message'
Однако я сделал псевдоним с некоторой проверкой ошибок, чтобы вы могли сделать это:
git squash 3 'my commit message'
Я рекомендую настроить псевдонимы, которые фактически запускают сценарии, чтобы было легче (а) кодировать ваши сценарии и (б) выполнять более сложную работу с проверкой ошибок. Ниже приведен скрипт, выполняющий работу сквоша, а затем скрипт для настройки ваших псевдонимов git.
Скрипт для сжатия (squash.sh)
#!/bin/bash
#
#get number of commits to squash
squashCount=$1
#get the commit message
shift
commitMsg=$@
#regular expression to verify that squash number is an integer
regex='^[0-9]+$'
echo "---------------------------------"
echo "Will squash $squashCount commits"
echo "Commit message will be '$commitMsg'"
echo "...validating input"
if ! [[ $squashCount =~ $regex ]]
then
echo "Squash count must be an integer."
elif [ -z "$commitMsg" ]
then
echo "Invalid commit message. Make sure string is not empty"
else
echo "...input looks good"
echo "...proceeding to squash"
git reset --soft HEAD~$squashCount
git commit -m "$commitMsg"
echo "...done"
fi
echo
exit 0
Затем, чтобы подключить этот скрипт squash.sh к псевдониму git, создайте еще один скрипт для настройки ваших псевдонимов git следующим образом (create_aliases.command или create_aliases.sh ):
#!/bin/sh
echo '-----------------------'
echo 'adding git aliases....'
echo '-----------------------'
echo
git config --global alias.squash "!bash -c 'bash <path to scripts directory>/squash.sh \$1 \$2' -"
#add your other git aliases setup here
#and here
#etc.
echo '------------------------------------'
echo 'here is your global gitconfig file:'
echo '------------------------------------'
more ~/.gitconfig
echo
echo
echo '----------------'
echo 'end of script...'
echo '----------------'
$PATH
с именем git-squash.sh
, и он автоматически получит псевдоним git squash
. Я не изменил ваш ответ на тот случай, если есть причина использовать скрипт create-aiases.sh
, о которой я не знаю.
- person ; 12.06.2014
-
. Кроме того, да, вам придется принудительно нажать, если вы уже отправили ранее не раздавленные коммиты. Я рекомендую принудительно нажимать только на ваши собственные ветки, а не на основную ветку.
- person n8tr; 27.10.2015
Чтобы добавить к ответу wilhelmtell, я считаю удобным выполнить программный сброс до HEAD~2
, а затем изменить фиксацию HEAD~3
:
git reset --soft HEAD~2
git commit --all --amend --no-edit
Это объединит все коммиты с коммитом HEAD~3
и будет использовать его сообщение коммита. Обязательно начните с чистого рабочего дерева.
--all
в git commit
не нужен, потому что измененные файлы уже помещены после мягкого сброса. Документ для git commit --all
- person li ki; 17.06.2021
Я использовал:
EDITOR="sed -i '2,/^$/s/^pick\b/s/'" git rebase -i <ref>
Работал вполне нормально. Только не пытайтесь вести журнал коммитов со строкой, начинающейся с «выбрать» :)
Используйте следующую команду, чтобы раздавить последние 4 коммита в последнем коммите:
git squash 4
С псевдонимом:
squash = !"f() { NL=$1; GIT_EDITOR=\"sed -i '2,$NL s/pick/squash/;/# This is the 2nd commit message:/,$ {d}'\"; git rebase -i HEAD~$NL; }; f"
sq = !git squash $1
sqpsf = !git squash $1 && git psf
Из https://github.com/brauliobo/gitconfig/blob/master/configs/.gitconfig
Вот один лайнер, чтобы раздавить последние 2 коммита. В этом примере будет сохранено сообщение предпоследней фиксации. Вы можете изменить сообщение по своему усмотрению.
git commit -am "$(git log -1 --skip=1 --pretty=%B | xargs && git reset --soft HEAD~2)"
Эта команда будет очень полезна, если вы создадите псевдоним для этой команды и будете использовать его вместо этого.
Чтобы раздавить все, так как ветвь была разветвлена от мастера:
git reset --soft $(git merge-base --fork-point master) \
&& git commit --verbose --reedit-message=HEAD --reset-author
--reedit-message=HEAD
будет использовать сообщение последней фиксации, которая не является частью сжатия. Скорее всего, это не тот, который вам нужен. Чтобы получить сообщение о первом включенном коммите, либо (1) замените HEAD
на хеш фиксации, сообщение о котором вы хотите получить, либо ( 2) перейти к первому включенному коммиту и git commit --amend --reedit-message=HEAD
. Вот что делает гармоничный ответ.
- person Maëlan; 09.11.2018
Вы можете быть довольно близко с
git rebase --onto HEAD~4 HEAD~ master
Это предполагает, что вы находитесь на мастере с линейной историей. Это не совсем сквош, потому что он отбрасывает промежуточные коммиты. Вам нужно будет изменить новый HEAD, чтобы изменить сообщение фиксации.
HEAD~4
был его родителем.
- person Greg Bacon; 06.09.2011