만약 하나 혹은 여러 파일에 걸쳐 많은 변경사항들이 존재하는 상황에서, 일부 변경사항에 대해서만 커밋을 수행하고 싶다면, 아래와 같은 방법으로 커밋에 포함되길 원하는 변경사항들을 선택할 수 있다:
git add -p
또는
git add -p [file]
위 명령어 수행시 변경사항들이 개별적으로 표시되며, 각 변경사항에 대하여 다음 옵션 중 하나를 선택할 수 있는 대화형 입력 프롬프트가 나타날 것이다:
y - 이 변경사항 조각(hunk) 을 추가한다.
n - 이 변경사항 조각을 추가하지 않는다.
d - 이 변경사항 조각 및 이후 현재 파일 내의 모든 조각들을 추가하지 않는다.
한 파일 내에서 이미 원하는 변경사항을 추가 완료하여 나머지를 건너뛰고 싶은 경우 유용하다.
s - 가능한 경우 이 변경사항 조각을 더 작은 단위의 조각으로 나눈다
e - 현재 변경사항 조각 내용을 직접 편집한다. 이 기능이 아마도 가장 강력한 기능일 것이다. 이 옵션 선택시 편집기가 실행되며, 이를 통해 주어진 변경사항을 필요에 따라 편집할 수 있다.
위에서 소개된 작업을 통해 파일들의 특정 부분들을 선택하여 stage 시킬 수 있을 것이다. 이렇게 stage 된 모든 변경사항들에 대해 이제 아래와 같이 커밋을 수행할 수 있다:
git commit -m 'Commit Message'
위와 같이 stage 및 커밋되지 않은 변경사항들은 여전히 사용자의 작업 디렉토리에 존재하여, 필요한 경우 이후 다른 커밋에 포함시킬 수 있다.
혹은 작업 디렉토리에 남아있는 변경사항들이 불필요한 경우, 아래 명령을 실행하여 제거할 수 있다:
git reset --hard
이러한 방법은 큰 규모의 변경사항을 작은 커밋들로 쪼개는 목적 이외에도, 커밋하려는 내용을 리뷰하기에도 매우 유용하다.
개별 변경사항들에 대해 검토하는 과정을 거침으로써, 스스로 작성한 코드를 확인할 수 있으며 불필요한 로그를 위한 코드 등이 잘못해서 stage 되는 실수 또한 방지할 수 있다.
사용자의 가장 마지막 커밋이 아직 발행되지 않았다면 (아직 upstream 저장소에 push 하지 않았다면) 해당 커밋을 수정(amend) 할 수 있다.
git commit --amend
위 명령어는 현재 stage 된 변경사항들을 이전 커밋에 추가해 준다.
Note: 이 방법은 잘못 작성된 커밋 메시지를 수정할 때에도 주로 사용된다. 위 명령어 수행시 기본 편집기가 실행되어 (주로 vi / vim / emacs) 이전 커밋 메시지를 변경할 수 있도록 해준다.
커밋 메시지를 명령줄에서 직접 기술하려면:
git commit --amend -m "New commit message"
혹은, 이전 커밋 메시지를 변경 없이 그대로 이용할 수도 있다:
git commit --amend --no-edit
amend 수행시 커밋 날짜는 업데이트 되지만, 작성 날짜 (author date) 는 변경하지 않는다. 이 날짜 정보까지 갱신하기를 원한다면 아래와 같이 입력한다.
git commit --amend --reset-author
커밋의 작성자 (author) 역시 amend 시에 변경 가능하다:
git commit --amend --author "New Author <email@address.com>"
Note: 마지막 커밋을 amend 한다는 것은 이전 커밋을 새로운 커밋으로 완전히 대체하는 작업으로써, 이전 커밋은 브랜치의 history 에서 아예 제거되게 된다. 이러한 특성은 공개된 (public) 저장소와 다른 협력자 (collaborator) 들과 함게하는 브랜치에서 작업할 때 항상 염두에 두어야 한다.
이러한 특성으로 인해, 이미 push 된 커밋을 amend 하게 된다면 이후 push 시에 --force 옵션 기술이 필요하게 된다.
git log 내역을 살펴보는 사람에게 있어, 각각의 커밋의 목적이나 내용을 쉽게 파악할 수 있는지의 여부는 굉장히 중요하다.
좋은 커밋 메시지는 일반적으로 작업 (task) 이나 문제점 (issue) 관리 시스템상의 번호와 함께 무엇을 어떤 이유로, 어떻게 작업하였는지에 대한 간략한 설명을 포함하게 된다.
다음과 같은 메시지들은 좋은 커밋 메시지의 한 예라고 할 수 있다:
TASK-123: Implement login through OAuth
TASK-124: Add auto minification of JS/CSS files
TASK-125: Fix minifier error when name > 200 chars
반면에, 아래와 같은 메시지들은 그다지 유용한 정보를 포함하고 있지 않다:
fix // 무엇을 고쳤는가?
just a bit of a change // 무엇을 변경하였는가?
TASK-371 // 다른 설명이 전혀 포함되어 있지 않아, 직접 이슈 관리 시스템을 확인해 보아야 커밋 내용에 대한 정보를 얻을 수 있다
Implemented IFoo in IBar // 이러한 수정사항이 왜 필요한가?
커밋 메시지가 적절한 방향으로 작성되었는지를 판단할 수 있는 한가지 방법으로는 아래 문장의 밑줄 부분에 작성한 커밋 메시지를 대입 가능한지 확인해 보는 것이다:
If I add this commit, I will ___ to my repository.
훌륭한 커밋 메시지를 작성하기 위한 7가지 규칙
주제를 기술한 라인과 본문을 작성한 부분 사이에 빈 줄을 하나 배치하여 두 부분을 분리시킨다
소스 코드를 변경한 이후에 커밋을 하기 위해서는, 해당 변경 사항들을 stage 하여야 한다.
예를 들어, README.md 파일과 program.py 파일을 수정하였다면:
git add README.md program.py
위와 같은 명령을 통해 해당 파일들을 다음에 수행할 커밋에 포함되도록 추가할 수 있다.
그런 다음, stage 된 변경사항을 아래와 같이 커밋한다.
git commit
위 명령 수행시 텍스트 편집기가 실행되는데, 많은 경우 vim 편집기가 뜨게 된다. 만약 vim 사용에 익숙치 않다면, i 키를 눌러 텍스트 삽입 모드로 변경할 수 있으며, 커밋 메시지를 작성한 다음에는 Esc 를 누르고 :wq 를 입력하여 저장 및 종료할 수 있다는 정도만 기억하도록 한다.
텍스트 편집기 실행을 피하고 싶다면,
-m 옵션과 함께 커밋 메시지를 직접 입력할 수도 있다.
git commit -m "Commit message here"
커밋 메시지는 종종 특정한 서식을 따르는 경우가 많으므로, 더 자세한 설명을 위해서는 "커밋 메시지 잘 작성하기" 섹션을 참고하도록 한다.
단축 옵션
만약 상당히 많은 수의 파일들을 변경하였다면, 각 파일들을 일일이 나열하는 대신에, 아래와 같이 수행할 수 있다:
git add --all # "git add -a" 와 동일하다
혹은 최상위 디렉토리에서부터 하위 디렉토리까지의 모든 변경사항들을 삭제된 파일들을 제외하고 추가하기를 원한다면 아래와 같이 수행한다:
git add .
혹은 현재 Git 에 의해 추적 (tracked) 되고 있는 파일들만 추가하기를 원한다면 ("update"):
git add -u
이후 만약 필요하다면, stage 된 변경사항들을 아래와 같이 확인한다:
git status # 변경된 파일들의 목록을 출력한다
git diff --cached # stage 된 파일들 내의 stage 된 변경사항들을 보여준다
최종적으로, 변경 사항들을 아래와 같이 커밋한다:
git commit -m "Commit message here"
다른 방법으로, 새로운 파일 생성 없이 기존 파일들에 대해 수정 혹은 삭제만 수행하였다고 하면, git add 와 git commit 을 한 명령어로 합쳐서 수행할 수 있다:
git commit -am "Commit message here"
이 방법은 git add --all 와 동일한 방법으로 변경된 파일들을 stage 시킨다는 점을 유의하라.
민감 정보 관련
커밋에는 비밀번호나 private key 등 어떠한 형태의 민감한 정보도 포함하여서는 안된다. 만약 이러한 일이 발생하여 해당 변경사항이 중앙 서버로 push 되었다면, 해당 민감 정보는 이미 유출외었다고 생각해야 할 것이다.
다른 측면에서는, 이후에 이러한 정보를 제거하는 것이 가능하기도 하다. 쉽고 빠른 방법중의 하나는 "BFG Repo-Cleaner" 를 이용하는 것이다: https://rtyley.github.io/bfg-repo-cleaner/.
bfg --replace-text passwords.txt my-repo.git 명령어 수행 시, passwords.txt 파일에서 암호들을 읽어 해당 암호들을 ***REMOVED*** 문자열로 치환시킨다. 이 작업은 전체 저장소 내의 모든 커밋들을 대상으로 한다.
커밋을 GPG-sign 하도록 설정하거나, commit.gpgSign 설정을 무시하도록 설정한다.
-n, --no-verify
커밋 수행시 pre-commit 과 commit-msg hook 을 수행하지 않도록 한다. "Hook 사용하기" 챕터를 참고하라.
Git 에서의 커밋은 매 코드상의 변경사항에 대해 작성자의 공헌 정보를 포함함으로써 책임 소재를 명확하게 하며, 특수성과 보안성을 위한 다양한 기능을 제공한다. 이 챕터에서는 Git 에서의 커밋 작업을 적절하게 수행하는 방법들을 설명하고 참고할 수 있는 예제를 제시한다.