git reset --hard HEAD ~ 1을 어떻게 취소 할 수 있습니까?


1156

다음 명령으로 인한 변경 사항을 취소 할 수 있습니까? 그렇다면 어떻게?

git reset --hard HEAD~1

8
나는 git으로 커밋을 잃어 버리는 것에 대한 완전한 가이드를 작성했다. 그림도 있습니다 :-) [체크 아웃] [fixLink] [fixLink] : programblings.com/2008/06/07/…
webmat

12
--hard커밋되지 않은 변경 사항을 삭제합니다. 이들은 git에 의해 추적되지 않으므로 git을 통해 복원 할 수있는 방법이 없습니다.
Zaz


1
문서는 파일 복구에 도움이되는 훌륭한 기사입니다.
Jan Swart

2
이것은 바로 Github에서에서 좋은 자원 : 힘내과 (거의) 아무것도 실행 취소 방법
jasonleonhard

답변:


1771

Pat Notz가 맞습니다. 커밋이 며칠 내에 있었던 한 커밋을 다시받을 수 있습니다. git은 가비지 수집을 약 한 달 정도 후에 새로운 블롭을 제거하도록 명시 적으로 지시하지 않는 한 수집합니다.

$ git init
Initialized empty Git repository in .git/

$ echo "testing reset" > file1
$ git add file1
$ git commit -m 'added file1'
Created initial commit 1a75c1d: added file1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file1

$ echo "added new file" > file2
$ git add file2
$ git commit -m 'added file2'
Created commit f6e5064: added file2
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file2

$ git reset --hard HEAD^
HEAD is now at 1a75c1d... added file1

$ cat file2
cat: file2: No such file or directory

$ git reflog
1a75c1d... HEAD@{0}: reset --hard HEAD^: updating HEAD
f6e5064... HEAD@{1}: commit: added file2

$ git reset --hard f6e5064
HEAD is now at f6e5064... added file2

$ cat file2
added new file

예제에서 file2가 하드 리셋의 결과로 제거되었지만 reflog를 통해 재설정 할 때 제자리에 다시 놓인 것을 볼 수 있습니다.


222
SHA1을 사용할 필요없이 "git reset --hard HEAD @ {1}"을 사용할 수 있습니다. 대부분의 경우 "git reset --hard ORIG_HEAD"를 사용하면 충분합니다.
Jakub Narębski

39
git log -greflog를 보는 것보다 조금 더 좋은 방법이 될 수 있습니다 git reflog.
Dan Molding

60
이것에 대한 하나의 중요한 경고가 있습니다. 그리고 그것은 "-단단한"부분입니다. -커밋되지 않은 로컬 변경 사항을 제거합니다. 그리고 당신은 (어딘가에 헌신하지 않았기 때문에) 이것을 이렇게 되돌릴 수 없습니다. 나는 당신이 그것에 대해 할 수있는 일이 없다고 생각합니다 :(
Michael Anderson

3
^ 재설정을하기 전에 로컬 변경 사항을 숨길 수 있다는 것을 알게되었으므로 변경하면 아무 것도 잃지 않습니다! 자식을 사랑해야합니다.
Lethjakman

5
내가 선호하는 git reflog동안 git log -g당신은 SHA1, HEAD 정보와 함께 한 줄에 모든 정보를 얻을 모든 줄을 커밋 메시지를 간단하게하기 때문이다. 훨씬 쉽게 읽을 수 있습니다.
Snowcrash

370

수행하려는 것은 복원하려는 커밋의 sha1을 지정하는 것입니다. reflog ( git reflog) 를 검사 한 후 다음을 수행 하여 sha1을 얻을 수 있습니다.

git reset --hard <sha1 of desired commit>

그러나 너무 오래 기다리지 마십시오 ... 몇 주 후에 git은 커밋을 참조되지 않은 것으로보고 모든 블롭을 삭제합니다.


2
몇 분 전 경고 : 모든 수정 사항이 재설정됩니다. 그러나 추적되지 않은 파일은 건드리지 않습니다.
aexl

175

위의 자세한 답변에 답이 숨겨져 있습니다.

$> git reset --hard HEAD@{1}

( git reflog show 출력 참조 )


17
재설정 이후에 다른 리포지토리를 변경 한 경우에는 이것이 해결책이 아닙니다. 무엇이든 실행하기 전에 반드시 reflog를 살펴보십시오.
forresthopkinsa 2016 년

2
실수로 저장소를 재설정하고 작업이 영원히 손실되었다고 생각했습니다. 이 대답은 나의 하루를 구했습니다.
자양 리

어! 당신은 정말 날 =) 저장
jfcogato 9

