Как мне отменить последние коммиты в Git?
Я случайно передал неправильные файлы в Git, но я еще не отправил коммит на сервер.
Как я могу отменить эти коммиты из локального репозитория?
115 ответов
Отменить фиксацию и повторить
$ git commit -m "Something terribly misguided" # (1)
$ git reset HEAD~ # (2)
<< edit files as necessary >> # (3)
$ git add ... # (4)
$ git commit -c ORIG_HEAD # (5)
- Это то, что вы хотите отменить.
- Это оставляет ваше рабочее дерево (состояние ваших файлов на диске) без изменений, но отменяет фиксацию и оставляет внесенные вами изменения без изменений (поэтому они будут отображаться как "Изменения не подготовлены для фиксации" в
git status
, так что вам нужно будет добавить их еще раз перед фиксацией). Если вы хотите только добавить больше изменений в предыдущую фиксацию или изменить сообщение фиксации1, вы можете использоватьgit reset --soft HEAD~
вместо этого, который какgit reset HEAD~
(гдеHEAD~
такой же какHEAD~1
), но оставляет ваши существующие изменения поэтапно. - Внесите исправления в рабочие файлы дерева.
git add
все, что вы хотите включить в свой новый коммит.- Зафиксируйте изменения, повторно используя старое сообщение.
reset
скопировал старую голову в.git/ORIG_HEAD
;commit
с-c ORIG_HEAD
откроет редактор, который изначально содержит сообщение журнала от старого коммита и позволяет редактировать его. Если вам не нужно редактировать сообщение, вы можете использовать-C
вариант.
Однако помните, что если вы добавили какие-либо новые изменения в индекс, используйте commit --amend
добавит их в ваш предыдущий коммит.
Если код уже передан на ваш сервер и у вас есть права на перезапись истории (перебазирование), тогда:
git push origin master --force
Вы также можете посмотреть на этот ответ:
Как переместить ГОЛОВУ назад в предыдущее место? (Отдельная голова)
Приведенный выше ответ покажет вамgit reflog
который используется, чтобы узнать, что такое SHA-1, к которому вы хотите вернуться. Как только вы нашли точку, к которой вы хотите отменить, используйте последовательность команд, как описано выше.
1 Учтите, однако, что вам не нужно возвращаться к более ранней фиксации, если вы только что сделали ошибку в своем сообщении фиксации. Более простой вариантgit reset
(чтобы отменить любые изменения, которые вы сделали с тех пор), а затемgit commit --amend
, который откроет ваш редактор сообщений по умолчанию, предварительно заполненный последним сообщением.
Отмена коммита немного страшна, если вы не знаете, как он работает. Но на самом деле это удивительно легко, если вы понимаете.
Скажем, у вас это есть, где C - это ваша ГОЛОВА, а (F) - это состояние ваших файлов.
(F)
A-B-C
↑
master
Вы хотите обнулить коммит C и больше никогда его не видеть. Ты делаешь это:
git reset --hard HEAD~1
Результат:
(F)
A-B
↑
master
Теперь Б - ГОЛОВА. Потому что вы использовали --hard
, ваши файлы возвращаются в их состояние при коммите B.
Ах, но предположим, что commit C - это не катастрофа, а совсем немного. Вы хотите отменить коммит, но сохраните свои изменения для небольшого редактирования, прежде чем сделать лучший коммит. Начиная снова здесь, с C в качестве вашей головы:
(F)
A-B-C
↑
master
Вы можете сделать это, оставив --hard
:
git reset HEAD~1
В этом случае результат:
(F)
A-B-C
↑
master
В обоих случаях HEAD - это просто указатель на последний коммит. Когда вы делаете git reset HEAD~1
, вы говорите Git переместить указатель HEAD назад на один коммит. Но (если вы не используете --hard
Вы оставляете свои файлы такими, какими они были. А сейчас git status
показывает изменения, которые вы зарегистрировали в C. Вы ничего не потеряли!
Для легкого прикосновения вы можете даже отменить фиксацию, но оставить свои файлы и индекс:
git reset --soft HEAD~1
Это не только оставляет ваши файлы в покое, но даже оставляет ваш индекс в покое. Когда вы делаете git status
вы увидите, что в индексе есть те же файлы, что и раньше. На самом деле, сразу после этой команды, вы можете сделать git commit
и вы будете переделывать тот же коммит, который только что получил.
Еще одна вещь: предположим, вы уничтожили коммит, как в первом примере, но потом обнаружили, что он вам нужен в конце концов? Не повезло, правда?
Нет, еще есть способ вернуть его. Тип git reflog
и вы увидите список (частичных) коммитов, в которых вы переместились. Найдите коммит, который вы уничтожили, и сделайте следующее:
git checkout -b someNewBranchName shaYouDestroyed
Вы сейчас воскресили этот коммит. Комитеты на самом деле не уничтожаются в Git в течение примерно 90 дней, поэтому обычно вы можете вернуться и спасти того, от которого не хотели избавиться.
Мне потребовалось некоторое время, чтобы понять, так что, возможно, это поможет кому-то...
Существует два способа "отменить" ваш последний коммит, в зависимости от того, сделали ли вы коммит открытым или нет (передан в удаленный репозиторий):
Как отменить локальный коммит
Допустим, я зафиксировал локально, но теперь хочу удалить этот коммит.
git log
commit 101: bad commit # latest commit, this would be called 'HEAD'
commit 100: good commit # second to last commit, this is the one we want
Чтобы восстановить все так, как это было до последнего коммита, нам нужно reset
перед совершением HEAD
:
git reset --soft HEAD^ # use --soft if you want to keep your changes
git reset --hard HEAD^ # use --hard if you don't care about keeping the changes you made
Сейчас git log
покажет, что наш последний коммит был удален.
Как отменить публичный коммит
Если вы уже сделали свои коммиты общедоступными, вы захотите создать новый коммит, который "отменит" изменения, сделанные вами в предыдущем коммите (текущем HEAD).
git revert HEAD
Теперь ваши изменения будут отменены и готовы к принятию:
git commit -m 'restoring the file I removed by accident'
git log
commit 102: restoring the file I removed by accident
commit 101: removing a file we don't need
commit 100: adding a file that we need
Для получения дополнительной информации, ознакомьтесь с Git Basics - Undoing Things
Добавить / удалить файлы, чтобы получить вещи, как вы хотите:
git rm classdir
git add sourcedir
Затем измените коммит:
git commit --amend
Предыдущая, ошибочная фиксация будет отредактирована, чтобы отразить новое состояние индекса - другими словами, это будет так, как если бы вы никогда не допустили ошибку с самого начала.
Обратите внимание, что вы должны делать это, только если вы еще не нажали. Если вы нажали, то вам просто нужно зафиксировать исправление в обычном режиме.
git rm yourfiles/*.class
git commit -a -m "deleted all class files in folder 'yourfiles'"
или же
git reset --hard HEAD~1
Предупреждение. Приведенная выше команда навсегда удалит изменения .java
файлы (и любые другие файлы), которые вы хотели зафиксировать.
hard reset
в HEAD-1
установит вашу рабочую копию в состояние коммита до вашего неверного коммита.
Чтобы изменить последний коммит
Заменить файлы в индексе:
git rm --cached *.class
git add *.java
Затем, если это частная ветка, измените коммит:
git commit --amend
Или, если это общая ветка, сделайте новый коммит:
git commit -m 'Replace .class files with .java files'
(чтобы изменить предыдущий коммит, используйте потрясающую интерактивную ребазу)
ProTip ™: Добавить *.class
чтобы gitignore остановить это снова.
Чтобы отменить коммит
Поправка коммита является идеальным решением, если вам нужно изменить последний коммит, но более общее решение reset
,
Вы можете сбросить git на любой коммит с помощью:
git reset @~N
куда N
количество коммитов до HEAD
, а также @~
сбрасывает до предыдущего коммита.
Таким образом, вместо внесения изменений в коммит, вы можете использовать:
git reset @~
git add *.java
git commit -m "Add .java files"
Проверять, выписываться git help reset
в частности, разделы о --soft
--mixed
а также --hard
, для лучшего понимания того, что это делает.
Reflog
Если вы запутались, вы всегда можете использовать reflog, чтобы найти упавшие коммиты:
$ git reset @~
$ git reflog
c4f708b HEAD@{0}: reset: moving to @~
2c52489 HEAD@{1}: commit: added some .class files
$ git reset 2c52489
... and you're back where you started
Использование git revert <commit-id>
Чтобы получить идентификатор фиксации, просто используйте git log
Если вы планируете полностью отменить локальный коммит, то, что вы изменили, вы сделали в коммите, и если вы не беспокоитесь об этом, просто выполните следующую команду.
git reset --hard HEAD^1
(Эта команда будет игнорировать весь ваш коммит, и ваши изменения будут полностью потеряны из вашего локального рабочего дерева). Если вы хотите отменить ваш коммит, но вы хотите, чтобы ваши изменения были в промежуточной области (перед коммитом, как после git add
) затем выполните следующую команду.
git reset --soft HEAD^1
Теперь ваши зафиксированные файлы попадают в область подготовки. Предположим, что если вы хотите, чтобы файлы были удалены, поскольку вам нужно отредактировать неправильный контент, выполните следующую команду
git reset HEAD
Теперь переданные файлы поступают из промежуточной области в неподготовленную область. Теперь файлы готовы к редактированию, поэтому, что бы вы ни изменили, вы захотите перейти к редактированию, добавить его и сделать новый / новый коммит.
Если у вас установлен Git Extras, вы можете запустить git undo
отменить последний коммит. git undo 3
отменит последние 3 коммита.
Я хотел отменить последние 5 коммитов в нашем общем хранилище. Я посмотрел идентификатор ревизии, на которую я хотел откатиться. Затем я набрал следующее.
prompt> git reset --hard 5a7404742c85
HEAD is now at 5a74047 Added one more page to catalogue
prompt> git push origin master --force
Total 0 (delta 0), reused 0 (delta 0)
remote: bb/acl: neoneye is allowed. accepted payload.
To git@bitbucket.org:thecompany/prometheus.git
+ 09a6480...5a74047 master -> master (forced update)
prompt>
Я предпочитаю использовать git rebase -i
для этой работы, потому что появляется хороший список, где я могу выбрать коммиты, от которых нужно избавиться. Это может быть не так прямо, как некоторые другие ответы здесь, но это просто кажется правильным.
Выберите, сколько коммитов вы хотите перечислить, а затем примените вот так (чтобы подключить последние три)
git rebase -i HEAD~3
Образец списка
pick aa28ba7 Sanity check for RtmpSrv port
pick c26c541 RtmpSrv version option
pick 58d6909 Better URL decoding support
Затем git удалит коммиты для любой строки, которую вы удалите.
Как исправить предыдущий локальный коммит
Используйте git-gui (или аналогичный) для выполнения git commit --amend
, Из графического интерфейса вы можете добавлять или удалять отдельные файлы из коммита. Вы также можете изменить сообщение коммита.
Как отменить предыдущий локальный коммит
Просто сбросьте вашу ветку на предыдущее место (например, используя gitk
или же git rebase
). Затем повторно примените изменения из сохраненной копии. После сборки мусора в вашем локальном хранилище будет похоже на то, что нежелательный коммит никогда не происходил. Чтобы сделать все это в одной команде, используйте git reset HEAD~1
,
Слово предупреждения: неосторожное использование git reset
хороший способ привести вашу рабочую копию в запутанное состояние. Я рекомендую новичкам Git избегать этого, если они могут.
Как отменить публичный коммит
Выполните обратный выбор вишни ( git-revert), чтобы отменить изменения.
Если вы еще не внесли другие изменения в свою ветку, вы можете просто сделать...
git revert --no-edit HEAD
Затем отправьте обновленную ветку в общий репозиторий.
История коммитов покажет оба коммита отдельно.
Дополнительно: исправление частной ветки в публичном хранилище
Это может быть опасно - убедитесь, что у вас есть локальная копия ответвления.
Также обратите внимание: вы не хотите делать это, если кто-то еще работает над веткой.
git push --delete (branch_name) ## remove public version of branch
Очистите вашу ветку локально, затем оттолкнитесь...
git push origin (branch_name)
В нормальном случае вам, вероятно, не нужно беспокоиться о том, что ваша история коммитов в частной ветке не имеет значения. Просто нажмите последующий коммит (см. "Как отменить публичный коммит" выше), а затем выполните сквош-слияние, чтобы скрыть историю.
Если вы хотите навсегда отменить это, и вы клонировали некоторый репозиторий
Идентификатор коммита можно увидеть
git log
Тогда вы можете сделать -
git reset --hard <commit_id>
git push origin <branch_name> -f
Если вы совершили мусор, но не столкнулись,
git reset --soft HEAD~1
HEAD ~ 1 - это сокращение для коммита перед головой. В качестве альтернативы вы можете обратиться к SHA-1 хэша, если вы хотите сбросить в. Опция --soft удалит коммит, но он оставит все ваши измененные файлы как "Изменения, которые будут зафиксированы", как будет указано в git status.
Если вы хотите избавиться от каких-либо изменений в отслеживаемых файлах в рабочем дереве, начиная с коммита до заголовка, используйте вместо него " --hard ".
ИЛИ ЖЕ
Если вы уже нажали, а кто-то нажал, что обычно является моим случаем, вы не можете использовать git reset. Вы можете, однако, сделать мерзавец,
git revert HEAD
Это создаст новый коммит, который полностью изменяет все, что вводит случайный коммит.
На SourceTree (графический интерфейс для GitHub) вы можете щелкнуть правой кнопкой мыши по коммиту и выполнить "Обратный коммит". Это должно отменить ваши изменения.
На терминале:
В качестве альтернативы вы можете использовать:
git revert
Или же:
git reset --soft HEAD^ # Use --soft if you want to keep your changes.
git reset --hard HEAD^ # Use --hard if you don't care about keeping your changes.
Единственная команда:
git reset --soft 'HEAD^'
Это прекрасно работает, чтобы отменить последний локальный коммит!
Просто сбросьте его, выполнив команду ниже, используя git
:
git reset --soft HEAD~1
Объясните: что git reset
делает, это в основном reset
на любой коммит, к которому вы хотели бы вернуться, тогда, если вы объедините его с --soft
ключ, он вернется, но сохранит изменения в ваших файлах, так что вы вернетесь к этапу, на котором файл был только что добавлен, HEAD
является руководителем филиала, и если вы объедините с ~1
(в этом случае вы также используете HEAD^
), вернется только один коммит, который вы хотите...
Я создаю шаги, изображенные на рисунке ниже, более подробно для вас, включая все шаги, которые могут произойти в реальных ситуациях, и фиксацию кода:
"Сбросить рабочее дерево до последнего коммита"
git reset --hard HEAD^
"Удалить неизвестные файлы из рабочего дерева"
git clean
смотри - Git Quick Reference
ПРИМЕЧАНИЕ. Эта команда удалит ваш предыдущий коммит, поэтому используйте его с осторожностью! git reset --hard
безопаснее -
Как отменить последний коммит Git?
Чтобы восстановить все, как было до последнего коммита, нам нужно сбросить коммит до HEAD.
Если вы не хотите сохранять сделанные вами изменения:
git reset --hard HEAD^
Если вы хотите сохранить свои изменения:
git reset --soft HEAD^
Теперь проверьте ваш журнал Git. Это покажет, что наш последний коммит был удален.
Используйте reflog, чтобы найти правильное состояние
git reflog
РЕФЛОГ ДО СБРОСА
Выберите правильный reflog (f3cb6e2 в моем случае) и введите
git reset --hard f3cb6e2
После этого заголовок репо будет сброшен на этот заголовокLOG ПОСЛЕ СБРОСА
Наконец, рефлог выглядит как на картинке ниже
ФИНАЛ РЕФЛОГА
Первый забег:
git reflog
Он покажет вам все возможные действия, которые вы выполнили в вашем хранилище, например, коммит, объединение, извлечение и т. Д.
Затем сделайте:
git reset --hard ActionIdFromRefLog
Отменить последний коммит:
git reset --soft HEAD^
или же git reset --soft HEAD~
Это отменит последний коммит.
Вот --soft
означает сброс в постановку.
HEAD~
или же HEAD^
означает двигаться, чтобы совершить перед HEAD.
Заменить последний коммит на новый коммит:
git commit --amend -m "message"
Он заменит последний коммит новым коммитом.
По-другому:
Извлеките ветку, которую вы хотите вернуть, затем сбросьте локальную рабочую копию на коммит, который вы хотите сделать последним на удаленном сервере (все после того, как оно пройдет до свидания). Для этого в SourceTree я щелкнул правой кнопкой мыши и выбрал "Сбросить BRANCHNAME для этого коммита".
Затем перейдите в локальный каталог вашего репозитория и выполните следующую команду:
git -c diff.mnemonicprefix=false -c core.quotepath=false push -v -f --tags REPOSITORY_NAME BRANCHNAME:BRANCHNAME
Это удалит все коммиты после текущего в вашем локальном репозитории, но только для этой ветки.
Тип git log
и найдите хеш-код последнего коммита и затем введите:
git reset <the previous co>
В моем случае я случайно передал некоторые файлы, которые я не хотел. Итак, я сделал следующее, и это сработало:
git reset --soft HEAD^
git rm --cached [files you do not need]
git add [files you need]
git commit -c ORIG_HEAD
Проверьте результаты с помощью gitk или git log --stat
ЧТО ИСПОЛЬЗОВАТЬ, reset --soft
или же reset --hard
?
Я просто добавляю два цента за ответ @Kyralessa:
Если вы не уверены, что использовать, перейдите на --soft
(Я использовал это соглашение, чтобы помнить это - часто для безопасности).
Зачем?
Если вы выбираете --hard
по ошибке вы потеряете ваши изменения, как это было раньше. Если вы выбираете --soft
по ошибке вы можете достичь тех же результатов --hard
применяя дополнительные команды
git reset HEAD file.html
git checkout -- file.html
Полный пример
echo "some changes..." > file.html
git add file.html
git commit -m "wrong commit"
# I need to reset
git reset --hard HEAD~1 (cancel changes)
# OR
git reset --soft HEAD~1 # Back to staging
git reset HEAD file.html # back to working directory
git checkout -- file.html # cancel changes
Кредиты идут в @Kyralessa.
Просто запустите это в командной строке:
git reset --soft HEAD~
Есть много способов сделать это:
Команда Git для отмены последнего коммита / предыдущих коммитов:
Предупреждение: не используйте --hard, если вы не знаете, что делаете. --hard слишком опасен, и он может удалить ваши файлы.
Основная команда для возврата коммита в Git:
$ git reset --hard <COMMIT -ID>
или же
$ git reset --hard HEAD~<n>
COMMIT-ID: идентификатор для фиксации
n: количество последних коммитов, которые вы хотите вернуть
Вы можете получить идентификатор фиксации, как показано ниже:
$ **git log --oneline**
d81d3f1 function to subtract two numbers
be20eb8 function to add two numbers
bedgfgg function to mulitply two numbers
где d81d3f1 и be20eb8 являются идентификатором коммита.
Теперь давайте посмотрим на некоторые случаи:
Предположим, вы хотите отменить последний коммит 'd81d3f1'. Вот два варианта:
$ git reset --hard d81d3f1
или же
$ git reset --hard HEAD~1
Предположим, вы хотите отменить коммит 'be20eb8':
$ git reset --hard be20eb8
Для получения более подробной информации вы можете обратиться и попробовать некоторые другие команды для возврата головки в указанное состояние:
$ git reset --help
Для локального коммита
git reset --soft HEAD~1
или если вы точно не помните, в каком именно коммите это происходит, вы можете использовать
git rm --cached <file>
Для толкаемого коммита
Правильный способ удаления файлов из истории хранилища использует git filter-branch
, То есть,
git filter-branch --index-filter 'git rm --cached <file>' HEAD
Но я рекомендую вам использовать эту команду с осторожностью. Узнайте больше на странице руководства git-filter-branch(1).
Есть два основных сценария
Вы еще не выдвинули коммит
Если проблема была в добавленных вами дополнительных файлах (и вы не хотите, чтобы они были в хранилище), вы можете удалить их, используя git rm
а затем совершить --amend
git rm <pathToFile>
Вы также можете удалить целые каталоги с -r
или даже комбинировать с другими командами Bash
git rm -r <pathToDirectory>
git rm $(find -name '*.class')
После удаления файлов вы можете сделать коммит с параметром --amend
git commit --amend -C HEAD # the -C option is to use the same commit message
Это перезапишет вашу недавнюю локальную фиксацию, удалив лишние файлы, поэтому эти файлы никогда не будут отправлены при загрузке, а также будут удалены из вашего локального репозитория.git GC.
Вы уже нажали коммит
Вы можете применить то же решение другого сценария, а затем делать git push
с -f
опция, но это не рекомендуется, так как она перезаписывает удаленную историю изменяющимися изменениями (это может испортить ваш репозиторий).
Вместо этого вы должны сделать коммит без --amend
(помните об этом -amend`: эта опция переписывает историю последнего коммита).