HOWTO · Git

`git reset --soft` 사용법

`git reset --soft`로 브랜치 끝을 이전 커밋으로 옮기면서 변경 사항을 스테이징된 상태로 유지하는 방법을 알아보세요. 스테이징된 변경 사항을 확인하고 안전하게 작업을 이어가는 방법도 설명합니다.

이 페이지의 내용

git reset --soft <target>을 사용하면 인덱스와 작업 트리는 그대로 둔 채 현재 브랜치의 끝을 이전 커밋으로 옮길 수 있습니다. 지나온 커밋에서 생긴 변경 사항은 스테이징된 상태로 남아 검토하고 다시 커밋할 수 있습니다. 최근 커밋을 합치거나 내용을 유지하면서 커밋 메시지를 수정할 때 유용합니다.

git reset --soft의 동작

소프트 리셋은 현재 브랜치의 HEAD와 브랜치 끝을 지정한 커밋으로 옮깁니다. 스테이징 인덱스나 작업 트리의 파일은 변경하지 않습니다. 따라서 이전 브랜치 끝과 대상 커밋 사이의 변경 사항은 새 브랜치 끝을 기준으로 스테이징됩니다. 이 명령은 현재 체크아웃된 브랜치에 적용되며, 이전 커밋을 가리키는 다른 브랜치까지 옮기지는 않습니다.

기록을 옮기려는 경우에는 대상을 지정하세요. 대상을 생략하면 Git은 HEAD를 사용하므로 브랜치는 이동하지 않습니다. 기존에 스테이징했거나 스테이징하지 않은 작업도 그대로 남습니다. 이후 커밋에 어떤 내용이 포함될지 정확히 알 수 있도록 리셋한 뒤 스테이징된 차이를 검토하세요.

리셋할 커밋 선택하기

git log --oneline으로 최근 기록을 살펴보세요. 현재 브랜치의 끝으로 삼을 커밋을 선택하고, 리셋을 실행하기 전에 커밋 제목이나 해시를 확인하세요. 예를 들어 HEAD~1은 현재 커밋의 첫 번째 부모를 뜻하며, 현재 기록 흐름에서 바로 이전 커밋을 선택합니다. HEAD~2는 첫 번째 부모를 두 단계 거슬러 올라갑니다. 이름이 지정된 브랜치나 태그, 커밋 해시도 대상으로 사용할 수 있습니다.

대상은 삭제할 커밋이 아니라 브랜치 끝으로 유지할 커밋입니다. HEAD~1로 리셋하면 브랜치가 한 커밋 뒤로 이동하고 이전 브랜치 끝에서 생긴 변경 사항은 스테이징된 채 남습니다. 기록이 직선적이지 않다면 번호가 붙은 부모 표현식이 원하는 커밋을 가리킨다고 가정하지 말고 로그에서 대상을 확인하세요.

변경 사항을 스테이징된 상태로 유지하며 커밋 리셋하기

커밋 하나를 리셋하려면 먼저 로그를 살펴본 다음 git reset --soft HEAD~1을 실행하세요. 최근 커밋 여러 개를 합치려면 git reset --soft HEAD~3처럼 그에 맞는 이전 커밋을 대상으로 지정합니다. 인덱스와 작업 트리는 보존되므로 해당 커밋들의 변경 사항을 함께 새 커밋으로 만들 수 있습니다.

다음 예제를 실행하세요.

이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.

work_dir="$(mktemp -d)"
trap 'rm -rf "$work_dir"' EXIT
cd "$work_dir"
git init -q
git config user.name "Example User"
git config user.email "example@example.com"
printf 'first version\n' > note.txt
git add note.txt
git commit -qm "Add note"
printf 'second version\n' > note.txt
git commit -qam "Update note"
git reset --soft HEAD~1
git status --short

예제는 정상적으로 종료되고 M note.txt를 출력합니다. 이는 소프트 리셋 후에도 변경 사항이 스테이징된 상태로 남아 있음을 보여 줍니다.

