Перебазировать ветку после GitHub "Squash and merge" на мастера
Допустим, я разработал функцию на branch1
и отправил его на проверку кода с помощью запроса на извлечение GitHub. Пока он рассматривается, я продолжаю работу над branch2
,
branch2 -> D --> E --> F
/
branch1 -> A --> B --> C
/
master M
Мой рецензент любит мою работу! Никаких изменений не требуется. Я объединяю запрос на получение branch1
используя функцию сквоша и слияния GitHub.
После запуска git pull
на master
и удаление branch1
Я остался в этой ситуации:
branch2 -> A --> B --> C -> D --> E --> F
/
master M --> S
Чтобы отправить чистый PR для branch2
Я хотел бы, чтобы мое дерево коммитов выглядело так:
branch2 -> D' --> E' --> F'
/
master M --> S
Код на S
(коммит, сгенерированный "Squash and merge" для branch1
) идентичен C
разжатый вариант A --> B --> C
,
Один из способов добиться этого - запустить такую последовательность на branch2
:
git reset --hard S
git cherry-pick D E F
Но перечисление всех коммитов таким образом становится утомительным, и это действительно похоже на перебазирование. git rebase master
не будет работать, конечно, так как совершает A
, B
а также C
нужно исчезнуть.
Каков наилучший способ перебазировать ветку из сжатой версии одного из его коммитов предка?
1 ответ
Использование git rebase
с --onto
, Это все еще немного сложно, поэтому, чтобы упростить его, вы захотите сделать что-то другое, раньше.
Кстати, я думаю, что лучше рисовать эти графики с названиями ветвей справа, указывая на один конкретный коммит. Это потому, что в Git коммиты находятся на нескольких ветвях, а имена веток действительно указывают только на один конкретный коммит. Также стоит обратить вспять внутренние стрелки (потому что Git действительно хранит их таким образом) или просто использовать соединительные линии, чтобы не указывать неправильное направление.
Следовательно:
D--E--F <-- branch2
/
A--B--C <-- branch1
/
M <-- master
Фиксации A
через C
на самом деле на обоих branch1
а также branch2
, пока совершает D
через F
только на branch2
, (Берет M
а раньше есть на всех трех ветках.)
Какие git rebase upstream
действительно, выбирает все 1 коммитов, достижимых из текущей ветви, но не достижимых из upstream
аргумент, а затем скопировать их (с git cherry-pick
или эквивалент), чтобы они пришли сразу после upstream
совершить.
После сквоша -"слияние" (на самом деле не слияние), если вы запускаете git fetch
а затем перемотать вперед master
, у вас есть то же самое, что вы нарисовали, но я ухожу branch1
в и поставить метки слева и добавить origin/master
Вот:
D--E--F <-- branch2
/
A--B--C <-- branch1
/
M--S <-- master, origin/master
(Или, если вы не перемотаете master
пока только origin/master
указывает на фиксацию S
).
Теперь вы хотите сказать Git для копирования D-E-F
с вишней, затем переместите этикетку branch2
указать на последний скопированный коммит. Вы не хотите копировать A-B-C
как они включены в S
, Вы хотите, чтобы копии шли после S
, которому origin/master
сейчас указывает - обновили вы или нет master
, Следовательно:
git checkout branch2
git rebase --onto origin/master branch1
upstream
сейчас branch1
вместо master
, но --onto
говорит Git, где разместить копии: branch1
служит только для разграничения, что не копировать. Так что теперь Git копирует D-E-F
и изменения branch2
указать там:
D--E--F [abandoned]
/
A--B--C <-- branch1
/
M--S <-- master?, origin/master
\
D'-E'-F' <-- branch2
и теперь вы можете удалить имя branch1
, (А теперь вы можете перемотать master
если вы еще этого не сделали - не имеет значения, когда вы это делаете, и на самом деле вам не нужен свой собственный master
совсем.)
1 Точнее, rebase выбирает коммиты, которые (а) не объединяют коммиты и (б) не имеют того же самого git patch-id
как некоторые фиксируют в исключенном множестве, используя симметричную разность. То есть, а не upstream..HEAD
Гит на самом деле работает git rev-list
на upstream...HEAD
, с --cherry-mark
или подобное, чтобы выбрать коммиты. Реализации немного различаются в зависимости от конкретного вида перебазирования.