git stash pop이 숨김 항목에서 추적되지 않은 파일을 복원 할 수 없다고 말하는 이유는 무엇입니까? 것입니다 –all) 그런 다음 은닉 물을 꺼내 러

나는 많은 단계적 및 비 단계적 변경 사항이 있었고 다른 분기로 빠르게 전환 한 다음 다시 전환하고 싶었습니다.

그래서 다음을 사용하여 변경 사항을 준비했습니다.

$ git stash push -a

(돌아 보면 아마 --include-untracked대신 사용할 수 있었을 것입니다 --all)

그런 다음 은닉 물을 꺼내 러 갔을 때 다음 줄을 따라 많은 오류가 발생합니다.

$ git stash pop
foo.txt already exists, no checkout
bar.txt already exists, no checkout
...
Could not restore untracked files from stash entry

숨김에서 복원 된 변경 사항이없는 것 같습니다.

나는 또한 시도 $ git stash branch temp했지만 동일한 오류를 보여줍니다.

나는 이것을 사용하는 방법을 알아 냈습니다.

$ git stash show -p | git apply

지금은 재난을 피했지만 이로 인해 몇 가지 의문이 제기됩니다.

이 오류가 처음에 발생한 이유는 무엇이며 다음에 어떻게 방지합니까?



답변

약간의 추가 설명 git stash으로 두 번의 커밋 또는 세 번의 커밋을 수행합니다. 기본값은 2입니다. --all또는 --include-untracked옵션의 철자를 사용하면 3 개를받습니다 .

이 두 가지 또는 세, 커밋은 하나의 중요한 방법으로 특별하다 : 그들은에있는 어떤 지점입니다. 힘내는 특별한 이름을 통해 그들을 찾습니다 stash. (1 개) 가장 중요한 것은, 그래도 힘내 당신을-하고 있습니다 무엇을 만들어 이 두 개 또는 세 개의 커밋으로 당신이 할 일. 이를 이해하려면 해당 커밋에 무엇이 있는지 살펴 봐야합니다.

은신처 안에있는 것

모든 커밋은 하나 이상의 상위 커밋을 나열 할 수 있습니다 . 이들은 나중에 커밋이 이전 커밋을 가리키는 그래프를 형성합니다. 숨김은 일반적으로 두 개의 커밋을 보유하고 있는데 i, 색인 / 스테이징 영역 콘텐츠와 w작업 트리 콘텐츠에 대해 호출 하고 싶습니다 . 또한 각 커밋에는 스냅 샷이 포함되어 있습니다. 일반 커밋에서이 스냅 샷은 인덱스 / 스테이징 영역 콘텐츠 에서 만들어집니다 . 따라서 i커밋은 사실 완벽하게 정상적인 커밋입니다! 어떤 지점에도 없습니다.

...--o--o--o   <-- branch (HEAD)
           |
           i

일반 숨김을 만드는 경우 git stash코드는 w추적 된 모든 작업 트리 파일을 임시 보조 인덱스로 복사하여 만듭니다 . Git은이 w커밋 의 첫 번째 부모가 커밋을 가리키고 HEAD두 번째 부모가 commit을 가리 키도록 설정 i합니다. 마지막 stash으로이 w커밋 을 가리 키도록 설정 합니다 .

...--o--o--o   <-- branch (HEAD)
           |\
           i-w   <-- stash

--include-untracked또는 을 추가 --all하면 Git은 u만들기 iw. 의 스냅 샷 내용 u은 추적되지 않지만 무시되지 않은 --include-untracked파일 ( ) 또는 무시 되더라도 추적되지 않는 파일 ( --all)입니다. 이 추가 u투입은 없습니다 에는 부모, 다음 경우 git stash차종은 w, 그것은 설정 w세 번째 이가 부모를 u당신이 얻을 정도로, 커밋 :

...--o--o--o   <-- branch (HEAD)
           |\
           i-w   <-- stash
            /
           u

또한 Git은이 시점 에서 커밋 에서 손상된 모든 작업 트리 파일을 제거 합니다 u( git clean이를 위해 사용 ).

숨김 복원

숨김 을 복원 할 때을 사용 --index하거나 사용하지 않을 수 있습니다. 이 이야기 git stash apply(또는 내부적으로 사용하는 명령의 apply같은 pop)가해야 사용 (가) i현재 인덱스를 수정하려고하는 커밋합니다. 이 수정은 다음으로 수행됩니다.

git diff <hash-of-i> <hash-of-i's-parent> | git apply --index

(어느 정도; 여기에 기본 아이디어를 방해하는 중요한 세부 사항이 많이 있습니다).

생략하면 --index, git stash apply완전히는 무시 i커밋합니다.

