Удалить коммиты из ветки в Git


3235

Я хотел бы знать, как удалить коммит.

К delete, я имею в виду, как если бы я не делал , что совершал, и когда я делаю толчок в будущем, мои изменения не будет толкать к удаленной ветви.

Я прочитал git help и думаю, что команда, которую я должен использовать, - это git reset --hard HEAD. Это правильно?


41
Я думаю, что это не дубликат Git отменить последний коммит, так как он спрашивает, как удалить любой коммит из ветви. Я также думаю, что ни один из ответов на самом деле не отвечает на этот вопрос. Все они натягивают последние коммиты, не cherry-pickи deleteодин коммит , который мог произойти некоторое время назад.
Крис

12
@Chris, ответ с помощью git rebase -i HEAD~10действительно отвечает на вопрос, так как позволяет произвольно выбирать коммиты для удаления. Git применяет коммиты в указанном вами диапазоне один за другим, игнорируя коммиты, которые вы удалили из журнала. Я использовал эту команду сегодня, чтобы избавиться от второго и третьего последних коммитов в моем репо, сохранив при этом верхний. Я согласен, что ни один из других ответов не является удовлетворительным.
MST

@ MST Да, я должен был сказать, что ни один из вариантов в принятом ответе не отвечает на этот вопрос, но вы абсолютно правы - эта команда, похоже, работает
Крис

Ответы:


4130

Осторожно: git reset --hard УДАЛИТ ВАШИ РАБОЧИЕ СПРАВОЧНИКИ ИЗМЕНЕНИЯ . Обязательно сохраните все локальные изменения, которые вы хотите сохранить, перед запуском этой команды.

Предполагая, что вы сидите на этом коммите, эта команда испортит его ...

git reset --hard HEAD~1

В HEAD~1означает , что совершить , прежде чем голова.

Или вы можете просмотреть выходные данные git log, найти идентификатор коммита коммита, на который вы хотите создать резервную копию, и затем сделать это:

git reset --hard <sha1-commit-id>

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

git push origin HEAD --force

Тем не менее , если другие его вытянули, вам лучше начать новую ветку. Потому что, когда они потянут, это просто объединит их с их работой, и вы снова подтолкнете их вверх.

Если вы уже нажали, может быть лучше использовать git revertдля создания фиксации «зеркального отображения», которая отменит изменения. Тем не менее, обе фиксации будут в журнале.


К вашему сведению - git reset --hard HEADэто здорово, если вы хотите избавиться от РАБОТЫ В ПРОГРЕССЕ. Он вернет вас к самому последнему коммиту и сотрет все изменения в вашем рабочем дереве и индексе.


И наконец, если вам нужно найти коммит, который вы «удалили», он обычно присутствует, git reflogесли вы не собрали мусор в своем хранилище.


59
HEAD~1или просто HEAD^. Если вы нажали, вы должны использовать git revertвместо этого.
Якуб Наребски

13
Очевидно, что вы также можете использовать HEAD~nдля «возврата» nкоммиты из своей головы. Может быть, с этого момента вы можете интерпретировать ... --hard HEADкак HEAD~0=> удаление незавершенного производства.
Нуала

13
@ beamrider9 imho git rebase - это почти всегда лучший способ удаления коммитов (как описано в ответе Грега Хьюгилла) - не в последнюю очередь потому, что фактически rebase содержит большое предупреждение о том, что вы будете удалять материал 4realz.
Ноа Суссман

20
Это не удаляет изменения из дерева коммитов. ОП запросил уже сделанный коммит. Если вы reset --hard, и проверьте log --oneline --all, коммиты все еще остаются в дереве. Как мы удаляем эти коммиты из дерева? Спасибо.
iGbanam

17
используйте reset --softдля удаления локального коммита БЕЗ возврата к текущей работе!

704

Если вы еще не отправили коммит, вы можете использовать его git rebase -iдля удаления. Во-первых, выясните, насколько далеко назад находится этот коммит (приблизительно). Затем сделайте:

