> ## Documentation Index
> Fetch the complete documentation index at: https://blog.nvim.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Git은 왜 변경을 기록할까요?

> index.js의 코드 변경으로 스냅샷과 커밋을 이해하고, 파일 저장·로컬 기록·원격 공유의 차이를 구분해봐요.

`index.js`에 이런 코드가 있어요.

```javascript title="index.js" theme={null}
console.log("hello");
```

출력할 문장을 바꾸고 저장했어요.

```javascript title="index.js" theme={null}
console.log("hello git");
```

그런데 동료가 물어요. “이 줄은 언제 바꿨고, 왜 바꿨어요?” 지금 파일만 봐서는 이전 내용이나 변경 이유를 알기 어려워요. 다시 고치다가 처음 코드가 필요해질 수도 있고요.

**Git은 파일의 현재 모습뿐 아니라, 그 모습에 도달한 기록을 함께 관리하는 도구**예요. 이 글에서는 같은 파일의 변경을 따라가며 저장, 커밋, 공유를 구분해봐요. Git 설치나 계정은 아직 필요하지 않아요.

> [!NOTE]
>
> 코드와 기록 이름은 개념을 설명하기 위한 예시예요. 실제 터미널 출력이 아니에요.
> 자바스크립트를 실행하는 실습도 아니므로 Node.js나 패키지는 필요하지 않아요.

## 파일을 저장하는 것만으로는 무엇이 부족할까요?

편집기에서 **저장**을 누르면 현재 파일 내용이 바뀌어요. 하지만 다음 질문에 답하려면 변경 기록이 필요해요.

| 알고 싶은 것 | 현재 파일만 있을 때의 어려움 |
| - | - |
| 이전에는 어떤 코드였을까요? | 바꾸기 전 내용을 따로 남겨야 해요 |
| 왜 문장을 바꿨을까요? | 수정 이유를 따로 기억해야 해요 |
| README도 함께 바꿨을까요? | 여러 파일이 어느 시점에 어떤 상태였는지 확인해야 해요 |
| 동료가 고친 코드와 어떻게 합칠까요? | 서로의 작업 출발점과 변경을 비교해야 해요 |

