Как отменить успешный «мерзавец»?

104

На локальном репо я только что выполнил git cherry-pick SHAбез каких-либо конфликтов или проблем. Затем я понял, что не хочу делать то, что только что сделал. Я никуда этого не толкал.

Как я могу удалить только эту вишенку?

Я хотел бы знать, есть ли способ сделать это:

  • когда у меня есть другие локальные изменения
  • когда у меня нет других местных изменений

Если возможно, желательно с одной командой в обоих случаях.

Брэд Паркс
источник

Ответы:

142

Выбор вишни - это в основном фиксация, поэтому, если вы хотите отменить ее, вы просто отменяете фиксацию.

когда у меня есть другие локальные изменения

Сохраните текущие изменения, чтобы вы могли повторно применить их после сброса фиксации.

$ git stash
$ git reset --hard HEAD^
$ git stash pop  # or `git stash apply`, if you want to keep the changeset in the stash

когда у меня нет других местных изменений

$ git reset --hard HEAD^
Тим
источник
6
Просто в дополнение к вопросу и ответу, если вы не уверены, что вы выбираете, вы всегда можете выбрать SHA Cherry --no-commit, и не будет никаких изменений только для фиксации, которые можно легко проверить , это полезно для частичного сбора вишни
kuskmen 06
2
windows: git reset --hard "HEAD ^"
slim
25

Чтобы отменить последнюю фиксацию, просто сделайте это git reset --hard HEAD~.

Изменить : этот ответ относился к более ранней версии вопроса, в которой не упоминалось сохранение локальных изменений; принятый ответ Тима действительно правильный. Спасибо qwertzguy за внимание.

Дэвид Дойч
источник
2
Это должно быть HEAD ^ или HEAD ~ 1
Андреас Ведербранд
Оба они эквивалентны HEAD ~ (и HEAD ^ 1, если на то пошло)
Дэвид Дойч
1
@DavidDeutsch Это правда (хотя только в более поздних версиях Git), но верхний регистр ( HEAD) более надежен: рассмотрим неудачный случай, когда headэто имя существующей ссылки.
jub0bs
1
@Jubobs - хорошее замечание; В своем ответе я поменял корпус.
Дэвид Дойч
1
@qwertzguy, хороший улов; глядя на временные метки, через минуту после того, как я опубликовал этот ответ, к вопросу был добавлен бит о локальных изменениях :)
Дэвид Дойч
9

По возможности избегайте аппаратных сбросов. Жесткий сброс - одна из очень немногих деструктивных операций в git. К счастью, вы можете отменить выборку без сброса и избежать чего-либо разрушительного.

Обратите внимание на хеш выборки, которую вы хотите отменить, скажем так ${bad_cherrypick}. Сделатьgit revert ${bad_cherrypick} . Теперь содержимое вашего рабочего дерева такое же, как и до вашего неудачного выбора.

Повторите git cherry-pick ${wanted_commit}, и когда вы будете довольны новым выбором вишни, сделайте git rebase -i ${bad_cherrypick}~1. Во время перебазирования удалите оба${bad_cherrypick} и соответствующий откат.

В ветке, над которой вы работаете, будет только хороший выбор. Сброс не требуется!

Cuadue
источник
7

git reflog может прийти вам на помощь.

Введите его в свою консоль, и вы получите список вашей истории git вместе с SHA-1, представляющим их.

Просто проверьте любой SHA-1, к которому вы хотите вернуться


Прежде чем ответить, давайте добавим немного предыстории, объясняя, что это такое HEAD.

First of all what is HEAD?

HEADпросто ссылка на текущую фиксацию (самую последнюю) в текущей ветке.
В HEADлюбой момент времени может быть только один . (исключаяgit worktree )

Содержимое HEADхранится внутри .git/HEADи содержит 40 байт SHA-1 текущего коммита.


detached HEAD

Если вы не в последней фиксации - это означает, что HEADэто указывает на предыдущую фиксацию в истории, которую он вызывает detached HEAD.

введите описание изображения здесь

В командной строке это будет выглядеть так: SHA-1 вместо имени ветки, поскольку HEADне указывает на конец текущей ветки.

введите описание изображения здесь

введите описание изображения здесь

Несколько вариантов восстановления после отключенной HEAD:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

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

# Checkout a given commit. 
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

Вы всегда можете использовать reflogтакже.
git reflogотобразит любое изменение, которое обновило HEADфайл, и проверка нужной записи в журнале reflog HEADвернет этот коммит обратно.

Каждый раз, когда ГОЛОВА изменяется, в reflog

git reflog
git checkout HEAD@{...}

Это вернет вас к желаемой фиксации

введите описание изображения здесь


git reset --hard <commit_id>

«Переместите» вашу ГОЛОВУ обратно к желаемой фиксации.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
  • Примечание. ( Начиная с Git 2.7 )
    вы также можете использовать git rebase --no-autostash.

git revert <sha-1>

«Отменить» данную фиксацию или диапазон фиксации.
Команда сброса "отменит" любые изменения, сделанные в данной фиксации.
Новая фиксация с патчем отмены будет зафиксирована, а исходная фиксация также останется в истории.

# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>

Эта схема показывает, какая команда что делает.
Как видите, reset && checkoutизмените файл HEAD.

введите описание изображения здесь

CodeWizard
источник
возможно добавитьgit reset --hard
wyx
4

Столкнувшись с той же проблемой, я обнаружил, что если вы совершили и / или нажали на удаленный доступ после успешного выбора вишни, и вы хотите удалить его, вы можете найти SHA вишневого выбора, запустив:

git log --graph --decorate --oneline

Затем (после использования :wqдля выхода из журнала) вы можете удалить выборку с помощью

git rebase -p --onto YOUR_SHA_HERE^ YOUR_SHA_HERE

где YOUR_SHA_HEREравно 40- или сокращенному 7-значному SHA выбранной фиксации.

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

git push --force origin YOUR_REPO_NAME

(Я адаптировал это решение от Сета Робертсона : см. «Удаление всей фиксации».)

брокер
источник
1

Одна команда и не использует деструктивную git resetкоманду:

GIT_SEQUENCE_EDITOR="sed -i 's/pick/d/'" git rebase -i HEAD~ --autostash

Он просто сбрасывает фиксацию, возвращая вас точно в состояние до выбора вишни, даже если у вас были локальные изменения.

qwertzguy
источник
Он просто сбрасывает фиксацию. как вы думаете, что git reset HEAD^делает?
Тим
@TimCastelijns git resetотменяет действие фиксации без отмены каких-либо изменений. Я рекомендую вам прочитать git-scm.com/docs/git-reset . Вопрос от OP - отменить выбор вишни. Попробуйте обе команды, моя вернет вас в то же состояние, в котором вы были до выбора вишни. git resetиспортит ваше рабочее дерево, поскольку оно оставит выбранные вами изменения, и они станут неотличимы от ваших ранее существовавших локальных изменений.
qwertzguy
да, извините, я имел в виду reset --hard. Не оставляет никаких изменений
Тим
1
@TimCastelijns git reset --hard- это деструктивная команда, которая также удалит несвязанные локальные изменения и сделает это безвозвратно! Так что ОП просила не об этом.
qwertzguy
2
Этот ответ был бы гораздо полезнее, если бы вы объяснили, что делает эта sedкоманда, чем она отличается от выполнения вручную и что --autostashделает.
Крис Пейдж