Git 되돌리기와 복구: restore · reset · revert · reflog 차이

··설명 약 9분·작성: 해비·블로그 소개

Git 변경을 되돌릴 때 restore·reset·revert·reflog 중 무엇을 선택하나요?

파일 수정 취소, staging 해제, 커밋 취소, 잃어버린 커밋 찾기는 서로 다른 작업입니다. restore·reset·revert·reflog 중 하나를 고르기 전에 무엇을 되돌릴지와 이미 공유한 이력인지부터 구분하세요.

적용 조건·범위: 출력에서 대상·내용을 확인하고 clean 상태일 때만 아래를 선택합니다. merge commit은 mainline 선택이 필요한 별도 경우라 이 예제에 넣지 않습니다.

본문 근거: git-scm.com/docs/git-restore · git-scm.com/docs/git-revert · git-scm.com/docs/git-reflog

핵심 원리

복구 명령을 고르기 전에 무엇을 되돌릴지 구분합니다. 파일 수정만 버릴지, staging을 해제할지, 공개된 commit을 취소할지, 사라진 commit을 찾아야 하는지에 따라 도구가 달라집니다.

Git에서는 현재 상태를 모른 채 강한 명령부터 실행하지 않습니다. 작업 전에는 status와 branch를 확인하고, history를 바꾸는 작업이라면 log와 reflog까지 확인합니다.

복구 대상별로 명령을 선택하기

이 절은 모든 명령을 연속 실행하는 절차가 아닙니다. 현재 작업을 보존한 연습용 복제본에서 한 상황씩 비교합니다. 파일 내용, staging, branch 위치, 공유 이력은 서로 다른 복구 대상입니다.

대상 선택 남는 상태
staging만 해제 git restore --staged README.md 작업 트리 수정 유지
추적 파일의 미commit 수정 취소 git restore README.md 기본적으로 index 내용으로 복원, 수정 유실 가능
branch만 이전 commit으로 git reset --soft HEAD~1 index·작업 트리 유지
branch와 index를 이전 commit으로 git reset --mixed HEAD~1 작업 트리 유지, staging 해제
branch·index·작업 트리를 이전 commit으로 git reset --hard HEAD~1 추적 파일 수정 유실 가능
공유 commit의 효과 취소 git revert 취소 변경을 새 commit으로 추가

soft/mixed/hard 비교는 각각 같은 세-commit 시작 상태의 별도 복제본에서 수행해야 합니다. 순서대로 실행하면 매번 HEAD가 달라져 비교가 성립하지 않습니다. --hard와 clean은 실제 작업을 잃을 수 있으므로 이 자료의 필수 실행 절차에 넣지 않습니다.

공유 commit을 취소하는 예제는 단일 부모의 일반 commit 하나를 대상으로 합니다. 먼저 log에서 대상 ID를 직접 확인한 뒤 입력합니다.

git status --short
git log --oneline -8
read -r -p "취소할 일반 commit ID: " REVERT_COMMIT
if [ -n "$REVERT_COMMIT" ]; then
  git show --stat "$REVERT_COMMIT"
fi

출력에서 대상·내용을 확인하고 clean 상태일 때만 아래를 선택합니다. merge commit은 mainline 선택이 필요한 별도 경우라 이 예제에 넣지 않습니다.

if [ -n "$REVERT_COMMIT" ]; then
  git revert "$REVERT_COMMIT"
fi
git log --oneline -3
git status --short

충돌이 나면 파일을 해결·stage한 후 git revert --continue를 사용하거나 중단하려면 git revert --abort를 선택합니다. 둘을 연속 실행하지 않습니다. 보호된 main은 revert 변경도 별도 branch와 PR로 검토합니다.

잃어버린 commit은 reflog에서 찾고 show로 내용을 확인한 다음 새 구조용 branch에 이름을 붙여 보존할 수 있습니다. reflog는 로컬 기록이며 영구 백업이 아닙니다.

git reflog --date=local -15
read -r -p "보존할 commit ID: " RECOVERY_COMMIT
if [ -n "$RECOVERY_COMMIT" ]; then
  git show --stat "$RECOVERY_COMMIT"
fi

확인한 ID가 맞을 때만 git branch rescue/recovered “$RECOVERY_COMMIT”로 새 이름을 붙입니다. 같은 branch가 있으면 덮어쓰지 않습니다. status/log로 결과를 다시 확인합니다.

