git 첫걸음: 빈 폴더에서 첫 커밋, 그리고 되돌리기까지
한동안 나는 파일을 이렇게 관리했다. 보고서.hwp, 보고서_수정.hwp, 보고서_최종.hwp, 그리고 부끄럽지만 보고서_최종_진짜최종(2).hwp. 어느 게 최신인지, 무엇을 왜 바꿨는지는 머릿속에만 있었고, 머릿속은 일주일이면 비워졌다.
git은 그 사본 더미를 대신한다. 파일을 복사하는 대신 “변경”을 기록하고, 각 기록에 “왜 바꿨는지”를 한 줄 붙인다. 나중에 어느 시점으로든 돌아갈 수 있고, 다른 사람과 같은 파일을 고쳐도 충돌 없이 합칠 수 있다. 여기서는 빈 폴더에서 시작해 첫 커밋을 만들고, 원격에 올리고, 실수를 되돌리는 데까지 가 본다. 아래 명령과 출력은 모두 실제로 실행해 확인한 것이다. 커밋 해시 같은 값은 환경마다 다르게 나온다.
저장소 만들기
새 프로젝트라면 폴더를 만들고 그 안에서 git init을 한다.
mkdir myproject && cd myproject
git init -b main
Initialized empty Git repository in /path/to/myproject/.git/
생긴 건 눈에 보이는 파일 하나 없지만, 숨은 .git 폴더가 만들어졌다. 앞으로의 모든 기록이 그 안에 쌓인다. -b main은 첫 브랜치 이름을 main으로 정한다는 뜻이다.
이미 GitHub 같은 곳에 저장소가 있다면 처음부터 만들 필요 없이 받아오면 된다.
git clone git@github.com:user/repo.git
지금 상태 보기
git에서 가장 자주 치게 되는 명령은 git status다. 무엇이 바뀌었고, 그중 무엇이 다음 기록에 들어갈지를 보여 준다. 파일 하나를 만들고 상태를 확인해 보자.
echo "hello" > hello.txt
git status
On branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
hello.txt
nothing added to commit but untracked files present (use "git add" to track)
Untracked files는 git이 아직 추적하지 않는, 즉 한 번도 기록한 적 없는 파일이다. git은 새 파일을 자동으로 따라가지 않는다. 무엇을 기록할지는 내가 직접 고른다.
변경을 기록하기: add 와 commit
여기가 git의 핵심이고, 처음 헷갈리는 지점이다. 기록은 두 단계로 나뉜다. 먼저 git add로 “이번 기록에 포함할 것”을 골라 무대(staging area) 위에 올리고, 그다음 git commit으로 도장을 찍는다.
git add hello.txt
git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: hello.txt
이제 hello.txt가 Changes to be committed로 올라왔다. 무대에 선 상태다. 도장을 찍는다.
git commit -m "첫 커밋: 인사 파일 추가"
[main (root-commit) e06dec7] 첫 커밋: 인사 파일 추가
1 file changed, 1 insertion(+)
create mode 100644 hello.txt
root-commit은 이 저장소의 첫 커밋이라는 표시고, e06dec7은 이 커밋의 해시다. 해시는 커밋마다 다르고, 나중에 특정 시점을 가리킬 때 쓴다. 커밋 메시지에는 “무엇을”보다 “왜”를 적는 편이 나중의 나에게 도움이 된다. 변경 내용은 코드를 보면 알지만, 이유는 코드에 안 남기 때문이다.
처음 커밋하기 전에 한 번은 이름과 이메일을 설정해 둬야 한다. 이 값이 각 커밋의 작성자로 남는다.
git config --global user.name "이름"
git config --global user.email "you@example.com"
add와 commit을 굳이 나눈 이유가 처음엔 번거롭게 느껴진다. 익숙해지면 이 덕분에 “고친 것 중 일부만 골라서 하나의 커밋으로 묶는” 일이 가능해진다. 한 번에 열 군데를 고쳤어도, 관련된 것끼리만 add해서 의미 있는 단위로 커밋을 나눌 수 있다.
기록 보기
쌓인 커밋은 git log로 본다. 한 줄로 간단히 보려면 --oneline을 붙인다.
git log --oneline
47d7657 내용 추가
e06dec7 첫 커밋: 인사 파일 추가
위가 최신이다. 각 줄의 앞부분이 커밋 해시, 뒤가 메시지다. 이 목록이 곧 프로젝트의 역사이고, 메시지를 성의 있게 적을수록 이 역사가 읽을 만해진다.
브랜치로 갈라서 작업하기
브랜치는 기록의 가지다. main을 건드리지 않고 따로 떨어져 나와 작업하다가, 다 되면 합친다. 실험하다 망쳐도 main은 그대로다.
git switch -c feature
Switched to a new branch 'feature'
-c는 새 브랜치를 만들면서 그쪽으로 옮긴다는 뜻이다. 여기서 마음껏 고치고 커밋한 뒤, main으로 돌아가 feature를 합친다.
git switch main
git merge feature
서로 다른 브랜치가 같은 줄을 다르게 고쳤다면 합칠 때 충돌이 난다. 충돌 해결은 처음 단계에서 가장 당황스러운 부분이라 여기서는 다루지 않는다. 혼자 작업하는 동안에는 충돌을 만날 일이 드물다.
원격과 주고받기
지금까지는 전부 내 컴퓨터 안의 일이다. GitHub 같은 원격 저장소에 올려야 백업도 되고 협업도 된다. 원격을 origin이라는 이름으로 연결하고 올린다.
git remote add origin git@github.com:user/repo.git
git push -u origin main
-u는 지금 브랜치(main)를 원격의 main과 짝지어 둔다는 뜻이다. 한 번 해 두면 다음부터는 git push만 쳐도 어디로 보낼지 git이 안다. 반대로 원격의 최신 변경을 내 쪽으로 가져올 때는 git pull을 쓴다.
실수 되돌리기
가장 자주 필요한데 가장 늦게 배우는 게 되돌리기다. 아직 커밋하지 않은 변경을 버리고 마지막 커밋 상태로 돌아가려면 git restore를 쓴다.
echo "실수로 적은 줄" >> hello.txt
git restore hello.txt
git status
restore 뒤에 git status를 치면 출력이 비어 있다. 바뀐 게 없다는 뜻이고, 방금 추가한 줄은 사라졌다. 무대에 올린 것만 내리고 싶다면 git restore --staged hello.txt를 쓴다. 파일 내용은 그대로 두고 add만 취소한다.
이미 만든 커밋을 되돌리는 git reset은 더 강력하지만 그만큼 위험하다. 처음에는 커밋 전 변경을 정리하는 restore 정도만 손에 익혀도 충분하다.
추적하지 않을 것 정해 두기
빌드 결과물, 비밀 키, 용량 큰 의존성 폴더는 기록할 필요도 없고 올려서도 안 된다. 저장소 루트에 .gitignore 파일을 만들어 패턴을 적으면 git이 그 파일들을 무시한다.
node_modules/
dist/
.env
.env처럼 토큰이나 비밀번호가 든 파일을 실수로 커밋해 올리는 일은 흔하고, 한 번 올라가면 기록에서 지우기 번거롭다. 처음부터 .gitignore에 넣어 두는 편이 안전하다.
정리
git의 기본 리듬은 단순하다. 파일을 바꾸고, git add로 무대에 올리고, git commit으로 기록하고, 필요하면 git push로 원격에 올린다. 길을 잃었다 싶을 때마다 git status와 git log를 치면 지금 어디에 서 있는지가 보인다. 나머지 명령은 이 리듬 위에서 필요할 때 하나씩 더하면 된다.