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

2303

Я хотел бы знать, как удалить фиксацию.

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

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

  • 30
    Я думаю, что это не дубликат Git отменить последний коммит, поскольку он спрашивает, как удалить любой коммит из ветви. Я также думаю, что ни один из ответов на самом деле не отвечает на этот вопрос. Все они перематывают последние коммиты, а не cherry-pick и delete один коммит, который мог произойти некоторое время назад.
  • 9
    @Chris, ответ с git rebase -i HEAD~10 действительно решает вопрос, так как позволяет произвольно выбирать коммиты для удаления. Git применяет коммиты в указанном вами диапазоне один за другим, игнорируя коммиты, которые вы удалили из журнала. Я использовал эту команду сегодня, чтобы избавиться от второго и третьего последних коммитов в моем репо, сохранив при этом верхний. Я согласен, что ни один из других ответов не является удовлетворительным.
Показать ещё 1 комментарий
Теги:
git-rebase

24 ответа

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

Осторожно: 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, чтобы создать фиксацию "зеркального изображения", которая отменяет изменения. Однако оба фиксатора будут в журнале.


FYI - git reset --hard HEAD отлично, если вы хотите избавиться от WORK IN PROGRESS. Он будет reset вернуться к последнему фиксации и удалить все изменения в рабочем дереве и индексе.


Наконец, если вам нужно найти коммит, который вы "удалили", он обычно присутствует в git reflog, если у вас нет мусора, собирающего ваш репозиторий.

  • 50
    HEAD~1 или просто HEAD^ . Если вы нажали, вы должны использовать вместо этого git revert .
  • 11
    Очевидно, вы также можете использовать HEAD~n для «возврата» n коммитов из вашей головы. Возможно, с этого момента вы можете интерпретировать ... --hard HEAD также как HEAD~0 => удаление незавершенной работы.
Показать ещё 14 комментариев
524

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

git rebase -i HEAD~N

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

