Git의 명령어…
지난번 새솔CRM 로컬-서버 동기화 이야기를 하다가, git reset --hard origin/main이 정확히 어디까지 건드리고 어디는 건드리지 않는지 궁금해졌다. 파다 보니 git clean처럼 나조차 처음 보는 명령어가 나왔고, “이거 하나 제대로 이해하려면 깃이 로컬을 몇 개의 방으로 나눠서 관리하는지부터 알아야겠구나” 싶어서 정리해봤다.
깃은 로컬을 세 개의 방으로 나눈다
깃 명령어가 헷갈리는 진짜 이유는, 명령어 이름이 아니라 “어느 방에 있는 걸 건드리는가”를 모르기 때문이다. 로컬 컴퓨터 안에서도 깃은 파일을 세 단계로 나눠서 관리한다.
새솔CRM 워크플로우 규칙인 “로컬은 git fetch origin && git reset --hard origin/main으로만 동기화, 로컬 push 금지”는 이 그림에서 맨 오른쪽 화살표(원격 → 왼쪽으로 되감기)만 쓰겠다는 뜻이다. 그리고 오늘 다룰 명령어들은 대부분 이 세 개의 방(Working / Staging / Repo) 사이에서 무슨 일이 벌어지는지에 관한 것이다.
안전한 명령어 — 읽기만 하거나, 되돌릴 수 있는 것들
git status
지금 세 방의 상태가 서로 어떻게 다른지 보여준다. 아무것도 바꾸지 않는다.
git diff
Working Directory와 마지막 커밋(또는 Staging)의 내용 차이를 줄 단위로 보여준다. git diff --staged는 Staging과 마지막 커밋의 차이를 보여준다.
git stash
지금 Working Directory에서 작업 중이던(아직 커밋 안 한) 변경사항을 “잠깐 서랍에 넣어두고” 커밋 시점 상태로 되돌린다. git stash pop으로 다시 꺼낼 수 있다. 예를 들어 로컬에서 뭔가 수정하던 중에 급하게 서버 최신본을 받아야 할 때, 수정분을 날리지 않고 잠깐 치워두는 용도로 쓴다.
주의가 필요한 명령어 — 방향에 따라 위험도가 갈리는 것들
git clean -n / git clean -fd
git clean은 깃이 한 번도 추적한 적 없는 파일(untracked)을 Working Directory에서 지워버리는 명령어다. -n(dry-run)은 “지울 예정 목록만” 보여주고 실제로는 아무것도 안 지운다. -fd는 실제로 지우는데, -f는 강제 실행, -d는 디렉토리까지 포함해서 지운다는 뜻이다.
바로 이 명령어가 지난번 질문의 답이었다. 9879.webp처럼 git add된 적 없는 파일은 reset --hard로는 안 지워지지만, git clean -fd를 실행하면 곧바로 삭제된다.
-n으로 먼저 확인할 것git reset --soft / --mixed / --hard
reset은 “커밋 위치를 과거(또는 다른 브랜치)로 옮기는” 명령어인데, 세 옵션이 건드리는 방의 범위가 다르다.
--soft: Local Repo의 커밋 위치만 이동. Staging과 Working Directory는 그대로 유지 → 커밋만 취소하고 변경 내용은 다시 add된 상태로 남김--mixed(기본값): 커밋 위치 이동 + Staging도 초기화. Working Directory는 그대로 유지 → 변경 내용은 남지만 다시 add해야 함--hard: 커밋 위치 이동 + Staging + Working Directory까지 전부 그 시점 상태로 덮어씀 → 추적 중이던 파일의 미커밋 변경 내용은 통째로 사라짐
--hard도 건드리지 않음 — 단, 같은 경로에 리모트 쪽 커밋이 새로 생기면 덮어써질 수 있음git checkout -- 파일명 / git restore 파일명
특정 파일 하나만 골라서 마지막 커밋(또는 Staging) 상태로 되돌린다. restore는 최근 버전 깃에서 checkout의 헷갈리는 역할을 분리하려고 새로 만든 명령어로, 기능은 사실상 같다.
히스토리를 대하는 태도가 다른 두 명령어
git revert vs git reset
reset은 “그 커밋이 아예 없었던 것처럼” 역사를 되감는 것이고, revert는 “그 커밋을 취소하는 새 커밋을 하나 더 쌓는” 방식이다. 이미 push해서 원격(GitHub)에 올라간 커밋이라면 reset으로 되감고 강제 push하는 건 협업 중인 다른 사람의 히스토리와 충돌하므로, 이런 경우는 revert가 안전하다.
실수했을 때의 안전망
git reflog
커밋을 지웠다고 착각하기 쉽지만, 깃은 HEAD가 이동한 모든 기록을 reflog라는 별도 로그에 상당 기간(기본 90일) 보관한다. reset --hard로 잘못 되감았더라도 git reflog로 되돌리기 직전 커밋 해시를 찾아서 git reset --hard 해시값으로 다시 살릴 수 있다.
git clean으로 지운 untracked 파일은 애초에 커밋된 적이 없어서 reflog에도 남지 않음한눈에 보는 위험도 매트릭스
| 명령어 | 영향 범위 | untracked 파일(예: 9879.webp) | 위험도 |
|---|---|---|---|
git status / git diff | 읽기만 | 영향 없음 | 안전 |
git stash | Working → 임시 저장 | 영향 없음 | 안전 |
git reset --soft/--mixed | Repo / Staging | 영향 없음 | 보통 |
git reset --hard | Repo + Staging + Working (tracked만) | 영향 없음* | 보통 |
git clean -fd | Working (untracked) | 완전 삭제 | 위험 |
git reflog | 읽기 + 복구 | 복구 불가(대상 아님) | 안전 |
* 단, 원격에 같은 경로의 파일이 새로 커밋되어 있으면 reset –hard 시 덮어써질 수 있음
결론 — 9879.webp는 언제 위험한가
정리하면, 새솔CRM 워크플로우(fetch + reset --hard만 사용, clean 미사용)를 그대로 지키는 한 로컬에만 있는 이미지 파일은 안전하다. 위험해지는 순간은 딱 두 가지뿐이다.
- 누군가(혹은 미래의 나)가 “로컬 찌꺼기 정리”를 위해
git clean -fd를 실행하는 순간 - 서버 쪽에서 우연히 같은 경로·같은 파일명으로 커밋해서 push하는 순간
이 두 가지만 의식하고 있으면, 깃의 세 개의 방 구조는 생각보다 훨씬 예측 가능하게 움직인다는 걸 이번에 다시 확인했다.