Bozuk git deposu nasıl düzeltilir?


106

Ubuntu bir klasörümde tuttuğum depomu yeni bir makineye klonlamayı denedim ve bunu aldım:

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$ 

Bu yüzden burada sorulan buna benzer birçok soruya bakmayı denedim ve çoğu kaçmam gerektiğini söylüyor git fsck --fullve bunu denediğimde bunu anlıyorum.

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

Bu gerçekten kötü görünüyor. Bunu yaptığımda git log | headanlıyorum

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

Buradaki diğer sorulara bakmayı söylediler ./git/refs/heads/master. Bu çıplak bir depo ve refs/heads/var ama refs/heads/masteryok. Çıplak repo BAŞ diyor ref: refs/heads/mastergerçi

packed-refs bunu yine de söylüyor

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

Yine de başka sorular çalıştırmayı önerdi git reflogve bunu çalıştırdığımda hiçbir çıktı görünmüyor.

Yani burada ne yapacağım konusunda hiçbir fikrim yok. Hangi strateji izlenmeli? Başlığı 7 Ağustos'taki bu son işlemeye sıfırlamak mümkün mü

DÜZENLE:

Git günlüğü yapmak ve ekran çıktısının altına gitmek şunu gösterir:

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

Bu, git budamanın çalışmasını engelliyor gibi görünüyor


3
Bu pek yardımcı olmamakla birlikte: Git depolarını Dropbox veya diğer senkronizasyon hizmetlerinde saklamayın. Git, başka bir şey yaparken dosyaları rastgele kilitleyen ve yeniden yazan başka bir programı işlemek için tasarlanmamıştır.
millimoose


2
Neredeyse tüm yanıtlar, birinin bozulmayan uzak bir kaynaktan basitçe yeniden klonlanabileceğini varsayar. Burada ne olursa ... problem vardır kökeni ve bozuk değil mi? Sağ. Yani, burada: karşılaştığı sorunları çözmek için git-repairçalışacak git fsckve oldukça sıkı çalışacak bir programdır . git-repair.branchable.com Oldukça yetenekli görünüyor ve sonunda nesneleri bir yedekten kopyalamak zorunda kalsanız da (yapabiliyorsanız!) (bir yedeğiniz var, değil mi?), bu size çok zaman kazandıracaktır. Elinizden geleni kurtarır ve size gerçek işi bırakır, çok sayıda otomatikleştirilebilir görev değil. Vb Hayır bağlı işletme
underscore_d

Yanıtlar:


119

CodeGnome'un son seçeneğine bir alternatif olarak, yalnızca yerel depo bozuksa ve uzaktaki url'yi biliyorsanız, bunu .gituzaktan kumandayla eşleşecek şekilde yeniden ayarlamak için kullanabilirsiniz ( ${url}uzak url ile değiştirerek ):

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

Bu, çalışma ağacınızı olduğu gibi bırakır ve yalnızca git'in defter tutma işlemini etkiler.
Ayrıca yakın zamanda bu amaç için (Ek A) bir bash betiği hazırladım , bu da bu operasyonun etrafını biraz daha güvenli hale getiriyor.

Not:

Deponuzun alt modülleri varsa, bu süreç onları bir şekilde karıştırır ve şu ana kadar bulduğum tek çözüm onları silmek ve sonra kullanmak git submodule update --init(veya repoyu yeniden klonlamak, ancak bu çok sert görünüyor ).

Ek A - Tam metin

#!/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
Muhteşem, projemin yedeğini aldım ve çözümünüzü denedim. Git, bir şekilde oldukça kötü bir şekilde bozulmuştu. Çözümünüzü denedim ve mükemmel çalıştı, çok teşekkür ederim.
kequc

2
komut dosyasını Windows'ta olduğum gibi kullanmadım, ancak bu komutlar izlenen herhangi bir dosyada yapılan her kayıt için yeni depo gösteren .git klasörümü kaydetti (bu yüzden bu düzeltmeyi denemeden önce 50 ana depo gibi son buldum )
moped

1
Bunu .gityaptıktan sonra klasörümü geri yükleyebildim . git reset origin/master --hardDaha yararlı buldum --mixed.
Felipe Alvarez

1
Harika. Değişiklikler içermeyen alt modüllerin olması durumunda, önce bunları kaldırın ve sonra tekrar almak için alt modül initini yapın.
herm

1
@ w33haa Ne yazık ki, bu çözüm yalnızca geçerli ve erişilebilir bir uzak deponuzun olduğu durumlar için geçerlidir. Diğer cevaplardan bazıları, erişilemeyen veya bozuk bir uzaktan kumanda durumunu ele almaktadır.
Zoey Hewll

54

TL; DR

