평범한 영어로 "git reset"은 무엇을 하는가?


674

에 대한 미묘함을 설명하는 흥미로운 게시물 을 보았습니다 git reset.

불행히도, 내가 그것에 대해 더 많이 읽을수록 나는 그것을 완전히 이해하지 못하는 것처럼 보입니다. 나는 SVN 배경에서 왔으며 Git은 완전히 새로운 패러다임입니다. 나는 수은을 쉽게 얻었지만 Git은 훨씬 더 기술적입니다.

git reset에 가깝다고 생각 hg revert하지만 차이점이있는 것 같습니다.

정확히 무엇을 git reset합니까? 다음에 대한 자세한 설명을 포함하십시오 :

  • 옵션 --hard, --soft--merge;
  • 당신이 사용하는 이상한 표기 HEADHEAD^HEAD~1;
  • 구체적인 사용 사례 및 작업 흐름;
  • 실무 카피 HEAD및 글로벌 스트레스 수준 에 미치는 영향 .

17
Visual Git Reference 는 일반적인 git 명령을 사용할 때 발생하는 일에 대한 통찰력을 제공 한다고 생각 합니다.

답변:


992

일반적으로 git reset의 기능은 현재 분기를 가져 와서 다른 곳을 가리 키도록 재설정하고 색인 및 작업 트리를 가져올 수 있습니다. 보다 구체적으로, 마스터 분기 (현재 체크 아웃 된)가 다음과 같은 경우 :

- A - B - C (HEAD, master)

그리고 마스터가 C가 아닌 B를 가리 키기를 원한다는 것을 깨달았 git reset B습니다.

- A - B (HEAD, master)      # - C is still here, but there's no branch pointing to it anymore

Digression : 체크 아웃과 다릅니다. 당신이 실행한다면 git checkout B, 당신은 이것을 얻을 것입니다 :

- A - B (HEAD) - C (master)

HEAD 상태가 분리되었습니다. HEAD, 작업 트리, 색인이 모두 일치 B하지만 마스터 지점은에 남아 있습니다 C. D이 시점에서 새로운 커밋 을 수행하면 원하는 것을 얻지 못할 것입니다.

- A - B - C (master)
       \
        D (HEAD)

reset은 커밋을하지 않으며 단지 다른 커밋을 가리 키도록 분기 (커밋에 대한 포인터)를 업데이트합니다. 나머지는 색인 및 작업 트리에 어떤 일이 발생하는지에 대한 세부 정보입니다.

사용 사례

git reset다음 섹션의 다양한 옵션에 대한 설명 내에서 많은 주요 사용 사례를 다룹니다. 그것은 실제로 다양한 것들에 사용될 수 있습니다. 일반적인 스레드는 그들 모두가 주어진 커밋을 가리 키거나 일치하도록 분기, 인덱스 및 / 또는 작업 트리를 재설정하는 것입니다.

조심해야 할 것들

  • --hard정말 직장을 잃을 수 있습니다. 작업 트리를 수정합니다.

  • git reset [options] commit커밋을 잃을 수 있습니다. 위의 장난감 예제에서 commit을 잃었습니다 C. 그것은 REPO에 아직, 당신은보고 찾을 수 있습니다 git reflog show HEAD또는 git reflog show master, 그러나 더 이상 실제로 어떤 지점에서 액세스 할 수 없습니다.

  • Git은 30 일 후에 그러한 커밋을 영구적으로 삭제하지만, 그때까지 C에 지점을 다시 지정하여 C를 복구 할 수 있습니다 ( git checkout C; git branch <new branch name>).

인수

매뉴얼 페이지를 설명하면, 가장 일반적인 사용법은 git reset [<commit>] [paths...]지정된 커밋에서 주어진 경로를 상태로 재설정하는 형식 입니다. 경로가 제공되지 않으면 전체 트리가 재설정되고 커밋이 제공되지 않으면 HEAD (현재 커밋)로 간주됩니다. 이것은 git 명령에서 공통적 인 패턴입니다 (예 : 정확한 의미론은 다르지만 체크 아웃, diff, log). 그리 놀라운 일이 아닙니다.

