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

2580

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

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

  • git проверить родительский элемент фиксации на обеих ветвях
  • затем создайте ветвь темпа
  • Черри-выберите все фиксации вручную
  • замените ветвь, в которой я переустановил ветвь, созданная вручную

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

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

Любые идеи?

Уточнение: я говорю о переустановке, в ходе которой была переиграна куча коммитов. Не только один.

  • 5
    Также обратите внимание, что во время перебазировки вы можете исключить коммиты или раздавить их; эти изменения необратимы без указания указателя на исходные узлы или просеивания рефлога, поэтому выбор вишни не будет работать.
Теги:
git-rebase
rebase
undo

17 ответов

3734
Лучший ответ

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

git reflog

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

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

git reset --hard HEAD@{5}

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

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

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

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

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

[core]
    logAllRefUpdates = true
  • 84
    Git reflog великолепен, просто помните, что вы можете получить лучший форматированный вывод с помощью git log -g (подсказка Скотта Чакона из progit.org/book ).
  • 0
    В ответе Аллана ниже необходим git rebase -i --abort . Одного вышесказанного недостаточно.
Показать ещё 16 комментариев
1204

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

git reset --hard ORIG_HEAD

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

  • 0
    Это именно то, что мне было нужно, я сделал ошибку, используя rebase с git tfs. Это вернуло меня к точке, где я мог совершить.
  • 0
    Не работал для меня Я провозил ребаз. Сделал ли git reset как вы предлагаете, теперь git log показывает некоторые все еще перебазированные коммит-сообщения и полностью пропускает другие.
Показать ещё 8 комментариев
330

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

git rebase --abort

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

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

  • 3
    Этот удалил часть «| REBASE» в моей подсказке. +1
  • 8
    Я думаю, что это должен быть git rebase --abort в (возможно, в зависимости от вашей версии git).
Показать ещё 2 комментария
79

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

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

git rebase --onto 0deadbeef master topic

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

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

Получайте удовольствие.: -)

  • 2
    Я думаю, что это лучший вариант из-за его гибкости. Я разветвлял b1 от master, затем переназначил b1 в новую ветвь b2, затем хотел вернуть b1, чтобы он снова был основан на master. Я просто люблю мерзавца - спасибо!
  • 2
    Это лучший вариант здесь! Он сохранил все изменения, которые у меня есть в моей текущей ветке, и удалил все ненужные!
Показать ещё 1 комментарий
64

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

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

  • 2
    Я тоже так делаю. Также полезно сделать команду diff BACKUP..HEAD, чтобы убедиться, что вы изменили то, что хотели.
  • 1
    Эта основная мера предосторожности спасла мою задницу много раз ... ошибки с перебазированием обходятся дорого.
Показать ещё 5 комментариев
57

Я удивлен, что никто еще не упомянул об этом здесь. Rebase оставляет прежнее состояние как ORIG_HEAD, поэтому вы можете вернуть последнюю rebase, запустив:

git reset --hard ORIG_HEAD
  • 1
    Это работает только до тех пор, пока вы не вызовете 'git reset' вручную во время интерактивной перезагрузки! Кроме того, моя текущая версия git (2.20.1), кажется, изменяет ORIG_HEAD, если вы применяете фиксацию фиксации во время перебазирования.
53

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

git reset - неправильное начало/{название ветки}

Пример:

$ ~/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
  • 0
    Это правильный ответ для меня. Rebase и commit до rebase имели одинаковые идентификаторы коммитов, и возвращение к HEAD {1} просто не вернет rebase!
53

Если вы не закончили rebase и посередине, выполните следующие действия:

git rebase --abort
  • 0
    Это сработало для меня. У меня были конфликты слияния, поэтому он квалифицировался как «в середине».
16

Использование reflog не помогло мне.

Что сработало для меня, было похоже на описанный здесь. Откройте файл .git/logs/refs, названный в честь ветки, которая была переустановлена, и найдите строку, содержащую "rebase finsihed", что-то вроде:

