Як виправити пошкоджене сховище git?


104

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

christopher@christopher-laptop:~/source/personal$ git clone ~/Ubuntu\ One\ Side\ Work/projects.git/
Cloning into 'projects'...
done.
fatal: unable to read tree 29a422c19251aeaeb907175e9b3219a9bed6c616
christopher@christopher-laptop:~/source/personal$ 

Тож я спробував розглянути багато інших питань, подібних до цього, які були задані тут, і більшість із них кажуть, що потрібно бігти, git fsck --fullі тоді я отримую це, коли намагаюся це.

christopher@christopher-laptop:~/Ubuntu One Side Work/projects.git$ git fsck --full
Checking object directories: 100% (256/256), done.
Checking objects: 100% (447/447), done.
broken link from  commit 235ae1f48701d577d71ebd430344a159e5ba4881
              to  commit 984c11abfc9c2839b386f29c574d9e03383fa589
broken link from    tree 632a9cf0ef9fccea08438b574e2f1c954f4ff08b
              to    blob 25a742dff0a403b2b3884f2ffddf63eb45721fac
broken link from    tree 632a9cf0ef9fccea08438b574e2f1c954f4ff08b
              to    blob dd4e97e22e159a585b20e21028f964827d5afa4e
broken link from    tree 632a9cf0ef9fccea08438b574e2f1c954f4ff08b
              to    tree 29a422c19251aeaeb907175e9b3219a9bed6c616
broken link from    tree 632a9cf0ef9fccea08438b574e2f1c954f4ff08b
              to    tree 8084e8e04d510cc28321f30a9646477cc50c235c
broken link from    tree 774b5b4157b4caae1c6cad96c8eaf5d4eba2c628
              to    blob a0daa0c1567b55d8de2b4d7a3bc010f58c047eab
broken link from    tree 774b5b4157b4caae1c6cad96c8eaf5d4eba2c628
              to    blob e9052d35bfb6d30065b206fc43f4200a04d5281b
broken link from    tree 774b5b4157b4caae1c6cad96c8eaf5d4eba2c628
              to    blob 1a3a5e4dd2502ac121c22f743c4250e254a94eeb
broken link from    tree 4aa336dc1a5838e8918e03b85580069d83f4ad09
              to    tree 8cc55ec952dc192a233e062201d1e7e873ac3db0
broken link from    tree e5674a91a53e15575a1f3bf5786bc5cc719fb483
              to    blob 4a994e1e7bb7ce28dcec98bad48b9a891d7dec51
broken link from    tree e5674a91a53e15575a1f3bf5786bc5cc719fb483
              to    blob ac033bf9dc846101320c96a5ce8aceb8c96ec098
broken link from    tree 252ab84542264e1589576b6ee51e7a31e580a0e2
              to    tree 2069041cd5950e529e2991d37b7290ec021d90d4
broken link from    tree 2d4964aa4d4f5d8c7228518ce72ef6a63f820c6d
              to    blob d83690e1b9a6bdd8a08754b38231799acefcb2ab
broken link from    tree c7192e82fc581bd6448bda1a25e8729bdac5f4ff
              to    blob 30d54d47ae82add1917ca173d42e58b396df580b
broken link from    tree 7c66306901fc71389623286936cef172d4ffe408
              to    blob bc7e05d705401273b1df4e939de0f540597c0931
broken link from    tree 0940f5fd227d4c84d6e6749d872db50a4522ae3a
              to    tree 923767594ac22023e824948d65622fe5b407d1a1
broken link from    tree 8eadcd2a971e8357d24f0d80f993d2963452209f
              to    blob 2598bde3dc8cb80ee49510b8159344004b88645f
broken link from    tree ffa302dd0d969172ef23caeefe856ab2f57a4e4d
              to    blob d6925fa431be1ac585bf9a481e98f75107a6e6fb
broken link from    tree 7045b8870a49ce30a2027537a96d73d162bda773
              to    blob 25688652dea26f61f576ca1b52b9d1a18fbfd01d
broken link from    tree 37e4705d34bd440ce681ae32ae9a180a13256d72
              to    tree 246f564d4cee53339b8a4244f3173b61caa518eb
