잘 사용하지 않지만 유용한 Git 명령어들

0

이 글은 dev.to에 올라온 Alicia Sykes의
“20 Git Commands you (probably) didn’t know about”
이란 글을 참고했습니다.


git 매뉴얼을 찾아본 적이 있거나 man git을 실행해본 적이 있다면 git에는 우리가 주로 사용하는 것보다 훨씬 더 많은 것이 있다는 것을 알게 될 겁니다. 그런데 이 중에서 잘 사용되지 않지만 사용하면 개발 프로세스를 레벨업하고, 동료들에게도 도움이 될 수 있는 꽤 멋진 기능들이 있는 만큼 한 번 정도는 살펴보고 사용법을 알아둘 필요가 있습니다.

멋진 사용자 경험을 제공하는 Git의 22가지 기능들

1. Git Web

git instaweb을 실행하여 작업 중인 저장소를 즉시 gitweb에서 둘러볼 수 있습니다.

Git에는 로컬 저장소 검색을 위한 웹 기반 비주얼라이저가 내장되어 있는데, 이 명령어를 실행하면 브라우저의 GUI를 통해 저장소를 보고 관리할 수 있고, 다음과 같은 유용한 기능을 사용할 수 있습니다.

  • 수정 사항 검색 및 단계별 검토, 다른 점, 파일 내용 및 메타 데이터 검사하기
  • commit 로그, 브랜치, 디렉터리, 파일 기록 및 첨부된 데이터 시각화하기
  • commit 및 저장소 활동 기록의 RSS 또는 Atom 피드 생성하기
  • commit, 파일, 변경 사항 및 다른 점 검색하기

이 유용한 기능들을 사용하려면, 해당 저장소 안에서 git instaweb을 실행하고, 브라우저에서 http://localhost:1234로 접속하면 됩니다. 만약 Lighttpd가 설치되어 있지 않다면 -d 플래그를 사용하여 대체 웹 서버를 지정할 수 있고, 이 외에도 -p(포트), -b(브라우저) 플래그로 구성하거나, git 설정의 instaweb블록 아래에 구성할 수도 있습니다.

또 GUI 기반의 git 앱을 열 수 있는 git gui 명령도 있는데, 이 명령어도 역시 유용할겁니다.

dev.to

2. Git Notes

git notes를 사용하여 commit에 추가 정보를 첨부할 수 있습니다.

때로는 변경 사항, 메시지, 날짜-시간 및 작성자 정보 이외의 추가 데이터를 git commit에 첨부해야 하는 경우가 있습니다. 메모는 .git/refs/notes에 저장이 되는데, commit 객체 데이터와는 별개로 언제든지 SHA-1 해시를 변경하지 않고 commit과 관련된 메모를 수정할 수 있습니다.

메모는 git log, Git GUI 앱 또는 git notes show 명령어를 사용하여 볼 수 있는데, 일부 git 호스트는 commit을 표시할 때 메모도 함께 표시해 주기도 합니다.

3. Git Bisect

git bisect를 사용하면 이진 검색을 사용하여 버그를 유발한 commit을 찾을 수 있습니다.

git bisect는 가장 강력하면서도 사용하기 쉬운 git 명령 중 하나입니다. bisect은 commit을 판별할 수 있게 해주는데, commit이 good(버그 없음)인지, 또는 bad(버그 발견)인지를 알려주기 때문에 버그를 유발한 가장 초기 commit으로 범위를 좁혀나갈 수 있습니다.

시작하려면 우선 git bisect start를 실행한 다음, git bisect good <commit-hash>를 사용하여 버그가 없는 good commit을 전달하고 git bisect bad <optional-hash>를 사용하여 버그가 있는 bad commit을 전달하면 됩니다.

그럼 good commit과 bad commit의 중간 commit으로 checkout이 되는데, 이때 또 git bisect good 또는 git bisect bad 중 하나로 버그가 존재하는지를 지정할 수 있습니다. 버그 포함된 commit을 찾을 때까지 이 프로세스를 반복하면서 bad commit과 good commit의 중간에 있는 commit을 확인할 수 있는데, git bisect reset을 사용하면 언제든지 취소할 수 있습니다.

