문서 읽는 데 53분 · A3

A-3: 되돌리기와 히스토리 정리

목차 29
전체 8강 중 3강 · Git·GitHub
난이도 · 입문

ℹ️코드 버전 관리와 협업의 기본기 — 어떤 트랙을 가든 처음에 익혀두면 좋아요.

다시 만났어요, 홍순구 튜터입니다. 지난 시간 우리는 한 줄기 역사에 가지를 치고, 평행 우주에서 실험하고, 본체에 합치고, 신입들이 무서워한다는 충돌까지 직접 풀어봤어요. 거기서 git merge --abort 로 "병합을 통째로 되돌리는" 안전망도 살짝 맛봤죠. 기억나시나요?

오늘은 그 안전망을 통째로 배웁니다. 사실 git 을 처음 쓰는 분들이 가장 겁내는 게 바로 이거예요. "잘못 고치면 어떡하지", "커밋을 잘못 찍었는데 되돌릴 수 있나", "실수로 비밀번호를 커밋해버렸다" 같은 상황이요. 현업 신입들도 첫 달에 한 번씩은 식은땀을 흘리는 순간이에요.

미리 안심부터 시키고 갈게요. git 은 되돌리기에 관한 한 거의 모든 것을 준비해뒀어요. 고치던 변경을 버리는 것, 잘못 찍은 커밋을 되감는 것, 심지어 "날려버린 줄 알았던 커밋" 까지 되살리는 구조대가 있어요. 오늘 끝나면 여러분은 "어, 실수해도 되돌릴 수 있네?" 하는 든든함을 손에 넣게 돼요. 그 믿음이 있어야 과감하게 실험할 수 있거든요. 같이 천천히 가요.

텍스트
   오늘의 여정 — 실수를 되돌리는 안전망

   ① 되돌리기, 그 전에 지도 한 장 — 무엇을 어디로
   ② 커밋 전이라면 마음 편히 — git restore
   ③ 방금 찍은 커밋이 마음에 안 들 때 — git commit --amend
   ④ 커밋을 통째로 되감기 — git reset 세 가지
   ⑤ 이미 남과 공유한 커밋이라면 — git revert
   ⑥ 날린 줄 알았던 커밋의 구조대 — git reflog
   ⑦ 비밀번호는 아예 안 들인다 — .gitignore

①에서 되돌리기 명령들의 전체 지도를 깔고, ②③에서 가벼운 되돌리기(고치던 변경·마지막 커밋)를 익혀요. ④⑤에서 커밋을 되감는 두 방법(reset·revert)을 배우고, ⑥에서 잃어버린 커밋을 되살리는 구조대를 만나요. ⑦에서 비밀번호 같은 건 애초에 안 들이는 법으로 마무리합니다.

💡 오늘 수업의 핵심 — "되돌리기는 '아직 커밋했나, 안 했나' 와 '나 혼자 쓰나, 남과 공유했나' 두 질문으로 갈린다. 커밋 전이면 git restore, 내 커밋이면 git reset, 공유한 커밋이면 git revert. 그리고 잘못 날려도 git reflog 라는 구조대가 있다."

🎯 학습 목표

  • 커밋 전 변경은 git restore 로, 방금 찍은 커밋은 git commit --amend 로 가볍게 되돌립니다.
  • 커밋을 되감는 git reset 세 가지(soft/mixed/hard)를 구분하고, 공유한 커밋은 git revert 로 안전하게 취소하는 기준을 잡습니다.
  • 잘못 되돌려 잃은 커밋을 git reflog 로 되살리고, .gitignore 로 비밀·산출물을 처음부터 추적에서 뺍니다.

Step 1: "되돌리기, 그 전에 지도 한 장 — 무엇을 어디로"

본격적으로 명령을 치기 전에, 지도 한 장을 먼저 깔게요. 되돌리기 명령이 오늘 여러 개 나오는데, 처음엔 "이건 언제 쓰고 저건 언제 쓰지?" 하고 헷갈리기 딱 좋거든요. 그런데 사실 딱 두 가지 질문만 던지면 거의 다 정리돼요.

첫째, "아직 커밋했나, 안 했나?" 둘째, "나 혼자 쓰는 커밋인가, 남과 공유한 커밋인가?" 이 두 질문에 따라 쓸 명령이 갈려요.

A-1 에서 깔았던 그림, 기억하시죠? Git 은 파일을 세 영역으로 나눠 다뤄요. 되돌리기도 결국 "이 세 영역 중 어디를, 어디로 되돌리느냐" 의 이야기예요.

텍스트
   되돌리기 명령 지도 — 가벼운 것부터 신중한 것까지

   [ 작업 폴더 ]  ── git add ──  [ 스테이징 ]  ── git commit ──  [ 저장소(커밋) ]
     고치는 중                      담아둔 변경                       박제된 역사

   아직 커밋 안 했다면
     git restore <파일>          고치던 변경을 버리고 마지막 커밋 상태로
     git restore --staged <파일>  add 로 담은 것을 도로 빼기 (고친 내용은 유지)

   이미 커밋했다면
     git commit --amend          방금 찍은 '마지막' 커밋만 살짝 고치기
     git reset                   커밋을 통째로 되감기 (나 혼자 쓰던 커밋)
     git revert                  커밋을 취소하는 새 커밋 얹기 (남과 공유한 커밋)

   그 밖의 안전장치
     git reflog                  잘못 되돌려 잃은 커밋을 되살리는 구조대
     .gitignore                  비밀·산출물을 애초에 추적 안 함 (예방)

오늘은 이 지도를 위에서 아래로, 가벼운 것부터 신중한 것 순서로 하나씩 익혀나가요. 위쪽(작업 폴더·스테이징 되돌리기)은 마음 편히 써도 되는 가벼운 명령이고, 아래로 갈수록(특히 git reset --hard) 신중하게 다뤄야 하는 명령이에요. 그래도 걱정 마세요. 마지막 git reflog 가 "그래도 날렸을 때" 를 위한 구조대로 늘 대기하고 있으니까요.

💡 한 줄 정리

되돌리기는 "아직 커밋 안 했으면 git restore, 이미 커밋했으면 reset/revert, 그래도 잃어버리면 git reflog" 로 갈리고, 결국 작업 폴더·스테이징·저장소 세 영역 중 어디를 되돌리느냐의 문제다.

🙋 학생 질문 — "튜터님, 되돌리기 명령이 이렇게 많아요? 하나로 다 안 되나요?"

처음엔 그렇게 느껴질 수 있어요. 그런데 명령이 나뉘어 있는 게 사실은 우리를 지켜주는 거예요.

생각해보면 "되돌린다" 는 상황이 다 달라요. 방금 고치다 만 걸 버리는 것과, 예전에 찍어 이미 동료에게 보낸 커밋을 취소하는 건 위험도가 완전히 다르잖아요? 만약 명령이 하나뿐이라면, 가벼운 되돌리기를 하려다 실수로 공유한 역사까지 날려버릴 수 있어요.

git 은 그래서 "이건 가벼우니 마음 편히(restore)", "이건 신중하게(reset)", "이건 공유한 거니 안전하게(revert)" 하고 상황별로 도구를 나눠놨어요. 오늘 이 지도만 머리에 넣어두면, 막상 실수했을 때 "아, 이 상황엔 이거구나" 하고 침착하게 고를 수 있어요.


Step 2: "커밋 전이라면 마음 편히 — git restore"

지도를 깔았으니 가장 가벼운 것부터 가볼게요. 지난 시간 만든 연습 저장소(my-diary)에서 이어가요. 가장 흔한 상황이에요. 파일을 고치다가 "아, 이거 아니다. 그냥 없던 일로 하고 싶다" 싶을 때요. 아직 커밋도 안 했고, add 도 안 한 상태죠.

직접 만들어봐요. 일기에 실수로 한 줄을 적었다고 해봐요.

