메인 콘텐츠로 건너뛰기
index.js를 console.log("hello git");로 바꾸고 git add까지 했어요. 그 뒤 console.log("hello world");로 다시 저장했어요. 지금 커밋하면 어느 코드가 기록될까요? 첫 커밋 실습에서는 파일을 저장하고, 스테이징하고, 커밋했어요. 이번에는 같은 파일의 내용이 작업 트리, 인덱스, 커밋에서 서로 다를 수 있다는 걸 직접 확인해봐요.

같은 파일을 세 상태로 확인해요

스테이징 영역은 인덱스라고도 불러요. 파일 이름인 index.js와 인덱스는 별개예요. HEAD는 이 실습에서 현재 브랜치의 마지막 커밋을 가리켜요. 인덱스는 다음 커밋의 파일 상태를 준비해요. 변경된 파일만 다음 스냅샷에 들어가는 것은 아니에요. 수정하지 않은 파일도 포함돼요. 스냅샷은 논리적인 모델이며, 모든 파일을 매번 통째 복사한다는 뜻은 아니에요. Pro Git의 세 영역 설명을 참고해요.

시작 상태를 맞춰요

명령은 Bash 기준이에요. 준비 명령의 git init -b main에는 Git 2.28 이상이 필요해요. 별도 hook이나 커밋 서명 설정이 없는 로컬 연습 저장소를 기준으로 해요. 코드를 실행하지 않으므로 Node.js는 필요하지 않아요. 앞 실습의 git-practice를 그대로 뒀다면 그 폴더에서 시작해요. 다른 작업이 섞여 있다면 되돌리거나 덮어쓰지 말고 별도 저장소를 만들어요.
설치는 첫 커밋 실습을 참고해요. 기존 프로젝트나 Git 저장소 밖에서 실행해요. 같은 이름의 폴더가 있어 mkdir가 실패하면 멈추고 새 이름을 골라요.
아래 >는 파일을 덮어써요. 방금 만든 빈 폴더에서만 실행해요.
작성자 설정은 이 저장소에만 적용하고 원격은 연결하지 않아요.
같은 터미널에서 시작 상태를 확인해요.
main과 working tree clean, 초기 커밋 한 개가 보여야 해요. 파일 내용은 console.log("hello");, # Git practice 순서예요. 원격 출력은 없어야 해요.

diff는 어느 두 상태를 비교할까요?

--staged는 --cached와 같은 뜻이에요. 뒤에 -- index.js를 붙이면 그 파일만 비교해요. --는 뒤의 값을 파일 경로로 구분해요. 출력이 별도 보기 화면으로 열렸다면 q로 나올 수 있어요. git diff 공식 문서에 비교 대상이 설명되어 있어요.

add한 뒤 다시 고쳐봐요

각 단계는 같은 터미널에서 순서대로 실행해요. 명령 전에 어느 상태가 바뀔지 예상해보세요.
1

작업 파일의 문자열 바꾸기

아래 명령은 연습용 index.js 전체를 한 줄로 덮어써요. 시작 상태를 확인한 연습 저장소에서만 실행해요.
상태에는 맨 앞에 공백이 있는 M index.js가 보여요. 일반 diff의 변경 줄은 다음과 같아요. 파일명·해시·줄 위치를 나타내는 헤더는 생략했어요.
index.js
git diff --cached는 비어 있어요. 파일만 저장했으므로 인덱스는 마지막 커밋과 같아요.
2

현재 코드를 스테이징하기

작업 파일의 내용을 인덱스에 반영해요. 기존 커밋은 바뀌지 않아요.
상태는 M index.js로 바뀌어요. 작업 트리와 인덱스가 같아 일반 diff는 비어 있고, cached diff에는 "hello" → "hello git" 변경이 나와요.diff가 비었다는 것만으로 커밋을 마쳤다고 판단할 수는 없어요. 비교한 두 상태를 확인해야 해요.
3

add를 다시 하지 않고 코드 고치기