큰. 정말 도움이되었습니다.
Prashant Biradar

117

Git이 아직 가비지 수집하지 않은 경우 복구 할 수 있습니다.

다음을 사용하여 매달려 커밋에 대한 개요를 얻으십시오 fsck.

$ git fsck --lost-found
dangling commit b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

rebase로 매달려 커밋을 복구하십시오.

$ git rebase b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

1
생명을 구했습니다.
Mohhamad Hasham

자세한 설명은 medium.com/@CarrieGuss/… 에서 확인할 수 있습니다 . 생명을 구하는 물건.
tuan.dinh

49

운이 좋으면 나처럼 텍스트 편집기로 돌아가 'undo'를 누를 수 있습니다.

나는 그것이 정답이 아니라는 것을 알고 있지만, 반나절의 작업을 저에게 저장했기 때문에 다른 누군가를 위해 같은 일을 할 수 있기를 바랍니다!


3
이것은 실제로 매우 유용한 팁이며, 많은 시간을 절약했습니다.) 그리고 git에서 작업하는 것보다 훨씬 간단합니다.
Severin

3
이 세상에서 은혜로운 모든 선의에 감사드립니다 감사합니다. 감사합니다. 감사합니다.
여행

9
하드 재설정 후 파일에서 비 단계적 변경 사항을 복구 할 수있는 유일한 방법입니다. 나도 저장된)
Czarek Tomczak

4
추가 힌트로 이클립스와 같은 일부 IDE에는 최근 파일 기록이 저장됩니다. 이렇게하면 편집기를 닫은 후 이전 변경 내용을 복구 할 수도 있습니다. 그것은 나를 위해 놀라운 일을했다.
martin

1
신의 축복 Chris
Adam Waite

45

내가 아는 한 --hard커밋되지 않은 변경 사항은 버립니다. 이것들은 git에 의해 추적되지 않기 때문에. 하지만을 취소 할 수 있습니다 discarded commit.

$ git reflog

다음을 나열합니다 :

b0d059c HEAD@{0}: reset: moving to HEAD~1
4bac331 HEAD@{1}: commit: added level introduction....
....

어디 4bac331입니다 discarded commit.

이제 커밋으로 머리를 옮기십시오.

$ git reset --hard 4bac331

34

IRL 사례의 예 :

$ git fsck --lost-found

Checking object directories: 100% (256/256), done.
Checking objects: 100% (3/3), done.
dangling blob 025cab9725ccc00fbd7202da543f556c146cb119
dangling blob 84e9af799c2f5f08fb50874e5be7fb5cb7aa7c1b
dangling blob 85f4d1a289e094012819d9732f017c7805ee85b4
dangling blob 8f654d1cd425da7389d12c17dd2d88d318496d98
dangling blob 9183b84bbd292dcc238ca546dab896e073432933
dangling blob 1448ee51d0ea16f259371b32a557b60f908d15ee
dangling blob 95372cef6148d980ab1d7539ee6fbb44f5e87e22
dangling blob 9b3bf9fb1ee82c6d6d5ec9149e38fe53d4151fbd
dangling blob 2b21002ca449a9e30dbb87e535fbd4e65bac18f7
dangling blob 2fff2f8e4ea6408ac84a8560477aa00583002e66
dangling blob 333e76340b59a944456b4befd0e007c2e23ab37b
dangling blob b87163c8def315d40721e592f15c2192a33816bb
dangling blob c22aafb90358f6bf22577d1ae077ad89d9eea0a7
dangling blob c6ef78dd64c886e9c9895e2fc4556e69e4fbb133
dangling blob 4a71f9ff8262701171d42559a283c751fea6a201
dangling blob 6b762d368f44ddd441e5b8eae6a7b611335b49a2
dangling blob 724d23914b48443b19eada79c3eb1813c3c67fed
dangling blob 749ffc9a412e7584245af5106e78167b9480a27b
dangling commit f6ce1a403399772d4146d306d5763f3f5715cb5a    <- it's this one

