'팀 개발을 위한 Git, GitHub 시작하기' 정리 (1) : log, branch, merge, HEAD, revert, reset
책 내용과 독학한 내용들을 섞어내서 적어보기로 했다. 책의 내용을 곧이 곧대로 따라가지 않는다.
우선, CLI 환경에 익숙해지는 것은 맞지만 GUI를 죄악시하지는 말아야 한다. 협업에서 깃의 흐름을 파악하는데 있어 GUI는 유용하므로 무엇이든 배워두는 것을 추천한다. 필자는 위 책에서 사용한 sourcetree를 앞으로도 사용할 예정이다.
- 기본 사항
git log
// git log --all --graph --online 과 같은 옵션 존재
git checkout [branch] // branch로 이동
// detached HEAD가 됨
git checkout [커밋 아이디] // 최신 commit로 돌아가기 git checkout -
GUI 환경에서 뿐만 아니라 CLI 환경에서도 graph로 branch를 볼 수 있습니다.
--all --graph --oneline 옵션은 log를 사용할 때 유용하기 때문에 단축키로 지정하는게 좋습니다.
1) git cmd 창에서 nano ~/.gitconfig 를 입력하셔서 설정 파일을 엽니다.
2) 아래 내용을 입력하면, git l 단축명령어를 사용할 수 있습니다.
[alias]
l = log --all --graph --oneline
// clone 시 끝에 .을 적으면 새로운 폴더를 만들지 않고 clone한다.
git clone https://github.com/MartinGwon/iTshirt .
// nano 에디터를 쓰고 싶다면 바꿀 수 있습니다.. 그러나 vim 사용에 익숙해집시다
git config --global core.editor "nano"
// branch 목록 출력
git branch
// branch 생성
git branch [brach 명]
// 이동 (HEAD가 가리킴)
git checkout [branch 명]
// A branch에서 B branch를 merge하고 싶다면
// HEAD를 A로 이동
git checkout A
// B를 merge
git merge B
-
untracked => tracked(수정 없음) => tracked(modified) => tracked(staged)
-
collaborator 참여 시키기
프로젝트의 setting - manage access - collaborator를 통해 협업자를 지정할 수 있다. 협업자가 수락하면 master branch에 병합할 수 있다.
-
git pull = git fetch + git merge
git fetch는 로컬에서 나타내는 원격 저장소의 상태를 실제 원격 저장소의 (지금)상태와 동기화합니다. sourcetree에서 사용해보아서 알겠지만, 내용을 다운로드 받는 것이 아니라 git의 현 상태를 가져오는 것입니다. 따라서 fetch 이후에는 merge를 통해 업데이트를 해야 하는데 이런 작업이 워낙 자주 있다보니 두 명령을 동시에 처리하는 git pull이 더 자주 사용됩니다.
팀원이 원격 저장소로 새로 푸시를 하면, 우리는 그 정보를 pull해서 받아와 최신의 상태에서 작업할 필요가 있습니다.
-
Fork vs Pull request
5명 내외의 적은 수의 개발자들은 모두 collaborator로 등록하는 것이 효율적이지만 100명 단위의 개발자들이 참여하는 거대 오픈 소스는 Fork가 효율적이다. 원본 저장소에 영향을 미치지 않으므로 원격 저장소에서 마음껏 코드를 수정할 수 있기 때문이다. 오픈 소스 기여를 위해 연구할 때는 Fork를 쓰되 프로젝트를 진행할 때는 Pull request를 사용하자.
(이 정도 규모를 운용한다면 git 공부로 머리를 싸맬 실력이 아닐 것이다...)
-
checkout을 통한 HEAD 분리 + 상대 참조와 절대 참조
HEAD는 현재 작업 중인 곳을 가리킵니다. 브랜치를 가리킬수도, 커밋 아이디값을 가리킬 수도 있습니다.
checkout을 통해 HEAD를 분리할 수 있습니다. 보통 checkout은 branch를 가리키지만 커밋 해시값(아이디)를 직접 지정해서 옮길 수 있습니다. 이 경우의 HEAD를 'detached head'라고 부릅니다.
이를 이용해 ^와 ~를 이용한 상대 참조도 가능하고, git log를 통해 확인한 해시값을 통해 절대 참조로 이동할 수도 있습니다.
-
branch 이동, reset(버전 삭제), revert(버전 되돌리기)
보통 상대 참조를 branch를 옮기거나 reset, reverse 등으로 사용합니다.
다음 코드는 마스터 branch를 현재 HEAD의 위치로부터 3번 전 커밋으로 강제(-f) 이동시키는 명령어입니다.
git branch -f master HEAD~3
reset은 애초에 커밋하지 않은 것처럼 되돌리는 버전 삭제입니다. 지정한 버전으로 reset 됩니다.
soft, mixed, hard 등의 모드가 있습니다.
git reset --hard 86a12f6d53b1f5bf7110e7ee630ceb1ab6c4491c
git reset HEAD^
git reset HEAD~2
reset은 로컬 저장소에서는 유용하게 사용할 수 있지만 이 때문에 다른 사람들과 공유하고 있는 원격(remote) 브랜치에는 쓰면 안됩니다.
다른 사람들과 공유하기 위해서는, git revert를 써야합니다. (버전 되돌리기) revert의 결과로, 대상이 된 git의 변화를 취소한 버전이 새롭게 커밋됩니다. 즉, 삭제가 아니라 되돌린 버전을 새로 커밋하는 것입니다.
주의할 점은 순차적으로 revert되기 때문에 가고자 하는 해시값을 넣었던 reset과 달리 현재경로를 적어야 한다는 것입니다. 중요한 건 현재 경로가 아닌 다른 값을 통해 한 번에 revert를 하려고 하면 충돌이 일어난다는 것입니다. 더 내려가기 위해서는 역순을 단계별로 타고 내려가야합니다.
예를 들어, 2 버전을 내려가려면 revert를 두 번 해야 한다는 것입니다.
git revert [현재 해시값]
log를 찍어보니 revert한 결과물이 다음과 같이 나왔습니다. 내용물을 비교해보면 알겠지만, revert된 값은 그 전의 커밋된 것과 같습니다. 8a9e7855b0a... 버전은 19fa85e816...의 내용이 같습니다.
-
3 way merge
conflict가 발생하는 곳에서 병합하는 방법이다. 3 way merge는 기본적으로, base와 비교하여 변화한 곳은 변화시키고, 둘 다 변화한 곳은 confilct 상태로 두어 사용자가 결정하게끔 한다.
반면 2 way merge는 같지 않다면 무조건 conflict 상태로 두게 된다.