Сквош мой последний X коммитов вместе с помощью Git
Как я могу сжать мои последние X коммитов в один коммит с помощью Git?
48 ответов
Использование git rebase -i <after-this-commit>
и замените "pick" на втором и последующих коммитах на "squash" или "fixup", как описано в руководстве.
В этом примере <after-this-commit>
является либо хэшем SHA1, либо относительным местоположением из HEAD текущей ветви, из которой анализируются коммиты для команды rebase. Например, если пользователь желает просмотреть 5 коммитов из текущего HEAD в прошлом, команда git rebase -i HEAD~5
,
Вы можете сделать это довольно легко без git rebase
или же git merge --squash
, В этом примере мы раздавим последние 3 коммита.
Если вы хотите написать новое сообщение с нуля, этого достаточно:
git reset --soft HEAD~3 &&
git commit
Если вы хотите начать редактирование нового сообщения о коммите с конкатенацией существующих сообщений о коммите (т. Е. Аналогично пику /squash/squash/…/squash git rebase -i
список команд будет начинаться с вас), затем вам нужно извлечь эти сообщения и передать их git commit
:
git reset --soft HEAD~3 &&
git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"
Оба эти метода объединяют последние три коммита в один новый коммит таким же образом. Мягкий сброс просто перенаправляет HEAD на последний коммит, который вы не хотите раздавливать. Программный сброс не затрагивает ни индекс, ни рабочее дерево, оставляя индекс в желаемом состоянии для вашего нового коммита (т. Е. Он уже содержит все изменения из коммитов, которые вы собираетесь "выбросить").
Ты можешь использовать git merge --squash
для этого, что немного более элегантно, чем git rebase -i
, Предположим, что вы мастер, и вы хотите раздавить последние 12 коммитов в один.
ВНИМАНИЕ: Сначала убедитесь, что вы совершаете свою работу - проверьте, что git status
чисто (так как git reset --hard
выбросит поэтапные и не постановочные изменения)
Затем:
# Reset the current branch to the commit just before the last 12:
git reset --hard HEAD~12
# HEAD@{1} is where the branch was just before the previous command.
# This command sets the state of the index to be as it would just
# after a merge from that commit:
git merge --squash HEAD@{1}
# Commit those squashed changes. The commit message will be helpfully
# prepopulated with the commit messages of all the squashed commits:
git commit
Документация дляgit merge
описывает --squash
вариант более подробно.
Обновление: единственное реальное преимущество этого метода перед более простым git reset --soft HEAD~12 && git commit
Крис Джонсен в своем ответе предположил, что вы получаете сообщение о коммите, предварительно заполненное каждым сообщением о коммите, которое вы нажимаете.
2020 Простое решение без ребаза:
git reset --soft HEAD~2
git commit -m "new commit message"
git push --force
2 означает, что последние два коммита будут сжаты. Вы можете заменить его на любой номер
Я рекомендую избегать git reset
когда это возможно - особенно для Git-новичков. Если вам действительно не нужно автоматизировать процесс, основанный на ряде коммитов, есть менее экзотический способ...
- Поместите коммиты, которые будут сдавлены, в рабочую ветку (если они еще не сделаны) - используйте для этого gitk
- Проверьте целевую ветвь (например, "мастер")
git merge --squash (working branch name)
git commit
Сообщение фиксации будет предварительно заполнено на основе сквоша.
Благодаря этому удобному сообщению в блоге я обнаружил, что вы можете использовать эту команду, чтобы раздавить последние 3 коммита:
git rebase -i HEAD~3
Это удобно, так как работает, даже когда вы находитесь в локальной ветке без информации об отслеживании / удаленного репо.
Команда откроет интерактивный редактор ребаз, который затем позволит вам изменить порядок, сквош, перефразировать слова и т. Д. Как обычно.
Использование интерактивного редактора ребаз:
Интерактивный редактор rebase показывает последние три коммита. Это ограничение было определено HEAD~3
при запуске команды git rebase -i HEAD~3
,
Самый последний коммит, HEAD
, отображается первым в строке 1. Строки, начинающиеся с #
Есть комментарии / документация.
Документация отображается довольно ясно. В любой строке вы можете изменить команду с pick
на команду по вашему выбору.
Я предпочитаю использовать команду fixup
так как это "сдавливает" изменения коммита в коммит в строке выше и отбрасывает сообщение коммита.
Поскольку коммит в строке 1 HEAD
в большинстве случаев вы бы оставили это как pick
, Вы не можете использовать squash
или же fixup
поскольку нет другого коммита, чтобы раздавить коммит в.
Основываясь на ответе Криса Джонсена,
Добавьте глобальный псевдоним "squash" из bash: (или Git Bash в Windows)
git config --global alias.squash '!f(){ git reset --soft HEAD~${1} && git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"; };f'
... или с помощью командной строки Windows:
git config --global alias.squash "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"
Ваш ~/.gitconfig
теперь должен содержать этот псевдоним:
[alias]
squash = "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"
Использование:
git squash N
... который автоматически сдавливает последний N
совершает включительно.
Примечание. Результирующее сообщение о фиксации представляет собой комбинацию всех сжатых фиксаций по порядку. Если вы недовольны этим, вы всегда можете git commit --amend
изменить его вручную. (Или измените псевдоним в соответствии со своими вкусами.)
В ветке, в которой вы хотите объединить коммиты, запустите:
git rebase -i HEAD~(n number of commits back to review)
Это откроет текстовый редактор, и вы должны переключить "pick" перед каждым коммитом с помощью "squash", если вы хотите, чтобы эти коммиты были объединены вместе. Например, если вы хотите объединить все коммиты в один, "пикап" - это первый коммит, который вы сделали, и все будущие (расположенные ниже первого) должны быть установлены на "сквош". Если используется vim, используйте :x в режиме вставки для сохранения и выхода из редактора.
Затем, чтобы закончить ребаз:
git rebase --continue
Подробнее об этом и других способах переписывания истории коммитов читайте в этом полезном посте.
Для этого вы можете использовать следующую команду git.
git rebase -i HEAD~n
n (= 4 здесь) - номер последнего коммита. Тогда у вас есть следующие варианты,
pick 01d1124 Message....
pick 6340aaa Message....
pick ebfd367 Message....
pick 30e0ccb Message....
Обновление как ниже,
p 01d1124 Message....
s 6340aaa Message....
s ebfd367 Message....
s 30e0ccb Message....
Для получения подробной информации нажмите на ссылку
Удачи!!
Многие ответы основаны на
git rebase
команда, но по моему опыту она несколько сложна и продвинута для начинающих git.
Допустим, вы хотите отменить последние 3 коммита. Затем следующие шаги:
- Сначала проверьте журнал git : используйте
git log -1 --oneline
чтобы записать идентификатор фиксации текущего состояния (на случай, если вы сделаете что-то не так с git reset) - Вернуться на 3 коммита : Использование
git reset --soft HEAD~3
вы вернетесь на 3 коммита (и как бы забудете, что вы сделали эти три коммита ранее) - Сделайте новую фиксацию : теперь просто сделайте
git commit -m <NEW_SINGLE_MESSAGE>
который автоматически объединит три коммита под вашим сообщением
Если что-то пойдет не так с git reset, вы можете снова вернуться в исходное состояние,
git reset --soft <ORIGINAL_COMMIT>
Если вы используете TortoiseGit, вы можете функцию Combine to one commit
:
- Открыть контекстное меню TortoiseGit
- Выбрать
Show Log
- Отметьте соответствующие коммиты в представлении журнала
- Выбрать
Combine to one commit
из контекстного меню
Эта функция автоматически выполняет все необходимые одиночные шаги git. К сожалению, доступно только для Windows.
Основываясь на этой статье, я нашел этот метод проще для моего сценария использования.
Моя ветка 'dev' опередила 'origin/dev' на 96 коммитов (поэтому эти коммиты еще не были перенесены на удаленный).
Я хотел раздавить эти коммиты в один, прежде чем приступить к изменениям. Я предпочитаю сбросить ветку в состояние origin / dev (это оставит все изменения из 96 коммитов без изменений), а затем зафиксировать изменения сразу:
git reset origin/dev
git add --all
git commit -m 'my commit message'
Ответ на вопрос об аномиях хорош, но я чувствовал себя неуверенно по этому поводу, поэтому решил добавить пару скриншотов.
Шаг 0: Git Log
Посмотри, где ты с git log
, Самое главное, найти хеш коммита первого коммита, который вы не хотите раздавить. Так что только
Шаг 1: git rebase
казнить git rebase -i [your hash]
, в моем случае:
$ git rebase -i 2d23ea524936e612fae1ac63c95b705db44d937d
Шаг 2: выбрать / раздавить, что вы хотите
В моем случае я хочу раздавить все на коммите, который был первым во времени. Порядок от первого до последнего, так же, как и в git log
, В моем случае я хочу:
Шаг 3: Настройте сообщение (я)
Если вы выбрали только один коммит и раздавили остальные, вы можете настроить одно сообщение о коммите:
Вот и все. Как только вы сохраните это (:wq
), все готово. Посмотрите на это с git log
,
Я думаю, что самый простой способ сделать это - создать новую ветку на основе master и выполнить слияние - сквош функциональной ветви.
git checkout master
git checkout -b feature_branch_squashed
git merge --squash feature_branch
Тогда у вас есть все изменения, готовые к фиксации.
1) Определить коммит с коротким хешем
# git log --pretty=oneline --abbrev-commit
abcd1234 Update to Fix for issue B
cdababcd Fix issue B
deab3412 Fix issue A
....
Здесь даже git log --oneline
также может быть использован для получения короткого хэша.
2) Если вы хотите раздавить (объединить) последние два коммита
# git rebase -i deab3412
3) Это открывает nano
редактор для слияния. И это выглядит ниже
....
pick cdababcd Fix issue B
pick abcd1234 Update to Fix for issue B
....
4) Переименуй слово pick
в squash
который присутствует раньше abcd1234
, После переименования это должно быть как ниже.
....
pick cdababcd Fix issue B
squash abcd1234 Update to Fix for issue B
....
5) Теперь сохраните и закройте nano
редактор. Нажмите ctrl + o
и нажмите Enter
сохранить. А затем нажмите ctrl + x
выйти из редактора.
6) Тогда nano
редактор снова открывается для обновления комментариев, при необходимости обновите его.
7) Теперь он успешно сдавлен, вы можете проверить это, проверив логи.
# git log --pretty=oneline --abbrev-commit
1122abcd Fix issue B
deab3412 Fix issue A
....
8) Теперь нажмите на репо. Примечание для добавления +
подписать перед названием филиала. Это означает принудительный толчок.
# git push origin +master
Примечание: это основано на использовании git на ubuntu
ракушка. Если вы используете разные ОС (Windows
или же Mac
) тогда приведенные выше команды такие же, кроме редактора. Вы можете получить другой редактор.
Чтобы раздавить последние 10 коммитов в один коммит:
git reset --soft HEAD~10 && git commit -m "squashed commit"
Если вы также хотите обновить удаленную ветку с помощью сжатого коммита:
git push -f
Например , если вы хотите объединить все коммиты в один коммит в ветке (удаленное хранилище), например: https://bitbucket.org/
Что я сделал
- git reset --soft Head~3 &&
- мерзавец совершить
- git push origin --force
Если вы находитесь в удаленном филиале (называется feature-branch
) клонирован из Золотого Хранилища (golden_repo_name
), то вот методика раздавливания ваших коммитов в один:
Оформить заказ на золотой репо
git checkout golden_repo_name
Создайте из него новую ветку (золотой репо) следующим образом
git checkout -b dev-branch
Сквош слиться с местным филиалом, который у вас уже есть
git merge --squash feature-branch
Зафиксируйте ваши изменения (это будет единственный коммит в ветке dev)
git commit -m "My feature complete"
Вставьте ветку в ваш локальный репозиторий
git push origin dev-branch
Что может быть действительно удобным:
Найдите хеш коммита, который вы хотите использовать, скажем d43e15
,
Сейчас использую
git reset d43e15
git commit -am 'new commit name'
Кто-нибудь упоминал, как легко это сделать в пользовательском интерфейсе IntelliJ IDEA:
- Перейти к
git
окно - Выберите все коммиты, которые вы хотите объединить в один.
- Щелкните правой кнопкой мыши>
Squash
> Отредактируйте сообщение фиксации - Щелкните имя ветки слева> щелкните правой кнопкой мыши> Нажать>
Push Force
метод 1 , если у вас много коммитов
git rebase -i master
затем нажмите клавиатуру «i», чтобы отредактировать
вы увидите следующее:
pick etc1
pick etc2
pick etc2
заменить слово выбрать на
'f'
и нажмите
esc y :wq
pick etc1 //this commit will the one commit
f etc2
f etc2
и нажмите эту команду
git push origin +head
метод 2 , если у вас мало коммитов, вы можете сделать это, чтобы удалить коммит, вам нужно сделать то же самое для удаления второго коммита и т. д.
git reset --soft HEAD^1
git commit --amend
git push -f
метод 3 , если у вас уже есть одна фиксация и вы не хотите отправлять еще одну фиксацию
git add files...
git commit --amend //then press `:wq`
git push origin +head
простое решение:
git reset --soft HEAD~5
git commit -m "commit message"
git push origin branch --force-with-lease
Если вы хотите объединить каждый коммит в один коммит (например, при первом публичном выпуске проекта), попробуйте:
git checkout --orphan <new-branch>
git commit
Это очень круто, но довольно круто, так что я просто брошу это на ринг:
GIT_EDITOR='f() { if [ "$(basename $1)" = "git-rebase-todo" ]; then sed -i "2,\$s/pick/squash/" $1; else vim $1; fi }; f' git rebase -i foo~5 foo
Перевод: предоставьте новый "редактор" для git, который, если имя файла для редактирования git-rebase-todo
(интерактивная подсказка перебазирования) изменяет все, кроме первого "пика", на "сквош", а в противном случае порождает vim - так что, когда вам будет предложено отредактировать сжатое сообщение о коммите, вы получите vim. (И, очевидно, я давил последние пять коммитов на ветке foo, но вы можете изменить это так, как вам нравится.)
Я бы, наверное, сделал то, что предложил Марк Лонгэйр.
Самый простой способ сделать это — использовать GitHub Desktop. Просто выберите все коммиты в вашей истории, щелкните правой кнопкой мыши и выберите «Squash x commits»:
Простой однострочный, который всегда работает, учитывая, что вы в данный момент находитесь в ветви, которую хотите сжать, master - это ветвь, из которой он возник, а последний коммит содержит сообщение о коммите и автора, которого вы хотите использовать:
git reset --soft $(git merge-base HEAD master) && git commit --reuse-message=HEAD@{1}
⚠️ ВНИМАНИЕ: "Мои последние X коммиты" могут быть неоднозначными.
(MASTER)
Fleetwood Mac Fritz
║ ║
Add Danny Lindsey Stevie
Kirwan Buckingham Nicks
║ ╚═══╦══════╝
Add Christine ║
Perfect Buckingham
║ Nicks
LA1974══════════╝
║
║
Bill <══════ YOU ARE EDITING HERE
Clinton (CHECKED OUT, CURRENT WORKING DIRECTORY)
В этой очень сокращенной истории хранилища https://github.com/fleetwood-mac вы открыли пулл-запрос для слияния коммита Билла Клинтона с оригиналом (MASTER
) Fleetwoodd Mac коммит.
Вы открыли пулл-запрос и на GitHub вы видите это:
Четыре коммитов:
- Добавить Дэнни Кирван
- Добавить Кристина Идеал
- LA1974
- Билл Клинтон
Думая, что никто не захочет читать всю историю хранилища. (Там на самом деле есть хранилище, нажмите на ссылку выше!) Вы решили уничтожить эти коммиты. Так ты иди и беги git reset --soft HEAD~4 && git commit
, Затем вы git push --force
это на GitHub, чтобы очистить ваш PR.
А что происходит? Вы только что сделали один коммит от Фрица до Билла Клинтона. Потому что вы забыли, что вчера вы работали над версией Бекингемского Ника. А также git log
не соответствует тому, что вы видите на GitHub.
МОРАЛЬ ИСТОРИИ
- Найдите нужные вам файлы и
git checkout
их - Найдите точный предыдущий коммит, который вы хотите сохранить в истории, и
git reset --soft
тот - Делать
git commit
который искажает непосредственно от к к
Если вас не интересуют сообщения о коммитах промежуточных коммитов, вы можете использовать
git reset --mixed <commit-hash-into-which-you-want-to-squash>
git commit -a --amend
Как с помощью Git объединить последние коммиты X в один?
git rebase -i HEAD~X
Будет показан следующий контент:
pick 1bffc15c My earlier commit
pick 474bf0c2 My recent commit
# ...
Для коммитов, которые вы хотите сжать, замените pick на fixup, чтобы он стал:
pick 1bffc15c My earlier commit
fixup 474bf0c2 My recent commit
# ...
Если он открыт в vim (интерфейс по умолчанию в терминале), нажмите Esc
на клавиатуре введите :wq
а также Enter
чтобы сохранить файл.
Проверить: Проверитьgit log