$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a

commit f6ce1a403399772d4146d306d5763f3f5715cb5a
Author: Stian Gudmundsen Høiland <stian@Stians-Mac-mini.local>
Date:   Wed Aug 15 08:41:30 2012 +0200

    *MY COMMIT MESSAGE IS DISPLAYED HERE*

diff --git a/Some.file b/Some.file
new file mode 100644
index 0000000..15baeba
--- /dev/null
+++ b/Some.file
*THE WHOLE COMMIT IS DISPLAYED HERE*

$ git rebase f6ce1a403399772d4146d306d5763f3f5715cb5a

First, rewinding head to replay your work on top of it...
Fast-forwarded master to f6ce1a403399772d4146d306d5763f3f5715cb5a.

2
매달려있는 얼룩 은 AD & D 괴물처럼 들립니다!
sbichenko

감사합니다 @Stian Well 설명했습니다! 이 답변을 찾는 다른 사람들을 위해 "dangling"커밋이 두 개 이상인 경우 마지막 행에서 리베이스를 수행 할 것인지 확실하지 않습니다. :)
JimiSweden

git show가 내 파일 중 일부를 저장했습니다. 친구 감사합니다!
William

32

대부분의 경우 그렇습니다.

명령을 실행할 때 리포지토리의 상태에 따라 그 결과는 git reset --hard사소한 것부터 실행 취소 할 수 있으며 기본적으로 불가능할 수 있습니다.

아래에는 다양한 가능한 시나리오와 복구 방법이 나와 있습니다.

내 모든 변경 사항이 커밋되었지만 이제 커밋이 사라졌습니다!

이 상황은 보통 다음 git reset과 같이 인수로 실행할 때 발생합니다 .git reset --hard HEAD~ . 걱정하지 마십시오. 복구하기 쉽습니다!

당신이 방금 달리고 git reset그 이후로 아무것도하지 않았다면,이 한 줄짜리가있는 곳으로 돌아갈 수 있습니다 :

git reset --hard @{1}

이렇게하면 마지막 분기가 수정되기 전의 상태에 관계없이 현재 분기가 재설정됩니다 (이 경우 분기에 대한 최신 수정은 실행 취소하려는 하드 재설정이됩니다).

그러나,이 경우 리셋 이후 지점에 다른 수정 한, 한 - 라이너 이상 작동하지 않습니다. 대신, 분기에 대한 모든 최근 변경 사항 목록 (재설정 포함)을 보려면 실행해야합니다 . 이 목록은 다음과 같습니다.git reflog <branchname>

7c169bd master@{0}: reset: moving to HEAD~
3ae5027 master@{1}: commit: Changed file2
7c169bd master@{2}: commit: Some change
5eb37ca master@{3}: commit (initial): Initial commit

이 목록에서 "실행 취소"할 조작을 찾으십시오. 위의 예에서 첫 번째 줄은 "재설정 : HEAD로 이동 ~"입니다. 그런 다음 해당 작업 (아래)에 커밋 표현을 복사하십시오 . 우리의 경우, 그것은 master@{1}(또는 3ae5027둘 다 동일한 커밋을 나타냅니다) 실행됩니다git reset --hard <commit> 현재 분기를 해당 커밋으로 다시 설정하기 위해 됩니다.

나는 내 변화를 준비했다 git add 했지만 절대 커밋하지 않았습니다. 이제 내 변경 사항이 사라졌습니다!

