Отмена мерзавца - PullRequest
       125

Отмена мерзавца

2762 голосов
/ 25 сентября 2008

Кто-нибудь знает, как легко отменить git rebase?

Единственный способ, который приходит на ум, - это взяться за это вручную:

  • git checkout родительский коммит для обеих ветвей
  • затем создайте временную ветку оттуда
  • Вишня выбирает все коммиты вручную
  • заменить ветку, в которую я перебазировал ветку, созданную вручную

В моей нынешней ситуации это сработает, потому что я легко могу определить коммиты из обеих веток (одна была моей, другая - коллегой).

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

Есть идеи?

Разъяснение: я говорю о ребазе, во время которого была повторена группа коммитов. Не только один.

Ответы [ 17 ]

3794 голосов
/ 25 сентября 2008

Самым простым способом было бы найти главный коммит ветви, как это было непосредственно перед началом перебазировки в reflog ...

git reflog

и сбросить текущую ветвь к ней (с обычными предостережениями о полной уверенности перед перезагрузкой с опцией --hard).

Предположим, что старая фиксация была HEAD@{5} в журнале ссылок:

git reset --hard HEAD@{5}

В Windows вам может потребоваться указать ссылку:

git reset --hard "HEAD@{5}"

Вы можете проверить историю старого кандидата, просто выполнив команду git log HEAD@{5} ( Windows: git log "HEAD@{5}").

Если вы не отключили повторные журналы для каждой ветви, вы можете просто сделать git reflog branchname@{1}, так как ребаз отсоединяет головку ветви перед повторным присоединением к последней. Я бы дважды проверил это, хотя я не проверял это недавно.

По умолчанию все reflogs активируются для не голых репозиториев:

[core]
    logAllRefUpdates = true
1340 голосов
/ 28 марта 2009

На самом деле, rebase сохраняет вашу начальную точку до ORIG_HEAD, поэтому обычно это просто:

git reset --hard ORIG_HEAD

Однако reset, rebase и merge все сохраняют ваш исходный указатель HEAD в ORIG_HEAD, поэтому, если вы выполнили какую-либо из этих команд после перезагрузки, которую вы пытаетесь отменить, вам придется использовать reflog.

346 голосов
/ 27 июля 2009

Ответ Чарльза работает, но вы можете сделать это:

git rebase --abort

для очистки после reset.

В противном случае вы можете получить сообщение «Interactive rebase already started».

100 голосов
/ 24 июля 2018

git reflog покажет вам все изменения до и после перезагрузки, и позволит вам найти подходящее для сброса. Но я удивлен, что никто еще не упомянул этот другой супер простой способ:

Rebase оставляет старое состояние как ORIG_HEAD, поэтому вы можете отменить последнюю перезагрузку, выполнив:

git reset --hard ORIG_HEAD
81 голосов
/ 26 сентября 2008

Сброс ветвления к висячему объекту фиксации его старого наконечника, конечно же, является лучшим решением, потому что он восстанавливает предыдущее состояние без дополнительных усилий. Но если вы потеряли эти коммиты (например, из-за того, что тем временем вы собрали мусор в своем хранилище, или это новый клон), вы всегда можете перебазировать ветку снова. Ключ к этому - переключатель --onto.

Допустим, у вас была ветвь темы с образным названием topic, которую вы разветвили master, когда кончик master был коммитом 0deadbeef. В какой-то момент в ветке topic вы сделали git rebase master. Теперь вы хотите отменить это. Вот как это сделать:

git rebase --onto 0deadbeef master topic

Это примет все коммиты на topic, которые не на master и воспроизведет их поверх 0deadbeef.

С помощью --onto вы можете изменить свою историю в значительной степени в любой форме .

Веселитесь. : -)

68 голосов
/ 13 мая 2009

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

Затем восстановление так же просто, как git reset --hard BACKUP.

59 голосов
/ 28 сентября 2015

В случае, если вы переместили свою ветку в удаленный репозиторий (обычно это источник), а затем сделали успешную перебазировку (без слияния) (git rebase --abort дает "Нет перебазирования в процессе"), вы можно легко сбросить ветку используя Команда:

git reset --hard origin / {branchName}

Пример:

$ ~/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
51 голосов
/ 16 октября 2014

Если вы еще не выполнили ребаз и в середине его, работает следующее:

git rebase --abort
19 голосов
/ 20 февраля 2012

Использование 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
15 голосов
/ 26 сентября 2008

Для нескольких коммитов помните, что любой коммит ссылается на всю историю, ведущую к этому коммиту. Так что в ответе Чарльза прочитайте «старый коммит» как «самый новый из старых коммитов». Если вы вернетесь к этому коммиту, то снова появится вся история, ведущая к этому коммиту. Это должно делать то, что вы хотите.

...