Перейти к содержимому

Как отменить git push

  • автор:

Как отменить сделанный Git push?

Доброго времени суток 🙂
Прошу у знающих Git людей помощи.
С гитом работать только начинаю и в упрощенном виде у меня сложилась вот такая ситуация:
У меня есть ветки master и task1,
Я в ветке task1 поработал и вот хочу эти наработки отправить в ветку task1 на GitHub.
Нахожусь я в ветке task1 и такой пишу:

git add . git commit -m"comment" git push origin master.

А надо то ведь было писать git push origin task1 =(
Что теперь нужно сделать?
Я гуглил, но не уверен что нашёл правильное решение и боюсь испортить себе репозиторий.
Подскажите плз что теперь нужно сделать?

  • Вопрос задан более трёх лет назад
  • 28484 просмотра

Комментировать
Решения вопроса 1
devian3000 @devian3000

Сперва отправь изменения в правильную ветку (в удалённом репозитории проверь что в task1 все изменения были приняты, т.е. что последний коммит прошёл, иначе есть шанс потерять всю работу)
git push origin task1

Потом на мастере получи все изменения из удалённой репы
git checkout master
git fetch —all
git rebase origin/master

Обресетить изменения и вернуть их на мастер с форсом
git reset —hard HEAD~1
git push origin master -f

2.4 Основы Git — Операции отмены

В любой момент вам может потребоваться что-либо отменить. Здесь мы рассмотрим несколько основных способов отмены сделанных изменений. Будьте осторожны, не все операции отмены в свою очередь можно отменить! Это одна из редких областей Git, где неверными действиями можно необратимо удалить результаты своей работы.

Отмена может потребоваться, если вы сделали коммит слишком рано, например, забыв добавить какие-то файлы или комментарий к коммиту. Если вы хотите переделать коммит — внесите необходимые изменения, добавьте их в индекс и сделайте коммит ещё раз, указав параметр —amend :

$ git commit --amend

Эта команда использует область подготовки (индекс) для внесения правок в коммит. Если вы ничего не меняли с момента последнего коммита (например, команда запущена сразу после предыдущего коммита), то снимок состояния останется в точности таким же, а всё что вы сможете изменить — это ваше сообщение к коммиту.

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

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

$ git commit -m 'Initial commit' $ git add forgotten_file $ git commit --amend

В итоге получится единый коммит — второй коммит заменит результаты первого.

Примечание

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

Очевидно, смысл изменения коммитов в добавлении незначительных правок в последние коммиты и, при этом, в избежании засорения истории сообщениями вида «Ой, забыл добавить файл» или «Исправление грамматической ошибки».

Отмена индексации файла

Следующие два раздела демонстрируют как работать с индексом и изменениями в рабочем каталоге. Радует, что команда, которой вы определяете состояние этих областей, также подсказывает вам как отменять изменения в них. Например, вы изменили два файла и хотите добавить их в разные коммиты, но случайно выполнили команду git add * и добавили в индекс оба. Как исключить из индекса один из них? Команда git status напомнит вам:

$ git add * $ git status On branch master Changes to be committed: (use "git reset HEAD . " to unstage) renamed: README.md -> README modified: CONTRIBUTING.md

Прямо под текстом «Changes to be committed» говорится: используйте git reset HEAD …​ для исключения из индекса. Давайте последуем этому совету и отменим индексирование файла CONTRIBUTING.md :

$ git reset HEAD CONTRIBUTING.md Unstaged changes after reset: M CONTRIBUTING.md $ git status On branch master Changes to be committed: (use "git reset HEAD . " to unstage) renamed: README.md -> README Changes not staged for commit: (use "git add . " to update what will be committed) (use "git checkout -- . " to discard changes in working directory) modified: CONTRIBUTING.md

Команда выглядит несколько странно, но — работает! Файл CONTRIBUTING.md изменен, но больше не добавлен в индекс.

Примечание

Команда git reset может быть опасной если вызвать её с параметром —hard . В приведённом примере файл не был затронут, следовательно команда относительно безопасна.

На текущий момент этот магический вызов — всё, что вам нужно знать о команде git reset . Мы рассмотрим в деталях что именно делает reset и как с её помощью делать действительно интересные вещи в разделе Раскрытие тайн reset главы 7.

Отмена изменений в файле

Что делать, если вы поняли, что не хотите сохранять свои изменения файла CONTRIBUTING.md ? Как можно просто отменить изменения в нём — вернуть к тому состоянию, которое было в последнем коммите (или к начальному после клонирования, или ещё как-то полученному)? Нам повезло, что git status подсказывает и это тоже.

В выводе команды из последнего примера список изменений выглядит примерно так:

Changes not staged for commit: (use "git add . " to update what will be committed) (use "git checkout -- . " to discard changes in working directory) modified: CONTRIBUTING.md

Здесь явно сказано как отменить существующие изменения. Давайте так и сделаем:

$ git checkout -- CONTRIBUTING.md $ git status On branch master Changes to be committed: (use "git reset HEAD . " to unstage) renamed: README.md -> README

Как видите, откат изменений выполнен.

Важно понимать, что git checkout — — опасная команда. Все локальные изменения в файле пропадут — Git просто заменит его версией из последнего коммита. Ни в коем случае не используйте эту команду, если вы не уверены, что изменения в файле вам не нужны.

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

Помните, всё что попало в коммит почти всегда Git может восстановить. Можно восстановить даже коммиты из веток, которые были удалены, или коммиты, перезаписанные параметром —amend (см. Восстановление данных). Но всё, что не было включено в коммит и потеряно — скорее всего, потеряно навсегда.

Отмена действий с помощью git restore

Git версии 2.23.0 представил новую команду: git restore . По сути, это альтернатива git reset, которую мы только что рассмотрели. Начиная с версии 2.23.0, Git будет использовать git restore вместо git reset для многих операций отмены.

Давайте проследим наши шаги и отменим действия с помощью git restore вместо git reset .

Отмена индексации файла с помощью git restore

В следующих двух разделах показано, как работать с индексом и изменениями рабочей копии с помощью git restore . Приятно то, что команда, которую вы используете для определения состояния этих двух областей, также напоминает вам, как отменить изменения в них. Например, предположим, что вы изменили два файла и хотите зафиксировать их как два отдельных изменения, но случайно набираете git add * и индексируете их оба. Как вы можете убрать из индекса один из двух? Команда git status напоминает вам:

$ git add * $ git status On branch master Changes to be committed: (use "git restore --staged . " to unstage) modified: CONTRIBUTING.md renamed: README.md -> README

Прямо под текстом «Changes to be committed», написано использовать git restore —staged …​ для отмены индексации файла. Итак, давайте воспользуемся этим советом, чтобы убрать из индекса файл CONTRIBUTING.md :

$ git restore --staged CONTRIBUTING.md $ git status On branch master Changes to be committed: (use "git restore --staged . " to unstage) renamed: README.md -> README Changes not staged for commit: (use "git add . " to update what will be committed) (use "git restore . " to discard changes in working directory) modified: CONTRIBUTING.md

Файл CONTRIBUTING.md изменен, но снова не индексирован.

Откат изменённого файла с помощью git restore

Что, если вы поймете, что не хотите сохранять изменения в файле CONTRIBUTING.md ? Как легко его откатить — вернуть обратно к тому, как он выглядел при последнем коммите (или изначально клонирован, или каким-либо образом помещён в рабочий каталог)? К счастью, git status тоже говорит, как это сделать. В выводе последнего примера, неиндексированная область выглядит следующим образом:

Changes not staged for commit: (use "git add . " to update what will be committed) (use "git restore . " to discard changes in working directory) modified: CONTRIBUTING.md

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

$ git restore CONTRIBUTING.md $ git status On branch master Changes to be committed: (use "git restore --staged . " to unstage) renamed: README.md -> README

Важно понимать, что git restore — опасная команда. Любые локальные изменения, внесённые в этот файл, исчезнут — Git просто заменит файл последней зафиксированной версией. Никогда не используйте эту команду, если точно не знаете, нужны ли вам эти несохранённые локальные изменения.

Как отменить последний push?

Допустим сделал push, но теперь нужно отменить этот последний пуш из-за ошибки.
Как это правильно сделать? Ветка master P.S. по просьбе выложил ответ от команды git reflog , названия коммитов вымышленные, т.к. на задачу большого значения не влияют

$ git reflog 4e212ca (HEAD -> master, origin/master, origin/HEAD) HEAD@: commit: мой последний коммит e12ea6d HEAD@: reset: moving to HEAD^ 132ae6f HEAD@: commit: ещё один коммит e43ea6d HEAD@: commit: ещё один коммит 2234538 HEAD@: pull: Fast-forward 89543c9 HEAD@: commit: fix search 

Отслеживать
задан 13 фев 2018 в 6:39
2,790 4 4 золотых знака 31 31 серебряный знак 69 69 бронзовых знаков
какая ошибка была?
13 фев 2018 в 7:07
просто чуть не то сделал и запушил
13 фев 2018 в 7:08

сделайте коммит-откат (git revert) и запуште. push c force — это очень плохо (особенно, если работаете в команде)

13 фев 2018 в 7:13
ассоциация: stackoverflow.com/questions/2389361
19 ноя 2018 в 10:48

3 ответа 3

Сортировка: Сброс на вариант по умолчанию

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

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

В принципе, если вы работали из командной строки и ещё не успели её закрыть – то можете просто посмотреть, какой коммит был последним:

git commit -m "asdf" [master 6703d65] asdf 1 file changed, 3 insertions(+), 3 deletions(-) git push Counting objects: 4, done. Delta compression using up to 8 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (4/4), 407 bytes | 407.00 KiB/s, done. Total 4 (delta 2), reused 0 (delta 0) To git.mydomain.tld:folder/repo.git 743acea..6703d65 master -> master 

Последняя строчка говорит, что ДО push’а последний коммит был 743acea, а стал 6703d65 — вот и вернитесь к 743acea:

git reset --hard 743acea git push --force 

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

git reset --hard HEAD~1 git push --force 

Вообще же лучше всего прочитать рефлог ( git reflog ) и откатиться к нужному коммиту через HEAD@ (уточните цифру сколько действий нужно отменить именно в вашем случае):

git reset --hard HEAD@ git push --force 
$ git reflog 6703d65 (HEAD -> master, origin/master, origin/HEAD) HEAD@: commit: asdf 743acea HEAD@: commit: asdf 1a4e976 HEAD@: commit: something . 

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

$ git reset --hard HEAD@

Envek / rescue-from-git-push-force.md

Иногда при работе с несколькими удалёнными репозиториями в git, может произойти страшное: git push —force в не тот remote и/или не в ту ветку.

Такое может случиться, например, если вы используете Deis, в котором деплой запускается при git push нужного коммита в сборщик, когда при отладке деплоя после очередного git commit —amend по запарке вместо git push deis master —force делается просто git push —force . Упс.

Как результат, последние коммиты коллег безвозвратно потеряны, и вы чувствуете неотвратимость их ярости…

Но это git, а значит всё можно починить!

Вариант самый простой и для ленивых

Немедленно врывайтесь в рабочий чат с воплем «кто последний пушил в branchname? форс-пушните вашу версию ветки!». С какой-то долей вероятности последним сделает git push —force именно тот коллега, у которого самая свежая версия кода.

Простой вариант: я последний пушил в ветку

Этот вариант прост тем, что у вас есть всё, что нужно для восстановления за 1 минуту, не выходя из консоли.

Перво-наперво: без паники. Не закрывайте терминал!

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

В выводе команды git push —force найдите строчку, похожую на эту:

 + deadbeef. f00f00ba master -> master (forced update) 

Первая группа символов, подозрительно похожих на SHA коммита и есть наш ключ к спасению: deadbeef — это действительно коммит, который был в ветке master до того, как мы всё сломали. Теперь просто пушните этот коммит в ветку, которую вы поломали:

git push --force origin deadbeef:master 

Всё, вы всех спасли. Но больше так не делайте.

Сложный вариант: починить за кем-то

Иногда бывает, что git push —force сделали либо не вы, либо кто-то принял пачку Pull Request’ов в то время, пока вы веселились со своими экспериментами.

Тяжесть ситуации в том, что вы не можете просто сделать git push —force sha1:master , поскольку у вас локально нет коммитов, которые нужно восстановить (и у вас не получиться скачать их с помощью git fetch ).

Стоп! Без паники! Зайдите в чат, покайтесь, скажите, чтобы никто ничего не делал — вам понадобится время, чтобы всё вернуть.

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

Если force-пуш сделали вы, то просто возьмите хэш коммита, который был в ветке до вас (как и в прошлом пункте). Если не вы, то можно зайти в ленту событий GitHub’а (на главной странице, в случае, если вы подписаны на репозиторий) и посмотреть, кто последний коммитил в эту ветку:

an hour ago Username pushed to master at org/repo - deadbeef Implement foo - deadf00d Fix bar 

Теперь перейдите по ссылке https://github.com/org/repo/tree/deadbeef (где deadbeef — хэш последнего коммита в ветке, которую вы перетёрли), откройте переключатель веток и тэгов, введите имя для новой ветки (например master-before-force-push ) и выберите пункт «Create branch».

Теперь через консоль можно получить недостающие коммиты:

$ git fetch From github.com:org/repo * [new branch] master-before-force-push -> origin/master-before-force-push

и теперь задача сводится к предыдущей:

git push --force origin origin/master-before-force-push:master 

Если наработки в вашем master е ещё нужны, то лучше отребейзить свои коммиты поверх него:

git rebase origin/master 

Как избежать такого в дальнейшем?

  1. В GitHub и GitLab есть функциональность под названием «защищённые ветки» (protected branches). Отметьте master , develop , stable или какие ещё ветки важны для вас как защищённые и система не даст вам выстрелить себе в ногу. Если force push всё же понадобится, то защиту всегда можно на время снять. См. документацию: https://help.github.com/articles/defining-the-mergeability-of-pull-requests/
  2. Используйте вместо ключа —force ключ —force-with-lease , который отменит push, если кто-то другой уже успел опубликовать новые коммиты. Подробнее здесь: https://developer.atlassian.com/blog/2015/04/force-with-lease/
  3. Создайте алиасы для команд, которые должны делать git push —force , чтобы обезопасить себя от ошибок по неосторожности:
# ~/.gitconfig [alias] deploy = "!git push --force deis \"$(git rev-parse --abbrev-ref HEAD):master\"" 

Pro Tip: У команды git push также ещё очень хорошо сочетаются друг с другом ключи —force и —all , особенно, если вы отвлеклись от проекта на месяцок-другой. Попробуйте, если, конечно, вам всё ещё мало приключений…

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *