Как разбить последний коммит на два в Git

У меня есть две рабочие ветки, мастер и форум, и я только что внесли некоторые изменения в ветку forum, что мне бы хотелось to cherry-pick в master. Но, к сожалению, фиксация, которую я хочу использовать для вишни, также содержит некоторые изменения, которые мне не нужны.

Решение, вероятно, состояло бы в том, чтобы каким-то образом удалить неправильную фиксацию и заменить ее двумя отдельными коммитами, с изменениями, которые я хочу выбрать в master, и другими, которые там не принадлежат.

Я пробовал делать

git reset --hard HEAD^

который удалил все изменения, поэтому мне пришлось вернуться с помощью

git reset ORIG_HEAD

Итак, мой вопрос: как лучше всего разделить последнее коммит на два отдельных коммита?

Ответ 1

Вы должны использовать индекс. После выполнения смешанного reset ( " git reset HEAD ^" ) добавьте первый набор изменений в индекс, а затем зафиксировать их. Затем зафиксируйте остальное.

Вы можете использовать git добавить", чтобы внести все изменения, сделанные в файл в индекс. если ты не хотят ставить каждую модификацию, сделанную в файле, только некоторые из них, вы может использовать "git add -p" .

Посмотрим на пример. Предположим, что у меня есть файл с именем myfile, который содержит следующий текст:

something
something else
something again

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

1
something
something else
something again
2

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

Сначала я возвращаюсь к родительскому элементу HEAD, но я хочу сохранить изменения в файловой системе, поэтому я использую "git reset" без аргумента (который будет делать так называемый "смешанный" ) reset):

$ git reset HEAD^
myfile: locally modified
$ cat myfile
1
something
something else
something again
2

Теперь я использую "git add -p" , чтобы добавить изменения, которые я хочу зафиксировать для индекса (= I этап их). "git add -p" - это интерактивный инструмент, который спрашивает вас о том, что изменения в файл должны быть добавлены в индекс.

$ git add -p myfile
diff --git a/myfile b/myfile
index 93db4cb..2f113ce 100644
--- a/myfile
+++ b/myfile
@@ -1,3 +1,5 @@
+1
 something
 something else
 something again
+2
Stage this hunk [y,n,a,d,/,s,e,?]? s    # split this section into two!
Split into 2 hunks.
@@ -1,3 +1,4 @@
+1
 something
 something else
 something again
Stage this hunk [y,n,a,d,/,j,J,g,e,?]? y  # yes, I want to stage this
@@ -1,3 +2,4 @@
 something
 something else
 something again
+2
Stage this hunk [y,n,a,d,/,K,g,e,?]? n   # no, I don't want to stage this

Затем я фиксирую это первое изменение:

$ git commit -m "Added first line"
[master cef3d4e] Added first line
 1 files changed, 1 insertions(+), 0 deletions(-)

Теперь я могу выполнить все остальные изменения (а именно цифру "2", помещенную в последнюю строку):

$ git commit -am "Added last line"
[master 5e284e6] Added last line
 1 files changed, 1 insertions(+), 0 deletions(-)

Позвольте проверить журнал, чтобы узнать, что у нас есть:

$ git log -p -n2 | cat
Commit 5e284e652f5e05a47ad8883d9f59ed9817be59d8
Author: ...
Date: ...

    Added last line

Diff --git a/myfile b/myfile
Index f9e1a67..2f113ce 100644
--- a/myfile
+++ b/myfile
@@ -2,3 +2,4 @@
 something
 something else
 something again
+2

Commit cef3d4e0298dd5d279a911440bb72d39410e7898
Author: ...
Date: ...

    Added first line

Diff --git a/myfile b/myfile
Index 93db4cb..f9e1a67 100644
--- a/myfile
+++ b/myfile
@@ -1,3 +1,4 @@
+1
 something
 something else
 something again

Ответ 2

Цели:

  • Я хочу разделить прошлое commit (splitme) на два.
  • Я хочу сохранить сообщение фиксации.

План:

  • перезагрузите интерактивный интерфейс от одного до splitme.
  • изменить splitme.
  • Reset файлы для разделения на вторую фиксацию.
  • Изменить фиксацию, сохранить сообщение, при необходимости изменить.
  • Добавить обратно файлы, разделенные с первого коммита.
  • Зафиксировать новое сообщение.
  • Продолжить перезагрузку.

Шаги восстановления (1 и 7) могут быть пропущены, если splitme является последним фиксатором.

git rebase -i splitme^
# mark splitme commit with 'e'
git reset HEAD^ -- $files
git commit --amend
git add $files
git commit -m "commit with just some files"
git rebase --continue

Если бы я хотел, чтобы сплит файлы были первыми записаны, я бы снова перезаписал -i и переключил порядок

git rebase -i splitme^
# swap order of splitme and 'just some files'

Ответ 3

Чтобы изменить текущую фиксацию на две коммиты, вы можете сделать что-то вроде следующего.

Или:

git reset --soft HEAD^

Это отменяет последнее коммит, но оставляет все поставленным. Затем вы можете отключить определенные файлы:

git reset -- file.file

По желанию вы можете отремонтировать части этих файлов:

git add -p file.file

Сделайте новый первый фиксатор:

git commit

Сцена и фиксация остальных изменений во второй фиксации:

git commit -a

Или:

Отменить и отключить все изменения от последнего фиксации:

git reset HEAD^

Выборочно выполните первый раунд изменений:

git add -p

Commit:

git commit

Завершите остальные изменения:

git commit -a

(В любом случае, если вы отменили фиксацию, которая добавила новый файл и хотите добавить это ко второй фиксации, вам придется вручную добавить ее как commit -a только этапы изменения уже отслеженных файлов.)

Ответ 4

Запустите git gui, выберите переключатель "Изменить последнюю фиксацию" и измените нестационарность (Commit > Unstage From Commit или Ctrl - U), которые вы не хотите вступать в первую фиксацию. Я думаю, что это самый простой способ сделать это.

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

Ответ 5

git reset HEAD^

the -hard - это то, что убивает ваши изменения.

Ответ 6

Я удивлен, что никто не предложил git cherry-pick -n forum. Это приведет к изменениям от последней forum фиксации, но не приведет к их фиксации - вы можете reset отменить изменения, которые вам не нужны, и зафиксировать то, что вы хотите сохранить.

Ответ 7

Метод double-revert-squash

  • Сделайте еще одну фиксацию, которая удалит ненужные изменения. (Если это файл, это очень просто: git checkout HEAD~1 -- files with unwanted changes и git commit. Если нет, файлы со смешанными изменениями могут быть частично поставлены git reset file и git add -p file в качестве промежуточного шага.) Назовите это возвратом.
  • git revert HEAD - Сделайте еще одну фиксацию, которая добавит лишние изменения. Это двойной возврат
  • Из двух коммитов, которые вы сейчас сделали, сквойте первый на фиксацию для разделения (git rebase -i HEAD~3). Эта фиксация теперь освобождается от нежелательных изменений, поскольку они находятся во второй фиксации.

Преимущества

  • Сохраняет сообщение о фиксации
  • Работает, даже если фиксация для разделения не является последней. Это требует только того, чтобы нежелательные изменения не конфликтуют с последующими коммитами