Как мне раздавить два непоследовательных коммита? - PullRequest
146 голосов
/ 13 октября 2010

Я немного новичок во всей функции перебазировки в git.Допустим, я сделал следующие коммиты:

A -> B -> C -> D

Впоследствии я понимаю, что D содержит исправление, которое зависит от нового кода, добавленного в A, и что эти коммиты принадлежат друг другу.Как мне сдавить A & D вместе и оставить B & C в покое?

Ответы [ 5 ]

194 голосов
/ 13 октября 2010

Вы можете запустить git rebase --interactive и изменить порядок D до B и вставить D в A.

Git откроет редактор, и вы увидите такой файл:

pick aaaaaaa Commit A
pick bbbbbbb Commit B
pick ccccccc Commit C
pick ddddddd Commit D

# Rebase aaaaaaa..ddddddd onto 1234567 (4 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

Теперьвы изменяете файл так, как он выглядит:

pick aaaaaaa Commit A
squash ddddddd Commit D
pick bbbbbbb Commit B
pick ccccccc Commit C

И теперь git объединяет изменения A и D в один коммит, а затем помещает B и C.Если вы не хотите сохранять сообщение фиксации D, вы также можете использовать ключевое слово «fix».

41 голосов
/ 21 июня 2013

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

git log --oneline -4

D commit_message_for_D
C commit_message_for_C
B commit_message_for_B
A commit_message_for_A

git rebase --interactive

pick D commit_message_for_D
pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A

Тип i (Переведите VIM в режим вставки)

Измените список таким образом (Выне нужно удалять или включать сообщение фиксации). Не пишите с ошибками squash! :

pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A
squash D

Тип Esc , затем ZZ (Сохранить и выйти из VIM)

# This is a combination of 2 commits.
# The first commit's message is:

commit_message_for_D

# This is the 2nd commit message:

commit_message_for_A

Введите i

Измените текст так, как вы хотите, чтобы выглядело новое сообщение о коммите.Я рекомендую это описание изменений в коммите A и D:

new_commit_message_for_A_and_D

Тип Esc затем ZZ

git log --oneline -4

E new_commit_message_for_A_and_D
C commit_message_for_C
B commit_message_for_B

git show E

(You should see a diff showing a combination of changes from A and D)

Вы создали новый коммит E.Коммиты A и D больше не в вашей истории, но не исчезли.Вы все еще можете восстановить их в этот момент и некоторое время на git rebase --hard D (git rebase --hard уничтожит все локальные изменения! ).

3 голосов
/ 15 апреля 2016

Для тех, кто использует SourceTree :

Убедитесь, что вы еще не отправили коммиты.

  1. Репозиторий> Интерактивная перебазировка ...
  2. Перетащите D (новый коммит) так, чтобы он находился непосредственно над A (более старый коммит)
  3. Убедитесь, что коммит D выделен
  4. Нажмите Squash with previous
1 голос
/ 10 октября 2018

Интерактивная перебазировка работает хорошо, пока у вас не появится большая ветка функций с 20-30 коммитами и / или парой слияний от мастера или / и исправления конфликтов, пока вы коммитили в своей ветке. Даже с поиском моих коммитов по истории и заменой pick на squash здесь не работает. Так что я искал другой путь и нашел эту статью . Я сделал свои изменения, чтобы поработать над этим в отдельной ветке:

git checkout master
git fetch
git pull
git merge branch-name
git reset origin/master
git branch -D branch-name
git checkout -b branch-name
git add --all
#Do some commit
git push -f --set-upstream origin branch-name

До этого я получил свой запрос на получение с ~ 30 коммитами с 2-3 слияниями от master + исправление конфликтов. И после этого я получил четкий пиар с одним коммитом.

P.S. здесь bash script для выполнения этих действий в автоматическом режиме.

0 голосов
/ 13 октября 2010

$ git checkout master

$ git log --oneline

D
C
B
A

$ git rebase --onto HEAD ^^^ HEAD ^

$ git log --oneline

D
A
...