본문 바로가기
프로그래밍 놀이터/Tips

[도서 정리] 7. Git 도구 #2 - ProGit

by 돼지왕 왕돼지 2020. 1. 12.
반응형

[도서 정리] 7. Git 도구 #2 - ProGit


7.7. Reset 명확히 알고 가기


* 세 개의 트리


-

git 은 일반적으로 세 가지 트리를 관리하는 시스템이다.


HEAD : 마지막 커밋 스냅샷, 다음 커밋의 부모 커밋

Index :다음에 커밋할 스냅샷

워킹 디렉터리 : 샌드박스



-

HEAD 는 현재 브랜치를 가리키는 포인터이며, 브랜치는 브랜치에 담긴 커밋 중 가장 마지막 커밋을 가리킨다.

지금의 HEAD 가 가리키는 커밋은 바로 다음 커밋의 부모가 된다.

단순히 생각하면 HEAD 는 마지막 커밋의 스냅샷이다.



-

HEAD 스냅샷의 디렉터리 리스팅과 각 파일의 SHA-1 체크섬을 보려면 아래와 같이 한다.

$ git cat-file -p HED

$ git ls-tree -r HEAD


cat-file 과 ls-tree 명령은 일상적으로는 잘 사용하지 않는 저수준 명령이다.

이런 저수준 명령을 plumbing 명령어라고 한다.

git 이 실제로 무슨 일을 하는지 볼 때 유용하다.



-

Index 는 바로 다음에 커밋할 것들이다.

staging area 라고 보면 된다.

먼저 Index 는 워킹 디렉터리에서 마지막으로 checkout 한 브랜치의 파일 목록과 파일 내용으로 채워진다.

이후 파일을 변경하고 변경한 내용으로 index 를 업데이트 할 수 있다.

이렇게 업데이트하고 git commit 명령을 실행하면 index 는 새 커밋으로 변환된다.


git ls-files -s 를 통해 현재 index 가 어떤 상태인지를 확인할 수 있다.

Index 는 엄릴히 말해 트리 구조는 아니다. 사실 index 는 평평한 구조(flattened manifest)로 구현되어 있지만, 이해를 위해 트리라고 설명한다.

$ git ls-files -s



-

HEAD 와 Index 는 파일과 그 내용을 효율적인 형태로 .git 디렉터리에 저장한다. 하지만 사람이 알아보기 어렵다.

워킹 디렉터리는 실제 파일로 존재한다.

바로 눈에 보이기 때문에 사용자가 편집하기 수월하다.

워킹 디렉터리는 샌드박스로 생각하자.




* 워크플로


-

Git 의 주목적은 프로젝트의 스냅샷을 지속적으로 저장하는 것이다.

Working Directory, Index, HEAD 를 이용해 더 나은 상태로 관리한다.



-

브랜치를 checkout 하면 HEAD 가 새로운 브랜치를 가리키도록 바뀌고,

새로운 커밋의 스냅샷을 index 에 놓는다. (돼왕 : add)

그리고 index 의 내용을 워킹 디렉터리로 복사한다. (돼왕 : commit)




* Reset 의 역할


-

reset 명령은 세 트리를 간단하고 예측 가능한 방법으로 조작한다.


1단계 : HEAD 이동

    reset 명령이 하는 첫 번째 일은 HEAD 브랜치를 이동시킨다.

    checkout 명령처럼 HEAD 가 가리키는 브랜치를 바꾸지는 않고, 현재 브랜치를 가리키는데, 그 브랜치의 가리키는 커밋을 바꾼다.

    reset 명령에 커밋을 넘기고 실행하면 언제나 이런 작업을 수행한다.

    reset —soft 옵션을 사용하면 딱 여기까지 진행하고 동작을 멈춘다.

    reset 명령 뒤에 HEAD~ 를 주면 Index 나 워킹 디렉터리는 그대로 놔두고 브랜치가 가리키는 커밋만 이전으로 되돌린다.

    index 를 업데이트한 다음에 git commit 명령을 실행하면 git commit —amend 명령의 결과와 같아진다.