Bash
echo "이 줄은 실수로 적었다. 지우고 싶다." >> diary.txt
git status
# 출력 예시:
# Changes not staged for commit:
#   modified:   diary.txt

이 고친 걸 통째로 버리고, 마지막 커밋 때의 깨끗한 모습으로 되돌리고 싶어요. 이때 쓰는 게 git restore 예요.

Bash
git restore diary.txt
git status
# 출력 예시:
# On branch main
# nothing to commit, working tree clean

diary.txt 가 고치기 전 모습으로 싹 돌아왔어요. 작업 폴더가 다시 깨끗해졌죠. 방금 적은 그 줄은 사라졌어요.

add 까지 했다면 — git restore --staged

이번엔 한 걸음 더 간 상황이에요. 고친 다음 git add 까지 해서 스테이징에 담았는데, "어, 이건 이번 커밋에 넣을 게 아닌데?" 싶을 때요. 담은 것만 도로 빼고 싶은 거죠.

Bash
echo "임시 메모 (아직 커밋할 단계 아님)" >> diary.txt
git add diary.txt
git status
# 출력 예시:
# Changes to be committed:
#   modified:   diary.txt        ← 스테이징(장바구니)에 담긴 상태

여기서 --staged 옵션을 붙이면, 장바구니에서 빼기만 하고 고친 내용 자체는 작업 폴더에 그대로 남겨둬요.

Bash
git restore --staged diary.txt
git status
# 출력 예시:
# Changes not staged for commit:
#   modified:   diary.txt        ← 장바구니에서 빠졌지만, 고친 내용은 작업 폴더에 남음

두 경우를 그림으로 비교하면 이래요.

텍스트
   git restore <파일>          : 작업 폴더의 변경을 버린다 (마지막 커밋 모습으로)
       [작업 폴더] ── 되돌림 ── [스테이징/저장소]

   git restore --staged <파일> : add 한 것만 장바구니에서 뺀다 (고친 내용은 유지)
       [스테이징] ── 도로 빼기 ── [작업 폴더]

지난 시간 잠깐 얘기했죠? 예전엔 git checkout 하나가 너무 많은 일을 해서 헷갈렸어요. 그래서 요즘 git 은 "브랜치 옮기기" 는 git switch, "파일 되돌리기" 는 git restore 로 또렷하게 나눴어요. 오늘 배우는 restore 가 바로 그 "파일 되돌리기" 담당이에요.

⚠️ 한 가지만 주의해요. git restore <파일> 로 버린 변경은 아직 커밋 안 한 변경이라, 한번 버리면 되살리기 어려워요. 오늘 뒤에 배울 reflog 구조대도 "커밋한 것" 만 구할 수 있거든요. 그러니 restore 로 버리기 전엔 "정말 버려도 되나?" 한 번만 확인하는 습관을 들여요.

한 걸음 더 — 특정 과거 커밋 때의 그 파일 모습으로 되돌리고 싶을 땐 git restore --source=<커밋해시> <파일> 을 써요. 파일 하나만 콕 집어 그 시점 모습으로 가져오는 "파일 타임머신" 이에요(커밋 해시는 git log 로 확인해요).

GUI 로는 — VS Code 의 Source Control 패널에서 고친 파일에 마우스를 올리면 되돌리기 아이콘(Discard Changes)이 떠요. 그게 git restore 고, 스테이징에 담은 걸 다시 내리는 "Unstage Changes" 가 git restore --staged 예요.

💡 한 줄 정리

아직 커밋 전이라면 git restore <파일> 로 고치던 변경을 버려 마지막 커밋 모습으로 되돌리고, add 까지 했다면 git restore --staged <파일> 로 장바구니에서만 도로 뺄 수 있다.

🙋 학생 질문 — "튜터님, restore 랑 reset 은 뭐가 다른가요? 둘 다 되돌리기잖아요."

아주 좋은 질문이에요. 헷갈리기 쉬운 한 쌍이거든요. 한마디로 "파일을 되돌리느냐, 커밋을 되돌리느냐" 의 차이예요.

git restore파일을 다뤄요. "이 파일의 고친 내용을 버리고 싶다", "이 파일을 장바구니에서 빼고 싶다" 처럼 아직 커밋 안 한 변경을 정리하는 도구예요. 역사(커밋)는 건드리지 않아요.

git reset커밋을 다뤄요. "이미 찍은 커밋을 통째로 되감고 싶다" 처럼 역사를 움직이는 도구죠. 그래서 더 신중해야 하고, 바로 다음다음 Step 에서 따로 배워요. 지금은 "고치던 파일 정리는 restore, 커밋 되감기는 reset" 정도로만 기억해두면 충분해요.


Step 3: "방금 찍은 커밋이 마음에 안 들 때 — git commit --amend"

이번엔 한 걸음 더 나아가요. 커밋을 이미 찍었는데, 바로 직후에 "앗" 하는 순간이에요. 두 가지가 흔해요. 커밋 메시지에 오타를 냈거나, 커밋에 넣어야 할 파일 하나를 깜빡 빠뜨렸을 때.

새 커밋을 또 찍어서 "오타 수정" 같은 걸 남기긴 좀 그렇죠? 역사가 지저분해지니까요. 이럴 때 마지막 커밋 하나를 살짝 고쳐 끼우는git commit --amend 예요.

먼저 메시지 오타부터요. 커밋을 하나 찍는데 메시지를 잘못 적었다고 해봐요.

Bash
echo "2026-06-15 오늘의 일기" >> diary.txt
git add diary.txt
git commit -m "일기에 오늘 날자 추가"      # '날짜'를 '날자'로 잘못 적음

메시지에 오타("날자")가 났어요. --amend 로 메시지만 새로 줘서 고쳐요.

Bash
git commit --amend -m "일기에 오늘 날짜 추가"
# 출력 예시:
# [main 7f3a9c2] 일기에 오늘 날짜 추가
#  1 file changed, 1 insertion(+)

이번엔 파일을 깜빡한 경우예요. 커밋을 찍고 나서 "아, 이 파일도 같이 넣었어야 했는데" 싶을 때요. 빠뜨린 파일을 add 한 다음, 메시지는 그대로 두고(--no-edit) 마지막 커밋에 끼워 넣어요.

Bash
echo "맑음" > weather.txt
git add weather.txt
git commit --amend --no-edit
# (메시지는 그대로, 빠뜨린 weather.txt 가 마지막 커밋에 함께 들어감)

여기서 중요한 걸 하나 짚을게요. --amend 는 마지막 커밋을 "수정" 하는 것처럼 보이지만, 사실은 마지막 커밋을 떼어내고 새 커밋으로 갈아 끼우는 거예요. 그래서 커밋의 이름표(해시)가 바뀌어요.

텍스트
   amend 전:  A───B───C         main (C: 메시지에 오타)
   amend 후:  A───B───C'        main (C 는 C' 로 교체, 해시가 바뀜)

⚠️ 그래서 딱 하나 기억할 게 있어요. --amend아직 나만 가진(공유 전) 마지막 커밋 에만 쓰세요. 이미 남에게 보낸(올린) 커밋을 amend 로 갈아 끼우면, 내 역사와 동료의 역사가 어긋나서 골치 아파져요. 이 "공유한 커밋은 함부로 고치지 않는다" 는 약속은, 나중에 저장소를 인터넷에 올려 협업할 때 아주 중요해져요. 지금은 "amend 는 방금 찍은 내 커밋에만" 정도로 담아두면 돼요.

GUI 로는 — GitHub Desktop 은 커밋 직후 "Amend last commit" 항목이 떠요. VS Code 도 Source Control 의 ... 메뉴에서 "Commit > Amend Last Commit" 으로 똑같이 할 수 있어요.

💡 한 줄 정리

방금 찍은 마지막 커밋의 메시지 오타나 빠뜨린 파일은 git commit --amend 로 새 커밋을 만들지 않고 고쳐 끼울 수 있지만, 해시가 바뀌므로 아직 공유 전인 내 커밋에만 쓴다.

