Как я могу сжать мои последние X коммитов вместе в один коммит, используя Git?
git
rebase
squash
git-squash
markdorison
источник
источник
Ответы:
Используйте
git rebase -i <after-this-commit>
и замените «pick» на втором и последующих коммитах на «squash» или «fixup», как описано в руководстве .В этом примере
<after-this-commit>
это либо хеш SHA1, либо относительное местоположение из HEAD текущей ветви, из которой анализируются коммиты для команды rebase. Например, если пользователь желает просмотреть 5 коммитов из текущего HEAD в прошлом, команда имеет видgit rebase -i HEAD~5
.источник
<after-this-commit>
?<after-this-commit>
это коммит X + 1, т.е. родитель самого старого коммита, который вы хотите раздавить.rebase -i
подходом иreset --soft
заключается в том, чтоrebase -i
я могу сохранить автора коммита, в то время какreset --soft
я могу подтвердить его. Иногда мне нужно раздавить коммиты по запросу, сохраняя при этом информацию об авторе. Иногда мне нужно сбросить софт на свои коммиты. В любом случае возбуждаю оба великолепных ответа.Вы можете сделать это довольно легко без
git rebase
илиgit merge --squash
. В этом примере мы раздавим последние 3 коммита.Если вы хотите написать новое сообщение с нуля, этого достаточно:
Если вы хотите начать редактирование нового сообщения фиксации с конкатенации существующих сообщений фиксации (т. Е. Аналогично тому, с чего
git rebase -i
начнёт список инструкций pick / squash / squash /… / squash ), то вам нужно извлечь эти сообщения и передать имgit commit
:Оба эти метода объединяют последние три коммита в один новый коммит одинаково. Мягкий сброс просто перенаправляет HEAD на последний коммит, который вы не хотите раздавливать. Программный сброс не затрагивает ни индекс, ни рабочее дерево, оставляя индекс в желаемом состоянии для вашего нового коммита (т. Е. Он уже содержит все изменения из коммитов, которые вы собираетесь «выбросить»).
источник
git rebase --squash-recent
или дажеgit commit --amend-many
.branch@{upstream}
(или только@{upstream}
для текущей ветки; в обоих случаях последняя часть может быть сокращена до@{u}
; см. Gitrevisions ). Это может отличаться от вашего «последнего выдвинутого коммита» (например, если кто-то выдвинул что-то, что построено поверх вашего самого последнего толчка, а затем вы его получили), но кажется, что это может быть близко к тому, что вы хотите.push -f
но в остальном это было прекрасно, спасибо.git push --force
потом, чтобы он взял коммитВы можете использовать
git merge --squash
для этого, что немного более элегантно, чемgit rebase -i
. Предположим, что вы мастер, и вы хотите раздавить последние 12 коммитов в один.ПРЕДУПРЕЖДЕНИЕ. Сначала убедитесь, что вы зафиксировали свою работу - убедитесь, что
git status
она чистая (посколькуgit reset --hard
отбросит поэтапные и неустановленные изменения)Затем:
Документация
git merge
описывает--squash
вариант более подробно.Обновление: единственное реальное преимущество этого метода перед более простым,
git reset --soft HEAD~12 && git commit
предложенным Крисом Джонсеном в его ответе, состоит в том, что вы получаете сообщение о коммите, предварительно заполненное каждым сообщением о коммите, которое вы подавляете.источник
git rebase -i
, но не приводите причину почему. Ориентировочно, потому что мне кажется, что на самом деле все наоборот, и это взлом; Разве вы не выполняете больше команд, чем необходимо, только для того, чтобы заставить васgit merge
выполнить одну из задач,git rebase
специально предназначенных для этого?git merge --squash
также легче использовать в скрипте. По сути, причина была в том, что вам вообще не нужна «интерактивность»git rebase -i
.git merge --squash
менее вероятно возникновение конфликтов слияния при перемещении / удалении / переименовании по сравнению с перебазированием, особенно если вы выполняете слияние из локальной ветки. (Отказ от ответственности: основываясь только на одном опыте, поправьте меня, если это не так в общем случае!)HEAD@{1}
чтобы просто быть в безопасности, например, когда ваш рабочий процесс прерывается на час из-за отключения электроэнергии и т. Д.Я рекомендую избегать,
git reset
когда это возможно, особенно для Git-новичков. Если вам действительно не нужно автоматизировать процесс, основанный на ряде коммитов, есть менее экзотический способ ...git merge --squash (working branch name)
git commit
Сообщение фиксации будет предварительно заполнено на основе сквоша.
источник
gitk
для обозначения строки кода, которую вы подавляете, а также для обозначения основы, на которую нужно нажимать. В обычном случае обе эти метки уже существуют, поэтому шаг (1) можно пропустить.git branch your-feature && git reset --hard HEAD~N
наиболее удобный способ. Тем не менее, он снова включает git reset, чего этот ответ пытался избежать.Основываясь на ответе Криса Джонсена ,
Добавьте глобальный псевдоним "squash" из bash: (или Git Bash в Windows)
... или с помощью командной строки Windows:
Вы
~/.gitconfig
должны теперь содержать этот псевдоним:Применение:
... который автоматически объединяет последние
N
коммиты включительно.Примечание. Результирующее сообщение о фиксации представляет собой комбинацию всех сжатых фиксаций по порядку. Если вы недовольны этим, вы всегда
git commit --amend
можете изменить его вручную. (Или измените псевдоним в соответствии со своими вкусами.)источник
git squash -m "New summary."
иN
определил автоматически как число невыдвинутых коммитов.git commit --amend
для дальнейшего изменения сообщения, но этот псевдоним позволяет вам хорошо начать с того, что должно быть в сообщении фиксации.Благодаря этому удобному сообщению в блоге я обнаружил, что вы можете использовать эту команду, чтобы раздавить последние 3 коммита:
Это удобно, так как работает, даже когда вы находитесь в локальной ветке без информации об отслеживании / удаленного репо.
Команда откроет интерактивный редактор ребаз, который затем позволит вам изменить порядок, сквош, перефразировать слова и т. Д. Как обычно.
Использование интерактивного редактора ребаз:
Интерактивный редактор rebase показывает последние три коммита. Это ограничение было определено
HEAD~3
при запуске командыgit rebase -i HEAD~3
.Самый последний коммит,
HEAD
отображается первым в строке 1. Строки, начинающиеся с a,#
являются комментариями / документацией.Документация отображается довольно ясно. В любой строке вы можете изменить команду
pick
на команду по вашему выбору.Я предпочитаю использовать команду, так
fixup
как она «раздавливает» изменения коммита в коммите в строке выше и отбрасывает сообщение коммита.Поскольку коммит в строке 1
HEAD
, в большинстве случаев вы бы оставили это какpick
. Вы не можете использоватьsquash
или,fixup
поскольку нет другого коммита, чтобы раздавить коммит в.Вы также можете изменить порядок коммитов. Это позволяет вам фиксировать или фиксировать коммиты, которые не являются смежными в хронологическом порядке.
Практический повседневный пример
Я недавно совершил новую функцию. С тех пор я исправил две ошибки. Но теперь я обнаружил ошибку (или, возможно, просто орфографическую ошибку) в новой функции, которую я совершил. Как раздражает! Я не хочу, чтобы новый коммит загрязнял мою историю коммитов!
Первое, что я делаю, это исправляю ошибку и делаю новый коммит с комментарием
squash this into my new feature!
.Затем я запускаю
git log
илиgitk
получаю коммит SHA новой функции (в данном случае1ff9460
).Затем я открываю интерактивный редактор ребаз
git rebase -i 1ff9460~
.~
После фиксации ША говорит редактор , чтобы включить этот коммит в редакторе.Затем я перемещаю коммит, содержащий fix (
fe7f1e0
), под коммит функции и изменяюpick
наfixup
.При закрытии редактора исправление попадет в коммит функции, и моя история коммитов будет выглядеть красиво и чисто!
Это хорошо работает, когда все коммиты являются локальными, но если вы попытаетесь изменить какие-либо коммиты, уже переданные на удаленный компьютер, вы действительно можете вызвать проблемы у других разработчиков, которые проверили ту же ветку!
источник
pick
в строке 1. Если вы выберитеsquash
илиfixup
для коммита в строке 1, git покажет сообщение «ошибка: невозможно исправить» без предыдущего коммита ». Затем он даст вам возможность исправить это: «Вы можете исправить это с помощью« git rebase --edit-todo »и затем запустить« git rebase --continue »». или вы можете просто прервать и начать заново: «Или вы можете прервать ребаз с помощью« git rebase --abort ».».Если вы используете TortoiseGit, вы можете использовать функцию
Combine to one commit
:Show Log
Combine to one commit
из контекстного менюЭта функция автоматически выполняет все необходимые одиночные шаги git. К сожалению, доступно только для Windows.
источник
Для этого вы можете использовать следующую команду git.
n (= 4 здесь) - номер последнего коммита. Тогда у вас есть следующие варианты,
Обновите, как показано ниже,
pick
один коммит, аsquash
остальные - в самый последний,Для получения подробной информации нажмите на ссылку
источник
Основываясь на этой статье, я нашел этот метод проще для моего сценария использования.
Моя ветка 'dev' опередила 'origin / dev' на 96 коммитов (поэтому эти коммиты еще не были перенесены на удаленный).
Я хотел раздавить эти коммиты в один, прежде чем приступить к изменениям. Я предпочитаю сбросить ветку в состояние origin / dev (это оставит все изменения из 96 коммитов без изменений), а затем зафиксировать изменения сразу:
источник
В ветке, в которой вы хотите объединить коммиты, запустите:
пример:
Это откроет текстовый редактор, и вы должны переключить «pick» перед каждым коммитом с помощью «squash», если вы хотите, чтобы эти коммиты были объединены вместе. Из документации:
p, pick = использовать коммит
s, squash = использовать коммит, но слиться с предыдущим коммитом
Например, если вы хотите объединить все коммиты в один, «пикап» - это первый коммит, который вы сделали, и все будущие (расположенные ниже первого) должны быть установлены на «сквош». Если используется vim, используйте : x в режиме вставки для сохранения и выхода из редактора.
Затем, чтобы продолжить ребаз:
Подробнее об этом и других способах переписывания истории коммитов читайте в этом полезном посте.
источник
--continue
vim:x
.git add
укажете правильную конфигурацию в ваших файлах,git rebase --continue
чтобы перейти к следующему коммиту и начать слияние.:x
это одна команда, которая сохранит изменения в файле при использовании vim, смотрите этоОтвет аномалии хороший, но я чувствовал себя неуверенно по этому поводу, поэтому я решил добавить пару скриншотов.
Шаг 0: Git Log
Посмотри, где ты
git log
. Самое главное, найти хэш коммита первого коммита, который вы не хотите раздавить. Так что толькоШаг 1: git rebase
Выполните
git rebase -i [your hash]
, в моем случае:Шаг 2: выбрать / раздавить, что вы хотите
В моем случае я хочу раздавить все на коммите, который был первым во времени. Порядок в порядке от первого до последнего, так же, как и в
git log
. В моем случае я хочу:Шаг 3: Настройте сообщение (я)
Если вы выбрали только один коммит и раздавили остальные, вы можете настроить одно сообщение о коммите:
Вот и все. Как только вы сохраните это (
:wq
), все готово. Посмотрите на это сgit log
.источник
git log
Процедура 1
1) Определите коммит короткого хэша
Здесь даже
git log --oneline
можно использовать короткий хеш.2) Если вы хотите раздавить (объединить) последние два коммита
3) Это открывает
nano
редактор для слияния. И это выглядит ниже4) Переименуйте слово
pick
вsquash
которое присутствует раньшеabcd1234
. После переименования это должно быть как ниже.5) Теперь сохраните и закройте
nano
редактор. Нажмитеctrl + o
и нажмите,Enter
чтобы сохранить. А затем нажмите,ctrl + x
чтобы выйти из редактора.6) Затем
nano
снова открывается редактор для обновления комментариев, при необходимости обновляйте его.7) Теперь его успешно завершили, вы можете проверить это, проверив логи.
8) Теперь нажмите на репо. Обратите внимание, чтобы добавить
+
знак перед названием ветви. Это означает принудительный толчок.Примечание: это основано на использовании git на
ubuntu
оболочке. Если вы используете разные ОС (Windows
илиMac
), то приведенные выше команды такие же, кроме редактора. Вы можете получить другой редактор.Процедура 2
--fixup
опцию, иOLDCOMMIT
мы должны объединить (сквош) этот коммит.Теперь это создает новый коммит поверх HEAD с
fixup1 <OLDCOMMIT_MSG>
.OLDCOMMIT
.Здесь
^
означает предыдущий коммитOLDCOMMIT
. Этаrebase
команда открывает интерактивное окно в редакторе (vim или nano) о том, что нам не нужно ничего делать, просто сохранить и выйти достаточно. Поскольку переданная опция будет автоматически перемещать последнюю фиксацию на следующую за старой фиксацией и изменять операцию наfixup
(эквивалентную сквошу). Затем перебазирование продолжается и заканчивается.Процедура 3
--amend
можно использовать средства сgit-commit
.Здесь
--amend
объединяет новые изменения с последним коммитомcdababcd
и генерирует новый идентификатор коммита1d4ab2e1
Вывод
источник
Чтобы раздавить последние 10 коммитов в один коммит:
Если вы также хотите обновить удаленную ветку с помощью сжатого коммита:
источник
Если вы находитесь в удаленной ветви (называемой
feature-branch
), клонированной из Золотого репозитория (golden_repo_name
), то вот метод, позволяющий объединить ваши коммиты в один:Оформить заказ на золотой репо
Создайте из него новую ветку (золотой репо) следующим образом
Сквош слиться с местным филиалом, который у вас уже есть
Зафиксируйте ваши изменения (это будет единственный коммит в ветке dev)
Вставьте ветку в ваш локальный репозиторий
источник
Что может быть действительно удобно:
скажем, найти хеш коммита, который вы хотите сжать поверх
d43e15
.Сейчас использую
источник
Это очень круто, но довольно круто, так что я просто брошу это на ринг:
Перевод: предоставьте новый «редактор» для git, который, если редактируемое имя файла
git-rebase-todo
(интерактивная подсказка перебазировки), изменяет все, кроме первого «pick», на «squash», а в противном случае порождает vim - так, чтобы при появлении запроса чтобы редактировать сжатое сообщение о коммите, вы получаете vim. (И, очевидно, я давил последние пять коммитов на ветке foo, но вы можете изменить это так, как вам нравится.)Я бы, наверное, сделал то, что предложил Марк Лонгэйр .
источник
Если вы хотите объединить каждый коммит в один коммит (например, при первом публичном выпуске проекта), попробуйте:
источник
2020 Простое решение без перебазирования:
git reset --soft HEAD~2
git commit -m "new commit message"
git push --force
2 означает, что последние два коммита будут раздавлены. Вы можете заменить его на любой номер
источник
Я думаю, что самый простой способ сделать это - создать новую ветку из master и выполнить слияние - сквош функциональной ветви.
Тогда у вас есть все изменения, готовые к фиксации.
источник
Простой однострочный, который всегда работает, учитывая, что вы в данный момент находитесь в ветви, которую хотите сжать, master - это ветвь, из которой он возник, а последний коммит содержит сообщение о коммите и автора, которого вы хотите использовать:
источник
например, если вы хотите раздавить последние 3 коммита в один коммит в ветке (удаленное хранилище), например: https://bitbucket.org
Что я сделал
источник
⚠️ ВНИМАНИЕ: «Мои последние X коммиты» могут быть неоднозначными.
В этой очень сокращенной истории хранилища https://github.com/fleetwood-mac/band-history вы открыли запрос на извлечение для объединения в коммит Билла Клинтона с оригинальным
MASTER
коммитом Fleetwood Mac.Вы открыли пулл-запрос и на GitHub вы видите это:
Четыре коммитов:
Думая, что никто не захочет читать всю историю хранилища. (Там на самом деле есть хранилище, нажмите на ссылку выше!) Вы решили раздавить эти коммиты. Так ты иди и беги
git reset --soft HEAD~4 && git commit
. Затем выgit push --force
отправляете его на GitHub, чтобы очистить ваш PR.А что происходит? Вы только что сделали один коммит от Фрица до Билла Клинтона. Потому что вы забыли, что вчера вы работали над версией Бекингемского Ника. И
git log
не соответствует тому, что вы видите на GitHub.🐻 МОРАЛЬ ИСТОРИИ
git checkout
ихgit reset --soft
этоgit commit
деформацию непосредственно от к кисточник
Если вас не интересуют сообщения о коммитах промежуточных коммитов, вы можете использовать
источник
Если вы работаете с GitLab, вы можете просто щелкнуть опцию Squash в запросе на слияние, как показано ниже. Сообщение фиксации будет названием запроса на слияние.
источник
где число ^ это X
(в этом случае раздавите два последних коммита)
источник
В дополнение к другим превосходным ответам, я хотел бы добавить, как
git rebase -i
всегда меня смущает порядок коммитов - от старого к более новому или наоборот? Так что это мой рабочий процесс:git rebase -i HEAD~[N]
где N - количество коммитов, к которым я хочу присоединиться, начиная с самого последнего . Такgit rebase -i HEAD~5
будет означать «раздавить последние 5 коммитов в новый»;Источники и дополнительные материалы: № 1 , № 2 .
источник
Как насчет ответа на вопрос, связанный с таким рабочим процессом?
merge --squash
после пиара разработчику будет легче , но команда подумала, что это замедлит процесс.)Я не видел такой рабочий процесс на этой странице. (Это могут быть мои глаза.) Если я
rebase
правильно понимаю , для множественных слияний потребуется многократное разрешение конфликтов . Я не хочу даже думать об этом!Так что, похоже, это работает для нас.
git pull master
git checkout -b new-branch
git checkout -b new-branch-temp
git checkout new-branch
git merge --squash new-branch-temp
// помещает все изменения в стадиюgit commit 'one message to rule them all'
git push
источник
Я считаю, что более общим решением является не указание N коммитов, а указание идентификатора ветки / commit, над которым вы хотите получить сжатие. Это менее подвержено ошибкам, чем подсчет коммитов до определенного коммита - просто укажите тег напрямую, или, если вы действительно хотите посчитать, вы можете указать HEAD ~ N.
В моем рабочем процессе я запускаю ветвь, и мой первый коммит в этой ветке суммирует цель (то есть обычно это то, что я отправляю как «окончательное» сообщение для функции в общедоступный репозиторий). Поэтому, когда я закончу, все Я хочу сделать, это
git squash master
вернуться к первому сообщению, а затем я готов нажать.Я использую псевдоним:
Это приведет к тому, что история будет сдавлена, прежде чем это произойдет, - это даст вам шанс восстановиться путем извлечения старого идентификатора коммита с консоли, если вы хотите вернуться. (Пользователи Solaris отмечают, что он использует
-i
опцию GNU sed , пользователи Mac и Linux должны с этим справиться.)источник
git squash master
когда мы проверены на ведомом. что это будет происходить? мы будем скрывать конфликт?Это может быть неоднозначно, что подразумевается под «последним».
например
git log --graph
выводит следующее (упрощенно):Тогда последними коммитами по времени являются H0, merge, B0. Чтобы раздавить их, вам придется перебазировать вашу объединенную ветвь при коммите H1.
Проблема в том, что H0 содержит H1 и H2 (и, как правило, больше коммитов до слияния и после ветвления), а B0 - нет. Таким образом, вы должны управлять изменениями от H0, слияния, H1, H2, B0 по крайней мере.
Можно использовать rebase, но иначе, чем в других упомянутых ответах:
rebase -i HEAD~2
Это покажет вам варианты выбора (как упоминалось в других ответах):
Положите сквош вместо кирки в H0:
После сохранения и выхода rebase будет применять коммиты по очереди после H1. Это означает, что он попросит вас снова разрешить конфликты (где HEAD будет сначала H1, а затем накапливает коммиты по мере их применения).
После завершения ребазирования вы можете выбрать сообщение для раздавленных H0 и B0:
PS Если вы просто сделаете некоторый сброс в BO: (например, использование
reset --mixed
этого объясняется более подробно здесь https://stackoverflow.com/a/18690845/2405850 ):затем вы давите на B0 изменений H0, H1, H2 (потеря полностью фиксирует изменения после ветвления и до слияния.
источник
1) git reset --soft HEAD ~ n
n - номер коммита, нужно сквош
2) git commit -m "новое сообщение коммита"
3) git push origin_name_force
источник