5fce6b51 88552c8f Kris Leech <[email protected]> 1329744625 +0000  rebase finished: refs/heads/integrate onto 9e460878

Оформить вторую фиксацию, указанную в строке.

git checkout 88552c8f

Как только это подтвердилось, мои потерянные изменения я разветкил и вздохнул с облегчением.

git log
git checkout -b lost_changes
  • 0
    или это: stackoverflow.com/questions/1108853/…
  • 2
    Вау - по той ссылке: «Есть одно предупреждение: я потерял историю ветки, но в этом случае это не имело значения. Я был просто счастлив получить мои изменения». ?
15

Для нескольких коммитов помните, что любая фиксация ссылается на всю историю, ведущую к этой фиксации. Поэтому в ответе Чарльза читайте "старый фиксат" как "самый новый из старых коммитов". Если вы reset, чтобы зафиксировать это, тогда вся история, ведущая к этой фиксации, снова появится. Это должно делать то, что вы хотите.

11

Следуя решению @Allan и @Zearin, я хотел бы просто сделать комментарий, хотя, но у меня недостаточно репутации, поэтому я использовал следующую команду:

Вместо git rebase -i --abort (обратите внимание на -i) мне просто нужно было сделать git rebase --abort (без -i).

Используя как -i, так и --abort, в то же время вызывает Git, чтобы показать мне список использования/параметров.

Таким образом, мой предыдущий и текущий статус ветки с этим решением:

matbhz@myPc /my/project/environment (branch-123|REBASE-i)
$ git rebase --abort

matbhz@myPc /my/project/environment (branch-123)
$
10

Если вы успешно переустановили удаленный филиал и не можете git rebase --abort, вы все равно можете сделать некоторые трюки, чтобы сохранить свою работу и не иметь принудительных нажатий. Предположим, что ваша текущая ветка, которая была перепутана по ошибке, называется your-branch и отслеживает origin/your-branch

  • git branch -m your-branch-rebased # переименовать текущую ветку
  • git checkout origin/your-branch # checkout к последнему состоянию, известному происхождению
  • 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
6

Просто:

git rebase --abort

?

3

Скажем, я переустанавливаю мастера на свою ветку функций, и я получаю 30 новых коммитов, которые что-то ломают. Я обнаружил, что часто проще всего просто удалить плохие коммиты.

git rebase -i HEAD~31

Интерактивная перестановка для последних 31 фиксации (это не больно, если вы слишком много выбираете).

Просто возьмите коммиты, от которых вы хотите избавиться, и пометьте их "d" вместо "pick". Теперь коммиты удаляются, эффективно уничтожая rebase (если вы удаляете только те коммиты, которые вы только что получили при перезагрузке).

0

Если вы находитесь на ветке, вы можете использовать:

git reset --hard @{1}

Существует не только справочный журнал для HEAD (полученный с помощью git reflog), но также есть и reflogs для каждой ветки (полученный с помощью 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.

-4

Если вы повредите что-то в рамках git rebase --abort git, например git rebase --abort, в то время как у вас есть незафиксированные файлы, они будут потеряны, а git reflog не поможет. Это случилось со мной, и вам нужно будет подумать нестандартно. Если вам повезло, как я, и используйте IntelliJ Webstorm, вы можете щелкнуть right-click->local history кнопкой мыши по right-click->local history и вернуться к предыдущему состоянию вашего файла/папок независимо от того, какие ошибки вы совершили с помощью программного обеспечения для управления версиями. Всегда хорошо иметь еще один отказоустойчивый ход.

  • 3
    git rebase --abort прекращает активную перебазироваться, не отменить перебазирования. Кроме того, использование двух VCS одновременно является плохой идеей. Это хорошая функция в программном обеспечении Jetbrains, но вы не должны использовать оба. Лучше просто изучать Git, особенно когда отвечаете на вопросы о переполнении стека, касающиеся Git.
-8

Чтобы отменить, вы можете ввести следующую команду:

git -c core.quotepath=false rebase --abort

Ещё вопросы

Сообщество Overcoder
Наверх
Меню