Сквош мой последний X совершает вместе с помощью Git
Как я могу раздавить мои последние X коммиты вместе в один коммит с помощью Git?
29 ответов:
использовать
git rebase -i <after-this-commit>
и замените "pick "на втором и последующих коммитах на" squash "или" fixup", как описано в руководство.В этом примере
<after-this-commit>
является либо хэшем SHA1, либо относительным местоположением от головы текущей ветви, из которой коммиты анализируются для команды rebase. Например, если пользователь хочет просмотреть 5 коммитов из текущей головы в прошлом, командаgit rebase -i HEAD~5
.
вы можете сделать это довольно легко, без
git rebase
илиgit merge --squash
. В этом примере мы раздавим последние 3 коммита.если вы хотите написать новое сообщение с нуля, этого достаточно:
git reset --soft HEAD~3 && git commit
если вы хотите начать редактирование нового сообщения фиксации с конкатенацией существующих сообщений фиксации (т. е. аналогично тому, что pick/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})"
оба этих метода сжимают последние три коммита в один новый коммит таким же образом. Мягкий сброс просто повторно указывает на последний фиксатор, который вы не хотите раздавить. Ни индекс, ни рабочее дерево не затрагиваются мягким сбросом, оставляя индекс в желаемом состоянии для вашего нового коммита (т. е. у него уже есть все изменения от коммитов, которые вы собираетесь "выбросить").
можно использовать
git merge --squash
для этого, что немного более элегантно, чемgit rebase -i
. Предположим, вы находитесь на master, и вы хотите раздавить последние 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
The документация
git merge
описание в более деталь.
обновление: единственное реальное преимущество этого метода перед более простым
git reset --soft HEAD~12 && git commit
предложил Крис Джонсен в ответ это то, что вы получаете сообщение фиксации, предварительно заполненное каждым сообщением фиксации, которое вы сжимаете.
Я рекомендую избегать
git reset
когда это возможно-особенно для Git-для новичков. Если вам действительно не нужно автоматизировать процесс на основе конечно, есть и менее экзотический способ...
- поставить должно быть сжато фиксации на рабочей ветви (если они еще не являются таковыми) - использование гифок для этого
- Проверьте целевую ветвь (например, 'master')
git merge --squash (working branch name)
git commit
сообщение фиксации будет предварительно заселенный на основе сквоша.
на основе ответ Криса Джонсена,
добавить глобальный псевдоним "сквош" из bash: (или Git Bash на Windows)
git config --global alias.squash '!f(){ git reset --soft HEAD~ && git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"; };f'
... или с помощью командной строки Windows:
git config --global alias.squash "!f(){ git reset --soft HEAD~ && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"
Ваш~/.gitconfig
теперь должен содержать этот псевдоним:[alias] squash = "!f(){ git reset --soft HEAD~ && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"
Использование:git squash N
... Который автоматически сжимает вместе последний
N
совершает включительно.Примечание: результирующее сообщение фиксации комбинация всех раздавленных коммитов, по порядку. Если вы недовольны этим, вы всегда можете
git commit --amend
изменить его вручную. (Или измените псевдоним в соответствии со своими вкусами.)
спасибо это удобный пост в блоге я обнаружил, что вы можете использовать эту команду, чтобы раздавить последние 3 совершает:
git rebase -i HEAD~3
это удобно, как это работает, даже если вы находитесь на локальном филиале без отслеживания информации/удаленного РЕПО.
команда откроет интерактивный редактор rebase, который затем позволяет вам переупорядочить, сквош, перефразировать и т. д. В обычном режиме.
использование интерактивной перебазирования редактор:
интерактивный редактор rebase показывает последние три коммита. Это ограничение было определено с помощью
HEAD~3
при выполнении командыgit rebase -i HEAD~3
.самый последний коммит,
HEAD
, отображается сначала в строке 1. Строки, начинающиеся с#
комментарии / документация.документация отображается довольно ясно. В любой заданной строке вы можете изменить команду с
pick
команды по вашему выбору.I предпочитаю использовать команду
fixup
поскольку это "сжимает" изменения фиксации в фиксации в строке выше и отбрасывает сообщение фиксации.как фиксация в строке 1
HEAD
в большинстве случаев вы бы оставить это какpick
. Вы не можете использоватьsquash
илиfixup
поскольку нет другого коммита, чтобы раздавить коммит.
Если вы используете TortoiseGit, вы можете использовать функцию
Combine to one commit
:
- откройте контекстное меню TortoiseGit
- выберите
Show Log
- отметьте соответствующие изменения в журнале
- выберите
Combine to one commit
в контекстном менюэта функция автоматически выполняет все необходимые действия один мерзавец. К сожалению, доступно только для Windows.
на основе в этой статье Я нашел этот метод проще для моего usecase.
моя ветвь " dev "опережала" origin/dev " на 96 коммитов (так что эти коммиты еще не были перенесены на пульт).
Я хотел раздавить эти коммиты в один, прежде чем нажимать на изменение. Я предпочитаю сбросить ветку в состояние "origin/dev" (это оставит все изменения из 96 коммитов нестагированными), а затем зафиксировать изменения сразу:
git reset origin/dev git add --all git commit -m 'my commit message'
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
), то выше команды такие же, кроме редактора. Вы можете получить другой редактор.
для этого вы можете использовать следующую команду 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....
для получения дополнительной информации нажмите на ссылке
удачи!!
если вы находитесь в удаленной ветке(называется
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
аномии отвечают - это хорошо, но я чувствовала себя неуверенно об этом, поэтому я решил добавить пару скриншотов.
Шаг 0: git log
смотрите, где вы находитесь с
git log
. Самое главное, найти хэш коммита первого коммита вы не хочу раздавить. Так что только то:Шаг 1: git rebase
выполнить
git rebase -i [your hash]
в моей дело:$ git rebase -i 2d23ea524936e612fae1ac63c95b705db44d937d
Шаг 2: Выберите / сквош, что вы хотите
в моем случае, я хочу раздавить все на фиксации, которая была первой во времени. На заказ от первого до последнего, так как в
git log
. В моем случае, я хочу:Шаг 3: отрегулируйте сообщения
если вы выбрали только один коммит и раздавили остальные, вы можете настроить один коммит сообщение:
вот и все. После того как вы сохраните (
:wq
), ты молодец. Взгляните на него сgit log
.
это супер-пупер kludgy, но в какой-то крутой способ, поэтому я просто брошу его в кольцо:
GIT_EDITOR='f() { if [ "$(basename )" = "git-rebase-todo" ]; then sed -i "2,$s/pick/squash/" ; else vim ; fi }; f' git rebase -i foo~5 foo
перевод: предоставьте новый "редактор" для git, который, если имя файла для редактирования
git-rebase-todo
(интерактивное приглашение rebase) изменяет все, кроме первого "выбора", на "сквош", а в противном случае порождает vim - так что, когда вам будет предложено отредактировать раздавленное сообщение фиксации, вы получите vim. (И, очевидно, я раздавил последние пять коммитов на ветке foo, но вы можете это изменить как вам будет угодно.)Я бы, наверное, сделал что предложил Марк Лонгэр, хотя.
Если вы хотите хлюпать каждый commit в один commit (например, при выпуске проекта публично в первый раз), попробуйте:
git checkout --orphan <new-branch> git commit
что может быть очень удобно: Найдите хэш фиксации, который вы хотите раздавить сверху; скажите, что это
d43e15
Теперь используйте
git reset d43e15
git commit -am 'new commit name'
Я думаю, что самый простой способ сделать это-сделать новую ветвь от master и сделать слияние --сквош ветви функции.
git checkout master git checkout -b feature_branch_squashed git merge --squash feature_branch
тогда у вас есть все изменения готовы совершить.
Я нахожу более общее решение не указывать' N ' коммитов, а скорее ветвь/commit-id, который вы хотите раздавить поверх. Это менее подвержено ошибкам, чем подсчет коммитов до определенного коммита-просто укажите тег напрямую, или если вы действительно хотите подсчитать, вы можете указать HEAD~N.
в моем рабочем процессе я запускаю ветку, и моя первая фиксация на этой ветке суммирует цель (т. е. обычно это то, что я буду нажимать как "окончательное" сообщение для функции для общественности хранилище.) Поэтому, когда я закончу, все, что я хочу сделать, это
git squash master
вернуться к первому сообщению, а затем я готов нажать.Я использую псевдоним:
squash = !EDITOR="\"_() { sed -n 's/^pick //p' \"\\"; sed -i .tmp '2,\$s/^pick/f/' \"\\"; }; _\"" git rebase -i
это сбросит историю, которая будет раздавлена, прежде чем она это сделает-это дает вам возможность восстановить, захватив старый идентификатор фиксации с консоли, если вы хотите вернуться. (Пользователи Solaris отмечают, что он использует GNU sed
-i
опция, пользователи Mac и Linux должны быть в порядке с этим.)
в вопросе может быть неоднозначно, что подразумевается под "последним".
git log --graph
выводит следующие (упрощенный):* commit H0 | * merge |\ | * commit B0 | | | * commit B1 | | * | commit H1 | | * | commit H2 |/ |
тогда последние коммиты по времени являются H0, merge, B0. Чтобы раздавить их, вам придется перебазировать объединенную ветку на фиксацию H1.
проблема в том, что содержится н0 Н1 и Н2 (и, как правило, более совершает до слияния и после разветвления), а В0-нет. Так что вы должны управлять изменениями от х0, слияния, Н1, Н2, В0 в наименьший.
можно использовать rebase, но по-разному, а затем в других упомянутых ответах:
rebase -i HEAD~2
это покажет вам варианты выбора (как уже упоминалось в других ответов):
pick B1 pick B0 pick H0
поставить сквош вместо того, чтобы выбрать для н0:
pick B1 pick B0 s H0
после сохранения и выхода rebase будет применять коммиты по очереди после H1. Это означает, что он попросит вас снова разрешить конфликты (где HEAD сначала будет H1, а затем накапливает коммиты как они применяются).
после завершения перебазирования вы можете выбрать сообщение для squashed H0 и B0:
* commit squashed H0 and B0 | * commit B1 | * commit H1 | * commit H2 |
P. S. Если вы просто сделать некоторые сброса БО: (например, с помощью
reset --mixed
это объясняется более подробно здесь https://stackoverflow.com/a/18690845/2405850):git reset --mixed hash_of_commit_B0 git add . git commit -m 'some commit message'
затем вы сквош в B0 изменения H0, H1, H2 (потеря полностью фиксирует изменения после ветвления и перед слиянием.
взгляните на эту суть:
вам нужно будет ввести, например,
git-squash 3
и это все. Последние три коммита слились в один, а их сообщения были объединены.
В дополнение к другим отличным ответам, я хотел бы добавить, как
git rebase -i
всегда путает меня с порядком фиксации-от старого к новому или наоборот? Так что это мой рабочий процесс:
git rebase -i HEAD~[N]
, где N-количество коммитов, к которым я хочу присоединиться,начиная с последней. Так чтоgit rebase -i HEAD~5
будет означать "сквош последние 5 коммитов в новый";- редактор всплывает, показывая список коммитов, которые я хочу объединить. Теперь они отображаются в обратный порядок: более старая фиксация находится сверху. Отметьте как "сквош" или " s " все коммиты там кроме первого/старшего: он будет использоваться в качестве отправной точки. Сохраните и закройте редактор;
- редактор снова появляется с сообщением по умолчанию для новой фиксации: измените его на свои потребности, сохраните и закройте. Сквош завершен!
чтобы раздавить последние 10 коммитов в один коммит:
git reset --soft HEAD~10 && git commit -m "squashed commit"
Если вы также хотите обновить удаленную ветку с помощью squashed commit:
git push -f
в ветке, в которой вы хотите объединить коммиты, запустите:
git rebase -i HEAD~(n number of commits back to review)
это откроет текстовый редактор, и вы должны переключить "pick" перед каждой фиксацией с помощью "squash", если вы хотите, чтобы эти фиксации были объединены вместе. Например, если вы хотите объединить все коммиты в один, "pick" - это первый коммит, который вы сделали, и все будущие (помещенные ниже первого) должны быть установлены в "squash". При использовании vim используйте : x в режиме вставки для сохранения и выйдите из редактора.
затем, чтобы закончить перебазирование:
git rebase --continue
для получения дополнительной информации об этом и других способах переписать историю фиксации см. этот полезный пост
как насчет ответа на вопрос, связанный с такой документооборот?
- многие локальные коммиты, смешивается с несколькими слияниями из master,
- наконец толчок к удаленному,
- PR и слияние в master Юра. (Да, было бы проще для разработчика
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
- рецензент делает PR и сливается с мастером.
Если вы используете GitUp, выберите фиксацию, которую вы хотите объединить с ее родителем, и нажмите S. Вы должны сделать это один раз для каждого коммита, но это гораздо проще, чем придумать правильное заклинание командной строки. Особенно если это то, что вы делаете только один раз в то время.
просто добавьте эту функцию bash в свой bash .файл zshrc.
# Squash last X commits with a Commit message. # Usage: squash X 'COMMIT_MSG' # where X= Number of last commits. # where COMMIT_MSG= New commit msg. function squash() { if [ -z "" -o -z "" ]; then echo "Usage: \`squash X COMMIT_MSG\`" echo "X= Number of last commits." echo "COMMIT_MSG= New commit msg." return 1 fi git reset --soft HEAD~"" git add . && git ci -m "" # With 100 emoji git push --force }
тогда просто беги
squash X 'New Commit Message'
и вы сделали.
другой способ сделать это, если у вас есть тонна коммитов, - это сделать сквош после фиксации, например
git rebase -i <hashbeforeyouwanttosquash>
это откроет ваш редактор, чтобы выбрать / сквош, как обычно.
сначала я узнаю количество коммитов между моей ветвью функции и текущей главной ветвью по
git checkout master git rev-list master.. --count
затем я создаю другую ветвь на основе ветви my-feature, keep
my-feature
филиала нетронутой.наконец, я бегу
git checkout my-feature git checkout -b my-rebased-feature git checkout master git checkout my-rebased-feature git rebase master git rebase head^x -i // fixup/pick/rewrite git push origin my-rebased-feature -f // force, if my-rebased-feature was ever pushed, otherwise no need for -f flag // make a PR with clean history, delete both my-feature and my-rebased-feature after merge
надеюсь, что это помогает, спасибо.
переключитесь на главную ветку и убедитесь, что вы в курсе:
sh git checkout master && git fetch && git pull
объединить вашу ветку в ветку master на месте:
sh git merge feature_branch
сброс локальной главной ветви в исходное состояние:
sh git reset origin/master
теперь все ваши изменения считаются проиндексированы изменилось. Вы можете совершить их в один или несколько коммитов.
sh git add . --all git commit