오늘 드디어 OT가 아닌 첫 수업이다.
Git 수업을 들었는데 생활코딩님이 강의를 해주셔서 내적 친밀감이 어느정도 있는지라 좀 반가웠다.
하지만 아쉬웠던건 CLI가 아닌 GUI로 git 실습을 해서 좀 아쉬웠다...
우테코를 하며 git에 대해 어느정도 사용법을 안다고 생각했다. 근데 로컬에서만 commit하고 협업은 해본적이 없는지라 협업 상황에서 대처법을 배울 수 있었다.
각설하고 배운점 정리하겠습니다. 참고로 모든 내용을 담기보단 제가 모르는 부분과 알려주고 싶은 부분 위주로 적었다고 생각하시면 좋겠습니다 헤헤
Git은 리누스 토르발스가 만들었다. 리누스는 이름에서 보이듯 Linux도 만들었다.
무수히 많은 푸쉬요청이...
Information manager from hell
컴퓨터 파일의 변경사항을 추적하고 여러 명의 사용자들 간에 해당 파일들의 작업을 조율하기 위한 스냅샷 스트림 기반의 분산 버전 관리 시스템이다
버전 관리 시스템 ? (version control system)
협업 프로젝트를 할 때, 너무 많은 복사본과 어떤 버전이 수정된 최신 버전인지 알기 어려웠던 적이 있을 것이다. 이외에도 많은 문제점을 보안하고 파일의 변화를 시간에 따라 버전별로 기록하고 특정 시점의 버전을 다시 불러올 수 있는 시스템이다.
왜 쓰는지에 대해서는 조금만 생각해봐도 좋은 점이 차고 넘친다.
각 스냅샷의 차이를 알 수 있고 백업으로 쓸 수도 있고 협업하기도 좋고...
들었던 강의에선 GUI를 이용하지만 나는 CLI로 해보겠다.
깃이 어떻게 파일들을 저장하고 관리하는지 알아보자.
일단 repository 만드는 방법은 두개가 있다.
❯ pwd #현재 디렉토리 경로 확인
/Users/gote/workspace/aivle_school/GO-TE
❯
❯ git init
/Users/gote/workspace/aivle_school/GO-TE/.git 안의 빈 깃 저장소를 다시 초기화했습니다
❯ ls -al
total 8
drwxr-xr-x 5 gote staff 160 2 21 13:45 .
drwxr-xr-x 3 gote staff 96 2 21 13:41 ..
drwxr-xr-x 13 gote staff 416 2 22 01:00 .git
drwxr-xr-x 8 gote staff 256 2 21 13:47 .idea
-rw-r--r-- 1 gote staff 50 2 21 13:45 README.md
짜잔 .git
이 생겼다. git init
을 작업중인 폴더에 생성해 깃허브 레포에 올릴 준비가 되었다. (깃허브에 repository 만드는 건 생략)
test.txt
파일을 작업파일이라 가정하고 파일을 생성했다.git status
로 변경 사항을 git이 캐치 했는지 보자.
❯ git status
현재 브랜치 main
브랜치가 'origin/main'에 맞게 업데이트된 상태입니다.
추적하지 않는 파일:
(커밋할 사항에 포함하려면 "git add <파일>..."을 사용하십시오)
test.txt
커밋할 사항을 추가하지 않았지만 추적하지 않는 파일이 있습니다 (추적하려면 "git
add"를 사용하십시오)
❯ git status
현재 브랜치 main
브랜치가 'origin/main'에 맞게 업데이트된 상태입니다.
추적하지 않는 파일:
(커밋할 사항에 포함하려면 "git add <파일>..."을 사용하십시오)
test.txt
커밋할 사항을 추가하지 않았지만 추적하지 않는 파일이 있습니다 (추적하려면 "git
add"를 사용하십시오)
바로 칼같이 잡아내는 모습이구연 이를 이제 git add test.txt
로 Staging area
에 추가하자.
사실 working directory의 파일은 먼저 Untracked, Tracked의 상태를 지닌다.
파일을 새로 만들 때 Untracked 상태가 되며 이는 git이 만들어진 파일에 대해 git이 신경 쓰지 않아도 되는 상태다.
이를 git이 관리하고 추적하기 위해서 Tracked로 만드려면git add [파일 명]
으로 Staging area에 추가해 git이 추적하도록 만드는 것이다.
또한, Staging Area에 추가 된 파일들은 Unmodified, Modified, Staged 상태로 분류된다.
❯ git add test.txt
❯ git status
현재 브랜치 main
브랜치가 'origin/main'에 맞게 업데이트된 상태입니다.
커밋할 변경 사항:
(use "git restore --staged <file>..." to unstage)
새 파일: test.txt
commit으로 이 작업이 무엇을 의미하는지 커밋 메세지로 나타낸 뒤 원격 저장소에 push하면 끝
push 전
❯ git status
현재 브랜치 main
브랜치가 'origin/main'보다 1개 커밋만큼 앞에 있습니다.
(로컬에 있는 커밋을 제출하려면 "git push"를 사용하십시오)
커밋할 사항 없음, 작업 폴더 깨끗함
push 후
❯ git status
현재 브랜치 main
브랜치가 'origin/main'보다 1개 커밋만큼 앞에 있습니다.
(로컬에 있는 커밋을 제출하려면 "git push"를 사용하십시오)
커밋할 사항 없음, 작업 폴더 깨끗함
❯ git push origin
오브젝트 나열하는 중: 4, 완료.
오브젝트 개수 세는 중: 100% (4/4), 완료.
Delta compression using up to 10 threads
오브젝트 압축하는 중: 100% (2/2), 완료.
오브젝트 쓰는 중: 100% (3/3), 317 bytes | 317.00 KiB/s, 완료.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/GO-TE/GO-TE.git
478bfa6..a7fae46 main -> main
❯ ls
p1
❯ git clone https://github.com/GO-TE/GO-TE.git
'GO-TE'에 복제합니다...
remote: Enumerating objects: 13, done.
remote: Counting objects: 100% (13/13), done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 13 (delta 2), reused 9 (delta 1), pack-reused 0
오브젝트를 받는 중: 100% (13/13), 4.99 KiB | 4.99 MiB/s, 완료.
델타를 알아내는 중: 100% (2/2), 완료.
❯ ls
GO-TE p1
깃허브 repository 만들고 git clone [깃허브 레포 주소.git]
을 입력하여 작업 폴더에 받아오면 된다.
그 후 상황은 첫번째 상황과 매우 유사하다.
새로 만든 파일은 git에 추척을 받지 않을 터이니 add - 파일이 수정이 되었다면 commit - push를 해주면 짜잔 새로운 버전이 탄생된다.
push한 뒤 로컬과 레포가 같은 버전인 모습을 볼 수 있다. 그림으로 볼까요?
대략적인 git이 원격 저장소에 푸쉬하는 흐름은 이렇다.
프로젝트에서 작업한 파일을 git이 추적하도록 add - commit으로 버전의 스냅샷을 만든다 - push하여 원격 저장소에 업로드한다.
이로서 나는 git의 신이며 무적인 줄만 알았지만 실무에선 여러 사람들과 협업하여 원격 저장소에 올립니다.
프로젝트를 할 때, 누군가는 이미 최신 버전에서 push하고 누구는 이전 버전에서 수정하여 push를 시도하려고 할 수 있다.
엄준식 군과 제갈선우 군은 프로젝트를 같이 하기로 되었습니다 !
제갈선우 군은 많은 경험으로 밤새 미친 작업속도로 많은 커밋을 push했습니다.
엄준식 군은 그런 사실 조차 모른 채 탱자탱자 놀다가 갑자기 프로젝트 생각이 들어 대충 작업 후 push
를 쏘아 올렸습니다.
되지않는 push
에 "어!" 소리가 저절로 나오는 준식씨였습니다.
❯ git push origin
! [rejected] main -> main (non-fast-forward)
error: 레퍼런스를 'https://github.com/GO-TE/GO-TE.git'에 푸시하는데 실패했습니다
힌트: 현재 브랜치의 끝이 리모트 브랜치보다 뒤에 있으므로 업데이트가
힌트: 거부되었습니다. 푸시하기 전에 ('git pull ...' 등 명령으로) 리모트
힌트: 변경 사항을 포함하십시오.
힌트: 자세한 정보는 'git push --help'의 "Note about fast-forwards' 부분을
힌트: 참고하십시오.
보아하니 이전 커밋에서 작업을 하고 푸쉬를 하려니 되지않았지만 준식씨는 머리가 띵해졌습니다.
선우 군에게 도움을 요청하여 최신 커밋을 fetch
하고 merge
를 하면 된다는 소리를 들은 준식씨는 헐레벌떡 실행에 옮깁니다.
선우씨 말대로
git fetch
후git merge ~
해도 되지만 둘 다 한번에 해주는git pull
이 있습니다. pull = fetch + merge
❯ git fetch
❯ git merge origin/main
자동 병합: test.txt
충돌 (내용): test.txt에 병합 충돌
자동 병합이 실패했습니다. 충돌을 바로잡고 결과물을 커밋하십시오.
"선우씨 말대로 했는데 왜...??????"
눈치는 보이지만 선우 군에게 다시 도움을 청해봅니다.
고인물 선우씨는 준식씨에게 착하게 설명해줍니다.
conflict가 생긴거 같네요. 이럴 땐 2 way merge
나 3 way merge
를 해야해요.
제가 링크 드릴테니 한번 보시겠어요?
- 2 way merge : 공통된 부분만 merge하고 나머지는 사용자에게 책임을 넘기는 merge 방식
- 3 way merge : 공통된 조상과 merge하려는 브랜치 2개와 비교한다
1. 세 버전이 같은 경우 : 그대로 merge
- 조상과 a와 같고 b가 업데이트 된 경우 : b로 merge
- 셋 다 다른 경우 : 사용자에게 책임을 넘긴다
오늘도 하나를 더 배워가는 준식씨였어요. 첫 커밋을 한 준식씨 입장에선 선우씨와 버전 차이가 너무 나니 2 way merge
를 하기로 마음 먹었어요.
일단 선우 군과 겹치는 파일을 수정을 하고 commit을 다시 해봅니다.
❯ git status
현재 브랜치 main
현재 브랜치와 'origin/main'이(가) 갈라졌습니다,
다른 커밋이 각각 1개와 1개 있습니다.
(리모트의 브랜치를 현재 브랜치로 병합하려면 "git pull"을 사용하십시오)
병합하지 않은 경로가 있습니다.
(충돌을 바로잡고 "git commit"을 실행하십시오)
(병합을 중단하려면 "git merge --abort"를 사용하십시오)
병합하지 않은 경로:
(해결했다고 표시하려면 "git add <파일>..."을 사용하십시오)
양쪽에서 수정: test.txt
git status
를 입력하니 무엇이 문제인지 알려줍니다
❯ git add test.txt
❯ git commit -m "선우씨는 짱이야"
[main 7293090] 선우씨는 짱이야
❯ git push origin
오브젝트 나열하는 중: 10, 완료.
오브젝트 개수 세는 중: 100% (10/10), 완료.
Delta compression using up to 10 threads
오브젝트 압축하는 중: 100% (4/4), 완료.
오브젝트 쓰는 중: 100% (6/6), 609 bytes | 609.00 KiB/s, 완료.
Total 6 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To https://github.com/GO-TE/GO-TE.git
912778c..7293090 main -> main
다시 add - commit - push로 문제를 해결함으로 준식 군의 이야기는 마무리됩니다.
1일차를 늦게 올린 감이 있는데, 혼자 로컬로만 써봤지 저런식으로 써 본 경험이 없어 정리하느라 조금 늦었습니다,,, 다음부턴 빠릿빠릿하게 올려볼게요
첫 수업이였지만 우려했던 바와 달리 초보자도 쉽게 배울 수 있게 아주 기초부터 시작하더라구요 몇 주간은 좀 그래도 편할거 같습니다. 에이블스쿨 화이팅 !!!!!!!!!!!!!
아 맞다 그리고 2, 3일차도 금방 올라갑니다