자주 찾아보는 Git 명령어 모음
작업하면서 그때그때 메모해 둔 Git 명령어를 상황별로 정리했다.
원격 브랜치
upstream에 새로 생긴 브랜치 가져오기
fork한 저장소에서 원본(upstream)에 새 브랜치가 생겼을 때:
git fetch upstream
git switch -c dev upstream/dev
로컬 브랜치를 원격 브랜치와 연결
git branch --set-upstream-to=origin/<원격 브랜치> <로컬 브랜치>
# 처음 push할 때 함께 연결
git push -u origin <브랜치>
원격 최신 변경을 rebase로 가져오기
git pull --rebase origin <브랜치>
병합 커밋 없이 내 로컬 커밋을 원격 커밋 위로 다시 쌓는다. 항상 이렇게 하려면 git config --global pull.rebase true.
커밋 수정
마지막 커밋 메시지 바꾸기
git commit --amend -m "바꿀 메시지"
이미 push한 커밋이라면 강제 push가 필요하므로, 공유 브랜치에서는 하지 않는다. 강제 push를 해야 한다면 --force-with-lease를 쓴다.
실수로 추적한 파일을 Git에서만 제거
git rm --cached <파일> [<파일> ...]
작업 디렉터리의 파일은 남기고 Git 추적만 끊는다. .gitignore에 추가한 뒤에도 이미 추적 중인 파일은 계속 추적되므로 이 명령이 필요하다. 이미 push한 비밀값이라면 제거만으로는 기록에 남아 있으므로 키를 반드시 재발급한다.
되돌리기
reflog로 시간 여행
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~3
# e4f5g6h HEAD@{1}: commit: 로그인 기능
# ...
git reset --hard e4f5g6h
reflog는 HEAD가 움직인 기록이라, 잘못 reset하거나 rebase로 사라진 커밋도 대부분 되찾을 수 있다. reset --hard는 커밋하지 않은 변경을 지우므로 실행 전에 git status를 확인한다.
이미 push한 병합을 취소할 때
공유 브랜치라면 기록을 지우는 reset --hard + push --force 대신 되돌리는 커밋을 만든다.
# 병합 커밋 되돌리기 (-m 1: 첫 번째 부모 기준으로 되돌림)
git revert -m 1 <병합 커밋>
git push
reset --hard HEAD~1 후 push --force는 그사이 다른 사람이 받아 간 기록과 어긋나고, 그 위에 쌓인 남의 커밋까지 지울 수 있다. 개인 브랜치에서만 쓴다.
정리
쓰지 않는 로컬 브랜치 한 번에 삭제
task로 시작하는 브랜치를 모두 지우는 예시다. -d는 병합되지 않은 브랜치를 지우지 않으므로 안전하다.
# macOS / Linux
git branch --list 'task*' | xargs git branch -d
# Windows PowerShell
git branch --list 'task*' | ForEach-Object { git branch -d $_.Trim() }
원격에서 이미 삭제된 브랜치의 추적 정보는 git fetch --prune으로 정리한다.
커밋 작성자 바꾸기 (다른 계정으로 잔디 옮기기)
다른 이메일로 커밋했던 기록을 내 GitHub 계정 기록으로 인정받으려면 커밋의 작성자 정보를 바꿔야 한다. 커밋 기록 전체를 다시 쓰는 작업이라 개인 저장소에서만 하고, 끝나면 강제 push가 필요하다.
git filter-branch는 Git 문서에서도 사용을 권하지 않으므로 git filter-repo를 쓴다.
# mailmap.txt - 새 이름 <새 이메일> 옛 이름 <옛 이메일>
New Name <new@example.com> Old Name <old@example.com>
git filter-repo --mailmap mailmap.txt
기록을 바꾸지 않고 GitHub에서 인정받는 더 간단한 방법은, 옛 이메일을 GitHub 계정의 보조 이메일로 등록하는 것이다. GitHub는 계정에 등록된 이메일로 작성된 커밋을 그 계정의 기여로 집계한다.