손상된 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

정말 안좋아 보입니다. 내가 할 때 나는 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 로그를 수행하고 화면 출력 하단으로 이동하면 다음과 같이 표시됩니다.

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
이것은별로 도움이되지 않지만 Dropbox 또는 다른 동기화 서비스에 Git 저장소를 저장하지 마십시오. Git은 다른 프로그램을 수행하는 동안 파일을 임의로 잠그고 다시 쓰는 다른 프로그램을 처리하도록 구축되지 않았습니다.
millimoose 2013 년


2
거의 모든 답변은 손상되지 않는 원격 출처에서 간단히 다시 복제 할 수 있다고 가정합니다. 여기에 문제가 있습니다 ... 당신 기원이고 당신이 타락했다면? 권리. 그래서, 여기에 : 발생하는 문제를 해결하기 위해 git-repair실행 git fsck되고 매우 열심히 노력할 프로그램이 있습니다. git-repair.branchable.com 꽤 유능 해 보이며 백업에서 개체를 복사 (가능하다면!)해야 할 수도 있지만 (백업이 있습니다. 그렇죠?) 이렇게하면 많은 시간을 절약 할 수 있습니다. 가능한 모든 것을 구하고 자동화 가능한 많은 작업이 아닌 실제 작업을 남겨 둡니다. 소속 없음 등
underscore_d

답변:


111

CodeGnome의 마지막 옵션에 대한 대안으로, 로컬 리포지토리 만 손상되고 원격 URL을 알고있는 경우이를 사용 하여 원격 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)를 만들었습니다.

노트 :

당신의 repo는, 어떻게 든이 프로세스 의지 엉망 그들을, 그리고 유일한 해결책 서브 모듈이있는 경우 I을 삭제 한 후 사용 지금까지 발견했습니다 git submodule update --init(또는 REPO를 재 복제,하지만 보인다 너무 과감 ).

부록 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

2
Windows 에서처럼 스크립트를 사용하지 않았지만 해당 명령은 추적 된 파일에 대한 모든 저장에 대해 새 저장소를 표시하는 .git 폴더를 저장했습니다 (그래서이 수정을 시도하기 전에 50 개의 마스터 저장소로 끝났습니다. )
오토바이

1
.git이 작업을 수행 한 후 내 폴더 를 복원 할 수있었습니다 . 나는 git reset origin/master --hard보다 유용하다는 것을 알았다 --mixed.
Felipe Alvarez

1
큰. 변경 사항을 포함하지 않는 서브 머듈이있는 경우 먼저 제거하고 서브 모듈 초기화를 수행하여 다시 가져 오십시오.
herm

1
@ w33haa 불행히도이 솔루션은 유효하고 액세스 가능한 원격 저장소가있는 경우에만 적용 할 수 있습니다. 다른 답변 중 일부는 액세스 할 수 없거나 손상된 리모컨의 경우를 다룹니다.
Zoey Hewll

54

TL; DR

Git은 당신이 생각하는 방식으로 역사를 저장하지 않습니다. 그것은 계산 조상 체인을 기반으로 실행 시간에 역사를. 조상에 얼룩, 트리 또는 커밋이 누락 된 경우 기록을 완전히 복구하지 못할 수 있습니다.

백업에서 누락 된 개체 복원

가장 먼저 시도 할 수있는 것은 백업에서 누락 된 항목을 복원하는 것입니다. 예를 들어, 다음과 같이 저장된 커밋의 백업이 있는지 확인하십시오..git/objects/98/4c11abfc9c2839b386f29c574d9e03383fa589 . 그렇다면 복원 할 수 있습니다.

git-verify-packgit-unpack-objects 를 살펴볼 수도 있습니다.커밋이 이미 압축되어 있고 저장소 수술을 위해 느슨한 객체로 되돌리려는 경우 .

외과 적 절제

백업에서 누락 된 항목을 교체 할 수없는 경우 누락 된 내역을 제거 할 수 있습니다. 예를 들어, 커밋 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나중에 내가 갈 수 있었다.
Aust

Full Restores and Re-Initialization내 생명을 구했습니다 :) git pull origin master --allow-unrelated-histories원격 저장소에서 내 코드의 마지막 버전을 가져 오기 위해 실행했습니다
Sami

6

원격 구성이 있고 푸시되지 않은 코드를 잃어 버릴 염려가없는 경우 다음을 수행 할 수 있습니다.

git fetch && git reset --hard

2
경우에 따라 git은 특정 개체가 손상된 경우 가져 오기를 허용하지 않으므로 먼저 repo를 다시 초기화해야합니다.
Zoey Hewll

내가했을 때 이것은 나를 위해 작동하지 않았습니다 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 bundle create my_repo.git --all다음은 이전과 똑같이 작동해야하지만, 모든 것이 하나의 파일에 있기 때문에, 당신은 더 이상 당신의 자식의 repo 손상을 동기화 위험을 감수하지 않습니다.
  2. 즉각적인 동기화 비활성화 : SpiderOak을 사용하면 변경 사항을 확인하기위한 일정을 "자동"으로 설정할 수 있습니다 (즉, OS 알림 덕분에 파일 변경 사항을 모니터링하는 것이 가능한 한 빨리). 변경 사항을 업로드하자마자 변경 사항을 업로드하기 시작하고 변경 사항을 다운로드하여 방금 수행 한 최신 변경 사항을 지울 수 있기 때문에 이것은 좋지 않습니다. 이 문제를 해결하는 해결책은 변경 모니터링 지연을 5 분 이상으로 설정하는 것입니다. 또한 메모 작성 응용 프로그램 (예 : 메모장 ++)을 즉시 저장하는 문제도 해결합니다.

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

색인을 제거하고 재설정하십시오.

rm -f .git/index
git reset

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에서이 폴더로 복제 한 다음 다시 커밋을 시도하십시오. 아니면 그냥 repo를 삭제하고 다시 복제하세요.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.