문서에는 다시 보기, commit 보기, 건너뛰기 등 훨씬 더 많은 기능이 있는데, 디버깅을 할 때는 문서를 확인해 보는 것이 좋습니다.

4. Git Grep

git grep을 사용하여 저장소에서 코드, 파일, commit 또는 기타 항목 검색할 수 있습니다.

git 프로젝트 내에서 문자열을 검색해야 하는 경우 git grep을 사용하면 어떤 문자열이나 정규식을 사용하여 Ctrl + F보다 강력하고 쉽게 검색할 수 있습니다.

git grep <regexp> <ref>

이 명령어에는 검색 범위를 좁히거나 결과 형식을 지정할 수 있는 다양한 옵션이 포함되어 있는데, 예를 들어, 파일 이름만 반환하려면 -l를, 반환할 파일당 일치 항목 수를 지정하려면 -c를, 조건과 일치하는 결과를 제외하려면 -e를 사용하면 되고, --and로 여러 조건을 지정하거나, -n를 사용하여 줄 번호로 검색할 수도 있습니다.

git grep은 정규식을 사용할 수 있어 검색 문자열을 훨씬 고도화 시킬 수 있는데, git grep 'console.log' *.js와 같이 파일 확장자를 지정하여, 자바스크립트 파일 내의 모든 console.log를 표시할 수도 있습니다.

두 번째 매개 변수는 참조로 브랜치 이름, commit, commit 범위 또는 기타 항목이 될 수 있는데, 예를 들어 git grep "foo" HEAD~1을 입력하면 이전 commit을 검색할 수 있습니다.

5. Git Archive

git archive를 사용하여 전체 저장소를 단일 파일로 결합할 수 있습니다.

저장소를 공유하거나 백업할 때는 단일 파일로 저장하는 것이 좋은데, git archive를 사용하면 모든 저장소 기록이 포함되기 때문에 쉽게 원래의 형태로 압축을 풀 수 있습니다. 또 이 명령어에는 많은 추가 옵션이 포함되어 있어 아카이브에 포함할 파일과 포함하지 않을 파일을 정의할 수 있습니다.

git archive --format=tar --output=./my-archive HEAD

6. Git Submodules

git submodule을 사용하여 다른 저장소를 자신의 저장소로 가져올 수 있습니다.

git의 submodules을 사용하면 하나의 저장소를 다른 저장소에 마운트할 수 있는데, 일반적으로는 코어 종속성 또는 컴포넌트를 별도의 저장소로 분할하기 위해 사용이 됩니다.

다음 명령을 실행하면 모듈을 지정된 위치로 pull하고 저장소가 복제될 때 항상 다운로드되도록 .gitmodules 파일도 생성되는데, --recursive 플래그를 사용하면 저장소를 복제할 때 하위 모듈을 포함하게 됩니다.

git submodule add https://github.com/<user>/<repo> <path/to/save/at>

유사한 작업을 수행하지만 메타데이터 파일이 필요하지 않은 경우에는 git subtree를 사용할 수도 있습니다.

7. Git Bug Report

git bugreport를 사용하여 git 및 시스템 정보를 포함한 버그 티켓을 작성할 수 있습니다.

이 명령어는 시스템 정보를 캡처한 다음 표준 버그 템플릿(재현 단계와 실제 + 예상 출력 등)을 여는데, 완성된 파일은 필요한 모든 정보가 캡처된 매우 완전한 버그 보고서로서, 필요한 모든 데이터가 포함되어 있는지 확인하기 때문에 오픈 소스 패키지의 관리자가 사용자(개발자)에게 버그 보고서를 제출하도록 요청하는 경우에 매우 편리합니다.

코어 git 시스템에 버그 리포트를 제출하는 경우에는, git diagnostic 명령어를 실행한 후 이 곳에서 문제를 제기할 수도 있습니다.

