[Git] 12장 고급기능
- 버전관리
- 2022. 6. 25. 09:35
참조
refs
- 깃은 커밋으로 코드 이력을 관리합니다.
- 커밋은 고유의 SHA1 해시 값을 가지고 있으며, 이 해시값은 여러 기능에서 참조합니다.
- 깃에서는 참조하는 해시 값을 refs 목록 으로 가지고 있습니다.
해시
- 깃에서 해시 값은 매우 중요합니다.
- 깃은 SHA1 알고리즘을 사용하여 해시 값을 생성합니다.
- 해시 값은 깃의 동작을 구분하며, 중복되지 않는 유일한 값입니다.
- 깃의 모든 작업은 SHA1 해시 값을 참조합니다.
- 깃 내부적으로 동작하는 작업들은 SHA1 해시 값으로 연결 고리를 생성합니다.
- 따라서 깃의 동작을 정확히 이해하려면 해사 값을 자세히 알아볼 필요가 있습니다.
- 생성된 모든 해시 값은 show 명령어로 확인할 수 있습니다.
$ git show 해시값
역조회
- show 명령어는 해시 값을 사용하여 커밋 정보를 확인합니다.
- 반대로 rev-parse 명령어로 포인터의 해시 값을 알 수 있습니다.
- 예를 들어 브랜치는 커밋 해시 값을 가리키는 포인터입니다.
- 따라서 브랜치 이름을 사용하여 참조하는 해시 값을 조회할 수 있습니다.
- master 브랜치의 해시값을 확인해 봅시다.
$ git rev-parse master
참조 목록
- 깃은 SHA1 해시 값을 생성하고, 커밋은 생성된 해시 값을 간접적으로 사용합니다.
- 또 깃에서는 생성된 해시 값을 쉽게 참조할 수 있도록 refs 목록을 생성합니다.
- 깃의 모든 refs 목록은 저장소의 숨긴 영역인 .git/refs 폴더 안에 저장됩니다.
- 또 복잡한 SHA1 해시 값을 쉽게 찾아 사용할 수 있도록 별칭도 쓸 수 있습니다.
- 별칭은 .git/refs 폴더 안에서 생성 및 관리할 수 있습니다.
- 즉, refs 정보는 깃의 기능들을 구현하는 내부 메커니즘입니다.
- 처음 저장소를 생성하면 .git/refs 폴더에는 heads 와 tags 폴더만 있습니다.
- 새로운 브랜치를 만들 때마다 해시 값을 가지는 refs 파일들을 생성합니다.
$ ls .git/refs -all ---------저장소 refs 파일 목록
reflog
- 깃은 안정적인 작업을 유지하려고 참조된 모든 refs 를 기록합니다.
- 그리고 내부적으로 작업한 모든 HEAD 와 브랜치 포인터를 기록합니다.
- 이때 사용된 포인터들의 기록을 reflog 라고 합니다.
참조 기록
- reflog 기록은 reflog 명령어를 사용하여 확인할 수 있습니다.
- reflog 는 한 번이라도 사용했던 HEAD 와 브랜치를 기록합니다.
- 하지만 모든 기록을 영구적으로 가지고 있지는 않습니다.
- reflog 는 시스템에서 정의한 며칠 간의 기록만 보관합니다.
- 그 이전의 작업들은 모두 삭제 합니다.
$ git reflog
기록 확인
- reflog 의 기록들은 HEAD@{숫자} 형태입니다.
- 각 숫자는 작업을 수행한 해시 값을 가리킵니다.
- 따라서 reflog에 기록된 HEAD@{숫자} 포인터를 이용하여 커밋 정보를 확인할 수 있습니다.
- 마지막에 참조한 refs 로그의 해시 값 정보를 확인해 봅시다.
기간 확인
- 커밋의 로그 기록이 많은 경우 필터링할 수 있습니다.
- 필터링은 특정한 날짜, 시간 등 기준을 적용합니다.
- 다음 예처럼 어제 작업한 내역말 출력할 수 있습니다.
- 깃에서 참조하는 refs의 로그는 reflog 명령어 또는 git log -g 옵션을 사용하여 확인할 수 있습니다.
$ git show master@{yesterday}
기록 유지
- refs는 현재 로컬 저장소에서 작업한 모든 로그의 참조 기록입니다.
- 깃은 커밋, 브랜치 등 내부적으로 사용한 모든 객체의 로그를 기록합니다.
- 하지만 refs는 로컬 저장소에만 기록하므로 원격 저장소나 복제, 복사 등으로는 refs 기록을 옮길 수 없습니다.
파일 애너테이션
- 개발하다 보면 코드를 잘못 작성해서 오류가 발생하곤 합니다.
- 하지만 여러 개발자와 협업하다 보면 잘못된 코드를 찾는 것이 쉽지 않습니다.
blame
- 잘못된 코드가 어디서부터 시작되었는지 찾기 어렵습니다.
- 잘못된 내용을 찾으려면 모든 커밋이력을 살펴보아야 하는데, 생각보다 시간이 오래 걸립니다.
- 깃은 이러한 코드를 쉽게 찾을 수 있게 파일의 수정 이력을 분석합니다.
- 그리고 blame 기능은 커밋의 메타 정보를 코드 라인별로 같이 결합하여 출력합니다.
- 코드를 수정한 사람이 누구인지, 언제 수정한지를 쉽게 판별할 수 있으며, 메타 정보를 바당으로 문제를 좀 더 쉽게 파악할 수 있습니다.
blame 기능 실습
1. master 브랜치에서 index.html 내용 수정 후 커밋
- master 브랜치로 checkout 합니다.
- 그리고 index.html 내용을 수정 후, 커밋합니다.
2. blame 명령어로 확인
- blame 명령어는 개별 파일에서만 동작하며, 명령어 인자 값으로 개별 파일을 전달합니다.
$ git blame 파일이름
옵션 활용
- 소스 코드의 용량이 클 때는 이력 정보도 많이 출력됩니다.
- 이때는 -L 옵션을 사용하여 파일의 특정 영역만 지정할 수 있습니다.
$ git blame -L 시작줄, 마지막줄 파일이름
replace
- 기본적으로 한 번 생성된 객체는 변경할 수 없습니다.
- 커밋을 변경하려면 깃의 원리를 응용해야 합니다.
- 커밋이 참조하는 해시 값을 속여서 다른 커밋으로 변경하는 것입니다.
- replace는 기존 커밋을 다른 커밋인 것처럼 변경하는 기능입니다.
- 깃 저장소에서 오랫돈안 작업하면 수많은 커밋 기록이 쌓입니다.
- 커밋이 많아지면 저장소 크기도 증가합니다.
- 저장소를 분리할 수 있는 서브모듈이 있지만, 오래된 저장소와는 다릅니다.
- 이때 replace 를 사용하면 커밋이 많은 오래된 저장소를 분리할 수 있습니다.
가비지 콜렉트(garbage collect)
- 깃은 저장소를 효율적으로 유지 관리하려고 가비지 콜렉트(garbage collect)를 지원합니다.
- 또 깃은 가비지를 효과적으로 관리할 수 있는 별도의 명령어를 제공합니다.
가비지
- 가비지(garbage) 는 동적인 언어에서 메모리를 관리하려고 생성한 개념입니다.
- 깃은 이력을 추적할 때 객체의 생성과 변경을 반복합니다.
- 여러 번 처리 동작을 반복하면서 시간이 지남에 따라 연결 고리가 없는 고립된 객체들이 생겨 비효율적인 자원 상태가 됩니다.
- 고립된 객체들은 대표적으로 리셋(reset) 또는 리베이스(rebase) 등을 자주 할 때 발생합니다.
- 연결 고리가 없는 객체들은 불필요하며, 용량만 차지하므로 정리해주는 작업이 필요합니다.
가비지 생기는 이유
- 깃의 커밋은 생성된 객체의 연결 고리를 설정하는 동작입니다.
- 커밋을 변경하면 새로운 객체로 연결 고리를 재설정합니다.
- 하지만 기존에 연결된 객체들은 삭제하지 않고 유지합니다.
- 이러한 과정에서 불필요한 가비지가 생성됩니다.
- 이처럼 객체는 향후 수동으로 커밋을 복구할 때 사용할 수 있기 때문에 유지합니다.
압축 관리
- 깃의 내부 원리는 SHA1 해시와 객체의 응용입니다.
- 파일 변경, 트리 구조, 커밋 등 대부분의 내부 작업은 객체를 생성하고 연결하는 동작들입니다.
- 커밋들이 실행될 때 이러한 내부 동작으로 연결 고리가 없는 객체가 수없이 생성됩니다.
- 깃 내부에 이러한 객체가 많아지면 저장소 용량도 커지고, 객체도 빠르게 관리하기 어렵습니다.
- 깃은 이러한 객체를 줄이려고 생성된 객체를 압축합니다.
- 즉, 깃은 연결 고리가 없는 객체들을 pack 파일 형태로 압축하여 저장합니다.
실행
- 깃은 가비지를 정리하려고 별도의 gc 명령어를 제공합니다.
- gc 는 저수준 명령어로 garbage collect 의 약어입니다.
- 깃에서 내부적으로 가비지 정리가 필요하다고 생각할 때, gc 명령어를 자동으로 실행합니다.
- gc 명령어가 실행되면 오래된 객체들은 삭제하고 저장소 용량도 정리합니다.
- 자동 실행 외에 사용자가 직접 gc 명령어를 실행할 수도 있습니다.
- gc 명령어를 실행할 때는 prune, repack, pack, rerere 등 하위 명령어와 같이 사용합니다.
- gc 명령어가 실행되면 객체를 압축하고 pack 파일 형태로 저장하거나 제거합니다.
$ git gc -auto
압축
- gc 명령어는 객체의 압축과 refs 를 같이 처리합니다.
- refs 를 같이 압축하면 압축하기 전의 파일들은 삭제됩니다.
- 그리고 새로운 .git/packed-refs 파일을 생성합니다.
- 이후 refs 가 추가로 변경되면 압축한 packed-refs 값을 수정하지 않고, 새로운 refs 파일을 생성합니다.
- 즉, 압축한 이후에는 refs 파일이 2개가 되며, refs 파일이 여러 개 있으면 기본적으로 refs 안에 있는 파일을 먼저 찾습니다.
- 그리고 이후에 압축된 packed-refs 내용을 검색합니다.
환경 설정
- gc 명령어의 동작은 환경 설정으로 제어할 수 있습니다.
- gc 명령어의 동작은 gc.auto 항목으로 자동 설정을 허용하지 않을 수도 있고, gc.autopacklimit 를 사용하여 최대 압축 숫자를 제어할 수도 있습니다.
gc.reflogExpire: reflog가 보존되는 기간을 설정합니다. 기본값은 90일입니다.
gc.reflogExpireUnreachable: 기본값은 30일입니다.
gc.aggressiveWindow: 창의 크기를 정합니다. 기본값은 250입니다.
gc.aggressiveDepth: 압축에 사용되는 매개변수이며, 기본값은 50입니다.
gc.pruneExpire: 저장소에 쓰는 다른 프로세스와 동시에 실행될 때 손상을 방지합니다.
gc.worktreePruneExpire: 유예 기간을 설정할 수 있습니다.
prune
- 깃의 가비지를 정리하는 gc 명령어의 몇 가지 명령어와 함께 사용합니다.
- 그중 prune 명령어는 고립된 객체를 정리하는 내부 유틸리티입니다.
고립된 객체
- 깃은 객체를 이용하여 이력을 추적하고 변경된 내역을 기록합니다.
- 새로운 변경과 커밋이 있을 때 기존 객체를 다른 객체로 연결합니다.
- 즉, 앞에서도 이야기 했듯이 객체들은 SHA1 해시 값을 사용하여 서로 연결되어 있습니다.
- 어떤 객체를 새로운 커밋으로 재설정하면 참조 링크가 해제되는데, 이것은 해당 객체가 더 이상 필요하지 않다는 것입니다.
- 즉, 불필요한 객체가 생기는 것입니다.
- 고립된 객체는 객체 간 연결 고리가 끊겨 명령어를 사용해도 해당 객체에 접근할 수 없는 객체를 의미합니다.
- 고립된 객체는 불필요하므로 정리해야 합니다.
- 깃 자체적으로 완벽하게 정리하기 어려우므로 수동 으로 정리해야 합니다.
객체 정리
리셋으로 제거된 객체는 삭제되지 않고 고립된 객체가 됩니다.
리셋으로 객체까지 완벽하게 삭제하려면 prune 명령어를 사용합니다.
prune 명령어를 실행할 때는 다음 두 옵션을 같이 사용합니다.
- -dry-run : 실행하지 않고 작업할 내역만 출력합니다.
- -verbos : 작업한 결과를 출력합니다.
prune 명령어는 실행 후의 작업 결과를 출력합니다.
하지만 어떤 메시지도 출력하지 않았습니다.
이처럼 작업 메시지가 없는 것은 아직 깃 내부에 고립된 객체가 없어 prune 동작 자체가 실행되지 않은 것입니다.
리셋은 단지 커밋의 참고 연결 고리만 해제하는 것입니다.
사실 깃은 생성된 객체를 쉽게 삭제하는 것을 허용하지 않습니다.
정확하게 말하자면 참고 연결 고리만 해제한 객체와 실제 고립된 객체는 서로 다릅니다.
원격 작업
- 보통 prune 명령어는 로컬 환경에서 실행합니다.
- 하지만 고립된 객체는 원격 저장소에도 있을수 있습니다.
- remote/fetch 명령어를 같이 조합하면 원격 저장소에도 prune 명령어를 실행할 수 있습니다.
- 원격 저장소의 브랜치를 병합한 후 삭제합니다.
- fetch -prune 명령어는 오래된 브랜치를 정리합니다.
- 원격 저장소에 연결한 후 제거하기 전에 최신 상태를 먼저 가져옵니다.
$ git remote prune
# git fetch -prune
rerere
- 불특정 다수의 사람과 협업하다 보면 여러 가지 문제가 발생합니다.
- 깃은 협업 작업을 할 때 발생한 문제들을 충돌이라는 형태로 알려 줍니다.
동일한 충돌
- 협업 중 발생하는 여러 문제 중에서 일부는 같은 유형의 문제입니다.
- 비슷한 충돌 패턴을 반복적으로 수동으로 해결하곤 합니다.
- 깃은 이렇게 반복되는 같은 유형의 충돌 문제를 자동으로 해결할 수 없을까 하는 의문점에서 등장한 기능입니다.
- rerere는 reuse recorded resolution 의 약어로, 어떤 문제로 충돌이 발생할 때 이를 기록합니다.
- rerere 기능을 활성화하면, 깃은 충돌을 해결할 때마ㅏ 해결한 문제의 유형을 기록합니다.
- 기록한 유형의 문제와 비슷한 문제가 향후 다시 발생한다면, 미리 기록한 해결 정보를 바탕으로 자동으로 적용합니다.
활성화
- 기본적으로 rerere 기능은 활성화되어 있지 않습니다.
- 이 기능을 사용하려면 다음 명령어로 활성화해야 합니다.
- 로컬의 전체 저장소에 모두 적용하고자 한다면 -global 옵션을 같이 사용합니다.
- 단일 저장소에서만 rerere 기능을 확성화할 때는 글로벌 옵션을 제외합니다.
- 환경 설정으로 활성화하면 저장소에서 rerere 기능을 사용할 수 있습니다.
$ git config rerere.enable true
정리
- 일반적인 사용자는 깃의 고급 기능까지 알 필요가 없습니다.
- 하지만 자신이 프로젝트에서 중요한 자리를 맡았거나 저장소를 운영한다면 좀 더 많은 기능을 알고 있는 것이 좋습니다.
- 깃의 고급기능을 이용하면 협업할 때 발생하는 저장소 문제들을 복구하고 해결할 수 있습니다.
728x90
'버전관리' 카테고리의 다른 글
[맥북]맥OS M1 git 설치하기 (2) | 2023.01.11 |
---|---|
[Git] 11장 서브모듈 (0) | 2022.06.25 |
[Git] 10장 배포 관리와 태그 (0) | 2022.06.24 |
[Git] 9장 복귀 (0) | 2022.06.20 |
[Git] 8장 병합과 충돌 (0) | 2022.06.20 |
이 글을 공유하기