복구하기에는 약간 까다 롭습니다. git 에는 추가 한 파일의 복사본이 있지만 이러한 복사본은 특정 커밋과 연결되어 있지 않으므로 변경 내용을 한 번에 모두 복원 할 수 없습니다. 대신, git의 데이터베이스에서 개별 파일을 찾아 수동으로 복원해야합니다. 당신은 이것을 사용하여 이것을 할 수 있습니다git fsck .

이에 대한 자세한 내용 은 준비 영역에서 커밋되지 않은 파일로 git reset --hard 실행 취소를 참조하십시오 .

작업 디렉토리에서 파일을 변경 한 적이 없었 git add으며 절대로 커밋하지 않았습니다. 이제 내 변경 사항이 사라졌습니다!

어 오. 나는 당신에게 이것을 말하고 싶지 않지만 아마도 운이 좋지 않을 것입니다. 자식은 추가하거나 커밋하고 따라하지 않는 것이 변경 저장하지 않습니다 에 대한 문서를git reset :

--단단한

색인 및 작업 트리를 재설정합니다. 작업 트리에서 추적 된 파일에 대한 모든 변경 내용 <commit>은 삭제됩니다.

그것은 당신이있을 가능성이 있습니다 디스크 복구 유틸리티 또는 전문 데이터 복구 서비스의 일종으로 변경 사항을 복구 할 수 있지만, 아마도 그것의 가치보다 더 많은 문제가있어이 시점에서.


1
한 명의 라이너가 저를 위해 일했습니다. 감사합니다.하지만 "@ {1}"이 정확히 무엇을하는지 궁금합니다.
Stan Bashtavenko

1
@StanB 문서는 여기에 있습니다 : git-scm.com/docs/git-rev-parse는 기본적으로 현재 브랜치의 첫 번째 reflog 항목을 나타냅니다.
Ajedi32

모든 사건을 다루어 주셔서 감사합니다. 나는 내 것을 저 지르거나 추가하지 않았다.
xdhmoore

21

당신이 경우 아직 쓰레기 (사용 예를 들어 저장소를 수집 git repack -d하거나 git gc,하지만 가비지 컬렉션도 자동으로 발생할 수 있습니다), 다음 여전히 커밋 -는 HEAD를 통해 단지 더 이상 연결할 수 없습니다.

의 출력을 통해 커밋을 찾을 수 있습니다 git fsck --lost-found.

Git의 최신 버전에는 "reflog"라는 것이 있는데, 이는 저장소 내용에 대한 변경과는 대조적으로 참조에 대한 모든 변경 사항의 로그입니다. 따라서 예를 들어 HEAD를 전환 할 때마다 (즉, git checkout분기를 전환 할 때마다 ) 기록됩니다. 물론 git resetHEAD도 조작 했으므로 기록되었습니다. 과 같은 @기호를 사용하여 리포지토리의 이전 상태에 액세스 할 수있는 것과 유사한 방식으로 이전 참조 상태에 액세스 할 수 있습니다.~git reset HEAD@{1} .

HEAD @ {1}과 HEAD ~ 1의 차이점을 이해하는 데 시간이 걸렸으므로 여기에 약간의 설명이 있습니다.

git init
git commit --allow-empty -mOne
git commit --allow-empty -mTwo
git checkout -b anotherbranch
git commit --allow-empty -mThree
git checkout master # This changes the HEAD, but not the repository contents
git show HEAD~1 # => One
git show HEAD@{1} # => Three
git reflog

따라서 HEAD~1"HEAD가 현재 가리키는 커밋 전에 커밋으로 이동"을 의미하지만HEAD@{1} 이동" 의미하고 커밋하기 전에 HEAD가 가리키는 커밋으로 이동" 의미합니다.

그러면 쉽게 커밋 된 커밋을 찾아서 복구 할 수 있습니다.


2
HEAD ~ 1은 "HEAD의 부모"로, HEAD @ {1}은 "HEAD의 역사에서 한 걸음 뒤로"를 의미합니다.
kizzx2

