Git 약간 특별한 사용법

2023년 9월 18일 수정

이 글은 Git에서 그나마 자주 사용하지는 않지만 한 번 쯤은 사용할 지도 모를 기능을 정리한다. 특별함의 기준은 그냥 개인적으로 잘 안 쓰는 기능 정도다. 이 외의 기본적인 기능은 Git 일반적인 사용법 글을 참고하자.

마지막 커밋 취소하기

reset 명령을 이용해 저장소의 내용을 특정 커밋 시점으로 되돌릴 수 있다.

git reset HEAD~

변경점만 스테이지 하기(Stage Patch)

파일 단위가 아니라 변경된 내역 단위로 스테이지 하려면 -p 옵션을 추가로 사용한다.

git add -p

이렇게 하면 각 변경점 위주로 리뷰하며 스테이지할 패치를 고를 수 있다.

커밋 메시지 수정하기

아래 명령으로 가장 최근의 커밋 메시지를 수정할 수 있다.

git commit --amend

브랜치 간 파일 비교하기

diff 명령으로 두 브랜치 사이의 특정 파일을 비교하려면 아래와 같은 커맨드를 사용할 수 있다.

git diff branch-a branch-b -- path/to/file

이외에 아래와 같은 방법도 있는 듯 하다.

git diff branch-a:path/to/file branch-b:path/to/file

특정 파일의 수정 이력 조회하기

아래 명령은 해당 파일의 커밋 별 변경 이력을 최근부터 과거 순으로 계속 보여준다.

git log -p path/to/file

다른 브랜치에서 파일 복사해오기

아래와 같이 다른 브랜치의 파일을 현재 브랜치로 복사해 올 수 있다.

git checkout branch_name path/to/file

특정 원격 브랜치를 로컬에 그대로 가져오기

원격에만 있는 특정 브랜치를 로컬에 같은 이름의 브랜치로 가져오기 위해서는 아래 커맨드를 이용한다.

git checkout -t origin/branch_name

위 커맨드를 사용하면 로컬에 branch_name 브랜치가 생성되고 여기에 원격(origin)의 branch_name 브랜치의 내용을 가져온다.

요즘은 pull 을 하게 되면 원격 브랜치도 쌓이기 때문에 그냥 switch 만 하면 되는 듯하다.

다른 브랜치의 내용 패치 하기

다른 브랜치의 내용을 현재 브랜치로 몽땅 머지하려면 아래와 같이 할 수 있었다.

git merge another_branch_name

만약 해당 브랜치의 모든 변경 내역이 아닌 특정 파일만 복사해 오고 싶다면 checkout 을 사용할 수 있다.

git checkout another_bracn file_path

특정 파일을 전체가 아닌 수정 단위로만 패치하고 싶다면 -p 옵션을 사용할 수 있다.

git checkout -p branch_name file_path

커밋 합치기

예를 들어 가장 최근의 4개 커밋을 하나로 합치고 싶다면 rebase 커맨드를 이용할 수 있다.

git rebase -i HEAD~4

-i 옵션은 인터랙티브(interactive) 하게 한다는 의미이며, HEAD~4 는 HEAD 에서 4단계의 커밋까지 라는 범위를 지정하는 의미다.

이후 편집기가 뜨면서 합칠 커밋을 선택한다. 대표가 될 커밋은 pick 을 하고 합쳐질 커밋은 squash 로 표기하면 된다. 작업 시 하단에 도움말이 나타나므로 잘 읽어보자.

업데이트 무시하기

어떤 이유(?)로 특정 파일이 업데이트 되어도 이를 커밋하지 않으려면 아래 커맨드를 이용할 수 있다.

git update-index --assume-unchanged PATH

이제 해당 파일은 업데이트 되어도 status 에 나타나지 않는다. 다만 이 방법은 몇몇 커맨드에 의해 다시 원래대로 돌아올 수 있다. 예를 들어 브랜치를 바꾸거나 pull 상황에 따라 다시 나타날 수 있다.

원격과 브랜치 동기화 하기

예를 들어 이런저런 작업을 하면서 원격에서 받은 브랜치가 많아졌는데, 시간이 흐른 후 원격에서 이런 브랜치들 일부가 사라졌다. 이럴 때 아래 커맨드로 원격에서 삭제된 브랜치를 로컬에서 지울 수 있다.

git fetch --prune

fetch 시 --prune 혹은 -p 옵션은 원격에 없는 원격 브랜치를 추적 중인 로컬 브랜치를 삭제해 준다. 참고로 완전한 동기화는 안 해주니 오해하지 말자.

다른 브랜치간의 변경 내역만 뽑아서 적용하기

예를 들어 A 라는 브랜치에서 출발한 B 브랜치에서 작업하다가 너무 잦은 머지로 트리가 너무 복잡해졌다. 이 경우 커밋을 정리하기 위해 rebase를 사용할 수도 있겠지만 이번에는 C라는 브랜치를 만들어서 여기다 B의 수정 사항만 별도로 커밋을 만들고 싶다고 하자.

우선 변경 사항만 뽑아보자.

git diff A B > /foo/bar/patch

이렇게 하면 A를 기준으로 B의 내용을 패치로 뽑아준다. 즉 A에서 B로 바꿔야 할 때 무엇을 수정해야 하는 지가 파일로 정리된다.

이제 원하는 브랜치인 C에다 변경 사항을 적용해보자.

git switch C
git apply /foo/bar/patch

apply 명령을 통해 현재 브랜치에 간단히 패치를 적용할 수 있다.

로컬의 변경점을 무시하고 원격으로 되돌리기

reset 을 강하게 원격으로 때려버리면(?) 원하는 대로 할 수 있다. 아래 예는 현재 로컬의 브랜치 내용을 원격의 master 브랜치로 일치시키는 커맨드다.

git reset --hard origin/master

뭐 알겠지만 로컬 커밋 내역이 싹 날아갈 수 있으므로 주의하자.

기여자 목록 보기

커밋 내역에서 기여자 혹은 작성자가 누구인지 확인할 때 유용한 명령이다.

git log --format='%aN' | sort -u

sort 를 하는 이유는 유니크 목록을 뽑기 위함이다. 즉 앞의 git 명령어는 커밋 히스토리 상의 기여자 이름을 중복 체크를 하지 않고 몽땅 출력한다.

나중에 커밋 끼워넣기

현재 스테이징 된 변경점을 특정 커밋에서 한 것처럼 끼워 넣으려면 아래와 같이 커밋 시 fixup 명령을 쓸 수 있다.

git commit --fixup=COMMIT_HASH

커밋 메시지 뿐만 아니라 커밋 변경점 자체를 바꾸기 위해서는 rebase 가 추가로 필요하다.

git rebase -i --autosquash COMMIT_HASH

이후 필요한 작업을 적절히 해서 변경 내역을 합칠 수 있다.