2단계 : Index 업데이트 (—mixed)

    reset 명령은 index 를 현재 HEAD 가 가리키는 스냅샷으로 업데이트까지 할 수 있다.

    —mixed 옵션을 주고 실행하면 reset 명령은 여기까지 하고 멈춘다.

    reset 명령을 실행할 때 아무 옵션도 주지 않으면 기본적으로 --mixed 옵션으로 동작한다.

    

3단계 : 워킹 디렉터리 업데이트 (—hard)

    reset 명령은 워킹 디렉터리까지 업데이트한다.

    —hard 옵션을 사용하면, HEAD, Index, Working Directory 모두 되돌린다.

    


-

reset 명령은 정해진 순서대로 세 개의 트리를 덮어써 나가다가 옵션에 따라 지정한 곳에서 멈춘다.

1. HEAD 가 가리키는 브랜치를 옮긴다. (—soft)

2. Index 를 HEAD 가 가리키는 상태로 만든다. (--mixed)

3. 워킹 디렉터리를 Index 의 상태로 만든다. (—hard)




* 경로를 주고 Reset 하기


-

git reset file_name 은 git reset —mixed HEAD file_name 과 같다.

HEAD 를 옮기지 않고, Index 를 HEAD 가 가리키는 상태로 만든다.

이 명령은 해당 파일을 unstaged 로 만든다.

$ git reset <file_name>



-

특정 커밋을 명시하면 git 은 HEAD 에서 파일을 가져오는게 아니라, 그 커밋에서 파일을 가져온다.

git reset sha_1 file_name 과 같이 실행한다.

$ git reset <sha_1> <file_name>



-

git add 명령처럼 reset 명령도 hunk 단위로 사용할 수 있다.

—patch 옵션을 사용하면 된다.




* 합치기 (Squash)


-

git reset —soft HEAD~2 를 수행한 후 git commit 을 수행하면 HEAD, HEAD~1 의 내용이 합쳐지며 새로운 commit 이 만들어진다.

$ git reset --soft HEAD~2

$ git commit




* Checkout


-

checkout 명령도 세 트리를 조작한다.

git checkout branch_name 명령은 git reset —hard branch_name 명령과 비슷하게 branch_name 스냅샷을 기준으로 세 트리를 조작한다.

하지만 두 가지 사항이 다르다.

$ git checkout <branch_name>

$ git reset --hard <branch_name>


1. reset —hard 명령과는 달리 checkout 명령은 워킹 디렉터리를 안전하게 다룬다. 저장하지 않은 것이 있는지 확인해서 날려버리지 않는다는 것을 보장한다. 워킹 디렉터리에서 머지 작업을 한 번 시도해보고 변경하지 않은 파일만 업데이트한다. 반면 reset --hard 명령은  모든 것을 바꿔버린다.

2. HEAD 를 업데이트하는가가 다르다. reset 명령은 HEAD 가 가리키는 브랜치를 움직이지만(브랜치 Refs를 업데이트하지만), checkout 명령은 HEAD 자체를 다른 브랜치로 옮긴다.



-

checkout 명령을 실행할 때에 파일 경로를 줄 수도 있다.

reset 명령과 비슷하게 HEAD 는 움직이지 않는다.

Index 의 내용이 해당 커밋 버전으로 변경될 뿐만 아니라 워킹 디렉터리의 파일도 해당 커밋 버전으로 변경된다.

git reset —hard branch_name file_name 명령의 동작이랑 같다.




* 요약








7.8. 고급 머지


-

git 의 머지는 진짜 가볍다.

git 의 철학은 머지가 잘될지 아닐지 판단하는 것을 잘 하자이다.

충돌이 나도 자동으로 해결하려고 노력하지 않는다.

오랫동안 따로 유지한 두 브랜치를 머지하려면 몇 가지 해야 할 일이 있다.




* 머지 충돌


-

머지할 때 충돌이 날 수 있어 머지하기 전 워킹 디렉터리를 깔끔히 정리하는 것이 좋다.

임시 브랜치에 커밋하거나 stash 해두면 된다.



-

머지중 발생한 충돌을 해결하는 방법은 몇 가지가 있다.