예를 들어 git reset other-branch path/to/foopath / to / foo의 모든 항목을 other-branch의 상태로 git reset -- .재설정하고, 현재 디렉토리를 HEAD의 상태로 git reset재설정 하고, 단순하게 모든 항목을 HEAD의 상태로 재설정합니다.

기본 작업 트리 및 색인 옵션

재설정하는 동안 작업 트리 및 색인에 발생하는 상황을 제어하는 ​​네 가지 주요 옵션이 있습니다.

인덱스는 git의 "스테이징 영역"이라는 점을 기억하십시오 git add. 커밋 준비를 할 때 상황이 발생합니다 .

  • --hard재설정 한 커밋과 모두 일치합니다. 아마도 가장 이해하기 쉬울 것입니다. 모든 로컬 변경 사항이 지워집니다. 하나 개의 기본 사용은 당신의 일을 멀리 불고 있지만 커밋 전환되지 않습니다 git reset --hard수단 git reset --hard HEAD, 즉 분기를 변경하지 않지만 모든 로컬 변경 사항을 제거. 다른 하나는 단순히 한 지점에서 다른 지점으로 지점을 이동하고 색인 / 작업 트리를 동기화 된 상태로 유지하는 것입니다. 이것은 작업 트리를 수정하기 때문에 실제로 작업을 잃을 수있는 것입니다. 당신이 실행하기 전에 로컬 작업을 버리고 싶어 매우 확신합니다 reset --hard.

  • --mixed기본, 즉이다 git reset수단 git reset --mixed. 작업 트리가 아닌 색인을 재설정합니다. 이것은 모든 파일이 손상되지 않았 음을 의미하지만 원래 커밋과 재설정 한 커밋 간의 차이점은 git 상태의 로컬 수정 (또는 추적되지 않은 파일)으로 표시됩니다. 잘못된 커밋을했다는 것을 알았지 만 수행 한 모든 작업을 유지하여 문제를 해결하고 다시 커밋 할 수 있도록하려는 경우에 사용하십시오. 커밋하려면 인덱스에 파일을 다시 추가해야합니다 ( git add ...).

  • --soft색인 또는 작업 트리를 건드리지 않습니다 . 모든 파일은에서와 동일 --mixed하지만 모든 변경 사항은 changes to be committedgit 상태와 같이 표시됩니다 (예 : 커밋 준비로 체크인 됨). 커밋이 잘못되었다는 것을 알았을 때 이것을 사용하십시오.하지만 작업이 모두 훌륭합니다.해야 할 일은 다르게 다시 커밋하는 것입니다. 인덱스는 변경되지 않으므로 원하는 경우 즉시 커밋 할 수 있습니다. 결과 커밋은 재설정하기 전의 위치와 동일한 내용을 갖습니다.

  • --merge최근에 추가되었으며 실패한 병합을 중단하는 데 도움이됩니다. 이는 git merge수정이 병합의 영향을받지 않는 파일에있는 한 더티 작업 트리 (로컬 수정이있는 하나)와의 병합을 실제로 시도 할 수 있기 때문에 필요 합니다. git reset --merge색인을 재설정 (예 --mixed: 모든 변경 사항이 로컬 수정으로 표시됨)하고 병합의 영향을받는 파일을 재설정하지만 나머지는 그대로 둡니다. 이렇게하면 병합이 잘못되기 전의 상태로 모든 것을 복원 할 수 있습니다. 일반적으로 분기를 이동하지 않고 병합을 재설정하기 만하 기 때문에 일반적으로 git reset --merge(의미 git reset --merge HEAD) 로 사용합니다 . ( HEAD병합이 실패하여 아직 업데이트되지 않았습니다)

    보다 구체적으로, 파일 A와 B를 수정하고 파일 C와 D를 수정 한 분기에서 병합하려고한다고 가정합니다. 어떤 이유로 병합이 실패하고 중단하기로 결정합니다. 사용 git reset --merge합니다. C와 D를 원래 상태로 되돌려 HEAD주지만 병합 시도의 일부가 아니기 때문에 수정 사항을 A와 B에만 남겨 둡니다.

