#git #github #branch #rebase #branching-and-merging
Вопрос:
Я работал над функцией локально и сделал пару коммитов в своей основной ветке (вместо того, чтобы создавать отдельную ветку и работать там). Затем я отправил эти коммиты в свою удаленную главную ветвь на GitHub (которая на самом деле является развилкой другого репозитория). Прошло некоторое время, прежде чем я понял ошибку, и в удаленную главную ветвь были добавлены новые коммиты. Теперь я хочу вернуться и создать отдельную ветвь для этой начальной функции. Как бы я это сделал?
Чтобы проиллюстрировать мою проблему, вот что у меня есть:
master A - B - C - D - E - F
Это то, чего я хочу:
newbranch C - D
/
master A - B ---- E - F
где фиксации C, D
-это начальная функция, для которой я забыл создать новую ветвь.
Комментарии:
1. Значит, вы на самом деле не хотите, чтобы C и D были включены
master
? Так ли это, что и E, и F ни от чего не зависят в C или D?2. И, если вы хотите удалить фиксации
master
, все ли, кто использует это репо, согласны переписать недавнюю историюmaster
? (В больших командах или публичных репозиториях ответ обычно отрицательный.)3. То, как вы нарисовали свою картину двух ветвей, вводит в заблуждение, и это может быть важно (для меня не очевидно, важно ли это): Git-коммиты не «застревают» на однажды созданной ветке. Сначала совершаются коммиты Git, после чего многим именам ветвей разрешается содержать любой заданный набор коммитов . Если
newbranch
содержит фиксациюD
, иD
ссылки фиксации обратно в фиксациюC
, иC
ссылки фиксации обратно в фиксациюB
, иmaster
содержит фиксациюB
, то обе ветви содержат фиксациюB
.4. Я рекомендую вам поработать над тем, чтобы думать Как (а) Мерзавец , после чего вы будете рисовать свои ветви по-другому.: -)
5. @torek Я думал о том же самом. Затем я решил, что на 90% уверен, что знаю, о чем спрашивает ОП, несмотря на то, что картинка неверна. 😀
Ответ №1:
Предостережение: обычно считается плохой практикой переписывать общие ветви, такие как master
. Вы захотите убедиться, что все, кто использует репо, знают, что вы это делаете.
Тем не менее, как и просили, вы могли бы сделать это:
# NOTE - this assumes your remote is called "origin"
git fetch
# create a branch called "newbranch" that points to commit hash D
git branch newbranch D
# checkout master so you can fix it up
git switch master
# change master to point to B
git reset --hard B
# Replay E through F (or any new commits if they exist!) onto master
git cherry-pick E..origin/master
# replace the remote master (make sure everyone is OK with it!)
git push --force-with-lease
Результаты этих команд сделают ваши две ветви похожими:
newbranch: A-B-C-D
master: A-B-E'-F'
Примечание E'
F'
. обозначение и указывает, что эти фиксации будут похожи на E и F, но с разными идентификаторами фиксации (потому что каждый раз, когда вы переписываете фиксацию, вы буквально делаете новую фиксацию, и, следовательно, идентификатор изменится).
Некоторые Мысли:
- Вполне возможно, что вы столкнетесь с конфликтами в команде «Выбор вишни». Это произойдет, если какое-либо из последующих коммитов будет
D
зависеть от любого из коммитов, из которых вы выходитеmaster
. Если это произойдет, вы, возможно, захотите полностью пересмотреть это действие. - В Git часто существует множество различных способов сделать одно и то же. Обратите внимание, что вы действительно можете поменять
reset
cherry-pick
местами команды и и сделать все это одним выстрелом с помощью одной «фантазии»rebase --onto
. Но концептуально я думаю, что выполнить сброс, а затем выбрать набор коммитов, которые легче понять в явном виде. Перебазирование просто делает и то, и другое за кулисами. - В команде cherry-pick причина, по которой я предлагаю перейти от фиксации
E
кorigin/master
вместо очевидногоE
кF
, заключается просто в том, что вы упомянули: «в удаленную главную ветвь было добавлено больше фиксаций». В случае, если будет добавлено еще больше, о которых вы не знаете до вашей первоначальнойgit fetch
команды в начале этого ответа, таким образом, вы также сохраните любые новые неизвестные коммиты.
Комментарии:
1. Спасибо @TTT. Позвольте мне более четко объяснить ситуацию. В основном, я работал над добавлением документации для проекта, и я забыл создать новую ветвь, прежде чем перейти к своей развилке репозитория и создать свой PR. И прежде чем я это понял, мой пиар был объединен и эти коммиты . Все, что я делал, полностью не зависит от того, что было сделано до/после. Однако теперь эти коммиты включены в историю моей главной ветви, и каждый раз, когда я делаю новый PR, эти коммиты также включаются в PR, потому что они считаются «впереди» основного репозитория, и это беспорядок.
2. Кроме того, поскольку это вилка, и никто, кроме меня, ею не пользуется, не испортит ли она основное хранилище? (Я сделал несколько пиаров)
3. @NicolasBoyer Я почти уверен , что ты не хочешь, чтобы C и D были включены
master
, верно? Такmaster
стало бы A-B-E’-F’ ? (Я использую E’ и F’ там, потому что идентификаторы фиксации изменятся, но содержание изменений будет таким же, как E и F.)4. @NicolasBoyer Если ответ » да » (вы вообще не хотите, чтобы C и D включались
master
), то вам нужно будет удалить строку, идущую от D до E. Обратите внимание, что вы бы оставили строку, идущую от B до C, потомуnewbranch
что становится: A-B-C-D.5. @NicolasBoyer Я обновил свой ответ, чтобы показать, каковы будут результирующие ветви. Я думаю, что это то, чего ты хочешь. И то, что вы делаете в своей вилке, не коснется первоначального репо, если (или пока) вы не подтолкнете что-то к нему.