Git 실수 안전하게 되돌리기: 리버트, 리셋, 체크아웃 설명

Git 실수를 자신 있게 해결하세요! 이 가이드는 `git revert`, `git reset`, `git checkout`을 설명하여 커밋을 안전하게 되돌리고, 파일을 복원하며, 리포지토리 기록을 관리하는 방법을 안내합니다. 각 명령어를 언제 어떻게 사용하여 소중한 작업을 잃지 않고 오류를 수정하는지 배워보세요. 모든 Git 사용자에게 필수적인 내용입니다.

38 조회수

Git 실수 안전하게 되돌리기: revert, reset, checkout 설명

Git은 버전 관리의 강력한 도구로, 개발자가 변경 사항을 추적하고, 협업하며, 코드 히스토리를 효율적으로 관리할 수 있게 해줍니다. 하지만 숙련된 사용자조차 실수를 할 수 있으며, 이는 의도하지 않은 커밋, 잘못된 파일 수정 또는 작업 손실로 이어질 수 있습니다. 다행히 Git은 이러한 오류를 안전하게 되돌릴 수 있는 여러 명령어를 제공합니다. 이 가이드에서는 세 가지 필수 명령어인 git revert, git reset, git checkout을 살펴보고, 각 명령어의 고유한 목적, 사용 사례 및 Git 실수를 프로젝트 무결성을 손상시키지 않으면서 효과적으로 수정하는 방법을 설명합니다.

이 명령어들을 이해하는 것은 깔끔하고 관리 가능한 Git 히스토리를 유지하는 데 매우 중요합니다. 이 명령어들은 모두 변경 사항을 되돌리는 것과 관련이 있지만, 작동 방식이 다르고 리포지토리의 상태와 히스토리에 미치는 영향이 다양합니다. 상황에 맞는 올바른 명령어를 선택하는 것은 상당한 데이터 손실과 디버깅의 어려움을 피하는 데 도움이 될 수 있습니다.

핵심 개념 이해하기

명령어로 들어가기 전에 몇 가지 기본적인 Git 개념을 파악하는 것이 중요합니다.

  • 작업 디렉토리 (Working Directory): 프로젝트 파일을 수정하는 로컬 파일 시스템입니다.
  • 스테이징 영역 (Staging Area / Index): 파일을 수정한 후, 다음 커밋을 위해 스테이징 영역에 git add 합니다.
  • 로컬 리포지토리 (Local Repository): Git이 프로젝트의 커밋 히스토리를 저장하는 곳입니다. 프로젝트 내의 숨겨진 .git 디렉토리입니다.
  • 커밋 (Commit): 특정 시점의 프로젝트 스냅샷입니다. 각 커밋은 고유한 SHA-1 해시를 가집니다.
  • HEAD: 일반적으로 현재 브랜치의 가장 최근 커밋을 가리키는 포인터입니다.

git revert: 변경 사항 안전하게 되돌리기

git revert는 특히 공유 리포지토리에서 커밋을 되돌리는 가장 안전한 방법입니다. 히스토리를 삭제하거나 다시 쓰는 대신, 이전 커밋에서 도입된 변경 사항을 되돌리는 새로운 커밋을 생성합니다.

작동 방식:

git revert <commit-hash>를 실행하면 Git은 지정된 커밋에서 이루어진 변경 사항을 분석하고, 반대되는 변경 사항을 적용하는 새 커밋을 생성합니다. 이 방식은 리포지토리의 히스토리를 보존하므로, 히스토리를 다시 쓰는 것이 협업자에게 문제를 일으킬 수 있는 공개 브랜치에 이상적입니다.

사용 사례:

  • 원격 리포지토리에 이미 푸시된 잘못된 커밋 되돌리기.
  • 문제를 일으킨 병합 커밋 수정.
  • 이후 커밋에 영향을 주지 않고 특정 변경 사항을 안전하게 롤백.

예시:

다음과 같은 커밋 히스토리가 있다고 가정해 봅시다.

A -- B -- C -- D (main)

그리고 C 커밋에서 도입된 변경 사항을 되돌리고 싶다고 가정해 봅시다. 먼저 git log를 사용하여 C의 커밋 해시를 찾습니다.

git log --oneline

C 커밋의 해시가 abcdef1이라고 가정해 봅시다.

git revert abcdef1

Git은 새 revert 커밋의 커밋 메시지를 수정할 수 있도록 기본 편집기를 엽니다. 저장하고 닫은 후 히스토리는 다음과 같이 보일 것입니다.

A -- B -- C -- D -- E (main)  <-- E는 C의 변경 사항을 되돌림