🙋 학생 질문 — "튜터님, amend 하면 원래 커밋(C)은 어디로 사라지나요?"

날카로운 질문이에요. 결론부터 말하면, 원래 커밋 C곧바로 완전히 사라지는 게 아니에요. main 이름표가 새 커밋 C' 를 가리키도록 옮겨갔을 뿐, C 자체는 잠시 git 안에 남아 있어요.

이렇게 "이름표가 안 가리키게 된 커밋" 도 한동안은 되살릴 수 있어요. 바로 오늘 Step 6 에서 배울 git reflog 가 그걸 찾아주는 구조대거든요. 그러니 amend 를 했다가 "아 역시 원래대로" 싶어도 방법이 있어요.

다만 이건 "그래도 되살릴 수 있다" 는 안심 장치일 뿐, 시간이 많이 지나면 git 이 안 쓰는 커밋을 청소하기도 해요. 그러니 amend 는 신중히 하되, 실수해도 너무 겁먹지는 마세요. 구조대가 있으니까요.


Step 4: "커밋을 통째로 되감기 — git reset 세 가지"

이제 좀 더 묵직한 도구예요. git restore 가 "파일" 을 되돌렸다면, git reset"커밋" 을 통째로 되감아요. "마지막 커밋 자체를 없던 일로 하고 싶다" 같은 상황이죠.

reset 을 이해하는 핵심은 이거예요. reset 은 현재 브랜치 이름표(HEAD)를 과거 커밋으로 되감는데, 그때 작업 폴더와 스테이징을 어디까지 함께 되돌릴지 를 세 가지 중에 고르는 거예요. 그게 --soft, --mixed, --hard 예요.

먼저 그림으로 "이름표를 되감는다" 가 뭔지 봐요. 커밋이 셋 있는 상태에서 마지막 커밋을 되감으면요.

텍스트
   reset 전:  A───B───C         main (HEAD)
   reset 후:  A───B             main (HEAD)
                   (C 는 더 이상 가리켜지지 않지만, 사라진 건 아니다  Step 6 reflog)

HEAD~1 은 "지금 커밋에서 한 칸 뒤" 라는 뜻이에요. (~2 면 두 칸 뒤고요.) 그럼 세 가지가 어떻게 다른지 직접 봐요. 먼저 가장 부드러운 --soft 예요.

Bash
git log --oneline
# 출력 예시:
# 7f3a9c2 (HEAD -> main) 실험적인 줄 추가
# 3c4d5e6 일기 둘째 날
# 0f9e8d7 첫 일기

git reset --soft HEAD~1
git status
# 출력 예시:
# Changes to be committed:
#   modified:   diary.txt        ← 커밋만 풀렸고, 변경은 '담긴 상태'로 그대로!

--soft커밋만 풀어요. 마지막 커밋이 했던 변경은 고스란히 스테이징에 남아 있죠. "커밋 메시지만 다시 쓰고 싶다" 거나 "커밋 두 개를 하나로 합치고 싶다" 할 때 좋아요.

그럼 옵션을 안 붙이거나 --mixed 를 쓰면(이게 기본값이에요), 한 단계 더 풀려요. 커밋도 풀고 add 도 풀어서, 변경이 작업 폴더 로 내려와요. 마지막으로 --hard 는 작업 폴더까지 전부 되돌려서, 그 변경 자체가 사라져요. 세 가지를 한눈에 비교하면 이래요.

옵션 저장소(커밋) 스테이징 작업 폴더
--soft 되감김 그대로 그대로
--mixed (기본값) 되감김 되감김 그대로
--hard 되감김 되감김 되감김 ⚠️

--hard 는 직접 해보면 이렇게 깨끗이 비워져요.

Bash
git reset --hard HEAD~1
# 출력 예시:
# HEAD is now at 3c4d5e6 일기 둘째 날
# (마지막 커밋이 했던 변경이 작업 폴더에서도 싹 사라짐)

⚠️ git reset --hard 는 오늘 배우는 명령 중 가장 신중하게 다뤄야 해요. 작업 폴더의 변경까지 지우거든요. 특히 아직 커밋 안 한 변경이 있는 상태에서 --hard 를 치면 그건 되살리기 어려워요(구조대 reflog 도 커밋한 것만 구해요). 그래도 너무 겁낼 필요는 없어요. --hard 로 날린 게 "이미 커밋했던 것" 이라면, 다음 Step 의 reflog 로 되살릴 수 있으니까요.

GUI 로는 — reset 은 위험할 수 있어서 GUI 가 일부러 깊숙이 숨겨놔요. GitHub Desktop·VS Code 모두 커밋 목록에서 특정 커밋을 우클릭해 "Reset to this commit" 으로 할 수 있는데, 입문 단계에선 의미를 정확히 알 때만 쓰는 걸 권해요.

💡 한 줄 정리

git reset 은 브랜치 이름표를 과거 커밋으로 되감으며, --soft(커밋만)·--mixed(커밋+add, 기본값)·--hard(전부, 작업 폴더까지) 중 "어디까지 함께 되돌릴지" 를 고르는 명령이고, --hard 는 변경을 지우니 가장 신중해야 한다.

🙋 학생 질문 — "튜터님, soft·mixed·hard 중에 보통 뭘 써야 하나요?"

상황마다 다르지만, 입문 단계에선 이렇게 기억하면 편해요.

기본은 옵션 없이 쓰는 --mixed 예요. "마지막 커밋을 풀고, 내용은 작업 폴더에 둔 채 다시 손보고 싶다" 는 가장 흔한 경우에 맞아요. 커밋을 풀되 고친 내용은 살아 있으니 안전하죠.

--soft 는 "내용은 그대로 담긴 채로, 커밋만 다시 묶고 싶다" 할 때예요. 예를 들어 자잘한 커밋 여러 개를 하나로 합치거나 메시지를 다시 쓸 때 좋아요.

--hard 는 "이 변경을 정말로 다 버리겠다" 는 확신이 있을 때만 써요. 가장 강력한 만큼 가장 신중하게요. 헷갈릴 땐 일단 --mixed(기본)로 풀어서 내용을 보존해두는 게 안전한 선택이에요.


Step 5: "이미 남과 공유한 커밋이라면 — git revert"

reset 을 배웠으니, 한 가지 중요한 한계를 짚어야 해요. reset 은 역사를 "지워서" 되감는 거예요. 나 혼자 쓰는 저장소라면 아무 문제 없어요. 그런데 만약 그 커밋을 이미 남과 공유했다면(인터넷에 올려 동료가 받아갔다면) 이야기가 달라져요.

내가 reset 으로 그 커밋을 지워버리면, 내 역사와 동료의 역사가 서로 어긋나요. "어, 분명 있던 커밋이 사라졌네?" 하고 협업이 꼬이는 거죠. 그래서 이미 공유한 커밋을 되돌릴 땐 reset 대신 git revert 를 써요.

git revert 는 커밋을 지우지 않아요. 대신 그 커밋과 정반대되는 변경을 '새 커밋' 으로 얹어서 결과적으로 취소된 모습을 만들어요. 원래 커밋은 역사에 그대로 남고, "이걸 취소했다" 는 사실까지 새 커밋으로 정직하게 기록되는 거죠. 직접 해봐요.

Bash
git log --oneline
# 출력 예시:
# 9z8y7x6 (HEAD -> main) 잘못된 내용을 커밋해버림
# 3c4d5e6 일기 둘째 날
# 0f9e8d7 첫 일기

git revert 9z8y7x6
# (편집기가 열리며 'Revert "잘못된 내용을 커밋해버림"' 메시지를 제안 — 그대로 저장)
# 출력 예시:
# [main 1c2d3e4] Revert "잘못된 내용을 커밋해버림"
#  1 file changed, 1 deletion(-)

이제 역사를 보면, 원래 커밋도 남아 있고 그 위에 "취소 커밋" 이 새로 얹혔어요.