8. Git Fsck

git fsck를 사용하여 모든 객체를 확인하거나 연결할 수 없는 객체를 복구할 수 있습니다.

자주는 아니지만, git에 의해 저장된 객체를 확인해야 하는 경우가 있는데, 이 때 fsck(또는 File System ChecK)를 통해 객체 데이터베이스를 테스트하고 모든 객체의 SHA-1 ID를 검증하고 연결을 확인할 수 있습니다.

또한 다른 명령과 달리 .git/objects의 모든 항목이 포함되기 때문에 --unreachable 플래그와 함께 사용하여 명명된 참조에서 더 이상 연결할 수 없는 객체를 찾을 수도 있습니다.

9. Git Stripspace

git stripspace를 사용하여 주어진 파일 내의 공백 형식을 지정할 수 있습니다.

가장 좋은 방법은 줄 끝에 후행 공백을 피하고 여러 개의 빈 줄이 연속되지 않도록 하고, 입력의 시작과 끝에서 빈 줄을 피하고 각 파일을 새 줄로 끝내는 겁니다. prettier 처럼 이런 작업을 자동으로 수행하는 언어별 도구가 많이 있지만 Git에도 이 기능이 내장되어 있습니다.

물론 이것은 메타데이터(commit 메시지, 태그, 브랜치 설명 등)를 위한 것이지만 파일에 파이프를 연결한 다음 응답을 다시 파일에 파이프(|)를 연결하는 경우에도 잘 작동합니다.

cat ./path-to-file.txt | git stripspace

또는

git stripspace < dirty-file.txt > clean-file.txt

또한 --strip-comments를 함께 사용하여 주석을 제거하거나 --comment-lines를 함께 사용하여 줄을 주석 처리할 수도 있습니다.

10. Git Diff

git diff를 사용하면 두 코드 간의 차이점을 비교할 수 있습니다.

git diff를 실행하여 마지막 commit 이후의 모든 변경 사항을 표시하거나, git diff <commit-sha>를 사용하여 2개의 commit 또는 1개의 commit을 HEAD와 비교할 수 있는 있는데, 사실 diff 명령으로 할 수 있는 것은 훨씬 더 많습니다.

diff file-1.txt file-2.txt와 같이 임의의 두 파일을 비교할 수도 있기 때문에 diffchecker.com와 같은 사이트를 방문할 필요가 없습니다.

git diff branch1..branch2와 같이 사용하면 2개의 브랜치 또는 참조를 서로 비교할 수 있는데, 이중 점(..)은 공백과 동일한 역할로, diff 입력이 브랜치의 끝이어야 함을 나타내지만, 트리플 점(…)을 사용하여 첫 번째 파라미터를 두 diff 입력 사이에 공유된 공통 조상 commit의 ref로 변환할 수도 있습니다.

이 기능은 매우 유용한데, 브랜치 간에 단일 파일만 비교하고 싶은 경우 파일 이름을 세 번째 인수로 전달하면 됩니다.

지정된 날짜 범위 내에서 변경된 모든 내용을 확인하고 싶다면, 다음과 같이 명령어를 입력하면 되는데, 이는 파일 이름, 브랜치 이름, 특정 commit 또는 기타 참조와 쌍을 이룰 수 있습니다.

git diff HEAD@{7.day.ago} HEAD@{0}(지난 주)

추가로 commit 범위를 비교하기 위한 간단한 인터페이스를 제공하는 git range-diff 명령어도 있는데, git range-diff 툴은 자신의 diff checker를 사용하는 옵션뿐만 아니라 훨씬 더 많은 기능을 제공하고 있기 때문에, 문서를 확인해 보는 것이 좋습니다.

11. Git Hooks

주어진 get 작업이 발생할 때 명령을 실행하거나 스크립트를 실행 할 때는 hooks를 사용하면 됩니다.