В книге Git есть хороший раздел для перезагрузки с картинками и примерами.

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

  • 1
    Примечание: Если у вас есть какие-либо слияния --no-ff в последнем пакете коммитов, rebase их разделит :( Это упоминается в -p на этой странице . Проблема в том, что если вы замените -i на -p, у вас больше не появляется всплывающее окно с вариантами «отредактировать этот коммит, создать его» и т. д. Кто-нибудь знает решение?
  • 0
    Это лучше, чем ответ «сбросить жесткий», так как он не удалит файлы, только ошибочное сообщение о коммите? Потому что, кажется, удалил мои файлы. Если удаление файла должно произойти, пожалуйста, добавьте это как четкое предупреждение!
Показать ещё 7 комментариев
409

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

git rebase -i <commit>~1

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

  • 3
    спасибо, кстати, если у вас возникнут какие-либо проблемы (например, пустые коммиты), вы можете использовать git rebase --continue
  • 7
    Еще проще: git rebase -i HEAD~1
Показать ещё 6 комментариев
242

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

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

git reset --soft HEAD~1

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

  • 4
    Вот пример того, почему: вы выполняете небольшую часть работы на сервере разработки, которую вы фиксируете. Затем выясняется, что этот сервер не имеет исходящего HTTPS-доступа, поэтому вы не можете нигде выдвинуть коммит. Проще всего сделать вид, что этого не произошло, и повторить патч с вашего локального компьютера.
  • 0
    @KarthikBose всегда будет рефлог. даже после git reset --hard HEAD~1 ваш последний последний коммит будет доступен через reflog (до истечения срока его действия); см. также здесь: gitready.com/intermediate/2009/02/09/…
Показать ещё 8 комментариев
46

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

$ git reset --hard HEAD^

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

Если вы уже опубликовали commit-to-be-commit, используйте git revert

$ git revert HEAD
  • 0
    Это не сработало. Когда я жму журнал, все еще там, независимо от того, почему я делаю это, просто добавляет больше коммитов. Я хочу очистить историю.
  • 0
    @Costa: Что не сработало (то есть, какую версию вы использовали), и как вы сделали git log?
Показать ещё 4 комментария
26

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

git reset HEAD~1

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

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

git reset HEAD~N

Если вы хотите избавиться от своей последней фиксации и не хотите сохранять изменения кода, вы можете сделать "жесткий" reset.

git reset --hard HEAD~1

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

git reset --hard HEAD~N
24

Удаление целой фиксации

git rebase -p --onto SHA^ SHA

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

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

  • 8
    как я могу больше ответить на этот ответ ??? другие решения просто показывают, как сделать это в интерактивном режиме или удалить верхние коммиты.
  • 0
    Спасибо за эту ссылку! Мне было интересно, после запуска этого, почему я все еще вижу коммит SHA в моем git reflog?
Показать ещё 3 комментария
22
git reset --hard commitId

git push <origin> <branch> --force

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

  • 0
    git push --force <origin> <branchName>. поскольку без упоминания имени ветки это может изменить весь файл на удаленном компьютере.
10
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 log message

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

d, drop = remove commit

Эти строки могут быть переупорядочены; они выполняются сверху вниз.  Если вы удалите строку здесь, то КОМИТЕТ БУДЕТ ПОТЕРЯТЬ.  Однако, если вы удалите все, rebase будет прерван.  Обратите внимание, что пустые коммиты закомментированы

Вы можете просто удалить эту фиксацию с помощью опции "d" или "Удалить строку с вашей фиксацией".

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

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

git reset --hard HEAD~1

Для удаления в удаленной ветки используйте

git push origin HEAD --force
9

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

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

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

  • 0
    Ключевое слово drop не определено. Чтобы удалить коммит, просто удалите всю строку.
  • 1
    drop сработало для меня
7

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

Зарезервируйте ветку, которую вы хотите вернуть, затем reset ваша локальная рабочая копия обратно к фиксации, которую вы хотите быть последним на удаленном сервере (все после того, как оно пройдет до свидания). Для этого в SourceTree я щелкнул правой кнопкой мыши на выбранном "Reset BRANCHNAME" для этого фиксации ". Я думаю, что в командной строке:

git reset --hard COMMIT_ID

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

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

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

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

7

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

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

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

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

git revert GIT_COMMIT_HASH

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

git push  

Когда вы выдаете git log, вы увидите как "неправильную" фиксацию, так и возврат сообщений журнала.

  • 0
    Да, но ОП было ясно, что это не то, что они хотят.
5

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

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

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

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

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

Docs: http://git-scm.com/docs/git-commit.html

  • 1
    Это не то, о чем просит OP.
4

Ошибка:

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

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

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

Теперь он снова добавил последнюю ненужную фиксацию, которую я хотел удалить, и так продолжалось.

Исчерпание опций:

Я не хотел git revert - он создавал бы дополнительную фиксацию, давая Git верхнюю часть.

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

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

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

Проверка возврата к мастеру, время, чтобы попробовать git rebase -i <SHA>, затем удалить строку... безрезультатно, к сожалению. "Если вы удалите строку здесь, то КОМИТЕТ БУДЕТ ПОТЕРЯТ". Ах... замалчивается новая функция троллинга n00b в примечания к выпуску 2.8.3.

Решение:

git rebase -i <SHA>, затем d, drop = remove commit.

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

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

Добрый день вам.

3

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

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

  • git checkout b3d92c5 Ознакомьтесь с последним используемым коммитом.
  • git checkout -b repair Создайте новую ветку для работы.
  • git cherry-pick 77b9b82 Запустить фиксацию 3.
  • git cherry-pick 2c6a45b Выполнять фиксацию 1.
  • git checkout master Мастер проверки.
  • git reset --hard b3d92c5 Reset мастер для последнего использования.
  • git merge repair Объедините нашу новую ветку с мастером.
  • git push --hard origin master Нажмите мастер на дистанционное репо.
  • 1
    последний шаг должен быть git push -f origin master нет опции --hard
  • 1
    Я думаю, что commit 0 старше, чем commit 1 . Пожалуйста, не могли бы вы сказать мне, почему сначала выполните commit 3 (по cherry-pick), а затем по commit 1 ? После извлечения b3d92cd ( commit 0 ), я ожидаю, что cherry-pick commit 1 , затем commit 3 . Благодарю.
Показать ещё 1 комментарий
2

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

git reset --hard HEAD~1

git push -f origin

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

2

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

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

Затем каждое место клонирования repo запускается:

git reset --hard origin/master
1

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

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

Затем скопируйте нужные файлы из папки temp, затем выполните

1

git reset --hard

git push origin HEAD --force

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

1

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

  • 0
    Очевидно, что он перемещается в хранилище на основе OP.
  • 0
    @ LucasHuang Нет, это не так: «когда я сделаю push в будущем , мои изменения не будут переданы в удаленную ветку»
0

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

-17

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

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

    tar czvf code.tgz *

  • отобразите список git commit с помощью команды:

    git log

  • получить "sha1-commit-id" фиксации под нежелательной фиксацией, это идентификатор фиксации до вашего (журнал git содержит список последних коммитов первая)

  • вернуть обратно нежелательную фиксацию с помощью команды

    git reset --hard "sha1-commit-id"

    * вы можете проверить, что вы сделали это правильно, выполнив команду анотера git log <* >

  • верните свой незаданный код с помощью команды:

    tar xzvf code.tgz

Команды tar используются для того, чтобы убедиться, что ваша тяжелая работа не будет стерта по ошибке, так как команда git reset удалит изменения вашего рабочего каталога, так что шаги 1 и 5 используются для хранения локальных изменений.

Ещё вопросы

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