스테이징 영역에서 커밋되지 않은 파일로 git reset –hard 실행 취소 user$ git status #

작업을 복구하려고합니다. 나는 어리석은 짓 git reset --hard을했지만 그 전에는했지만 get add .하지 않았다 git commit. 도와주세요! 내 로그는 다음과 같습니다.

MacBookPro:api user$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)

#   modified:   .gitignore
...


MacBookPro:api user$ git reset --hard
HEAD is now at ff546fa added new strucuture for api

git reset --hard이 상황에서 실행 취소 할 수 있습니까?



답변

git add .약간의 작업이긴하지만 색인에 추가 한 모든 파일을 복구 할 수 있어야합니다 (예 :를 사용하여 상황에서 ). 색인에 파일을 추가하기 위해 git은 파일을 객체 데이터베이스에 추가합니다. 즉, 가비지 수집이 아직 발생하지 않은 한 복구 할 수 있습니다. Jakub Narębski의 답변에 제공된 방법에 대한 예가 있습니다.

그러나 테스트 저장소에서 시도해 보았고 몇 가지 문제가있었습니다. --cached이어야하며 --cache실제로 .git/lost-found디렉터리를 생성하지 않았 음을 발견했습니다 . 그러나 다음 단계가 저에게 효과적이었습니다.

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)")

어떤 ref, 인덱스 또는 reflog를 통해 도달 할 수없는 개체 데이터베이스의 모든 개체를 출력해야합니다. 출력은 다음과 같습니다.

unreachable blob 907b308167f0880fb2a5c0e1614bb0c7620f9dc3
unreachable blob 72663d3adcf67548b9e0f0b2eeef62bce3d53e03

… 각 blob에 대해 다음을 수행 할 수 있습니다.

git show 907b308

파일의 내용을 출력합니다.


너무 많은 출력?

아래 sehe 의 의견 에 대한 응답으로 업데이트 :

해당 명령의 출력에 많은 커밋과 트리가 나열되어있는 경우 참조되지 않은 커밋에서 참조되는 모든 객체를 출력에서 ​​제거 할 수 있습니다. (일반적으로 리플 로그를 통해 이러한 커밋으로 돌아갈 수 있습니다. 인덱스에 추가되었지만 커밋을 통해 찾을 수없는 객체에만 관심이 있습니다.)

먼저 다음을 사용하여 명령의 출력을 저장합니다.

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > all

이제 도달 할 수없는 커밋의 개체 이름은 다음을 사용하여 찾을 수 있습니다.

egrep commit all | cut -d ' ' -f 3

따라서 다음을 사용하여 인덱스에 추가되었지만 커밋되지 않은 트리와 개체 만 찾을 수 있습니다.

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") \
  $(egrep commit all | cut -d ' ' -f 3)

이는 고려해야 할 대상의 수를 엄청나게 줄여줍니다.


업데이트 : 아래의 Philip Oakley 는 고려할 개체 수를 줄이는 또 다른 방법을 제안합니다. 이는 .NET에서 가장 최근에 수정 된 파일 만 고려하는 것 .git/objects입니다. 다음을 통해 찾을 수 있습니다.

find .git/objects/ -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort

( 여기서find 호출을 찾았 습니다 .) 목록의 끝은 다음과 같습니다.

2011-08-22 11:43:43.0234896770 .git/objects/b2/1700b09c0bc0fc848f67dd751a9e4ea5b4133b
2011-09-13 07:36:37.5868133260 .git/objects/de/629830603289ef159268f443da79968360913a

이 경우 다음과 같은 개체를 볼 수 있습니다.

git show b21700b09c0bc0fc848f67dd751a9e4ea5b4133b
git show de629830603289ef159268f443da79968360913a

( /객체 이름을 얻으려면 경로 끝에 있는를 제거해야합니다 .)


답변

나는 방금 git reset --hard한 커밋을 잃었습니다. 하지만 커밋 해시를 알고 있었으므로 git cherry-pick COMMIT_HASH복원 할 수있었습니다 .

커밋을 잃은 지 몇 분 안에이 작업을 수행 했으므로 일부 사용자에게는 효과가있을 수 있습니다.


