Git 2
지각/과제에 대한 공지¶
오늘 23:59 전까지 안올리면 과제 점수 -1¶
질문에 답변 제일 많이 한 사람 과제 x¶
-
merge 충돌에 대해서도 알아야 합니다. 여러부운 ~
-
github 기본 branch 설정방법이 있습니다 여러부운 ~
1. Github에서 Repository 삭제하는 방법¶
레포지토리 세팅 에서 삭제할 수 있다.
여러분의 정결한 github 유지와
오늘 스터디를 깔끔하게 진행하기 위해서 지난번에 만든 remote Repository와 바탕화면의 local Repository 모두 삭제해주세요 :)
2. 있어보이게 Git 사용하기¶
alias : 가명
- git 대신 g로 설정하기
⬇ EXECUTE! ⬇
$ vi ~/.bash_profile
//1. vi editor로 열린 파일 마지막 줄에 아래 코드 추가
alias g="git"
//2. :wq 입력하고 빠져나오기
//3. 터미널 껐다키기
$ g --version
- git 명령어 단축시키기
⬇ EXECUTE! ⬇
g config --global alias.cm "comit -m"
여러분을 위해 주는 코드 ;)
[alias]
i = init
s = status
sb = status -s -b
cm = commit -m
a = add --all
l = log --oneline
lg = log --oneline --graph --decorate
rao = remote add origin
cl = clone
ps = push
pl = pull
psom = push origin master
plom = pull origin master
b = branch
bd = branch -d
m = merge
co = checkout
cob = checkout -b
- alias 내용정리
alias | 원래 명령어 | 완성된 명령어 | 의미 |
---|---|---|---|
i |
init |
g i |
git 레포지토리 관리를 시작하도록 한다. |
s |
status |
g s |
레포지토리 상태를 본다. |
sb |
satuts -s -b |
g sb |
레포지토리 상태를 간략하게 본다. |
cm |
commit -m |
g cm "<MESSAGE>" |
커밋을 한다. |
a |
a --all |
g a |
추가되거나 변경된 파일을 스테이징 한다. |
l |
log --oneline |
g l |
git 의 커밋 기록을 한줄씩 출력한다. |
lg |
log --oneline --graph --decorate |
g lg |
git 의 커밋 기록을 그래프로 출력한다. |
rao |
remote add origin |
g rao <REMOTE> |
원격 레포지토리를 추가한다. |
cl |
clone |
g cl <URL> |
원격 레포지토리를 복제해 온다. |
ps |
push |
g ps <NAME> <BRANCH> |
원격 레포지토리로 푸쉬한다. |
pl |
pull |
g pl <NAME> <BRANCH> |
원격 레포지토리를 가져온다. |
psom |
push origin master |
g psom |
원격 레포지토리 origin에 master를 푸쉬한다. |
plom |
pull origin master |
g plom |
원격 레포지토리 origin에서 master로 가져온다. |
b |
branch |
g b <BRANCH> |
브랜치를 생성한다. |
bd |
branch -d |
g bd <BRANCH> |
브랜치를 삭제한다. |
m |
merge |
g m |
작업이 완료된 브랜치를 병합한다. |
co |
chechout |
g o <BRANCH> |
브랜치로 이동한다. |
cob |
chechout -b |
g cob <BRANCH> |
브랜치를 생성함과 동시에 이동한다. |
MAC에서만 해봐서 Win에서 안될수도...
3. BRANCH¶
프로젝트를 진행하면 새로운 기능을 추가할 때 그 기능이 전체 프로젝트와 호환되는지 알 수 없습니다. 개인 프로젝트라면 상관 없지만 함께 하는 프로젝트라면 걱정이 시작됩니다. Git 이 없을 때에는 이렇게 했습니다. 프로젝트를 통채로 복사하고 새로운 기능을 추가하고 호환되는지 충분히 검증한 다음에 원래의 레포지토리에 새로운 기능을 옮깁니다.
하지만 Git 은 이러한 과정을 자동화시켜주고 로그 기록으로 남기고 최악의 경우 복원하는 기능까지 제공합니다. 이것이 Git 의 Branching 기능입니다. 평행세계를 만드는 것입니다. 그리고 원래의 세계에서 평행세계로 넘어가서 그 세계에서 마음껏 실험적인 행동을 자행하는 것이죠. 그 평행세계가 바로 Branch 입니다.
Git 은 최대한 Branch 를 자주만들고 master 브랜치로 병합하라고 권장합니다. 저도 Branch 를 만들고 master 브랜치에 병합하는 습관 을 평소에 들이라고 권고하고 싶습니다. 왜냐하면 Git Branching 기능으로 여러분의 개발 과정이 매우 매우 안정적으로 바뀔 것이기 때문입니다.
브랜치란?¶
그렇다면 브랜치란 대체 무엇인가요? 브랜치란 포인터입니다. 그러면 그 포인터는 무엇을 포인팅하고 있나요? 바로 커밋들을 포인팅하고 있습니다. Git 은 기본 브랜치로 master 브랜치를 갖고 있는데 이 master 브랜치는 언제나 마지막 커밋을 포인팅하고 있습니다. 실제로 커밋을 할 때마다 master 브랜치가 자동으로 마지막 커밋으로 포인팅을 변경해주고 있던 겁니다.
엄밀히 말하면
HEAD
포인터가 포인팅하고 있는 브랜치는 커밋을 할 때마다 자동으로 마지막 커밋으로 이동하는 것입니다. 아래의 내용을 읽으면 자연히 이해할 수 있을 겁니다.
브랜치 생성¶
그러면 이제 말로만 하지말고 직접 몸으로 부딪혀보면서 브랜치를 느껴보겠습니다. 브랜치란 포인터라고 했으므로 브랜치를 생선하는 것은 포인터를 만드는 것입니다.
실습하고 싶은 분은 실습하고 싶은 다음 명령어로 Git 레포지토리를 하나 만들어주세요.
⬇ EXECUTE! ⬇
$ mkdir branch-test
$ cd branch-test
$ g i
$ touch main.c
$ v main.c
그리고 main.c 에 다음과 같은 코드를 입력하고 저장하고 vim 을 종료하세요.
void main(){
puts("what is branch?");
}
그리고 다음 명령어로 스테이징 후 커밋해주세요.
⬇ EXECUTE! ⬇
$ g a
$ g cm "main.c"
이제 실제로 브랜치를 생성해보겠습니다.
-
git branch
: 현재 상주하고 있는 브랜치를 출력한다. -
git branch
: 새로운 브랜치 을 만든다.
다음 명령어를 실행하여 testing
이라는 브랜치를 만드세요.
⬇ EXECUTE! ⬇
$ g b testing
그러면 다음과 같이 현재 커밋을 두 개의 포인터 master 와 testing 이 포인팅하고 있습니다.
위 그림은 이전의 커밋이 2개 있다는 것을 보여주지만 실제로 현재 우리의 레포지토리에는 커밋은 하나밖에 없습니다!
아니 그럼 현재 우리가 어떤 브랜치에 상주하고 있는지 대체 어떻게 알 수 있는 것인가요? 그것은 바로 HEAD
라는 특별한 포인터로 알 수 있습니다.
-
HEAD
: 현재 상주하고 있는 브랜치를 가르키는 포인터이다.- 아니 그럼 또
HEAD
는 어떻게 알 수 있는 것입니까?zsh
을 사용하고 있다면 다음과 같이 프롬프트 우측에HEAD
가 가르키고 있는 브랜치, 즉 현재 상주하고 있는 브랜치를 알 수 있습니다.
하지만 굳이 현재 상주하고 있는 브랜치를 직접 알아내야 한다면
g b
또는cat .git/HEAD
를 입력하면 됩니다.git branch
명령이 현재 상주하고 있는 브랜치를 출력하므로g b
가HEAD
의 내용을 출력해주는 것입니다. - 아니 그럼 또
우리는 다음과 같이 아직 master 브랜치에 상주하고 있습니다.
브랜치 이주¶
이제 testing
브랜치로 이주해서 온갖 실험적이고 진취적인 행동을 마음껏 해야겠습니다. 그러려면 testing 브랜치로 이주해야만 합니다.
-
git checkout
: 브랜치로 이주한다. -
git checkout -b
: 브랜치를 생성함과 동시에 이주한다. - 이 형태가 가장 자주 쓰입니다. 즉
g ob <NAME>
이 자주 쓰입니다. 다음 명령을 실행하여 브랜치를 이주하세요.
- 이 형태가 가장 자주 쓰입니다. 즉
⬇ EXECUTE! ⬇
그러면 다음과 같이 HEAD 포인터가 testing 을 가르키게 됩니다.
좋습니다! 이제 평행세계로 이동한 것입니다. 마음껏 실험적이고 파괴적인(?) 행동을 할 수 있습니다. main.c 함수의 코드에 매우 실험적이고 새로운 기능을 추가하고 싶다고 하겠습니다. 다음과 같이 코드를 고쳐주세요.
void message(){
puts("branch is good");
}
void main(){
message();
}
새로 추가한 함수가 너무 실험적이고 진취적이어서 본래의 레포지토리와 호환되는지 알 수 없을 것만 같습니다. 하지만 이곳은 testing 브랜치니까 아무런 걱정이 안됩니다. 이제 코드를 저장하고 다음 명령을 실행하여 커밋하세요.
⬇ EXECUTE! ⬇
$ g a
$ g cm "new function"
그러면 testing
브랜치는 다음과 같이 마지막 커밋을 포인팅하게 위하여 앞으로 나아갔지만 master 브랜치는 가만히 멈추어 있습니다.
이제 다음 명령어로 'master' 브랜치로 되돌아갑니다.
⬇ EXECUTE! ⬇
$ g o master
그러면 다음과 같이 HEAD 가 master 로 옮겨갔습니다.
$ cat main.c
브랜치 병합 시나리오 (1) - Fast-forward¶
브랜치 병합은 두 가지 시나리오로 설명하겠습니다. 우선 첫번째 시나리오입니다.
제 testing
브랜치에서 작업한 내용이 완전히 검증되었다고 하겠습니다. 그러면 남은 일은 master
브랜치에서 testing
브랜치를 병합하는 것입니다.
git merge <NAME>
:<NAME>
브랜치를 현재의 브랜치로 병합한다.
다음 명령어로 브랜치를 병합해주세요.
⬇ EXECUTE! ⬇
$ g m testing
커밋 구조를 보면 master 브랜치가 testing 브랜치 바로 뒤에 있기 때문에 이 경우 Git 은 단순히 master 브랜치가 testing 브랜치가 포인팅하고 있는 커밋을 포인팅하게 합니다. 이것을 Fast-forward 병합이라고 합니다.
브랜치 병합 시나리오 (2) - Merge Conflict¶
이제 다시 testing
브랜치에서 master
브랜치로 되돌아온 상황입니다. 이 경우 master
브랜치에서 main.c
를 다음과 같이 고쳤다고 하겠습니다.
void main(){
puts("branch is good");
}
그런 다음 다음 명령어로 스태이징을 하고 커밋을 합니다
⬇ EXECUTE! ⬇
$ g a
$ g cm "new main"
그러면 현재 상황은 다음과 같습니다.
master
브랜치도 한 단계 더 나아갔습니다. 이 상황에서 다음의 명령어로 testing
브랜치를 병합합니다.
⬇ EXECUTE! ⬇
$ g s
그러면 다음과 같이 both modified: 에 해당하는 파일 목록이 출력되는데 그 목록에는 main.c 가 포함되어 있음을 알 수 있습니다.
이 경우 main.c
를 열어서 병합 충돌이 발생한 코드를 확인해주어야 합니다. 실제로 main.c
를 열어보면 다음과 같이 되어있습니다.
병합충돌이 발생하면 Git 은 위와 같이 자동으로 충돌 영역을 =======
로 구분해줍니다. 그리고 HEAD 가 가르키는 브랜치(master
)의 변경사항과 testing 브랜치의 변경사항을 비교하여 보여줍니다. HEAD 에서 변경된 부분은 <<<<<<< HEAD
에서부터 =======
까지이고 testing
브랜치에서 변경된 부분은 =======
부터 >>>>>>> testing
까지입니다. 정말 편하죠?
여러분은 두 변경사항 중 하나를 택하거나 둘 다 택하여 <<<<<<<
와 =======
그리고 >>>>>>>
를 없애주어야 합니다. 여기에서는 main.c
를 다음과 같이 고쳐주겠습니다.
void message(){
puts("branch is good.");
}
void main(){
message();
}
그런 다음 다음 명령어로 다시 커밋해주면 병합이 최종적으로 완성됩니다.
⬇ EXECUTE! ⬇
$ g a
$ g cm "merge testing"
브랜치 삭제¶
이제 마지막으로 병합이 완료된 testing 브랜치를 삭제하는 일만 남았습니다.
-
git branch -d <NAME>
: 병합이 완료된브랜치를 삭제한다. -
git branch -D <NAME>
: 병합이 완료되지 않은브랜치를 삭제한다.
다음 명령어로 testing
브랜치를 삭제하세요.
⬇ EXECUTE! ⬇
$ g bd testing
지금까지 Git Branching 을 매우 간단하게 알아보았는데, 나중에 https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell 을 통하여 Git Branching 의 더욱 강력한 기능을 추가 학습하시길 강력하게 추천합니다.
VSCode 에서는 왼쪽 하단부의 Branch 를 클릭하거나 명령 팔레트에서 branch 를 검색하는 것으로 매우 쉽게 Branch 를 생성하거나 이주할 수 있습니다.
4. remote와 local에서 생기는 coflict 해결하기 (merge)¶
- [Local] 바탕화면에 git-conflict 폴더를 만드세요
- [Local] 해당 폴더를 git 레파지토리로 만드세요
- [Local] conflict.txt 텍스트 파일을 하나 만들고 "한재 형 고생 많아요" 라는 내용을 추가하고 "첫 커밋 한재형"로 커밋해주세요
- [Remote] github에도 git-conflict라는 이름으로 레파지토리를 하나 만들어 주세요. (기본 branch를 master로 설정해주세요)
- [Local] 해당 remote 레파지토리에 local 레파지토리 push 해주세요
- [Remote] github 주소에서 conflict.txt 내용을 "한재 형/오빠 고생많아요"로 바꾸고 "한재 형/오빠"로 커밋해주세요
- [Local] 이제 local git-conflict에서 conflict.txt 내용을 "한재 형/오빠/동생 고생많아요"로 고치고 "한재 형/오빠/동생"으로 커밋해주세요
- [Local] 이제 local 레파지토리의 내용을 remote로 push 해보세요
푸쉬에 실패할것입니다.이게 conflict 이란 것입니다. - [Local] remote의 내용을 local에서 pull 합니다. pull이 되기는 했지만 auto merging / CONFLICT 라는 메시지를 볼 것 입니다.
- [Local] local에서 conflict.txt 파일의 내용을 확인하고 "한재 형/오빠/동생 고생많아요" 내용으로 변경하고 "conflict 해결"로 코밋을 남겨주세요
- [Local]
git log --graph --oneline
명령어로 커밋기록을 보고 이해해봅니다.
위 과제는 원숭이git 사이트의 내용을 바탕으로 제작하였습니다.