Git, geçmişi düşündüğünüz şekilde gerçekten saklamıyor. Bu hesaplar bir atası zincirine dayalı çalışma anda tarih. Atalarınızda lekeler, ağaçlar veya taahhütler eksikse geçmişinizi tam olarak kurtaramayabilirsiniz.

Eksik Nesneleri Yedeklemelerden Geri Yükleme

Deneyebileceğiniz ilk şey, eksik öğeleri yedekten geri yüklemektir. Örneğin, kaydetme işleminin bir yedeğine sahip olup olmadığınıza bakın .git/objects/98/4c11abfc9c2839b386f29c574d9e03383fa589. Eğer öyleyse onu geri yükleyebilirsiniz.

Ayrıca , commit zaten paketlenmişse ve onu depo ameliyatı amacıyla gevşek bir nesneye geri döndürmek istiyorsanız git-doğrulama-paketi ve git-unpack-nesnelerine de bakmak isteyebilirsiniz.

Cerrahi rezeksiyon

Eksik öğeleri bir yedeklemeden değiştiremezseniz, eksik geçmişi çıkarmanız mümkün olabilir. Örneğin, 984c11abfc9c2839b386f29c574d9e03383fa589 işleminin bir atasını bulmak için geçmişinizi inceleyebilir veya yeniden yazabilirsiniz. Birini sağlam bulursanız, o zaman:

  1. Git çalışma dizininizi bir yerde geçici bir dizine kopyalayın.
  2. Bozulmamış işleme için donanımdan sıfırlama yapın.
  3. Mevcut dosyalarınızı Git çalışma ağacına geri kopyalayın, ancak .git klasörünü geri kopyalamadığınızdan emin olun!
  4. Mevcut çalışma ağacını işleyin ve onu tüm eksik geçmişin sıkıştırılmış bir işlemi olarak ele almak için elinizden gelenin en iyisini yapın.

Eğer işe yararsa, elbette araya giren geçmişi kaybedeceksiniz. Bu noktada, bir çalışma geçmişi günlüğünüz varsa, ulaşılamayan tüm işlemlerin ve nesnelerin geçmişini ve yeniden günlüklerini eritmek iyi bir fikirdir.

Tam Geri Yükleme ve Yeniden Başlatma

Deponuz hala bozuksa, umarım geri yükleyebileceğiniz bozulmamış bir yedeklemeniz veya klonunuz vardır. Değilse, ancak mevcut çalışma dizininiz geçerli dosyalar içeriyorsa, Git'i her zaman yeniden başlatabilirsiniz. Örneğin:

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

Bu çok zor, ancak depo geçmişiniz gerçekten kurtarılamazsa tek seçeneğiniz olabilir. YMMV.


3
Bu konuyla az önce karşılaştım ve cevabınızda olmadığı için bunu belirtmek istedim, ancak benim sorunum sadece basit bir izin sorunuydu. error: Could not read abcdeDepom GitLab tarafından yönetiliyor ve kullanıcımın okuyamadığı dosyalar yaratıyordu. Daha sudo chownsonra ve gitmek için iyiydim.
Aust

Full Restores and Re-Initializationcanımı kurtardım :) git pull origin master --allow-unrelated-historiesKodumun son versiyonunu uzak depodan almak için bir de çalıştırdım
Sami

6

Yapılandırılmış bir uzaktan kumandanız varsa ve bazı çalıştırılmamış kodu kaybetmeyi umursamıyorsanız, şunları yapabilirsiniz:

git fetch && git reset --hard

2
Bazı durumlarda git, belirli nesneler bozuksa getirmenize izin vermez, bu nedenle önce deponuzu yeniden başlatmanız gerekir.
Zoey Hewll

Bu benim için işe yaramadı fatal: pack has 13 unresolved deltas.
Artem Russakovskii

5

İşte bir yedekten geri yüklemek için ilk çözümü @CodeGnome tarafından otomatikleştirmek için bir komut dosyası (bash) (bozuk deponun en üst düzeyinden çalıştırın). Yedeklemenin tamamlanması gerekmez, yalnızca eksik nesnelere sahip olması gerekir.

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

Bu sayfada açıklanan düzeltmelerden herhangi birini denemeden önce, deponuzun bir kopyasını oluşturmanızı ve yalnızca bu kopya üzerinde çalışmanızı öneririm. Ardından, düzeltebilirseniz, onarım sürecinde herhangi bir dosyayı kaybetmediğinizden emin olmak için orijinaliyle karşılaştırın.

Benim için çalışan başka bir alternatif, git başlığını ve dizini kullanarak önceki durumuna sıfırlamaktı:

git reset --keep

Aynı işlemi Git GUI'yi açıp her "Aşamalı değişiklikleri" seçerek ve "Değişikliği Aşamadan Çıkar" ı tıklayarak manuel olarak da yapabilirsiniz. Her şey aşamalı olmadığında, artık veritabanınızı sıkıştırabilmeli, veritabanınızı kontrol edebilmeli ve gerçekleştirebilmelisiniz.