Bash
git log --oneline
# 출력 예시:
# 1c2d3e4 (HEAD -> main) Revert "잘못된 내용을 커밋해버림"   ← 취소가 새 커밋으로 남음
# 9z8y7x6 잘못된 내용을 커밋해버림                          ← 원래 커밋도 그대로 보존
# 3c4d5e6 일기 둘째 날

reset 과 revert 가 어떻게 다른지 그림으로 나란히 봐요.

텍스트
   reset  : 커밋 C 를 되감아 없앤다 (역사를 고쳐 씀)
       A───B───C   ─   A───B

   revert : C 를 취소하는 새 커밋 R 을 얹는다 (C 는 남고, R 이 무효화)
       A───B───C   ─   A───B───C───R

둘을 언제 쓰는지 표로 정리하면 기준이 분명해져요.

git reset git revert
방식 커밋을 되감아 없앰 반대 변경을 새 커밋으로 추가
역사 고쳐 씀 (지움) 그대로 보존 (+ 취소 기록)
어울리는 곳 아직 안 올린 내 커밋 이미 남과 공유한 커밋

지금은 혼자 연습 저장소를 쓰니 둘 다 자유롭게 써도 괜찮아요. 그런데 이 감각을 미리 들여두는 게 중요해요. 다음 시간부터 저장소를 인터넷에 올려 협업하게 되면, "공유한 커밋은 reset 으로 지우지 않고 revert 로 취소한다" 가 사고를 막는 철칙이 되거든요. (공유한 역사를 강제로 고쳐 쓰는 일이 왜 위험한지, 그걸 다루는 안전한 방법은 협업과 히스토리 정리를 더 배우는 뒷부분에서 깊게 다뤄요.)

GUI 로는 — GitHub Desktop·VS Code 모두 커밋 목록에서 특정 커밋을 우클릭해 "Revert Changes (in commit)" 를 고르면 방금 한 revert 와 똑같이 취소 커밋이 하나 생겨요.

💡 한 줄 정리

git revert 는 커밋을 지우지 않고 반대 변경을 새 커밋으로 얹어 안전하게 취소하므로, 이미 남과 공유한 커밋을 되돌릴 땐 역사를 고쳐 쓰는 reset 대신 revert 를 쓴다.

🙋 학생 질문 — "튜터님, revert 하면 잘못된 커밋이 역사에 그대로 남잖아요. 지저분하지 않나요?"

정확히 그 점이 revert 의 핵심이에요. 언뜻 "깔끔하게 지우는 게 낫지 않나?" 싶지만, 협업에선 "있었던 일을 지우는 것" 보다 "취소했다는 사실을 남기는 것" 이 훨씬 안전하고 정직해요.

이유는 두 가지예요. 첫째, 남과 공유한 커밋을 지우면 내 역사와 동료의 역사가 어긋나 협업이 꼬여요. revert 는 커밋을 그대로 두니 그런 충돌이 없죠.

둘째, 나중에 "왜 이 변경이 취소됐지?" 를 추적하기 좋아요. 원래 커밋도, 취소한 커밋도 다 남아 있으니 "이런 시도를 했다가 이래서 되돌렸구나" 하는 맥락이 보이거든요. 깔끔해 보이려고 역사를 지우는 것보다, 사실을 그대로 남기는 게 팀에선 더 큰 가치예요.


Step 6: "날린 줄 알았던 커밋의 구조대 — git reflog"

자, 오늘의 클라이맥스예요. 지난 시간 예고했던 git 의 진짜 안전망, git reflog 입니다. 이걸 알고 나면 git 이 한결 덜 무서워질 거예요.

Step 4 에서 git reset --hard 로 커밋을 날렸을 때, 제가 "사라진 게 아니다" 라고 했죠? 그 비밀이 여기 있어요. git 은 우리가 모르는 사이에 HEAD 가 움직인 모든 발자취 를 따로 기록해둬요. 브랜치를 옮기든, 커밋을 찍든, reset 으로 되감든, amend 로 갈아 끼우든 — 그 모든 순간이 reflog 에 남아요. 그래서 "이름표가 안 가리키게 된 커밋" 도 한동안은 여기서 찾아 되살릴 수 있어요.

아까 reset --hard HEAD~1 로 날린 커밋을 되살려봐요. 먼저 발자취를 펼쳐봐요.

Bash
git reflog
# 출력 예시:
# 3c4d5e6 (HEAD -> main) HEAD@{0}: reset: moving to HEAD~1
# 7f3a9c2 HEAD@{1}: commit: 실험적인 줄 추가      ← 날린 줄 알았던 그 커밋!
# 3c4d5e6 HEAD@{2}: commit: 일기 둘째 날
# 0f9e8d7 HEAD@{3}: commit (initial): 첫 일기

보이시나요? HEAD@{1} 자리에 아까 날린 커밋(7f3a9c2)이 멀쩡히 남아 있어요. HEAD@{1} 은 "한 단계 전의 HEAD 위치" 라는 뜻이에요. 이제 그 지점으로 다시 이름표를 옮기면 커밋이 되살아나요.

Bash
git reset --hard HEAD@{1}
# 출력 예시:
# HEAD is now at 7f3a9c2 실험적인 줄 추가
# (날린 줄 알았던 커밋이 되살아남!)

해시로 직접 가도 돼요(git reset --hard 7f3a9c2). 더 안전하게 하고 싶으면, 되살릴 커밋을 아예 새 가지로 떠둘 수도 있어요(git switch -c rescued 7f3a9c2). 그림으로 보면 이런 일이 일어난 거예요.

텍스트
   현재:  A───B           main (HEAD), reset --hard 로 B 로 되감긴 상태
              \
               C          잃은 줄 알았던 커밋, reflog 에 HEAD@{1} 로 남음

   git reset --hard HEAD@{1}   ─   main 이 다시 C 를 가리켜 되살아남

이게 바로 git 이 무섭지 않은 이유예요. 커밋만 해뒀다면, 어지간한 실수는 reflog 가 되돌려줘요. "잘못해도 되돌릴 수 있다" 는 이 믿음이 있어야 우리가 과감하게 가지를 따고, 실험하고, 되감아볼 수 있는 거죠.

⚠️ 단, 구조대도 못 구하는 게 있어요. 첫째, 애초에 커밋한 적 없는 변경이에요(작업 폴더에서 고치다 --hard 로 날린 것 등). reflog 는 "커밋" 의 발자취라 커밋 안 한 건 기록이 없어요. 둘째, reflog 는 내 컴퓨터에만 있고(원격엔 안 가요) 시간이 한참 지나면 git 이 청소하기도 해요. 그래서 결국 답은 하나예요 — 작은 단위로 자주 커밋하기. A-1 에서 좋은 커밋을 강조한 이유가 여기서도 빛을 발하죠.

GUI 로는 — reflog 는 GUI 에 잘 안 보여서, 사실 이 구조 작업이야말로 명령어(CLI)의 진가가 드러나는 순간이에요. "GUI 로 다 되는데 왜 명령어를 배워요?" 의 답이 바로 이런 데 있어요.

💡 한 줄 정리

git reflogHEAD 가 움직인 모든 발자취를 기록해 두므로, reset 이나 amend 로 잃은 줄 알았던 커밋도 HEAD@{n} 이나 해시로 되살릴 수 있다. 단 커밋 안 한 변경은 못 구하니, 자주 커밋하는 습관이 최선의 안전망이다.

🙋 학생 질문 — "튜터님, 그럼 git 에선 영영 잃어버리는 게 없는 건가요?"

거의 그렇지만, 딱 두 가지 예외가 있어요. 이걸 알면 "무엇이 안전하고 무엇이 위험한지" 가 또렷해져요.

한 번이라도 커밋한 것은 거의 다 구할 수 있어요. 이름표가 안 가리키게 됐어도 reflog 에 발자취가 남아 있으니까요. reset, amend, 심지어 브랜치를 잘못 지운 것도 대부분 되살릴 수 있어요.

