Как я могу восстановиться после ошибочного git push -f origin master?

93

Я просто добавил неправильный источник в свой проект, используя --force option.

Можно ли вернуться? Я понимаю, что все предыдущие ветки были перезаписаны с использованием -foption, поэтому я, возможно, испортил свои предыдущие версии.

Дэвид ван Дугтерен
источник
возможный дубликат Есть ли способ отменить git push -f?
cmbuckley

Ответы:

55

Git обычно ничего не выбрасывает, но восстановление после этого может быть непростым.

Если у вас есть правильный источник, вы можете просто вставить его в пульт с --forceопцией. Git не удалит никаких веток, если вы ему не скажете. Если вы действительно потеряли коммиты, взгляните на это полезное руководство по восстановлению коммитов . Если вы знаете SHA-1 коммитов, которые вам нужны, то, вероятно, все в порядке.

Лучшее, что можно сделать: создать резервную копию всего и посмотреть, что еще находится в вашем локальном репозитории. Если возможно, сделайте то же самое на пульте. Используйте, git fsckчтобы узнать, можете ли вы восстановить вещи, и, прежде всего, НЕ запускайтеgit gc .

Прежде всего, никогда не используйте эту --forceопцию, если вы действительно, действительно серьезно этого не понимаете.

Кэмерон Скиннер
источник
65
Скорее всего, вы можете просто посмотреть рефлоги, чтобы определить, где изначально находились удаленные ветки. Например, git reflog show remotes/origin/master. Вы должны увидеть там свой толчок; коммит в предыдущей строке находится там, где он был до того, как вы его испортили. Затем вы можете просто отправить эту ревизию (с --force) в исходную точку и вернуться туда, где вы были!
Cascabel
@ Дэвид: Ой. Вы не упомянули в своем вопросе, что у вас нет репо. (Это, конечно, то, что вы никогда не захотите делать.) Однако, если у вас есть доступ к файловой системе, на которую вы нажали, вы все равно можете делать все это там.
Cascabel
1
@ Дэвид: Ой. Всегда хорошо иметь текущий каталог как часть вашего приглашения, чтобы избежать подобных вещей.
Cascabel
1
@Jefromi Я думаю, что то, что вы сказали, является фактическим ответом: даже со старой версией (которая не git fetchредактировалась в течение длительного времени) вы можете отобразить журнал ссылок на стороне GitHub и восстановить!
nh2
1
Где этот ответ @Jefromi? Я не вижу этого пользователя, упомянутого на этой странице, за пределами этой ветки комментариев.
Don McCurdy
47

Если вы знаете хеш фиксации, это легко, просто создайте свою ветку заново.

5794458...b459f069 master -> master (forced update)

Удалите удаленную ветку:

git push origin :master

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

git checkout 5794458
git branch master
git push origin master
user1094125
источник
28

Решение уже упоминалось здесь

# work on local master
git checkout master

# reset to the previous state of origin/master, as recorded by reflog
git reset --hard origin/master@{1}

# at this point verify that this is indeed the desired commit.
# (if necessary, use git reflog to find the right one, and
# git reset --hard to that one)

# finally, push the master branch (and only the master branch) to the server
git push -f origin master
Абдельхафид
источник
Спасибо, у меня это сработало. У меня не было доступа для удаления мастера, поэтому одобренный комментарий не прошел.
Andi
Да, и git reflog show remotes/origin/masterесли необходим git reflog (как упомянуто @Cascabel выше)
Джозия Йодер
2
Это правильный ответ, спасибо за ссылку на правильный.
Noitidart
6

Если вы не находитесь в том локальном репо, откуда поступил принудительный толчок, на уровне источника / мастера нет возможности восстановить. Но если вам посчастливилось использовать GitHub или GitHub for Enterprise , вы можете взглянуть на REST API и получить потерянную фиксацию в качестве патча, например:

  1. Перечислите события и найдите формат фиксации sha1 long

https://api.github.com/repos/apache/logging-log4j2/events

  1. Загрузите потерянный коммит и получите соответствующий патч в пути json .files [] / patch