공식 근거: https://git-scm.com/docs/git-restore · https://git-scm.com/docs/git-reset · https://git-scm.com/docs/git-revert · https://git-scm.com/docs/git-reflog

실습에서 확인할 것

세 개의 commit을 만든 뒤 soft/mixed/hard가 작업 트리와 index에 미치는 차이를 별도 복제 저장소에서 비교합니다.
reflog로 이전 commit을 다시 찾습니다.
공유된 main에서는 revert로 취소합니다.

다음 세 가지를 구분해서 기록합니다.

관찰
- Git이 현재 보여 주는 상태

판단
- 왜 이런 상태가 되었는지

조치
- 상태를 바꾸기 위해 선택한 최소 명령

이 순서를 유지하면 명령이 실패했을 때 원인을 추적하기 쉽고, 성공했더라도 무엇이 실제로 바뀌었는지 설명할 수 있습니다.

독자 질문과 결과 확인

질문: 실수한 변경을 취소할 때 restore, reset, revert 중 무엇을 고르나요?

본인의 연습용 저장소에서 순서대로 실행합니다.

git status --short
git diff
git diff --cached
git log --oneline -5

예상 결과: 미commit 작업, staging, 이미 만든 commit 중 무엇을 취소할지 구분합니다. 공유한 일반 commit의 효과는 git revert <확인한-commit-ID>로 새 commit을 만들어 취소합니다.

오류 점검: reset --hard는 추적 파일의 미저장 변경을 잃을 수 있어 기본 절차에서 제외합니다. revert 충돌이면 git status를 보고 해결 후 --continue 또는 --abort 중 하나를 선택합니다.

검증 기록: 위 명령은 이 편집 작업에서 실행하지 않았습니다. Git 이력과 원격 상태는 독자 환경에서 확인해야 하므로 미확인입니다.

다음 학습: 07회차에서 작업을 보관하고 다른 branch의 commit만 가져옵니다.

독립 학습 변형 과제: README 한 줄이 작업 트리와 index에 모두 있을 때 restore --staged 이후 어느 diff에 남는지 예측합니다. hard는 표로 제거 범위를 설명하고 실제 중요한 변경에 시험하지 않습니다.

선택 실습: 같은 프로젝트로 연습하기

이 선택 실습은 TaskFlow 개발 과정을 Git 저장소와 협업 기록으로 남기는 연습입니다. Git 이력은 직접 명령을 실행해 만듭니다.

저장소 상태에 맞춰 restore·reset·revert·reflog를 구분하고 변경·commit 복구 결과를 확인합니다.

선택: 연재 프로젝트와 전체 자료

연재 프로젝트를 이어 만드는 분을 위한 자료입니다. 이 글의 개념과 예제만 찾으셨다면 필요한 파일과 실행 방법만 펼쳐보세요.

TaskFlow 적용

시작 체크포인트: 이전 글의 프로젝트 적용과 완료 확인을 마친 본인의 Git 저장소에서 이어갑니다. 다운로드 ZIP은 문서·설정 참고 자료이며 commit 이력·branch·remote·PR 상태를 복원하지 않습니다. 현재 저장소의 status·log와 아래 시작 조건을 직접 대조합니다.

5편의 개념과 이전 체크포인트를 확인합니다. ZIP은 Git 이력 자체가 아니므로 Git 상태는 본인의 연습용 저장소에서 준비합니다.

이전 체크포인트:

git-step-05-conflict-pr

TaskFlow에 의도적 오류 commit을 만든 뒤 local-only 상황과 already-pushed 상황을 나누어 서로 다른 복구 방법을 적용합니다.

적용 후에는 다음을 다시 확인합니다.

git status --short
git log --oneline --decorate -8

remote가 관련된 회차라면 local과 origin의 위치도 함께 봅니다.

git branch -vv
git remote -v

자주 발생하는 실수

  • 파일만 취소 → restore
  • staging만 취소 → restore --staged
  • 아직 공유하지 않은 최근 commit 수정 → reset/amend 검토
  • 이미 공유한 main 취소 → revert 우선
  • commit을 잃어버림 → reflog

