1. 가장 최근 커밋, 가볍게 수정하기 (commit --amend)

가장 흔하게 발생하는 실수는 방금 완료한 커밋에 오타가 있거나 파일을 빠뜨린 경우입니다. 이럴 때는 새로운 커밋을 추가하는 대신, 마지막 커밋을 간단히 수정하는 것이 가장 깔끔합니다. git commit --amend 명령어는 바로 이런 상황을 위해 존재합니다.

  1. 커밋 메시지만 수정할 때 방금 작성한 커밋 메시지에 오타가 있거나 내용을 보충하고 싶다면, 아래 명령어를 사용해 간단히 수정할 수 있습니다.
    git commit --amend -m "수정된 새로운 커밋 메시지"
  2. 파일을 추가하거나 변경 내용을 덧붙일 때 커밋에 포함했어야 할 파일을 빠뜨렸거나, 일부 수정 사항을 추가하고 싶을 때 사용합니다. 먼저 원하는 파일을 스테이징 영역에 추가한 뒤, -no-edit 옵션을 사용하면 커밋 메시지는 그대로 둔 채 내용만 마지막 커밋에 덧붙일 수 있습니다.
    # 빠뜨린 파일을 스테이징 영역에 추가합니다.
    git add 빠뜨린_파일.js
    
    # 기존 커밋 메시지를 유지하면서 마지막 커밋에 파일을 추가합니다.
    git commit --amend --no-edit

2. 과거의 특정 상태로 돌아가기 (reset vs revert)

단순한 수정이 아니라 과거의 특정 시점으로 프로젝트 상태를 되돌려야 할 때가 있습니다. 이때는 git reset과 git revert라는 두 가지 선택지가 있으며, 둘의 차이를 명확히 이해하고 사용하는 것이 매우 중요합니다.

  1. 히스토리를 삭제하며 과거로 돌아가기: git resetreset은 브랜치가 가리키는 위치(HEAD)를 지정한 과거 커밋으로 강제로 이동시키는 강력한 명령어입니다. 즉, 지정한 과거 시점 이후의 모든 커밋 히스토리가 사라질 수 있어 주의가 필요합니다. 주로 원격 저장소에 공유되지 않은 로컬 커밋을 정리할 때 유용하며, 세 가지 옵션이 있습니다.
    • -soft: 커밋 기록만 취소하고, 변경했던 내용들은 모두 스테이징 영역(git add를 마친 상태)에 그대로 남겨둡니다.
      # 가장 최근 커밋 1개를 취소하고, 변경 내용은 스테이징 상태로 유지합니다.
      git reset --soft HEAD~1
    • -mixed (기본 옵션): 커밋 기록과 스테이징 내용까지 취소합니다. 변경했던 내용들은 작업 디렉토리(파일을 수정만 한 상태)에 남아있습니다.
      # 가장 최근 커밋 2개를 취소하고, 변경 내용은 작업 디렉토리에 보존합니다.
      git reset --mixed HEAD~2
    • -hard (매우 위험!): 커밋, 스테이징, 작업 디렉토리의 모든 변경 내용을 완전히 삭제하고 과거의 특정 상태로 돌아갑니다. 복구가 어려울 수 있으므로 사용에 각별한 주의가 필요합니다.
      # 특정 커밋 해시의 상태로 모든 것을 되돌립니다. 이후의 모든 변경 내용은 영구 삭제됩니다.
      git reset --hard <되돌아가고_싶은_커밋_해시>
  2. 히스토리를 유지하며 변경 내용만 취소하기: git revertrevert는 reset과 달리 기존 히스토리를 삭제하지 않습니다. 대신, 특정 커밋에서 발생한 변경 사항을 되돌리는 새로운 커밋을 생성합니다. 이미 다른 팀원과 공유된 원격 저장소의 커밋을 안전하게 되돌려야 할 때 반드시 사용해야 하는 방법입니다.
    # 문제가 된 커밋의 변경 사항을 취소하는 새로운 커밋을 생성합니다.
    git revert <문제가_된_커밋_해시>

    이 방법을 사용하면 "A라는 작업을 추가했다"는 커밋과 "A라는 작업을 다시 제거했다"는 커밋이 모두 히스토리에 남게 되어, 누가 언제 어떤 작업을 되돌렸는지 투명하게 추적할 수 있습니다.

