Это происходило несколько раз, когда у нас есть ветка devel
, над которой над большой функцией (ветвь feature/one
) работают несколько человек. Каждый разработчик ответвляется от feature/one
и выполняет подзадачу. Периодически подзадачи объединяются в feature/one
.
Начальный граф фиксации.
Ветви: devel
отключен от main
, feature/one
отключен от devel
и more-work
отключен от функции/одного. Поскольку main
не влияет на оставшуюся часть этого вопроса, он не отображается ни на каких последующих графиках коммитов.
o--o--o (main)
\
A---B---C (devel)
\
D---E---F (feature/one)
\
G---H (more-work) # one sub-task.
Ветка feature/one
готова к объединению, поэтому сначала ее необходимо перебазировать. Для этого команда git rebase
используется следующим образом:
git checkout devel
git pull
git checkout feature/one
git rebase devel
Эти команды гарантируют, что у вас установлена последняя ветка разработки, а затем вы выполняете перезагрузку на нее.
Итоговый график коммитов git:
A---B---C (devel)
\ \
\ D2--E2--F2 (rebased feature/one)
\
D---E---F (original feature/one, now detached from feature/one branch)
\
G---H (more-work)
Это дает желаемый результат и является обычным случаем, который я успешно использовал много раз.
ПРИМЕЧАНИЕ. Хэш D2 представляет собой фиксацию D, но с новым хешем, аналогично E2 и F2.
Далее я хочу объединить more-work
с feature/one
.
ВАЖНОЕ ПРИМЕЧАНИЕ: ИМО, используя вишневый выбор, будет проще достичь желаемого результата.
Ниже приведены кратные (2 шага), необходимые для использования git rebase –onto feature/one
. Это означает, что more-work
необходимо сначала перебазировать на исходную feature/one
(чтобы включить F
коммит), а затем на rebased feature/one
ветку.
Сначала перебазируйте исходную функцию/функцию, чтобы включить коммит F
. Я не уверен, что это можно сделать с помощью команды git, поэтому она не отображается, но результирующий график коммитов git будет выглядеть так:
A---B---C (devel)
|\ \
| \ D2--E2--F2 (rebased feature/one)
| \
| D---E---F (original feature/one, now detached from feature/one branch)
| \
\ G---H (more-work)
\
D3---E3---F3 (original feature/one rehashed a 2nd time)
\
G2---H2 (more-work (rebased))
На этом этапе перебазированная ветвь more-work
теперь включает в себя изменение, внесенное в хэш F
, что позволяет использовать команду git rebase --onto feature/one
следующим образом:
git rebase --onto feature/one F3-hash more-work
После приведенной выше команды git у нас есть следующий график
A---B---C (devel)
|\ \
| \ D2--E2--F2 (feature/one after rebase)
| \ \
| \ G3---H3 (more-work (rebased-2nd-time))
| \
| D---E---F (original feature/one, now detached from feature/one branch)
| \
\ G---H (more-work)
\
D3---E3---F3 (original feature/one rehashed a 2nd time)
\
G2---H2 (more-work (rebased))
Правильно ли я понимаю, как перебазировать дочернюю ветвь, родительская ветвь которой была перебазирована?
Ниже приведены соответствующие ссылки, которые я нашел, чтобы сформировать мое понимание того, как работает git rebase.
Есть ли способ перебазировать дочернюю ветку после того, как была перебазирована родительская? - этот вопрос/ответ отличается от вопроса здесь тем, что дочерняя ветвь не «обновлена» с родительской ветвью на момент перебазирования родительской ветки. И я считаю, что необходимы многочисленные перебазировки, как я иллюстрирую на своих графиках коммитов.
Как я могу изменить родительскую ветку? Это описано в документации git по адресу https://git-scm.com/docs/git-rebase и показывает, как ветку topic
можно переместить из ветки next
(она же devel
в моем примере) в ветку master
. .
o---o---o---o---o master
\
o---o---o---o---o next
\
o---o---o topic
Самая большая разница между этим и моим вопросом заключается в том, что в моем примере тема не выходит из HEAD следующего.
Команда для перебазирования на master проста.
git rebase --onto master next topic
что приводит к
o---o---o---o---o master
| \
| o'--o'--o' topic
\
o---o---o---o---o next
Другие запросы отвечали на другие вопросы
Перебазирование ветки, разветвленной от - не актуально.
git rebase master с дочерними ветвями - это кажется другим (мне)
Правильно ли я понимаю, как перебазировать дочернюю ветвь, родительская ветвь которой была перебазирована?
Правильный? вроде. Идеально? нет.
Перебазирование more-work
на перебазированное feature/one
может и должно выполняться за один проход. Это именно тот сценарий, для которого был создан rebase --onto
.
* 9a7c139 (HEAD -> more-work) H
* 922d375 G
| * 978c327 (feature/one) F
|/
* bce6cab E
* 3cf018e D
| * 9c2aeeb (devel) C
|/
* 0c5017f B
* 8914d3a A
* fbc5771 (master) Initial commit
feature/one
на devel
git switch feature/one && git rebase devel
* 6f50942 (HEAD -> feature/one) F
* 3cad97b E
* d0f8a97 D
* 9c2aeeb (devel) C
| * 9a7c139 (more-work) H
| * 922d375 G
| * bce6cab E
| * 3cf018e D
|/
* 0c5017f B
* 8914d3a A
* fbc5771 (master) Initial commit
more-work
на feature/one
E_sha1=bce6cab
git rebase --onto feature/one $E_sha1 more-work
* 6cb28df (HEAD -> more-work) H
* 1fc20f8 G
* 6f50942 (feature/one) F
* 3cad97b E
* d0f8a97 D
* 9c2aeeb (devel) C
* 0c5017f B
* 8914d3a A
* fbc5771 (master) Initial commit
Приятно использовать журнал git, чтобы показать это «в действии».
В некотором роде git rebase --onto feature/one E more-work
— это канонический способ сделать это, и вам не нужны два «шага», чтобы выполнить перебазирование. Перебазируйте первую ветку (git rebase deve feature/one
), затем перебазируйте вторую ветку (см. первую команду перебазирования). Команда означает «принять коммиты между F и more-work и создать их копии поверх Feature/One, а затем обновить ветку more-work, чтобы она указывала на новые коммиты». git rebase --onto feature/one F more-work
даст точно такой же результат, поскольку оба диапазона коммитов E..more-work
и F..more-work
описывают один и тот же набор коммитов (т. е. G
и H
).
Итак, начнем с вашей первоначальной истории:
o--o--o (main)
\
A--B--C (devel)
\
D--E--F (feature/one)
\
G--H (more-work)
чтобы добраться до желаемой финальной истории:
o--o--o (main)
\
A--B--C (devel)
\
D--E--F (feature/one)
\
G--H (more-work)
выполните следующие команды по порядку:
git rebase devel feature/one
git rebase --onto feature/one E more-work
# or, same result: git rebase --onto feature/one F more-work
Вы также можете попробовать простой git rebase feature/one more-work
— Git обычно достаточно умен, чтобы определить, какие коммиты уже являются частью нового родителя.
Альтернативой является перебазирование обеих веток одновременно, если вы уже знаете, что одна ветка является прямым потомком другой, а другая ветка полностью содержится в вашей:
A--B--C (devel)
\
D--E--F (feature/one)
\
G--H (more-work)
Чтобы оба перебазировать их в новый восходящий поток:
git rebase --update-refs devel more-work`
Это приведет к перебазированию всех коммитов между devel
и more-work
и обновит вашу ссылку feature/one
(т. е. ветку). Итоговая история будет такой:
A--B--C (devel)
\
D2--E2--F2 (rebased feature/one)
\
G2---H2 (rebased more-work)
На самом деле все это не так уж и отличается от «изменения родительской ветки»: изначально родительская «ветвь» (ветвь — это не что иное, как имя коммита) more-work
была фиксацией E
(предварительная перезагрузка), и вы пытаетесь чтобы изменить его на фиксацию F2
(после перезагрузки). На самом деле не имеет значения, есть ли другие коммиты, которые являются потомками вашей ветки или вашей старой (или новой) ветки.
Но хеш для F3-hash
еще не существует, когда вы запускаете git rebase --onto feature/one F3-hash more-work
, если только вы не выполнили первую перезагрузку. Вы предлагаете это: git rebase --onto feature/one F more-work
? Если да, то я не уверен, как GIT узнает, что я хочу перебазировать коммиты G
и H
.
@PatS извини, ты абсолютно прав; Я скопировал хэш из неправильного ASCII-изображения из вопроса (их было слишком много :)). Я обновил свой ответ некоторыми разъяснениями, надеюсь, теперь он стал яснее. Git знает, что вы хотите перебазировать коммиты G и H, потому что вы указываете ему именно это с помощью команды: G и H — это коммиты между F и more-work (F..more-work
или ^F more-work
разрешается в G и H).
Отличное обновление. Спасибо за пояснение. Я уже выбрал другой ответ в качестве «ответа», потому что он действительно утверждает то, что вы сейчас утверждаете. Если бы я мог выбрать два ответа, я бы это сделал. Добавление update-refs
— это еще одна новинка, о которой я не знал. Еще раз спасибо!
Когда вы сказали: Git обычно достаточно умен, чтобы выяснить, какие коммиты уже являются частью нового родителя. Я создал тестовый репозиторий для эксперимента и с удивлением обнаружил, что git
нашел общие родительские коммиты и проигнорировал их (до сих пор не понимаю, как он это сделал).
@PatS, если перебазируемый коммит имеет тот же набор изменений, что и один из коммитов в родительских элементах, он будет пропущен.
Я пытался выяснить, как git узнает, что коммит тот же, но я не уверен, откуда он это знает. Использует ли git SHA-1 содержимого изменения (то есть измененного файла), чтобы определить, что фиксация совпадает с предыдущей фиксацией? Я думал, что это произошло потому, что в хранилище объектов .git
все еще были отдельные коммиты, но я запустил команду git gc
, чтобы удалить все объекты, и git все равно это понял, поэтому я узнал, что git может выяснить это с другой информацией, хранящейся в коммите. .
@PatS Я не смотрел реализацию, но всегда предполагал, что она будет использовать идентификатор патча . Git может вычислить идентификатор патча перед применением коммита, и если такой же патч уже существует в исходной версии, он будет проигнорирован.
Нет никакой разницы в «изменении родительской ветки». Вы хотите изменить родительскую ветку: с версии вашей ветки до перебазирования (F3) на версию вашей ветки после перебазирования. Ветка — это не что иное, как имя коммита.