Git: Відновлення видаленої (віддаленої) гілки


94

Мені потрібно відновити дві гілки Git, які я якось видалив під час натискання.

Ці дві гілки були створені в іншій системі, а потім передані до мого "спільного" (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 "скасувати", яку я погуглив, має відновити втрачені коміти. Я не думаю, що це стосується тут, оскільки я не маю комітів UID для цих гілок.

Я хотів би знати, як я можу їх отримати назад. Я також хотів би знати, як їх видалили спочатку і як я можу цього уникнути в майбутньому.

EDIT: за запитом, ось моя конфігурація репо

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 як звичайний пульт? У моїй відповіді повинні бути команди, які вам потрібні в будь-якому випадку.
Кріс Джонсен

Я здогадуюсь, що у 2-му сховищі дзеркальне відображення більше не є варіантом (це, ймовірно, спричинило видалення).
Крейг Уокер

Відповіді:


103

Я не фахівець. Але можна спробувати

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

знайти коміт HEAD видаленої гілки та отримати їх назад.


Я спробував fsck раніше; Ви знаєте, як дізнатись, який коміт є правильним? Мені потрібно 20 спробувати.
Крейг Уокер

1
Це зробило це; одного разу я отримав повідомлення коміту, git branch <uid>отримав їх назад. Дякую!
Крейг Уокер

Радий чути. Не забудьте також вирішити конфлікт між вашими remotes.origin.mirrorта remotes.origin.fetchналаштуваннями, інакше ви неодмінно зіткнетеся з проблемою ще раз (або ненавмисно коміт-клобери, витіснені з інших репозиторіїв).
Chris Johnsen

@Craig: Радий бути корисним :)
iamamac

3
Сьогодні я втратив відділення кандидата на випуск Не знав ідентифікатора коміту. Отримав це за допомогою:git fsck --full --no-reflogs | cut -d' ' -f3 | xargs -P8 git log --oneline | grep 'Release 2.60.0.157'
spezifanta

23

лише дві команди рятують мені життя

1. Тут буде перераховано всі попередні ГОЛОВИ

git reflog

2. Це поверне HEAD до коміту, який ви видалили.

git reset --hard <your deleted commit>
ex. git reset --hard b4b2c02

1
Я ніколи не реєструвався у гілці локально, тому мій HEAD ніколи там не був, тому я не можу знайти ідентифікатор коміту git reflog. Чи можу я ще щось спробувати?
zyy

1
Так само, як @zyy Фіксація була видалена іншим членом команди у віддаленому режимі, тому я повинен повернути його на свою локальну машину (я ніколи цього не робив локально) і відсунути назад ...
OmGanesh

11

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

Вибір / висунення конфлікту

Схоже, ви виконуєте вибірку в звичайному `` віддаленому режимі '' (віддалені посилання / голови / зберігаються локально в refs / remotes / origin /), але натискаєте в `` дзеркальному режимі '' (локальні посилання / переносяться на віддалені посилання /) . Перевірте свій .git / config та примиріть налаштування remote.origin.fetchта remote.origin.push.

Зробіть резервну копію

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

Варіант А: Переналаштувати як дзеркало

Якщо ви маєте намір використовувати віддалений репо як дзеркало локального, зробіть наступне:

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", які ви рекомендували повернути, "fatal: неоднозначний аргумент 'origin / contact_page': невідома редакція або шлях, що не в робочому дереві": - \ Хоча дякую.
Крейг Уолкер

1
Ну, ці гілки були там, ваш журнал відштовхувань це показує. Шукаючи посилання в .gitпапці, обов’язково перевірте .git/packed_refsдодатково .git/refs/. git show-refвикине всі ваші місцеві посилання (упаковані чи «вільні»). Ви все одно зможете знайти посилання на репо, які спочатку підштовхували їх до вашого репозиторію GitHub (на іншій машині? Чиєсь репо?). В іншому випадку, до тих пір , поки ви не зробили дс або чорнослив, ви повинні бути в змозі до git fsckвиходу , щоб досліджувати звисають фіксацій і їх прикріпити: git branch contact_page-recovered <SHA-1-of-dangling-commit>.
Chris Johnsen

packed_refs теж цього не мав. Комісії, безумовно, звисали; не уявляю, як це сталося. Дякую за вашу допомогу!
Крейг Уолкер,

8

Якщо видалення є недавнім (наприклад, "О-НІ!"), У вас все одно має бути повідомлення:

Deleted branch <branch name> (was abcdefghi).

Ви все ще можете запустити:

git checkout abcdefghi

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


8
  1. дізнатися ідентифікатор coimmit

    git reflog

  2. відновити локальну гілку, яку ви помилково видалили

    git branch need-recover-branch-name commitId

  3. ще раз натисніть push-recovery-branch-name, якщо ви також раніше видаляли віддалену гілку

    git push origin need-recover-branch-name


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

1

Я думаю, що у вас є невідповідна конфігурація для 'fetch' та 'push', тож це призвело до того, що вибір за замовчуванням fetch / push не відповідає правильному напрямку. На щастя, ви дістали гілки, які згодом видалили, тому ви зможете відтворити їх за допомогою явного натискання.

git push origin origin/contact_page:contact_page origin/new_pictures:new_pictures

Як і у випадку з моїм коментарем @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

Привіт Чарльз; Оскільки я це написав, я змінив (і виправив) свою конфігурацію, тому я більше не можу отримати (означальний) вивід синтаксичного аналізу. Однак я не думаю, що у віддалених системах існував подвійний вкладений каталог "origin".
Крейг Уокер

0

Якщо ваша організація використовує JIRA або іншу подібну систему, яка пов’язана з git, ви можете знайти коміти, перераховані в самому квитку, і натиснути посилання на зміни коду. Github видаляє гілку, але все ще є коміти, доступні для збору вишні.


-1

Це може здатися занадто обережним, але я часто створюю копію того, над чим я працював, перед тим, як внести зміни до джерела. У проекті Gitlab, над яким я працюю, нещодавно помилково видалив віддалену гілку, яку хотів зберегти після об’єднання запиту на об’єднання. Виявляється, все, що мені потрібно було зробити, щоб повернути його з історією комітів, було знову натиснути. Запит на злиття все ще відстежувався Gitlab, тому він все ще відображає синю позначку "злиття" праворуч від гілки. Я все ще стискав свою локальну папку на випадок, якщо трапилось щось погане.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.