Разбить предыдущую фиксацию на несколько фиксаций

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

11 ответов


git rebase -i сделаю это.

во-первых, начните с чистого рабочего каталога:git status не ожидающих изменений, удалений или добавлений.

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

$ git reset HEAD~

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

если он был дальше в дереве, то

$ git rebase -i HEAD~3

здесь 3 сколько совершает это назад.

если он был дальше в дереве, Чем вы хотите посчитать, то

$ git rebase -i 123abcd~

здесь 123abcd является SHA1 фиксации, которую вы хотите разделить.

когда вы получите экран редактирования rebase, найдите фиксацию, которую вы хотите разбить. В начале этой строки замените pick С edit (e для краткости). Сохраните буфер и выйдите. Rebase теперь остановится сразу после фиксации, которую вы хотите отредактировать. Затем:

$ git reset HEAD~

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

$ git rebase --continue

С git-rebase руководство (раздел раздел коммитов)

в интерактивном режиме, вы можете отметить совершает действие "редактировать". Однако это не обязательно означает, что git rebase ожидает, что результат этого редактирования будет точно одним фиксацией. Действительно, Вы можете отменить фиксацию или добавить другие фиксации. Это можно использовать для разделения фиксации на две части:

  • запустить интерактивный перебазирования с git rebase -i <commit>^, где <commit> это commit вы хотите разделить. Фактически, любой диапазон фиксации будет делать, пока он содержит эту фиксацию.

  • отметьте фиксацию, которую вы хотите разделить, действием "редактировать".

  • когда дело доходит до редактирования, совершить, выполнить git reset HEAD^. Эффект заключается в том, что голова перематывается на единицу, и индекс следует примеру. Однако, рабочее дерево остается прежним.

  • теперь добавьте изменения в индекс, который вы хотите иметь в первое обязательство. Вы можете использовать git add (возможно, в интерактивном режиме) или git gui (или оба), чтобы сделать это.

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

  • повторите последние два шага, пока ваше рабочее дерево не будет чистым.

  • продолжить перебазирование с git rebase --continue.


использовать git rebase --interactive чтобы изменить эту предыдущую фиксацию, запустите git reset HEAD~, а потом git add -p чтобы добавить некоторые, затем сделайте фиксацию, затем добавьте еще и сделайте еще одну фиксацию столько раз, сколько захотите. Когда закончишь, беги!--10-->, и у вас будут все коммиты разделения ранее в вашем стеке.

важно: обратите внимание, что вы можете играть и делать все изменения, которые вы хотите, и не придется беспокоиться о потере старых изменений, потому что вы всегда можете запустить git reflog найти точку в вашем проекте, который содержит нужные вам изменения ,(назовем его a8c4ab), а затем git reset a8c4ab.

вот ряд команд, чтобы показать, как это работает:

mkdir git-test; cd git-test; git init

теперь добавьте файл A

vi A

добавьте следующую строку:

one

git commit -am one

затем добавьте эту строку в A:

two

git commit -am two

затем добавить этот строку:

three

git commit -am three

теперь файл A выглядит так:

one
two
three

