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

#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, но с разными идентификаторами фиксации (потому что каждый раз, когда вы переписываете фиксацию, вы буквально делаете новую фиксацию, и, следовательно, идентификатор изменится).

Некоторые Мысли:

  1. Вполне возможно, что вы столкнетесь с конфликтами в команде «Выбор вишни». Это произойдет, если какое-либо из последующих коммитов будет D зависеть от любого из коммитов, из которых вы выходите master . Если это произойдет, вы, возможно, захотите полностью пересмотреть это действие.
  2. В Git часто существует множество различных способов сделать одно и то же. Обратите внимание, что вы действительно можете поменять reset cherry-pick местами команды и и сделать все это одним выстрелом с помощью одной «фантазии» rebase --onto . Но концептуально я думаю, что выполнить сброс, а затем выбрать набор коммитов, которые легче понять в явном виде. Перебазирование просто делает и то, и другое за кулисами.
  3. В команде 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 Я обновил свой ответ, чтобы показать, каковы будут результирующие ветви. Я думаю, что это то, чего ты хочешь. И то, что вы делаете в своей вилке, не коснется первоначального репо, если (или пока) вы не подтолкнете что-то к нему.