복구가 필요한 상황에서는 명령을 더 많이 실행하는 것이 해결책이 아닙니다. 현재 상태를 보존하고, 필요한 경우 새 branch를 만들어 안전한 기준점을 확보한 뒤 조치합니다.

학습 완료 체크리스트

  • 명령 이름이 아니라 현재 상태와 공유 여부를 기준으로 복구 방법을 선택할 수 있어야 합니다.
전체 파일·코드 보기

실습 프로젝트 전체 코드

이 회차는 Git 명령 실습을 위한 문서·설정 자료입니다. ZIP에는 실제 Git 이력이나 앱 전체가 없습니다. 아래 Markdown 문서는 자동 실행 스크립트가 아니며, 각 명령의 전제와 예상 상태를 읽고 본인의 연습 환경에서 단계별로 확인합니다.

README.md

# git-step-06-recovery 문서 체크포인트

이 ZIP은 Git·GitHub 실습 안내와 관련 설정 파일을 모은 자료입니다. `.git` 이력, 실제 branch/tag/stash/worktree, 원격 저장소, 사용자 계정이나 TaskFlow 앱 전체를 포함하지 않습니다. 별도의 개발환경 과정 TaskFlow 프로젝트에서 실습 안내를 읽고 명령을 단계별로 적용하세요. 이 폴더 자체를 완성된 Git 저장소로 간주하거나 명령을 한꺼번에 실행하지 마세요.

01~13 필수 과정의 이 회차까지 문서를 누적합니다.

검증 범위는 명령 문법·설정 형식·공식 문서 및 기존 프로젝트 스크립트 대조입니다. 실제 init/commit/branch/stash/worktree/reset/rebase/merge/push/PR/Release/서명 작업을 수행했다는 기록이 아닙니다. 개인 키·토큰·비밀번호는 포함하지 않습니다.

docs/git-step-01.md

# Git·GitHub 01 실습 안내

이 파일은 독자가 상태를 확인하며 따라갈 Markdown 문서입니다. 자동 실행 스크립트나 검수 과정에서 실행한 Git 이력 로그가 아닙니다.

## 첫 저장소부터 원격 연결까지

Git 공식 설치 안내에서 운영체제에 맞는 Git을 설치합니다. Windows 명령 예제는 Git Bash 기준입니다. 이후 회차도 같은 셸을 사용합니다. 먼저 개발환경 과정에서 만든 TaskFlow 폴더를 편집기로 열고 그 폴더에서 터미널을 엽니다. 이미 .git이 있는 프로젝트라면 아래 init을 반복하기보다 현재 이력과 브랜치를 먼저 확인합니다.

```bash
git --version
git init -b main
git status --short
```

이름과 이메일은 이 저장소의 commit 작성자 정보입니다. GitHub 인증 비밀번호가 아닙니다. 공개 이메일을 원하지 않으면 GitHub Settings의 Emails에서 본인의 noreply 주소를 확인합니다. 아래 입력은 실제 값을 화면에 재출력하지 않고 저장소 로컬 설정에만 기록합니다.

```bash
read -r -p "commit 작성자 이름: " GIT_AUTHOR_LABEL
read -r -p "commit 작성자 이메일 또는 본인 noreply 주소: " GIT_AUTHOR_MAIL
if [ -n "$GIT_AUTHOR_LABEL" ] && [ -n "$GIT_AUTHOR_MAIL" ]; then
  git config --local user.name "$GIT_AUTHOR_LABEL"
  git config --local user.email "$GIT_AUTHOR_MAIL"
else
  printf '%s\n' '빈 작성자 정보로 진행하지 않습니다.'
fi
```

편집기에서 README.md에 TaskFlow의 목적 한 줄을 작성합니다. 기존 파일은 덮어쓰지 않고 내용을 읽고 수정합니다. .gitignore에는 기존 개발환경의 node_modules, 빌드 산출물, 실제 환경변수 파일 제외 규칙을 유지합니다. 첫 commit은 README만 명시적으로 선택합니다.

```bash
git status --short
git add README.md
git diff --cached
git commit -m "docs: describe TaskFlow"
git log --oneline -1
```

처음에는 README가 untracked라서 일반 git diff에 나오지 않을 수 있습니다. add 후 cached diff는 첫 commit에 들어갈 내용을 보여 줍니다. 이제 README에 실행 방법 한 줄을 추가해 add하고, commit하기 전에 다른 설명 한 줄을 더 수정합니다.

