Ребаз на Ребаз / Сквош - PullRequest
       70

Ребаз на Ребаз / Сквош

1 голос
/ 08 марта 2019

Это обычная ситуация, с которой я сталкиваюсь, и я ищу чистое решение.

  1. Сделайте некоторую работу над веткой git (my-first-work)
  2. Нажми на github
  3. Создать новую ветку (some-further-work), основанную на вершине работы my-first-work

Не указано количество времени, прошедшего

  1. Подтверждающий восстанавливает или раздавливает my-first-work на master
  2. Это создает новые коммиты, которые git не рассматривает как эквивалент материала, на котором я базируюсь, даже если конечный результат идентичен (т. Е. Заголовок master идентичен заголовку my-first-work)
  3. Я бегу git rebase master, чтобы переместиться some-further-work на master
  4. коммиты от my-first-work, на которых я сейчас основываюсь, конфликтуют с тем, что уже было сквошем / слито

В настоящее время я обхожу это с помощью git rebase -i master, а затем удаляю все коммиты до заголовка my-first-work. Это точно воспроизводит дополнительные коммиты поверх master.

Есть ли более чистое решение? И есть ли способ заставить git автоматически распознавать, когда произошла перебазировка / сквош (как в 4)?

1 Ответ

1 голос
/ 08 марта 2019

Очиститель находится в глазу (или руках?) Наблюдателя / работника, но вы можете использовать git rebase --onto, чтобы отделить , который обязуется скопировать из , гдечтобы поместить копии .

Помните, что git rebase означает: 1 У меня есть линейная цепочка коммитов, как показано на рисунке 1, которую я хотел бы скопироватьна новую линейную цепочку коммитов, как показано на рисунке 2. Как только копии будут сделаны, я бы хотел, чтобы имя моей ветви указывало на последний скопированный коммит.Оригинальная цепочка A-B-C больше не нужна, даже если она все еще там.

[drawing 1]
...--o--*--o   <-- upstream/master
         \
          A--B--C   <-- topic

[drawing 2]
...--o--*--o   <-- upstream/master
            \
             A'-B'-C'  <-- topic

Различия между оригинальными коммитами и копиями заключаются в том, что оригиналы основаны на коммите *, который был верхушкой upstream/master раньше.Копии основаны на (новом) наконечнике upstream/master.Фраза на основе здесь имеет буквально два значения: родитель commit A - это commit *, а parent commit A' - этоболее поздняя фиксация, и снимок в commit A равен * -plus-some-changes, тогда как снимок в commit A' добавляет то же самое изменения позже коммита.

Поскольку мы используем наш новый блестящий коммит A' (который имеет другой хэш) в пользу старого скучного A, нам нужно скопироватьB до B' и C до C', и как только мы закончим, нам нужно, чтобы наше имя topic указывало не на C, а на последний скопированный коммит C'.

Обычный старый git rebase делает именно это.Мы говорим:

git checkout topic; git rebase upstream/master

, что говорит Git:

  1. Перечислять все коммиты, начиная с C и работая в обратном направлении. Это C затем B, затем A, затем *, затем все до *.
  2. Перечислите все коммиты, начиная с upstream/master и работая в обратном направлении. Это второй o, затем*, а затем все до *.
  3. Вычеркните все из списка second из списка first . Так, что выбиваетout * и все предыдущие коммиты.Второго o нет в первом списке, но это нормально: мы бы выбили его, если бы оно было , но это не так, мы ничего не делаем.Наш список теперь идет C, B и A.
  4. Переверните список, чтобы упорядочить его в правильном порядке, затем по одному копируйте каждый коммит в новыйместо.Новое место начинается с коммита, на который upstream/master указывает. Таким образом, это копирует A в A', B в B' и C в C'.
  5. Снимите текущее имя ветки topic со своего предыдущего местоположения и прикрепите его к новой цепочке коммитов, как обычно в конце. Так что topic указывает на C' вместоC.

В вашем новом случае, однако, вы имели:

...--o--*   <-- upstream/master
         \
          A--B--C   <-- feature1
                 \
                  D--E--F--G   <-- feature2

Они, в своем верхнем течении, не взяли вашу A-B-C цепочку.Вместо этого они сделали свой собственный коммит ABC сквош.Вы взяли его из верхнего хранилища, и теперь у вас есть:

...--o--*--ABC   <-- upstream/master
         \
          A--B--C   <-- feature1
                 \
                  D--E--F--G   <-- feature2

Если вы просто запустите git checkout feature2; git rebase upstream/master, ваш Git будет перечислять коммиты G-F-E-D-C-B-A-*-..., перечислять ABC-*-..., вычитать второе из первогои оставьте инструкции по копированию цепочки G-F-E-D-C-B-A.

Командой сбитого любителя:

git checkout feature2
git rebase --onto upstream/master feature1

То, что это делает, является отдельным аргументом target -место, где Git начнет копирование - из аргумента limit . target теперь upstream/master (документация Git называет это аргументом to ).Аргумент limit теперь feature1.Вы можете использовать необработанный хэш-идентификатор commit C, если хотите.Git просто нужно знать: С чего мне начать перечисление «нокаут-эти-коммиты»? (В документации по Git этот аргумент называется upstream .)

Как вы можете видеть, это теперь выбивает коммиты C-B-A-*, а не просто *, так что после копирования вы получите:

               D'-E'-F'-G'  [in progress]
              /
...--o--*--ABC   <-- upstream/master
         \
          A--B--C   <-- feature1
                 \
                  D--E--F--G   <-- feature2

и теперь Git может очистить ярлык feature2 с G и прикрепить вместо него G2.


1 Технически, есть гораздо больше git rebase, особенно теперь с новой модной опцией --rebase-merges.Это У меня есть линейная цепочка коммитов все еще ее основное использование, хотя.

Как хороший бонус, ребаз обычно может сказать, взяли ли они ваш A-B-C цепи и скопировал его в собственную A'-B'-C' цепь.Но это просто обычно .Rebase может никогда сказать, что они взяли ваш A-B-C и раздавили его до своего ABC, поэтому в этом случае вы застряли с --onto.

...