Git: восстановить удаленную (удаленную) ветку

95

Мне нужно восстановить две ветки Git, которые я каким-то образом удалил во время push.

Эти две ветки были созданы в другой системе и затем помещены в мой «общий» (github) репозиторий.

В моей системе я (по-видимому) получил ветки во время выборки:

~/myfolder> git fetch
remote: Counting objects: 105, done.
remote: Compressing objects: 100% (58/58), done.
remote: Total 62 (delta 29), reused 0 (delta 0)
Unpacking objects: 100% (62/62), done.
From github.com:mygiturl
 * [new branch]      contact_page -> origin/contact_page
   731d1bb..e8b68cc  homepage   -> origin/homepage
 * [new branch]      new_pictures -> origin/new_pictures

Сразу после этого я отправил свои локальные изменения в центральное репо. По какой-то причине эти ветки были удалены как из моей локальной системы, так и из центрального репо:

~/myfolder> git push
Counting objects: 71, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (43/43), done.
Writing objects: 100% (49/49), 4.99 KiB, done.
Total 49 (delta 33), reused 0 (delta 0)
To git@github.com:mygiturl.git
 - [deleted]         contact_page
 + e8b68cc...731d1bb homepage -> homepage (forced update)
   bb7e9f2..e0d061c  master -> master
 - [deleted]         new_pictures
   e38ac2e..bb7e9f2  origin/HEAD -> origin/HEAD
   731d1bb..e8b68cc  origin/homepage -> origin/homepage
   e38ac2e..bb7e9f2  origin/master -> origin/master
 * [new branch]      origin/contact_page -> origin/contact_page
 * [new branch]      origin/new_pictures -> origin/new_pictures

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

Вся информация о git "undo", которую я нашел в Google, связана с восстановлением потерянных коммитов. Я не думаю, что здесь это применимо, поскольку у меня нет идентификаторов фиксации для этих веток.

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

РЕДАКТИРОВАТЬ: по запросу, вот моя конфигурация репо