Hooks를 사용하면 거의 모든 것을 자동화할 수 있는데, 예를 들어 표준이 충족되는지 확인(commit 메시지, 브랜치 이름, 패치 크기)하거나, 코드 품질(테스트, 린트)을 테스트하고, commit에 부가 정보(사용자, 장치, 티켓 ID)를 추가하거나, 이벤트 기록 또는 파이프라인 실행을 위해 webhook을 호출 할 수도 있습니다.

git hooks에는 commit, rebase, merge, push, update, applypatch 등과 같은 대부분의 git 이벤트에 사용할 수 있는 사전 및 사후 hook이 있는데, hook은 git config core.hooksPath를 사용하여 다른 위치에 구성하지 않는 한 .git/hooks에 저장이 되고, git hook 명령어로 테스트 할 수 있습니다. 또 이 명령어는 쉘 파일이기 때문에 모든 명령을 실행하는 데 사용할 수 있습니다.

hook은 원격 저장소로는 push되지 않기 때문에, 팀 전체에서 hook을 공유하고 관리하려면 lefthook 또는 husky와 같은 hook manager를 사용해야 합니다. hook을 더 쉽게 관리할 수 있는 다른 도구들도 있지만, hook은 언제든지 --no-verify 플래그를 사용하여 건너뛸 수 있기 때문에, 특히 보안과 관련된 모든 경우에는 hook에만 전적으로 의존해선 안됩니다.

12. Git Blame

git blame은 특정 수정 사항 및 라인에 대한 작성자 정보를 표시하는 데 사용합니다.

git blame는 누가 특정 코드 라인을 작성했는지 빠르게 찾아주는데, 변경된 시점을 확인하고 해당 commit 및 관련 메타데이터를 검사하는 데도 유용하게 사용할 수 있습니다.

예를 들어 index.rs라는 파일이 있고, 400~420행에 대한 작성자 및 commit 정보를 보고 싶다면 다음과 같이 실행하면 됩니다.

git blame -L 400,420 index.rs

13. Git LFS

git lfs를 사용하여 대용량 파일을 저장할 때 저장소가 다운되지 않도록 할 수 있습니다.

종종 프로젝트에는 데이터베이스, 바이너리 에셋, 아카이브 또는 미디어 파일과 같은 대용량의 파일이 포함되어 git 워크플로우가 느려지고 사용 한도에 도달하게 되는데, 대용량 파일 스토리지는 이런 대용량 자산을 다른 곳에 저장하는 동시에 git으로 추적할 수 있고, 동일한 액세스 제어 및 권한을 유지할 수 있도록 지원해줍니다.

LFS는 대용량의 파일을 git 내에서 추적되는 텍스트 포인터로 대체하여 작동하는데, git lfs track <file glob>을 통해 실행할 수 있고, 실행 후에는 .gitattributes 파일이 업데이트 됩니다. *.psd와 같이 확장자나 디렉토리 또는 개별적으로 파일을 지정할 수 있는데, 추적하고 있는 LFS 파일 목록을 보고 싶다면 git lfs ls-files를 실행하면 됩니다.

14. Git GC

git gc를 사용하여 저장소 최적화할 수 있습니다.

시간이 지남에 따라 git 저장소에는 다양한 유형의 가비지가 축적되어 디스크 공간을 차지하고 작업 속도를 늦추게 되는데, 이때 내장된 가비지 컬렉터를 사용할 수 있습니다.

git gc를 실행하면 git prune을 포함하는 고립되고 액세스할 수 없는 commit, 파일 수정 사항 및 저장된 git 객체를 압축할 뿐만 아니라, ref 압축, reflog 가지치기, revere 메타데이터 또는 오래된 워킹 트리 및 인덱스 업데이트와 같은 일반적인 하우스 키핑 작업을 수행하게 됩니다.

--aggressive 플래그를 추가하면 저장소를 적극적으로 최적화시키는데, 기존 델타를 버리고 다시 계산하기 때문에, 실행 시간이 훨씬 더 오래 걸리지만 저장소가 큰 경우에는 이 플래그를 사용해 최적화할 필요가 있습니다.