답변

Mark Longair 덕분에 제 물건을 되찾았습니다!

먼저 모든 해시를 파일에 저장했습니다.

git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") > allhashes

다음으로 나는 그것들을 모두 목록에 넣고 ( ‘연결할 수없는 blob’을 제거하는) 데이터를 모두 새 파일에 넣습니다 … 파일을 선택하고 필요한 이름을 다시 바꿔야합니다 …하지만 몇 개만 필요했습니다. files .. 누군가에게 도움이되기를 바랍니다 …

commits = ["c2520e04839c05505ef17f985a49ffd42809f",
    "41901be74651829d97f29934f190055ae4e93",
    "50f078c937f07b508a1a73d3566a822927a57",
    "51077d43a3ed6333c8a3616412c9b3b0fb6d4",
    "56e290dc0aaa20e64702357b340d397213cb",
    "5b731d988cfb24500842ec5df84d3e1950c87",
    "9c438e09cf759bf84e109a2f0c18520",
    ...
    ]

from subprocess import call
filename = "file"
i = 1
for c in commits:
    f = open(filename + str(i),"wb")
    call(["git", "show", c],stdout=f)
    i+=1


답변

댓글의 @ Ajedi32의 솔루션은 정확히이 상황에서 저에게 효과적이었습니다.

git reset --hard @{1}

이 모든 솔루션은 git gc가 없다는 것에 의존하고 일부는 원인이 될 수 있으므로 아무것도 시도하기 전에 .git 디렉토리의 내용을 압축하여 스냅 샷이없는 경우 다시 돌아갈 수 있도록합니다. 당신을 위해 일하지 않습니다.


답변

동일한 문제가 발생했지만 색인에 변경 사항을 추가하지 않았습니다. 따라서 위의 모든 명령은 원하는 변경 사항을 다시 가져 오지 못했습니다.

위의 모든 정교한 답변 끝에 이것은 순진한 힌트이지만 내가 한 것처럼 먼저 생각하지 않은 사람을 구할 수 있습니다.

절망에 빠진 저는 열려있는 모든 탭에서 한 번씩 내 편집기 (LightTable)에서 CTRL-Z를 누르려고했습니다. 운 좋게도 해당 탭의 파일을 git reset --hard. HTH.


답변

이것은 아마도 git 전문가들에게는 분명 할 것입니다. 그러나 나는 광란의 검색에서 이것이 제기되는 것을 보지 못했기 때문에 그것을 올리고 싶었습니다.

일부 파일을 스테이징 git reset --hard하고, 약간 놀란 후 내 상태에 모든 파일이 스테이징되고 모든 삭제가 스테이징되지 않은 것으로 표시되는 것을 발견했습니다.

이 시점에서 삭제를 준비하지 않는 한 이러한 단계적 변경을 커밋 할 수 있습니다. 그 후에는 용기를 내면됩니다.git reset --hard 한 번 더 변경 사항으로 돌아갈 수 있습니다.

다시 말하지만, 이것은 아마도 대부분의 사람들에게 새로운 것은 아니지만, 그것이 저를 도왔고 이것을 제안하는 것을 찾지 못했기 때문에 다른 사람에게 도움이 될 수 있기를 바랍니다.


답변

맙소사, 나는이 질문과 대답을 만날 때까지 머리카락을 뽑았습니다. 질문에 대한 정확하고 간결한 답변은 위의 두 개의 댓글을 함께 가져와야 만 가능하므로 여기에 모두 한곳에 있습니다.

  1. chilicuil에서 언급했듯이 돌아 가려는 git reflog커밋 해시를 확인하기 위해 실행 하십시오.

  2. akimsko에서 언급했듯이 커밋을 하나만 잃지 않는 한 체리 선택을 원하지 않을 것이므로 다음을 실행해야합니다. git reset --hard <hash-commit-you-want>

egit Eclipse 사용자를위한 참고 사항 : egit을 사용하여 Eclipse 내에서 이러한 단계를 수행하는 방법을 찾을 수 없습니다. Eclipse를 닫고 터미널 창에서 위의 명령을 실행 한 다음 Eclipse를 다시 열면 잘 작동했습니다.