1
문제는 "역사"라는 용어가 실제로 VCS에 과부하되어 있다는 것입니다. 또 다른 표현 방법은 ~는 커밋 히스토리 에서 뒤로 가고, @는 시간순 또는 시간 히스토리 에서 뒤로 간다는 것입니다 . 그러나 세 버전 중 어느 것도 특히 좋지 않습니다.
Jörg W Mittag

@ kizzx2 (그리고 요 르그) 실제로 함께 많은 도움을 촬영하는 3 설명 - THX
리처드 르 Mesurier

14

응답하기 전에 이것에 대해 설명하는 배경을 추가해 보겠습니다 HEAD.

First of all what is HEAD?

HEAD단순히 현재 분기의 현재 커밋 (최신)에 대한 참조입니다. 주어진 시간에
하나만있을 수 있습니다 HEAD. (을 제외한git worktree )

내용은 HEAD내부에 저장 .git/HEAD되며 현재 커밋의 40 바이트 SHA-1을 포함합니다.


detached HEAD

최근 커밋-의미에 있지 않은 경우 HEAD기록에서 이전 커밋을 가리키고 detached HEAD있습니다.

여기에 이미지 설명을 입력하십시오

명령 행에서 분기 이름 대신 다음과 같이 표시됩니다 HEAD. 현재 분기의 끝을 가리 키지 않기 때문 입니다.

여기에 이미지 설명을 입력하십시오


분리 된 HEAD에서 복구하는 방법에 대한 몇 가지 옵션 :


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

원하는 커밋을 가리키는 새 분기를 체크 아웃합니다.
이 명령은 주어진 커밋을 체크 아웃합니다.
이제 지점을 만들고이 지점부터 작업을 시작할 수 있습니다.

# Checkout a given commit. 
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

당신은 항상 사용할 수 있습니다 reflog.
git reflog변경 사항을 표시 HEAD하고 원하는 참조 로그 항목을 체크 아웃하면 HEAD이 커밋으로 다시 설정됩니다 .

HEAD가 수정 될 때마다 reflog

git reflog
git checkout HEAD@{...}

원하는 커밋으로 돌아갑니다.

여기에 이미지 설명을 입력하십시오


git reset HEAD --hard <commit_id>

머리를 원하는 커밋으로 "이동"하십시오.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.
  • 참고 : ( Git 2.7 이후 )
    도 사용할 수 있습니다 git rebase --no-autostash.


git revert <sha-1>

지정된 커밋 또는 커밋 범위를 "실행 취소"합니다.
reset 명령은 지정된 커밋에서 변경 한 내용을 "실행 취소"합니다.
실행 취소 패치가 포함 된 새 커밋이 커밋되고 원래 커밋도 기록에 남아 있습니다.

# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>

이 스키마는 어떤 명령이 무엇을 수행하는지 보여줍니다.
보시다시피을 reset && checkout수정하십시오 HEAD.

여기에 이미지 설명을 입력하십시오


git reset HEAD --hard <commit_id>예제가 stackoverflow.com/questions/4114095/… 에서 가져온 것으로 보입니다 .-이 경우 속성을 편집 해 주시겠습니까?
Rob

12

git reflog

  • 목록에서 커밋 sha를 찾은 다음 복사하여 다음 명령에 붙여 넣습니다.

git cherry-pick <the sha>


1
git-cherry-pick-기존 커밋이 도입 한 변경 사항을 적용합니다. 이 상황에서 간단하고 매우 도움이된다고 생각합니다
Amitesh

1
모든 사람들은 하드 리셋 변경을 취소하는 방법을 검색 할 때 실제로 이것을 찾고 있습니다. 이 답변은 더 인기를 얻을 것입니다
ErenL

@ ErenL 나는 방금 생각한 것 같아 사람들은 추가 작업을하는 것을 좋아합니다. haha
ScottyBlades

1
이게 다야 내
방을 구했다

11

나는 이것이 오래된 스레드라는 것을 알고 있습니다 ...하지만 많은 사람들이 Git에서 물건을 취소하는 방법을 찾고 있기 때문에 계속 여기에 팁을주는 것이 좋습니다.