반대로 못 구하는 건 두 가지예요. 첫째, 한 번도 커밋 안 한 변경. 작업 폴더에서 고치다가 restorereset --hard 로 날린 건 reflog 에 없어요. 둘째, 시간이 아주 많이 지나 청소된 것. reflog 도 영원하진 않거든요.

그래서 결론은 늘 같아요. "되돌릴 수 있다" 는 안전망을 진짜로 누리려면, 의미가 생길 때마다 작게 자주 커밋 하는 거예요. 커밋만 해두면 reflog 가 지켜주니까요.


Step 7: "비밀번호는 아예 안 들인다 — .gitignore"

마지막은 되돌리기와 짝을 이루는 예방 이야기예요. 지금까지는 "실수한 걸 되돌리는" 법을 배웠다면, 이번엔 "애초에 실수가 안 생기게 막는" 법이에요.

현업 신입이 정말 자주 겪는 사고가 있어요. 비밀번호나 API 키 같은 비밀 정보를 코드에 적은 채로 커밋 해버리는 거예요. 혼자 쓸 땐 별일 아닌 것 같지만, 다음 시간에 배울 것처럼 이걸 인터넷(GitHub)에 올리면 큰일이 나요. 공개된 저장소를 자동으로 훑는 봇들이 키를 그대로 가져가버리거든요. 다들 한 번씩 식은땀 흘리는 사고예요. 그런데 오늘 이걸 배우면 안 무서워요.

해법은 .gitignore 라는 파일이에요. "이 파일들은 git 이 추적하지 마" 라고 적어두는 목록이죠. 연습 저장소에 비밀 파일과 빌드 산출물이 있다고 해봐요.

Bash
ls
# 출력 예시:
# diary.txt  secret.txt  .env  build/

secret.txt.env 에는 비밀번호가 들었고, build/ 는 프로그램이 자동으로 만들어내는 산출물이라 굳이 역사에 남길 필요가 없어요. 저장소 폴더에 .gitignore 파일을 만들고 이렇게 적어요.

텍스트
# 비밀 정보 — 절대 커밋 금지
secret.txt
.env

# 자동 생성되는 산출물 — 역사에 안 남김
build/
*.log

*.log 처럼 * 를 쓰면 "확장자가 .log 인 모든 파일" 을 뜻하고, build/ 처럼 / 로 끝내면 폴더 전체를 가리켜요. # 으로 시작하는 줄은 사람이 읽는 주석이고요. 이제 상태를 보면요.

Bash
git status
# 출력 예시:
# Untracked files:
#   .gitignore
#   (secret.txt, .env, build/ 는 목록에 아예 안 보임 — git 이 무시하는 중!)

비밀 파일들이 목록에서 싹 빠졌죠? 이제 실수로 git add . 를 해도 그 파일들은 안 담겨요. .gitignore 자체는 팀과 공유해야 하니 이건 커밋해둬요.

Bash
git add .gitignore
git commit -m ".gitignore 추가: 비밀 파일과 빌드 산출물 제외"

이미 커밋해버린 비밀 파일이라면 — git rm --cached

한 가지 함정이 있어요. .gitignore 는 "아직 추적 안 하는" 파일만 막아줘요. 이미 한 번 커밋해버린 파일은 .gitignore 에 적어도 계속 추적돼요. 이미 들여놓은 건 따로 빼줘야 하죠.

Bash
git rm --cached secret.txt
# (추적만 중단해요. --cached 라서 작업 폴더의 실제 파일은 안 지워져요.)
git commit -m "secret.txt 를 추적에서 제외"

--cached 가 핵심이에요. git 의 추적 목록에서만 빼고, 내 컴퓨터의 실제 파일은 그대로 둬요(파일은 계속 써야 하니까요).

참고로 파일을 git 으로 다룰 때, 아예 지울git rm 파일(추적에서 빼고 실제 파일도 삭제), 이름을 바꿀git mv 옛이름 새이름 을 쓰면 그 변경이 깔끔하게 추적돼요. 그냥 운영체제에서 지우거나 이름을 바꾼 뒤 git add -A 로 담아도 결과는 같고요.

⚠️ 솔직하게 한 가지 더 짚을게요. 이미 커밋해서 인터넷에 올린 비밀번호는, .gitignoregit rm --cached 만으로는 과거 커밋에서 깨끗이 지워지지 않아요. 역사에 남아 있거든요. 그래서 진짜로 키가 유출됐다면 정답은 "그 키를 무효화하고 새로 발급받는 것" 이에요. 겁주려는 게 아니라, 그만큼 처음부터 .gitignore 로 안 들이는 게 최고의 예방 이라는 걸 말하고 싶었어요. 오늘 이걸 배웠으니 여러분은 그 사고를 피할 수 있어요.

GUI 로는 — GitHub Desktop 은 변경 파일을 우클릭해 "Ignore file" 을 누르면 그 파일이 .gitignore 에 자동으로 추가돼요. 어떤 git 도구든 새 프로젝트를 시작할 때 .gitignore 부터 챙기는 게 좋은 습관이에요.

💡 한 줄 정리

.gitignore 에 적은 파일·폴더·패턴(*.log)은 git 이 추적하지 않아 비밀번호·산출물을 처음부터 들이지 않을 수 있고, 이미 커밋해버린 파일은 git rm --cached 로 추적에서 빼야 한다.

🙋 학생 질문 — "튜터님, 그럼 이미 올려버린 비밀번호는 .gitignore 로 지워지나요?"

안타깝지만 그건 안 돼요. 이 점을 꼭 정확히 알아야 사고를 막아요.

.gitignore 는 "지금부터 추적하지 마" 라는 약속이라, 이미 역사(과거 커밋)에 들어간 비밀번호는 그대로 남아 있어요. .gitignore 에 적어도, git rm --cached 로 지금부터 빼도, 과거 커밋을 들춰보면 여전히 보이죠.

그래서 정말로 비밀번호나 키가 한 번이라도 올라갔다면, 가장 확실한 답은 그 키를 즉시 무효화하고 새로 발급받는 것 이에요. 파일을 지우려 애쓰기보다, "노출된 키는 죽은 키로 만든다" 가 실무의 원칙이에요.

결국 가장 좋은 건 처음부터 안 올리는 거예요. 새 프로젝트를 시작하면 코드를 짜기 전에 .gitignore 부터 만들어 비밀 파일을 등록해두는 습관, 오늘 꼭 챙겨가세요.


마무리

오늘 우리는 git 의 진짜 든든함을 손에 넣었어요. 고치던 걸 버리고, 잘못 찍은 커밋을 되감고, 공유한 커밋을 안전하게 취소하고, 날린 줄 알았던 커밋까지 되살려봤죠. 그리고 비밀번호 같은 건 애초에 안 들이는 법까지요. 어때요, 이제 "실수하면 어쩌지" 하는 두려움이 좀 가셨나요? 그 든든함이 오늘의 가장 큰 수확이에요.

오늘 배운 핵심 세 가지

  • 💡 하나 — 커밋 전이면 마음 편히 되돌린다. 고치던 변경은 git restore, add 한 건 git restore --staged, 방금 찍은 마지막 커밋은 git commit --amend 로 가볍게 손본다.
  • 💡 둘 — 커밋 되감기엔 reset 과 revert 가 있다. 나 혼자 쓰는 커밋은 git reset(soft/mixed/hard)으로 되감고, 이미 남과 공유한 커밋은 역사를 지우지 않는 git revert 로 취소한다.
  • 💡 셋 — 그래도 잃으면 reflog, 애초에 막으려면 .gitignore. git reflog 가 잃은 커밋을 되살리는 구조대이고, .gitignore 는 비밀·산출물을 처음부터 추적에서 뺀다. "되돌릴 수 있다" 는 믿음이 과감한 실험을 가능하게 한다.

다음 시간 예고

지금까지 우리는 내 컴퓨터 안에서만 git 을 다뤘어요. 커밋하고, 가지를 치고, 되돌리고 — 인터넷 없이 혼자서요. 이제 되돌리기까지 익혔으니, 안심하고 다음 단계로 넘어갈 준비가 됐어요.