이번에는 작업 파일만 바꿔요. 인덱스에는 방금 스테이징한 코드가 남아요.
상태에 MM index.js가 보여요. 아래 표는 각 diff에서 console.log의 문자열만 줄여 적었어요.add는 실행한 시점의 내용을 반영해요. 이후 편집도 담으려면 다시 스테이징해야 해요. git add 공식 문서를 참고해요.
4

준비한 내용만 커밋하기

add를 다시 하지 않고 커밋해요. 인덱스의 코드와 작업 파일 중 무엇이 기록될까요?
git show HEAD:index.js는 마지막 커밋의 파일을 읽어서 console.log("hello git");를 보여줘요. cat index.js는 현재 파일을 읽어서 console.log("hello world");를 보여줘요.상태에는 M index.js가 남아요. cached diff는 비어 있고 일반 diff에는 "hello git" → "hello world" 변경이 있어요. 커밋이 성공해도 미커밋 변경이 남을 수 있어요.인덱스의 파일이 사라진 것은 아니에요. 인덱스와 새 커밋이 같아져서 스테이징된 차이가 없어진 거예요.
5

남은 변경도 별도 커밋으로 기록하기

인덱스를 갱신하고 준비된 변경을 검토한 뒤 커밋해요.
커밋 전 diff에는 "hello git" → "hello world" 변경이 나와요. 커밋 뒤의 파일 내용은 console.log("hello world");와 # Git practice예요. 수정하지 않은 README도 새 커밋의 스냅샷에 포함돼요.status는 main과 working tree clean을 보여줘요. 커밋은 총 세 개이고 원격은 없어요. 커밋 ID는 실행마다 달라질 수 있으니 개수와 메시지를 확인해요.

MM은 충돌 표시일까요?

이번 실습의 MM은 충돌이 아니에요. 충돌 중이 아닌 일반적인 짧은 상태 출력은 XY 경로 형태예요. 공백도 상태의 일부예요. 새 파일의 ??나 병합 충돌 표시는 별도 규칙이 있으므로 이 표를 모든 상태에 적용하지 않아요. git status 공식 문서를 참고해요.

실제 작업에서는 무엇을 확인하면 좋을까요?

커밋 직전에 git status로 전체 상태를 보고, git diff --cached로 이번에 기록할 변경을 읽어요. git diff에서는 현재 파일에 있지만 이번 커밋에서 빠질 변경을 확인해요. 새 미추적 파일은 일반 diff에 나오지 않으므로 status도 함께 봐야 해요. 두 번 커밋한 것은 세 상태를 관찰하기 위한 실습이에요. 처음부터 "hello world"로 바꾼 결과만 남기고 싶었다면 첫 변경 커밋 전에 git add index.js를 다시 실행하면 돼요. 커밋은 저장 횟수보다 변경 목적에 맞춰 나누는 편이 읽기 좋아요.
이 글은 파일 경로나 -a 없이 실행하는 git commit -m "..."을 기준으로 해요. git commit -a는 이미 추적하는 파일의 수정·삭제를 자동으로 스테이징해요. git commit index.js처럼 경로를 주는 방식도 커밋할 내용을 고르는 규칙이 달라요. git commit 공식 문서를 참고해요.

예상과 다른 결과가 나왔다면

자, 정리해볼까요?

  • add 뒤 다시 고친 시점에 마지막 커밋은 "hello", 인덱스는 "hello git", 작업 파일은 "hello world"였어요.
  • 첫 변경 커밋에는 "hello git"이 기록됐고, 파일의 "hello world"는 남았어요.
  • 마지막에는 세 상태가 같고 미커밋 변경이 없어요.
  • README는 모든 커밋에 남아 있고 원격 저장소는 없어요.
이 세 커밋은 커밋 이력과 변경 내용 읽기에서 이어서 살펴봐요. 기록의 ID만 필요하다면 현재 커밋 해시 확인하기를 참고해요. 실무에서 조회 명령만 빠르게 찾으려면 현재 브랜치와 변경 내용 확인하기를 참고해요.