첫번째는 그저 이 상황을 벗어나는 것인데, git merge --abort 명령을 때리면 된다.

이는 머지를 시작하기 전으로 되돌린다.

$ git merge --abort



-

공백 때문에 충돌이 날 때도 있다.

기본 머지 전략은 공백의 변화는 무시하도록 하는 옵션을 주는 것이다.

—Xignore-all-space 나 -Xignore-space-change 옵션을 주어 머지하면 된다.

첫번째 옵션은 모든 공백을 무시하고, 두번째 옵션은 뭉쳐 있는 공백을 하나로 취급한다.



-

수동 머지할 때는 git merge-file 명령을 이용한다.

머지 전과 후의 결과를 비교하려면 git diff —ours 명령을 실행한다.

머지할 파일을 가져온 쪽과 비교해서 무엇이 바뀌었는지 보려면 git diff —theirs 를 실행한다.


ex) 

$ git diff —theirs -b # -b 는 공백을 빼고 비교한다.



-

git diff —base 는 양쪽 모두와 비교하여 바뀐 점을 본다.

$ git diff --base



-

충돌을 해결하는 맥락을 더 살펴봐야 한다면 git checkout —conflict 를 사용하는 게 좋은 방법이 될 수 있다.

이 명령은 파일을 다시 checkout 받아서 충돌 표시된 부분을 교체한다.

충돌 난 부분은 원래의 코드로 되돌리고 다시 고쳐보려고 할 때 알맞은 도구다.

$ git checkout --conflict


—conflict 옵션에는 diff3 나 merge 를 넘길 수 있고, merge 가 기본값이다.

diff3 옵션을 사용하면 git 은 약간 다른 모양의 충돌 표시를 남긴다.

ours 나 theirs 말고도 base 버전의 내용까지 제공한다.


항상 diff3 옵션을 적용하려면 git config —global merge.conflictstyle diff3 을 수행해주면 된다.



-

git checkout 명령도 —ours 와 —theirs 옵션을 지원한다.

이 옵션은 merge 하지 않고 둘 중 한쪽만을 선택할 때에 사용한다.

$ git checkout --ours

$ git checkout --theirs



-

git log 명령은 충돌을 해결할 때도 도움이 된다.

triple dot 문법을 이용하면 머지에 사용한 양 브랜치의 모든 커밋의목록을 얻을 수 있다.


$ git log —oneline —left-right HEAD…MERGE_HEAD


git log 명령에 —merge 옵션을 추가하면 충돌이 발생한 파일이 속한 커밋만 보여준다.

—merge 대신 -p 를 사용하면 충돌 난 파일의 변경사항만 볼 수 있다.



-

머지하다가 충돌이 났을 때 git diff 명령을 실행하면 꽤 생소한 diff 결과를 보여준다.

이런 형식을 combined diff 라고 한다.

각 라인은 두 개의 칼럼으로 구분할 수 있다.

첫번째 칼럼은 ours 브랜치와 워킹 디렉터리의 차이.

두번째 칼럼은 theirs 와 워킬 디렉터리 사이의 차이를 나타낸다.


머지 커밋에 대한 정보를 git log 를 통해서 얻을 수 있다.

머지 후에 무엇이 어떻게 바뀌었는지 알아야 할 때 유용하다.

머지 커밋에 대해서 git show 명령을 실행하거나 git log -p 에 —cc 옵션을 추가해도 같은 결과를 얻을 수 있다.




* Merge 되돌리기


-

머지할 때 실수를 해도 간단히 되돌릴 수 있다.

실수로 생긴 머지 커밋이 로컬 저장소에만 있을 때는 브랜치를 원하는 커밋을 가리키면 된다.

$ git reset —hard HEAD~


브랜치를 옮기지 못하는 경우는 모든 변경사항을 취소하는 새로운 커밋을 만들 수 있다.

git 에서는 이 기능을 revert 라고 부른다.

ex)

$ git revert -m 1 HEAD




* 다른 방식의 Merge


-

머지는 보통 recursive 전략을 사용한다.



-