다음 시간엔 드디어 이 저장소를 인터넷(GitHub)에 올려 여럿이 함께 다뤄요. 내 저장소를 원격에 올리는 git push, 남의 저장소를 받아오는 git clone, 원격의 변화를 가져오는 git pull 까지요. 그리고 GitHub 계정을 만들 때 빠뜨릴 수 없는 보안 설정(2FA)도 함께 챙겨요. 오늘 마지막에 .gitignore 부터 챙긴 이유가 그거예요 — 인터넷에 올리기 전에 비밀이 새지 않게 막아두는 거죠. "혼자 다루기" 를 끝냈으니, 다음은 "여럿이 협업하기" 의 첫걸음이에요.


과제

오늘 배운 되돌리기는 눈으로만 봐선 절대 안 익어요. 꼭 여러분 컴퓨터의 연습 저장소에서 직접 되돌려보세요. 특히 일부러 커밋을 날렸다가 reflog 로 되살려보면, "아 진짜 되돌려지는구나" 하는 안심이 몸에 새겨져요.

[기초] restore 와 amend 로 가볍게 되돌리기

연습 저장소에서 diary.txt 에 아무 줄이나 하나 더한 뒤, git restore diary.txt 로 그 변경을 버려보세요. 작업 폴더가 깨끗해지는 걸 git status 로 확인하세요.

그다음 새 줄을 더해 일부러 오타가 있는 메시지로 커밋하세요(예: git commit -m "오늘 일기 추가함니다"). 그리고 git commit --amend -m "오늘 일기 추가합니다" 로 메시지를 고친 뒤, git log --oneline 으로 오타가 사라졌는지 확인하세요. 마지막으로, amend 로 고친 커밋의 해시가 원래와 달라졌다는 걸 한 문장으로 적어보세요.

[응용] 커밋을 날렸다가 reflog 로 되살리기

연습 저장소에 커밋을 두세 개 쌓으세요. 그런 다음 git reset --hard HEAD~1 로 마지막 커밋을 일부러 날려보세요. git log --oneline 으로 정말 사라졌는지 확인하면 가슴이 철렁할 거예요.

이제 구조대를 부를 차례예요. git reflog 로 발자취를 펼쳐, 날린 커밋이 HEAD@{1} 같은 자리에 남아 있는지 찾으세요. 그리고 git reset --hard HEAD@{1} 로 그 커밋을 되살리세요. git log --oneline 으로 되살아난 걸 확인하고, "커밋만 해뒀다면 되돌릴 수 있다" 는 게 어떤 안심을 주는지 한두 문장으로 적어보세요.

[심화] 팀 상황을 상상하며 revert 와 .gitignore 써보기

이런 팀 상황을 떠올려보세요. "이미 동료들과 공유한 커밋에 잘못된 내용이 들어가 있다는 걸 발견했다. 이걸 되돌려야 한다." 이 상황에선 resetrevert 중 무엇을 써야 할까요? 연습 저장소에서 커밋을 하나 만든 뒤 git revert 로 취소해보고, git log --oneline 에서 원래 커밋과 취소 커밋이 둘 다 남아 있는 걸 확인하세요. 그리고 "공유한 커밋엔 왜 reset 이 아니라 revert 인지" 를 한두 문장으로 적어보세요.

이어서 .gitignore 도 연습해보세요. 저장소에 secret.txt 파일을 만들어 비밀번호 한 줄을 적고, .gitignoresecret.txt 를 등록한 뒤 git status 에서 그 파일이 목록에 안 뜨는지 확인하세요. (여유가 되면, secret.txt 를 실수로 먼저 커밋한 다음 git rm --cached 로 추적에서 빼는 것까지 해보면 더 좋아요.)


생각해볼 주제

1. reset 과 revert — 왜 "공유했나" 로 갈릴까

reset 과 revert 는 둘 다 커밋을 되돌리지만, 쓰는 기준이 "이 커밋을 남과 공유했는가" 로 갈려요. 혼자 쓰는 커밋은 reset 으로 지워도 되지만, 공유한 커밋은 revert 로 취소해야 하죠. 왜 "공유" 라는 한 가지 조건이 이렇게 큰 차이를 만들까요? 역사를 "지우는 것" 과 "취소했다고 기록하는 것" 이 협업에서 각각 어떤 결과를 낳는지, 동료가 이미 받아간 역사를 내가 몰래 고쳐 쓰면 무슨 일이 벌어질지 상상하며 생각해보세요.

2. reflog 라는 구조대가 있는데도 왜 "자주 커밋" 하라고 할까

오늘 우리는 reflog 가 잃어버린 커밋을 되살려주는 걸 봤어요. 그런데 reflog 에는 분명한 한계가 있었죠 — 한 번도 커밋 안 한 변경은 못 구한다는 거요. 이 사실과 A-1 에서 배운 "작은 단위로 의미 있게 자주 커밋하라" 는 조언을 엮어보세요. 커밋을 자주 한다는 건 단순히 역사를 잘 정리하는 것을 넘어, 어떤 실용적인 안전을 주는 걸까요? "자주 커밋" 이 왜 가장 든든한 안전망인지 풀어보세요.

3. 왜 "지우기" 보다 "처음부터 안 들이기" 가 중요한가

.gitignore 를 배우며, 이미 역사에 올라간 비밀번호는 나중에 지우기가 무척 어렵다는 걸 봤어요. 한 번 커밋된 비밀은 과거 커밋에 그대로 남고, 인터넷에 공개됐다면 이미 누군가 가져갔을 수도 있죠. 이 "한번 새면 되돌리기 어렵다" 는 성질은 비밀번호뿐 아니라 어떤 일들에 또 해당될까요? 사고가 난 뒤 수습하는 것보다 처음부터 예방하는 게 훨씬 값싼 경우를, 여러분의 경험과 엮어 생각해보세요.

✅ 예시 답안정답 보기

이 문서는 A-3 「되돌리기와 히스토리 정리」의 과제와 생각해볼 주제에 대한 예시답안입니다. 정답을 외우는 용도가 아니라, 직접 손으로 쳐본 결과를 어떻게 정리하고 설명하는지 흐름을 참고하는 용도로 보세요. 특히 되돌리기는 눈으로 읽기보다 직접 날렸다가 되살려봐야 무서움이 사라집니다. 답안을 보기 전에 꼭 먼저 터미널에서 직접 되돌리고, 커밋을 날렸다가 reflog 로 구해보세요.


과제 예시답안

🎯 [과제 1 예시답안] restore 와 amend 로 가볍게 되돌리기

채점 포인트

항목 배점 기준
restore 로 변경 버리기 35% 고친 변경을 git restore 로 버리고 git status 로 작업 폴더가 깨끗해진 걸 확인했는가
amend 로 메시지 고치기 40% 오타 메시지로 커밋한 뒤 git commit --amend 로 메시지를 고쳤는가
해시 변화 설명 25% amend 후 커밋 해시가 달라졌다는 점을 한 문장으로 설명했는가

풀이 예시

먼저 restore 로 고치던 변경을 버려요.

Bash
echo "실수로 적은 줄" >> diary.txt
git status
# Changes not staged for commit:
#   modified:   diary.txt

git restore diary.txt
git status
# On branch main
# nothing to commit, working tree clean        ← 고친 게 사라지고 깨끗해짐

이제 오타가 있는 메시지로 커밋한 뒤, amend 로 고쳐요.

Bash
echo "2026-06-15 일기" >> diary.txt
git add diary.txt
git commit -m "오늘 일기 추가함니다"            # 메시지에 오타

git log --oneline
# a1b2c3d (HEAD -> main) 오늘 일기 추가함니다

git commit --amend -m "오늘 일기 추가합니다"     # 메시지 정정

git log --oneline
# e4f5a6b (HEAD -> main) 오늘 일기 추가합니다     ← 메시지가 고쳐짐

