Git: Отменить все коммиты в ветви функций до последнего коммита - PullRequest
0 голосов
/ 22 января 2019

У меня есть ветка, которая получила ошибочную историю коммитов из-за принудительного нажатия в нашей ветке master. В основном у меня есть следующие коммиты в этой истории веток: A, B, C, D, E, где E должно быть сохранено, но ABCD должно быть удалено. Они были добавлены из-за слияния мастера с веткой до того, как эти коммиты были принудительно удалены из источника происхождения. Как я могу сделать это?

Если бы А был тем, кого нужно сохранить, я мог бы просто выполнить git reset --hard A, но это другое направление ...

Ответы [ 3 ]

0 голосов
/ 22 января 2019

Вы можете использовать git reset --hard A^, чтобы перейти к последнему "хорошему" коммиту, а затем git cherry-pick E, чтобы применить коммит, который вы хотите сохранить.

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

0 голосов
/ 22 января 2019

Опция с перебазированием + drop

Поскольку Ромен предложил "rebase - это другое", вот один из способов сделать это, предполагая, что вы хотите, чтобы конечный результат @-A-B-C-D-E был @-E, как спросил Лассе.

Я предлагаю это так же, как другой инструмент в вашем наборе инструментов : это , а не более простое решение этой проблемы. Однако он позволяет вам удалить коммиты, которые не находятся в последовательности (например, удалить A, C, E и сохранить B, D):

git rebase -i HEAD~6

, который откроет ваш редактор (вероятно, vi) с буфером, который выглядит следующим образом:

pick 4231648cb4 Some previous commit
pick 4bccf2ce81 A some message
pick 7b4cd5ff17 B some message
pick faa44efb7c C some message
pick 0ce0525a79 D some message
pick f104648cc3 E some message

# Rebase 76eb9131b5..ed71142fcb onto 4231648cb4 (6 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

Да, порядок коммитов сверху вниз находится в обратном временном порядке (обратный git log) с последними в нижней части. Вот почему «строки выполняются сверху вниз» - от самых старых до самых последних.

Следуя инструкциям, измените слово pick на d (или drop) в строках, которые вы хотите удалить.

pick 4231648cb4 Some previous commit
d 4bccf2ce81 A some message
d 7b4cd5ff17 B some message
d faa44efb7c C some message
d 0ce0525a79 D some message
pick f104648cc3 E some message

Если вы допустили неисправимую ошибку, например, удалили строку, прервитесь, выйдя без сохранения (:q!), и повторите попытку.

Если все выглядит хорошо, сохраните и выйдите из буфера (:wq) и продолжайте перебазирование, пока ваша ветвь не будет исправлена.

Если после этого случается что-то нехорошее (например, вы изменили хеш коммита на тот, который не существует, или rebase перестает что-то делать, и вы не знаете почему), вы можете полностью прервать ребаз с помощью git rebase --abort, что вернуть вас в исходное состояние.

Если ваша ветвь выглядит правильно, нажмите принудительно.

git push -f

Важное замечание о силовом толкании

Вероятно, малоизвестно, но стратегия push по умолчанию перед git 2 равна matching, то есть, когда вы git push, он будет толкать все ваши локальные ветви с соответствующими именами удаленных веток, а не только ваши текущая ветка.

Так что, когда вы git push -f, это заставит всех ваших веток (это случилось с коллегой только вчера). Проверьте с git config --global push.default. Это означает, что если вы играете с какой-то другой веткой, это тоже может заставить ее толкнуть.

Я бы предложил изменить стандартную стратегию push на simple, если это еще не так. Это значение по умолчанию для git 2.

Защита ветви

Если вы используете централизованно размещенное git-решение, такое как Stash / BitBucket, Gitlab или Github, все они предлагают так называемые правила "защиты веток", чтобы, среди прочего, не дать разработчикам принудительно перейти на ветки.

Добавить правило для предотвращения принудительного нажатия на master и, возможно, release ответвлений.

0 голосов
/ 22 января 2019
# make a backup of the current state of your branch
git branch backup your_branch

# reset to the commit prior to A
git reset --hard A^

# then re-apply E
git cherry-pick E

был бы способ сделать это. Rebase является еще одним (см. очень подробный ответ MSanford на эту тему)

...