Aşağıdaki komutları da denedim, ancak benim için işe yaramadılar, ancak tam olarak sahip olduğunuz soruna bağlı olarak sizin için olabilirler:

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

Son olarak, git dizininize (DropBox, SpiderOak veya başka herhangi bir bulut diskinde olabilir) zarar veren bu senkronizasyon problemini önlemek için aşağıdakileri yapabilirsiniz:

  1. .gitgit bundle create my_repo.git --allŞunu kullanarak klasörünüzü tek bir "paket" git dosyasına dönüştürün , daha sonra eskisi gibi çalışmalıdır, ancak her şey tek bir dosyada olduğu için senkronizasyonun git deponuza zarar verme riskini ortadan kaldırmazsınız.
  2. Anlık senkronizasyonu devre dışı bırakın : SpiderOak, değişiklikleri kontrol etmek için zamanlamayı "otomatik" olarak ayarlamanıza olanak tanır (bu, işletim sistemi bildirimleri sayesinde dosya değişikliklerini izlemek için mümkün olan en kısa sürede olacağı anlamına gelir). Bu kötüdür, çünkü siz bir değişiklik yaptığınız anda değişiklikleri yüklemeye başlayacak ve sonra değişikliği indirecek, böylece yaptığınız en son değişiklikleri silebilir. Bu sorunu düzeltmenin bir çözümü, değişiklik izleme gecikmesini 5 dakika veya daha uzun bir süreye ayarlamaktır. Bu aynı zamanda anında kaydetme not alma uygulamalarıyla (Notepad ++ gibi) ilgili sorunları da düzeltir.

3

Eğer çaresizseniz şunu deneyebilirsiniz:

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

Verilerinizi alacak, ancak geçmişi kaybedeceksiniz. Depomda deneme yanılma ile gittim ve --depth=10çalıştım ama --depth=50başarısız oldum.


3

Nesne dosyalarını 0 bayt ile uzaklaştırmayı ve uzaktan kumandadan tekrar almayı denedim ve işe yaradı:

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

Eksik nesneleri uzaktan kumandadan aldı ve tüm depoyu yeniden başlatmadan çalışmaya devam etmeme izin verdi.


2

Aynı sorunla karşı karşıyaydım, bu yüzden ".git" klasörünü yedeklenmiş bir sürümle değiştirdim ve .gitconfig dosyası bozuk olduğu için hala çalışmıyordu. Dizüstü bilgisayarımdaki BSOD onu bozdu. Bunu aşağıdaki kodla değiştirdim ve kaynak ağacı tüm depolarımı geri yükledim.

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

Bunun kimseye yardımcı olup olmayacağını bilmiyorum ama bu benim için çalışan başka bir çözüm.


2

Dizini kaldırın ve sıfırlayın

rm -f .git/index
git reset

2

Son zamanlarda Ubuntu 18.04.3 altında 2.7.1 git sürümünü kullanırken benzer sorunlar yaşadım. İşte böyle yaptım:

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

Kurtarma işlemi çoğu zaman başarılı oldu


git-repair gerçekten çok kullanışlı bir araçtır. Bir depoyu kurtarmama yardımcı oldu. Diğer yöntemlerin çoğundaki sorun, zulalarınızı kaybetmenizdir ki bu benim için bir seçenek değildi.
Jan Rychter

1

Benim durumumda, depoyu zaten bilgisayarımda bulunan kaynak koddan oluşturuyordum ve bu hata ortaya çıktı. .Git klasörünü sildim ve her şeyi tekrar yaptım ve işe yaradı :)


1

Bunu, Zoey Hewil'in yukarıdaki harika cevabının altına bir yorum olarak eklemek istedim , ancak şu anda bunu yapmak için yeterli temsilcim yok, bu yüzden buraya eklemem ve çalışmalarına atıfta bulunmam gerekiyor: P

Poshgit kullanıyorsanız ve son derece tembel hissediyorsanız , URL'nizi git yapılandırmanızdan otomatik olarak çıkarmak ve kolay bir işi daha da kolaylaştırmak için aşağıdakileri kullanabilirsiniz. Yüzünüzde patlaması ihtimaline karşı önce yerel deponuzu bir kopya / yedeklemede test etmek için standart uyarılar geçerlidir.

$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

Hızlı bir şekilde, mevcut projenizde değişiklik yaptıysanız ve onu kaybetmek istemiyorsanız, mevcut projenizi bir yere taşıyın, projeyi github'dan bu klasöre kopyalayın ve biraz değişiklik yaparak tekrar taahhüt etmeyi deneyin. Ya da sadece depoyu silin ve tekrar klonlayın, benden çalıştı.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.