```bash
git add README.md
git status --short
git diff
git diff --cached
```

이때 예상하는 MM의 첫 M은 staging, 두 번째 M은 staging 이후 작업 트리 변경입니다. 두 diff를 비교한 뒤 두 변경 모두 포함하려면 다시 add하고 두 번째 commit을 만듭니다.

```bash
git add README.md
git diff --cached
git commit -m "docs: add TaskFlow usage"
```

GitHub에서는 본인 계정에 빈 저장소를 만들고 README나 초기 commit을 추가하지 않습니다. 저장소 화면의 HTTPS 또는 SSH 주소를 복사합니다. HTTPS는 Git Credential Manager 등 공식 인증 흐름을, SSH는 이미 등록한 키를 사용합니다. 비밀번호나 토큰을 URL에 넣지 않습니다. 아래는 독자가 본인 원격 저장소를 연결할 때 실행하는 절차이며 이 글의 검수에서 push한 결과가 아닙니다.

```bash
read -r -p "본인의 빈 GitHub 저장소 clone 주소: " TASKFLOW_REMOTE
if [ -n "$TASKFLOW_REMOTE" ]; then
  git remote add origin "$TASKFLOW_REMOTE"
else
  printf '%s\n' '원격 주소가 없어 연결하지 않습니다.'
fi
git remote -v
```

origin이 이미 존재하면 add 실패를 무시하지 말고 기존 주소가 본인의 대상인지 확인합니다. 주소와 commit 내용을 검토한 뒤에만 첫 push를 실행합니다.

```bash
git push -u origin main
git status -sb
git rev-parse HEAD
git ls-remote origin refs/heads/main
```

마지막 두 출력의 commit ID가 같고 GitHub 파일 화면이 일치하면 첫 연결 기준을 충족합니다. 빈 원격이 아니어서 rejected가 발생했다면 강제 push하지 않고 4편의 fetch/이력 비교로 이동합니다. init 전에는 status가 실패하고 첫 commit 전에는 log가 실패하는 것이 정상일 수 있습니다.

공식 근거: https://git-scm.com/docs/git-init · https://git-scm.com/docs/git-add · https://git-scm.com/docs/git-commit · https://docs.github.com/en/get-started/git-basics/set-up-git

## 체크포인트 기준

git-step-01-first-push: 위 실습의 관찰 기준을 본인의 연습 환경에서 확인한 뒤 사용합니다. 이 ZIP을 내려받았다는 사실만으로 실습 완료가 성립하지 않습니다.

docs/git-step-02.md

# Git·GitHub 02 실습 안내

이 파일은 독자가 상태를 확인하며 따라갈 Markdown 문서입니다. 자동 실행 스크립트나 검수 과정에서 실행한 Git 이력 로그가 아닙니다.

## 목적별 commit을 만드는 실습

1편 이후 README.md에 서로 떨어진 두 문단을 수정합니다. 하나는 실행 방법, 다른 하나는 오타 수정으로 구분합니다. 이미 공유한 commit을 재작성하지 않도록 이 실습에서는 아직 push하지 않은 새 변경만 사용합니다.

```bash
git diff --stat
git diff -- README.md
git add -p README.md
git diff --cached
git diff -- README.md
```

대화형 질문에서 y는 현재 hunk를 staging하고 n은 남깁니다. 한 hunk에 섞였으면 s로 분할할 수 있는지 확인하고, 분할되지 않으면 편집기에서 변경을 다시 나눕니다. cached diff에 첫 목적만 남았을 때 commit하고 나머지 변경을 두 번째 commit으로 만듭니다.

```bash
git commit -m "docs: clarify TaskFlow startup"
git add README.md
git diff --cached
git commit -m "docs: correct wording"
git log --oneline -2
```

이어서 README 한 줄을 다시 수정하고 git add README.md로 stage합니다. 이 추가 변경을 다음 명령으로 index에서만 되돌립니다. 작업 트리의 수정은 남아 있는지 status와 diff로 확인합니다.

```bash
git add README.md
git restore --staged README.md
git status --short
git diff -- README.md
```

