git reset
git reset
명령은 변경 사항을 실행 취소하는 데 사용하는 복잡한 다용도 도구입니다. 이 명령에는 세 가지 기본 호출 형식이 있습니다. 이러한 형식은 명령줄 인수 --soft, --mixed, --hard
에 해당하며, 세 인수는 각각 Git의 3가지 내부 상태 관리 메커니즘인 커밋 트리(HEAD
), 스테이징 색인 및 작업 디렉터리에 해당합니다.
Git Reset 및 Git 3개의 트리
git reset
사용법을 제대로 파악하려면 먼저 Git의 내부 상태 관리 시스템을 이해해야 합니다. 이러한 메커니즘을 Git의 "3개의 트리"라고 부르기도 합니다. 트리는 엄밀히 말하면 전통적인 트리 데이터 구조가 아니기 때문에 잘못된 명칭일 수도 있습니다. 3개의 트리는 Git이 편집 타임라인을 추적하는 데 사용하는 노드 및 포인터 기반 데이터 구조입니다. 이 메커니즘을 보여주는 가장 좋은 방법은 리포지토리에서 변경 집합을 만들고 3개의 트리를 통해 따라가는 것입니다.
시작하기 위해 아래 명령으로 새 리포지토리를 만들어 보겠습니다.
$ mkdir git_reset_test
$ cd git_reset_test/
$ git init .
Initialized empty Git repository in /git_reset_test/.git/
$ touch reset_lifecycle_file
$ git add reset_lifecycle_file
$ git commit -m"initial commit"
[main (root-commit) d386d86] initial commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 reset_lifecycle_file
위의 예시 코드는 하나의 빈 파일인 reset_lifecycle_file
을 사용하여 새로운 Git 리포지토리를 만듭니다. 이때 예시 리포지토리는 reset_lifecycle ycle_file
을 추가하여 단일 커밋(d386d86
)을 가집니다.
관련 자료
Git 치트 시트
솔루션 보기
Bitbucket Cloud에서 Git에 대해 알아보기
작업 디렉터리
가장 먼저 살펴볼 트리는 "작업 디렉터리"입니다. 이 트리는 로컬 파일 시스템과 동기화되며 파일 및 디렉터리의 콘텐츠에 대한 즉각적인 변경 사항을 나타냅니다.
$ echo 'hello git reset' > reset_lifecycle_file
$ git status
On branch main
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: reset_lifecycle_file
데모 리포지토리에서 일부 콘텐츠를 수정하고 reset_lifecycle_file
에 추가합니다. git status
를 호출하면 Git이 파일의 변경 사항을 인식하고 있음을 알 수 있습니다. 이러한 변경 사항은 현재 첫 번째 트리인 "작업 디렉터리"의 일부입니다. git status
는 작업 디렉터리에 대한 변경 사항을 표시하는 데 사용할 수 있습니다. 'modified' 접두사와 함께 빨간색으로 표시됩니다.
스테이징 색인
다음은 '스테이징 색인' 트리입니다. 이 트리는 git add
로 승격된 작업 디렉터리 변경 사항을 추적하여 다음 커밋에 저장합니다. 이 트리는 복잡한 내부 캐싱 메커니즘입니다. Git은 보통 스테이징 색인의 구현 세부 정보를 사용자에게 숨기려고 합니다.
스테이징 색인의 상태를 정확하게 확인하려면 조금 덜 알려진 Git 명령인 git ls-files
를 사용해야 합니다. git ls-files
명령은 기본적으로 스테이징 색인 트리의 상태를 검사하기 위한 디버그 유틸리티입니다.
git ls-files -s
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 reset_lifecycle_file
여기서는 -s
또는 --stage
옵션을 사용하여 git ls-files
를 실행했습니다. -s
옵션이 없으면 git ls-files
출력은 단순히 현재 색인에 포함된 파일 이름과 경로의 목록일 뿐입니다. -s
옵션은 스테이징 색인에 있는 파일에 대한 추가 메타데이터를 표시합니다. 이 메타데이터는 스테이징된 콘텐츠의 모드 비트, 개체 이름 및 스테이지 번호입니다. 여기서 주목해야 할 부분은 두 번째 값인 개체 이름(d7d77c1b04b5edd5acfc85de0b592449e5303770
)입니다. 이것은 표준 Git 개체 SHA-1 해시로, 파일 콘텐츠의 해시입니다. 커밋 기록은 커밋과 참조에 대한 포인터를 식별하기 위한 자체적인 개체 SHA를 저장하며, 스테이징 색인은 색인에 있는 파일 버전을 추적하는 자체적인 개체 SHA가 있습니다.
다음으로 수정된 reset_lifecycle_file
을 스테이징 색인으로 승격시켜 보겠습니다.
$ git add reset_lifecycle_file
$ git status
On branch main Changes to be committed:
(use "git reset HEAD ..." to unstage)
modified: reset_lifecycle_file
여기에서 스테이징 색인에 파일을 추가하는 git add reset_lifecycle_file
을 호출했습니다. 이제 git status
를 호출하면 "커밋할 변경 사항" 아래에 녹색으로 reset_lifecycle_file
이 표시됩니다. 중요한 것은 git status
가 스테이징 색인의 진정한 표현이 아니하는 사실입니다. git status
명령 출력은 커밋 기록과 스테이징 색인 간의 변경 사항을 표시합니다. 이 시점에서 스테이징 색인 콘텐츠를 살펴보겠습니다.
$ git ls-files -s 100644 d7d77c1b04b5edd5acfc85de0b592449e5303770 0 reset_lifecycle_file
reset_lifecycle_file
에 대한 개체 SHA가 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
에서 d7d77c1b04b5edd5acfc85de0b592449e5303770
으로 업데이트되었음을 알 수 있습니다.
커밋 기록
마지막 트리는 커밋 기록입니다. git commit
명령은 커밋 기록에 있는 영구적인 스냅샷에 변경 사항을 추가합니다. 이 스냅샷은 커밋 시점의 스테이징 색인 상태도 포함합니다.
$ git commit -am"update content of reset_lifecycle_file"
[main dc67808] update content of reset_lifecycle_file
1 file changed, 1 insertion(+)
$ git status
On branch main
nothing to commit, working tree clean
여기에서는 "update content of resetlifecyclefile"
메시지가 포함된 새 커밋을 만들었습니다. 변경 집합이 커밋 기록에 추가되었습니다. 이 시점에서 git status
를 호출하면 트리에 보류 중인 변경 사항이 없음을 알 수 있습니다. git log
를 실행하면 커밋 기록이 표시됩니다. 이제 3개의 트리를 통해 이 변경 집합을 따랐으므로 git reset
을 활용할 수 있습니다.
작동 방식
표면적인 수준에서 볼 때 git reset
은 git checkout
과 동작이 비슷합니다. git checkout
이 HEAD
참조 포인터에서만 작동하는 경우, git reset
은 HEAD
참조 포인터 및 현재 브랜치 참조 포인터를 이동시킵니다. 다음 예시를 통해 이러한 동작을 더 자세히 설명해 보겠습니다.
이 예시는 main
브랜치의 커밋 시퀀스를 보여줍니다. HEAD
참조와 main
브랜치 참조는 현재 커밋 d를 가리킵니다. 이제 git checkout b
와 git reset b
를 실행하여 비교해 보겠습니다.
git checkout b
git checkout
의 경우 main
참조는 여전히 d
를 가리키고 있습니다. HEAD
참조가 이동했으며 이제 커밋 b
를 가리킵니다. 리포지토리는 이제 '분리된 HEAD
' 상태입니다.
git reset b
반면 git reset
은 HEAD
및 브랜치 참조를 모두 지정된 커밋으로 이동시킵니다.
참조 포인터를 업데이트하는 것 외에도 git reset
은 3개의 트리 상태를 수정합니다. 참조 포인터 수정은 항상 발생하며 세 번째 트리인 커밋 트리에 대한 업데이트입니다. 명령줄 인수 --soft, --mixed
및 --hard
는 스테이징 색인 및 작업 디렉터리 트리를 수정하는 방법을 지시합니다.
메인 옵션
git reset
의 기본 호출에는 --mixed
및 HEAD
라는 암시적 인수가 있습니다. 즉, git reset
을 실행하는 것은 git reset --mixed HEAD
를 실행하는 것과 같습니다. 이 형식에서 HEAD
는 지정된 커밋입니다. HEAD
대신 Git SHA-1 커밋 해시를 사용할 수 있습니다.
'--hard
가장 직접적이고 위험하며 자주 사용하는 옵션입니다. --hard
를 전달하면 커밋 기록 참조 포인터가 지정된 커밋으로 업데이트됩니다. 그런 다음 스테이징 색인 및 작업 디렉터리가 지정된 커밋과 일치하도록 재설정됩니다. 스테이징 색인 및 작업 디렉터리에 대해 보류 중인 이전의 변경 사항은 커밋 트리 상태와 일치하도록 재설정됩니다. 즉, 스테이징 색인 및 작업 디렉터리에서 보류 중이었던 모든 작업이 손실된다는 것을 의미합니다.
이것을 설명하기 위해 앞서 만든 3개의 트리 예시 리포지토리로 계속해 보겠습니다. 먼저 리포지토리를 약간 수정해 보겠습니다. 예시 리포지토리에서 다음 명령을 실행합니다.
$ echo 'new file content' > new_file
$ git add new_file
$ echo 'changed content' >> reset_lifecycle_file
이러한 명령은 new_file
이라는 새 파일을 만들어 리포지토리에 추가했습니다. 또한 reset_lifecycle_file
콘텐츠가 수정될 것입니다. 이러한 변경 사항을 적용했으니 이제 git status
를 사용하여 리포지토리 상태를 살펴보겠습니다.
$ git status
On branch main
Changes to be committed:
(use "git reset HEAD ..." to unstage)
new file: new_file
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: reset_lifecycle_file
여기에서 스테이징 색인에 파일을 추가하는 git add reset_lifecycle_file
을 호출했습니다. 이제 git status
를 호출하면 "커밋할 변경 사항" 아래에 녹색으로 reset_lifecycle_file
이 표시됩니다. 중요한 것은 git status
가 스테이징 색인의 진정한 표현이 아니하는 사실입니다. git status
명령 출력은 커밋 기록과 스테이징 색인 간의 변경 사항을 표시합니다. 이 시점에서 스테이징 색인 콘텐츠를 살펴보겠습니다.
$ git ls-files -s
100644 8e66654a5477b1bf4765946147c49509a431f963 0 new_file
100644 d7d77c1b04b5edd5acfc85de0b592449e5303770 0 reset_lifecycle_file
new_file
이 색인에 추가된 것을 볼 수 있습니다. reset_lifecycle_file
을 업데이트했지만 스테이징 색인 SHA(d7d77c1b04b5edd5acfc85de0b592449e5303770
)는 그대로 유지됩니다. git add
를 사용하여 이러한 변경 사항을 스테이징 색인으로 승격하지 않았기 때문에 이는 예상된 동작입니다. 이러한 변경 사항은 작업 디렉터리에 있습니다.
이제 git reset --hard
를 실행하고 리포지토리의 새 상태를 살펴보겠습니다.
$ git reset --hard
HEAD is now at dc67808 update content of reset_lifecycle_file
$ git status
On branch main
nothing to commit, working tree clean
$ git ls-files -s
100644 d7d77c1b04b5edd5acfc85de0b592449e5303770 0 reset_lifecycle_file
여기서는 --hard
옵션을 사용하여 "하드 재설정"을 실행했습니다. Git은 HEAD
가 최근 커밋 dc67808
을 가리키고 있다는 출력을 표시합니다. 다음으로 git status
로 리포지토리 상태를 확인합니다. Git은 보류 중인 변경 사항이 없음을 표시합니다. 스테이징 색인의 상태도 살펴보고 new_file
이 추가되기 전의 시점으로 재설정되었는지 확인합니다. reset_lifecycle_file
에 대한 수정 사항과 new-file
추가는 삭제되었습니다. 이 데이터 손실은 되돌릴 수 없으므로 주의해야 합니다.
'--mixed
이것은 기본 작동 모드로 참조 포인터가 업데이트됩니다. 스테이징 색인은 지정된 커밋 상태로 재설정됩니다. 스테이징 색인에서 실행 취소된 모든 변경 사항은 작업 디렉터리로 이동합니다. 계속해 보겠습니다.
$ echo 'new file content' > new_file
$ git add new_file
$ echo 'append content' >> reset_lifecycle_file
$ git add reset_lifecycle_file
$ git status
On branch main
Changes to be committed:
(use "git reset HEAD ..." to unstage)
new file: new_file
modified: reset_lifecycle_file
$ git ls-files -s
100644 8e66654a5477b1bf4765946147c49509a431f963 0 new_file
100644 7ab362db063f9e9426901092c00a3394b4bec53d 0 reset_lifecycle_file
위의 예시에서는 리포지토리를 일부 수정했습니다. 다시 말하자면, new_file
을 추가하고 reset_lifecycle_file
콘텐츠를 수정했습니다. 그런 다음 git add
를 사용하여 이러한 변경 사항을 스테이징 색인에 적용했습니다. 이 상태의 리포지토리에서 이제 재설정을 실행합니다.
$ git reset --mixed
$ git status
On branch main
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: reset_lifecycle_file
Untracked files:
(use "git add ..." to include in what will be committed)
new_file
no changes added to commit (use "git add" and/or "git commit -a")
$ git ls-files -s
100644 d7d77c1b04b5edd5acfc85de0b592449e5303770 0 reset_lifecycle_file
여기에서는 "혼합 재설정"을 실행했습니다. 다시 말하자면, --mixed
는 기본 모드이며 git reset
을 실행하는 것과 동일한 효과가 있습니다. git status
및 git ls-files
출력을 살펴보면 reset_lifecycle_file
이 색인에서 유일한 파일인 상태로 스테이징 색인이 재설정되었음을 알 수 있습니다. reset_lifecycle_file
에 대한 개체 SHA가 이전 버전으로 재설정되었습니다.
여기서 주목해야 할 중요한 점은 git status
가 reset_lifecycle_file
에 수정 사항이 있었으며 추적되지 않은 파일인 new_file
이 있음을 알려준다는 것입니다. 이것은 명시적인 --mixed
동작입니다. 스테이징 색인이 재설정되었고 보류 중인 변경 사항이 작업 디렉터리로 이동했습니다. 스테이징 색인이 재설정되고 작업 디렉터리도 재설정되어 업데이트가 손실된 --hard
재설정 사례와 비교해 보세요.
'--soft
--soft
인수가 전달되면 참조 포인터가 업데이트되고 재설정이 중지됩니다. 스테이징 색인 및 작업 디렉터리는 그대로 유지됩니다. 이 동작은 명확하게 보여주기 어려울 수 있습니다. 데모 리포지토리로 계속하여 소프트 재설정 준비를 해보겠습니다.
$ git add reset_lifecycle_file
$ git ls-files -s
100644 67cc52710639e5da6b515416fd779d0741e3762e 0 reset_lifecycle_file
$ git status
On branch main
Changes to be committed:
(use "git reset HEAD ..." to unstage)
modified: reset_lifecycle_file
Untracked files:
(use "git add ..." to include in what will be committed)
new_file
여기서는 다시 git add
를 사용하여 수정된 reset_lifecycle_file
을 스테이징 색인으로 승격시켰습니다. git ls-files
출력으로 색인이 업데이트되었음을 확인합니다. 이제 git status
출력에 "커밋할 변경 사항"이 녹색으로 표시됩니다. 이전 예시의 new_file
은 작업 디렉터리에서 추적되지 않은 파일로 남아 있습니다. 다음 예시에서는 필요하지 않으므로 rm new_file
을 빠르게 실행하여 파일을 삭제해 보겠습니다.
이 상태의 리포지토리에서 이제 소프트 재설정을 실행합니다.
$ git reset --soft
$ git status
On branch main
Changes to be committed:
(use "git reset HEAD ..." to unstage)
modified: reset_lifecycle_file
$ git ls-files -s
100644 67cc52710639e5da6b515416fd779d0741e3762e 0 reset_lifecycle_file
'소프트 재설정'을 실행했습니다. git status
및 git ls-file
로 리포지토리 상태를 살펴보면 아무것도 변경되지 않았음을 알 수 있습니다. 이것은 예상된 동작입니다. 소프트 재설정은 커밋 기록만 재설정합니다. 기본적으로 git reset
은 HEAD
를 대상 커밋으로 하여 호출됩니다. 커밋 기록이 이미 HEAD
에 있었고 암시적으로 HEAD
로 재설정했기 때문에 아무 일도 일어나지 않았습니다.
--soft
를 더 잘 이해하고 활용하려면 HEAD
가 아닌 대상 커밋이 필요합니다. 스테이징 색인에 대기 중인 reset_lifecycle ycle_file
이 있습니다. 새 커밋을 만들어 보겠습니다.
$ git commit -m"prepend content to reset_lifecycle_file"
이 시점에서는 리포지토리에 커밋이 3개 있어야 합니다. 이제 첫 번째 커밋으로 시간을 거슬러 올라가겠습니다. 이를 수행하려면 첫 번째 커밋의 ID가 필요합니다. 이 ID는 git log
의 출력을 확인하여 찾을 수 있습니다.
$ git log
commit 62e793f6941c7e0d4ad9a1345a175fe8f45cb9df
Author: bitbucket
Date: Fri Dec 1 15:03:07 2017 -0800
prepend content to reset_lifecycle_file
commit dc67808a6da9f0dec51ed16d3d8823f28e1a72a
Author: bitbucket
Date: Fri Dec 1 10:21:57 2017 -0800
update content of reset_lifecycle_file
commit 780411da3b47117270c0e3a8d5dcfd11d28d04a4
Author: bitbucket
Date: Thu Nov 30 16:50:39 2017 -0800
initial commit
커밋 기록 ID는 시스템마다 고유합니다. 즉, 이 예시의 커밋 ID는 개인 컴퓨터에 표시되는 것과 다르게 표시됩니다. 이 예시에서 우리가 살펴볼 커밋 ID는 780411da3b47117270c0e3a8d5dcfd11d28d04a4
입니다. 이 ID는" 최초 커밋"에 해당하는 ID입니다. ID를 찾고 나면 소프트 재설정의 대상으로 사용할 것입니다.
시간을 거슬러 올라가기 전에 먼저 리포지토리의 현재 상태를 확인해 보겠습니다.
$ git status && git ls-files -s
On branch main
nothing to commit, working tree clean
100644 67cc52710639e5da6b515416fd779d0741e3762e 0 reset_lifecycle_file
여기에서 git status 및
git ls-files- s
를 혼합한 명령을 실행합니다. 그러면 리포지토리에 보류 중인 변경 사항이 있고 스테이징 색인의 reset_lifecycle_file
은 67cc52710639e5da6b515416fd779d0741e3762e
버전이라는 것을 알 수 있습니다. 이것을 염두에 두고 첫 번째 커밋까지 소프트 재설정을 실행하겠습니다.
$git reset --soft 780411da3b47117270c0e3a8d5dcfd11d28d04a4
$ git status && git ls-files -s
On branch main
Changes to be committed:
(use "git reset HEAD ..." to unstage)
modified: reset_lifecycle_file
100644 67cc52710639e5da6b515416fd779d0741e3762e 0 reset_lifecycle_file
위의 코드는 "소프트 재설정"을 실행하며 리포지토리의 상태를 출력하는 git status
및 git ls-files
혼합 명령도 호출합니다. 리포지토리 상태 출력을 살펴보고 몇 가지 흥미로운 사실을 확인할 수 있습니다. 먼저 git status
는reset_lifecycle_file
에 수정 사항이 있음을 나타내며 수정 사항을 강조 표시하여 다음 커밋을 위해 스테이징된 변경 사항임을 나타냅니다. 두 번째로, git ls-files
출력은 스테이징 색인이 변경되지 않았으며 이전의 SHA 67cc52710639e5da6b515416fd779d0741e3762e를 유지함을 나타냅니다.
이러한 재설정에서 발생한 사항을 더욱 명확하게 이해하기 위해 git log
를 살펴보겠습니다.
$ git log commit 780411da3b47117270c0e3a8d5dcfd11d28d04a4 Author: bitbucket Date: Thu Nov 30 16:50:39 2017 -0800 initial commit
이제 로그 출력은 커밋 기록에 단일 커밋이 있다는 것을 보여줍니다. 이것은 --soft
가 수행한 작업을 명확하게 설명하는 데 도움이 됩니다. 모든 git reset
호출과 마찬가지로 재설정이 수행하는 첫 번째 작업은 커밋 트리를 재설정하는 것입니다. --hard
및 --mixed
를 사용한 이전 예시에서는 모두HEAD
에 대한 것이며 커밋 트리를 이전으로 이동시키지 않았습니다. 소프트 재설정 동안 일어나는 일은 이것이 전부입니다.
그러면 git status
가 수정된 파일이 있다고 나타내는 이유가 헷갈릴 수도 있습니다. --soft
는 스테이징 색인에 영향을 주지 않으므로 스테이징 색인에 대한 업데이트는 커밋 기록을 통해 과거로 거슬러 올라갑니다. 이것은 reset_lifecycle_file
에 대한 SHA가 변경되지 않았음을 보여주는 git ls-files -s
출력으로 확인할 수 있습니다. 다시 말해, git status
는 '3개의 트리'의 상태를 나타내지 않으며 그들 사이의 차이점을 보여줍니다. 이 경우 마치 이미 스테이징된 것처럼 스테이징 색인이 커밋 기록의 변경 사항보다 먼저 표시됩니다.
재설정 및 되돌리기
git revert가 변경 사항을 실행 취소하는 “안전한” 방법이라면 git reset
은 위험한 방법이라고 생각할 수 있습니다. git reset
의 경우 작업을 손실할 위험이 있습니다. git reset
은 커밋을 절대 삭제하지 않지만 커밋이 '고립'될 수 있습니다. 즉, 참조에서 커밋에 액세스할 수 있는 직접적인 경로가 없음을 의미합니다. 이러한 고립된 커밋은 일반적으로 git reflog를 사용하여 찾고 복원할 수 있습니다. Git은 내부 가비지 컬렉터를 실행한 후 고립된 커밋을 영구적으로 삭제합니다. 기본적으로 Git은 30일마다 가비지 컬렉터를 실행하도록 구성되어 있습니다. 커밋 기록은 'Git 3개의 트리' 중 하나로, 나머지 2개인 스테이징 색인 및 작업 디렉터리는 커밋만큼 영구적이지 않습니다. 이 도구를 사용할 때는 주의해야 합니다. Git 명령 중에서 작업 내용을 잃을 가능성이 있는 유일한 Git 명령이기 때문입니다.
되돌리기는 공개 커밋을 안전하게 실행 취소하도록 설계된 반면, git reset
은 스테이징 색인 및 작업 디렉터리에 대한 로컬 변경 사항을 실행 취소하도록 설계되었습니다. 목적이 분명히 다르므로 두 명령은 다르게 구현됩니다. 재설정은 변경 집합을 완전히 제거하는 반면 되돌리기는 원래 변경 집합을 유지하고 새 커밋을 사용하여 실행 취소를 적용합니다.
공개 기록 재설정하지 않기
git reset
을 사용하면 안 됩니다. 커밋을 게시한 후에는 다른 개발자가 해당 커밋에 의존하고 있다고 가정해야 합니다.
다른 팀원이 계속 개발 중인 커밋을 제거하면 공동 작업에 심각한 문제를 야기할 수 있습니다. 다른 팀원이 리포지토리에 동기화하려고 하면 일련의 프로젝트 기록이 갑자기 사라진 것처럼 보입니다. 아래 시퀀스는 공개 커밋을 재설정하려고 할 때 발생하는 현상을 보여줍니다. origin/main
브랜치는 로컬 main
브랜치의 중앙 리포지토리 버전입니다.
재설정 후 새 커밋을 추가하자마자 Git은 로컬 기록이 origin/main
에서 분기되었다고 생각할 것이며, 리포지토리를 동기화하는 데 필요한 병합 커밋은 팀을 혼란스럽고 답답하게 만들 수 있습니다.
요점은 게시된 변경 사항이 아닌 잘못된 로컬 실험에서 git reset
을 사용하고 있는지 확인하는 것입니다. 공개 커밋을 수정해야 하는 경우 git revert
명령이 이러한 목적을 위해 특별히 설계되었습니다.
예제
git reset <file>
스테이징 영역에서 지정된 파일을 제거하지만 작업 디렉터리는 그대로 둡니다. 이렇게 하면 변경 사항을 덮어쓰지 않고 파일을 스테이징 취소합니다.
git reset
스테이징 영역을 가장 최근 커밋과 일치하도록 재설정하지만 작업 디렉터리는 그대로 둡니다. 이렇게 하면 변경 사항을 덮어쓰지 않고도 모든 파일이 스테이징 취소되어 스테이징된 스냅샷을 처음부터 다시 구축할 수 있습니다.
git reset --hard
스테이징 영역 및 작업 디렉터리를 가장 최근 커밋과 일치하도록 재설정합니다. --hard
플래그는 변경 사항을 스테이징 취소하는 것 외에도 Git에게 작업 디렉터리의 모든 변경 사항을 덮어쓰도록 지시합니다. 다른 말로 설명하자면 커밋되지 않은 모든 변경 사항이 삭제되므로 사용하기 전에 로컬에서 개발한 내용을 버리고 싶은지 확인해야 합니다.
git reset
현재 브랜치 팁을 뒤로 이동하여 commit
하고 스테이징 영역을 그와 일치하도록 재설정하지만 작업 디렉터리는 그대로 둡니다.
이후의 모든 변경 사항은 작업 디렉터리에 있으므로 더 깔끔하고 원자적인 스냅샷을 사용하여 프로젝트 기록을 다시 커밋할 수 있습니다.
git reset --hard
현재 브랜치 팁을 뒤로 옮겨
하고 스테이징 영역과 작업 디렉터리를 모두 일치하도록 재설정합니다. 이렇게 하면 커밋되지 않은 변경 사항뿐만 아니라 이후의 모든 커밋도 삭제됩니다.
파일 스테이징 취소
스테이징된 스냅샷을 준비하는 동안 git reset
명령을 자주 접하게 됩니다. 다음 예시에서는 리포지토리에 이미 hello.py
및 main.py
라는 파일 2개를 추가했다고 가정하겠습니다.
# Edit both hello.py and main.py
# Stage everything in the current directory
git add .
# Realize that the changes in hello.py and main.py
# should be committed in different snapshots
# Unstage main.py
git reset main.py
# Commit only hello.py
git commit -m "Make some changes to hello.py"
# Commit main.py in a separate snapshot
git add main.py
git commit -m "Edit main.py"
보시다시피 git reset
은 다음 커밋과 관련이 없는 변경 사항을 스테이징 취소할 수 있도록 하여 커밋에 집중하도록 도와줍니다.
로컬 커밋 제거
다음 예시에서는 고급 사용 사례를 살펴봅니다. 한동안 새로운 실험을 진행했지만 몇 개의 스냅샷을 커밋한 후 완전히 버리기로 결정했을 때 어떤 일이 발생하는지 보여줍니다.
# Create a new file called `foo.py` and add some code to it
# Commit it to the project history
git add foo.py
git commit -m "Start developing a crazy feature"
# Edit `foo.py` again and change some other tracked files, too
# Commit another snapshot
git commit -a -m "Continue my crazy feature"
# Decide to scrap the feature and remove the associated commits
git reset --hard HEAD~2
git reset HEAD~2
명령은 현재 브랜치를 두 번의 커밋만큼 뒤로 이동하여 방금 만든 두 개의 스냅샷을 프로젝트 기록에서 효과적으로 제거합니다. 이러한 유형의 재설정은 게시되지 않은 커밋에만 사용해야 합니다. 이미 커밋을 공유 리포지토리로 푸시했다면 위의 작업을 수행하지 마세요.
요약
복습하자면 git reset
은 Git 리포지토리 상태에 대한 로컬 변경 사항을 실행 취소하는 데 사용하는 강력한 명령입니다. git reset
은 "Git 3개의 트리"에서 작동합니다. 이러한 트리는 커밋 기록(HEAD
), 스테이징 색인 및 작업 디렉터리입니다. 3개의 트리에 해당하는 세 가지 명령줄 옵션이 있습니다. --soft, --mixed
및 --hard
옵션을 git reset
에 전달할 수 있습니다.
이 문서에서는 재설정 프로세스를 설명하는 데 도움이 되는 몇 가지 다른 Git 명령을 활용했습니다. git status, git log, git add, git checkout, git reflog 및 git revert 명령에 대한 자세한 내용은 해당 명령의 개별 페이지를 참조하세요.
이 문서 공유
다음 토픽
여러분께 도움을 드릴 자료를 추천합니다.
이러한 리소스에 책갈피를 지정하여 DevOps 팀의 유형에 대해 알아보거나 Atlassian에서 DevOps에 대한 지속적인 업데이트를 확인하세요.