missing blob d6925fa431be1ac585bf9a481e98f75107a6e6fb
missing blob ac033bf9dc846101320c96a5ce8aceb8c96ec098
missing tree 29a422c19251aeaeb907175e9b3219a9bed6c616
missing tree 8084e8e04d510cc28321f30a9646477cc50c235c
missing blob 30d54d47ae82add1917ca173d42e58b396df580b
missing tree 8cc55ec952dc192a233e062201d1e7e873ac3db0
missing blob e9052d35bfb6d30065b206fc43f4200a04d5281b
dangling tree 4b26e95db542c72ac4a22ec25abe38fb2de79752
missing blob d83690e1b9a6bdd8a08754b38231799acefcb2ab
missing blob 25a742dff0a403b2b3884f2ffddf63eb45721fac
missing tree 923767594ac22023e824948d65622fe5b407d1a1
missing blob 25688652dea26f61f576ca1b52b9d1a18fbfd01d
missing blob 2598bde3dc8cb80ee49510b8159344004b88645f
dangling tree 3a683869f1bb0c1634de75700c316b3b36570dbd
dangling blob 4098d30843380d798a811f1aa9a02994f0dbbb27
missing tree 2069041cd5950e529e2991d37b7290ec021d90d4
missing blob 4a994e1e7bb7ce28dcec98bad48b9a891d7dec51
missing blob 1a3a5e4dd2502ac121c22f743c4250e254a94eeb
missing blob a0daa0c1567b55d8de2b4d7a3bc010f58c047eab
dangling tree 6c7b5162aa7a303fa3fe8dc393c5da564e309521
missing commit 984c11abfc9c2839b386f29c574d9e03383fa589
missing blob bc7e05d705401273b1df4e939de0f540597c0931
missing blob dd4e97e22e159a585b20e21028f964827d5afa4e
missing tree 246f564d4cee53339b8a4244f3173b61caa518eb
dangling commit a01f5c1e5315dc837203d6dee00d3493be9c5db9

Це виглядає дійсно погано. Коли я роблю a, git log | headя отримую це

christopher@christopher-laptop:~/Ubuntu One Side Work/projects.git$ git log | head
error: Could not read 984c11abfc9c2839b386f29c574d9e03383fa589
fatal: Failed to traverse parents of commit 235ae1f48701d577d71ebd430344a159e5ba4881
commit 2fb0d2d0643b445440f01b164f11ee9ee71fca48
Author: christopher <christopher@christopher.christopher>
Date:   Wed Aug 7 15:51:42 2013 -0400

    finishing chapter 7

Інші запитання тут було сказано дивитись ./git/refs/heads/master. Це просто репо і refs/heads/існує, але refs/heads/masterйого немає. ГОЛОВА в голому репо говорить, ref: refs/heads/masterщоправда

packed-refs все-таки це говорить

# pack-refs with: peeled 
2fb0d2d0643b445440f01b164f11ee9ee71fca48 refs/heads/master

Інші запитання пропонують запустити, git reflogі жоден результат не відображається, коли я запускаю це.

Тож я справді не уявляю, що тут робити. Яку стратегію слід взяти? Чи можна скинути голову до цього останнього коміту 7 серпня

Редагувати:

Виконання журналу git і перехід до нижньої частини екрану показує це:

commit 996e03b949aea176238e3c7a8452700bbb987ac9
Author: christopher <christopher@christopher>
Date:   Wed Jul 3 23:00:44 2013 -0400

    many many changes
error: Could not read 984c11abfc9c2839b386f29c574d9e03383fa589
fatal: Failed to traverse parents of commit 235ae1f48701d577d71ebd430344a159e5ba4881

Здається, це заважає Git prune працювати


3
Це не дуже допомагає, але: не зберігайте репозиторії Git у Dropbox або будь-яких інших службах синхронізації. Git не побудований для обробки іншої програми, яка випадково блокує та переписує файли, коли вона робить щось інше.
milimoose


2
Майже всі відповіді припускають, що можна просто перекланувати з якогось нетлінного віддаленого походження. Ось проблема ... Що робити , якщо ви перебуваєте походження, і ви пошкоджені? Правильно. Отже, ось: git-repairце програма, яка буде запускатись git fsckі намагатись досить важко, щоб вирішити будь-які проблеми, з якими вона стикається. git-repair.branchable.com Це здається цілком спроможним, і, хоча вам, можливо, доведеться копіювати (якщо зможете!) об'єкти із резервної копії (у вас є резервна копія, так?), це має заощадити вам багато часу рятуючи все, що можна, і залишаючи вам справжню роботу, а не багато автоматизованих завдань. Немає приналежності тощо
underscore_d

