Без создания ветки и выполнения какой-то сложной работы над новой веткой, возможно ли разбить один коммит на несколько разных коммитов после его фиксации в локальном репозитории?
Документы, ссылки на которые приведены выше, превосходны и лучше объяснены, чем ответы ниже.
Blaisorblade
2
Я предлагаю использовать этот псевдоним stackoverflow.com/a/19267103/301717 . Это позволяет разделить коммит, используяgit autorebase split COMMIT_ID
Jérôme Pouiller
Проще всего обойтись без интерактивного перебазирования - это (вероятно) создать новую ветвь, начинающуюся с коммита до того, который вы хотите разделить, cherry-pick -n за коммит, сбросить, спрятать, зафиксировать перемещение файла, повторно применить кэш и зафиксируйте изменения, а затем либо объединитесь с предыдущей веткой, либо выберите те коммиты, которые последовали. (Затем переключите прежнее имя ветки на текущий руководитель.) (Вероятно, лучше последовать совету MBO и сделать интерактивную перебазировку.) (Скопировано из ответа 2010 года ниже)
Уильям Перселл
1
Я столкнулся с этой проблемой после того, как случайно раздавил два коммита во время перебазирования в более раннем коммите. Мой способ , чтобы исправить это было проверка сжатую совершить, git reset HEAD~, git stash, то git cherry-pickпервым совершить в сквош, а затем git stash pop. Мой случай с вишней весьма специфичен, но git stashи git stash popвесьма удобен для других.
Во-первых, начните с чистого рабочего каталога: не git statusдолжно отображаться ожидающих изменений, удалений или дополнений.
Теперь вы должны решить, какие коммиты вы хотите разделить.
A) Разделение самого последнего коммита
Чтобы разделить ваш последний коммит, сначала:
$ git reset HEAD~
Теперь фиксируйте фигуры индивидуально обычным способом, создавая столько коммитов, сколько вам нужно.
Б) Разделить коммит дальше назад
Это требует перебазирования , то есть переписывания истории. Чтобы найти правильный коммит, у вас есть несколько вариантов:
Если это было три коммитов назад, то
$ git rebase -i HEAD~3
где 3сколько коммитов это обратно.
Если это было дальше в дереве, чем вы хотите сосчитать, то
$ git rebase -i 123abcd~
где 123abcdSHA1 коммита, который вы хотите разделить.
Если вы находитесь в другой ветке (например, ветке функций), которую вы планируете объединить в master:
$ git rebase -i master
Когда вы получите экран редактирования rebase, найдите коммит, который вы хотите разбить на части. В начале этой строки заменить pickна edit( eдля краткости). Сохраните буфер и выйдите. Rebase теперь остановится сразу после коммита, который вы хотите отредактировать. Затем:
$ git reset HEAD~
Зафиксируйте фрагменты индивидуально обычным способом, выполнив столько коммитов, сколько вам нужно, затем
Спасибо за этот ответ. Я хотел, чтобы некоторые предварительно зафиксированные файлы находились в области подготовки, поэтому инструкции для меня были немного другими. Прежде , чем я мог git rebase --continue, я на самом деле был git add (files to be added), git commit, а затем git stash(для остальных файлов). После git rebase --continueэтого я git checkout stash .получал оставшиеся файлы
Эрик Ху,
18
Ответ manojlds на самом деле содержит эту ссылку на документацию по git-scm , которая также очень четко объясняет процесс разделения коммитов.
56
Вы также захотите воспользоваться преимуществом git add -pдобавления только частичных разделов файлов, возможно, с eвозможностью редактирования различий, чтобы зафиксировать только часть фрагмента. git stashтакже полезно, если вы хотите продолжить работу, но удалите ее из текущего коммита.
Крейг Рингер
2
Если вы хотите разделить и изменить порядок коммитов, сначала мне нужно разделить, а затем изменить порядок отдельно, используя другую git rebase -i HEAD^3команду. Таким образом, если раскол пойдет не так, вам не придется отменять столько работы.
Дэвид М. Ллойд
4
@kralyk Файлы, которые были недавно зафиксированы в HEAD, останутся на диске после git reset HEAD~. Они не потеряны.
Уэйн Конрад
312
Из руководства git- rebase (раздел SPLITTING COMMITS)
В интерактивном режиме вы можете пометить коммиты с помощью действия «изменить». Однако это не обязательно означает, что git rebase ожидает, что результатом этого редактирования будет ровно один коммит. Действительно, вы можете отменить коммит или добавить другие коммиты. Это можно использовать для разделения коммита на две части:
Начните интерактивную перебазировку git rebase -i <commit>^, где <commit>находится коммит, который вы хотите разделить. Фактически, подойдет любой диапазон фиксации, если он содержит этот коммит.
Пометьте коммит, который вы хотите разделить, с помощью действия «изменить».
Когда дело доходит до редактирования этого коммита, выполняйте git reset HEAD^. В результате HEAD перематывается на единицу, и индекс следует за ним. Однако рабочее дерево остается прежним.
Теперь добавьте изменения в индекс, которые вы хотите иметь при первом коммите. Вы можете использовать git add(возможно, в интерактивном режиме) или git gui(или оба), чтобы сделать это.
Зафиксируйте текущий текущий индекс с любым соответствующим сообщением.
Повторяйте последние два шага, пока ваше рабочее дерево не станет чистым.
Слово предостережения: при таком подходе я потерял сообщение коммита.
user420667
11
@ user420667 Да, конечно. Мы делаем resetкоммит, в конце концов - сообщение включено. Если вы знаете, что собираетесь разбивать коммит, но хотите сохранить некоторые / все его сообщения, разумно сделать копию этого сообщения. Итак, git showсделайте коммит перед rebaseзагрузкой, или, если вы забыли или предпочли это: вернитесь к нему позже через reflog. Ничто из этого на самом деле не будет «потеряно», пока не будет собрано мусор через 2 недели или что-то еще.
underscore_d
4
~и ^это разные вещи, даже на Windows. Вы по-прежнему хотите использовать каретку ^, поэтому вам нужно просто избежать ее в соответствии с вашей оболочкой. В PowerShell это так HEAD`^. С cmd.exe вы можете удвоить его, чтобы сбежать, как HEAD^^. В большинстве (всех?) Оболочек можно заключать в кавычки, например "HEAD^".
AndrewF
7
Вы также можете сделать git commit --reuse-message=abcd123. Краткий вариант для этого есть -C.
j0057
41
Используйте, git rebase --interactiveчтобы отредактировать этот предыдущий коммит, запустить git reset HEAD~, а затем git add -pдобавить некоторые, затем сделать коммит, затем добавить еще несколько и сделать еще один коммит столько раз, сколько захотите. Когда вы закончите, запустите git rebase --continue, и у вас будут все коммиты split ранее в вашем стеке.
Важно : обратите внимание, что вы можете поиграть и внести все необходимые изменения, и вам не нужно беспокоиться о потере старых изменений, потому что вы всегда можете запустить, 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
затем добавьте эту строку в A:
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на a 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
У нас есть конфликт с нашим коммитом three, поэтому давайте разрешим его:
Мы изменим
one
<<<<<<< HEAD
two and a third
two and two thirds
=======
two
three
>>>>>>> bfb8e46... three
в
one
two and a third
two and two thirds
three
git add .; git rebase --continue
Теперь наш git log -pвыглядит так:
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, у вас есть два варианта.
После использования git reset HEAD~, пройдитесь по патчам индивидуально, используя, git add -pчтобы выбрать те, которые вы хотите в каждом коммите.
Отредактируйте рабочую копию, чтобы удалить изменения, которые вы не хотите; совершить это временное состояние; и затем вытяните полный коммит для следующего раунда.
Вариант 2 полезен, если вы разделяете большой коммит, так как он позволяет вам проверить, что промежуточные версии создаются и работают правильно как часть слияния. Это происходит следующим образом.
После использования rebase -iи editфиксации, используйте
git reset --soft HEAD~
отменить фиксацию, но оставить зафиксированные файлы в индексе. Вы также можете сделать смешанный сброс, пропустив --soft, в зависимости от того, насколько близок к конечному результату ваш первоначальный коммит. Разница лишь в том, начинаете ли вы со всех этапов изменений или со всеми без изменений.
Теперь зайдите и отредактируйте код. Вы можете удалить изменения, удалить добавленные файлы и сделать все, что хотите, чтобы создать первый коммит из серии, которую вы ищете. Вы также можете собрать его, запустить и подтвердить, что у вас есть согласованный набор источников.
Как только вы будете довольны, подготовьте / разархивируйте файлы по мере необходимости (я хотел бы использовать 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:
Спасибо!!! Это должен быть принятый ответ. Сэкономил бы мне сегодня много времени и боли. Это единственный ответ, когда результат окончательного коммита приводит вас в то же состояние, что и редактируемый коммит.
Даг Кобурн
1
Мне нравится, как вы используете оригинальное сообщение о коммите.
Саламандар
Используя вариант 2, когда я это делаю, git checkout *Sha I'm Editing* .он всегда говорит Updated 0 paths from *Some Sha That's Not In Git Log*и не дает никаких изменений.
В интерактивном режиме вы можете пометить коммиты с помощью действия «изменить». Однако это не обязательно означает, git rebaseчто в результате этого редактирования будет ровно один коммит. Действительно, вы можете отменить коммит или добавить другие коммиты. Это можно использовать для разделения коммита на две части:
Начните интерактивную перебазировку git rebase -i <commit>^, где <commit>находится коммит, который вы хотите разделить. Фактически, подойдет любой диапазон фиксации, если он содержит этот коммит.
Пометьте коммит, который вы хотите разделить, с помощью действия «изменить».
Когда дело доходит до редактирования этого коммита, выполняйте git reset HEAD^. В результате HEAD перематывается на единицу, и индекс следует за ним. Однако рабочее дерево остается прежним.
Теперь добавьте изменения в индекс, которые вы хотите иметь при первом коммите. Вы можете использовать git add(возможно, в интерактивном режиме) или git gui (или оба), чтобы сделать это.
Зафиксируйте текущий текущий индекс с любым соответствующим сообщением.
Повторяйте последние два шага, пока ваше рабочее дерево не станет чистым.
Продолжите ребаз с git rebase --continue.
Если вы не совсем уверены, что промежуточные ревизии являются согласованными (они компилируются, проходят тестовый набор и т. Д.), Вы должны использовать, git stashчтобы скрыть еще не зафиксированные изменения после каждой фиксации, тестирования и изменения фиксации, если необходимы исправления ,
В Windows запомните ^это управляющий символ для командной строки: он должен быть удвоен. К примеру, вопрос git reset HEAD^^вместо git reset HEAD^.
Фредерик,
@ Фредерик: я никогда не сталкивался с этим. По крайней мере, в PowerShell это не так. Затем с помощью ^двойного сброса два коммита выше текущего заголовка.
Фарвей
@ Farway, попробуйте в классической командной строке. PowerShell - совсем другой зверь, его экранирующий символ - задняя часть.
Фредерик
Подводя итог: "HEAD^"в cmd.exe или PowerShell, HEAD^^в cmd.exe, HEAD`^в PowerShell. Полезно узнать о том, как работают оболочки - и ваша конкретная оболочка - (то есть, как команда превращается в отдельные части, которые передаются в программу), чтобы вы могли адаптировать команды онлайн в правильные символы для вашей конкретной оболочки. (Не
относится только
12
Теперь в последней версии TortoiseGit для Windows вы можете сделать это очень легко.
Откройте диалоговое окно rebase, настройте его и выполните следующие шаги.
Щелкните правой кнопкой мыши на коммите, который вы хотите разделить, и выберите « Edit» (среди выбора, сквоша, удаления ...).
Нажмите « Start», чтобы начать перебазирование.
Как только он прибудет в коммит для разделения, проверьте Edit/Splitкнопку " " и нажмите " Amend" напрямую. Откроется диалоговое окно фиксации.
Отмените выбор файлов, которые вы хотите поместить в отдельный коммит.
Отредактируйте сообщение о коммите и нажмите « commit».
Пока не появятся файлы для фиксации, диалог фиксации будет открываться снова и снова. Когда больше нет файла для фиксации, он все равно спросит вас, хотите ли вы добавить еще один коммит.
Предоставить немного больше контекста о том, как подходить к решению проблем, чем просто дать RTFM, было бы немного более полезно.
Джордан Деа-Мэтсон
8
Обратите внимание, что есть также git reset --soft HEAD^. Это похоже на git reset(по умолчанию --mixed), но оно сохраняет содержимое индекса. Так что если вы добавили / удалили файлы, они уже есть в индексе.
Оказывается очень полезным в случае гигантских коммитов.
Вот как разделить один коммит в IntelliJ IDEA , PyCharm , PhpStorm и т. Д.
В окне журнала контроля версий выберите коммит, который вы хотите разделить, щелкните правой кнопкой мыши и выберите Interactively Rebase from Here
Отметьте тот, который вы хотите разделить edit, нажмитеStart
Rebasing
Вы должны увидеть желтую метку, означающую, что для HEAD установлена эта фиксация. Щелкните правой кнопкой мыши на этом коммите, выберитеUndo Commit
Теперь эти коммиты вернулись в область подготовки, затем вы можете зафиксировать их отдельно. После того, как все изменения были зафиксированы, старая фиксация становится неактивной.
Проще всего обойтись без интерактивного перебазирования - это (вероятно) создать новую ветвь, начинающуюся с коммита до того, который вы хотите разделить, cherry-pick -n за коммит, сбросить, спрятать, зафиксировать перемещение файла, повторно применить кэш и зафиксируйте изменения, а затем либо объединитесь с предыдущей веткой, либо выберите те коммиты, которые последовали. (Затем переключите прежнее имя ветки на текущий заголовок.) (Вероятно, лучше последовать совету MBO и сделать интерактивную перебазировку.)
в соответствии со стандартами SO в наши дни это следует квалифицировать как отсутствие ответа; но это все еще может быть полезно для других, поэтому, если вы не возражаете, пожалуйста, переместите это в комментарии к оригинальному сообщению
YakovL
@ ЯковЛ Кажется разумным. По принципу минимального действия я не буду удалять ответ, но я бы не стал возражать, если кто-то другой сделает это.
Уильям Перселл
это было бы намного проще, чем все rebase -iпредложения. Я думаю, что это не привлекло большого внимания из-за отсутствия какого-либо форматирования. Может быть, вы могли бы просмотреть его, теперь, когда у вас есть 126 тыс. Баллов и, вероятно, знаете, как это сделать. ;)
Прошло уже более 8 лет, но, возможно, кто-то найдет это полезным в любом случае. Я был в состоянии сделать трюк без rebase -i. Идея состоит в том, чтобы привести git в то же состояние, в котором он находился до этого git commit:
# first rewind back (mind the dot,# though it can be any valid path,# for instance if you want to apply only a subset of the commit)
git reset --hard <previous-commit>.# apply the changes
git checkout <commit-you-want-to-split># we're almost there, but the changes are in the index at the moment,# hence one more step (exactly as git gently suggests):# (use "git reset HEAD <file>..." to unstage)
git reset
После этого вы увидите это блестящее, Unstaged changes after reset:и ваш репо находится в состоянии, как будто вы собираетесь зафиксировать все эти файлы. Отныне вы можете легко совершить это снова, как обычно. Надеюсь, поможет.
git autorebase split COMMIT_ID
git reset HEAD~
,git stash
, тоgit cherry-pick
первым совершить в сквош, а затемgit stash pop
. Мой случай с вишней весьма специфичен, ноgit stash
иgit stash pop
весьма удобен для других.Ответы:
git rebase -i
сделаю это.Во-первых, начните с чистого рабочего каталога: не
git status
должно отображаться ожидающих изменений, удалений или дополнений.Теперь вы должны решить, какие коммиты вы хотите разделить.
A) Разделение самого последнего коммита
Чтобы разделить ваш последний коммит, сначала:
Теперь фиксируйте фигуры индивидуально обычным способом, создавая столько коммитов, сколько вам нужно.
Б) Разделить коммит дальше назад
Это требует перебазирования , то есть переписывания истории. Чтобы найти правильный коммит, у вас есть несколько вариантов:
Если это было три коммитов назад, то
где
3
сколько коммитов это обратно.Если это было дальше в дереве, чем вы хотите сосчитать, то
где
123abcd
SHA1 коммита, который вы хотите разделить.Если вы находитесь в другой ветке (например, ветке функций), которую вы планируете объединить в master:
Когда вы получите экран редактирования rebase, найдите коммит, который вы хотите разбить на части. В начале этой строки заменить
pick
наedit
(e
для краткости). Сохраните буфер и выйдите. Rebase теперь остановится сразу после коммита, который вы хотите отредактировать. Затем:Зафиксируйте фрагменты индивидуально обычным способом, выполнив столько коммитов, сколько вам нужно, затем
источник
git rebase --continue
, я на самом деле былgit add (files to be added)
,git commit
, а затемgit stash
(для остальных файлов). Послеgit rebase --continue
этого яgit checkout stash .
получал оставшиеся файлыgit add -p
добавления только частичных разделов файлов, возможно, сe
возможностью редактирования различий, чтобы зафиксировать только часть фрагмента.git stash
также полезно, если вы хотите продолжить работу, но удалите ее из текущего коммита.git rebase -i HEAD^3
команду. Таким образом, если раскол пойдет не так, вам не придется отменять столько работы.git reset HEAD~
. Они не потеряны.Из руководства git- rebase (раздел SPLITTING COMMITS)
источник
~
вместо^
.reset
коммит, в конце концов - сообщение включено. Если вы знаете, что собираетесь разбивать коммит, но хотите сохранить некоторые / все его сообщения, разумно сделать копию этого сообщения. Итак,git show
сделайте коммит передrebase
загрузкой, или, если вы забыли или предпочли это: вернитесь к нему позже черезreflog
. Ничто из этого на самом деле не будет «потеряно», пока не будет собрано мусор через 2 недели или что-то еще.~
и^
это разные вещи, даже на Windows. Вы по-прежнему хотите использовать каретку^
, поэтому вам нужно просто избежать ее в соответствии с вашей оболочкой. В PowerShell это такHEAD`^
. С cmd.exe вы можете удвоить его, чтобы сбежать, какHEAD^^
. В большинстве (всех?) Оболочек можно заключать в кавычки, например"HEAD^"
.git commit --reuse-message=abcd123
. Краткий вариант для этого есть-C
.Используйте,
git rebase --interactive
чтобы отредактировать этот предыдущий коммит, запуститьgit reset HEAD~
, а затемgit add -p
добавить некоторые, затем сделать коммит, затем добавить еще несколько и сделать еще один коммит столько раз, сколько захотите. Когда вы закончите, запуститеgit rebase --continue
, и у вас будут все коммиты split ранее в вашем стеке.Важно : обратите внимание, что вы можете поиграть и внести все необходимые изменения, и вам не нужно беспокоиться о потере старых изменений, потому что вы всегда можете запустить,
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
затем добавьте эту строку в A:
three
git commit -am three
Теперь файл A выглядит так:
и наш
git log
выглядит следующим образом (ну, я используюgit log --pretty=oneline --pretty="%h %cn %cr ---- %s"
Допустим, мы хотим разделить второй коммит
two
.git rebase --interactive HEAD~2
Это вызывает сообщение, которое выглядит так:
Измените первый
pick
на ae
для редактирования этого коммита.git reset HEAD~
git diff
показывает нам, что мы только что сделали unstaged обязательство, которое мы сделали для второго коммита:Давайте внесем это изменение и добавим «и третий» к этой строке в файле
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
У нас есть конфликт с нашим коммитом
three
, поэтому давайте разрешим его:Мы изменим
в
git add .; git rebase --continue
Теперь наш
git log -p
выглядит так:источник
В предыдущих ответах рассказывалось о том,
git rebase -i
как редактировать коммит, который вы хотите разделить, и коммитить его по частям.Это хорошо работает при разделении файлов на разные коммиты, но если вы хотите разбить изменения на отдельные файлы, вам нужно знать больше.
Получив коммит, который вы хотите разделить, используя
rebase -i
и пометив егоedit
, у вас есть два варианта.После использования
git reset HEAD~
, пройдитесь по патчам индивидуально, используя,git add -p
чтобы выбрать те, которые вы хотите в каждом коммите.Отредактируйте рабочую копию, чтобы удалить изменения, которые вы не хотите; совершить это временное состояние; и затем вытяните полный коммит для следующего раунда.
Вариант 2 полезен, если вы разделяете большой коммит, так как он позволяет вам проверить, что промежуточные версии создаются и работают правильно как часть слияния. Это происходит следующим образом.
После использования
rebase -i
иedit
фиксации, используйтеотменить фиксацию, но оставить зафиксированные файлы в индексе. Вы также можете сделать смешанный сброс, пропустив --soft, в зависимости от того, насколько близок к конечному результату ваш первоначальный коммит. Разница лишь в том, начинаете ли вы со всех этапов изменений или со всеми без изменений.
Теперь зайдите и отредактируйте код. Вы можете удалить изменения, удалить добавленные файлы и сделать все, что хотите, чтобы создать первый коммит из серии, которую вы ищете. Вы также можете собрать его, запустить и подтвердить, что у вас есть согласованный набор источников.
Как только вы будете довольны, подготовьте / разархивируйте файлы по мере необходимости (я хотел бы использовать
git gui
для этого) и зафиксируйте изменения через пользовательский интерфейс или командную строкуЭто первый сделанный коммит. Теперь вы хотите восстановить свою рабочую копию в состояние, которое она имела после разделения коммита, чтобы вы могли принять больше изменений для вашего следующего коммита. Чтобы найти sha1 коммита, который вы редактируете, используйте
git status
. В первых нескольких строках состояния вы увидите команду rebase, которая выполняется в данный момент, в которой вы можете найти sha1 вашего исходного коммита:В этом случае редактируемый мной коммит имеет sha1
65dfb6a
. Зная это, я могу проверить содержимое этого коммита в моем рабочем каталоге, используя форму,git checkout
которая принимает как коммит, так и местоположение файла. Здесь я использую.
в качестве местоположения файла замену всей рабочей копии:Не пропустите точку на конце!
После этого будут проверены и отредактированы файлы, какими они были после коммита, который вы редактируете, но относительно предыдущего коммита, который вы сделали, поэтому любые изменения, которые вы уже зафиксировали, не будут частью коммита.
Вы можете либо пойти дальше и зафиксировать его как есть, чтобы завершить разделение, либо вернуться снова, удалив некоторые части коммита перед выполнением другого временного коммита.
Если вы хотите повторно использовать исходное сообщение о коммите для одного или нескольких коммитов, вы можете использовать его прямо из рабочих файлов rebase:
Наконец, как только вы совершите все изменения,
продолжит и завершит операцию перебазирования.
источник
git checkout *Sha I'm Editing* .
он всегда говоритUpdated 0 paths from *Some Sha That's Not In Git Log*
и не дает никаких изменений.git rebase --interactive
может использоваться для разделения коммита на коммиты меньшего размера. В документации Git по rebase есть краткое описание этого процесса - Splitting Commits :источник
^
это управляющий символ для командной строки: он должен быть удвоен. К примеру, вопросgit reset HEAD^^
вместоgit reset HEAD^
.^
двойного сброса два коммита выше текущего заголовка."HEAD^"
в cmd.exe или PowerShell,HEAD^^
в cmd.exe,HEAD`^
в PowerShell. Полезно узнать о том, как работают оболочки - и ваша конкретная оболочка - (то есть, как команда превращается в отдельные части, которые передаются в программу), чтобы вы могли адаптировать команды онлайн в правильные символы для вашей конкретной оболочки. (НеТеперь в последней версии TortoiseGit для Windows вы можете сделать это очень легко.
Откройте диалоговое окно rebase, настройте его и выполните следующие шаги.
Edit
» (среди выбора, сквоша, удаления ...).Start
», чтобы начать перебазирование.Edit/Split
кнопку " " и нажмите "Amend
" напрямую. Откроется диалоговое окно фиксации.commit
».Очень полезно, спасибо TortoiseGit!
источник
Вы можете сделать интерактивный ребаз
git rebase -i
. Справочная страница содержит именно то, что вы хотите:http://git-scm.com/docs/git-rebase#_splitting_commits
источник
Обратите внимание, что есть также
git reset --soft HEAD^
. Это похоже наgit reset
(по умолчанию--mixed
), но оно сохраняет содержимое индекса. Так что если вы добавили / удалили файлы, они уже есть в индексе.Оказывается очень полезным в случае гигантских коммитов.
источник
Вот как разделить один коммит в IntelliJ IDEA , PyCharm , PhpStorm и т. Д.
В окне журнала контроля версий выберите коммит, который вы хотите разделить, щелкните правой кнопкой мыши и выберите
Interactively Rebase from Here
Отметьте тот, который вы хотите разделить
edit
, нажмитеStart Rebasing
Вы должны увидеть желтую метку, означающую, что для HEAD установлена эта фиксация. Щелкните правой кнопкой мыши на этом коммите, выберите
Undo Commit
Теперь эти коммиты вернулись в область подготовки, затем вы можете зафиксировать их отдельно. После того, как все изменения были зафиксированы, старая фиксация становится неактивной.
источник
Проще всего обойтись без интерактивного перебазирования - это (вероятно) создать новую ветвь, начинающуюся с коммита до того, который вы хотите разделить, cherry-pick -n за коммит, сбросить, спрятать, зафиксировать перемещение файла, повторно применить кэш и зафиксируйте изменения, а затем либо объединитесь с предыдущей веткой, либо выберите те коммиты, которые последовали. (Затем переключите прежнее имя ветки на текущий заголовок.) (Вероятно, лучше последовать совету MBO и сделать интерактивную перебазировку.)
источник
rebase -i
предложения. Я думаю, что это не привлекло большого внимания из-за отсутствия какого-либо форматирования. Может быть, вы могли бы просмотреть его, теперь, когда у вас есть 126 тыс. Баллов и, вероятно, знаете, как это сделать. ;)Я думаю, что лучший способ, которым я пользуюсь
git rebase -i
. Я создал видео, чтобы показать шаги для разделения коммита: https://www.youtube.com/watch?v=3EzOz7e1ADIисточник
Если у вас есть это:
Где вы зафиксировали некоторый контент в коммите B:
Но вы хотите разделить B на C - D и получить такой результат:
Вы можете, например, разделить контент (контент из разных каталогов в разных коммитах) ...
Сбросьте ветку обратно до коммита перед тем, чтобы разделить:
Создайте первый коммит (C):
Создайте второй коммит (D):
источник
Прошло уже более 8 лет, но, возможно, кто-то найдет это полезным в любом случае. Я был в состоянии сделать трюк без
rebase -i
. Идея состоит в том, чтобы привести git в то же состояние, в котором он находился до этогоgit commit
:После этого вы увидите это блестящее,
Unstaged changes after reset:
и ваш репо находится в состоянии, как будто вы собираетесь зафиксировать все эти файлы. Отныне вы можете легко совершить это снова, как обычно. Надеюсь, поможет.источник
Краткий справочник необходимых команд, потому что я в основном знаю, что делать, но всегда забываю правильный синтаксис:
Кредиты к сообщению в блоге Эммануила Бернарда .
источник