3. 복잡한 히스토리, 마음대로 편집하기 (rebase -i)

여러 개의 커밋을 합치거나, 순서를 바꾸거나, 특정 커밋만 삭제하는 등 히스토리 자체를 정교하게 재구성하고 싶을 때가 있습니다. git rebase -i (대화형 리베이스)는 마치 Git의 타임머신처럼 과거의 커밋 목록을 자유자재로 편집할 수 있게 해줍니다.

  1. 대화형 리베이스 시작하기 아래 명령어는 현재 브랜치의 최근 3개 커밋을 대상으로 대화형 리베이스를 시작합니다.
    git rebase -i HEAD~3
  2. 커밋 편집하기 명령어를 실행하면 텍스트 편집기가 열리면서 지정한 커밋 목록과 함께 선택할 수 있는 작업들이 나타납니다.
    • pick (p): 해당 커밋을 그대로 사용합니다.
    • reword (r): 커밋은 그대로 두되, 커밋 메시지를 수정합니다.
    • squash (s): 바로 이전 커밋과 하나로 합칩니다. 두 커밋의 메시지를 합쳐 새로운 메시지를 작성할 수 있습니다.
    • fixup (f): squash와 동일하게 이전 커밋과 합치지만, 이 커밋의 메시지는 버리고 이전 커밋의 메시지를 사용합니다.
    • drop (d): 해당 커밋을 히스토리에서 완전히 삭제합니다.

    이 기능들을 조합하여 지저분했던 커밋 기록을 의미 있는 단위로 깔끔하게 정리할 수 있습니다.

4. 브랜치 관련 실수, 깔끔하게 해결하기

때로는 작업 내용 자체보다 작업한 브랜치가 잘못된 경우가 있습니다. 이런 상황을 해결하는 유용한 명령어 두 가지를 소개합니다.

  1. 다른 브랜치의 특정 커밋만 가져오기: cherry-pickfeature/A 브랜치에 작업해야 할 내용을 실수로 main 브랜치에 커밋했다면, cherry-pick을 사용하여 해당 커밋만 feature/A 브랜치로 쏙 가져올 수 있습니다.
    # 올바른 브랜치로 이동합니다.
    git checkout feature/A
    
    # main 브랜치에 있던 특정 커밋을 현재 브랜치로 가져옵니다.
    git cherry-pick <main에_잘못_올린_커밋_해시>
  2. 작업 내용 임시로 저장하기: stash 아직 커밋하기는 애매한 작업 도중에 급하게 다른 브랜치로 이동해서 코드를 확인해야 할 때가 있습니다. 이때 git stash를 사용하면 현재 작업 내용을 임시로 저장하고 작업 디렉토리를 깨끗하게 만들 수 있습니다.
    # 1. 현재 변경 내용을 임시 저장합니다.
    git stash
    
    # 2. 다른 브랜치로 이동하여 필요한 작업을 수행합니다.
    git checkout other-branch
    # ... 작업 수행 ...
    
    # 3. 원래 브랜치로 돌아와 저장했던 내용을 다시 불러옵니다.
    git checkout original-branch
    git stash pop

5. 원격 저장소 강제 수정 (주의 필요!)

