Трудно понять материал без диаграмм перемещения коммитов из одной ветки в другую - PullRequest
0 голосов
/ 10 апреля 2020

Я не понимаю содержимое страницы https://sethrobertson.github.io/GitFixUm/fixup.html#move_commit:

Перемещение коммита из одной ветви в другую

Итак, у вас есть Коммит, который находится в неправильном месте, и вы хотите переместить его из одной ветви в другую. Для этого вам необходимо знать SHA первого и последнего коммита (в непрерывной серии коммитов), которые вы хотите переместить (эти значения одинаковы, если вы перемещаете только один коммит), имя ветвь, из которой вы перемещаете коммит, и название ветви, в которую вы перемещаете коммит. В приведенном ниже примере я назову эти четыре значения $ first, $ last, $ source и $ destination (соответственно). Кроме того, вам нужно использовать ветку nonce в качестве заполнителя. Я буду называть ветку nonce «nonce» в следующем примере. Однако вы можете использовать любое имя ветки, которое в данный момент не используется. Вы можете удалить его сразу же после того, как закончите.

git branch nonce $last
git rebase -p --onto $destination $first^ nonce

Помните, что когда вы подставляете $ first в вышеприведенной команде, оставьте «^» в покое, это буквально.

Использование gitk --all --date-order проверить, чтобы убедиться, что движение выглядит правильно (делая вид, что одноразовый номер является ветвью назначения). Пожалуйста, проверьте очень внимательно, если вы пытаетесь переместить слияние, возможно, оно было воссоздано неправильно. Если вам не нравится результат, вы можете удалить ветвь nonce (git branch -D nonce) и повторить попытку.

Однако, если все выглядит хорошо, мы можем переместить указатель фактической ветви назначения туда, где находится nonce:

git checkout $destination
git reset --hard nonce
git branch -d nonce

Если вы дважды проверите с gitk --all --date-order, вы увидите, что ветвь назначения выглядит правильно. Тем не менее, коммиты все еще находятся в исходной ветке. Теперь мы можем избавиться от них:

git rebase -p --onto $first^ $last $source

Используя последний раз gitk --all --date-order, вы должны увидеть, что коммиты в ветке-источнике исчезли. Вы успешно переместили коммиты. Пожалуйста, очень внимательно проверьте, произошли ли слияния после коммитов, которые были удалены. Возможно, они были воссозданы неправильно. Если это так, вы можете либо отменить удаление , либо попытаться удалить неудачное слияние и попытаться воссоздать его вручную, либо создать поддельное (--ours) слияние из того же SHA, чтобы git знало, что произошло слияние.

Я постараюсь объяснить, что я знаю, а что нет. Я был бы признателен, если бы кто-нибудь др aws дерево коммитов после каждой команды.

Во-первых,

git branch nonce $last   (1)
git rebase -p --onto $destination $first^ nonce   (2)

Как я понимаю (1) копирует коммит $ last в ветви с именем nonce , В (2) диапазон коммитов от $ first до nonce включительно перемещается поверх $ destination. Я не понимаю, как будет выглядеть дерево коммитов в этой точке, потому что я не совсем получаю эффект (1).

Затем

git checkout $destination   (3)
git reset --hard nonce   (4)
git branch -d nonce   (5)

(3) проверок коммит из пункта назначения. Тогда в (4) hard сбрасывается в nonce, но каков эффект этого? Затем в (5) удалите ветку nonce.

Наконец,

git rebase -p --onto $first^ $last $source   (6)

Текст говорит (6), что приводит к удалению коммитов в исходной ветке. Как я понимаю этот синтаксис, это помещает диапазон коммитов, определенных как потомки $ last, включая $ source поверх родительского $ first.

Я знаю синтаксис git rebase --onto. Но я не понимаю, что именно здесь происходит.

Буду признателен, если вы поможете мне нарисовать диаграмму дерева коммитов после каждой команды.

1 Ответ

1 голос
/ 10 апреля 2020

Часть путаницы здесь, вероятно, происходит от терминологии «перемещение коммитов». Технически нет такой вещи как перемещение коммита. После создания коммита его содержимое, а также родительский указатель являются неизменяемыми и никогда не могут быть изменены.

Однако возможно создать новые коммиты с другим родителем , который достигает того же самого изменения , что и происходит в данном конкретном случае.

Также полезно помнить, что ветви - это просто изменяемые указатели на коммиты.

Начальная точка: Предположим, что followig

  • $destination - целевая ветвь
  • $source - исходная ветвь
  • $first - C (Первый коммит в серии мы хотим "переместить")
  • $last - это D (последний коммит в серии, который мы хотим "переместить")
                      $destination
                           |  
A -- B ------------------- F
      \ -- C -- D ----- E
                        |
                     $source              

Шаг 1: git branch nonce $last

  • Присоединяет новый указатель ветки nonce к $last коммиту
                      $destination
                           |  
A -- B ------------------- F
      \ -- C -- D ----- E
                |       |
              $nonce  $source             

Шаг 2: git rebase -p --onto $destination $first^ nonce

  • Принимает все различия между родителем $first и nonce (то есть изменения, введенные C и D) и применяет их как новые коммиты поверх $destination
  • Это приводит к новым коммитам C' и D' (оригинальные коммиты C и D не затрагиваются)
    • Указатель ветви nonce перемещается в последнюю из вновь созданных фиксаций D'
                      $destination
                           |  
A -- B ------------------- F 
      \ -- C -- D ----- E   \ -- C' -- D'        
                        |              | 
                     $source        $nonce             

Шаг 3: git checkout $destination

  • Изменяет рабочую копию на ветку $destination. Это не влияет на график истории

Шаг 4: git reset --hard nonce

  • Перемещает указатель ветки $destination на тот же коммит, что и nonce
  • Может также (и, вероятно, чаще) сделать git merge --ff-only nonce, что должно привести к ускоренному слиянию и, следовательно, к тому же результату.
                                 $destination
                                      |  
A -- B ------------------- F -- C' -- D'
      \ -- C -- D ----- E             |         
                        |           $nonce                
                     $source                            

Шаг 5: git branch -d nonce

  • Удаляет указатель ветви nonce
                                 $destination
                                      |  
A -- B ------------------- F -- C' -- D'
      \ -- C -- D ----- E                     
                        |                           
                     $source                           

Шаг 6: git rebase -p --onto $first^ $last $source

  • Принимает все различия между $last и $source (то есть изменения, внесенные E) и применяет их как новые коммиты поверх $first^ (родительский элемент $first, то есть B)
  • Это приводит к новым коммитам E' (оригинальные коммиты E не затрагиваются)
                                 $destination
                                      |  
A -- B ------------------- F -- C' -- D'
      \ -- C -- D ----- E
       \-- E'                     
           |                           
        $source                    

С внешнего вида Эффект коммитов C и D был удален из $source и применен вместо $destination.

РЕДАКТИРОВАТЬ: Как видно выше, исходные коммиты C и D все еще присутствуют т, но не доступны из любой ветви, они «отделены». Однако они все еще существуют в хранилище, так как git очень строго не удаляет и не изменяет существующие коммиты (в конце концов, они неизменяемы). Чтобы явно удалить этот коммит, используйте git prune

                                 $destination
                                      |  
A -- B ------------------- F -- C' -- D'
      \-- E'                     
          |                           
       $source                    
...