중요 고려 사항:

  • git revert는 항상 새 커밋을 추가합니다. 기존 커밋을 변경하지 않습니다.
  • revert 과정에서 충돌이 발생하는 경우(예: revert 커밋의 변경 사항이 이후 변경 사항과 겹치는 경우), Git은 일시 중지되며 수동으로 충돌을 해결한 후 revert를 커밋해야 합니다.

git reset: 히스토리 다시 쓰기

git reset은 브랜치 포인터를 이동시키고 작업 디렉토리와 스테이징 영역을 선택적으로 수정할 수 있는 더 강력한 명령어입니다. 주로 로컬 리포지토리의 변경 사항을 되돌리는 데 사용되며, 이미 공유된 커밋에 사용하면 위험할 수 있습니다.

작동 방식:

git resetHEAD 포인터를 다른 커밋으로 이동시킵니다. 작업 디렉토리와 스테이징 영역에 미치는 영향은 선택한 모드에 따라 달라집니다.

  • --soft: HEAD 포인터를 이동시키지만 작업 디렉토리와 스테이징 영역은 그대로 둡니다. 되돌려진 커밋의 변경 사항은 작업 디렉토리에서 스테이징되지 않은 변경 사항으로 나타납니다.
  • --mixed (기본값): HEAD 포인터를 이동시키고 스테이징 영역을 재설정합니다. 되돌려진 커밋의 변경 사항은 스테이징되지 않은 상태로 작업 디렉토리에 나타납니다.
  • --hard: HEAD 포인터를 이동시키고, 스테이징 영역을 재설정하며, 되돌려진 커밋에 대한 작업 디렉토리의 모든 변경 사항을 삭제합니다. 이것이 가장 파괴적인 옵션이며 데이터 손실로 이어질 수 있습니다.

사용 사례:

  • 파일 스테이징 취소 (git reset HEAD <file>).
  • 푸시하기 전에 마지막 로컬 커밋 되돌리기.
  • 공유하기 전에 지저분한 로컬 커밋 히스토리 정리.

예시:

  1. 파일 스테이징 취소:

    실수로 파일을 git add한 경우.

    ```bash
    git add unwanted_file.txt
    git status # unwanted_file.txt가 스테이징됨으로 표시

    git reset HEAD unwanted_file.txt
    git status # unwanted_file.txt가 스테이징되지 않은 상태로 표시
    ```

    모든 변경 사항 스테이징 취소:

    bash git reset

  2. 마지막 커밋 되돌리기 (soft reset):

    마지막 커밋을 되돌리고 싶지만 변경 사항을 유지하여 다르게 다시 커밋하고 싶을 때:

    ```bash
    git reset --soft HEAD~1

    HEAD는 이제 마지막 커밋 이전 커밋을 가리킵니다.

    마지막 커밋의 변경 사항은 이제 스테이징되었습니다.

    ```

  3. 마지막 커밋 되돌리기 (mixed reset - 기본값):

    마지막 커밋을 되돌리고 변경 사항을 작업 디렉토리에서 스테이징되지 않은 상태로 사용하고 싶을 때:

    ```bash
    git reset --mixed HEAD~1

    또는 간단히:

    git reset HEAD~1

    HEAD는 이제 마지막 커밋 이전 커밋을 가리킵니다.

    마지막 커밋의 변경 사항은 이제 작업 디렉토리에서 스테이징되지 않은 상태입니다.

    ```

  4. 마지막 커밋 및 해당 변경 사항 모두 삭제 (hard reset):

    경고: 이 작업은 변경 사항을 영구적으로 삭제합니다. 극도로 주의하여 사용하세요!

    ```bash
    git reset --hard HEAD~1

    HEAD는 이제 마지막 커밋 이전 커밋을 가리킵니다.

    마지막 커밋에 의해 도입된 모든 변경 사항이 사라집니다.

    ```

  5. 특정 커밋으로 재설정:

    브랜치를 HEAD보다 이전 커밋(commit_hash)으로 되돌리려면:

    ```bash
    git reset --hard commit_hash

    이 작업은 commit_hash 이후의 모든 커밋과 변경 사항을 삭제합니다.

    ```

중요 고려 사항:

  • git reset은 히스토리를 다시 씁니다. 이미 원격 리포지토리에 푸시된 커밋을 reset하는 경우, 강제 푸시(git push -f)를 수행해야 하며, 이는 협업자에게 문제가 될 수 있습니다.
  • --hard는 파괴적입니다. git reset --hard를 사용하기 전에 항상 커밋 히스토리와 작업 중인 파일을 다시 확인하세요.

git checkout: 파일 전환 및 복원

