Як скасувати успішний “git cherry-pick”?


99

У локальному репо, я щойно виконував git cherry-pick SHAбез жодних конфліктів чи проблем. Тоді я зрозумів, що не хочу робити те, що щойно зробив. Я цього нікуди не штовхав.

Як я можу видалити лише цю вишневу кірку?

Я хотів би знати, чи є спосіб зробити це:

  • коли у мене інші місцеві зміни
  • коли я не маю інших локальних змін

Бажано з однією командою для обох випадків, якщо це можливо.

Відповіді:


134

Вишневий вибір - це в основному коміт, тому, якщо ви хочете його скасувати, ви просто скасуєте коміт.

коли у мене інші місцеві зміни

Зберігайте свої поточні зміни, щоб ви могли повторно застосувати їх після скидання коміту.

$ 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 --no-commit", і не буде жодних змін, які можна легко перевірити , це корисно для часткового збору вишні
kuskmen

2
windows: git reset --hard "HEAD ^"
тонкий

22

Щоб скасувати останню фіксацію, просто виконайте git reset --hard HEAD~.

Редагувати : ця відповідь стосувалася попередньої версії питання, в якій не згадувалося про збереження місцевих змін; прийнята відповідь Тіма справді правильна. Дякую qwertzguy за підняті голови.


2
Це має бути HEAD ^ або HEAD ~ 1
Андреас Ведербранд

Вони обидва еквівалентні HEAD ~ (і HEAD ^ 1, з цього приводу)
Девід Дойч

1
@DavidDeutsch Це правда (правда, лише в останніх версіях Git), але великі регістри ( HEAD) є більш надійними: розглянемо невдалий випадок, де headє ім'я існуючого посилання.
jub0bs

1
@Jubobs - хороший момент; У своїй відповіді я змінив оболонку.
Девід Дойч

1
@qwertzguy, хороший улов; дивлячись на мітки часу, трохи про місцеві зміни було додано до запитання через хвилину після того, як я опублікував цю відповідь :)
Девід Дойч

8

Якщо можливо, уникайте жорстких скидань. Активні скидання - одна з небагатьох руйнівних операцій у git. На щастя, ви можете скасувати вишню без скидання та уникнути чогось руйнівного.

Зверніть увагу на хеш вишні, який ви хочете скасувати, скажіть, що він є ${bad_cherrypick}. Зробіть a git revert ${bad_cherrypick}. Тепер вміст вашого робочого дерева такий же, як і до вашого поганого вишневого збору.

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

Гілка, над якою ви працюєте, матиме лише добрий вишневий сорт. Скидання не потрібні!


6

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не вказує на кінчик поточної гілки

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

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

Кілька варіантів того, як відновити після від'єднаної ГОЛОВИ:


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а перевірка бажаного запису перезапису HEADповернеться до цього коміту .

Щоразу, коли HEAD модифікується, у файлі з'явиться новий запис reflog

git reflog
git checkout HEAD@{...}

Це поверне вас до бажаного коміту

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


git reset --hard <commit_id>

"Перемістіть" HEAD назад до бажаного коміту.

# 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.

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


можливо, додатиgit reset --hard
wyx

3

Зіткнувшись з цією ж проблемою, я виявив, чи ви здійснили та / або перенесли на віддалене управління після вашого успішного вишневого вибору, і ви хочете його видалити, ви можете знайти 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

Це просто скидає коміт, повертаючи вас точно в стан перед вишнею, навіть якщо у вас були місцеві зміни.


Це просто скидає коміт. що, на вашу думку, git reset HEAD^робить?
Тім,

@TimCastelijns git resetскасовує дію коміту, не відкидаючи жодних змін. Рекомендую прочитати git-scm.com/docs/git-reset . Питання ОП полягає у скасуванні вишні. Спробуйте обидві команди, моя поверне вас у той самий стан, яким ви були до вишні. git resetзіпсує ваше робоче дерево, оскільки воно залишає вишневі зміни, і вони неможливо відрізнити від ваших вже існуючих місцевих змін.
qwertzguy

так, вибачте, я мав на увазі reset --hard. Це не залишає змін
Тім,

1
@TimCastelijns git reset --hard- це руйнівна команда, яка також видалить непов’язані локальні зміни, і зробить це безпоправним способом! Отже, це не те, про що просив ОП.
qwertzguy

2
Ця відповідь була б набагато кориснішою, якби ви пояснили, що робить ця sedкоманда, чим вона відрізняється від виконання вручну та що --autostashробить.
Кріс Пейдж
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.