Сквош мой последний Х коммитирует вместе, используя Git

Как я могу сквош мой последний X коммитирует вместе в одну фиксацию с помощью Git?

Ответ 1

Используйте git rebase -i <after-this-commit> и замените "pick" на второй и последующие коммиты "squash" или "fixup", как описано в руководстве.

В этом примере <after-this-commit> представляет собой либо хэш SHA1, либо относительное местоположение из HEAD текущей ветки, из которой анализируются коммиты для команды rebase. Например, если пользователь хочет просмотреть 5 коммитов из текущего HEAD в прошлом, команда git rebase -i HEAD~5.

Ответ 2

Вы можете сделать это довольно легко без 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 [email protected]{1})"

Оба этих метода скворуют последние три коммита в один новый коммит таким же образом. Мягкий reset просто переводит HEAD в последнюю фиксацию, которую вы не хотите раздавить. Ни индекс, ни рабочее дерево не касаются мягкого reset, оставляя индекс в нужном состоянии для вашего нового коммита (т.е. Он уже имеет все изменения от коммитов, которые вы собираетесь "выбросить" ).

Ответ 3

Вы можете использовать git merge --squash для этого, что немного более элегантно, чем git rebase -i. Предположим, что вы на хозяине, и вы хотите выкачать последние 12 коммитов в один.

ПРЕДУПРЕЖДЕНИЕ. Сначала убедитесь, что вы выполняете проверку git reset --hard что git status чиста (поскольку git reset --hard будет отбрасывать ступенчатые и неустановленные изменения)

Затем:

# Reset the current branch to the commit just before the last 12:
git reset --hard HEAD~12

# [email protected]{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 [email protected]{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 предложенным Крисом Джонсеном в его ответе, заключается в том, что вы получаете сообщение о фиксации, предварительно заполненное каждым сообщением о коммитстве, которое вы раздавите.

Ответ 4

Я рекомендую избегать git reset, когда это возможно, особенно для Git -новей. Если вам действительно не нужно автоматизировать процесс, основанный на ряде коммитов, существует менее экзотический способ...

  • Положите компрометированные коммиты на рабочую ветвь (если они еще не установлены) - используйте gitk для этого
  • Проверьте целевую ветку (например, "мастер" )
  • git merge --squash (working branch name)
  • git commit

Сообщение о фиксации будет предварительно заполнено на основе сквоша.

Ответ 5

На основе ответ Криса Джонсена,

Добавьте глобальный псевдоним 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 [email protected]{1})"; };f'

... или с помощью командной строки Windows:

git config --global alias.squash "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse [email protected]{1})\"; };f"


Теперь ваш ~/.gitconfig должен содержать этот псевдоним:

[alias]
    squash = "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse [email protected]{1})\"; };f"


Использование:

git squash N

... который автоматически сквозит вместе, последний N совершает, включительно.

Примечание. Полученное сообщение фиксации представляет собой комбинацию всех раздавленных коммитов по порядку. Если вы недовольны этим, вы всегда можете git commit --amend изменить его вручную. (Или отредактируйте псевдоним, чтобы он соответствовал вашим вкусам.)

Ответ 6

Благодаря этому удобному сообщению в блоге я обнаружил, что вы можете использовать эту команду для раздачи последних трех коммитов:

git rebase -i HEAD~3

Это удобно, так как оно работает, даже если вы находитесь в местном филиале без информации отслеживания/удаленного репо.

Команда откроет интерактивный редактор переадресации, который затем позволит вам изменить порядок, сквош, слово и т.д. В соответствии с нормальным.


Использование интерактивного редактора переадресации:

В интерактивном редакторе сводки отображаются последние три фиксации. Это ограничение было определено HEAD~3 при запуске команды git rebase -i HEAD~3.

Последняя фиксация, HEAD, отображается сначала в строке 1. Строки, начинающиеся с # - это комментарии/документация.

Отображаемая документация довольно ясна. На любой заданной строке вы можете изменить команду из команды pick на команду по вашему выбору.

