Git에서 떨어진 스테이크를 복구하는 방법?


1737

작업 트리에서 자주 사용 git stash하고 git stash pop변경 내용을 저장하고 복원합니다. 어제 나는 작업 트리에서 약간 숨겨져 서 튀어 나와서 작업 트리를 더 많이 변경했습니다. 돌아가서 어제의 숨겨진 변경 사항을 검토하고 싶지만 git stash pop관련 커밋에 대한 모든 참조를 제거하는 것으로 보입니다.

내가 사용 git stash하면 .git / refs / stash에 숨김 을 만드는 데 사용되는 커밋의 참조가 포함되어 있음을 알고 있습니다 . 그리고 .git / logs / refs / stash 는 전체 숨김을 포함 합니다. 그러나 그 참조는 사라졌다 git stash pop. 커밋이 여전히 내 저장소에 있다는 것을 알고 있지만 그것이 무엇인지 모르겠습니다.

어제의 숨김 커밋 참조를 복구하는 쉬운 방법이 있습니까?

매일 백업이 있고 변경 사항을 가져 오기 위해 어제 작업 트리로 돌아갈 수 있기 때문에 이것은 오늘 나에게 중요하지 않습니다. 더 쉬운 방법이 있어야하기 때문에 묻습니다!


74
미래에 대한 참고 사항 : 매번 스 태쉬를 잃고 싶지 않다면 대신 git stash pop할 수 있습니다 git stash apply. 적용된 숨김에 대한 참조를 제거하지 않는다는 점을 제외하고는 동일한 작업을 수행합니다.
Kevin

3
여기에 모든 것을 시도했지만 이미 팝업 된 숨김을 찾을 수 없었습니다. IntelliJ에의에 대한 그래서 기쁜 jetbrains.com/help/idea/local-history.html
후안 멘데스


나는이 문제가 있었다. 내 REPO를 업데이트하려면, 내가 실행 git stash, git pull -r upstream, git push -f origin, git stash pop"심판에 대한 로그 / 마리화나가 비어 치명적인는"팝 말했다. these 나는이 답변을 많이 시도했지만 아무것도 효과가 없었습니다. .git / refs / stash 살펴 보았을 때 SHA가 거기에있었습니다. 오프라인 동기화를 위해 Windows 네트워크 드라이브를 표시하는 데 문제가 있습니까? 🤷‍♂️
brianary

답변:


2784

삭제 한 숨김 커밋의 해시를 알게되면이를 숨김으로 적용 할 수 있습니다.

git stash apply $stash_hash

또는 다음과 같이 별도의 분기를 만들 수 있습니다.

git branch recovered $stash_hash

그런 다음 모든 일반 도구를 사용하여 원하는 모든 작업을 수행 할 수 있습니다. 완료되면 지점을 날려 버립니다.

해시 찾기

방금 터져서 터미널이 여전히 열려 있으면 화면에 해시 값이 인쇄됩니다git stash pop (감사합니다, Dolda).

그렇지 않으면 Linux, Unix 또는 Git Bash for Windows에서 다음을 사용하여 찾을 수 있습니다.

git fsck --no-reflog | awk '/dangling commit/ {print $3}'

... 또는 Windows 용 Powershell 사용 :

git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}

이것은 커밋 그래프의 끝에서 더 이상 모든 브랜치 또는 태그에서 참조되지 않는 모든 커밋을 보여줍니다. 생성 한 모든 숨김 커밋을 포함하여 손실 된 커밋은 해당 그래프의 어딘가에 있습니다.

원하는 숨김 커밋을 찾는 가장 쉬운 방법은 해당 목록을 gitk다음 으로 전달하는 것입니다 .

gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )

... 또는 Windows 용 Powershell을 사용하는 경우 엠 라긴의 답변을 참조하십시오 .

도달 가능한지 여부에 관계없이 저장소의 모든 단일 커밋을 보여주는 저장소 브라우저가 시작됩니다 .

콘솔에서 별도의 GUI 앱보다 멋진 그래프를 선호하는 경우 gitk와 같은 것으로 바꿀 수 있습니다 git log --graph --oneline --decorate.

숨김 커밋을 발견하려면 다음 형식의 커밋 메시지를 찾으십시오.

somebranch의         WIP : commithash 일부 오래된 커밋 메시지

참고 : 커밋 메시지는 메시지를 제공하지 않은 경우에만 "WIP on"으로 시작하는이 형식 git stash입니다.