git rebase -i HEAD~N

В ~Nсредства перебазироваться последние Nкоммиты ( Nдолжен быть числом, например HEAD~10). Затем вы можете отредактировать файл, который Git представляет вам, чтобы удалить оскорбительный коммит. При сохранении этого файла Git перезапишет все следующие коммиты, как если бы тот, который вы удалили, не существовал.

В Git Book есть хороший раздел о перебазировании с картинками и примерами.

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


2
Примечание: Если у вас есть какие-либо слияния --no-ff в последнем пакете коммитов, ребаз будет их разделывать :( Это упоминается в разделе -p на этой странице . Проблема в том, что если вы замените -i на -p, у вас больше не появляется всплывающее окно с вариантами «отредактировать этот коммит, создать его» и т. д. и т. д. Кто-нибудь знает решение?
Буков

4
Что делать, если вы нажали это? (только я использую удаленное репо)
Коста

6
@Costa, который вы можете использовать push -fдля принудительной отправки и замены удаленной ветви вашей локальной. Если это просто ваше собственное удаленное репо, нет проблем. Беда начинается, если кто-то еще получил за это время.
Грег Хьюгилл

3
Я добавил и зафиксировал файл данных, который был слишком велик для GitHub (да, в любом случае, его, вероятно, не должно было быть в исходном репо; да ладно). Когда я попытался нажать, GitHub отказался из-за слишком большого файла. Все, что я хотел сделать, - это отменить этот коммит, сохранив несколько последующих связанных коммитов. Команда git rebase -i HEAD~5была именно то , что мне нужно, чтобы полностью удалить этот коммит из моего локального репо! Спасибо!
Альдо

4
@dumbledad: При rebase -iэтом изменения, соответствующие удаленному коммиту , не сохраняются.
Грег Хьюгилл

517

Другая возможность - одна из моих любимых команд:

git rebase -i <commit>~1

Это начнёт перебазирование в интерактивном режиме -iс того момента, когда вы хотите сделать коммит. Редактор запустит список всех коммитов с тех пор. Удалите строку, содержащую коммит, который вы хотите стереть, и сохраните файл. Rebase выполнит остальную часть работы, удалив только этот коммит и воспроизведя все остальные обратно в журнал.


3
спасибо, кстати, если у вас возникнут какие-либо проблемы (например, пустые коммиты), которые вы можете использоватьgit rebase --continue
realgt

8
Еще проще: git rebase -i HEAD~1
запомни

2
Wowzers. git rebase -i HEAD~1действительно много почистил репо! Трудно сказать, что именно он сделал, но все выглядит намного аккуратнее. На самом деле немного тревожно.
Чарльз Вуд

7
Думаю, стоит отметить, что коммит не уничтожен, а просто удален из списка. Если вы запутались, вы можете вернуть коммит, используя reflog .
Заз

6
Удаляет ли строка то же самое, что и d / drop?
Лев

345

Я добавляю этот ответ, потому что не понимаю, почему кто-то, кто только что попытался зафиксировать работу, захочет удалить всю эту работу из-за какой-то ошибки с помощью Git!

Если вы хотите сохранить свою работу и просто «отменить» эту команду коммита (вы поймали перед тем, как нажать на репо):

git reset --soft HEAD~1

Не используйте флаг --hard, если вы не хотите уничтожить вашу работу, выполняемую с момента последнего коммита.


5
Вот пример того, почему: вы выполняете небольшую часть работы на сервере разработки, которую вы фиксируете. Затем выясняется, что этот сервер не имеет исходящего HTTPS-доступа, поэтому вы не можете нигде выдвинуть коммит. Проще всего сделать вид, что этого не произошло, и повторить патч с вашего локального компьютера.
Стив Беннетт

1
@KarthikBose всегда будет рефлог. даже после того, как git reset --hard HEAD~1ваш последний последний коммит будет доступен через reflog (до истечения срока его действия); см. также здесь: gitready.com/intermediate/2009/02/09/…
кодирование

4
Спасибо. Этот ответ должен быть оценен выше или включен в принятый ответ. Удаление коммита! = Отмена коммита.
Alsciende

2
@RandolphCarter: вы все равно потеряете все незафиксированные изменения.
naught101

7
@Rob, один из примеров, когда вы случайно фиксируете файл, который содержит секрет (например, пароль), который никогда не должен находиться в системе контроля версий. Локальный коммит должен быть уничтожен , а не просто отменен, поэтому он никогда не будет отправлен на сервер.
Боб Мейерс

143

Удаление всего коммита

git rebase -p --onto SHA^ SHA

Очевидно, замените «SHA» ссылкой, от которой вы хотите избавиться. «^» В этой команде буквально.

http://sethrobertson.github.io/GitFixUm/fixup.html#change_deep


26
как я могу больше ответить на этот ответ ??? другие решения просто показывают, как сделать это в интерактивном режиме или удалить верхние коммиты.
Рибамар

5
-p, --preserve-merges Воссоздание коммитов слияния вместо выравнивания истории путем воспроизведения коммитов, которые вводит коммит слияния. Разрешения конфликтов слияния или ручные изменения для слияния коммитов не сохраняются.
raittes

5
Это действительно точный ответ
Хамман Самуэль

9
В нем говорится: «замените SHA ссылкой, от которой вы хотите избавиться», но в строке дважды присутствует SHA. Вот что я сделал. git rebase -p --onto 5ca8832c120 ^ 5ca8832c120 Но ничего не изменилось. Я должен использовать один и тот же SHA дважды? Если нет, то каков SHA для удаления коммита и каким должен быть другой SHA?
Рубиксман

3
ВАУ, это сработало без нареканий! Это должен быть принятый ответ!
Лиран Х

51

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

$ git reset --hard HEAD^

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

Если вы уже опубликовали коммит для удаления, используйте git revert

$ git revert HEAD

Это не сработало. Когда я жму журнал, все еще там, независимо от того, почему я делаю это, просто добавляет больше коммитов. Я хочу очистить историю.
Коста

@Costa: Что не сработало (то есть, какую версию вы использовали) и как вы сделали журнал?
Якуб Наребски

Я попробовал почти все в этом Q & A. (Я недавно попробовал git revert HEAD) Мой журнал git:tree = log --all --graph --format=format:'%C(bold blue)%h%C(reset) %C(dim black)%s%C(reset)%C(bold red)%d%C(reset) %C(green)by %an, %ar%C(reset)'
Costa

1
Я просто хочу удалить коммиты (как будто их никогда не было). Я отправился в какое-то странное приключение по программированию с несколькими новыми коммитами, и все это оказалось мусором. Как я могу просто удалить их из моего журнала git?
Коста

2
Черт возьми, что-то волшебным образом сделало именно то, что я хотел .... какая из этих команд сделала это? !!?!
Коста

45

Скажем, мы хотим удалить коммиты 2 и 4 из репо.

commit 0 : b3d92c5
commit 1 : 2c6a45b
commit 2 : <any_hash>
commit 3 : 77b9b82
commit 4 : <any_hash>

Примечание: вам нужно иметь права администратора на репо, так как вы используете --hardи -f.

  • git checkout b3d92c5 Оформить последний использованный коммит.
  • git checkout -b repair Создайте новую ветку для работы.
  • git cherry-pick 77b9b82 Запустите коммит 3.
  • git cherry-pick 2c6a45b Запустите коммит 1.
  • git checkout master Оформить заказ мастеру.
  • git reset --hard b3d92c5 Сбросьте мастер до последнего используемого коммита.
  • git merge repair Слей нашу новую ветку на мастера.
  • git push -f origin master Подтолкните мастера к удаленному репо.

1
последний шаг должен быть git push -f origin masterнет выбора--hard
Vivex

2
Я думаю commit 0, старше commit 1. Пожалуйста, не могли бы вы сказать мне, почему сначала пробегать commit 3(по черри-пик), а затем мимо commit 1? После проверки b3d92cd( commit 0), я бы ожидал вишни commit 1, тогда commit 3. Спасибо.
Jarek C

@JarekC Я думаю, что самый верхний коммит - это самый новый коммит здесь, если только я не вижу что-то не так ...
Джефф

41
git reset --hard commitId

git push <origin> <branch> --force

PS: CommitId ссылается на тот, который вы хотите вернуть обратно


git push --force <origin> <branchName>. поскольку без упоминания имени ветки это может изменить весь файл на удаленном компьютере.
Sheelpriy

39

Принудительно изменить историю

Предполагая, что вы не хотите просто удалить последний коммит, но хотите удалить определенные коммиты из последних n коммитов, перейдите к:

git rebase -i HEAD~<number of commits to go back>, так что git rebase -i HEAD~5если вы хотите увидеть последние пять коммитов.

Затем в текстовом редакторе измените слово pickна dropрядом с каждым коммитом, который вы хотите удалить. Сохраните и выйдите из редактора. Вуаля!

История изменений

Попробуй git revert <commit hash>. Revert создаст новый коммит, который отменяет указанный коммит.


dropКлючевое слово не определено. Чтобы удалить коммит, просто удалите всю строку.
Шаян Салехиан

1
Для меня drop был определен как ключевое слово, но выполнение drop, похоже, не удаляло коммит из истории. Однако удаление строки из интерактивной перебазировки сделало.
Адам Паркин

Это именно то, что мне было нужно. Работает отлично; Спасибо!
diekunstderfuge

30

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

git reset HEAD~1

Это вернет ваш репозиторий в его состояние до того, как команды git add разместили файлы. Ваши изменения будут в вашем рабочем каталоге. HEAD ~ 1 относится к коммиту ниже текущей вершины ветви.

Если вы хотите отменить N коммитов, но сохраните изменения кода в вашем рабочем каталоге:

git reset HEAD~N

Если вы хотите избавиться от своего последнего коммита и не хотите сохранять изменения кода, вы можете выполнить «жесткий» сброс.

git reset --hard HEAD~1

Аналогично, если вы хотите отменить последние N коммитов и не хотите сохранять изменения кода:

git reset --hard HEAD~N

22
git rebase -i HEAD~2

Здесь «2» - это количество коммитов, которые вы хотите перебазировать.

'git rebase -i HEAD`

если вы хотите отменить все коммиты.

Тогда вы сможете выбрать один из этих вариантов.

p, pick = use commit

r, reword = use commit, but edit the commit message

e, edit = use commit, but stop for amending

s, squash = use commit, but meld into previous commit

f, fixup = like "squash", but discard this commit's log message

x, exec = run command (the rest of the line) using shell

d, drop = remove commit

Эти строки можно переупорядочить; они выполняются сверху вниз. Если вы удалите строку здесь, то этот коммит будет потерян. Однако, если вы удалите все, ребаз будет прерван. Обратите внимание, что пустые коммиты закомментированы

Вы можете просто удалить этот коммит, используя опцию «d» или «Удаление строки с вашим коммитом».


В последней версии git больше нет опции d . Вам нужно просто удалить строки с коммитами из rebase, чтобы удалить их.
Олег Абражаев

17

Чтобы удалить в локальной ветке, используйте

git reset --hard HEAD~1

Чтобы удалить в удаленной ветке, используйте

git push origin HEAD --force

12

[Быстрый ответ]

У вас есть много альтернатив, например:

  • Альтернатива 1:

    git rebase -i <YourCommitId>~1
    

    Измените YourCommitId на номер коммита, к которому вы хотите вернуться.

  • Альтернатива 2:

    git reset --hard YourCommitId
    git push <origin> <branch> --force
    

    Измените YourCommitId на номер коммита, к которому вы хотите вернуться.

    Я не рекомендую эту опцию, потому что вы можете потерять свою работу в процессе.

  • Альтернатива 3:

    git reset --soft HEAD~1
    

    Вы можете сохранить свою работу и только отменить коммит.


спасибо спасибо спасибо (Y)
Хабиб Рехман

11

Источник: https://gist.github.com/sagarjethi/c07723b2f4fa74ad8bdf229166cf79d8

Удалить последний коммит

Например, ваш последний коммит

git push origin + aa61ab32 ^: master

Теперь вы хотите удалить этот коммит, а затем простой способ сделать следующее

меры

  1. Сначала сбросьте ветвь к родителю текущего коммита

  2. Сила-толкни его на пульт.

git reset HEAD^ --hard

git push origin -f

Для конкретного коммита вы хотите сбросить следующее

git reset bb676878^ --hard

git push origin -f

9

Вот еще один способ сделать это:

Извлеките ветку, которую вы хотите вернуть, а затем сбросьте свою локальную рабочую копию обратно на коммит, который вы хотите, чтобы он был последним на удаленном сервере (все после того, как оно пройдет до свидания). Для этого в SourceTree я щелкнул правой кнопкой мыши и выбрал «Сбросить BRANCHNAME для этого коммита». Я думаю, что командная строка:

git reset --hard COMMIT_ID

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

Затем перейдите в локальный каталог вашего репозитория и выполните следующую команду:

git -c diff.mnemonicprefix=false -c core.quotepath=false \
push -v -f --tags REPOSITORY_NAME BRANCHNAME:BRANCHNAME

Это удалит все коммиты после текущего в вашем локальном репозитории, но только для этой ветки.


9

Ошибка:

Я git rebase -i --rootредактировал свою ветку, не зная, что могу перефразировать первый коммит, отличный от основного (представление по умолчанию GitHub для Windows - это сравнение с основным, скрывающее его целостность).

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

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

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

Исчерпывающие возможности:

Я не хотел git revert- это создаст дополнительный коммит, предоставив Git преимущество.

git reset --hard HEADничего не сделал, проверив reflog, последним и единственным HEADбыл клон - Git побеждает.

Чтобы получить самый последний SHA, я проверил удаленный репозиторий на github.com - незначительный выигрыш.

После того, как размышления git reset --hard <SHA>сработали, я обновил другую ветку до master и 1 ... 2 ... poof! коммит вернулся - Гит побеждает.

Возвращаясь к мастеру, пора попробовать git rebase -i <SHA>, затем убрать строку ... безрезультатно, к сожалению. « Если вы удалите строку здесь, то этот коммит будет потерян ». Ах ... в новой заметке о тролле n00b в примечаниях к выпуску 2.8.3 .

Решение:

git rebase -i <SHA>тогда d, drop = remove commit.

Чтобы проверить, я проверил в другую ветку, и вуаля - нет скрытого коммита для извлечения / извлечения от мастера.

https://twitter.com/holman/status/706006896273063936

Хороший день для тебя.


8

Все вышеперечисленные команды восстанавливают состояние вашего рабочего дерева и индекса, как они были до принятия коммита, но не восстанавливают состояние репозитория. Если вы посмотрите на него, «удаленный» коммит на самом деле не удаляется, он просто не тот, что на кончике текущей ветви.

Я думаю, что нет способа удалить коммит с помощью фарфоровых команд . Единственный способ - удалить его из журнала и reflog, а затем выполнить git prune --expire -now.


1
Порядок отображения ответов в StackOverflow не является фиксированным. Пожалуйста, не обращайтесь к «Все команды выше». Сделайте свой собственный ответ самодостаточным.
Паскаль Куок

Этот ответ не совсем правильный. git prune на самом деле одна из "фарфоровых" команд . Кроме того, редко вы захотите полностью очистить ваш reflog (один из вариантов использования - удалить конфиденциальную информацию из вашего репо, но, как я уже сказал, это редкий случай использования). Чаще всего вы захотите сохранить старые коммиты в reflog на случай, если вам понадобится восстановить данные. См. Pro Git: 9.7 Git Internals - Обслуживание и восстановление данных .

8

Если вы хотите сохранить историю, показывая фиксацию и возврат, вы должны использовать:

git revert GIT_COMMIT_HASH

введите сообщение, объясняющее, почему вы возвращаетесь, а затем:

git push  

При выдаче git logвы увидите как «неправильный» коммит, так и возврат сообщений журнала.


Да, но ОП было ясно, что это не то, что они хотят.
Стив Беннетт

7

Если вы только что испортили свой последний коммит (неправильное сообщение, забыли добавить некоторые изменения) и хотите исправить его, прежде чем отправлять в публичный репозиторий, почему бы не использовать:

git commit --amend -m "New message here"

Если у вас есть новые изменения, они будут объединены с последним коммитом (от которого вы пытаетесь избавиться) и заменит этот коммит.

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

Вы также можете передать опцию «--no-edit» вместо «-m», если вы предпочитаете использовать сообщение предыдущего коммита.

Документы: http://git-scm.com/docs/git-commit.html


2
Это не то, о чем просит OP.
Стив Беннетт

5

Если вы уже нажали, сначала найдите коммит, которым вы хотите быть в HEAD ($ GIT_COMMIT_HASH_HERE) , а затем выполните следующее:

git reset --hard $GIT_COMMIT_HASH_HERE
git push origin HEAD --force

Затем каждое место, где репозиторий был клонирован, запускается:

git reset --hard origin/master

5

Что я обычно делаю, когда я фиксирую и нажимаю (если кто-то нажал на его фиксацию, это решит проблему):

git reset --hard HEAD~1

git push -f origin

надеюсь, это поможет


5

Я уже подтолкнул. Нужно вернуть некоторые коммиты обратно удаленно. Перепробовал много вариантов, но только это от Джастина через git bush работает нормально для меня:

git reset --hard $GIT_COMMIT_HASH_HERE
git push origin HEAD --force

4

Сброс на локальный филиал

git reset --hard HEAD~<Number of commit> So git reset --hard HEAD~3

Принудительный толчок к началу

git push -f origin

3

Сделайте резервную копию вашего кода во временную папку. Следующая команда будет сброшена так же, как сервер.

git reset --hard HEAD
git clean -f
git pull

Если вы хотите сохранить свои изменения и удалить последние коммиты

git reset --soft HEAD^
git pull


2

удалить локальный коммит

Как вы можете видеть на изображении выше, я хочу удалить возвращенную фиксацию «test change 2» (SHA1 ID: 015b5220c50e3dfbb1063f23789d92ae1d3481a2 (вы можете получить ID SHA1, используя gitkкоманду в git bash)).

Для этого я могу использовать (все нижеприведенные команды работают только на локальных. Вам нужно нажать после удаления):

  1. git reset --hard 515b5220c50e3dfbb1063f23789d92ae1d3481a2// его обратно вверх , чтобы вы , что совершить (SHA1 идентификатор изменения тест 4 фиксации является 515b5220c50e3dfbb1063f23789d92ae1d3481a2 )
  2. git reset --hard HEAD~1 // это резервное копирование перед одним коммитом.
  3. git reset --hard HEAD^ // Удалить последний коммит из git

после удаления:

после удаления коммита


2

git reset --hard HEAD~1
Вы будете теперь в предыдущей главе. Потяните ветку. Нажмите новый код. Коммит будет удален из Git


Если вы уже не выдвинули изменения. В этом случае жесткий сброс не очистит ваш пульт. В этом случае ребаз является хорошим вариантом
c0der512

1

git reset --hard

git push origin HEAD --force

Если один или несколько коммитов помечены, сначала удалите тег (ы). В противном случае помеченный коммит не удаляется.


0

используйте git revert https://git-scm.com/docs/git-revert. Он вернет весь код, после чего вы сможете сделать следующий коммит. Затем глава укажет на этот последний коммит. отмененные коммиты никогда не удаляются, но это не повлияет на ваш последний коммит.


0

В моем случае, мой магический код для этой цели:

git reset --hard @{u}

Проверьте это и скажите мне. Я пробовал несколько разных, но этот был единственным, который помог мне.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.