더 알고 싶습니까?

나는 이것이 이것 man git reset에 정말로 좋다고 생각합니다. 아마도 git이 실제로 싱크하는 데 약간의 감각이 필요할 것입니다. 특히, 파일을주의 깊게 읽는 데 시간이 걸리면 모든 다양한 옵션 및 사례에 대한 색인 및 작업 트리의 파일 상태를 자세히 설명하는 테이블이 매우 유용합니다. (그러나 그들은 매우 조밀합니다. 위의 많은 정보를 매우 간결한 형태로 전달하고 있습니다.)

이상한 표기법

언급 한 "이상한 표기법"( HEAD^HEAD~1)은과 같은 해시 이름을 사용할 필요없이 커밋을 지정하기위한 축약 형입니다 3ebe3f6. 그것은 완전히에 문서화 "지정 수정"섹션 예제 및 관련 구문의 많은, 자식-REV-구문 분석에 대한 매뉴얼 페이지. 캐럿과 물결표는 실제로 다른 것을 의미합니다 .

  • HEAD~HEAD~1커밋의 첫 번째 부모의 약자 이며 의미합니다. HEAD~2커밋의 첫 번째 부모의 첫 번째 부모를 의미합니다. HEAD~n"HEAD보다 먼저 커밋"또는 "HEAD의 n 세대 조상"으로 생각하십시오 .
  • HEAD^(또는 HEAD^1)는 커밋의 첫 번째 부모를 의미합니다. HEAD^2커밋의 두 번째 부모를 의미합니다 . 일반적인 병합 커밋에는 두 개의 부모가 있습니다. 첫 번째 부모는 병합 된 커밋이고 두 번째 부모는 병합 된 커밋입니다. 일반적으로 병합은 실제로 많은 부모를 가질 수 있습니다 (문어 병합).
  • ^~연산자에서와 같이 서로 연결된 수 HEAD~3^2의 3 세대 조상의 제 부모 HEAD, HEAD^^2상기 제 부모의 부모 제 HEAD짝수 또는 HEAD^^^동등하다 HEAD~3.

캐럿과 물결표


"git reset을 사용하여 그곳으로 이동합니다." 왜 git checkout을 사용하지 않습니까?
e-satis

5
@ e-satis : git checkout은 HEAD를 움직이지만 지점은 그대로 둡니다. 분기를 이동하려는 경우에 사용됩니다.
Cascabel

따라서 내가 잘 이해하면 재설정 B는 다음을 수행합니다.-A-B-C-B (마스터) 체크 아웃 B는-A-B (마스터)?
e-satis

32
문서를 읽는 데 시간이 오래 걸리고 매우 조밀하며 문서의 작동 방식을 이미 알고있는 것처럼 작동하는지 확인하려면 시간이 오래 걸립니다. 워드 프로세서 같은 소리하지 않습니다 ... 나에게 좋은
커비

4
훨씬 간단하고 이해할 수있는 설명이 SO 응답에 의해 주어진다 : stackoverflow.com/questions/3528245/whats-the-difference-between-git-reset-mixed-soft-and-hard
니틴 반살

80

git당신이 가지고 있음을 기억하십시오 :

  • 작업중인 커밋을 알려주 는 HEAD포인터
  • 작업 트리 시스템에있는 파일의 상태를 나타냅니다,
  • 준비 영역 (또한 불리는 인덱스 가 나중에 함께 헌신 할 수 있도록 변경 "단계"),

다음에 대한 자세한 설명을 포함하십시오 :

--hard, --soft--merge;

위험성이 증가하는 순서로 :

  • --soft움직 HEAD이지만 준비 영역이나 작업 트리를 건드리지 않습니다.
  • --mixedHEAD준비 영역을 이동 하고 업데이트하지만 작업 트리는 업데이트하지 않습니다.
  • --merge이동 HEAD, 준비 영역을 재설정하고 작업 트리의 모든 변경 사항을 새 작업 트리로 이동합니다.
  • --hard스테이징 영역과 작업 트리를 새로운 것으로 이동 HEAD 하고 조정하여 HEAD모든 것을 버립니다.

