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.