49
Jaydel은 내 입에서 단어를 꺼내었다. 이 게시물은 내 직업을 저장했습니다.
Sridhar Sarnobat

4
@Codey : PowerShell 때문입니다. MsysGit이 AWK 바이너리를 제공하는지 모르겠습니다. 인터넷 검색은 PowerShell의 해당 명령 %{ $_.Split(' ')[2]; }과 동등한 기능을 수행해야한다고 말하지만 Windows 시스템이 테스트하지 않으므로 여전히 해당 기능이 필요합니다 . 어쨌든, 그냥 실행 하고 출력을보십시오. "dangling commit <commitID>"줄의 해시를 원합니다. {print $3}awk/dangling commit/git fsck --no-reflog
Aristotle Pagaltzis

7
보관할 때 (예 : 수행 git stash save "<message>") 자신의 메시지를 제공하지 않은 경우 커밋 메시지에는 "WIP"문자열 만 포함됩니다 .
Samir Aguiar

12
삭제가 언제 발생했는지 아는 경우이 단일 라이너를 사용하여 시간을 늘림으로써 매달려있는 커밋 목록을 얻을 수 있습니다. git fsck --no-reflog | awk '/dangling commit/ {print $3}' | xargs -L 1 git --no-pager show -s --format="%ci %H" | sort마지막 항목은 아마도 원하는 항목입니다 stash apply.
ris8_allo_zen0

3
git stash apply {ref}떨어진 스테이크를 복원했습니다! git너무 커서 불법입니다!
Tom Russell

707

터미널을 닫지 않은 경우 출력을 보면 git stash pop드롭 된 숨김의 개체 ID가 표시됩니다. 일반적으로 다음과 같습니다.

$ git stash pop
[...]
Dropped refs/stash@{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1)

( git stash drop또한 동일한 라인을 생성합니다.)

그 숨김을 다시 얻으려면을 실행 git branch tmp 2cae03e하면 지점으로 얻을 수 있습니다. 이것을 숨김으로 변환하려면 다음을 실행하십시오.

git stash apply tmp
git stash

분기로 사용하면 분기를 자유롭게 조작 할 수도 있습니다. 예를 들어, 체리 피킹 또는 병합합니다.


54
그런 git stash apply commitid다음 git stash새 숨김을 얻기 위해 수행 할 수도 있습니다 .
Matthew Flaschen

32
git이 숨김을 자동 병합하고 충돌이 있으면 해시가 표시되지 않습니다.
제임스

31
@James : 그런 다음에도 이러한 충돌이 실행의 결과라면 git stash pop숨김을 제거하지 않으므로 일반적으로 문제가되지 않습니다.
Dolda2000