user.name=Craig Walker
user.email=github@softcraft.ca
alias.unadd=reset HEAD
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.ignorecase=true
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
remote.origin.url=git@github.com:MyGitURL.git
remote.origin.mirror=true
branch.master.remote=origin
branch.master.merge=refs/heads/master
alias.undo=reset --hard
alias.test=push -f ci HEAD:master
alias.st=status
alias.ci=commit
alias.br=branch
alias.co=checkout
alias.ch=checkout
alias.df=diff
alias.lg=log -p
alias.who=shortlog -s --
remote.ci.url=ContinuousIntegrationGitURL
remote.ci.fetch=+refs/heads/*:refs/remotes/ci/*
branch.photo.remote=origin
branch.photo.merge=refs/heads/photos
remote.foo.url=FooGitURL
remote.foo.fetch=+refs/heads/*:refs/remotes/cynthia/*
branch.homepage.remote=origin
branch.homepage.merge=refs/heads/homepage
Крэйг Уокер
источник
Похоже, у вас «необычная» или несоответствующая конфигурация извлечения и отправки. Что git config -lпоказывает локальный репозиторий?
CB Bailey
Вполне возможно; Я выложил это.
Крейг Уокер
2
Ваш remote.origin.fetchrefspec не подходит для использования с remote.origin.mirror = true. Вы хотите отразить или использовать репозиторий GitHub как обычный пульт? В моем ответе должны быть команды, которые вам нужны в любом случае.
Крис Джонсен
Я предполагаю, что со вторым репозиторием зеркальное отображение больше не является вариантом (вероятно, это в первую очередь вызвало удаление).
Крейг Уокер,

Ответы:

103

Я не специалист. Но ты можешь попробовать

git fsck --full --no-reflogs | grep commit

чтобы найти фиксацию HEAD удаленной ветки и вернуть их.

iamamac
источник
Я пробовал fsck раньше; ты знаешь, как узнать, какой коммит правильный? У меня есть 20 попыток.
Craig Walker
1
Это сделало это; как только я получил сообщения фиксации, я git branch <uid>получил их обратно. Благодарность!
Крейг Уокер,
Приятно слышать. Не забудьте также разрешить конфликт между вашим remotes.origin.mirrorи remotes.origin.fetchнастройками, в противном случае вы обязаны снова столкнуться с проблемой (или неумышленно CLOBBER фиксаций толкнули от других сделок РЕПО).
Крис Джонсен
@Craig: Рад быть полезным :)
iamamac
3
Сегодня я потерял ветку релиз-кандидата. Не знал идентификатор фиксации. Получил восстановление с помощью:git fsck --full --no-reflogs | cut -d' ' -f3 | xargs -P8 git log --oneline | grep 'Release 2.60.0.157'
spezifanta 05
23

всего две команды спасают мою жизнь

1. Это список всех предыдущих заголовков

git reflog

2. Это вернет HEAD для фиксации, которую вы удалили.

git reset --hard <your deleted commit>
ex. git reset --hard b4b2c02
Chinnawatp
источник
1
Я никогда не заходил в ветку локально, поэтому моего HEAD там никогда не было, поэтому я не могу найти идентификатор фиксации с git reflog. Что еще я могу попробовать?
зыы
1
То же, что и @zyy Коммит был удален другим членом команды удаленно, поэтому мне нужно вернуть его на свой локальный компьютер (у меня никогда не было этого коммита локально) и вернуть его обратно ...
ОмГанеш,
11

Ваши удаленные ветки не потеряны, они были скопированы в origin / contact_page и origin / new_pictures «ветки удаленного отслеживания» с помощью полученной вами выборки (они также были вытеснены назад показанным вами push, но они были помещены в refs / remotes / origin / вместо refs / heads /). Проверьте git log origin/contact_pageи , git log origin/new_picturesчтобы увидеть , если ваши локальные копии «до даты» с тем, что вы думаете , должны быть там. Если какие-либо новые коммиты были помещены в эти ветки (из какого-то другого репо) между извлечением и отправкой, которые вы показали, вы могли их «потерять» (но, вероятно, вы могли бы найти их в другом репо, которое совсем недавно подтолкнуло эти ветки) .

Конфликт загрузки / извлечения

Похоже, вы выполняете выборку в обычном, «удаленном режиме» (удаленные ссылки / головы / хранятся локально в refs / remotes / origin /), но нажимаете в «зеркальном режиме» (локальные ссылки / помещаются в удаленные ссылки /) . Проверьте .git / конфигурацию и примирить remote.origin.fetchи remote.origin.pushнастройку.

Сделать резервную копию

Прежде чем пытаться внести какие-либо изменения, создайте простой tar или zip-архив или все локальное репо. Таким образом, если вам не нравится то, что происходит, вы можете попробовать еще раз из восстановленного репо.

Вариант A: перенастроить как зеркало

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

git branch contact_page origin/contact_page &&
git branch new_pictures origin/new_pictures &&
git config remote.origin.fetch '+refs/*:refs/*' &&
git config --unset remote.origin.push &&
git config remote.origin.mirror true

Вы также можете в конечном итоге удалить все ваши refs / remotes / origin / refs, поскольку они бесполезны, если вы работаете в зеркальном режиме (ваши обычные ветки заменяют обычные ветки удаленного отслеживания).

Вариант B: перенастроить как обычный пульт

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

git config push.default tracking &&
git config --unset remote.origin.push
git config --unset remote.origin.mirror

Затем, вы в конечном итоге хотите удалить фиктивные ссылки / пультов ДУ / происхождения рефов в удаленном репо: git push origin :refs/remotes/origin/contact_page :refs/remotes/origin/new_pictures ….

Тестовый толчок

Попробуйте git push --dry-runпосмотреть, что он git pushбудет делать, не внося никаких изменений в удаленное репо. Если вам не нравится то, что он собирается делать, восстановитесь из резервной копии (tar / zip) и попробуйте другой вариант.

Крис Джонсен
источник
1
Я не думаю, что ветки удаленного отслеживания сохранились, если они вообще были скопированы. 'git branch -a' их не показывает, и я также не могу найти файлы с такими именами в каталоге .git. Наконец, рекомендуемые вами команды «git log» возвращают «фатальный: неоднозначный аргумент 'origin / contact_page': неизвестная ревизия или путь не в рабочем дереве»: - \ Тем не менее, спасибо.
Крейг Уокер
1
Ну, эти ветки были там, ваш журнал push показывает это. При поиске ссылок в .gitкаталоге обязательно проверьте .git/packed_refsв дополнение к .git/refs/. git show-refвыгружает всех ваших местных референсов (упакованных или «незакрепленных»). Вы по-прежнему сможете найти ссылки в репозитории, которые изначально отправили их в репозиторий GitHub (на другом компьютере? В чужом репо?). В противном случае, до тех пор , пока вы не сделали дс или чернослив, вы должны быть в состоянии к git fsckвыходу , чтобы исследовать свисающие фиксаций и их прикрепить: git branch contact_page-recovered <SHA-1-of-dangling-commit>.
Крис Джонсен
Pack_refs тоже не было. Коммиты определенно болтались; не знаю, как это случилось. Спасибо за вашу помощь!
Крейг Уокер,
8

Если удаление произошло достаточно недавно (например, в момент О-НЕТ!), Вы все равно должны получить сообщение:

Deleted branch <branch name> (was abcdefghi).

вы все еще можете бегать:

git checkout abcdefghi

git checkout -b <some new branch name or the old one>

Тимми
источник
8
  1. узнать идентификатор Коиммита

    git reflog

  2. восстановить локальную ветку, которую вы удалили по ошибке

    git branch need-recover-branch-name commitId

  3. снова нажмите need-recovery-branch-name, если вы тоже удалили удаленную ветку

    git push origin need-recover-branch-name

JackChouMine
источник
2
Это сработало для меня. Я предпочитаю принятый ответ, потому что это было намного меньше шагов. Я смог увидеть свое сообщение о фиксации git reflog, вместо того, чтобы угадывать и git show.
theUtherSide
3

Данные все еще существуют в github, вы можете создать новую ветку из старых данных:

git checkout origin/BranchName #get a readonly pointer to the old branch
git checkout –b BranchName #create a new branch from the old
git push origin BranchName #publish the new branch
Jhilden
источник
1

Я думаю, что у вас несоответствующая конфигурация для «выборки» и «толчка», поэтому это привело к тому, что выборка / отправка по умолчанию не выполнялась должным образом. К счастью, вы получили ветки, которые впоследствии удалили, так что вы сможете воссоздать их с помощью явного нажатия.

git push origin origin/contact_page:contact_page origin/new_pictures:new_pictures
CB Bailey
источник
Как и в случае с моим комментарием к @Chris Johnson, похоже, что ветки больше (никогда?) Не существуют локально. Когда я git push origin origin/contact_page:contact_pageполучаю это: error: src refspec origin/contact_page does not match any
Крейг Уокер
Хорошо, я думаю, что понимаю, что произошло (хотя полная ошибка была бы полезна). push обновил удаленную ветку и удалил ссылку локально, а также ссылку для отслеживания. Что git rev-parse refs/remotes/origin/origin/contact_pageговорит? Из-за фальшивой конфигурации «зеркало» ветка my теперь упоминается здесь, в локальном репозитории.
CB Bailey
Привет, Чарльз; Поскольку я написал это, я изменил (и исправил) свою конфигурацию, поэтому я больше не могу получить (значительный) вывод rev-parse. Однако я не думаю, что в пультах был двойной вложенный каталог "origin".
Крейг Уокер
0

Если ваша организация использует JIRA или другую подобную систему, связанную с git, вы можете найти коммиты, перечисленные в самом билете, и щелкнуть ссылки на изменения кода. Github удаляет ветку, но коммиты по-прежнему доступны для выбора.

Рорали
источник
-1

Это может показаться слишком осторожным, но я часто заархивирую копию всего, над чем я работал, прежде чем вносить изменения в систему контроля версий. В проекте Gitlab, над которым я работаю, я недавно по ошибке удалил удаленную ветку, которую хотел сохранить после слияния запроса на слияние. Оказывается, все, что мне нужно было сделать, чтобы вернуть его с историей коммитов, - это снова нажать. Запрос на слияние все еще отслеживался Gitlab, поэтому справа от ветки по-прежнему отображается синяя метка «объединено». Я все еще заархивировал свою локальную папку на случай, если что-то случится.

Арториас2718
источник