충돌을 직접 해결하는게 아니라 미리 git 에 충돌이 났을 때 두 브랜치 중 한쪽을 선택하라고 알려줄 수 있다.

merge 명령을 사용할때 -Xours 나  -Xtheirs 옵션을 추가하면 된다.

git 에 이 옵션을 주면 충돌 표시가 남지 않는다.

머지가 가능하면 머지될 것이고, 충돌이 나면 사용자가 명시한 내용으로 대체한다.



-

애초에 git 이 머지 시도조차 하지 않는 자비 없는 옵션도 있는데, 이는 ours 머지 전략이다.

이 전략은 Recursive Merge 전략의 ours 옵션과는 다르다.

이 작업은 기본적으로 거짓으로 머지한다.

그리고 양 브랜치를 부모로 삼는 새 머지 커밋을 만든다.

하지만 Their 브랜치는 참고하지 않는다.

Our 브랜치의 코드를 그대로 사용하고 머지한 것처럼 기록한다.


ex) 

$ git merge -s ours <branch_name>


이 ours 전략은 이미 머지가 되었다고 git 을 속이고 실제로는 머지를 나중에 수행한다.



-

서브트리 머지의 개념은 프로젝트 두 개가 있을 때 한 프로젝트를 다른 프로젝트의 하위 디렉터리로 매핑하여 사용하는 것이다.

머지 전략으로 서브트리를 사용하는 경우 git 은 매우 똑똑하게 서브트리를 찾아서 메인 프로젝트로 서브 프로젝트의 내용을 머지한다.

이는 read-tree 명령을 사용한다. read-tree 명령은 어떤 브랜치로부 루트 트리를 읽어서 현재 staging area 나 워킹 디렉터리로 가져온다.

......





7.9. Rerere


-

git rerere 기능은 약간 숨겨진 기능이다.

reuse recorded resolution 은 기록한 해결책 재사용하기란 뜻의 이름이고 이름 그대로 동작한다.

충돌이 났을 때 각 코드 덩어리를 어떻게 해결했는지 기록을 해 두었다가 나중에 같은 충돌이 나면 기록을 참고하여 자동으로 해결한다.


아래 명령으로 enable 시킬 수 있다.

$ git config —global rerere.enabled true


그럼 저장소에 .git/rr-cache 디렉터리를 만들어 관련 내용을 저장한다.





7.10. Git 으로 버그 찾기


* 파일 어노테이션(Blame)


-

$ git blame -L 12,22 simplegit.rb # rb 파일의 12~22 사이의 commit 이력이 나온다.


^sha_1 의 형태는 이 sha_1 커밋에서 처음 커밋됐다는 것을 의미한다.



-

git 은 파일 이름을 변경한 이력을 별도로 기록해두지 않는다.

하지만 원래 이 정보들은 각 스냅샷에 저장되고 이 정보를 이용하여 변경 이력을 만들어 낼 수 있다.

결론적으로 파일에 생긴 변화는 무엇이든지 알아낼 수 있다.



-

git 은 파일 어노테이션을 분석하여 코드들이 원래 어떤 파일에서 커밋된 것인지 찾아준다.

예를 들어 ServerHandler.m 을 여러 개의 파일로 리펙토링했는데, 그 중 한 파일이 PackUpload.m 이었다면, -C 옵션으로 PackUpload.m 파일을 추적해서 각 코드가 원래 어떤 파일로 커밋된 것인지 알 수 있다.


ex) 

$ git blame -C -L 141,153 PackUpload.m




* 이진 탐색


-

git bisect 명령은 커밋 히스토리를 이진 탐색 방법으로 좁혀 주기 때문에 이슈와 관련된 커밋을 최대한 빨리 찾을 수 있게 도와준다.

git bisect start 명령으로 이진 탐색을 시작하고, git bisect bad 를 실행하여 커밋에 문제가 있다고 표시를 남기고 나서 문제가 없는 마지막 커밋을 git bisect good [good_commit] 명령으로 표시한다.


ex) 

$ git bisect start

$ git bisect bad

$ git bisect good v1.0


