У вас есть два прямых и очевидных варианта:
Добавьте второй коммит, который отменяет первый вишневый кир. (Теперь у вас есть исходный снимок, который выглядит так, как будто вы никогда не делали первый выбор вишни.)
Удалите первую вишню, то есть измените историю коммитов.
Какой из них использовать, зависит от многих вещей, в том числе от того, что вы из школы, которая говорит: «никогда не переписывайте историю» (в этом случае вы должны использовать первый подход), или у вас есть дополнительные коммиты, кроме вишни выбранный в порядке графа.
Помните, что каждый коммит Git уникально идентифицируется по своему хеш-идентификатору. Если мы используем заглавные буквы для представления этих коммитов (вместо необработанных хеш-идентификаторов), мы можем нарисовать более четкую картину того, что происходит. Например, предположим, что мы начинаем с этой серии коммитов:
... <-F <-G <-H <--yourbranch (HEAD)
\
I <-J <--origin/theirbranch
Затем вы решаете, что по какой-то причине вам нравится их коммит J
, поэтому вы запускаете git cherry-pick <hash-of-J>
или git cherry-pick theirbranch
. копирует эффект коммита J
, делая новый коммит. Мы можем назвать этот коммит K
, но давайте использовать J'
, чтобы указать, что это копия J
:
...--F--G--H--J' <-- yourbranch (HEAD)
\
I--J <-- origin/theirbranch
В какой-то момент в будущем они - кем бы они ни были - отказались от своего коммита J
в пользу своего нового и улучшенного коммита K
, так что после запуска git fetch
вы получите:
...--F--G--H--J' <-- yourbranch (HEAD)
\
I--K <-- origin/theirbranch
(Фиксация J
полностью исчезла: новый коммит K
указывает непосредственно на I
. Это то «переписывание истории», о котором говорят люди.)
На данный момент вы можете переписать свою собственную историю, используя git reset --hard
. Конечно, это отбрасывает любую работу, которую вы делаете, но давайте предположим, что вы не сделали никакой новой работы, так что все в порядке:
J' [abandoned]
/
...--F--G--H <-- yourbranch (HEAD)
\
I--K <-- origin/theirbranch
Теперь вы можете легко выбирать их коммит K
, поскольку он не конфликтует с вашей копией J'
их оригинала J
. В результате вы получите:
J' [abandoned]
/
...--F--G--H--K' <-- yourbranch (HEAD)
\
I--K <-- origin/theirbranch
Но предположим, с другой стороны, что у вас есть есть работа, которая зависит от вашей J'
копии их J
. Например, предположим, что вы сделали еще полдюжины коммитов с тех пор, как выбрали вишню J
, чтобы получить J'
? Тогда у вас есть это прямо сейчас:
...--F--G--H--J'-L--M--N--O--P--Q <-- yourbranch (HEAD)
\
I--K <-- origin/theirbranch
Теперь вам намного сложнее избавиться от J'
: он встроен в вашу историю, которая простирается от Q
до F
.
Вы можете использовать интерактивное перебазирование (git rebase -i
), чтобы попытаться вырвать J'
из своей истории, скопировав коммиты L-M-N-O-P-Q
в новые коммиты L'-M'-N'-O'-P'-Q'
, которые на много похожи на оригиналы, но пропустить J'
:
J'-L--M--N--O--P--Q [abandoned]
/
...--F--G--H--L'-M'-N'-O'-P'-Q' <-- yourbranch (HEAD)
\
I--K <-- origin/theirbranch
(Обратите внимание, что это выглядит как повторный сбор вишни. Это потому, что git rebase
равен , это повторный сбор вишни!) Но если это слишком болезненно или нежелательно по другим причинам, теперь вы можете сделать новый коммит R
, который отменяет действие вашей копии J'
их оригинала J
, и добавить его в вашу ветку:
...--F--G--H--J'-L--M--N--O--P--Q--R <-- yourbranch (HEAD)
\
I--K <-- origin/theirbranch
Новый коммит R
может быть легко сделать (или нет), запустив:
git revert <hash-of-J>
Команда git revert
сообщает Git: Выясните, что изменилось в данном коммите, и создайте новый коммит, который приведет к отмене этих изменений. Для каждой строки, которую я добавил в какой-либо файл, удалите эту строку из этого файла. Для каждой строки, которую я удалил из некоторого файла, поместите эту строку обратно. Для каждого файла, который я удалил оптом, верните этот файл; для каждого файла, который я создал с нуля, удалите этот файл полностью.
Когда этот процесс завершается, у вас есть моментальный снимок в коммите R
, который выглядит так, как будто фиксация J'
никогда не происходила. (Если ваши изменения в коммитах L
- Q
вступают в конфликт с этой попыткой возврата J'
, вы, как правило, увидите конфликт слияния во время процесса возврата. Обратите внимание, что , если , это так, как правило, вы увидите такие же конфликты, если вы будете использовать интерактивное перебазирование для отмены коммита J'
при копировании L
-through- Q
в новые коммиты.)