git checkout은 주로 브랜치 간 전환 및 파일을 이전 상태로 복원하는 데 사용됩니다. revertreset처럼 직접적으로 커밋을 되돌리지는 않지만, 의도하지 않은 파일 수정 사항을 수정하거나 과거 상태를 보는 데 필수적입니다.

작동 방식:

git checkout은 여러 방식으로 사용될 수 있습니다.

  1. 브랜치 전환: git checkout <branch-name>HEAD를 지정된 브랜치로 이동시키고 작업 디렉토리를 해당 브랜치의 최신 커밋과 일치하도록 업데이트합니다.
  2. 브랜치 생성 및 전환: git checkout -b <new-branch-name>은 새 브랜치를 생성하고 즉시 해당 브랜치로 전환합니다.
  3. 로컬 파일 변경 사항 삭제: git checkout -- <file>은 작업 디렉토리의 특정 파일을 마지막 커밋(또는 스테이징된 경우 인덱스)의 상태로 복원합니다. 원치 않는 수정을 삭제하는 데 유용합니다.
  4. 과거 커밋 보기: git checkout <commit-hash>는 특정 커밋을 체크아웃할 수 있게 합니다. 이는 HEAD를 분리시켜 "detached HEAD" 상태로 만들어, 현재 브랜치를 변경하지 않고 해당 시점의 프로젝트를 검사할 수 있게 합니다.

사용 사례:

  • 파일의 커밋되지 않은 변경 사항 삭제.
  • 기능 브랜치와 메인 브랜치 간 전환.
  • 특정 과거 커밋의 코드 검토.

예시:

  1. 파일 변경 사항 삭제:

    my_file.txt에 일부 수정을 가했고 이를 삭제하고 싶을 때:

    ```bash

    my_file.txt에 일부 변경 사항 적용

    git status # my_file.txt가 수정됨으로 표시

    git checkout -- my_file.txt
    git status # my_file.txt가 수정되지 않은 상태(마지막 커밋 상태)로 표시
    ```

  2. 특정 커밋 체크아웃 (detached HEAD):

    프로젝트가 abcdef1 커밋 시점에 어떻게 보였는지 확인하려면:

    ```bash
    git checkout abcdef1

    이제 'detached HEAD' 상태입니다.

    HEAD는 직접 commit abcdef1을 가리킵니다.

    이 시점부터의 히스토리를 보려면 git log를 사용하세요.

    브랜치(예: main)로 돌아가려면:

    git checkout main
    ```

중요 고려 사항:

  • git checkout -- <file>을 사용할 때 해당 파일의 커밋되지 않은 변경 사항은 영구적으로 손실됩니다. 정말로 삭제해도 되는지 확인하세요.
  • detached HEAD 상태에서는 새로 만드는 커밋이 어떤 브랜치에도 속하지 않습니다. 이러한 변경 사항을 저장하려면 해당 상태에서 새 브랜치를 만드세요 (git checkout -b new-feature-branch).

어떤 명령어를 언제 사용해야 할까?

  • git revert를 사용할 때:

    • 이미 공유된 원격 리포지토리에 푸시된 커밋을 되돌려야 할 때.
    • 명확하고 변경 불가능한 히스토리를 유지하고 싶을 때.
    • 이후 커밋에 직접적인 영향을 주지 않고 특정 변경 사항을 되돌리고 싶을 때.
  • git reset을 사용할 때:

    • 파일 스테이징을 취소해야 할 때.
    • 공유하기 전에 하나 이상의 로컬 커밋을 되돌리고 싶을 때.
    • 로컬 커밋 히스토리를 다시 작성하는 것에 익숙할 때 (예: 풀 리퀘스트 전에 정리).
    • 히스토리 다시 쓰기의 위험을 이해할 때, 특히 나중에 푸시할 계획이 있다면.
  • git checkout을 사용할 때:

    • 작업 디렉토리의 특정 파일에 대한 커밋되지 않은 변경 사항을 삭제해야 할 때.
    • 브랜치 간 전환하거나 프로젝트의 과거 상태를 볼 필요가 있을 때.

결론

git revert, git reset, git checkout을 능숙하게 사용하는 것은 효과적인 Git 사용의 기본입니다. 이 명령어들의 차이점을 이해하고 올바르게 사용하면 실수를 자신 있게 되돌리고, 커밋 히스토리를 관리하며, 프로젝트의 무결성을 보장할 수 있습니다. 히스토리를 다시 쓰는 명령어(예: git reset)를 사용하기 전에 변경 사항이 로컬인지 공유된 것인지 항상 고려하세요. 확신이 서지 않을 때는 공유 브랜치의 경우 git revert가 종종 더 안전한 선택입니다.