bisect good 과 bad 사이의 커밋이 12개였다면, git 은 그 중간에 있는 커밋을 checkout  해준다.

여기서 해당 이슈가 구현됐는지 테스트해보고 만약 이슈가 있으면 그 중간 커밋 이전으로 범위를 좁히고 이슈가 없으면 그 중간 커밋 이후로 범위를 좁힌다.

이슈를 발견하지 못하면 git bisect good 으로 이슈가 아직 없음을 알리고 계속 진행한다.


ex) 

$ git bisect good


그러면 문제가 있는 커밋과 지금 테스트한 커밋 사이에서 중간에 있는 커밋이 다시 checkout 된다.

다시 테스트해보고 이슈가 있으면 git bisect bad 로 이슈가 있다고 알린다.


ex) 

$ git bisect bad


이렇게 범위를 좁혀나가면 결국 문제가 된 커밋을 찾을 수 있다.

git bisect reset 명령을 실행시켜 이진 탐색을 시작하기 전 HEAD 로 돌려놓는다.


ex)

$ git bisect reset



-

프로젝트가 정상적으로 수행되면 0 을 반환하고 문제가 있으면 1을 반환하는 스크립트를 만든다면 이 git bisect 과정을 완전히 자동으로 수행할 수 있다.





7.11. 서브 모듈


-

프로젝트를 수행하다 보면 다른 프로젝트를 함께 사용해야 하는 경우가 있다.

함께 사용할 다른 프로젝트는 외부에서 개발한 lib 등이 있겠다.

이런 상황에서 자주 생기는 이슈는 두 프로젝트를 서로 별개로 다루면서도 그 중 하나를 다른 하나 안에서 사용할 수 있어야 한다는 것이다.


git 서브모듈은 이런 문제를 다루는 도구다.

git 저장소 안에 다른 git 저장소를 디렉터리로 분리해 넣는 것이 서브모듈이다.

다른 독립된 git 저장소를 clone 해서 내 git 저장소 안에 포함할 수 있으며 각 저장소의 커밋은 독립적으로 관리한다.




* 서브 모듈 시작하기


-

작업한 git 저장소에 미리 준비된 리모트 git 저장소를 서브모듈로 추가해보자.

서브모듈을 추가하는 명령으로 git submodule add repo_url 을 수행해주면 된다.

$ git submodule add <repo_url>


기본적으로 서브모듈은 프로젝트 저장소의 이름으로 디렉터리를 만든다.

명령의 마지막에 원하는 이름을 넣어 다른 디렉터리 이름으로 서브모듈을 추가할 수도 있다.



-

서브 모듈을 추가하고 git status 를 보면..

.gitmodules 와 새로운 repo 를 clone 한 dir 가 new file 로 잡힌다.


.gitmodules 는 서브디렉터리와 하위 프로젝트 url 의 매핑 정보를 담은 설정파일이다.

이 파일도 .gitignore 파일처럼 버전을 관리한다.



-

git 은 서브모듈로 취급하는 디렉터리 아래의 파일 수정사항을 직접 추적하지 않는다.

대신 서브모듈 디렉터리를 통째로 특별한 커밋으로 취급한다.

git diff —submodule 을 하면 서브모듈에 대해 자세히 나온다.

$ git diff --submodule



-

서브모듈 폴더는 git 에 있어 160000 모드로 취급하는데, 이는 파일이나 디렉터리가 아니라 특별하다는 의미이다.




* 서브모듈 포함한 프로젝트 Clone


-

서브모듈을 가진 프로젝트를 clone 하면 기본적으로 서브모듈 디렉터리는 빈 디렉터리이다.

서브모듈에 관련된 두 명령을 실행해야 완전히 clone 이 끝난다.

먼저 git submodule init 명령을 실행해서 서브모듈 정보를 시반으로 로컬 환경설정 파일을 준비한다.

이후 git submodule update 명령으로 서브모듈의 리모트 저장소에서 데이터를 가져오고 서브모듈을 포함한 프로젝트의 현재 스냅샷에서 checkout 해야 할 커밋 정보를 가져와서 서브모듈 프로젝트에 대한 checkout 을 한다.