15. Git Show

git show를 사용하여 모든 git 객체를 쉽게 검사할 수 있습니다.

git show는 블롭, 트리, 태그 또는 commit 객체를 쉽게 읽을 수 있는 형태로 출력해 주는데, git show <object>와 같이 사용할 수 있고, 더욱 명확한 출력을 원한다면 --pretty 플래그를 추가할 수도 있습니다. 또 --format을 사용하면 모든 사용자 정의 출력 옵션을 확인 할 수 있습니다.

브랜치를 전환하지 않고 다른 브랜치의 파일을 미리 보는 것은 매우 유용한 기능인데, git show branch:file로 해당 기능을 사용할 수 있습니다.

16. Git Describe

git describe는 commit에서 연결할 수 있는 최신 태그를 찾고 읽을 수 있는 이름을 지정하기 위해 사용합니다.

git describe를 실행하면 마지막 태그 이름과 현재 commit을 결합한 문자열을 생성하여 만든 사람이 읽을 수 있는 문자열이 표시되고, 특정 태그를 전달할 수도 있습니다.

--all 플래그를 추가하지 않는 경우에는 태그를 생성해야 하는데, Git describe는 기본적으로 주석이 달린 태그만 사용하기 때문에 경량 태그를 사용하려면 --tags 플래그를 지정해야 주어야 합니다.

17. Git Tag

git tag를 사용하여 저장소 기록의 특정 지점에 태그를 지정할 수 있습니다.

릴리즈 버전을 나타낼 때, 가장 일반적으로 사용되는 저장소 기록의 특정 중요 지점에 태그를 지정하는 것은 종종 유용한데, 태그를 생성하는 것은 git tag <tagname>만큼 간단합니다. git tag -a v4.2.0 <commit sha>로 기록 commit에 태그를 지정할 수 있고, commit과 마찬가지로 -m을 사용하여 태그 옆에 메시지를 추가 할 수 있습니다.

git push origin <tagname>을 사용하여 태그를 원격으로 push해 주어야 하는데, 모든 태그를 나열하려면 git tag를 실행하고, 와일드카드 검색을 하려면 -l을 사용하면 됩니다. 그런 다음 git checkout <tagname>을 사용하여 특정 태그로 checkout 할 수 있습니다.

18. Git Reflog

git reflog를 사용하여 저장소에서 수행한 모든 업데이트를 나열 할 수 있습니다.

Git은 참조 로그 또는 “reflogs”라는 메커니즘을 사용하여 브랜치에 대한 업데이트를 추적하는데, clone, pull, push, commit, checkout 및 merge를 포함한 다양한 이벤트를 추적할 수 있습니다. 많은 명령에서는 ref를 매개 변수로 사용하기 때문에 이벤트 참조를 찾는 것이 유용한 경우가 많은데, HEAD의 최근 이벤트를 보려면 git reflog를 실행하면 됩니다.

reflog는 손실된 commit을 복구하는데 매우 유용한데, Git은 rebase 또는 commit 수정과 같은 것을 통해 히스토리를 다시 작성한다 해도 실제로 손실되는 것이 없기 때문에, Reflog를 사용하면 브랜치나 태그에서 참조하지 않더라도 commit으로 돌아갈 수 있습니다.

기본적으로 reflog는 HEAD(현재 분기)를 사용하지만 모든 ref에서 reflog를 실행할 수 있습니다. 예를 들어, git reflog show <branch name>을 표시하거나 git reflog stash를 사용하여 숨겨진 변경 사항을 확인할 수 있고, 또는 git reflog show --all을 사용하여 모든 참조를 표시할 수 있습니다.

19. Git Log

git log를 commit 목록을 보는 데 사용할 수 있습니다.

현재 브랜치에서 최근 commit 목록을 보려면 git log를 실행하면 되는데, git log로 할 수 있는 일은 몇 가지가 더 있습니다.

