노트

reflog로 날린 커밋 되살리기

Reference Log (git reflog)

인프라#git · 연결된 개념 3개

쉽게 말하면

reflog는 HEAD와 브랜치가 언제 어디를 가리켰는지 시간순으로 적힌 출입 기록부 같아요. reset이나 rebase로 커밋을 날려도 기록부에서 그 시점 위치를 찾아 되살릴 수 있어요.

비유가 깨지는 곳 이 기록은 내 컴퓨터에만 있고 푸시되지 않으며 영원하지도 않아요. 기본 설정에서 도달할 수 없는 항목은 30일, 도달 가능한 항목은 90일 뒤 만료되고 git gc 때 정리돼요.

git reflog(reference log)는 HEAD와 브랜치가 가리킨 위치가 바뀐 기록을 시간순으로 보여준다. git log가 커밋 사이의 부모-자식 관계라면, reflog는 "내가 언제 어디에 있었나"의 기록이다.

  • commit, checkout, reset, merge, rebase, pull, cherry-pick, amend처럼 HEAD를 움직이는 거의 모든 작업이 남는다
  • HEAD@{n}은 n번 전의 HEAD 위치다. 그대로 명령에 넣을 수 있다
  • 로컬에만 있고 푸시되지 않는다. 기본 설정에서 도달할 수 없는 항목은 30일, 도달 가능한 항목은 90일 뒤 만료되고 git gc(garbage collection) 때 정리된다
git reflog -10
# 0c17a91 HEAD@{2}: reset: moving to HEAD~3
git reset --hard HEAD@{2}        # 잘못한 reset 이전으로
git branch restore 0c17a91       # 또는 브랜치로 살려 두고 살펴보기

reflog에도 없을 때

stash를 지웠거나 reflog가 정리된 뒤라면 어디에서도 참조하지 않는 커밋(dangling commit)을 직접 찾는다.

git fsck --no-reflog | awk '/dangling commit/ {print $3}' \
  | xargs -L1 git --no-pager show -s --format="%ci %H" | sort
git show <해시>:path/to/dir/     # 내용 확인
git branch restore <해시>        # 브랜치로 되살리기

git stash apply <해시>는 stash 형태의 커밋에만 통하므로, 일반 커밋은 브랜치를 만들어 꺼낸다. reset --hard나 리베이스가 무섭지 않은 이유가 이 안전망이다. 원인 커밋을 찾는 일은 git bisect로 원인 커밋 찾기가 맡는다.

출처: git-reflog 문서

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 머지와 리베이스

    두 브랜치의 작업을 합치는 두 방법이다. 머지는 히스토리를 그대로 두고 합치는 커밋을 하나 더 만들고, 리베이스는 내 커밋들을 상대 브랜치 끝 위로 다시 적용해 일직선 히스토리를 만든다.

  • 여러 저장소 합치기

    따로 관리하던 Git 저장소를 하나로 합칠 때, 히스토리를 버리지 않고 옮기는 방법이 두 가지 있다. 저장소 루트끼리 그대로 합치거나(unrelated histories 머지), 한쪽을 다른 쪽의 하위 폴더로 넣는다(subtree). 모노레포로 옮길 때 자주 쓴다.

  • 커밋 메시지와 원자적 커밋

    좋은 커밋은 한 가지 변경만 담고(원자적 커밋, atomic commit), 그 변경이 무엇이고 왜 필요했는지를 메시지로 설명한다. 히스토리는 나중의 나와 동료가 읽는 문서다.

  • GitOps

    GitOps는 "환경이 어떤 상태여야 하는가"를 전부 git 저장소에 선언해 두고, git에 적힌 것을 유일한 진실(single source of truth)로 삼아 실제 환경을 맞추는 운영 방식이다. 서버에 직접 손대지 않고, 바꾸고 싶으면 git을 고친다.

  • 커넥션 드레이닝과 무중단 재시작

    배포 중 서버를 재시작하는 몇 초 동안 로드밸런서가 그 서버로 요청을 보내면 502가 난다. 먼저 로드밸런서에서 빼고(드레이닝), 진행 중인 요청을 마친 뒤 재시작하고, 준비되면 다시 넣는다.

보기 옵션