해시 변화에 대해: amend 전에는 커밋 해시가 a1b2c3d 였는데, amend 후에는 e4f5a6b 로 바뀌었어요. --amend 가 마지막 커밋을 "수정" 하는 게 아니라 새 커밋으로 갈아 끼우기 때문이에요. 그래서 같은 내용이라도 이름표(해시)가 새로 붙어요.

💡 튜터의 한마디 — 해시가 바뀐다는 게 별것 아닌 듯해도, 협업에선 아주 중요해요. 이미 남에게 보낸 커밋을 amend 하면 내 커밋의 해시와 동료가 가진 해시가 어긋나거든요. 그래서 amend 는 "아직 나만 가진 마지막 커밋" 에만 쓰는 거예요. 지금은 혼자 연습이라 마음껏 써도 되지만, 이 감각을 미리 들여두면 나중에 협업할 때 사고를 피할 수 있어요.

🎯 [과제 2 예시답안] 커밋을 날렸다가 reflog 로 되살리기

채점 포인트

항목 배점 기준
커밋 날리기 30% git reset --hard HEAD~1 로 마지막 커밋을 날리고 git log 로 사라진 걸 확인했는가
reflog 로 찾기 35% git reflog 에서 날린 커밋이 HEAD@{n} 에 남아 있는 걸 찾았는가
되살리기 + 안심 설명 35% git reset --hard HEAD@{1} 로 되살리고, 그 안심을 한두 문장으로 적었는가

풀이 예시

커밋을 쌓은 뒤, 마지막 하나를 일부러 날려봐요.

Bash
git log --oneline
# 7f3a9c2 (HEAD -> main) 셋째 줄 추가
# 3c4d5e6 둘째 줄 추가
# 0f9e8d7 첫 줄 추가

git reset --hard HEAD~1
# HEAD is now at 3c4d5e6 둘째 줄 추가

git log --oneline
# 3c4d5e6 (HEAD -> main) 둘째 줄 추가        ← 마지막 커밋이 사라짐!
# 0f9e8d7 첫 줄 추가

마지막 커밋이 사라져서 가슴이 철렁하죠? 이제 reflog 로 구조해요.

Bash
git reflog
# 3c4d5e6 (HEAD -> main) HEAD@{0}: reset: moving to HEAD~1
# 7f3a9c2 HEAD@{1}: commit: 셋째 줄 추가       ← 날린 커밋이 여기 살아 있다!
# 3c4d5e6 HEAD@{2}: commit: 둘째 줄 추가

git reset --hard HEAD@{1}
# HEAD is now at 7f3a9c2 셋째 줄 추가

git log --oneline
# 7f3a9c2 (HEAD -> main) 셋째 줄 추가          ← 되살아남!
# 3c4d5e6 둘째 줄 추가
# 0f9e8d7 첫 줄 추가

안심에 대해: reset --hard 로 분명히 날렸는데도 reflog 에 발자취가 남아 있어서 한 줄로 되살릴 수 있다는 걸 직접 보니, "커밋만 해뒀다면 어지간한 실수는 되돌릴 수 있구나" 하는 안심이 생겼어요. 덕분에 되감기나 실험을 두려워하지 않고 시도하게 돼요.

💡 튜터의 한마디 — 이 과제의 핵심은 "겁나는 명령(reset --hard)을 직접 쳐보고, 그래도 되살아나는 걸 눈으로 확인" 하는 거예요. 머리로 "reflog 가 있다" 고 아는 것과, 실제로 날렸다가 구해본 경험은 안심의 깊이가 달라요. 다만 reflog 도 "커밋한 것" 만 구한다는 점은 꼭 기억하세요. 커밋 안 한 변경은 못 구하니, 결국 가장 든든한 안전망은 "작게 자주 커밋하기" 예요.

🎯 [과제 3 예시답안] 팀 상황을 상상하며 revert 와 .gitignore 써보기

채점 포인트

항목 배점 기준
revert 로 취소 35% git revert 로 커밋을 취소하고 원래 커밋과 취소 커밋이 둘 다 남은 걸 확인했는가
reset 대신 revert 이유 30% "공유한 커밋엔 왜 revert 인지" 를 한두 문장으로 적었는가
.gitignore 적용 35% .gitignore 에 비밀 파일을 등록해 git status 에서 안 뜨게 만들었는가

풀이 예시

공유한 커밋을 되돌리는 상황이라 가정하고 revert 로 취소해요.

Bash
git log --oneline
# 9z8y7x6 (HEAD -> main) 잘못된 내용 커밋
# 3c4d5e6 둘째 줄 추가

git revert 9z8y7x6
# (편집기에서 'Revert "잘못된 내용 커밋"' 메시지 그대로 저장)
# [main 1c2d3e4] Revert "잘못된 내용 커밋"

git log --oneline
# 1c2d3e4 (HEAD -> main) Revert "잘못된 내용 커밋"    ← 취소 커밋이 새로 생김
# 9z8y7x6 잘못된 내용 커밋                            ← 원래 커밋도 그대로 남음
# 3c4d5e6 둘째 줄 추가

reset 대신 revert 인 이유: 이미 동료와 공유한 커밋이라, reset 으로 지우면 내 역사와 동료의 역사가 어긋나 협업이 꼬여요. revert 는 커밋을 지우지 않고 "취소했다" 는 새 커밋만 얹으니, 동료의 역사와 어긋나지 않으면서 안전하게 되돌릴 수 있어요.

이어서 .gitignore 로 비밀 파일을 막아요.

Bash
echo "DB_PASSWORD=mysecret123" > secret.txt
echo "secret.txt" >> .gitignore

git status
# Untracked files:
#   .gitignore
#   (secret.txt 는 목록에 안 보임 — 무시되는 중!)

git add .gitignore
git commit -m ".gitignore 추가: secret.txt 제외"

(만약 secret.txt 를 먼저 커밋해버렸다면, git rm --cached secret.txt 로 추적에서 뺀 뒤 다시 커밋하면 돼요. --cached 라서 작업 폴더의 파일은 안 지워져요.)

💡 튜터의 한마디 — 이 과제는 오늘 배운 "되돌리기" 와 "예방" 을 한 번에 묶어요. 잘못된 건 상황에 맞게 되돌리고(공유했으면 revert), 비밀은 애초에 안 들이는(.gitignore) 두 습관이 현업 사고를 크게 줄여줘요. 특히 새 프로젝트를 시작하면 코드를 짜기 전에 .gitignore 부터 만드는 습관을 꼭 들이세요. "노출된 키는 무효화가 답" 이라는 것도 함께 기억해두면, 다음 시간에 저장소를 인터넷에 올릴 때 한결 안심돼요.


생각해볼 주제 예시답안

🤔 [생각해볼 주제 1] reset 과 revert — 왜 "공유했나" 로 갈릴까

문제 상황 요약

reset 과 revert 는 둘 다 커밋을 되돌리지만, 쓰는 기준이 "이 커밋을 남과 공유했는가" 로 갈린다. 혼자 쓰는 커밋은 reset 으로 지워도 되지만, 공유한 커밋은 revert 로 취소해야 한다. 왜 "공유" 라는 한 조건이 이렇게 큰 차이를 만드는지, 역사를 지우는 것과 취소를 기록하는 것이 협업에서 각각 어떤 결과를 낳는지 풀어보는 주제다.

튜터의 가이드 및 해설

핵심은 "공유한 역사는 더 이상 나 혼자의 것이 아니다" 라는 점이다.

나 혼자 쓰는 저장소라면, 내 역사는 온전히 내 것이다. 마지막 커밋이 마음에 안 들면 reset 으로 지우고 새로 쓰면 그만이다. 아무도 그 커밋을 본 적 없으니 지워도 어긋날 상대가 없다.