구체적인 사용 사례 및 워크 플로우;

  • --soft다른 장소로 옮기고 "장소를 잃지 않고"패치하고 싶을 때 사용하십시오 . 이것이 필요한 경우는 매우 드 rare니다.

-

# git reset --soft example
touch foo                            // Add a file, make some changes.
git add foo                          // 
git commit -m "bad commit message"   // Commit... D'oh, that was a mistake!
git reset --soft HEAD^               // Go back one commit and fix things.
git commit -m "good commit"          // There, now it's right.

-

  • 사용 --mixed커밋 무슨 일이 다른에서 같이보고 싶은,하지만 당신은 당신이 이미 가지고있는 모든 변경 사항을 잃고 싶지 않을 때 (기본값).

  • --merge새 지점으로 이동하고 있지만 이미 변경 사항을 작업 트리에 통합하려는 경우에 사용하십시오 .

  • --hard새로운 커밋에서 모든 것을 지우고 새로운 슬레이트를 시작하는 데 사용하십시오 .


2
의 의도 된 사용 사례가 아닙니다 reset --merge. 3 방향 병합을 수행하지 않습니다. 문서에 설명 된 것처럼 실제로 충돌 병합을 재설정하기위한 것입니다. 당신 checkout --merge이 말하는 것을하는 데 사용하고 싶을 것 입니다. 지점을 이동하려는 경우 유일한 방법은 체크 아웃 / 재설정을 수행하여 지점을 드래그하는 것입니다.
Cascabel

@Jefromi»그렇습니다, 나는 그것을 아주 잘 말하지 않았습니다. "새로운 지점"이란 말은 "충돌 된 병합이없는 신선한 곳"을 의미했습니다.
John Feminella

1
아, 알겠습니다 여기서 중요한 것은 실제로 수행중인 작업을 알지 않는 한 reset --merge(기본값) 이외의 대상과 함께 사용하고 싶지 않을 것입니다 HEAD. 충돌 된 병합을 중단하는 것 외에는 버릴 수 있기 때문입니다. 그렇지 않으면 저장할 수있는 정보.
Cascabel

2
나는이 대답은 간단하고 가장 도움이 발견
Jazzepi

다음 명령에 대한 정보를 추가하십시오 : git resetgit reset -- ..
Flimm

35

포스트 신비성을 재설정 블로그에 프로 힘내 아주 제공 낙승 에 대한 설명을 git reset하고 git checkout.

해당 게시물 상단에서 도움이되는 모든 토론이 끝나면 저자는 규칙을 다음과 같은 간단한 3 단계로 줄입니다.

그것은 기본적으로입니다. 이 reset명령은이 세 트리를 특정 순서대로 덮어 쓰고 지시하면 중지합니다.

  1. HEAD가 가리키는 분기를 이동하십시오 (있는 경우 중지 --soft).
  2. 그런 다음 색인을 다음과 같이 보이게하십시오 (여기서는 중지 --hard).
  3. 그런 다음 작업 디렉토리를 이렇게 보이게하십시오.

옵션 --merge--keep옵션 도 있지만 지금은 더 간단하게 유지하고 싶습니다. 다른 기사 에서도 마찬가지 입니다.


25

git에 무언가를 커밋하면 먼저 변경 사항을 준비해야합니다 (색인에 추가). 이것은 git이 커밋의 일부로 간주하기 전에이 커밋에 포함하려는 모든 파일을 git add해야한다는 것을 의미합니다. 먼저 git repo의 이미지를 살펴 보겠습니다. 여기에 이미지 설명을 입력하십시오

이제 간단합니다. 우리는 작업 디렉토리에서 작업하여 파일, 디렉토리 및 모두를 만들어야합니다. 이러한 변경 사항은 추적되지 않은 변경 사항입니다. 추적하려면 git add 명령 을 사용하여 git index에 추가해야합니다 . git index에 추가되면 git 저장소로 변경하려면이 변경 사항을 커밋 할 수 있습니다.