dev.to

git log --graph --decorate --oneline를 사용하면 ref 포인터와 함께 깔끔한 commit 그래프가 표시되고, 또 다양한 매개변수를 기반으로 로그를 필터링해야 하는 경우에는 다음과 같은 매개변수를 사용할 수 있습니다.

git log --search="<anything>"
특정 코드 변경에 대한 로그 검색
git log --author="<pattern>"
특정 작성자에 대한 로그만 표시
git log --grep="<pattern>"
검색어 또는 정규식을 사용하여 로그 필터링
git log <since>..<until>
두 참조 간의 모든 commit 표시
git log -- <file>
특정 파일에 대한 모든 commit 표시

git shortlog를 실행하면 요약된 commit 목록을 볼 수 있습니다.

20. Git Cherry Pick

git cherry-pick은 참조로 지정된 commit을 선택하고 작업중인 HEAD에 추가할 때 사용합니다.

예를 들어, 다른 곳에서 현재 브랜치로 특정 commit을 가져와야 하는 경우가 있는데, 이는 핫픽스 적용, 변경 실행 취소, 손실된 commit 복원 및 특정 팀 협업 설정에 매우 유용할 수 있습니다. 하지만, 로그에 중복 commit이 발생할 수도 있는 만큼 전통적인 병합을 고려하는 것이 더 나은 경우가 많습니다.

Git Cherry Pick의 사용법은 간단한데, 그냥 git cherry-pick <commit-hash>를 실행하면 지정된 commit이 현재 브랜치로 pull되는 것을 확인할 수 있습니다.

21. Git Switch

git switch를 사용하면 브랜치 간 이동을 할 수 있습니다.

브랜치 간 이동은 꽤 자주 하게 되는 작업인데, switch 명령어는 git checkout의 단순화된 버전과 같아. switch는 브랜치 간에 생성하고 탐색하는 데 사용할 수 있지만 checkout과는 달리 브랜치 간에 이동할 때 수정된 파일을 복사하지는 않습니다.

checkout -b와 유사하게 switch 명령어에 -c 플래그를 추가하여 새 브랜치를 생성할 수 있는데, git switch -c <new branch>와 같이 사용하여 해당 브랜치로 바로 이동할 수 있습니다. 또 git switch -를 실행하면 실험적으로 변경한 사항이 모두 삭제되고 이전 브랜치로 돌아가게 됩니다.

22. Git Standup

git standup은 git commit을 기반으로 마지막 근무일에 수행한 작업을 기억하기 위해 사용 됩니다.

이 기능은 대부분의 git 클라이언트에는 포함되어 있지 않은 기능인데, 시스템 패키지 관리자를 사용하거나 1줄 짜리 curl 스크립트 또는 소스에서 빌드하여 쉽게 설치할 수 있습니다.

이 기능을 사용하면 주어진 시간 프레임에서 수행된 모든 작업을 멋진 형식의 목록으로 표시해 주는데, 사용법은 간단합니다. 그냥 git standup을 실행하거나 여러 옵션을 사용하여 표시할 데이터(작성자, 기간, 분기 등)를 지정해 주면 됩니다.

23. Tip

Git은 유용한 작업을 수행하는 추가 명령을 추가 기능으로 쉽게 확장할 수 있습니다. 예를 들어, 가장 완벽한 확장 기능 중 하나로 @tjgit-extras를 꼽을 수 있는데, 이 기능은 일반적인 git 작업을 자동화하기 위한 70개 이상의 추가 명령어를 제공해 주고 있습니다.

다른 유용한 git 애드온 목록은 stevemao/awesome-git-addons를 참조하면 되고, GitHub 저장소로 작업을 하는 경우에는 GitHub CLI를 사용하여 PR 관리, 이슈, 코드 리뷰 등과 같이 CLI에서 일반적으로 할 수 있는 작업을 수행할 수 있습니다.

출처: “20 Git Commands you (probably) didn’t know about”, Alicia Sykes

Leave a Reply