и наш git log выглядит следующим образом (Ну, я использую git log --pretty=oneline --pretty="%h %cn %cr ---- %s"

bfb8e46 Rose Perrone 4 seconds ago ---- three
2b613bc Rose Perrone 14 seconds ago ---- two
9aac58f Rose Perrone 24 seconds ago ---- one

предположим, мы хотим разделить второй коммит,two.

git rebase --interactive HEAD~2

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

pick 2b613bc two
pick bfb8e46 three

изменить pick до e редактировать, что совершать.

git reset HEAD~

git diff показывает нам, что мы просто unstaged фиксацию, которую мы сделали для второго фиксации:

diff --git a/A b/A
index 5626abf..814f4a4 100644
--- a/A
+++ b/A
@@ -1 +1,2 @@
 one
+two

давайте сделаем это изменение и добавим "и третий" к этой строке в файле A.

git add .

это обычно точка в ходе интерактивной перебазирования, где мы будем работать git rebase --continue, потому что обычно мы просто хотим вернуться в наш стек обязуется изменить ранее совершал. Но в этот раз мы хотим создайте новую фиксацию. Так мы побежим git commit -am 'two and a third'. Теперь мы редактируем файл A и добавить строку two and two thirds.

git add . git commit -am 'two and two thirds' git rebase --continue

у нас есть конфликт с нашим commit,three, так давайте решим это:

мы изменим

one
<<<<<<< HEAD
two and a third
two and two thirds
=======
two
three
>>>>>>> bfb8e46... three

to

one
two and a third
two and two thirds
three

git add .; git rebase --continue

теперь наш!--42--> выглядит так:

commit e59ca35bae8360439823d66d459238779e5b4892
Author: Rose Perrone <roseperrone@fake.com>
Date:   Sun Jul 7 13:57:00 2013 -0700

    three

diff --git a/A b/A
index 5aef867..dd8fb63 100644
--- a/A
+++ b/A
@@ -1,3 +1,4 @@
 one
 two and a third
 two and two thirds
+three

commit 4a283ba9bf83ef664541b467acdd0bb4d770ab8e
Author: Rose Perrone <roseperrone@fake.com>
Date:   Sun Jul 7 14:07:07 2013 -0700

    two and two thirds

diff --git a/A b/A
index 575010a..5aef867 100644
--- a/A
+++ b/A
@@ -1,2 +1,3 @@
 one
 two and a third
+two and two thirds

commit 704d323ca1bc7c45ed8b1714d924adcdc83dfa44
Author: Rose Perrone <roseperrone@fake.com>
Date:   Sun Jul 7 14:06:40 2013 -0700

    two and a third

diff --git a/A b/A
index 5626abf..575010a 100644
--- a/A
+++ b/A
@@ -1 +1,2 @@
 one
+two and a third

commit 9aac58f3893488ec643fecab3c85f5a2f481586f
Author: Rose Perrone <roseperrone@fake.com>
Date:   Sun Jul 7 13:56:40 2013 -0700

    one

diff --git a/A b/A
new file mode 100644
index 0000000..5626abf
--- /dev/null
+++ b/A
@@ -0,0 +1 @@
+one

предыдущие ответы охватывали использование git rebase -i для редактирования фиксации, которую вы хотите разделить, и фиксации ее по частям.

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

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

  1. после использования git reset HEAD~, пройдите через патчи индивидуально, используя git add -p чтобы выбрать те, которые вы хотите в каждом commit

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

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

после использования rebase -i и editing фиксации, использовать

git reset --soft HEAD~

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

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

как только вы будете счастливы, этап / unstage файлы по мере необходимости (мне нравится использовать git gui для этого), и внести изменения через интерфейс или командную строку

git commit

это первое совершенное обязательство. Теперь вы хотите восстановить свою рабочую копию в состояние, которое она имела после фиксации, которую вы разделяете, чтобы вы можете принять больше изменений для следующего коммита. Чтобы найти sha1 коммита, который вы редактируете, используйте git status. В первых нескольких строках статуса вы увидите команду rebase, которая выполняется в настоящее время, в которой вы можете найти sha1 вашей исходной фиксации:

$ git status
interactive rebase in progress; onto be83b41
Last commands done (3 commands done):
   pick 4847406 US135756: add debugging to the file download code
   e 65dfb6a US135756: write data and download from remote
  (see more in file .git/rebase-merge/done)
...

в этом случае фиксация, которую я редактирую, имеет sha1 65dfb6a. Зная это, я могу проверить содержимое этой фиксации по моему рабочему каталогу, используя форму git checkout что требует как фиксации, так и расположение файла. Здесь я использую . в качестве местоположения файла для замены всей рабочей копии:

git checkout 65dfb6a .

не пропустите точку на конце!

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

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

если вы хотите повторно использовать исходное сообщение фиксации для одного или нескольких коммитов, вы можете использовать его прямо из рабочих файлов rebase:

git commit --file .git/rebase-merge/message

наконец, как только вы совершили все изменения,

git rebase --continue

продолжит и завершит операцию перебазирования.


git rebase --interactive можно использовать для разделения фиксации на меньшие фиксации. The git docs на rebase имеют краткое пошаговое руководство процесса-разделение коммитов:

в интерактивном режиме, вы можете отметить совершает действие "редактировать". Однако, это не обязательно означает, что git rebase ожидает, что результатом этого изменения будет ровно один коммит. Действительно, Вы можете отменить фиксацию или добавить другие фиксации. Это можно использовать для разделения фиксации на два:

  • запустить интерактивный перебазирования с git rebase -i <commit>^, где <commit> это фиксация, которую вы хотите разделить. Фактически, любой диапазон фиксации будет делать, пока он содержит эту фиксацию.

  • отметьте фиксацию, которую вы хотите разделить, действием "редактировать".

  • когда дело доходит до редактирования, совершить, выполнить git reset HEAD^. Эффект заключается в том, что голова перематывается на единицу, и индекс следует примеру. Однако, рабочее дерево остается прежним.

  • теперь добавьте изменения в индекс, который вы хотите иметь в первом коммите. Вы можете использовать git add (возможно, интерактивно) или Git gui (или оба) для этого.

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

  • повторите последние два шага, пока ваше рабочее дерево не очистится.

  • продолжить перебазирование с помощью git rebase --continue.

если вы не совсем уверены, что промежуточные версии согласованы (они компилируются,проходят testsuite и т. д.) вы должны использовать git stash чтобы спрятать еще не зафиксированные изменения после каждой фиксации, протестировать и изменить фиксацию, если необходимы исправления.


вы можете сделать интерактивный rebase git rebase -i. Man page имеет именно то, что вы хотите:

http://git-scm.com/docs/git-rebase#_splitting_commits


обратите внимание, что есть также git reset --soft HEAD^. Это похоже на git reset (по умолчанию --mixed), но он сохраняет содержимое индекса. Таким образом, если вы добавили/удалили файлы, они уже есть в индексе.

оказывается очень полезным в случае гигантских совершает.


теперь в последнем TortoiseGit на Windows вы можете сделать это очень легко.

откройте диалоговое окно rebase,настроить, и выполните следующие действия.

  • щелкните правой кнопкой мыши фиксацию, которую вы хотите разделить, и выберите"Edit" (среди pick, squash, delete...).
  • нажмите "Start" для начала перебазирования.
  • как только он прибывает в фиксацию для разделения, проверьте "" и нажмите на кнопку"Amend" напрямую. Диалог фиксации открытие.
    Edit/Split commit
  • отмените выбор файлов, которые вы хотите поместить на отдельную фиксацию.
  • отредактируйте сообщение фиксации и нажмите кнопку"commit".
  • пока нет файлов для фиксации, диалог фиксации будет открываться снова и снова. Когда больше нет файла для фиксации, он все равно спросит вас, Хотите ли вы добавить еще одну фиксацию.

очень полезно, спасибо TortoiseGit !


Я думаю, что лучший способ я использую git rebase -i. Я создал видео, чтобы показать шаги, чтобы разделить совершить: https://www.youtube.com/watch?v=3EzOz7e1ADI


проще всего обойтись без интерактивной ребазы (возможно), чтобы сделать новую ветвь, начиная с фиксации до той, которую вы хотите разделить, cherry-pick-N фиксации, сброса, заначки, фиксации перемещения файла, повторно применить заначку и зафиксировать изменения, а затем либо слиться с бывшей ветвью, либо вишневый выбор коммитов, которые следовали. (Затем переключите прежнее название ветви на текущую головку.) (Это, наверное, лучше следовать советам Опч и делать интерактивный перебазирования.)


если у вас есть это:

A - B <- mybranch

где вы совершили некоторый контент в commit B:

/modules/a/file1
/modules/a/file2
/modules/b/file3
/modules/b/file4

но вы хотите разделить B на C-D и получить этот результат:

A - C - D <-mybranch

вы можете разделить содержимое, например, так (содержимое из разных каталогов в разных коммитах)...

сбросьте ветвь обратно в фиксацию перед тем, как разделить:

git checkout mybranch
git reset --hard A

создать первую фиксацию (C):

git checkout B /modules/a
git add -u
git commit -m "content of /modules/a"

создать второй commit (D):

git checkout B /modules/b
git add -u
git commit -m "content of /modules/b"