$ git submodule init

$ git submodule update


이 과정을 더 간단히 할 수 있는데 git clone 에 —recursive 옵션을 붙이면 알아서 서브모듈을 자동으로 초기화하고 업데이트한다.


$ git clone --recursive




* 서브모듈 포함한 프로젝트 작업


-

가장 단순한 서브모듈 사용 방법은 하위 프로젝트를 수정하지 않고 참조만 하면서 최신 버전으로 업데이트하는 것이다.

최신으로 업데이트하려면 서브모듈 디렉터리에서 git fetch 명령을 실행하고 git merge 명령으로 머지한다.



-

git diff —submodule 명령으로 서브모듈과 각 서브모듈에 추가된 커밋을 볼 수 있다.

$ git diff --submodule



-

서브모듈을 최신으로 업데이트하는 더 쉬운 방법도 있다.

서브모듈 디렉터리에서 fetch & merge 하지 않아도

git submodule update —remote 명령을 실행하면 git 이 알아서 서브모듈 프로젝트를 fetch & merge 한다.

$ git submodule update --remote


그리고 이 명령은 모든 서브모듈을 업데이트한다.


이 명령은 기본적으로 서브모듈 저장소의 master 브랜치를 checkout 하고 업데이트를 수행한다.

업데이트할 대상 브랜치를 원하는 브랜치로 바꿀 수도 있다.

.gitmodules 파일에 설정하거나, .git/config 파일에 설정한다.



-

git 의 서브모듈 기능을 사용하지 않는다면 maven 이나 gradle 같은 dependency 관리 시스템을 사용할 수도 있다.



-

서브모듈 저장소에서 git submodule update 명령을 실행하면 git 은 서브모듈의 변경사항을 업데이트한다.

하지만 서브모듈 로컬 저장소는 Detached HEAD 상태로 남는다.

이 말은 변경 내용을 추적하는 로컬 브랜치가 없다는 것이다.


서브모듈이 브랜치를 추적하게 하려면 할 일이 두가지다.

우선 각 서브모듈 디렉터리로 가서 추적할 브랜치를 checkout 하고 일을 시작해야 한다.

이후 서브모듈을 수정한 다음 git submodule update —remote 명령을 실행해 새로운 커밋을 가져온다.



-

git submodule update 에 —merge 옵션을 추가하여 머지하도록 지정할 수 있다.

$ git submodule update --merge



-

서브모듈의 변경사항을 push 하지 않은 채로 메인 프로젝트에서 커밋을 push 하면 안 된다.

변경사항을 checkout 한 다른 사람은 서브모듈이 의존하는 코드를 어디서도 가져올 수 없는 상황이 돼 곤란해진다.


이런 불상사가 발생하지 않도록 하려면 메인 프로젝트를 push 하기 전에 서브모듈을 모두 push 했는지 검사하도록 git 에 물어보면 된다.

git push —recurse-submodules 를 행하며 옵션 값으로 check 나 on-demand 를 설정한다.

$ git push --recurse-submodules


check 는 서브모듈이 push 되지 않으면 현재의 push 명령도 실패하도록 한다.

on-demand 는 git 이 push 를 대신 시도한다.





* 서브모듈 팁


-

foreach 라는 서브모듈 명령이 있어 한번에 각 서브모듈에 git 명령을 내릴 수 있다.

ex) 

$ git submodule foreach ‘git stash’



-

서브모듈을 이용하는 명령은 대부분 길이가 길기 때문에 alias 를 만들어 사용하는 것이 편하다.

ex)

$ git config alais.sdiff ‘!’”git diff && git submodule foreach ‘git diff’”




* 서브모듈 사용할 때 주의할 점들


-

서브모듈의 코드를 수정하는 경우에는 주의해야 한다.

예를 들어 checkout 으로 브랜치를 변경하는 경우 서브모듈이 포함된 작업이라면 좀 애매하게 동작할 수 있다.

메인 프로젝트에서 새 브랜치를 생성하고 checkout 한 후 새로 서브모듈을 추가한다.