마지막 commit의 메시지만 바꾸려면 staged 변경이 없는지 확인한 다음 실행합니다. 방금 unstage한 작업 트리 수정은 이 amend에 포함되지 않고 그대로 남습니다. amend는 새 commit을 만들어 ID를 바꾸며 이미 push한 이력에는 기본 절차로 적용하지 않습니다. --no-edit도 staged 내용까지 기존 commit에 합칠 수 있습니다.

```bash
git diff --cached
git rev-parse HEAD
git commit --amend -m "docs: fix TaskFlow guide wording"
git rev-parse HEAD
git show --stat HEAD
```

.gitignore는 미추적 파일의 추가를 막는 규칙입니다. 이미 추적한 일반 파일을 추적에서 빼는 git rm --cached는 별도의 삭제 commit을 만들므로 대상과 영향을 확인해야 합니다. 비밀이 이미 공개됐다면 ignore 변경만으로 과거 이력이 사라지지 않습니다. 우선 자격증명을 폐기·교체하고 저장소 관리 절차로 대응합니다. 학습 중 실제 비밀을 만들거나 commit하지 않습니다.

공식 근거: https://git-scm.com/docs/git-add · https://git-scm.com/docs/git-restore · https://git-scm.com/docs/git-commit · https://git-scm.com/docs/gitignore

## 체크포인트 기준

git-step-02-clean-commit: 위 실습의 관찰 기준을 본인의 연습 환경에서 확인한 뒤 사용합니다. 이 ZIP을 내려받았다는 사실만으로 실습 완료가 성립하지 않습니다.

docs/git-step-03.md

# Git·GitHub 03 실습 안내

이 파일은 독자가 상태를 확인하며 따라갈 Markdown 문서입니다. 자동 실행 스크립트나 검수 과정에서 실행한 Git 이력 로그가 아닙니다.

## fast-forward와 merge commit 비교 실습

working tree가 깨끗한지 먼저 확인합니다. 아래 학습용 branch 이름이 이미 있으면 중단하고 기존 작업을 확인합니다. 먼저 feature/a를 만들고 편집기에서 새 문서 docs/branch-a.md에 기능 설명을 작성합니다. docs 폴더가 없으면 편집기로 만듭니다.

```bash
git status --short
git switch -c feature/a
```

파일 작성 후 해당 파일만 commit하고 main으로 돌아와 병합합니다. 이 사이 main에 다른 commit을 만들지 않습니다.

```bash
git add docs/branch-a.md
git commit -m "docs: add branch A notes"
git switch main
git merge --ff-only feature/a
git log --graph --oneline --decorate -5
```

새 merge commit 없이 main이 feature/a의 끝으로 이동하는 것이 fast-forward입니다. 다음에는 같은 main에서 feature/b를 만들고 docs/branch-b.md를 작성해 commit합니다.

```bash
git switch -c feature/b
```

파일 작성 뒤 다음을 실행합니다.

```bash
git add docs/branch-b.md
git commit -m "docs: add branch B notes"
git switch main
```

main에서는 다른 파일 docs/main-notes.md를 작성해 commit합니다. 양쪽에 서로 다른 commit이 생긴 다음 feature/b를 병합합니다.

```bash
git add docs/main-notes.md
git commit -m "docs: add main notes"
git merge feature/b -m "Merge branch feature/b"
git log --graph --oneline --decorate --all -10
git show --no-patch --format='%h %p' HEAD
```

마지막 commit의 부모 ID가 두 개라면 merge commit입니다. --no-ff는 fast-forward가 가능해도 merge commit을 만들도록 선택하는 옵션이며, 이번 두 번째 예제는 이미 갈라진 이력이므로 없어도 merge commit이 생깁니다. 병합을 확인한 branch만 git branch -d로 정리할 수 있지만 삭제는 실습 완료의 필수 조건이 아닙니다.

공식 근거: https://git-scm.com/docs/git-switch · https://git-scm.com/docs/git-merge · https://git-scm.com/docs/git-branch

## 체크포인트 기준

git-step-03-branch-merge: 위 실습의 관찰 기준을 본인의 연습 환경에서 확인한 뒤 사용합니다. 이 ZIP을 내려받았다는 사실만으로 실습 완료가 성립하지 않습니다.

docs/git-step-04.md

# Git·GitHub 04 실습 안내

이 파일은 독자가 상태를 확인하며 따라갈 Markdown 문서입니다. 자동 실행 스크립트나 검수 과정에서 실행한 Git 이력 로그가 아닙니다.