숨김에 두 개의 커밋 만있는 경우 git stash apply이제 w커밋을 적용 할 수 있습니다 . git merge2 를 호출 하여 (결과를 일반 병합으로 커밋하거나 처리하도록 허용하지 않고) 숨김이 생성 된 원래 커밋 ( i‘s parent 및 w‘s first parent)을 병합 기반 w으로 사용합니다. --theirs커밋하고 현재 (HEAD) 커밋을 병합 대상으로 지정합니다. 병합이 성공하면 모든 것이 좋습니다. 적어도 Git 은 그렇게 생각하고 git stash apply있습니다. git stash pop숨김을 적용한 경우 코드는 이제 숨김을 삭제 합니다. 3 병합이 실패하면 Git은 적용이 실패했다고 선언합니다. 사용한 경우git stash pop, 코드는 숨김을 유지하고와 동일한 오류 상태를 제공합니다 git stash apply.

그러나 세 번째 커밋이있는 경우 u-적용중인 숨김에 커밋 이 있으면 모든 것이 변경됩니다! 커밋이없는 척할 수있는 옵션 u이 없습니다. 4 Git은 해당 커밋의 모든 파일 u 현재 작업 트리로 추출하도록 고집합니다 . 이것은 파일이 전혀 존재하지 않거나 u커밋 에서와 동일한 내용을 가져야 함을 의미합니다 .

그렇게하려면 git clean직접 사용할 수 있습니다. 그러나 추적되지 않은 파일 (무시 여부에 관계없이)은 Git 저장소 내에 다른 존재가 없으므로 이러한 파일이 모두 파괴 될 수 있는지 확인하십시오! 또는, 임시 디렉토리를 만들고, 다른 작업을 수행에도 보관 또는 거기에 파일을 이동할 수 있습니다 git stash save -u또는 git stash save -a그 실행하기 때문에, git clean당신을 위해. 그러나 그것은 u나중에 처리 할 또 다른 스타일의 은닉을 남깁니다 .


1 이것은 사실 refs/stash입니다. 이것은 당신이라는 이름의 브랜치를 만드는 경우에 중요합니다 stash: 브랜치의 전체 이름은 refs/heads/stash이므로 충돌하지 않습니다. 하지만 그렇게하지 마세요 : Git 은 신경 쓰지 않을 것입니다.하지만 당신은 자신을 혼란스럽게 할 것입니다. 🙂

2git stash 코드는 실제로 사용하는 git merge-recursive바로 여기. 이것은 여러 가지 이유로 필요하며 충돌을 해결하고 커밋 할 때 Git이 병합으로 처리하지 않도록하는 부작용도 있습니다.

3 이것이 내가 git stash pop찬성하여 피하는 것이 좋습니다 git stash apply. 적용된 내용을 검토하고 실제로 올바르게 적용되었는지 여부를 결정할 수 있습니다 . 그렇지 않다면, 모든 것을 완벽하게 복구 하는 데 사용할 수있는 은닉처 가 있습니다 git stash branch. 글쎄, 그 성가신 u커밋 이 없다고 가정하면 .

4 정말로 있어야합니다 : git stash apply --skip-untracked또는 무언가. 또한 수단이있는 변형이 있어야 모든 드롭 u새로운 디렉토리에 파일을 커밋 , 예를 들면 git stash apply --untracked-into <dir>, 아마.


답변

나는 당신의 문제를 재현했습니다. 추적되지 않은 파일을 숨긴 다음 해당 파일 (예 : foo.txtbar.txt)을 생성하면 git stash pop.

이 문제를 해결하려면 다음 명령을 사용할 수 있습니다. 이렇게하면 저장되지 않은 로컬 변경 사항무시 되므로주의하십시오.

git checkout stash -- .

다음은 이전 명령에서 찾은 추가 정보 입니다.


답변

Daniel Smith의 답변 을 확장하려면 숨김을 만들 때 (또는 ) 을 사용하더라도 해당 코드는 추적 된 파일 만 복원합니다 . 필요한 전체 코드는 다음과 같습니다.--include-untracked-u

git checkout stash -- .
git checkout stash^3 -- .
git stash drop

# Optional to unstage the changes (auto-staged by default).
git reset

이렇게하면 추적 된 콘텐츠 (에서 stash)와 추적되지 않은 콘텐츠 (에서 stash^3)가 완전히 복원 된 다음 숨김이 삭제됩니다. 몇 가지 참고 :

  • 조심하세요 -이것은 당신의 숨김 내용으로 모든 것을 덮어 쓸 것입니다!
  • 로 파일을 복원하면 git checkout모든 파일 이 자동으로 스테이징되므로 모든 스테이징을 해제하도록 추가 git reset했습니다.
  • 일부 리소스 사용 stash@{0}stash@{0}^3, 내 테스트에서 동일하게 작동합니다.@{0}

출처 :


답변

다른 답변 외에도 약간의 트릭을

  • 모든 새 파일 삭제 (이미 기존 파일, 예 : 질문의 foo.txt 및 bar.txt)
  • git stash apply (적용, 팝 등 모든 명령을 사용할 수 있습니다.)