Відповіді:


111

Як альтернативу останньому варіанту CodeGnome, якщо пошкоджено лише локальне репо, і ви знаєте URL-адресу на пульт дистанційного керування, ви можете скористатися цим, щоб повторно встановити .gitвідповідність віддаленого (замінивши ${url}на віддалений url):

mv -v .git .git_old &&            # remove old git
git init &&                       # initialise new repo
git remote add origin "${url}" && # link to old repo
git fetch &&                      # get old history
git reset origin/master --mixed   # force update to old history

Це залишає ваше робоче дерево недоторканим і впливає лише на ведення бухгалтерії git.
Також нещодавно я створив скрипт bash саме для цієї мети (Додаток А), який трохи захищає цю операцію.

Примітка:

Якщо у вашому репо є підмодулі, цей процес якось їх зіпсує, і єдиним рішенням, яке я знайшов на сьогоднішній день, є їх видалення, а потім використання git submodule update --init(або повторне клонування репо, але це здається занадто різким).

Додаток А - Повний сценарій

#!/bin/bash

# Author: Zoey Llewellyn "Zobean" Hewll
#
# Usage: fix-git [REMOTE-URL]
#   Must be run from the root directory of the repository.
#   If a remote is not supplied, it will be read from .git/config
# 
# For when you have a corrupted local repo, but a trusted remote.
# This script replaces all your history with that of the remote.
# If there is a .git, it is backed up as .git_old, removing the last backup.
# This does not affect your working tree.
#
# This does not currently work with submodules!
# This will abort if a suspected submodule is found.
# You will have to delete them first
# and re-clone them after (with `git submodule update --init`)
#
# Error codes:
# 1: If a url is not supplied, and one cannot be read from .git/config
# 4: If the url cannot be reached
# 5: If a git submodule is detected


if [[ "$(find -name .git -not -path ./.git | wc -l)" -gt 0 ]] ;
then
    echo "It looks like this repo uses submodules" >&2
    echo "You will need to remove them before this script can safely execute" >&2
    echo "Then use \`git submodule update --init\` to re-clone them" >&2
    exit 5
fi

