Сквош мой последний X коммитов вместе с помощью Git - PullRequest
3036 голосов
/ 04 марта 2011

Как мне сжать мои последние X коммитов в один коммит с помощью Git?

Ответы [ 31 ]

7 голосов
/ 16 мая 2019

если, например, вы хотите раздавить последние 3 коммита в один коммит в ветке (удаленный репозиторий), например: https://bitbucket.org

То, что я сделал, это

  1. git reset --soft Head ~ 3 &&
  2. git commit
  3. git push origin (branch_name) --force
5 голосов
/ 20 июня 2018

Как насчет ответа на вопрос, связанный с таким рабочим процессом?

  1. много локальных коммитов, , смешанных с несколькими слияниями с мастера ,
  2. наконец, толчок к пульту,
  3. PR и объединение с мастером рецензентом . (Да, разработчику было бы проще merge --squash после PR, но команда решила, что это замедлит процесс.)

Я не видел такой рабочий процесс на этой странице. (Это могут быть мои глаза.) Если я правильно понимаю rebase, для нескольких слияний потребуется разрешение нескольких конфликтов . Я НЕ хочу даже думать об этом!

Так что, похоже, это работает для нас.

  1. git pull master
  2. git checkout -b new-branch
  3. git checkout -b new-branch-temp
  4. редактировать и фиксировать много локально, регулярно объединять мастер
  5. git checkout new-branch
  6. git merge --squash new-branch-temp // помещает все изменения в стадию
  7. git commit 'one message to rule them all'
  8. git push
  9. Рецензент делает пиар и сливается с мастером.
5 голосов
/ 25 мая 2017

В вопросе может быть неоднозначно, что подразумевается под «последним».

например git log --graph выводит следующее (упрощенно):

* commit H0
|
* merge
|\
| * commit B0
| |
| * commit B1
| | 
* | commit H1
| |
* | commit H2
|/
|

Тогда последними коммитами по времени являются H0, слияние, B0. Чтобы раздавить их, вам придется перебазировать вашу объединенную ветвь при коммите H1.

Проблема в том, что H0 содержит H1 и H2 (и, как правило, больше коммитов до слияния и после ветвления), а B0 - нет. Таким образом, вы должны управлять изменениями, начиная с H0, слияния, H1, H2, B0 как минимум.

Можно использовать rebase, но иначе, чем в других упомянутых ответах:

rebase -i HEAD~2

Это покажет вам варианты выбора (как упоминалось в других ответах):

pick B1
pick B0
pick H0

Поместите сквош вместо пика в H0:

pick B1
pick B0
s H0

После сохранения и выхода rebase будет применять коммиты по очереди после H1. Это означает, что он попросит вас снова разрешить конфликты (где HEAD будет сначала H1, а затем будет накапливать коммиты по мере их применения).

После завершения ребазирования вы можете выбрать сообщение для сдавленных H0 и B0:

* commit squashed H0 and B0
|
* commit B1
| 
* commit H1
|
* commit H2
|

P.S. Если вы просто выполните сброс в BO: (например, используя 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 (потеря полностью фиксирует изменения после ветвления и до слияния.

4 голосов
/ 19 февраля 2018
git rebase -i HEAD^^

, где число ^ равно X

(в этом случае раздавите два последних коммита)

4 голосов
/ 04 ноября 2014

Я считаю, что более общим решением является не указание N коммитов, а ответвление / идентификатор фиксации, над которым вы хотите раздавить. Это менее подвержено ошибкам, чем подсчет коммитов до определенного коммита - просто укажите тег напрямую или, если вы действительно хотите посчитать, вы можете указать HEAD ~ N.

В моем рабочем процессе я запускаю ветвь, и мой первый коммит в этой ветке суммирует цель (то есть обычно это то, что я отправляю как «окончательное» сообщение для функции в общедоступный репозиторий). Поэтому, когда я Готово, все, что я хочу сделать, это git squash master вернуться к первому сообщению, а затем я готов нажать.

Я использую псевдоним:

squash = !EDITOR="\"_() { sed -n 's/^pick //p' \"\\$1\"; sed -i .tmp '2,\\$s/^pick/f/' \"\\$1\"; }; _\"" git rebase -i

Это приведет к сбросу истории, сжатой до того, как это произойдет, - это даст вам шанс восстановиться путем извлечения старого идентификатора коммита с консоли, если вы хотите вернуться. (Пользователи Solaris отмечают, что он использует опцию GNU sed -i, пользователи Mac и Linux должны с этим справиться.)

4 голосов
/ 09 марта 2018

В дополнение к другим отличным ответам, я хотел бы добавить, что git rebase -i всегда путает меня с порядком коммитов - от старого к новому или наоборот? Так что это мой рабочий процесс:

  1. git rebase -i HEAD~[N], где N - количество коммитов, к которым я хочу присоединиться, начиная с самого последнего . Так что git rebase -i HEAD~5 будет означать "раздавить последние 5 коммитов в новый";
  2. появится редактор, показывающий список коммитов, которые я хочу объединить. Теперь они отображаются в обратном порядке : более старый коммит находится сверху. Пометить как "squash" или "s" все коммиты , кроме первого / более старого : он будет использоваться в качестве отправной точки. Сохраните и закройте редактор;
  3. редактор снова появляется с сообщением по умолчанию для нового коммита: измените его по своему усмотрению, сохраните и закройте. Сквош завершен!

Источники и дополнительные материалы: # 1 , # 2 .

2 голосов
/ 08 июля 2019

Если вам не нужны сообщения о коммитах промежуточных коммитов, вы можете использовать

git reset --mixed <commit-hash-into-which-you-want-to-squash>
git commit -a --amend
2 голосов
/ 12 марта 2019

Если вы работаете с GitLab, вы можете просто щелкнуть опцию Squash в запросе на слияние, как показано ниже.Сообщение о фиксации будет заголовком запроса на слияние.

enter image description here

2 голосов
/ 29 августа 2018

Сначала я узнаю количество коммитов между моей ветвью функций и текущей основной ветвью по

git checkout master
git rev-list master.. --count

Затем я создаю другую ветку на основе моей ветки функций, оставив ветвь 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

Надеюсь, это поможет, спасибо.

1 голос
/ 19 февраля 2016

Если вы используете GitUp , выберите коммит, который вы хотите объединить с его родителем, и нажмите S . Вы должны сделать это один раз для каждого коммита, но это гораздо проще, чем придумать правильное заклинание командной строки. Особенно если это то, что вы делаете только время от времени.

...