그런데 그 커밋을 이미 남과 공유했다면(인터넷에 올려 동료가 받아갔다면) 사정이 달라진다. 동료의 컴퓨터에는 그 커밋이 이미 들어가 있다. 이 상태에서 내가 reset 으로 그 커밋을 지우면, 내 역사에선 사라졌는데 동료의 역사엔 남아 있는 엇갈림 이 생긴다. 다음에 서로의 작업을 합치려 할 때, git 은 "분명 있던 커밋이 한쪽엔 없네?" 하고 혼란에 빠지고, 동료의 작업이 꼬이거나 엉뚱하게 되살아나는 사고로 이어진다.

revert 는 이 문제를 정면으로 피한다. 커밋을 지우는 대신, 그 커밋을 무효화하는 새 커밋 을 하나 얹는다. 원래 커밋은 그대로 남으니 동료의 역사와 어긋나지 않고, 그 위에 "이걸 취소했다" 는 사실이 정직하게 기록된다. 모두가 같은 역사를 보면서, "이런 변경이 있었고 이런 이유로 취소됐구나" 까지 함께 추적할 수 있다.

그래서 기준은 의외로 단순하다. 아직 나만 가진 커밋은 reset 으로 자유롭게, 남이 이미 본 커밋은 revert 로 정직하게. 역사를 깔끔하게 지우고 싶은 유혹보다, 공유된 사실을 흔들지 않는 게 협업에선 늘 우선이다.

💡 핵심을 한마디로

혼자 가진 커밋은 reset 으로 지워도 어긋날 상대가 없지만, 공유한 커밋을 지우면 동료의 역사와 엇갈려 협업이 꼬인다. revert 는 커밋을 지우지 않고 취소 커밋을 얹어 모두의 역사를 일치시킨다. 그래서 "공유 전이면 reset, 공유 후면 revert" 가 협업의 철칙이다.

🤔 [생각해볼 주제 2] reflog 라는 구조대가 있는데도 왜 "자주 커밋" 하라고 할까

문제 상황 요약

reflog 는 잃어버린 커밋을 되살려주는 든든한 구조대다. 그런데 reflog 에는 분명한 한계가 있다 — 한 번도 커밋 안 한 변경은 못 구한다. 이 사실과 "작은 단위로 의미 있게 자주 커밋하라" 는 조언을 엮어, 자주 커밋하는 것이 어떤 실용적 안전을 주는지 풀어보는 주제다.

튜터의 가이드 및 해설

핵심은 "reflog 의 구조 능력은 '커밋' 이라는 경계선 안에서만 작동한다" 는 점이다.

reflog 는 강력하지만, 만능은 아니다. reflog 가 기록하는 건 HEAD 가 움직인 발자취, 즉 커밋 단위의 역사 다. 그래서 reset 으로 날린 커밋, amend 로 갈아 끼운 커밋, 심지어 잘못 지운 브랜치도 되살릴 수 있다. 하지만 한 번도 커밋한 적 없는 변경 은 reflog 에 흔적조차 없다. 작업 폴더에서 한참 고치다가 restorereset --hard 로 날려버리면, 그건 구조대도 손쓸 수가 없다.

여기서 "자주 커밋하라" 는 조언이 단순한 정리 습관을 넘어선다는 게 드러난다. 커밋은 단지 역사를 깔끔하게 남기는 게 아니라, 내 작업을 reflog 가 지켜줄 수 있는 영역 안으로 들여놓는 행위 다. 두 시간 동안 고친 내용을 커밋 없이 작업 폴더에만 두면, 그 두 시간은 어떤 안전망도 없는 맨몸 상태다. 반대로 의미가 생길 때마다 작게 커밋해두면, 매 순간이 reflog 의 보호 아래 들어간다. 실수로 무엇을 날려도 마지막 커밋으로 돌아갈 수 있다.

비유하자면 커밋은 등산할 때 박는 확보 지점(안전 고리) 같다. 고리를 자주 걸어둘수록 미끄러져도 멀리 떨어지지 않는다. 고리 없이 한참 올라가면, 한 번 미끄러질 때 그동안의 높이를 통째로 잃는다. "자주 커밋" 은 곧 "안전 고리를 촘촘히 걸어두기" 다.

그래서 A-1 에서 강조한 "작고 의미 있는 커밋" 은 깔끔함의 문제이기 이전에 생존의 문제 다. 자주 커밋하는 사람은 reflog 라는 구조대를 최대한으로 활용하는 사람이고, 그래서 가장 과감하게 실험할 수 있다.

💡 핵심을 한마디로

reflog 는 "커밋한 것" 만 되살리고, 커밋 안 한 변경은 구하지 못한다. 그래서 자주 커밋한다는 건 내 작업을 안전망 안으로 들여놓는 행위다. 등산의 안전 고리처럼, 촘촘히 커밋할수록 실수로 잃는 양이 적어진다. 자주 커밋이 곧 가장 든든한 안전망이다.

🤔 [생각해볼 주제 3] 왜 "지우기" 보다 "처음부터 안 들이기" 가 중요한가

문제 상황 요약

.gitignore 를 배우며, 이미 역사에 올라간 비밀번호는 나중에 지우기가 무척 어렵다는 걸 봤다. 한 번 커밋된 비밀은 과거 커밋에 그대로 남고, 인터넷에 공개됐다면 이미 누군가 가져갔을 수도 있다. 이 "한번 새면 되돌리기 어렵다" 는 성질이 또 어떤 일들에 해당되는지, 수습보다 예방이 값싼 경우를 생각해보는 주제다.

튜터의 가이드 및 해설

핵심은 "어떤 사고는 일어난 순간 이미 되돌릴 수 없는 영역으로 넘어간다" 는 점이다.

비밀번호 유출이 무서운 이유는 단순히 "지우기 번거로워서" 가 아니다. 한 번 인터넷에 공개된 키는, 내가 그 사실을 깨닫기도 전에 누군가 복사해 갔을 수 있다. 커밋을 지우든 저장소를 비공개로 바꾸든, 이미 빠져나간 정보 는 회수할 수 없다. 그래서 정답이 "파일을 깨끗이 지우기" 가 아니라 "그 키를 무효화하고 새로 발급받기" 인 것이다. 지우는 게 의미 없을 만큼, 유출은 일어나는 순간 끝난 일이 된다.

이런 "한번 새면 끝" 성질은 우리 주변에 흔하다. 한 번 보낸 메시지나 이메일은 상대가 읽은 뒤엔 취소해도 소용없다. 인터넷에 올린 사진은 누군가 저장해버리면 원본을 지워도 떠돈다. 말로 내뱉은 실언, 한 번 깨진 신뢰도 마찬가지다. 공통점은 "되돌리기 비용이 예방 비용보다 비교할 수 없이 크다" 는 것이다. 어떤 일은 사후 수습이 거의 불가능해서, 사고를 막는 작은 노력이 유일하게 합리적인 선택이 된다.

.gitignore 가 가르치는 교훈이 바로 이거다. 비밀번호를 커밋한 뒤 지우려 애쓰는 것보다, 새 프로젝트를 시작할 때 코드 한 줄 짜기 전에 .gitignore 부터 만드는 1분이 훨씬 값싸고 확실하다. 좋은 개발자는 "사고가 나면 어떻게 수습하지?" 만 묻지 않고, "이 사고가 아예 안 일어나게 하려면?" 을 먼저 묻는다. 되돌리기 도구를 잔뜩 배운 오늘, 역설적으로 가장 중요한 깨달음은 "되돌릴 필요 없게 처음부터 막는 게 최선" 이라는 점이다.

💡 핵심을 한마디로

유출된 비밀번호는 깨닫는 순간 이미 누가 가져갔을 수 있어, 지우기보다 키 무효화가 답이다. 보낸 메시지·올린 사진처럼 "한번 새면 되돌리기 어려운" 일은 수습 비용이 예방 비용보다 압도적으로 크다. 그래서 되돌리기 도구를 다 배운 끝에 남는 교훈은 "되돌릴 필요 없게 처음부터 막기" 다.

전체 목록 Git·GitHub