Отмена git rebase
-
02-07-2019 - |
Вопрос
Кто-нибудь знает, как легко отменить git rebase?
Единственный способ, который приходит на ум, - сделать это вручную:
- git checkout родительский элемент фиксации для обеих ветвей
- затем создайте оттуда временную ветку
- выбирать все коммиты вручную
- заменить ветку, в которой я перебазировался, на ветку, созданную вручную
В моей нынешней ситуации это сработает, потому что я могу легко обнаружить коммиты из обеих веток (одна была моя, другая — моего коллеги).
Однако мой подход кажется мне неоптимальным и подверженным ошибкам (скажем, я только что перебазировал две свои собственные ветки).
Есть идеи?
Уточнение:Я говорю о ребазе, во время которого переигралась куча коммитов.Не только один.
Решение
Самый простой способ — найти главный коммит ветки, который был непосредственно перед началом перебазирования в файле перерегистрировать...
git reflog
и сбросить к ней текущую ветку (с обычными предостережениями о необходимости быть абсолютно уверенным перед сбросом с помощью --hard
вариант).
Предположим, старый коммит был HEAD@{5}
в журнале ссылок:
git reset --hard HEAD@{5}
В Windows вам может потребоваться процитировать ссылку:
git reset --hard "HEAD@{5}"
Вы можете проверить историю старого руководителя кандидата, просто выполнив git log HEAD@{5}
(Окна: git log "HEAD@{5}"
).
Если вы не отключили рефлоги для каждой ветки, вы можете просто сделать git reflog branchname@{1}
при перебазировании голова ветки отсоединяется перед повторным подключением к последней голове.Я бы проверил это дважды, хотя я не проверял это в последнее время.
По умолчанию все журналы рефлогов активированы для непустых репозиториев:
[core]
logAllRefUpdates = true
Другие советы
На самом деле, rebase сохраняет вашу отправную точку в ORIG_HEAD
так что это обычно так же просто, как:
git reset --hard ORIG_HEAD
Однако reset
, rebase
и merge
все сохраните свой оригинал HEAD
указатель на ORIG_HEAD
Итак, если вы выполнили какую-либо из этих команд после перебазирования, которое пытаетесь отменить, вам придется использовать reflog.
Ответ Чарльза работает, но вы можете сделать это:
git rebase --abort
убраться после reset
.
В противном случае вы можете получить сообщение «Interactive rebase already started
”.
git reflog
покажет вам все изменения до и после перебазирования и позволит вам найти правильный вариант для сброса.Но я удивлен, что никто еще не упомянул здесь еще один очень простой способ:
Rebase оставляет старое состояние как ORIG_HEAD
, поэтому вы можете отменить последнюю перезагрузку, выполнив:
git reset --hard ORIG_HEAD
Сброс ветки к висячему объекту фиксации ее старой подсказки, конечно, является лучшим решением, поскольку он восстанавливает предыдущее состояние без каких-либо усилий.Но если вы случайно потеряли эти коммиты (например.потому что вы тем временем собрали мусор в своем репозитории, или это свежий клон), вы всегда можете снова перебазировать ветку.Ключом к этому является --onto
выключатель.
Допустим, у вас была тематическая ветка, образно названная topic
, что ты отделился master
когда кончик master
был 0deadbeef
совершить.В какой-то момент, находясь на topic
ветка, ты сделал git rebase master
.Теперь вы хотите отменить это.Вот как:
git rebase --onto 0deadbeef master topic
Это возьмет на себя все коммиты topic
этого нет master
и воспроизвести их поверх 0deadbeef
.
С --onto
, вы можете изменить свою историю в значительной степени любая форма, какая бы то ни было.
Веселиться.:-)
На самом деле я помещаю тег резервного копирования в ветку, прежде чем выполнять какую-либо нетривиальную операцию (большинство перебазировок тривиальны, но я бы сделал это, если это выглядит чем-то сложным).
Тогда восстановить так же просто, как git reset --hard BACKUP
.
В случае вы отправили свою ветку в удаленный репозиторий (обычно это источник), а затем вы выполнили успешное перебазирование (без слияния) (git rebase --abort
выдает «Перебазирование не выполняется»), вы можете легко сбросить ветку Использование команды:
git reset --hard origin/{имя ветки}
Пример:
$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is ahead of 'origin/{branchName}' by 135 commits.
(use "git push" to publish your local commits)
nothing to commit, working directory clean
$ ~/work/projects/{ProjectName} $ git reset --hard origin/{branchName}
HEAD is now at 6df5719 "Commit message".
$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is up-to-date with 'origin/{branchName}.
nothing to commit, working directory clean
Если вы не завершили перебазирование и находитесь в его середине, работает следующее:
git rebase --abort
С использованием reflog
у меня не сработало.
То, что сработало для меня, было похоже на описанное здесь.Откройте файл .git/logs/refs, названный в честь ветки, которая была перебазирована, и найдите строку, содержащую «rebase finsihed», что-то вроде:
5fce6b51 88552c8f Kris Leech <me@example.com> 1329744625 +0000 rebase finished: refs/heads/integrate onto 9e460878
Оформите второй коммит, указанный в строке.
git checkout 88552c8f
Убедившись, что это содержит мои потерянные изменения, я разветвился и вздохнул с облегчением.
git log
git checkout -b lost_changes
При использовании нескольких коммитов помните, что любой коммит ссылается на всю историю, предшествовавшую этому коммиту.Итак, в ответе Чарльза прочтите «старый коммит» как «самый новый из старых коммитов».Если вы вернетесь к этому коммиту, вся история, предшествовавшая этому коммиту, появится снова.Это должно делать то, что вы хотите.
Следуя решению @Allan и @Zearin, мне бы хотелось просто оставить комментарий, но у меня недостаточно репутации, поэтому я использовал следующую команду:
Вместо того, чтобы делать git rebase -i --abort
(Обратите внимание -я) Мне пришлось просто сделать git rebase --abort
(без тот -я).
Использование обоих -i
и --abort
в то же время заставляет Git показывать мне список использования/опций.
Итак, мой предыдущий и текущий статус ветки с этим решением:
matbhz@myPc /my/project/environment (branch-123|REBASE-i)
$ git rebase --abort
matbhz@myPc /my/project/environment (branch-123)
$
Если вы успешно перебазировали удаленную ветку и не можете git rebase --abort
вы все равно можете сделать некоторые трюки, чтобы сохранить свою работу и избежать принудительных нажатий.Предположим, ваша текущая ветка, которая была перебазирована по ошибке, называется your-branch
и отслеживает origin/your-branch
git branch -m your-branch-rebased
# переименовываем текущую веткуgit checkout origin/your-branch
# проверка до последнего состояния, происхождение которого известноgit checkout -b your-branch
- проверять
git log your-branch-rebased
, по сравнению сgit log your-branch
и определить коммиты, которые отсутствуют вyour-branch
git cherry-pick COMMIT_HASH
за каждый коммит вyour-branch-rebased
- продвигайте свои изменения.Обратите внимание, что два местных филиала связаны с
remote/your-branch
и вам следует нажать толькоyour-branch
Допустим, я перебазирую master в свою функциональную ветку и получаю 30 новых коммитов, которые что-то нарушают.Я обнаружил, что зачастую проще всего просто удалить плохие коммиты.
git rebase -i HEAD~31
Интерактивное перебазирование для последнего 31 коммита (не повредит, если вы выберете слишком много).
Просто возьмите коммиты, от которых вы хотите избавиться, и отметьте их буквой «d» вместо «pick».Теперь коммиты удаляются, что фактически отменяет перебазирование (если вы удаляете только те коммиты, которые вы только что получили при перебазировании).
Если вы находитесь в ветке, вы можете использовать:
git reset --hard @{1}
Существует не только справочный журнал для HEAD (полученный git reflog
), для каждой ветки также есть релоги (полученные git reflog <branch>
).Итак, если вы находитесь на master
затем git reflog master
перечислит все изменения в этой ветке.Вы можете обратиться к этим изменениям, master@{1}
, master@{2}
, и т. д.
git rebase
обычно меняет HEAD несколько раз, но текущая ветка будет обновлена только один раз.
@{1}
это просто ярлык для текущей ветки, поэтому оно равно master@{1}
если ты включен master
.
git reset --hard ORIG_HEAD
не будет работать, если вы использовали git reset
во время интерактивного rebase
.
Для новичков или тех, кто слишком боится делать полный сброс, вы можете извлечь коммит из журнала обновлений, а затем сохранить его как новую ветку.
git reflog
Найдите коммит непосредственно перед тем, как вы начали перебазирование.Возможно, вам придется прокрутить страницу вниз, чтобы найти его (нажмите Enter или PageDown).Обратите внимание на номер HEAD и замените 57:
git checkout HEAD@{57}
Просмотрите ветку/коммит, если она выглядит хорошо, создайте новую ветку, используя этот HEAD:
git checkout -b new_branch_name
git reset --hard origin/{имя ветки}
это правильное решение для сброса всех локальных изменений, выполненных путем перебазирования.
Обычно я делаю следующее:git reset #commit_hash
до последнего коммита, где, я думаю, перебазирование не имело никакого эффекта.
затем git pull
Теперь ваша ветка должна совпадать с основной, и в ней не должно быть перебазированных коммитов.
Теперь можно просто выбрать коммиты в этой ветке.
Если вы что-то испортили при перезагрузке git, например. git rebase --abort
, хотя у вас есть незафиксированные файлы, они будут потеряны и git reflog
не поможет.Это случилось со мной, и вам придется мыслить нестандартно.Если вам повезло, как и мне, и вы используете IntelliJ Webstorm, вы можете right-click->local history
и может вернуться к предыдущему состоянию вашего файла/папки независимо от того, какие ошибки вы допустили с помощью программного обеспечения для управления версиями.Всегда хорошо иметь еще один отказоустойчивый вариант.