2
내 자식 숨김 팝 출력에 SHA가 없습니다. :(
던져 버림 계정

2
@Honey : 그게 요점입니다 git stash pop. 스 태쉬를 떨어 뜨리지 않고 적용하려면 git stash apply대신 사용하십시오. 또한 여러 브랜치에 변경 사항을 적용하려는 경우 대신 커밋을 체리 픽으로 선택할 수도 있습니다.
Dolda2000

271

허용 된 솔루션에이 추가 사항을 언급하고 싶었습니다. 이 방법을 처음 시도했을 때 나에게 명백하지는 않았지만 (아마도 그렇 겠지만) 해시 값에서 숨김을 적용하려면 "git stash apply"를 사용하십시오.

$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219

내가 git을 처음 접했을 때 이것은 분명하지 않았으며 "git show", "git apply", "patch"등의 다른 조합을 시도하고있었습니다.


3
이것은 현재 작업 트리에 숨김을 적용합니다 (duh!). 트리가 더티 인 경우 임시 분기를 사용하거나 먼저 숨김을 사용하고 SHA-1에서 숨김을 적용한 후 다시 숨김을 누른 다음 두 번째를 마지막 숨김 (popsh @ {1})으로 팝하십시오.
musiKk

111

아직 저장소에 있지만 더 이상 연결할 수없는 숨김 목록을 가져 오려면 다음을 수행하십시오.

git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP

숨김에 제목을 지정한 -grep=WIP경우 명령 끝에 "WIP"를 메시지의 일부로 바꾸 십시오 (예 :) -grep=Tesselation.

숨김에 대한 기본 커밋 메시지가 다음과 같은 형식이므로 명령이 "WIP"를 가져 오는 중입니다. WIP on mybranch: [previous-commit-hash] Message of the previous commit.


1
echo 'git fsck-연결 불가 | grep commit | 컷 -d ""-f3 | xargs git log --merges --no-walk --grep = WIP '> / usr / local / bin / git-stashlog; chmod a + rx / usr / local / bin / git-stashlog # git stashlog
Erik Martino

또는 이것을 별칭으로 .gitconfig에 추가 할 수 있습니다 (명령 앞에 a !).
asmeurer

내 베이컨을 저장했습니다-실제로는 아니지만 일을 다시 코딩하는 것을 저장했습니다-감사합니다-최근에 떨어 졌다는 것을 감안할 때 명령의 출력에서 ​​최상위 SHA를 선택했습니다 ... 그런 다음 .... git stash apply SHA ... 다른 답변에서 언급했듯이-많은 thx
danday74

75

방금 잃어버린 숨김 커밋을 찾는 데 도움이되는 명령을 만들었습니다.

for ref in `find .git/objects | sed -e 's#.git/objects/##' | grep / | tr -d /`; do if [ `git cat-file -t $ref` = "commit" ]; then git show --summary $ref; fi; done | less

이것은 .git / objects 트리의 모든 객체를 나열하고, commit 타입 인 객체를 찾은 다음 각 객체의 요약을 보여줍니다. 이 시점에서 적절한 "WIP on work : 6a9bb2"( "work"은 내 브랜치, 619bb2는 최근 커밋)를 찾기 위해 커밋을 살펴 보는 것입니다.

"git stash pop"대신 "git stash apply"를 사용하면이 문제가 발생하지 않으며 "git stash save message "를 사용하면 커밋을 찾기가 더 쉬울 수 있습니다.

업데이트 : Nathan의 아이디어로, 이것은 짧아집니다.

for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less

41

git fsck --unreachable | grep commit그것이 반환하는 목록이 상당히 클 수도 있지만 sha1을 표시해야합니다. git show <sha1>원하는 커밋인지 표시합니다.

git cherry-pick -m 1 <sha1> 커밋을 현재 브랜치에 병합합니다.


37

gitk를 사용하는 Windows PowerShell :

gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] })

하나의 파이프 에서이 작업을 수행하는보다 효율적인 방법이있을 수 있지만이 작업을 수행합니다.


1
나는 당신의 답변에 매우 감사합니다
Виталий Шебаниц

32

잃어버린 숨김을 다시 저장하려면 먼저 잃어버린 숨김의 해시를 찾아야합니다.

아리스토텔레스 Pagaltzis가 제안한대로 git fsck당신을 도울 것입니다.

개인적으로 log-all상황을 더 잘 볼 수 있도록 모든 커밋 (복구 가능한 커밋)을 보여주는 별칭을 사용 합니다.

git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3)

"WIP on"메시지 만 찾으려면 더 빠른 검색을 수행 할 수 있습니다.

sha1을 알고 나면 숨김 숨김을 변경하여 이전 숨김을 추가하십시오.

git update-ref refs/stash ed6721d

당신은 아마 관련된 메시지를 가지고 선호합니다 -m

git update-ref -m "$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721d

그리고 이것을 별명으로 사용하고 싶을 수도 있습니다.

restash = !git update-ref -m $(git log -1 --pretty=format:'%s' $1) refs/stash $1

2
그러나이 -d\\ 있어야한다 -d\ (또는 명확 -d' ')
joeytwiddle

오류 : "치명적 : 모호한 인수 'dangling': 알 수없는 개정 또는 작업 트리에없는 경로입니다."
Daniel Ryan

당신은 또한 따옴표와 함께 하위 명령을 포장 할 필요가 git update-ref -m "$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721
안드레이 Shostik

18

나는 아리스토텔레스의 접근 방식을 좋아했지만 GITK를 사용하는 것을 좋아하지 않았다.

대신, 매달린 커밋을 가져 와서 코드 편집기에서 검토 할 수 있도록 코드를 DIFF 파일로 출력했습니다.

git show $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' ) > ~/stash_recovery.diff

이제 결과 diff / txt 파일 (홈 폴더에 있음)을 txt 편집기에로드하고 실제 코드와 결과 SHA를 볼 수 있습니다.

그런 다음 사용하십시오

git stash apply ad38abbf76e26c803b27a6079348192d32f52219

17

터미널에이 명령을 작성하여 도달 할 수없는 모든 커밋을 나열 할 수 있습니다.

git fsck --unreachable

연결할 수없는 커밋 해시 확인-

git show hash

보관 된 항목을 찾으면 마지막으로 적용하십시오.

git stash apply hash

15