reset이나 rebase로 로컬 히스토리를 수정한 후 원격 저장소에 반영하려면 일반적인 push로는 불가능합니다. 로컬과 원격의 히스토리가 달라졌기 때문입니다. 이때 강제로 원격 저장소를 덮어쓰는 명령어를 사용해야 하지만, 이는 팀원들과 함께 사용하는 공유 브랜치에서는 심각한 문제를 일으킬 수 있으므로 사용법을 정확히 알아야 합니다.

  1. 원격 저장소 강제 덮어쓰기: push --force 이 명령어는 로컬 저장소의 히스토리를 기준으로 원격 저장소의 내용을 강제로 덮어씁니다. 만약 내가 모르는 사이에 다른 팀원이 원격 브랜치에 새로운 내용을 push 했다면, 그 내용이 사라질 수 있는 매우 위험한 명령어입니다.
    # (경고!) 원격 저장소의 main 브랜치를 내 로컬 main 브랜치 상태로 강제 덮어씁니다.
    git push origin main --force
  2. 더 안전하게 강제 푸시하기: push --force-with-lease-force의 위험성을 보완한 더 안전한 대안입니다. 이 명령어는 push를 시도할 때, 내가 마지막으로 원격 저장소의 상태를 확인한 이후(fetch) 다른 누군가가 새로운 커밋을 올리지 않았는지 검사합니다. 만약 원격 브랜치에 변경 사항이 있다면 push를 거부하여 다른 사람의 작업을 덮어쓰는 위험을 막아줍니다. 개인 브랜치가 아니라면 force 대신 항상 이 명령어를 사용하는 습관을 들이는 것이 좋습니다.
    # 원격 저장소에 내가 모르는 변경 사항이 없을 때만 강제 푸시를 실행합니다.
    git push origin main --force-with-lease

6. 최후의 보루, 모든 것을 되돌리는 reflog

git reset --hard로 중요한 커밋을 날려버렸거나, rebase 도중 히스토리가 완전히 꼬여버려 어디서부터 잘못됐는지조차 알 수 없을 때가 있습니다. 이때 git reflog는 당신을 구해줄 최후의 보루입니다. 이 명령어는 브랜치, HEAD가 이동했던 모든 기록을 마치 블랙박스처럼 저장하고 있습니다.

  1. 모든 이동 기록 확인하기git reflog를 입력하면 commit, reset, rebase, merge 등 내가 했던 모든 작업 기록과 해당 시점의 커밋 해시가 나타납니다.
    git reflog
    a1b2c3d HEAD@{0}: reset: moving to a1b2c3d
    e4f5g6h HEAD@{1}: commit: 새로운 기능 추가
    i7j8k9l HEAD@{2}: rebase -i (finish): returning to refs/heads/main
    ...
  2. 잃어버린 커밋으로 복구하기 로그에서 되돌아가고 싶은 상태의 커밋 해시(예: a1b2c3d)를 찾았다면, reset 명령어를 통해 해당 상태로 완벽하게 복구할 수 있습니다.
    # reflog에서 찾은 해시로 상태를 완전히 복구합니다.
    git reset --hard a1b2c3d

7. 특별 케이스: 외부 서비스 연동 문제 해결 (Vercel 예시)

때로는 Git 자체의 문제라기보다 Vercel과 같은 배포 자동화 서비스와의 연결이 꼬이는 경우도 있습니다. 이럴 때는 연결을 완전히 끊고 새로 설정하는 것이 가장 확실한 해결책이 될 수 있습니다.

  1. Vercel에서 프로젝트 연결 해제하기 Vercel 대시보드에서 해당 프로젝트의 Settings > Git 메뉴로 이동하여 'Disconnect' 버튼을 클릭합니다. 이렇게 하면 Git 저장소와의 연결이 해제되고 자동 배포가 중단됩니다.
  2. 로컬 Git 저장소 원격 연결 정리하기 로컬 프로젝트 폴더에서 기존 원격 저장소 연결을 제거합니다.
    # 기존 원격 저장소 연결을 제거합니다.
    git remote remove origin
  3. Vercel에서 프로젝트 재연결하기 Vercel 대시보드에서 'New Project'를 클릭하고, 다시 연결하려는 Git 저장소를 선택하여 프로젝트를 새로 생성하고 배포 설정을 구성합니다.