Я хотел бы перебазировать к конкретному коммиту, а не к HEAD другой ветки:
A --- B --- C master
\
\-- D topic
в
A --- B --- C master
\
\-- D topic
вместо того
A --- B --- C master
\
\-- D topic
Как я могу этого достичь?
git
version-control
rebase
git-rebase
Ондра Жижка
источник
источник
git checkout B
перед запускомgit rebase
?rebase
команды имеют значение.Ответы:
Вы можете избежать использования параметра --onto, сделав временную ветвь для коммита, который вам нравится, и затем используйте rebase в его простой форме:
источник
git rebase temp
(когда в группе ) отказывается с "Текущий группы филиалов в актуальном состоянии."git rebase --onto <target> <from> <to>
чтобы вы могли указать коммит <from>.Вы даже можете принять прямой подход:
источник
topic
иcommitB
.It works by going to the common ancestor of the two branches (the one you’re on and the one you’re rebasing onto), getting the diff introduced by each commit of the branch you’re on, saving those diffs to temporary files, resetting the current branch to the same commit as the branch you are rebasing onto, and finally applying each change in turn.
я попробовал это снова теперь, и, казалось, работал отлично.m > n
.Используйте опцию «на»:
источник
D
иD^
был бы хэш последнего и предпоследнего коммита "темы"?git rebase --onto <new-parent> <old-parent>
. См. Установка указателя родителя git на другого родителя . В вашем случае <new-parent> - это B, а <old-parent> - это A.git rebase --onto <commit-ID> master
git rebase --onto master <commit-ID-of-old-parent>
и для ОПgit rebase --onto B A
.Комментарий jsz выше спас меня от тонны боли, поэтому вот пошаговый получатель, основанный на нем, который я использовал, чтобы перебазировать / переместить любой коммит поверх любого другого коммита:
git rebase --onto <new parent> <old parent>
В приведенном выше примере это так же просто, как:
источник
git rebase --onto B master
, см. Мой ответ для более подробного объяснения.Тема Решение
Правильная команда для ответа на заданный вопрос может быть любой из следующих (при условии, что ветвь
topic
уже извлечена):Если
topic
не отмечено, вы просто добавляетеtopic
команду (кроме последней) следующим образом:В качестве альтернативы, проверьте ветку сначала с:
Перебазировать любую строку коммитов в целевой коммит
Базовая форма команды, которая нам нужна, взята из документации:
<Branch>
не является обязательным, и все, что он делает, это проверяет ветвь, указанную перед выполнением остальной команды. Если вы уже отметили ветку, которую хотите перебазировать, вам это не нужно. Обратите внимание, что вы должны были указать<Upstream>
, чтобы указать,<Branch>
или git будет думать, что вы указываете<Upstream>
.<Target>
это коммит, к которому мы прикрепим нашу строку коммитов. Предоставляя имя ветки, вы просто указываете коммит заголовка этой ветки.<Target>
может быть любым коммитом, который не будет содержаться в строке коммитов, которые будут перемещены. Например:Чтобы переместить всю ветвь функции, вы не можете выбрать
X
,Y
,Z
или ,feature
как<Target>
так как те все коммиты внутри группы перемещения.<Upstream>
особенный, потому что это может означать две разные вещи. Если это коммит, который является предком извлеченной ветви, то он служит точкой вырезания. В этом примере я представил, это было бы ничего , что неC
,D
илиmaster
. Все коммиты после,<Upstream>
пока глава извлеченной ветки не будут перемещены.Однако если if
<Upstream>
не является предком, то git выполняет резервное копирование цепочки из указанного коммита до тех пор, пока if не найдет общего предка с извлеченной ветвью (и не прекратит работу, если не может его найти). В нашем случае,<Upstream>
изB
,C
,D
илиmaster
будет весь результат фиксации ,B
выступающим в качестве точки разреза.<Upstream>
сама по себе является необязательной командой, и если она не указана, то git просматривает родителя извлеченной ветви, что эквивалентно вводуmaster
.Теперь, когда git выбрал коммиты, которые он будет вырезать и перемещать, он применяет их для того, чтобы
<Target>
пропустить все, которые уже применены к цели.Интересные примеры и результаты
Используя эту отправную точку:
git rebase --onto D A feature
Будет ли применяться фиксаций
B
,C
,X
,Y
,Z
совершитьD
и в конечном итоге пропускB
иC
потому , что они уже были применены.git rebase --onto C X feature
Будет применять коммиты
Y
иZ
коммититьC
, эффективно удаляя коммитX
источник
Более простое решение
git rebase <SHA1 of B> topic
. Это работает независимо от того, где выHEAD
находитесь.Мы можем подтвердить это поведение из git rebase doc
Вы можете подумать, что произойдет, если я упомяну о SHA1
topic
тоже в приведенной выше команде?git rebase <SHA1 of B> <SHA1 of topic>
Это также будет работать, но rebase не будет
Topic
указывать на новую созданную ветку иHEAD
будет в отдельном состоянии. Отсюда вы должны вручную удалить старуюTopic
ветку и создать новую ссылку на новую ветку, созданную rebase.источник
Я использовал смесь решений, описанных выше:
Мне было намного легче читать и понимать. Принятое решение привело меня к конфликту слияний (слишком ленив, чтобы исправить вручную):
источник
Поскольку перебазирование является настолько фундаментальным, вот расширение ответа Нестора Миляева . Объединение комментариев jsz и Simon South из ответа Адама Димитрука дает команду, которая работает на
topic
ветви независимо от того, ветвится ли она изmaster
коммита ветвиA
илиC
:Обратите внимание, что последний аргумент обязателен (иначе он перематывает вашу ветку для фиксации
B
).Примеры:
Поэтому последняя команда - это та, которую я обычно использую.
источник
Есть другой способ сделать это, или если вы хотите вернуться к более чем одному коммиту.
Вот пример возврата к
n
количеству коммитов:Ради этого вопроса это также можно сделать:
Команда отлично работает на
git version 2.7.4
. Не проверял ни на одной другой версии.источник