Я предпочитаю использовать команду fixup как это "сжимает" фиксацию в фиксации в строке выше и отбрасывает сообщение коммита.

Поскольку фиксация в строке 1 - HEAD, в большинстве случаев вы оставите это как pick. Вы не можете использовать squash или fixup как нет другой фиксации, чтобы раздавить фиксацию.

interactive rebase editor

Ответ 7

Если вы используете TortoiseGit, вы можете использовать функцию Combine to one commit:

  • Открыть контекстное меню TortoiseGit
  • Выберите Show Log
  • Отметьте соответствующие коммиты в представлении журнала
  • Выберите Combine to one commit из контекстного меню

Объединить коммиты

Эта функция автоматически выполняет все необходимые одиночные шаги git. К несчастью, доступно только для Windows.

Ответ 8

Основываясь на в этой статье, я нашел этот метод проще для моего использования.

Моя ветвь "dev" опередила "origin/dev" на 96 коммитов (поэтому эти коммиты еще не были нажаты на удаленный компьютер).

Я хотел пробить эти коммиты в один, прежде чем нажимать изменения. Я предпочитаю reset ветки до состояния "origin/dev" (это оставит все изменения из 96 коммитов неустановленными), а затем зафиксирует изменения сразу:

git reset origin/dev
git add --all
git commit -m 'my commit message'

Ответ 9

Для этого вы можете использовать следующую команду 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....

Подробнее см. Ссылка

Удачи!

Ответ 10

В ветке, в которой вы хотите объединить коммиты, запустите:

git rebase -i HEAD~(n number of commits back to review)

пример:

git rebase -i HEAD~1

Это откроет текстовый редактор, и вы должны переключить "pick" перед каждым коммитом с помощью "squash", если вы хотите, чтобы эти коммиты были объединены вместе. Из документации:

p, pick = использовать коммит

s, squash = использовать коммит, но слиться с предыдущим коммитом

Например, если вы хотите объединить все коммиты в один, "пикап" - это первый коммит, который вы сделали, и все последующие коммиты (расположенные ниже первого) должны быть установлены на "сквош". Если используется vim, используйте : x в режиме вставки для сохранения и выхода из редактора.

Затем, чтобы продолжить ребаз:

git rebase --continue

Подробнее об этом и других способах переписывания истории коммитов читайте в этом полезном посте.

Ответ 11

Ответ на аномии хорош, но я чувствовал себя неуверенно в этом, поэтому решил добавить пару скриншотов.

Шаг 0: git log

Посмотрите, где вы находитесь, с git log. Самое главное, найти хеш фиксации первого коммита, который вы не хотите сквош. Таким образом, только:

enter image description here

Шаг 1: git rebase

Выполнить git rebase -i [your hash], в моем случае:

$ git rebase -i 2d23ea524936e612fae1ac63c95b705db44d937d

Шаг 2: выберите/сквош, что вы хотите

В моем случае я хочу раздавить все на коммит, который был первым во времени. Заказ выполняется с первого до последнего, так что точно так же, как в git log. В моем случае я хочу:

enter image description here

Шаг 3: Отрегулируйте сообщение (и)

Если вы выбрали только одну фиксацию и раздавили остальное, вы можете настроить одно сообщение коммита:

enter image description here

Это. Как только вы сохраните этот (:wq), все готово. Посмотрите на это с git log.

Ответ 12

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 (Windows или Mac), то выше команды такие же, кроме редактора. Вы можете получить другой редактор.

Ответ 13

Если вы находитесь на удаленной ветке (называемой 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
    

Ответ 14

Что может быть действительно удобным:
Найдите хеш коммита, который вы хотите d43e15, например, d43e15.

Сейчас использую

git reset d43e15
git commit -am 'new commit name'

Ответ 15

Это супер-пупер kludgy, но каким-то классным способом, поэтому я просто брошу его в кольцо:

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, но вы можете изменить это, как вам нравится.)