"git add"를 수행하거나 git gui에서 왼쪽 상단에서 왼쪽 하단으로 무언가를 이동하면 파일의 내용이 Blob에 저장되고 파일 내용이 해당 Blob에서 복구 될 수 있습니다.

따라서 파일이 커밋되지 않았지만 추가 된 경우에도 파일을 복구 할 수 있습니다.

git init  
echo hello >> test.txt  
git add test.txt  

이제 Blob이 생성되지만 인덱스에서 참조되므로 재설정 할 때까지 git fsck와 함께 나열되지 않습니다. 그래서 우리는 재설정합니다 ...

git reset --hard  
git fsck  

매달린 물방울 모양을 얻을 수 있습니다 .013013030ba8dba906f756967f9e9ca394464a

git show ce01362  

파일 내용을 "hello"로 돌려줍니다.

참조되지 않은 커밋을 찾으려면 이것을 제안하는 팁을 찾았습니다.

gitk --all $(git log -g --pretty=format:%h)  

나는 git gui의 도구로 가지고 있으며 매우 편리합니다.


+1. stackoverflow.com/a/21350689/6309 에서 언급했듯이 git fsck --lost-found도움이 될 수 있습니다.
VonC

7

JetBrains IDE (IntelliJ 기반)를 사용하는 경우 "로컬 히스토리"기능을 통해 커밋되지 않은 변경 사항도 복구 할 수 있습니다.

파일 트리에서 최상위 디렉토리를 마우스 오른쪽 단추로 클릭하고 상황에 맞는 메뉴에서 "로컬 히스토리"를 찾은 다음 "히스토리 표시"를 선택하십시오. 그러면 최근 수정 사항을 찾을 수있는보기가 열리고 돌아 가려는 개정을 찾았 으면 마우스 오른쪽 단추로 클릭하고 "되돌리기"를 클릭하십시오.


4

방금 잘못된 프로젝트에서 하드 재설정을 수행했습니다. 내 목숨을 구한 것은 Eclipse의 현지 역사였습니다. IntelliJ Idea에는 하나도 있다고 말하며 편집자도 확인할 가치가 있습니다.

  1. 로컬 히스토리에 대한 Eclipse 도움말 주제
  2. http://wiki.eclipse.org/FAQ_Where_is_the_workspace_local_history_stored%3F

1
Jetbrains CLion 지역의 역사는 훌륭하고 나를 위해 2 시간 일을 절약했습니다 :)
Fabian Knapp

3

찾고있는 커밋을 쉽게 찾을 수 있도록 작은 스크립트를 만들었습니다.

git fsck --lost-found | grep commit | cut -d ' ' -f 3 | xargs -i git show \{\} | egrep '^commit |Date:'

예, awk 또는 이와 유사한 것으로 훨씬 더 예쁘게 만들 수는 있지만 간단하고 방금 필요했습니다. 30 초 동안 다른 사람을 구할 수 있습니다.


0

내 문제는 거의 비슷합니다. 입력하기 전에 커밋되지 않은 파일이 있습니다 git reset --hard.

고맙게도 나는이 모든 자원을 건너 뛰었다. 실행 취소 할 수 있음을 알게 된 후 ( ctrl-z). 😊 위의 모든 답변에 이것을 추가하고 싶습니다.

노트. ctrl-z파일을 열 수 없습니다 .


0

이것은 나의 생명을 구했습니다 : https://medium.com/@CarrieGuss/how-to-recover-from-a-git-hard-reset-b830b5e3f60c

기본적으로 다음을 실행해야합니다.

for blob in $(git fsck --lost-found | awk ‘$2 == “blob” { print $3 }’); do git cat-file -p $blob > $blob.txt; done

그런 다음 수동으로 어려움을 겪고 파일을 올바른 구조로 재구성하십시오.

테이크 아웃 : git reset --hard100 % 작동 방식을 완전히 이해하지 못하면 사용하지 않는 것이 좋습니다.

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