그러나 갑자기 인덱스에 추가 한 파일이 하나 더 필요하다는 것을 커밋하면서 알았습니다 .git 저장소를 푸시 할 필요는 없습니다. 그것은 우리가 그 파일을 색인에 원하지 않는 것을 의미합니다. 이제 질문은 git index에서 해당 파일을 제거하는 방법입니다 .git add 를 사용하여 파일을 색인 에 넣었 으므로 git rm 을 사용하는 것이 논리적입니다 . 잘못된! git rm 은 단순히 파일을 삭제하고 인덱스에 삭제를 추가합니다. 이제해야 할 일 :

사용하다:-

자식 재설정

색인을 지우고 작업 디렉토리를 그대로 둡니다. (간단히 모든 것을 언 스테이징).

여러 옵션과 함께 사용할 수 있습니다. git reset 과 함께 사용하는 세 가지 주요 옵션 인 --hard, --soft 및 --mixed가 있습니다. 이는 재설정 할 때 HEAD 포인터 외에 재설정 대상에 영향을줍니다.

첫째, --hard 재설정 모든 것을. 현재 디렉토리는 그 지점을 따라 온 경우와 똑같습니다. 작업 디렉토리와 색인이 해당 커밋으로 변경됩니다. 이것은 내가 가장 자주 사용하는 버전입니다. git reset --hardsvn revert 와 같습니다 .

다음으로 완전한 반대쪽 인 --soft 는 작업 트리 나 인덱스를 재설정하지 않습니다. HEAD 포인터 만 이동합니다. 이렇게하면 현재 상태는 디렉토리에서 전환하려는 커밋과 다른 변경 사항이 적용되고 커밋을위한 "스테이징"됩니다. 커밋을 로컬로 만들지 만 커밋을 git 서버로 푸시하지 않은 경우 이전 커밋으로 재설정하고 좋은 커밋 메시지로 다시 커밋 할 수 있습니다.

마지막으로 --mixed 는 인덱스를 재설정하지만 작업 트리는 재설정하지 않습니다. 따라서 변경 사항은 모두 여전히 존재하지만 "스테이지되지 않은"상태이므로 git add'ed 또는 git commit -a 이어야 합니다. 우리는 때때로 git commit -a보다 의도 한 것보다 많은 것을 커밋하면 이것을 사용합니다 .git reset --mixed로 커밋을 취소하고 커밋하려는 것을 추가하고 커밋 할 수 있습니다.

git revert와 git reset의 차이점 :-


간단히 말해서, git reset"수정되지 않은 실수 수정" 명령 이고 git revert"수정 된 실수 수정" 명령 입니다.

그것은 우리가 어떤 변화에서 약간의 실수를 저지르고 그것을 커밋하고 git repo에 푸시했다면, git revert 가 해결책입니다. 푸시 / 커밋하기 전에 동일한 오류를 식별 한 경우 git reset 을 사용하여 문제를 해결할 수 있습니다 .

혼란을 없애는 데 도움이되기를 바랍니다.


2
이것은 OP가 요청한 멋진 영어 답변입니다.
Episodex

1
비록 당신의 대답에서 그것을 놓칠 수도 있습니다. git reset HEAD기본적으로 무엇입니까 ? --hard, --soft또는 --mixed? 큰 대답 btw.
giannis christofakis

1
좋은 대답이지만 git reset --hard데이터를 잃어 버릴 수 있음을 분명히 합니다. 그리고 틀릴 수있는 요점이 있습니다 (100 % 확실하지는 않지만 ... 여전히 배우고 있습니다!) : --mixed"우리는 때때로 우리가 git commit -a보다 더 많은 것을 커밋하면 이것을 사용합니다." "우리 가 생각했던 것보다 더 많은 무대를 준비 했다면"을 의미 했습니까 git stage .? 정말로 커밋했다면 너무 늦었다 고 생각합니다 (결국 git reset은 커밋되지 않은 실수를 수정하는 명령입니다)
Fabio는 Reinstate Monica라고

6

TL; DR

git reset스테이징을 마지막 커밋으로 재설정합니다. --hard작업 디렉토리의 파일을 마지막 커밋으로 재설정하는 데에도 사용하십시오 .

