Как я сквошу два не последовательных фиксации?

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

A -> B -> C -> D

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

Ответ 1

Вы можете запустить 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 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, вы также можете использовать ключевое слово "fixup".

Ответ 2

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

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 message is:

commit_message_for_D

# This is the 2nd commit message:

commit_message_for_A

Введите i

Измените текст на то, что вы хотите, чтобы новое сообщение фиксации выглядело. Я рекомендую это описание изменений в commit 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)

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

Ответ 3

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

Убедитесь, что вы еще не нажали на фиксации.

  • Репозиторий > Интерактивная ребаза...
  • Перетащите D (новый фиксатор) непосредственно над A (старший коммит)
  • Убедитесь, что выделена команда D.
  • Нажмите Squash with previous

Ответ 4

Интерактивная перебазировка работает хорошо, пока у вас не появится большая ветка функций с 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 + исправление конфликтов. И после этого я получил четкий пиар с одним коммитом.

PS вот скрипт bash для выполнения этих шагов в автоматическом режиме.

Ответ 5

$git мастер проверки

$git log --oneline

D
C
B
A

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

$git log --oneline

D
A