## 원격 이력을 확인한 뒤 동기화하기

origin은 저장소 주소의 별명이고 origin/main은 마지막 fetch 시점에 관찰한 원격 main입니다. 실시간 서버 상태 자체가 아닙니다. 기존 TaskFlow 저장소에서 먼저 다음을 확인합니다.

```bash
git status -sb
git remote -v
git branch -vv
git fetch origin
git log --graph --oneline --decorate --all -15
git log --left-right --oneline main...origin/main
```

fetch는 원격 정보를 가져오지만 현재 작업 트리를 자동 병합하지 않습니다. 마지막 비교에서 왼쪽은 local에만, 오른쪽은 원격 추적 branch에만 있는 commit입니다. working tree가 깨끗하고 local main에 고유 commit이 없을 때만 다음처럼 fast-forward 동기화를 선택합니다.

```bash
git switch main
git pull --ff-only origin main
git status -sb
```

양쪽 이력이 갈라지면 --ff-only는 실패합니다. 이때 실패를 강제 push로 덮지 않습니다. 3편의 merge 또는 8편의 공유 여부를 고려한 rebase 중 팀 정책에 맞는 절차를 정합니다. branch의 upstream이 없다면 대상이 맞는지 확인한 뒤 git branch --set-upstream-to=origin/main main을 사용할 수 있습니다.

clone을 비교하려면 기존 프로젝트 안이 아닌 별도 상위 폴더에서 진행합니다. taskflow-peer 폴더가 이미 있으면 실행하지 않습니다. 본인 원격의 읽기 권한을 확인하고 실제 clone 주소를 입력합니다.

```bash
read -r -p "본인의 GitHub clone 주소: " TASKFLOW_REMOTE
if [ -n "$TASKFLOW_REMOTE" ] && [ ! -e taskflow-peer ]; then
  git clone "$TASKFLOW_REMOTE" taskflow-peer
else
  printf '%s\n' '주소와 새 대상 폴더를 확인하세요.'
fi
```

두 clone의 branch와 remote-tracking 상태를 비교합니다. push rejected를 재현하려면 본인의 연습용 원격에 한쪽 clone에서 변경을 먼저 push한 뒤 다른 clone에서 이전 상태를 기준으로 push하는 순서를 사용합니다. 이는 원격을 변경하는 선택 실습입니다. 검수 과정에서는 원격을 만들거나 push하지 않았습니다.

공식 근거: https://git-scm.com/docs/git-fetch · https://git-scm.com/docs/git-pull · https://git-scm.com/docs/git-clone · https://git-scm.com/docs/git-push

## 체크포인트 기준

git-step-04-remote-sync: 위 실습의 관찰 기준을 본인의 연습 환경에서 확인한 뒤 사용합니다. 이 ZIP을 내려받았다는 사실만으로 실습 완료가 성립하지 않습니다.

docs/git-step-05.md

# Git·GitHub 05 실습 안내

이 파일은 독자가 상태를 확인하며 따라갈 Markdown 문서입니다. 자동 실행 스크립트나 검수 과정에서 실행한 Git 이력 로그가 아닙니다.

## 같은 줄의 충돌을 재현하고 해결하기

독자의 연습용 저장소에서만 진행합니다. clean main의 README.md에 같은 기준 문장이 commit되어 있어야 합니다. feature/conflict-demo 이름이 이미 있으면 기존 작업을 확인한 뒤 새 이름을 선택합니다.

```bash
git switch main
git status --short
git switch -c feature/conflict-demo
```

편집기에서 README의 한 문장을 기능 설명으로 바꾸고 commit합니다. main으로 돌아와 같은 원래 문장을 다른 설명으로 수정하고 별도 commit합니다. 두 문장을 서로 다른 줄에 추가하면 충돌이 발생하지 않을 수 있으므로 같은 줄을 바꿉니다.

```bash
git add README.md
git commit -m "docs: explain feature behavior"
git switch main
```

main 쪽의 같은 줄 수정 후 다음을 실행합니다.

```bash
git add README.md
git commit -m "docs: clarify main behavior"
git switch feature/conflict-demo
git merge main
git status
git diff --name-only --diff-filter=U
git diff -- README.md
```