더 긴 버전

그러나 그것은 명백히 단순하기 때문에 많은 장황한 답변입니다. git reset변경 사항을 취소하는 맥락에서 읽는 것이 더 합리적이었습니다 . 예를 들면 다음과 같습니다.

git revert가 변경을 취소하는 "안전한"방법 인 경우 git reset을 위험한 방법으로 생각할 수 있습니다. git reset으로 실행을 취소하고 커밋이 더 이상 참조 또는 참조 로그에 의해 참조되지 않는 경우 원래 사본을 검색 할 방법이 없습니다. 이는 영구 실행 취소입니다. 이 도구는 작업을 잃을 수있는 유일한 Git 명령 중 하나이므로이 도구를 사용할 때는주의해야합니다.

에서 https://www.atlassian.com/git/tutorials/undoing-changes/git-reset

커밋 수준에서 재설정은 분기의 끝을 다른 커밋으로 이동하는 방법입니다. 현재 브랜치에서 커밋을 제거하는 데 사용할 수 있습니다.

에서 https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/commit-level-operations


2

이 복잡한 기능을 이해하기위한 첫 번째 단계로 단순화 된 설명입니다.

다음 각 명령 후에 프로젝트 상태를 시각화하려는 시각 학습자에게 도움이 될 수 있습니다.


색상을 켠 상태에서 터미널을 사용하는 사용자 (git config --global color.ui auto) :

git reset --soft A 그리고 당신은 B와 C의 물건을 녹색으로 볼 것입니다 (단계적이며 커밋 준비가되었습니다)

git reset --mixed A(또는 git reset A) B와 C의 내용이 빨간색으로 표시됩니다 (미 준비 및 준비 (녹색) 및 커밋 준비 완료).

git reset --hard A 더 이상 어디에도 B와 C의 변화가 보이지 않을 것입니다.


또는 'Tower'또는 'SourceTree'와 같은 GUI 프로그램을 사용하는 사람들

git reset --soft A '준비된 파일'영역에서 B와 C의 내용을 커밋 할 준비가 된 것을 볼 수 있습니다.

git reset --mixed A(또는 git reset A) '스테이지되지 않은 파일'영역에서 B 및 C의 항목을 스테이지로 이동 한 다음 커밋 할 수 있습니다.

git reset --hard A 더 이상 어디에도 B와 C의 변화가 보이지 않을 것입니다.


1

Checkout은 특정 커밋에서 헤드를 가리 킵니다.

재설정은 특정 커밋에서 분기를 가리 킵니다. 분기는 커밋에 대한 포인터입니다.

또한, 헤드가 브랜치가 가리키는 커밋을 가리 키지 않으면 헤드가 분리 된 것입니다. (잘못된 것으로 판명되었습니다. 의견을 참조하십시오 ...)


1
아니 nitpick에 있지만 (예, 사실 그것은 이다 하찮은 일에 속 태우고 있지만하자의 완료를 위해 추가) 3 번째 문장은 기술적으로 false입니다. HEAD가 abc123 커밋을 가리키는 B 지점을 가리키고 있다고 가정 해 봅시다. commit abc123을 체크 아웃하면 HEAD와 브랜치 B가 모두 abc123을 커밋하고 HEAD가 분리됩니다. 이 시점에서 커밋하면 지점 B의 위치가 업데이트 되지 않습니다 . 당신은 "당신의 머리가 다음 분기 가리 키지 않는 경우 분리 된 머리를"말했다 수
RomainValeri

@RomainValeri 그 상황에서 커밋은 무엇을 할 것인가?
Ian Warburton

1
커밋하면 브랜치에서 참조하지 않는 커밋이 생성되고 브랜치 B는 그 후에 여러 번 커밋 한 후에도 동일한 커밋 abc123을 계속 가리키게됩니다. HEAD가이 '와일드 한'일련의 커밋에서 마지막 커밋을 가리 키지 않을 때 이러한 커밋이 가비지 수집의 후보가됨을 의미합니다.
RomainValeri
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.