사람들은 왜이 질문을합니까? 그들은 reflog에 대해 아직 알지 못하거나 이해하지 못하기 때문입니다.

이 질문에 대한 대부분의 대답은 거의 아무도 기억하지 못하는 옵션이있는 긴 명령을 제공합니다. 그래서 사람들은이 질문에 들어 와서 필요하다고 생각하는 것을 붙여넣고 거의 즉시 잊어 버립니다.

나는이 질문을 가진 모든 사람들에게 reflog (git reflog)를 확인하는 것이 좋습니다. 모든 커밋 목록을 확인하면 원하는 커밋을 확인하고 체리 픽을 선택하거나 지점에서 분기를 만들 수있는 100 가지 방법이 있습니다. 이 과정에서 다양한 기본 git 명령에 대한 reflog 및 유용한 옵션에 대해 배웠습니다.


1
안녕 로비. 이것은 일을하고 있고, 부수적이며, 몇 주 전에 중단 한 부분을 다시 찾아야 만 숨겨둔 작업을 찾을 수없는 경우와 관련이 있습니다. 하고 있었다. reflog는 최근의 역사라면 훌륭하지만 오랜 시간 차이는 없습니다.
emragins 2016 년

1
이봐, 나는 동의하지만, 이것은 정확히 OP의 사용 사례였습니다. 나는 여기에 게시 된 다른 명령이 어떻게 작동하는지 확실하지 않지만, 내 명령은 그의 숨김 커밋에 대한 심판이 정리되면 작동을 멈출 것입니다.
RobbyD

1
흠 ... 위의 시나리오는이 질문에 나를 이끌어 냈으며, 나는 (무의식적으로) 내 숨김을 잃어 버렸을 때와 그것을 회복 할 수있을 때 사이에 한 달에 가깝지 않으면 적어도 몇 주가 걸렸다는 것을 알고 있습니다.
emragins

15

git v2.6.4가있는 OSX에서는 실수로 git stash drop을 실행 한 다음 단계 아래로 이동하여 찾았습니다.

숨김 이름을 알고 있으면 다음을 사용하십시오.

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show | grep -B 6 -A 2 <name of the stash>

그렇지 않으면 다음을 사용하여 수동으로 결과에서 ID를 찾을 수 있습니다.

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show

그런 다음 commit-id를 찾으면 git stash apply {commit-id}를 누르십시오.

이것이 누군가를 빨리 도울 수 있기를 바랍니다.


12

사용할 수있는 gitk가 없거나 출력을 위해 X가 없을 때 모든 변경 사항을 처리하는 또 다른 좋은 방법을 허용 된 솔루션에 추가하고 싶습니다.

git fsck --no-reflog | awk '/dangling commit/ {print $3}' > tmp_commits

for h in `cat tmp_commits`; do git show $h | less; done

그런 다음 해시에 대한 모든 차이점을 차례로 표시합니다. 다음 차이점으로 가려면 'q'를 누르십시오.


12

간단한 명령 창 (필자의 경우 Windows 7)에서 Windows에서 작동하는 답변을 얻을 수 없었습니다. awk, grepSelect-string명령으로 인식되지 않았다. 그래서 다른 접근법을 시도했습니다.

  • 첫 실행 : git fsck --unreachable | findstr "commit"
  • 출력을 메모장에 복사
  • "도달 할 수없는 커밋"을 start cmd /k git show

다음과 같이 보일 것입니다 :

start cmd /k git show 8506d235f935b92df65d58e7d75e9441220537a4 start cmd /k git show 44078733e1b36962571019126243782421fcd8ae start cmd /k git show ec09069ec893db4ec1901f94eefc8dc606b1dbf1 start cmd /k git show d00aab9198e8b81d052d90720165e48b287c302e

  • .bat 파일로 저장하고 실행
  • 스크립트는 각 커밋을 보여주는 많은 명령 창을 엽니 다.
  • 찾고있는 것을 찾으면 다음을 실행하십시오. git stash apply (your hash)

최선의 해결책은 아니지만 나를 위해 일했습니다.


Windows에서도 git bash를 사용할 수 있습니다. git bash에는 필요한 모든 (unixoid) 명령 행 도구가 있습니다.
Adrian W

10

Aristotle이 수락 한 답변에는 비스 태시 같은 커밋을 포함하여 도달 가능한 모든 커밋이 표시됩니다. 노이즈를 필터링하려면

git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
  --grep="WIP on" --min-parents=3 --max-parents=3