충돌이 있다면 README에서 <<<<<<<, =======, >>>>>>>가 구분하는 두 의도를 읽습니다. 최종 요구에 맞는 한 문장 또는 두 설명으로 편집하고 marker를 제거합니다. 문서를 확인한 다음 해당 파일만 stage하고 병합 commit을 만듭니다.

```bash
git add README.md
git diff --cached
git commit -m "docs: resolve explanation conflict"
git status --short
```

해결 방향이 불명확하면 진행 중인 merge에서만 git merge --abort를 선택합니다. 이미 병합을 완료한 뒤 abort하는 명령이 아닙니다. merge 시작 전 미완료 변경이 있으면 abort가 원래 상태를 완전히 복원하지 못할 수 있으므로 clean 상태로 시작합니다.

본인 원격과 공개할 변경을 검토한 뒤 feature/conflict-demo를 push하고 GitHub에서 base main, compare feature/conflict-demo인 PR을 만듭니다. Files changed에서 marker가 남지 않았는지 확인하고 프로젝트의 lint/build를 실행합니다. 자신의 PR은 스스로 승인하는 리뷰를 남길 수 없으므로 혼자 학습하면 self-review 결과만 기록하고, 실제 승인 검증은 다른 권한 있는 리뷰어가 있을 때 수행합니다. 병합 후 local main은 fetch/pull로 별도 갱신합니다.

공식 근거: https://git-scm.com/docs/git-merge · https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line

## 체크포인트 기준

git-step-05-conflict-pr: 위 실습의 관찰 기준을 본인의 연습 환경에서 확인한 뒤 사용합니다. 이 ZIP을 내려받았다는 사실만으로 실습 완료가 성립하지 않습니다.

docs/git-step-06.md

# Git·GitHub 06 실습 안내

이 파일은 독자가 상태를 확인하며 따라갈 Markdown 문서입니다. 자동 실행 스크립트나 검수 과정에서 실행한 Git 이력 로그가 아닙니다.

## 복구 대상별로 명령을 선택하기

이 절은 모든 명령을 연속 실행하는 절차가 아닙니다. 현재 작업을 보존한 연습용 복제본에서 한 상황씩 비교합니다. 파일 내용, staging, branch 위치, 공유 이력은 서로 다른 복구 대상입니다.

| 대상 | 선택 | 남는 상태 |
| --- | --- | --- |
| staging만 해제 | git restore --staged README.md | 작업 트리 수정 유지 |
| 추적 파일의 미commit 수정 취소 | git restore README.md | 기본적으로 index 내용으로 복원, 수정 유실 가능 |
| branch만 이전 commit으로 | git reset --soft HEAD~1 | index·작업 트리 유지 |
| branch와 index를 이전 commit으로 | git reset --mixed HEAD~1 | 작업 트리 유지, staging 해제 |
| branch·index·작업 트리를 이전 commit으로 | git reset --hard HEAD~1 | 추적 파일 수정 유실 가능 |
| 공유 commit의 효과 취소 | git revert | 취소 변경을 새 commit으로 추가 |

soft/mixed/hard 비교는 각각 같은 세-commit 시작 상태의 별도 복제본에서 수행해야 합니다. 순서대로 실행하면 매번 HEAD가 달라져 비교가 성립하지 않습니다. --hard와 clean은 실제 작업을 잃을 수 있으므로 이 자료의 필수 실행 절차에 넣지 않습니다.

공유 commit을 취소하는 예제는 단일 부모의 일반 commit 하나를 대상으로 합니다. 먼저 log에서 대상 ID를 직접 확인한 뒤 입력합니다.

```bash
git status --short
git log --oneline -8
read -r -p "취소할 일반 commit ID: " REVERT_COMMIT
if [ -n "$REVERT_COMMIT" ]; then
  git show --stat "$REVERT_COMMIT"
fi
```

출력에서 대상·내용을 확인하고 clean 상태일 때만 아래를 선택합니다. merge commit은 mainline 선택이 필요한 별도 경우라 이 예제에 넣지 않습니다.

```bash
if [ -n "$REVERT_COMMIT" ]; then
  git revert "$REVERT_COMMIT"
fi
git log --oneline -3
git status --short
```

충돌이 나면 파일을 해결·stage한 후 git revert --continue를 사용하거나 중단하려면 git revert --abort를 선택합니다. 둘을 연속 실행하지 않습니다. 보호된 main은 revert 변경도 별도 branch와 PR로 검토합니다.