이후 다시 이전 브랜치로 checkout 하면 서브모듈 디렉터리는 추적하지 않는 디렉터리로 남게 된다.


수동으로 지워야 하며, 이 현상 자체가 요상하다.

수동으로 디렉터리를 지우고 다시 서브모듈을 추가했던 브랜치로 checkout 하면 submodule update —init 을 실행해줘야 서브모듈의 코드가 나타난다.



-

서브디렉터리를 서브모듈로 교체하면서 브랜치 간 이동하는 경우도 문제다.







7.12. Bundle


-

bundle 이란 데이터를 한 파일에 몰아넣는 것이다.

bundle 명령은 보통 git push 명령으로 올려 보낼 모든 것을 감싸서 하나의 바이너리 파일로 만든다.

이 파일을 이메일로 보내거나 USB 로 다른 사람에게 보내서 다른 저장소에 unbundle 해서 사용한다.


ex) 

$ git bundle create <bundle_name> HEAD master 

# master 브랜치를 다시 만드는데 필요한 모든 정보가 들어간다.

# HEAD 가 없으면 이 bundle 을 다른 곳에서 clone 할 수 없다.



-

bundle 파일을 이용해서 clone 처럼 사용할 수도 있다.


ex) 

$ git clone <bundle_file> <folder_name>



-

…. 이하 생략





7.13. Replace


-

히스토리(혹은 db)에 일단 저장한 git 의 개체는 기본적으로 변경할 수 없다.

그러나 변경된 것처럼 보이게 하는 재밌는 기능이 있다.


git 의 replace 명령은 어떤 개체를 읽을 때 항상 다른 개체로 보이게 한다.

히스토리에서 어떤 커밋이 다른 커밋처럼 보이게 할 때 유용하다.


예를 들어 아주 방대한 히스토리를 가진 프로젝트가 있다.

히스토리를 둘로 나누어 새로 시작하는 개발자에게는 히스토리를 아주 간단한 몇 개의 커밋으로 만들어 제공하고, 프로젝트 히스토리를 분석할 사람에게는 전체 히스토리를 제공하는 상황을 만들 수 있다.



-

…. 이하 생략





7.14. Credential 저장소


-

SSH 프로토콜을 사용하여 리모트 저장소에 접근할 때 Passphase 없이 생성한 SSH Key 를 사용하면 사용자 이름과 비밀번호를 입력하지 않고도 안전하게 데이터를 주고받을 수 있다.

반면 HTTP 프로토콜을 사용하는 경우는 매번 사용자 이름과 비밀번호를 입력해야 한다.


다행히 git 은 이렇게 매번 인증정보(Crednetial)를 입력하는 경우 저장해두고 자동으로 입력해주는 시스템을 제공한다.


일단 기본적으로 아무 설정도 하지 않으면 비밀번호를 저장하지 않는다.

cache 모드로 설정하면 일정 시간 동안 메모리에 사용자 이름과 비밀번호 같은 인증정보를 기억한다. 15분까지 유지한다.

store 모드로 설정하면 인증정보를 disk 텍스트 파일로 저장하며 계속 유지한다. 

맥에서 git 을 사용하는 경우 osxkeychain 모드를 사용하면 맥에서 제공하는 keychain 시스템에 사용자 이름과 비밀번호를 현재 로그인 계정에 속하게 저장한다. store 모드와 달리 암호화해서 저장한다는 점이 다르다.

윈도루 환경에서는 winstore 라는 helper 가 있다. osxkeychain 과 비슷하게 동작한다.


ex) 

$ git config —global credential.helper cache




* 뚜껑을 열어보면


-

git credential-helper 시스템의 기본 명령은 git credential 이다.

git credential fill 명령으로 인증정보를 추가할 수 있다.



-

....이하 생략




* 맞춤 Crednetial 캐시


-

git-credential-store 나  다른 명령도 독립된 프로그램이다.

아무 스크립트나 프로그램도 git credential helper 가 될 수 있다.

이미 git 이 제공하는 helper 로도 충분하지만 모든 경우를 커버하지 않는다.



-

…. 이하 생략





7.15. 요약




반응형

댓글