스테이징된 변경 사항 확인하기

리셋한 뒤 git status로 원하는 파일이 스테이징되었는지 확인하세요. 다른 커밋을 만들기 전에 git diff --cached로 스테이징된 패치의 정확한 내용을 살펴보세요. --cached 옵션은 인덱스와 이제 선택된 대상인 HEAD를 비교합니다. 표시된 변경 사항이 의도한 내용과 다르면 커밋하기 전에 멈추고 대상과 차이를 확인하세요.

스테이징된 패치가 올바르면 git commit -m "Describe the combined change"로 대체 커밋을 만드세요. 가장 최근 커밋을 수정하려면 git commit --amend로 해당 커밋을 대체할 수 있습니다. 실행을 확정하기 전에 스테이징된 내용과 커밋 메시지를 주의 깊게 확인하세요. 소프트 리셋은 새 커밋을 자동으로 만들거나 커밋 메시지를 바꾸지 않습니다.

--soft, --mixed, --hard는 어떻게 다를까요?

세 리셋 모드 모두 현재 브랜치의 끝을 대상으로 옮기지만, 인덱스와 작업 트리를 다루는 방식은 서로 다릅니다.

  • git reset --soft <target>은 브랜치 끝을 옮기고 인덱스와 작업 트리를 모두 그대로 둡니다. 해당 커밋의 변경 사항은 스테이징된 상태로 남습니다.
  • git reset --mixed <target>은 브랜치 끝을 옮기고 인덱스를 대상과 일치시키지만 작업 트리의 파일은 그대로 둡니다. 지나온 커밋에서 생긴 변경 사항은 스테이징되지 않은 상태가 됩니다. 모드를 지정하지 않으면 기본값은 --mixed입니다.
  • git reset --hard <target>은 브랜치 끝을 옮기고 인덱스와 추적 중인 작업 트리 파일을 모두 대상과 일치시킵니다. 대상에 없는 추적 파일의 편집 내용은 버려질 수 있으므로, 그 결과가 의도된 경우에만 사용하세요.

리셋 모드는 일반적으로 관련 없는 추적되지 않은 파일을 그대로 둡니다. 하지만 대상의 추적 파일 경로를 쓰는 데 방해가 되는 추적되지 않은 파일이나 디렉터리는 git reset --hard가 삭제할 수 있습니다. 대체 커밋을 위해 변경 사항을 스테이징된 상태로 유지하려면 --soft를 선택하고, 스테이징되지 않은 작업으로 검토하려면 --mixed를 선택하세요. 소프트 리셋 대신 --hard를 사용하지 마세요.

git reset --soft를 안전하게 사용하는 경우

소프트 리셋은 여러 커밋을 하나로 합치거나 변경 사항을 다른 커밋에 포함하도록 준비하는 등 최근의 로컬 기록을 편집할 때 적합합니다. 실행하기 전에 git status와 git log --oneline으로 현재 브랜치와 대상을 확인하세요. 실행한 뒤에는 커밋하기 전에 git status와 git diff --cached를 살펴 관련 없는 스테이징 작업이 실수로 포함되지 않도록 하세요.

커밋을 이미 공유했다면 브랜치를 옮길 때 다른 사람이 작업의 기반으로 삼았을 수 있는 기록도 다시 쓰게 됩니다. 공유된 기록을 바꾸기 전에 협의하세요. 공개된 변경 사항을 기록으로 보존하면서 되돌려야 한다면 일반적으로 revert가 더 적합합니다. 소프트 리셋은 나중에 푸시하기 전까지 로컬 저장소만 바꾸지만, 기록을 다시 쓴 뒤 푸시하면 협업에 지장을 줄 수 있습니다. 대상과 스테이징된 차이를 명확히 확인하고, 일반적인 후속 작업으로 강제 푸시를 사용하지 마세요.