if [[ $# -ge 1 ]] ;
then
    url="$1"
else
    if ! url="$(git config --local --get remote.origin.url)" ;
    then
        echo "Unable to find remote 'origin': missing in '.git/config'" >&2
        exit 1
    fi
fi
url_base="$(echo "${url}" | sed -E 's;^([^/]*://)?([^/]*)(/.*)?$;\2;')"
echo "Attempting to access ${url_base} before continuing"
if ! wget -p "${url_base}" -O /dev/null -q --dns-timeout=5 --connect-timeout=5 ;
then
    echo "Unable to reach ${url_base}: Aborting before any damage is done" >&2
    exit 4
fi

echo
echo "This operation will replace the local repo with the remote at:"
echo "${url}"
echo
echo "This will completely rewrite history,"
echo "but will leave your working tree intact"
echo -n "Are you sure? (y/N): "

read confirm
if ! [ -t 0 ] ; # i'm open in a pipe
then
    # print the piped input
    echo "${confirm}"
fi
if echo "${confirm}"|grep -Eq "[Yy]+[EeSs]*" ; # it looks like a yes
then
    if [[ -e .git ]] ;
    then
        # remove old backup
        rm -vrf .git_old | tail -n 1 &&
        # backup .git iff it exists
        mv -v .git .git_old
    fi &&
    git init &&
    git remote add origin "${url}" &&
    git config --local --get remote.origin.url | sed 's/^/Added remote origin at /' &&
    git fetch &&
    git reset origin/master --mixed
else
    echo "Aborting without doing anything"
fi

3
Вражаюче, я зробив резервну копію свого проекту і спробував ваше рішення. Git був якось досить пошкоджений. Я спробував ваше рішення, і воно спрацювало чудово дякую.
kequc

2
не використовував сценарій, як я в Windows, але ці команди просто зберегли мою папку .git, яка показувала нове репозиторій для кожного збереження будь-якого відстежуваного файлу (тому у мене з’явилося приблизно 50 головних сховищ, перш ніж спробувати це виправлення )
мопед

1
Після цього я зміг відновити .gitпапку. Я виявив, що це git reset origin/master --hardбуло корисніше, ніж --mixed.
Феліпе Альварес

1
Чудово. Якщо є субмудули, які не містять змін, спочатку видаліть їх, а потім виконайте ініціювання підмодуля, щоб отримати їх знову.
гермафродит

1
@ w33haa На жаль, це рішення застосовується лише у випадку, коли у вас є дійсне та доступне віддалене сховище. Деякі інші відповіді стосуються випадку недоступного або пошкодженого пульта дистанційного керування.
Zoey Hewll

53

TL; DR

Git насправді не зберігає історію так, як ти думаєш. Він обчислює історію під час виконання на основі ланцюжка предків. Якщо у вашому родоводі відсутні краплі, дерева чи коміти, можливо, ви не зможете повністю відновити свою історію.

Відновлення відсутніх об’єктів із резервних копій

Перше, що ви можете спробувати, це відновити відсутні елементи з резервної копії. Наприклад, перевірте, чи є у вас резервна копія коміту як .git/objects/98/4c11abfc9c2839b386f29c574d9e03383fa589. Якщо так, ви можете відновити його.

Можливо, ви також захочете розглянути git-verify-pack та git-unpack-object у тому випадку, якщо коміт вже запакований, і ви хочете повернути його до вільного об'єкта для цілей операції зі сховищем.

Хірургічна резекція

Якщо вам не вдається замінити відсутні елементи з резервної копії, можливо, ви зможете скоротити відсутні історії. Наприклад, ви можете перевірити свою історію або перекласти журнал, щоб знайти предка коміту 984c11abfc9c2839b386f29c574d9e03383fa589. Якщо ви знайдете його цілим, то:

  1. Скопіюйте свій робочий каталог Git у тимчасовий каталог десь.
  2. Виконайте апаратне скидання до непошкодженого коміту.
  3. Скопіюйте поточні файли назад у робоче дерево Git, але переконайтесь, що не скопіювали папку .git назад!
  4. Зафіксуйте поточне робоче дерево та зробіть все можливе, щоб розглядати його як зіпсований коміт усієї відсутньої історії.

Якщо це спрацює, ви, звичайно, втратите проміжну історію. На даний момент, якщо у вас є журнал робочої історії, то непогано обрізати вашу історію та переглядати всі недосяжні коміти та об’єкти.

Повне відновлення та повторна ініціалізація

Якщо ваш репозиторій все ще не працює, то, сподіваємось, у вас є непошкоджена резервна копія або клон, з якого ви можете відновити. Якщо ні, але ваш поточний робочий каталог містить дійсні файли, ви завжди можете повторно ініціалізувати Git. Наприклад:

rm -rf .git
git init
git add .
git commit -m 'Re-initialize repository without old history.'

Це кардинально, але це може бути вашим єдиним варіантом, якщо історія вашого сховища справді не підлягає відновленню. YMMV.


3
Я просто зіткнувся з цією проблемою і хотів вказати на це, оскільки це не у вашій відповіді, але моя проблема полягала лише у простому дозволі. error: Could not read abcdeМоїм репо керує GitLab, і він створював файли, які мій користувач не міг прочитати. sudo chownПізніше , і я був добре йти.
Австрія,

6

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

git fetch && git reset --hard

2
У деяких випадках git не дозволяє вам отримувати файли, якщо певні об'єкти пошкоджені, тому вам потрібно спочатку повторно ініціалізувати репо.
Zoey Hewll

Це не працювало для мене, коли я мав fatal: pack has 13 unresolved deltas.
Артем Руссаковський,

5

Ось сценарій (bash) для автоматизації першого рішення @CodeGnome для відновлення з резервної копії (запуску з верхнього рівня пошкодженого репо). Резервне копіювання не повинно бути повним, потрібно лише мати відсутні об'єкти.

git fsck 2>&1 | grep -e missing -e invalid | awk '{print $NF}' | sort -u |
    while read entry; do
        mkdir -p .git/objects/${entry:0:2}
        cp ${BACKUP}/objects/${entry:0:2}/${entry:2} .git/objects/${entry:0:2}/${entry:2}
    done

4

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

Ще однією альтернативою, яка працювала для мене, було скинути git head та індекс до попереднього стану, використовуючи:

git reset --keep

Ви також можете зробити те ж саме вручну, відкривши графічний інтерфейс Git і вибравши кожен "Поетапні зміни" та натиснувши "Зняти зміну". Коли все буде знято, ви тепер зможете стискати базу даних, перевіряти базу даних і фіксувати.

Я також спробував наступні команди, але вони не працювали для мене, але вони могли б і для вас, залежно від конкретної проблеми, яка у вас є:

git reset --mixed
git fsck --full
git gc --auto
git prune --expire now
git reflog --all

Нарешті, щоб уникнути цієї проблеми синхронізації, що пошкоджує ваш git-індекс (що може статися з DropBox, SpiderOak або будь-яким іншим хмарним диском), ви можете зробити наступне:

  1. Перетворіть свою .gitпапку в один "пакетний" git-файл , використовуючи:, git bundle create my_repo.git --allтоді він повинен працювати так само, як і раніше, але оскільки все знаходиться в одному файлі, ви більше не будете ризикувати синхронізацією, завдаючи шкоди вашому git-репо.
  2. Вимкніть миттєву синхронізацію : SpiderOak дозволяє встановити планування для перевірки змін на "автоматичне" (це означає, що це відбувається якомога швидше, відстежуючи зміни файлів завдяки сповіщенням ОС). Це погано, оскільки воно почне завантажувати зміни, як тільки ви внесете зміни, а потім завантажить зміну, тому це може стерти останні зміни, які ви щойно робили. Рішенням для вирішення цієї проблеми є встановлення затримки моніторингу змін до 5 хвилин або більше. Це також усуває проблеми з миттєвим збереженням програм для створення нотаток (наприклад, Notepad ++).

3

Якщо ви відчайдушні, можете спробувати це:

git clone ssh://me@my.git.server/path/to/project destination --depth=1

Він отримає ваші дані, але ви втратите історію. Я пішов із спробами та помилками на моє репо і --depth=10працював, але --depth=50дав мені невдачу.


3

Я спробував перенести об'єктні файли на 0 байт і отримати їх знову з пульта, і це спрацювало:

find . -type f -size 0 -exec mv {} /tmp \;
git fetch

Це дістало відсутні елементи з пульта дистанційного керування і дозволило мені продовжувати працювати без повторної ініціалізації всього репо.


2

Я стикався з тією ж проблемою, тому замінив папку ".git" на резервну версію, і вона все ще не працювала, оскільки файл .gitconfig був пошкоджений. BSOD на моєму ноутбуці пошкодив його. Я замінив його наступним кодом, і sourcetree відновив усі мої сховища.

[user]
name = *your username*
email = *your email address*
[core]
autocrlf = true
excludesfile = C:\\Users\\*user name*\\Documents\\gitignore_global.txt

Не знаю, чи допоможе це комусь, але це просто ще одне рішення, яке спрацювало для мене.



2

Нещодавно я відчував подібні проблеми, використовуючи git версії 2.7.1 під Ubuntu 18.04.3. Ось як я це зробив:

sudo apt install git-repair
git-repair  # fix a broken git repository
or
git-repair --force  # force repair, even if data is lost
git fsck  # to verify it was fixed

Більшу частину часу процес відновлення був успішним


git-repair - справді дуже корисний інструмент. Це допомогло мені відновити сховище. Проблема більшості інших методів полягає в тому, що ви втрачаєте схованки, що для мене не було можливості.
Ян Рихтер,

1

У моєму випадку я створював сховище з вихідного коду вже на своєму ПК, і ця помилка з’явилася. Я видалив папку .git і зробив все знову, і це спрацювало :)


1

Я хотів би додати це як коментар під дивним ZOEY Hewil в відповідь вище, але я в даний час не вистачає респ , щоб зробити це, так що я повинен додати його тут і віддати за свою роботу: P

Якщо ви використовуєте Poshgit і відчуваєте себе надзвичайно лінивим, ви можете скористатися наведеним нижче, щоб автоматично витягти свою URL-адресу з конфігурації git і зробити просту роботу ще простішою. Застосовуються стандартні застереження щодо тестування цього на копії / резервному копіюванні вашого локального репо, на випадок, якщо він підірве вам обличчя.

$config = get-content .git\config
$url = $config -match " url = (?<content>.*)"
$url = $url.trim().Substring(6)
$url

move-item -v .git .git_old;
git init;
git remote add origin "$url";
git fetch;
git reset origin/master --mixed

0

Швидкий спосіб, якщо у вас є зміни у вашому поточному проекті, і ви не хочете його втратити, перемістіть свій поточний проект кудись, клонуйте проект з github у цю папку та внесіть деякі зміни, спробуйте здійснити знову. Або просто видаліть репо та клонуйте його знову, це спрацювало у мене.


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