잃어버린 commit은 reflog에서 찾고 show로 내용을 확인한 다음 새 구조용 branch에 이름을 붙여 보존할 수 있습니다. reflog는 로컬 기록이며 영구 백업이 아닙니다.

```bash
git reflog --date=local -15
read -r -p "보존할 commit ID: " RECOVERY_COMMIT
if [ -n "$RECOVERY_COMMIT" ]; then
  git show --stat "$RECOVERY_COMMIT"
fi
```

확인한 ID가 맞을 때만 git branch rescue/recovered "$RECOVERY_COMMIT"로 새 이름을 붙입니다. 같은 branch가 있으면 덮어쓰지 않습니다. status/log로 결과를 다시 확인합니다.

공식 근거: https://git-scm.com/docs/git-restore · https://git-scm.com/docs/git-reset · https://git-scm.com/docs/git-revert · https://git-scm.com/docs/git-reflog

## 체크포인트 기준

git-step-06-recovery: 위 실습의 관찰 기준을 본인의 연습 환경에서 확인한 뒤 사용합니다. 이 ZIP을 내려받았다는 사실만으로 실습 완료가 성립하지 않습니다.

실행·검증 범위

이 자료는 독자가 실행할 절차와 기대 관찰 기준입니다. 제공 ZIP에는 Git 이력·실제 원격 저장소·CI 성공 기록이 포함되지 않습니다. 이번 원문 검수에서 branch/worktree/stash/reset/삭제/commit/push 또는 보안·서명 설정을 실행하지 않았습니다. 실제 수행 결과는 독자가 자신의 연습용 저장소와 권한을 확인하여 기록합니다.

완료 체크포인트

git-step-06-recovery

다음 학습

07 Git stash와 cherry-pick

다음 회차로 넘어가기 전에 working tree가 의도한 상태인지 확인하고, 실습 중 만든 임시 branch·stash·worktree가 있다면 유지할 이유가 있는지 정리합니다.

체크포인트 다운로드

git-step-06-recovery 문서·설정 ZIP 다운로드

시작 참고 자료: 5회차 ZIP

ZIP은 명령 안내와 설정 자료이며 Git 이력·브랜치·원격 저장소 상태를 복원하지 않습니다.

글 소개·학습 준비·전체 목차
시계와 복구 문서로 표현한 되돌리기와 복구 표지

Git·GitHub · 6 / 17 · 중급

Git 되돌리기와 복구 restore reset revert reflog 차이

Git에서 가장 위험한 영역인 되돌리기를 작업 트리, staging, commit 이력, 공유 여부에 따라 구분합니다.

이번 글에서 배우는 내용

  • git restore
  • git restore --staged
  • git reset --soft / --mixed / --hard
  • HEAD~1 표현
  • git revert
  • reset과 revert의 결정적 차이
  • git reflog
  • 삭제된 branch/잃어버린 commit 복구
  • 이미 push한 이력에서 reset을 조심해야 하는 이유
  • git clean은 개념과 위험만 소개

선수 지식

작업 트리·index·commit의 차이와 status·diff를 알고 시작합니다. 복구 실습은 별도 연습 저장소의 본인이 만든 변경에만 적용합니다.

Git 설치·셸·첫 commit 준비가 필요하면 Git 기초의 독립 실습에서 준비합니다. 누적 TaskFlow 파일은 상단 학습의 선수가 아닙니다.

목차

  1. 핵심 원리
  2. 복구 대상별로 명령을 선택하기
  3. 실습에서 확인할 것
  4. 독자 질문과 결과 확인
  5. TaskFlow 적용
  6. 자주 발생하는 실수
  7. 학습 완료 체크리스트
  8. 실습 프로젝트 전체 코드
  9. 실행·검증 범위
  10. 완료 체크포인트
  11. 다음 학습

이 글이 도움이 되었나요?

조회 중

읽음 기록

읽음 — / 전체 17개 · 필수 13개

이 글을 쓴 해비

웹사이트를 제작·운영하고, 개인 서비스와 자동화·AI 도구를 만듭니다. 직접 만들며 배운 내용과 문제 해결 과정을 BlogFlow에 기록합니다.

새 글 받아보기

RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.

RSS 피드 구독하기

댓글 남기기