Git 기초 입문 [#1] — 설치·커밋·브랜치·원격 저장소 한 번에
이 글의 핵심
Git 명령어를 외우기 전에 커밋이 변경분이 아니라 스냅샷이라는 점을 먼저 이해하면 대부분의 동작이 자연스럽게 설명됩니다. 이 글은 시리즈 첫 편으로 파일 상태 변화, add -A와 -u의 차이, 커밋 메시지 규칙, amend와 restore로 실수를 되돌리는 법, .gitignore 작성법을 실습 순서대로 정리합니다.
[Git 실전 가이드 #1] Git 기초 입문
이 글을 읽으면 Git 설치부터 커밋·브랜치·원격 저장소 연동까지 기본 흐름을 따라 할 수 있습니다.
Git은 소프트웨어 개발에서 가장 많이 사용되는 버전 관리 시스템(VCS—파일 변경 이력을 추적하며, 이전 버전으로 되돌리거나 여러 사람이 협업할 수 있게 해 주는 도구)입니다. 코드의 변경 이력을 추적하며, 여러 사람이 협업할 수 있게 해주는 필수 도구입니다.
이 글에서는 Git의 기본 개념부터 실전에서 자주 사용하는 명령어까지, 초보자가 Git을 시작하는 데 필요한 모든 내용을 다룹니다.
처음에는 “커밋 → 푸시” 흐름만 익혀도 실제 작업에 쓸 수 있으며, 브랜치와 병합은 Git 브랜치와 병합에서 이어서 다룹니다. 명령어보다 “변경 이력을 스냅샷으로 남긴다”는 생각을 먼저 잡는 것이 중요합니다.
헷갈리기 쉬운 것: git add는 “커밋할 목록에 넣는 것”이지, 아직 서버에 올라가는 게 아닙니다. 실제로 원격 저장소에 반영되려면 git push까지 해야 합니다. 반대로 git pull은 원격의 변경을 가져와서 현재 브랜치에 합치는 것이므로, 협업 시 자주 쓰게 됩니다.
Git이란?
버전 관리가 없던 시절
여러분도 이런 경험이 있지 않나요?
Git을 사용하지 않을 때:
project_0315.zip
project_0320_수정.zip
project_0325_진짜최종.zip
project_0326_진짜진짜최종.zip
project_0327_이번진짜최종.zip
이런 방식은 다음과 같은 문제가 있습니다:
- 어떤 파일이 최신 버전인지 헷갈립니다.
- 각 버전에서 무엇이 바뀌었는지 알 수 없습니다.
- 이전 버전으로 되돌리기가 어렵습니다.
- 여러 사람이 협업하기 거의 불가능합니다. Git을 사용하면:
# 복사해 붙여넣은 뒤: 터미널에서 실행 (Git 설치 필요)
git log --oneline -5 # 최근 커밋 5개 한 줄씩 확인
git diff # 작업 디렉터리와 스테이징 차이
git branch # 현재 브랜치 목록
실행 결과: git log --oneline -5는 이미 커밋이 있는 저장소에서 최근 5개 커밋 해시와 메시지를 한 줄씩 보여 줍니다. 새 폴더에서는 먼저 git init 후 git add . → git commit -m "first"로 커밋을 하나 만든 뒤 실행해 보세요.
Git과 GitHub의 차이
초보자가 자주 혼동하는 개념입니다:
Git:
- 버전 관리 도구 (소프트웨어)
- 여러분의 컴퓨터(로컬)에 설치됩니다.
- 혼자서도 사용할 수 있습니다. GitHub:
- Git 저장소를 온라인으로 호스팅하는 서비스
- 클라우드에서 코드를 공유하고 협업합니다.
- GitLab, Bitbucket 같은 대안도 있습니다. 간단히 말하면, Git은 도구이고 GitHub는 Git을 사용하는 온라인 서비스입니다.
Git 설치 및 초기 설정
Windows
- 공식 설치 프로그램: git-scm.com/download/win에서 설치 파일을 받아 실행합니다. 기본 옵션으로도 대부분의 개발 환경에 맞습니다.
- winget(Windows 10/11):
winget install Git.Git
설치 후 Git Bash 또는 PowerShell에서 아래 설치 확인을 실행합니다.
macOS
- Homebrew:
brew install git
- Xcode Command Line Tools만 설치해도 Git이 포함됩니다: 터미널에서
xcode-select --install후 안내에 따릅니다.
Linux
배포판에 따라 패키지 관리 명령이 다릅니다.
# Ubuntu / Debian
sudo apt update && sudo apt install git
# Fedora
sudo dnf install git
# Arch Linux
sudo pacman -S git
설치 확인
git --version
예: git version 2.43.x처럼 버전이 출력되면 정상입니다.
git config 필수 설정
커밋마다 작성자 이름·이메일이 기록되므로, 처음 한 번은 전역(--global)으로 설정합니다.
git config --global user.name "표시될 이름"
git config --global user.email "[email protected]"
GitHub를 쓴다면 계정에 등록된 이메일과 맞추는 것이 좋습니다. 주소를 공개하고 싶지 않으면 GitHub 설정의 noreply 이메일을 user.email에 넣을 수 있습니다.
설정이 잘 들어갔는지 확인:
git config --global --list
특정 프로젝트만 다른 이름을 쓰려면 해당 폴더에서 --global 없이 git config user.name "..."처럼 설정하면 됩니다.
자주 쓰는 선택 설정:
git config --global init.defaultBranch main
git config --global core.editor "code --wait" # VS Code로 커밋 메시지 편집 (경로는 환경에 맞게)
SSH 키 설정 (GitHub 연동)
HTTPS URL로 git push할 때마다 인증을 묻는 대신, SSH로 연결하면 키 한 번 등록 후 편하게 쓸 수 있습니다.
- 기존 키가 있는지 확인:
ls -al ~/.ssh - 없으면 생성(이메일은 본인 것으로):
ssh-keygen -t ed25519 -C "[email protected]"
프롬프트가 나오면 기본 경로(~/.ssh/id_ed25519)를 쓰며, passphrase는 분실에 대비해 설정하는 것을 권장합니다.
3. ssh-agent에 키를 등록합니다. macOS는 GitHub 문서의 ssh-add 절차를 따르는 것이 안전합니다.
4. 공개 키 내용을 복사합니다: cat ~/.ssh/id_ed25519.pub
5. GitHub → Settings → SSH and GPG keys → New SSH key에 붙여넣습니다.
6. 연결 테스트: ssh -T [email protected] — 성공 메시지가 나오면 준비 완료입니다.
원격 저장소 URL은 [email protected]:사용자명/저장소명.git 형식으로 두면 SSH로 push/pull 합니다. (아래 GitHub 연동에서 git remote add 예시와 함께 설명합니다.)
핵심 개념
작업 영역
Working Directory → Staging Area → Repository
(작업 중) (git add) (git commit)
파일 상태
- Untracked: Git이 추적하지 않는 새 파일
- Modified: 수정된 파일
- Staged: 커밋 준비된 파일
- Committed: 저장소에 저장된 파일
기본 워크플로우 심화
작업 디렉터리(Working Directory), 스테이징 영역(Staging Area), 로컬 저장소(Repository)의 관계를 한 번에 보면 다음과 같습니다. 스테이징은 “다음 커밋에 넣을 변경만 골라 담는 바구니”라고 이해하면 됩니다.
flowchart TB
subgraph WD["작업 디렉터리 (Working Directory)"]
F1["편집한 파일"]
end
subgraph SA["스테이징 영역 (Staging Area / Index)"]
F2["git add로 선택된 스냅샷"]
end
subgraph REPO["로컬 저장소 (Repository .git)"]
C["커밋 객체 — git commit"]
end
WD -->|git add| SA
SA -->|git commit| REPO
REPO -.->|git checkout / restore로 특정 버전 반영| WD
- 작업 디렉터리: 실제로 편집하는 폴더 트리입니다.
- 스테이징:
git add로 “이번 커밋에 포함할 변경”을 표시합니다. 같은 파일이라도 일부만 스테이징할 수 있습니다(git add -p). - 저장소:
git commit으로 스테이징된 내용이 커밋(스냅샷)으로 기록됩니다.
커밋 안을 들여다보기: 변경분이 아니라 스냅샷
처음 Git을 쓸 때 흔한 오해가 “커밋은 이전 버전과의 차이(diff)를 저장한다”는 것입니다. 실제로 커밋은 그 시점 프로젝트 전체의 스냅샷을 가리킵니다. 파일 내용 하나하나는 blob, 폴더 구조는 tree, 그리고 루트 tree와 부모 커밋·작성자·메시지를 묶은 것이 commit 객체이며, 모든 객체는 내용의 해시로 이름이 붙습니다. 내용이 같으면 해시도 같으므로 바뀌지 않은 파일은 새로 저장되지 않고 이전 blob을 그대로 가리킵니다. 매번 전체를 저장하는데도 저장소가 커지지 않는 이유입니다(오래된 객체는 git gc 때 팩 파일로 델타 압축됩니다). 직접 열어 보면 감이 옵니다.
git cat-file -p HEAD # 커밋 객체: tree 해시, parent, author, 메시지
git ls-tree HEAD # 루트 tree: 파일/폴더 이름과 각 blob·tree 해시
git show HEAD:README.md # 마지막 커밋 스냅샷 속 README (작업 중인 파일이 아님)
세 영역을 기준으로 보면 diff 명령도 정리됩니다. git diff는 작업 디렉터리와 스테이징, git diff --staged는 스테이징과 마지막 커밋, git diff HEAD는 작업 디렉터리와 마지막 커밋을 비교합니다. git reset의 세 옵션도 “어느 층까지 되돌리나”의 차이입니다. --soft는 브랜치가 가리키는 커밋만 옮기고 스테이징과 파일은 그대로 두며, 기본값인 --mixed는 스테이징까지 되돌리고 파일은 남겨 두고, --hard는 작업 디렉터리의 파일까지 덮어써서 커밋하지 않은 변경이 사라집니다.
릴리스 버전을 표시할 때 쓰는 태그도 두 종류가 있습니다. git tag v1.0은 커밋을 가리키는 이름표만 만드는 가벼운 태그이고, git tag -a v1.0 -m "release"는 작성자·날짜·메시지를 가진 태그 객체를 만듭니다. 배포 이력을 남기거나 서명해야 한다면 -a를 쓰는 편이 맞습니다.
git add: -A vs -u vs .
현재 디렉터리 기준으로 자주 쓰는 형태입니다(경로를 붙이면 그 범위만 적용됩니다).
| 명령 | 대략적인 의미 |
|---|---|
git add . | 현재 디렉터리 이하의 변경·새 파일을 스테이징합니다. 상위 디렉터리의 파일은 포함하지 않습니다. |
git add -A (또는 --all) | 저장소 전체에서 추적 대상이 되는 변경과 삭제까지 포함해 스테이징합니다(보통 프로젝트 루트에서 실행). |
git add -u (또는 --update) | 이미 추적 중인 파일의 변경·삭제만 스테이징합니다. 새로 만든 untracked 파일은 포함하지 않습니다. |
정리하면, 새 파일까지 한꺼번에 올리려면 git add . 또는 git add -A, “예전부터 있던 파일만” 고치는 단계에서는 git add -u를 쓰는 경우가 많습니다.
커밋 메시지 작성 규칙 (Conventional Commits)
팀·오픈소스에서 읽기 쉬운 이력을 남기려면 Conventional Commits 형태를 쓰는 경우가 많습니다.
형식: <type>(optional scope): <짧은 설명>
자주 쓰는 type 예:
- feat: 새 기능
- fix: 버그 수정
- docs: 문서만 변경
- style: 포맷·세미콜론 등 동작에 영향 없는 스타일
- refactor: 리팩터링
- test: 테스트 추가·수정
- chore: 빌드·보조 도구 등 예시:
feat(auth): add OAuth2 login handler
fix(api): handle empty response body
docs: update install steps for Windows
본문이 필요하면 제목 다음 빈 줄 뒤에 왜 바꿨는지 적습니다. 한 커밋에는 한 가지 논리적 변경만 담는 것이 나중에 git revert나 리뷰에 유리합니다.
기본 명령어
저장소 생성
mkdir myproject
cd myproject
git init
파일 추가 및 커밋
Git의 가장 기본적인 워크플로우입니다:
# 1. 파일 생성 (예시)
echo "Hello Git" > README.md
# README.md 파일에 "Hello Git" 내용 작성
# 2. 상태 확인
git status
# 출력 예시:
# On branch main
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
# README.md
#
# nothing added to commit but untracked files present
#
# 설명: README.md가 Untracked 상태 (Git이 아직 추적하지 않음)
# 3. 스테이징 (Staging Area에 추가)
git add README.md
# 또는 모든 변경 파일 추가
# git add .
#
# 스테이징: 커밋할 파일을 선택하는 단계
# "이 파일들을 다음 커밋에 포함시키겠다"는 의미
# 4. 상태 재확인
git status
# 출력 예시:
# On branch main
# Changes to be committed:
# (use "git restore --staged <file>..." to unstage)
# new file: README.md
#
# 설명: README.md가 Staged 상태 (커밋 준비 완료)
# 5. 커밋 (변경 사항을 저장소에 기록)
git commit -m "Add README"
# -m "메시지": 커밋 메시지 (변경 내용 설명)
# 커밋: 현재 스테이징된 변경사항의 스냅샷을 저장
# 각 커밋은 고유한 해시(SHA-1)를 가짐
#
# 출력 예시:
# [main 1a2b3c4] Add README
# 1 file changed, 1 insertion(+)
# create mode 100644 README.md
워크플로우 정리:
- 파일 수정 (Working Directory)
git add: 스테이징 (Staging Area)git commit: 저장소에 기록 (Repository)git push: 원격 저장소에 업로드 (Remote Repository)
변경 이력 확인
git log
git log --oneline # 간단히 보기
변경 내용 확인
git diff # 작업 디렉토리 vs 스테이징
git diff --staged # 스테이징 vs 저장소
파일 되돌리기
# 작업 디렉토리 변경 취소
git restore README.md
# 스테이징 취소
git restore --staged README.md
브랜치
브랜치는 독립적인 작업 공간을 만들어 여러 기능을 동시에 개발할 수 있게 해줍니다:
# 1. 브랜치 생성
git branch feature
# "feature"라는 이름의 새 브랜치 생성
# 현재 커밋을 가리키는 포인터가 생성됨
# 아직 브랜치를 이동하지는 않음
# 2. 브랜치 목록 확인
git branch
# 출력 예시:
# * main (* 표시: 현재 브랜치)
# feature
# 3. 브랜치 이동
git checkout feature
# HEAD가 feature 브랜치로 이동
# 작업 디렉토리가 feature 브랜치 상태로 변경됨
#
# 출력: Switched to branch 'feature'
# 4. 생성 + 이동 (한 번에)
git checkout -b feature
# 위의 1번과 3번을 한 번에 수행
# -b: 브랜치 생성 옵션
#
# 최신 Git에서는 switch 명령도 사용 가능:
# git switch -c feature
# 5. 브랜치에서 작업 후 커밋
echo "new feature" > feature.txt
git add feature.txt
git commit -m "Add new feature"
# feature 브랜치에만 커밋이 추가됨
# main 브랜치는 영향 받지 않음
# 6. 브랜치 병합 (merge)
git checkout main
# main 브랜치로 이동
git merge feature
# feature 브랜치의 변경사항을 main에 병합
#
# 출력 예시 (Fast-forward):
# Updating abc1234..def5678
# Fast-forward
# feature.txt | 1 +
# 1 file changed, 1 insertion(+)
#
# Fast-forward: main이 feature의 조상이면 포인터만 이동
# 3-way merge: 두 브랜치가 갈라졌으면 새 커밋 생성
# 7. 브랜치 삭제 (병합 후)
git branch -d feature
# -d: 병합된 브랜치만 삭제 (안전)
# -D: 강제 삭제 (병합 안 된 브랜치도 삭제)
브랜치 사용 시나리오:
main: 안정적인 배포 버전develop: 개발 중인 버전feature/login: 로그인 기능 개발bugfix/crash: 버그 수정 병합 충돌 해결:
# 병합 시 충돌 발생 시
git merge feature
# 출력: CONFLICT (content): Merge conflict in file.txt
# 충돌 파일 확인
git status
# 충돌 파일에는 다음과 같은 마커가 표시됨:
# <<<<<<< HEAD
# main 브랜치의 내용
# =======
# feature 브랜치의 내용
# >>>>>>> feature
# 충돌 해결 후
git add file.txt
git commit -m "Resolve merge conflict"
실전 시나리오
첫 프로젝트 Git 시작하기 (init부터 push까지)
로컬에서 새 폴더를 만들고 GitHub에 처음 올리는 흐름입니다.
- 프로젝트 폴더 준비
mkdir my-app && cd my-app
git init
.gitignore와README.md를 두고 첫 커밋(아래 .gitignore 참고)
echo "# my-app" > README.md
git add README.md
git commit -m "chore: initial commit"
- GitHub에서 빈 저장소 생성(README 없이 생성하면 로컬과 충돌이 적습니다).
- 원격 추가 후 push — HTTPS 예시:
git remote add origin https://github.com/YOUR_USER/my-app.git
git branch -M main
git push -u origin main
SSH를 쓰는 경우 origin URL은 [email protected]:YOUR_USER/my-app.git 형식으로 넣습니다. -u는 이후 git push만으로 같은 브랜치를 올릴 수 있게 upstream을 기억해 둡니다.
실수한 커밋 수정하기 (amend)
방금 만든 마지막 커밋의 메시지를 고치거나, 빠뜨린 파일을 같은 커밋에 합치고 싶을 때 사용합니다.
# 메시지만 수정 (에디터가 열리거나 -m으로 한 줄 수정)
git commit --amend -m "fix: correct commit message"
# 스테이징을 추가한 뒤 마지막 커밋에 합치기
git add forgotten.txt
git commit --amend --no-edit
주의: 이미 git push로 원격에 올린 커밋을 --amend로 바꾸면 히스토리가 달라지므로, 혼자 쓰는 브랜치가 아니면 git push --force-with-lease가 필요하고 팀 규칙을 확인해야 합니다.
파일 되돌리기 (restore, checkout)
Git 2.23 이후로는 작업 트리·스테이징 되돌리기에 git restore를 쓰는 방식이 권장됩니다.
# 작업 디렉터리의 변경을 버리고, 마지막 커밋 상태로 되돌림 (주의: 복구 어려움)
git restore README.md
# 스테이징만 취소 (파일 내용은 그대로, unstaged로만)
git restore --staged README.md
# 특정 커밋의 파일 내용만 가져와 작업 디렉터리에 반영
git restore --source=HEAD~1 README.md
브랜치 전환은 예전처럼 git checkout other-branch 또는 최신 문법으로 git switch other-branch를 씁니다. git checkout -- file은 git restore file과 대응되는 옛 표현입니다.
흔한 문제 해결
fatal: not a git repository
이 메시지는 현재 디렉터리(또는 상위)에 .git 폴더가 없을 때 나옵니다.
- 프로젝트 루트로 이동했는지 확인:
pwd,ls -la - 처음이라면
git init으로 저장소를 만들거나, 기존 저장소를git clone으로 받았는지 확인합니다. - 하위 폴더가 아니라 저장소 루트에서 명령을 실행하는지 확인합니다.
rejected - non-fast-forward (push 거절)
원격에 로컬에 없는 커밋이 있을 때, 단순히 push만으로는 안전하게 앞으로 갈 수 없어서 거절됩니다.
- 먼저 원격 변경을 가져와 합칩니다:
git pull --rebase origin main
# 또는
git pull origin main
- 충돌이 없으면 다시
git push. - 강제 push(
git push --force)는 원격의 커밋을 덮어쓰므로, 혼자 쓰는 브랜치가 아니면 사용하지 않습니다. 필요할 때는--force-with-lease가 조금 더 안전합니다.
.gitignore 작성법
버전에 올리지 않을 파일을 나열합니다. 빌드 산출물, 의존성 폴더, OS·IDE 설정, 비밀 키 등을 제외하는 데 씁니다.
- 저장소 루트에
.gitignore파일을 둡니다. - 한 줄에 하나씩 패턴을 씁니다. 예:
# 빌드 출력
/build/
/dist/
*.o
*.exe
# Node
node_modules/
# Python
__pycache__/
.venv/
# 환경·비밀
.env
.env.local
- 이미 추적 중인 파일은
.gitignore에 넣어도 자동으로 빠지지 않습니다. 추적을 끊으려면git rm --cached <파일>후 커밋합니다. - gitignore.io 등에서 언어·OS에 맞는 템플릿을 생성할 수 있습니다.
GitHub 연동
원격 저장소 추가 (remote add)
로컬 저장소에 별칭 이름(보통 origin)과 URL을 연결합니다.
git remote add origin https://github.com/username/repo.git
# SSH 예시
# git remote add origin [email protected]:username/repo.git
이미 잘못 넣었다면 git remote set-url origin <새 URL>로 바꿉니다. 확인은 git remote -v.
첫 push 하기
브랜치 이름이 main일 때:
git push -u origin main
GitHub 저장소가 비어 있으며, 로컬에 커밋이 있으면 위 한 번이면 됩니다. 이후 같은 브랜치는 git push만으로 충분합니다.
풀·클론
git pull origin main
git clone https://github.com/username/repo.git
README.md 작성 팁
- 프로젝트 이름과 한 줄 설명을 맨 위에 둡니다.
- 설치 방법, 실행 방법, 환경 변수가 있으면 단계별로 적습니다.
- 라이선스·기여 방법은 링크로 연결해도 좋습니다.
- 스크린샷·다이어그램은
README에 넣으면 새 참여자가 구조를 빨리 이해합니다.
자주 쓰는 명령어 요약
# 초기화
git init
# 상태 확인
git status
# 스테이징
git add <file>
git add . # 모든 파일
# 커밋
git commit -m "message"
# 이력 확인
git log
git log --oneline
# 브랜치
git branch <name>
git checkout <name>
git checkout -b <name>
git merge <name>
# 원격 저장소
git remote add origin <url>
git push -u origin main
git pull origin main
git clone <url>
마무리
핵심 요약
Git의 기본 개념을 정리하겠습니다:
✅ Git의 역할: 코드 변경 이력을 체계적으로 관리하며, 여러 사람이 협업할 수 있게 해줍니다.
✅ 기본 워크플로우: git add로 스테이징 → git commit으로 저장 → git push로 원격 저장소에 업로드합니다.
✅ 브랜치: 독립적인 작업 공간을 만들어 동시에 여러 기능을 개발할 수 있습니다.
✅ GitHub 연동: 원격 저장소를 사용하면 코드를 백업하고 다른 사람과 공유할 수 있습니다.
자주 사용하는 명령어 모음
# 초기 설정
git config --global user.name "Your Name"
git config --global user.email "[email protected]"
# 저장소 관리
git init # 새 저장소 생성
git clone <url> # 원격 저장소 복제
# 변경 사항 관리
git status # 상태 확인
git add . # 모든 변경 사항 스테이징
git commit -m "message" # 커밋
git push # 원격 저장소에 업로드
git pull # 원격 저장소에서 가져오기
# 브랜치 관리
git branch # 브랜치 목록
git checkout -b <name> # 새 브랜치 생성 및 이동
git merge <name> # 브랜치 병합
다음 단계
Git의 기본을 익혔다면, 이제 팀 협업을 위한 브랜치 전략과 고급 기능을 배울 차례입니다.
자주 묻는 질문 (FAQ)
Q. push가 rejected - non-fast-forward로 거절되면 어떻게 하나요?
A. 원격에 로컬에 없는 커밋이 있다는 뜻이므로 먼저 git pull --rebase origin main(또는 git pull)으로 원격 변경을 가져와 합친 뒤 다시 push합니다. 여기서 git push --force로 밀어붙이면 다른 사람의 커밋을 덮어쓸 수 있어, 혼자 쓰는 브랜치가 아니면 쓰지 않습니다. 꼭 강제로 올려야 한다면 원격이 예상한 상태일 때만 덮어쓰는 --force-with-lease가 더 안전합니다.
Q. git add .만 쓰면 안 되나요?
A. 의도하지 않은 파일이 함께 스테이징되기 쉽습니다. 커밋 전에 git status로 무엇이 올라가는지 확인하고, 빌드 산출물이나 비밀 파일은 .gitignore로 제외해 두세요.
다음 글: Git 실전 가이드 #2: 브랜치와 병합 — branch, merge, 충돌 해결
참고 자료
실전 팁 (Git)
git status로 작업 트리·스테이징을 먼저 확인합니다. 무엇이 다음 커밋에 들어가는지 모른 채 명령을 치면 실수가 누적됩니다.- 문제가 생기면
git log --oneline과git branch -vv로 “지금 어느 커밋·브랜치인지”를 고정한 뒤diff로 원인을 좁힙니다. - 이미 푸시한 커밋을 되돌릴 때는
reset --force보다 팀 규칙에 따라revert가 안전한 경우가 많습니다.