git перебазировать все промежуточные ветки - PullRequest
0 голосов
/ 20 апреля 2020

Предположим, у меня есть набор ВЕТЕК (не коммитов), таких как:

A
|
B   C
|   |
 \ /
  D

Я хотел бы перебазировать A на C, но при этом я хотел бы также перейти B чтобы получить что-то вроде

A
|
B
|
C
|
D

, в данный момент я делаю это вручную, перебрасывая A на C и затем перемещая B. Есть ли опция для команды git rebase, которая позволяет мне сделать это с помощью одной команды?

Использование простого git rebase C, когда он находится в A (или git rebase C A), недостаточно, поскольку перемещает только ветку A, тогда как ветка B остается там, где она есть (ее коммиты копируются, но ветка не перемещается)

Ответы [ 3 ]

2 голосов
/ 20 апреля 2020

В ветви B, запустите это

git rebase C A
0 голосов
/ 20 апреля 2020

Если я рендерим ваши четыре коммита в стиле, который я предпочитаю для сообщений StackOverflow, это выглядит так, с более новыми коммитами вправо:

  C   <-- branch1
 /
D
 \
  B--A   <-- branch2

Два имени - вы не сказали нам, что они есть, поэтому я просто использовал branch1 и branch2 здесь - содержит необработанный идентификатор ha sh фактических коммитов C и A, которые являются коммитом наконечника двух ветвей. (C и A заменяют настоящие идентификаторы ha sh, которые являются большими, некрасивыми и случайными на вид.)

Родителем коммита A является коммит B. Родителем коммита B является коммит D. Родителем коммита C также является коммит D. (Если есть коммиты до коммита D, мы их не видим.)

Вы говорите, что хотели бы иметь:

D--C--B--A

в качестве конечного результата. Вы не можете: commit B Родитель - commit D, сейчас и навсегда. Вы можете иметь:

D--C--B'-A'

, где B' является копией из B, но с другим идентификатором ha sh, поскольку он также имеет другой родитель (и, возможно, другой снимок). Аналогично, A' должен быть результатом извлечения коммитов B' и A и повторной передачи чего-то немного другого: родительский элемент, если A' равен B', а A', вероятно, содержит снимок, отличный от A точно так же, как B', вероятно, содержит снимок, отличный от B.

фиксирует B и A продолжит существовать, т. е. ваш репозиторий будет иметь:

D--C--B'-A'
    \
     B--A

в этом. Если вы запишите где-нибудь действительные идентификаторы ha sh, равные B и A, и введете их позже, вы увидите, что коммиты продолжают существовать. (По умолчанию они будут работать не менее 30 дней, если вы решите, что хотите их вернуть.)

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

D--C--B'-A'  <-- branch1, branch2

, или вы можете branch2 указывать на A' и оставлять branch1, указывая на существующий коммит C, вот так:

     B'-A'  <-- branch2
    /
D--C   <-- branch1

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

Примечание что ответ Саураба П Бхандари эквивалентен:

git checkout --detach branch2     # or git checkout <hash-of-A>
git rebase branch1

, что дает:

     B'-A'  <-- HEAD
    /
D--C   <-- branch1
    \
     B--A   <-- branch1

т.е. вы отсоединены от HEAD в режиме конец, с ни одним именем ветви перемещено.

Поскольку существует два имени ветви задействовано - branch1 и branch2 являются двумя именами - он принимает как минимум две Git команды для достижения:

D--C--B'-A'  <-- branch1, branch2
    \
     B--A   [abandoned]

в качестве конечного результата, если вы этого хотите. Минимальный набор команд - есть много последовательностей команд, которые достигнут этого результата - это:

git checkout branch2
git rebase branch1
git push . branch2:branch1

, что оставляет вас с HEAD прикрепленным к имени branch2:

D--C--B'-A'  <-- branch1, branch2 (HEAD)
    \
     B--A   [abandoned]

ответ символической ссылки с подстановками имен составляет:

git checkout branch2
git rebase branch1
git checkout branch1
git merge --ff-only branch2    # the --ff-only is not required here

, что делает то же самое, но оставляет HEAD прикрепленным к имени branch1:

D--C--B'-A'  <-- branch1 (HEAD), branch2
    \
     B--A   [abandoned]

Флаг --ff-only гарантирует, что если что-то пошло не так и фиксация, идентифицируемая именем branch2, теперь не строго впереди фиксации, идентифицируемой branch1, Git выдаст сообщение об ошибке, а не новый коммит слияния.

Команда git push . <em>src</em>:<em>dst</em> особенно хитрая / хитрая, и я не очень рекомендую ее вообще, но она иллюстрирует способ попросить Git перемотать вперед одно из ваших имен - dst - указывать на любой данный коммит, в данном случае src. Здесь мы переместим имя branch1, чтобы оно указывало на тот же коммит, что и branch2. Опять же, команда pu sh имеет source слева и destination справа, поэтому мы пишем это как branch2:branch1.

Ключ к пониманию всего этого

Git заключается в commits . Каждый коммит имеет уникальный идентификатор ha sh, и как только коммит сделан, его часть не может быть изменена . Поэтому, если вы хотите другие коммиты, вы должны делать новые. Это обычно не имеет большого значения. Вот что делает git rebase : копирует некоторые существующие коммиты в некоторые новые и улучшенные.

Вы - и Git в этом отношении - находка Коммит, однако, начинается с last в цепочке, идентифицируемого по имени ветви, а затем работает в обратном направлении. (Вот почему commit A является последним, а не первым, на каждом из наших рисунков: вы помещаете последний вверху, а я помещаю последний справа.)

Скопировав серию коммитов, найденных по определенному имени, git rebase now перетаскивает имя, чтобы указать на последний из новых коммитов . Для одного имени это как раз то, что вы хотите.

Но после того, как вы скопировали серию коммитов, если есть более одного имени , которое вы хотели бы переместить, Вы должны переместить остальные имена. Это действительно все, что нужно сделать.

0 голосов
/ 20 апреля 2020

Если A - это верхушка ветви feature, а C - это верхушка ветви master:

A //feature
|
B   C //master
|   |
 \ /
  D
git checkout feature //if not on feature

git rebase master //rebase feature onto master

Вы также можете сделать это на любой ветви и получить то же самое результат:

git rebase master feature //rebase feature onto master

Результат:

A //feature
|
B
| 
C //master
|
D

Для быстрой перемотки вперед мастера, чтобы указать на A:

git checkout master //if not on master

git merge feature //merge master with feature

Результат:

A //feature, master
|
B
| 
C 
|
D
...