https://api.github.com/repos/apache/logging-log4j2/commit/889232e28f3863d2a17392c06c1dd8cac68485de

  1. Нанесите локально и нажмите снова

git apply patch.patch && git commit -m "восстановленная фиксация" && git push origin master

Пьеррик ГИМБЕРТ
источник
4

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

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

Машина CI может даже сохранить локальный клон репозитория, из которого вы сможете выполнить это восстановление.

Источник: вероятно, непрерывная доставка: надежные выпуски программного обеспечения с помощью автоматизации сборки, тестирования и развертывания (серия подписей Аддисона-Уэсли (Фаулер))

user7610
источник
3

Да, вы можете восстановить коммиты после git push -f your_branch

Текст из документа :

Удалять записи старше указанного времени. Если этот параметр не указан, срок действия берется из параметра конфигурации gc.reflogExpire, который, в свою очередь, по умолчанию равен 90 дням. --expire = все записи чернослива независимо от их возраста; --expire = никогда не отключает сокращение доступных записей (но см. --expire-unreachable).

Итак, вы можете:

1- git reflog

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

2- вы выбираете Head_Number, хотите ли вы восстановить git reset –hard HEAD@{HEAD-NUMBER}

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

3- вы можете увидеть все коммиты в этой главе git cherry -v branch_name

4- в конце вы должны заставить толкнуть git push -f branch_name

ИЛИ

1- получить номер SHA от вашего клиента GIT (интерфейс)

git reset --hard commit_SHA

2- принудительный толчок

git push -f your_branch

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

Джейкоб
источник
2

Я сделал то же самое, отменив последнее нажатие только для одного файла. Завершился возврат к исходному состоянию репозитория. Я использовал команды git от Линуса, поскольку у меня была локальная копия в Linux. К счастью, эта копия осталась нетронутой.

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

git add .
git status

(он сказал, что origin / master был впереди на 68 коммитов, хорошо ... это были все коммиты, которые я удалил)

git remote set-url origin <GIT_SSH_URL>
git push

И все вернулось так, как было до того, как я сделал сильный толчок. Самая важная вещь, о которой следует помнить, - никогда не выполнять проверку с помощью git. после того, как вы сильно толкнули. Но лучше всего отключить опцию push. Я больше никогда им не пользуюсь. Выучил урок !!

Пран
источник
1

Для людей, находящихся в действительно плохих ситуациях, как я (например, если вы получаете bad objectошибки при работе git reset --hard):

Я написал скрипт под названием treeaver, который в крайнем случае извлекает все ваши файлы из GitHub API. Вот как им пользоваться:

  1. Клонируйте treesaverсценарий и cdк нему.
  2. Найдите SHAстроку дерева, которую вы хотите восстановить, открыв https://api.github.com/repos/<your_username_or_org>/<repo>/events .
  3. В payloadсвойстве, соответствующем вашему push-событию, найдите commitто, к чему вы хотите вернуться, и нажмите на него url.
  4. Под commit.treeскопируйте treeфайл url.
  5. Беги python3 main.py <tree_url> <path_to_save_to>.

Например, в моем случае я бы запустил:

python3 main.py https://api.github.com/repos/anthonykrivonos/my-repo/git/trees/1234567 .

Конечно, пиар приветствуется.

Энтони Кривонос
источник
0

Здесь вы можете прочитать решения https://evilmartians.com/chronicles/git-push---force-and-how-to-deal-with-it

Второй мне помог. Я ошибся в этих командах

1) (some-branch) git pull -> correct command was git pull origin some-branch

2) (some-branch) git push -f origin some-branch

После этих команд я потерял три коммита. Чтобы восстановить их, я посмотрел на терминал, где я ошибочно сделал git pull, и увидел там вывод вроде

60223bf ... 0b258eb некоторая ветка -> происхождение / некоторая ветка

Второй хеш 0b258eb был именно тем, что мне было нужно. Итак, я взял этот хеш и произвел команду

git push --force origin 0b258eb:some-branch
Андрей
источник