시간에 따른 파일의 변경 이력을 관리하는 것을 **버전 관리(version control)** 라고 해요. Git을 쓰면 `index-final.js` 같은 복사본을 계속 만드는 대신, `index.js`를 편집하면서 이력을 남길 수 있어요. 소스 코드뿐 아니라 README 같은 텍스트도 관리할 수 있어요. [Pro Git의 버전 관리 설명](https://git-scm.com/book/en/v2/Getting-Started-About-Version-Control)을 참고해요.

## 지금 파일, 다음 커밋의 내용, 이미 남긴 기록

파일을 고친 뒤 바로 커밋하는 대신, 먼저 `git add`로 다음 커밋에 담을 내용을 준비해요.

| Git 용어 | 이 예제에서 뜻하는 것 |
| - | - |
| 작업 트리(working tree) | 지금 편집하고 저장하는 `index.js` 같은 파일이 있는 곳이에요 |
| 스테이징 영역(staging area), 인덱스(index) | 다음 커밋에 담을 파일 상태를 준비하는 곳이에요 |
| 커밋(commit) | 프로젝트의 스냅샷과 작성 정보, 메시지 등을 연결한 기록이에요 |
| 저장소(repository) | 커밋 이력과 Git 데이터를 저장하고 관리해요 |

`index.js`라는 파일명과 Git의 **인덱스(index)** 는 서로 다른 말이에요. `git add index.js`는 그 파일의 현재 내용을 인덱스에 반영하는 명령이에요. 파일을 다른 폴더로 옮기지는 않아요.

Git은 무엇이 바뀌었는지 비교할 수 있지만, **왜 바꿨는지는 사람이 커밋 메시지로 남겨야** 나중에 판단하기 좋아요.

## 커밋은 어떤 모습을 기억할까요?

`index.js`와 `README.md`를 함께 기록한다고 해볼게요.

| 설명용 기록 이름 | `index.js` | `README.md` | 커밋 메시지 예시 |
| - | - | - | - |
| A | `console.log("hello");` | `# Git practice` | Add initial script and README |
| B | `console.log("hello git");` | `# Git practice` | Change greeting to hello git |
| C | `console.log("hello world");` | `# Git practice` | Change greeting to hello world |

각 커밋이 가리키는 **그 시점의 프로젝트 상태**를 **스냅샷(snapshot)** 이라고 해요. B에서 `README.md`를 수정하지 않았어도, B의 프로젝트 상태에는 그 파일이 포함돼요.

스냅샷이라는 말이 커밋할 때마다 모든 파일을 물리적으로 통째 복사한다는 뜻은 아니에요. 변경되지 않은 파일의 데이터는 기존 것을 참조할 수 있어요. [Pro Git의 스냅샷 설명](https://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3F)은 이 논리적 상태와 저장 방식을 구분해요.

반면 **차이(diff)** 는 두 상태를 비교한 결과예요. A와 B의 `index.js`를 비교하면 바뀐 줄은 이렇게 표현할 수 있어요.

```diff title="index.js" theme={null}
-console.log("hello");
+console.log("hello git");
```

앞의 `-`는 이전 줄, `+`는 이후 줄을 나타내요. 파일 내용에 들어가는 문자는 아니에요. 스냅샷은 기록된 상태이고, diff는 상태 사이의 비교예요.

실제 Git에서는 A, B, C 대신 커밋 ID로 기록을 구분해요. 이 글의 문자는 이력을 설명하기 위한 표시예요.

## 저장 버튼을 누르면 커밋도 될까요?

`index.js`를 `console.log("hello git");`로 바꾸고 저장해도 새 커밋은 생기지 않아요. 기본적인 기록 흐름은 다음과 같아요.

```mermaid theme={null}
flowchart TB
    W["작업 트리<br/>파일을 편집하고 저장"]
    I["스테이징 영역<br/>다음 커밋의 파일 상태 준비"]
    C["로컬 저장소<br/>새 커밋으로 기록"]
    W -->|"git add · 현재 내용을 반영"| I
    I -->|"git commit · 준비한 상태를 기록"| C
```

작업 파일은 작업 트리에 남아요. 이 그림은 파일을 옮기는 경로가 아니라, 인덱스와 이력이 갱신되는 순서예요.

`git add`는 **실행한 시점의 파일 내용**을 인덱스에 반영해요. 이후 같은 파일을 더 고쳐도 자동으로 반영되지 않아요. [git add 공식 문서](https://git-scm.com/docs/git-add)에 설명된 동작이에요.

아래 표는 `console.log`의 문자열만 줄여 적었어요. 마지막 커밋에 `"hello"`가 있는 상태에서 시작해요.

| 한 일 | 작업 파일 | 인덱스 | 마지막 커밋 |
| - | - | - | - |
| `"hello git"`으로 고치고 저장 | `"hello git"` | `"hello"` | `"hello"` |
| `git add index.js` 실행 | `"hello git"` | `"hello git"` | `"hello"` |
| 다시 `"hello world"`로 고치고 저장 | `"hello world"` | `"hello git"` | `"hello"` |
| 경로나 `-a` 없이 `git commit -m` 실행 | `"hello world"` | `"hello git"` | `"hello git"` |

**지금 파일과 방금 커밋한 내용이 다를 수 있어요.** 마지막 줄에서 `"hello world"`로 바꾼 내용은 아직 커밋하지 않은 변경으로 남아요.

인덱스를 사용하면 여러 파일을 수정해도 이번 커밋에 담을 내용을 고를 수 있어요. 코드 수정과 README 수정을 서로 다른 목적으로 했다면 별도 커밋으로 나누어 이유를 남길 수 있어요.

## 커밋하면 GitHub에도 올라갈까요?

커밋은 먼저 **내 컴퓨터의 로컬 저장소**에 남아요. 이 기본적인 기록 작업에는 GitHub 계정이나 인터넷 연결이 필요하지 않아요.

다른 사람과 기록을 공유하려면 별도의 저장소와 주고받는 과정이 필요해요. 이렇게 주고받는 상대 저장소를 **원격 저장소(remote repository)** 라고 불러요.

```mermaid theme={null}
flowchart LR
    L["내 컴퓨터<br/>로컬 Git 저장소"]
    R["공유할 원격 Git 저장소"]
    T["동료 컴퓨터<br/>동료의 Git 저장소"]

    L -->|"push · 기록 보내기"| R
    R -->|"fetch · 기록 가져오기"| T
```

이 그림에서 커밋을 만드는 일은 왼쪽 저장소 안에서 먼저 일어나요. `push`는 그 기록을 상대 저장소에 보내는 별도 작업이에요. 동료도 기록을 가져온 뒤 자기 작업과 어떻게 합칠지 판단해야 해요. 가져오자마자 편집 중인 파일이 무조건 덮어써진다는 뜻은 아니에요. [Pro Git의 원격 저장소 설명](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes)에서 이 흐름을 확인할 수 있어요.

그렇다면 Git과 GitHub는 어떻게 다를까요?

| 구분 | 하는 일 |
| - | - |
| Git | 파일의 상태와 변경 이력을 관리하는 버전 관리 시스템이에요 |
| GitHub | Git 저장소를 호스팅하고, PR과 코드 리뷰 같은 협업 기능을 제공하는 플랫폼이에요 |

GitHub는 원격 저장소를 둘 수 있는 서비스 중 하나예요. Git을 사용한다고 꼭 GitHub에 올려야 하는 것은 아니에요. [GitHub 공식 소개](https://docs.github.com/en/get-started/start-your-journey/what-is-github)도 Git과 GitHub의 역할을 구분해요.

## 기록이 있어도 자동으로 해결되지는 않아요

Git이 남겨 주는 것은 코드와 변경을 판단할 근거예요. 어떤 코드가 요구사항에 맞는지는 사람이 결정해야 해요.

동료는 같은 줄을 `console.log("hi");`로, 나는 `console.log("hello git");`로 고쳤다면 어떤 내용을 남길지 확인해야 해요. Git이 변경을 자동으로 합칠 수 없는 경우에는 충돌을 알려줘요. 자동으로 합쳐졌더라도 프로그램이 의도대로 동작하는지는 별도로 검증해야 해요.

기록과 백업도 구분해야 해요. 커밋이 내 노트북에만 있다면 노트북이 고장 났을 때를 대비한 다른 사본은 아직 없어요. 원격 저장소에 공유하면 사본을 둘 수 있지만, **아직 보내지 않은 로컬 커밋이나 기록하지 않은 변경까지 함께 보호되는 것은 아니에요.**

> [!NOTE]
>
> Git에 기록하지 않은 작업까지 언제나 복구할 수 있는 것은 아니에요.
> 특히 변경을 버리는 명령을 사용할 때는 현재 파일과 기록된 상태를 먼저 확인해야 해요.
> [Pro Git의 되돌리기 설명](https://git-scm.com/book/en/v2/Git-Basics-Undoing-Things)도 이 경계를 강조해요.

## 내 변경은 지금 어디에 있을까요?

마지막으로 세 장면을 구분해보세요.

1. `index.js`를 수정하고 편집기에서 저장했어요.
2. 기록할 내용을 골라 커밋했지만, 원격 저장소에는 보내지 않았어요.
3. 그 커밋을 원격 저장소에 push했어요.

어느 시점에 로컬 이력이 생기고, 어느 시점에 원격 저장소에도 그 기록이 있을까요?

> [accordion] 답과 이유 확인하기
>
> 첫 번째는 작업 파일을 저장한 상태예요. 새 커밋은 아직 없어요.
>
> 두 번째는 로컬 저장소에 새 커밋이 생긴 상태예요. 이 커밋을 원격 저장소에 공유한 것은 아니에요.
>
> 세 번째는 push가 성공해 원격 저장소에도 그 기록을 보낸 상태예요. 동료가 자기 컴퓨터로 가져왔는지는 또 별개의 일이에요.

## 자, 정리해볼까요?

**오늘 우리가 구분한 것**

* 파일 저장은 작업 파일을 바꾸는 일이에요.

* 커밋은 준비한 프로젝트 상태를 로컬 이력에 남기는 일이에요.

* push는 그 기록을 원격 저장소와 공유하는 일이에요.

명령을 입력하기 전에 “지금 편집 중인 내용일까, 다음 기록에 고른 내용일까, 이미 남긴 이력일까?”를 떠올려보세요. 이 구분이 잡히면 Git 명령이 어느 상태를 바꾸는지 따라갈 수 있어요.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.