여기에는 정확히 3 개의 부모 커밋이 있고 (스 태쉬가 가질) 커밋과 메시지에 "WIP on"이 포함 된 커밋 만 포함됩니다.

숨김 메시지를 메시지와 함께 저장하면 (예 git stash save "My newly created stash":) 기본 "WIP on ..."메시지를 무시합니다.

각 커밋에 대한 추가 정보를 표시 할 수 있습니다 (예 : 커밋 메시지 표시 또는 전달) git stash show.

git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
  --grep="WIP on" --min-parents=3 --max-parents=3 | \
xargs -n1 -I '{}' bash -c "\
  git log -1 --format=medium --color=always '{}'; echo; \
  git stash show --color=always '{}'; echo; echo" | \
less -R

6

내가 가장 좋아하는 것은이 라이너입니다.

git log --oneline  $( git fsck --no-reflogs | awk '/dangling commit/ {print $3}' )

이것은 기본적 으로이 답변 과 동일 하지만 훨씬 짧습니다. 물론 --graph나무 모양의 디스플레이를 얻기 위해 추가 할 수 있습니다.

목록에서 커밋을 찾았을 때

git stash apply THE_COMMIT_HASH_FOUND

나를 위해, --no-reflogs잃어버린 숨김 항목을 사용했지만 --unreachable(다른 많은 답변에서 찾은 것처럼) 그렇지 않았습니다.

Windows를 사용하는 경우 git bash에서 실행하십시오.

크레딧 : 위의 명령에 대한 자세한 내용은 https://gist.github.com/joseluisq/7f0f1402f05c45bac10814a9e38f81bf 에서 가져옵니다.


5

다음 단계를 사용하여 복구했습니다.

  1. 삭제 된 숨김 해시 코드를 식별하십시오.

    gitk --all $ (git fsck --no-reflog | awk '/ dangling commit / {print $ 3}')

  2. 체리는 창고를 선택하십시오 :

    자식 체리-피크 -m 1 $ stash_hash_code

  3. 다음을 사용하여 충돌을 해결하십시오.

    자식 병합 도구

또한 gerrit을 사용하는 경우 커밋 메시지에 문제가있을 수 있습니다. 다음 대안을 따르기 전에 변경 사항을 보관하십시오 :

  1. 이전 커밋으로 하드 리셋을 사용한 다음이 변경을 다시 커밋하십시오.
  2. 변경 사항을 숨기고 리베이스하고 다시 커밋 할 수도 있습니다.

@ miva2 귀하의 수정으로이 질문에서 가장 정확한 답변에 대한 링크가 제거되었습니다. 코멘트 stackoverflow.com/questions/89332/…에
Abhijeet

4

내가 찾은 것은 내가 체크 아웃 한 것에 관계없이 실제로 숨김을 다시 얻는 방법입니다. 특히, 나는 무엇인가를 숨기고, 구 버전을 체크 아웃 한 후 튀어 나왔지만, 그 초기에는 아무런 숨김이 없었기 때문에 그 숨기는 사라졌다; git stash스택에 다시 밀어 넣을 수 없었습니다 . 이것은 나를 위해 일했다 :

$ git checkout somethingOld
$ git stash pop
...
nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/stash@{0} (27f6bd8ba3c4a34f134e12fe69bf69c192f71179)
$ git checkout 27f6bd8ba3c
$ git reset HEAD^    # Make the working tree differ from the parent.
$ git stash # Put the stash back in the stack.
Saved working directory and index state WIP on (no branch): c2be516 Some message.
HEAD is now at c2be516 Some message.
$ git checkout somethingOld # Now we are back where we were.

돌이켜 보면 나는 git stash applynot을 사용 했어야했다 git stash pop. 나는 bisect모든 bisect단계 에서 적용하고 싶었던 작은 패치를 가지고있었습니다 . 이제 나는 이것을하고있다 :

$ git reset --hard; git bisect good; git stash apply
$ # Run tests
$ git reset --hard; git bisect bad; git stash apply
etc.

이것이 답변입니까, 아니면 질문의 지속입니까?
Alex Brown

둘 다. 은신처를 잃어 버렸기 때문에이 페이지를 찾았습니다. 나를위한 유스 케이스는 각 단계에서 테스트하기 전에 변경 사항을 적용하려는 이등분을하고 있습니다. 나는 팝에 다른 커밋을 남길 수 있기 때문에 팝, 테스트, 숨김, 이등분 할 수없는 어려운 방법을 배웠습니다 stash apply.
Ben
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.