破損したgitリポジトリを修正するにはどうすればよいですか?


104

Ubuntuの1つのフォルダーに保持しているリポジトリを新しいマシンに複製してみましたが、次のようになりました。

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

それは本当に悪いようです。私がするとき、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しません。裸のレポでHEADは言うref: refs/heads/masterものの

packed-refs とは言っても

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

さらに他の質問で実行が提案されてgit reflogおり、実行しても出力が表示されません。

だから私は本当にここで何をすべきか分かりません。どのような戦略をとるべきですか?8月7日にこの最後のコミットに頭をリセットすることは可能ですか

編集:

git logを実行して画面出力の下部に移動すると、次のようになります。

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は、別のプログラムが他のことをしているときにランダムにファイルをロックしたり書き換えたりする別のプログラムを処理するように構築されていません。
ミリムース2013


2
ほとんどすべての回答は、破損していないリモートの起点から単純に再クローンできると想定しています。ここに問題があります...あなた起源であり、あなたが堕落している場合はどうなりますか?正しい。だから、ここに:git-repair実行してgit fsck、遭遇した問題を修正するために一生懸命試みるプログラムです。git-repair.branchable.com非常に機能しているようで、バックアップからオブジェクトを(できれば!)コピーする必要があるかもしれません(バックアップがありますよね?)自動化できる多くのタスクではなく、できる限りのことを実行して、実際の作業を残します。
underscore_d 2016

回答:


110

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スクリプトも作成しまし (付録A)。これは、この操作を少し安全に囲みます。

注意:

リポジトリにサブモジュールがある場合、このプロセスは何らかの形でそれらを台無しにし、私がこれまでに見つけた唯一の解決策はそれらを削除してから使用することですgit submodule update --init(またはリポジトリを再クローニングしますが、それはあまりにも徹底的です)。

付録A-完全なスクリプト

#!/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 2017

2
私はWindowsのようにスクリプトを使用しませんでしたが、これらのコマンドは.gitフォルダーを保存しただけで、追跡されたファイルで行われたすべての保存に対して新しいリポジトリを表示していました)
原付

1
これを実行した.git後、フォルダを復元することができました。git reset origin/master --hardよりも便利だと思いました--mixed
フェリペアルバレス

1
すごい。変更を含まないサブモジュールがある場合は、まずそれらを削除してから、サブモジュールinitを実行して再度取得します。
herm

1
@ w33haa残念ながら、このソリューションは、有効でアクセス可能なリモートリポジトリがある場合にのみ適用できます。他の回答のいくつかは、アクセス不能または破損したリモートの場合に対処します。
Zoey Hewll

53

TL; DR

Gitは、あなたが思っているように実際に履歴を保存するわけではありません。これは、計算祖先チェーンに基づいて、実行時に歴史を。祖先にブロブ、ツリー、またはコミットがない場合、履歴を完全に回復できない可能性があります。

欠落しているオブジェクトをバックアップから復元する

あなたが試すことができる最初のことは、欠落しているアイテムをバックアップから復元することです。たとえば、コミットのバックアップがとして保存されているかどうかを確認します.git/objects/98/4c11abfc9c2839b386f29c574d9e03383fa589。もしそうなら、それを復元することができます。

また、コミットがすでにパックされており、リポジトリの手術のために緩いオブジェクトに戻したい場合は、git-verify-packおよびgit-unpack-objectsを調べることもできます。

外科的切除

欠落しているアイテムをバックアップから置き換えることができない場合は、欠落している履歴を削除できる可能性があります。たとえば、履歴またはreflogを調べて、コミットの祖先984c11abfc9c2839b386f29c574d9e03383fa589を見つけることができます。無傷のものが見つかった場合:

  1. Git作業ディレクトリを一時ディレクトリのどこかにコピーします。
  2. 破損していないコミットにハードリセットを実行します。
  3. 現在のファイルをGit作業ツリーにコピーしますが、.gitフォルダーはコピーしないでください。
  4. 現在の作業ツリーをコミットし、不足しているすべての履歴の押しつぶされたコミットとして扱うように最善を尽くします。

それがうまくいけば、もちろんあなたはその間の歴史を失うでしょう。この時点で、作業履歴ログがある場合は、すべての到達不能なコミットとオブジェクトの履歴とreflogを削除することをお勧めします。

完全な復元と再初期化

リポジトリがまだ壊れている場合は、復元できる破損していないバックアップまたはクローンがあることを願っています。そうでない場合でも、現在の作業ディレクトリに有効なファイルが含まれていれば、いつでも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 2017年

私が持っていたとき、これは私にはうまくいきませんでしたfatal: pack has 13 unresolved deltas
Artem Russakovskii

5

@CodeGnomeによる最初のソリューションを自動化して、バックアップから復元する(破損したリポジトリの最上位から実行する)スクリプト(bash)を次に示します。バックアップは完全である必要はありません。欠落しているオブジェクトがあれば十分です。

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ヘッドとインデックスを以前の状態にリセットすることでした:

git reset --keep

Git GUIを開き、各「段階的変更」を選択して「変更のステージング解除」をクリックすることにより、手動で同じことを行うこともできます。すべてのステージが解除されると、データベースを圧縮し、データベースを確認してコミットできるようになります。

次のコマンドも試してみましたが、うまくいきませんでしたが、問題の内容によっては、次のコマンドが役立つ場合があります。

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を使用すると、変更をチェックするためのスケジュールを「自動」に設定できます(つまり、OS通知のおかげで、ファイルの変更を監視しています)。変更を行うとすぐに変更のアップロードを開始し、変更をダウンロードするため、これは悪いことです。これにより、実行していた最新の変更が消去される可能性があります。この問題を解決する解決策は、変更監視の遅延を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

これが誰かに役立つかどうかはわかりませんが、これは私にとって有効な解決策の1つにすぎません。



2

最近、Ubuntu 18.04.3でgitバージョン2.7.1を使用して同様の問題を経験しました。これが私がやった方法です:

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は確かに非常に便利なツールです。それは私がリポジトリを回復するのに役立ちました。他のほとんどの方法の問題は、あなたが隠し場所を失うことです。これは私には選択肢ではありませんでした。
Jan Rychter

1

私の場合、すでにPCにあるソースコードからリポジトリを作成していたところ、そのエラーが表示されました。私は.gitフォルダーを削除し、すべてを再度実行しましたが、うまくいきました:)


1

これをZoey Hewilの素晴らしい答えの下にコメントとして追加したかった上記たのですが、現在のところ、それを行うのに十分な担当者がいないため、ここに追加して、彼女の仕事の功績を認める必要があります:P

Poshgitを使用していて、 ている場合は、次を使用してgit構成からURLを自動的に抽出し、簡単な作業をさらに簡単にすることができます。これがあなたの顔で爆発した場合に備えて、最初にローカルリポジトリのコピー/バックアップでこれをテストすることについて、標準的な警告が適用されます。

$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からこのフォルダーにプロジェクトのクローンを作成して、変更を加えてもう一度コミットしてみてください。または、リポジトリを削除して再度クローンを作成するだけで、私からはうまくいきました。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.