Перебазировать ветку после 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 или подобное, чтобы выбрать коммиты. Реализации немного различаются в зависимости от конкретного вида перебазирования.

Другие вопросы по тегам