Я бы, вероятно, сделал то, что Марк Лонгэр предложил.

Ответ 16

Чтобы раздавить последние 10 коммитов в один коммит:

git reset --soft HEAD~10 && git commit -m "squashed commit"

Если вы также хотите обновить удаленную ветку с помощью сжатого коммита:

git push -f

Ответ 17

Если вы хотите хлюпить каждую фиксацию в одном коммите (например, при первом выпуске проекта в первый раз), попробуйте:

git checkout --orphan <new-branch>
git commit

Ответ 18

Я думаю, что самый простой способ сделать это - сделать новую ветку от мастера и выполнить слияние --squash ветки функций.

git checkout master
git checkout -b feature_branch_squashed
git merge --squash feature_branch

Затем у вас есть все изменения, готовые к фиксации.

Ответ 19

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

Что я сделал, так это

  1. git reset --soft Head ~ 3 &&
  2. мерзавец совершить
  3. git push origin (branch_name) --force

Ответ 20

Простой однострочный, который всегда работает, учитывая, что вы в данный момент находитесь в ветки, которую хотите сжать, master - это ветвь, из которой он возник, а последний коммит содержит сообщение о коммите и автора, которого вы хотите использовать:

git reset --soft $(git merge-base HEAD master) && git commit [email protected]{1}

Ответ 21

⚠️ ВНИМАНИЕ: "Мои последние 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/band-history репозитория вы открыли запрос на извлечение для объединения в коммит Билла Клинтона с оригинальным (MASTER) коммитом Fleetwood Mac.

Вы открыли пулл-запрос и на GitHub вы видите это:

Четыре коммитов:

  • Добавить Дэнни Кирван
  • Добавить Кристина Идеал
  • LA1974
  • Билл Клинтон

Думая, что никто не захочет читать всю историю хранилища. (На самом деле есть хранилище, нажмите на ссылку выше!) Вы решаете раздавить эти коммиты. Итак, вы запускаете git reset --soft HEAD~4 && git commit. Затем вы git push --force на GitHub, чтобы очистить ваш PR.

А что происходит? Вы только что сделали один коммит от Фрица до Билла Клинтона. Потому что вы забыли, что вчера вы работали над версией Бекингемского Ника. И git log не соответствует тому, что вы видите на GitHub.

🐻 МОРАЛЬ ИСТОРИИ

  1. Найдите нужные вам файлы и git checkout их
  2. Найдите точный предыдущий коммит, который вы хотите сохранить в истории, и git reset --soft который
  3. Сделайте git commit который деформируется прямо от к

Ответ 22

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

git reset --mixed <commit-hash-into-which-you-want-to-squash>
git commit -a --amend

Ответ 23

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

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

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

Тогда последними фиксациями по времени являются H0, merge, 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, а затем накапливает фиксации по мере их применения).

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

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

P.S. Если вы просто сделаете несколько reset для BO: (например, используя reset --mixed, который более подробно объясняется здесь fooobar.com/questions/4636/...):

git reset --mixed hash_of_commit_B0
git add .
git commit -m 'some commit message'

то вы раздавите в B0 изменения H0, H1, H2 (потеря полностью фиксирует изменения после разветвления и перед слиянием.

Ответ 24

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

  1. многие локальные коммиты, смешанные с несколькими слияниями FROM master,
  2. наконец, толчок к дистанционному,
  3. PR и слияние TO мастер-рецензентом. (Да, разработчику было бы проще 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. Рецензент делает PR и объединяется для освоения.

Ответ 25

Я нахожу, что более общим решением является не указание "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 должны быть в порядке с этим.)

Ответ 26

git rebase -i HEAD^^

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

(в этом случае сквош две последние фиксации)

Ответ 27

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

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

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

Ответ 28

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

enter image description here

Ответ 29

Посмотрите на эту суть:

Gist - Easy git -squash

Вам нужно будет ввести, например. git-squash 3 и что он. Последние три коммита объединяются в один с конкатенированными сообщениями.

Ответ 30

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

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

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

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