업데이트:

이제 git이 무엇인지 알겠는가?

git은 프로젝트의 버전 관리와 협업을 위한 도구이다.

그럼 이제 github에 대해 알아보고 git을 사용해보자.

Github

github은 git repository hosting을 지원해주는 web service이다.

github은 초기 git 호스팅의 선두주자였기 때문에 오픈소스들이 github에 많이 존재한다.

git / github을 관리하라는 말은 내 github 메인 화면을 관리하라는 말과 같다. 내가 얼마나 개발을 해왔는지를 볼 수 있다.

image

현재 내 github 메인 화면인데 아직 시작한지 얼마 되지않아 형편 없지만 개인 프로젝트 또는 팀 프로젝트를 통해 레포지토리를 채우고 잔디밭을 만들어나갈 것이다.

레포지토리 만들기

github이 뭔지 알았으니 사용방법을 알아보자.

일단 앞서 얘기했던 레포지토리란 것을 만들어보자.

레포지토리(Repository)란 깃이 관리하는 하나의 저장소를 의미한다.

여기에 우리가 만들 프로젝트와 관련된 모든 파일들을 업로드하고 git을 이용해 프로젝트의 버전을 관리하고 팀원과 협업할 수 있다.

일단 github에 가입을 하고 다음과 같이 github test용 원격 레포지토리(이하 Repo)를 생성하자.

image

만들면 다음과 같은 창이 뜰텐데 일단 무시하자.
image

branch에 대하여

소프트웨어 버전은 보통 A.B.C로 표시된다. 각 문자는 다음을 의미한다.

  • A : Major : 새 버전
  • B : Minor : 기능 추가, 변경
  • C : Patch : 에러 수정

소프트웨어 개발 프로젝트는 순차적으로 진행되지않고 병렬적으로 진행되는데

이때 branch라는 것을 이용하여 병렬작업을 수행한다.

branch란 커밋 사이를 가볍게 이동할 수 있는 어떤 포인터라고 이해하면 된다.

기본적으로 git은 master 브랜치를 생성한다.

git 명령어 알아보기

git을 사용하기 전에 git으로 관리할 폴더를 만들자.

git bash에서 다음과 같이 명령어를 입력하자.
image

cd [디렉토리주소]

cd는 change directory로 현재 작업 위치를 이동한다.

mkdir [폴더명]

mkdir은 make directory로 현재 작업 위치에 폴더를 생성한다.

먼저 git을 사용하기 위해선 git을 선언해야 한다.

1. git init

git init

git init은 git의 시작을 의미하며 이 순간부터 git은 사용자가 변경한 모든 것들을 추적한다.

git init은 해당 Repo에 .git이라는 폴더를 생성한다. .git 폴더에는 해당 Repo의 모든 버전 관리 정보가 저장된다.

만약 추적을 피하고 싶은 파일이 있다면 .gitignore 파일을 정규표현식에 맞춰 작성하면 된다.

위에서 만든 폴더로 이동하고 git을 선언해보자.
image

다음 명령어로 README.md 파일을 만들어보자.

touch README.md

touch는 말 그대로 touch로 빈 파일 하나를 생성한다.
image

잘 만들어졌는지 확인해보자.

ls

ls는 list로 파일들의 목록을 보여준다.
image

하지만 .git폴더는 보이지 않는다. 숨김폴더이기 때문이다. 다음 명령어를 입력해보자.

ls -al

ls -al는 list all로 해당 폴더의 모든 파일정보를 보여준다.
image

이제 README.md 파일을 수정해보자.

README.md 파일을 수정하기 위해 다음 링크로 이동하여 vscode를 설치하자.

https://code.visualstudio.com/download에서 vscode를 설치하자.

Ctrl + p를 입력하고 > shell을 입력한 다음 엔터를 눌러 code 명령어를 Path에 추가하자.

code .

code는 vscode가 컴퓨터에 깔려있다면 해당 위치에서 vscode를 실행한다. .은 현재 위치를 뜻한다.

다음과 같이 입력하고 저장하자.
image

그리고 git bash에서 다음 명령어를 입력해보자.

cat README.md

cat은 파일의 내용을 보여준다.
image

git status

git status는 현재 git의 상태를 보여준다.
image

현재 README.md파일은 Untracked 파일이라고 나온다.

git은 모든 파일을 Tracked 아니면 Untracked로 나눈다. git은 새로운 파일을 만들면 그 파일을 Untracked 상태로 만든다.

만약 추적하고 싶다면(버전을 관리하고 싶다면) staging area에 파일을 올리면 된다.

2. git add

파일을 staging area에 올리려면 git add를 하면 된다.

git add [파일명]

git add는 해당 파일을 stage area에 올려 다음 커밋에 추가한다.
image

현재 커밋할 사항이 생겼다고 나온다. 아직 commit하기 전이기 때문에 저장을 했다하더라도 버전(스냅샷)이 생성되지 않는다.

스냅샷을 만들기 위해 commit을 해보자.

3. git commit

git commit -m "message"

git commit은 staging area에 있는 스냅샷(버전)을 커밋한다. -m 옵션을 주어 커밋 메시지 입력이 가능하다.
image

git status를 통해 확인해보니 커밋할 사항이 없다고 나온다.
image

git log

git log는 git의 커밋 히스토리(스냅샷의 정보들)을 보여준다.
image

현재 브랜치, 체크섬, 저자 이름, 저자 이메일, 커밋 날짜, 커밋 메세지 등이 출력된다.

README.md 파일을 다음과 같이 수정해보자.
image

vscode에서 파일의 변경사항도 확인할 수 있다.
image

변경사항은 git bash에서도 확인할 수 있다.

git diff

git diff는 수정했지만 아직 staged 상태가 아닌 파일의 변경사항을 볼 수 있다.
image

git add를 통해 수정된 사항을 staging area로 옮기자.

git add .

git add .은 현재 폴더의 파일 모두를 stage area에 올린다.
image

git status를 통해 확인해보니 unstage하는 방법이 나온다. 한번 해보자.

git restore --staged [파일명]

git restore –staged는 staged 상태인 파일을 unstaged인 상태로 만든다.
image

수정했지만 unstaged인 상태라고 나온다.

다시 stage area에 올리고 커밋을 해보자.
image

git commit에서 -m 옵션으로 커밋메시지를 주지않으면 다음과 같은 창이 나온다.
image

여기서 커밋메시지를 입력할 수도 있지만 esc를 누르고 :q!를 입력하고 창을 빠져나오자.

원래 하던대로 커밋하자.
image

이쯤에서 git log를 다시 입력해보자.
image

두개의 버전이 보인다. HEAD는 git이 현재 가르키고 있는 버전을 의미한다.

checkout을 통해 버전이동을 해보자.

아래 버전의 체크섬 앞 7자리를 복사하자. 30df288

git checkout [체크섬 7자리]

git checkout은 git의 HEAD를 해당 체크섬 브랜치로 이동한다.
image

다시 README.md 파일을 확인해보자.
image

파일의 버전이 과거로 돌아갔다. 버전 이동을 한 것이다.

git log도 버전이 없어진 것처럼 보인다.
image

옆에 master라고 쓰였던 부분이 30df288...으로 바뀌어있다.

git log –all을 통해 숨겨진 버전을 볼 수 있다.
image

git의 HEAD가 과거 버전을 가리키고 있고 현재 master 브랜치는 최신 버전을 가리키고 있다.

최신 버전인 master 버전으로 다시 버전이동을 하자.

git checkout master

git checkout master는 git의 HEAD를 master 브랜치로 이동한다.
image

git의 HEAD가 30df288에서 master로 이동한 것을 알 수 있다.

4. git push

이렇게 작업한 것들을 리모트 저장소에 푸쉬하여 다른사람들과 협업을 수행할 수 있다.

image

아까전 만들어두었던 github 레포지토리에서 다음 링크를 복사하자.

image

우측에 url 주소 옆에 있는 copy 버튼을 누르면 복사된다.

git remote add origin [url]

git remote add는 원격 저장소와 로컬 저장소을 연결한다.

image

origin이라는 이름으로 url과 연결하는 것이다.

git remote -v를 통해 연결된 원격 저장소의 이름과 url을 볼 수 있다.

image

보통 git clone을 하면 원격저장소의 이름은 자동으로 origin이 된다. (git clone은 뒤에서 배운다.)

git push -u origin master

git push는 커밋한 내용을 원격저장소에 업데이트한다.

image

이렇게 하면 원격저장소의 내용이 다음과 같이 업데이트된다.

image

우측 상단의 시계모양인 commits 버튼을 통해 커밋 이력을 볼 수도 있고 변경사항도 볼 수 있다.

이렇게 함으로써 다른 사람들과 작업 내용을 공유하면서 협업할 수 있다.

레포지토리 권한 부여

다른 사람들과 같이 개발을 하기 위해 원격 저장소에 대한 권한을 부여하는 법을 알아보자.

image

같이 작업할 레포지토리의 Settings 탭으로 들어간 후 Access 카테고리에서 Collaborators 메뉴로 들어가면 다음과 같이
Manage access를 통해 권한을 다른 사람에게 부여할 수 있다.

image

Add people 버튼을 누른 뒤 권한을 부여할 사람의 깃허브 아이디를 검색하여 추가할 수 있다.

권한을 부여받았으니 이제 프로젝트를 같이 진행할 수 있게 되었다.

프로젝트를 진행하기 위해 레포지토리를 복사해서 내 컴퓨터에 가져오고 싶다.
그러기 위해서 여러 가지 방법이 있지만 git clone을 통해 레포지토리 전체를 가져와보자.

5. git clone

git clone [url]

git clone은 원격저장소를 복제하여 다운로드한다.

그런데 이렇게 다운로드하고 작업을 한 다음 master 브랜치에 commit을 하면 되는걸까?

master 브랜치는 보통 배포용이다. 그래서 배포 전에 어떤 작업을 완성한 다음에 배포를 진행한다.

이때 master 브랜치와 별개로 작업을 진행하도록 도와주는 것이 바로 브랜치이다.

브랜치는 커밋 사이를 가볍게 이동할 수 있는 어떤 포인터 같은 것인데, 개발에 있어 분기점을 만들어준다.

6. git branch

git branch [branch-name]

git branch는 branch-name 이라는 브랜치를 만든다.

새로 만든 브랜치(branch-name)는 마지막 커밋을 가리킨다. 이때 git의 HEAD는 아직 master 브랜치를 가리키고 있다.
image
그림 14. HEAD는 testing 브랜치를 가리킴

git checkout [branch-name]

git checkout은 branch-name 브랜치로 이동한다.

git의 HEAD를 branch-name 브랜치로 옮기고 커밋을 하는 순간부터 branch-name이라는 브랜치에 버전(스냅샷)이 생성된다.
image
그림 16. HEAD가 Checkout한 브랜치로 이동함

7. git merge

git merge [branch-name]

git merge는 branch-name 브랜치를 현재 브랜치로 합친다.

새 브랜치에서 커밋을 남기고 master 브랜치로 이동 후 커밋을 남기면 프로젝트 히스토리는 분리되어 진행한다. image
그림 17. 갈라지는 브랜치

나중에 브랜치가 완성되면 master 브랜치와 합치고 push를 해서 원격저장소에 저장한다.

git의 merge 방식에는 두가지 방식이 있다. Fast forward 방식과 3-way 방식이다.

image
그림 21. master브랜치에서 갈라져 나온 hotfix 브랜치

위와 같은 상황에서 master 브랜치에 hotfix 브랜치를 merge하면 master 브랜치는 그저 최신 커밋으로 이동한다.
이런 merge 방식을 “Fast forward”라고 부른다.

image
그림 22. Merge 후 hotfix 브랜치와 같은 것을 가리키는 master 브랜치

필요없어진 hotfix 브랜치는 git branch 명령에 -d 옵션을 주고 브랜치를 삭제한다.

git branch -d hotfix

git branch -d는 브랜치를 삭제한다.

hotfix 브랜치를 삭제하고 iss53 브랜치에서 커밋을 하나 더 진행했다.

image
그림 23. master와 별개로 진행하는 iss53 브랜치

이 때, 현재 브랜치(master)가 가리키는 커밋이 Merge 할 브랜치(iss53)의 조상이 아니므로 Git은 ‘Fast-forward’로 Merge하지 않는다. 이 경우에는 Git은 각 브랜치가 가리키는 커밋 두 개(C4, C5)와 공통 조상 하나(C2)를 사용하여 “3-way Merge”를 한다.

image
그림 25. Merge 커밋

단순히 브랜치 포인터를 최신 커밋으로 옮기는 게 아니라 3-way Merge의 결과를 별도의 커밋으로 만들고 나서
해당 브랜치가 그 커밋을 가리키도록 이동시킨다. 그래서 이런 커밋은 부모가 여러 개고 Merge 커밋이라고 부른다.

브랜치를 합치는 다른 방법으로는 rebase가 있다.

8. git rebase

git rebase master

git rebase는 base를 master 브랜치로 re-base한다.

image
그림 35. 두 개의 브랜치로 나누어진 커밋 히스토리

위와 같은 상황에서 3-way Merge로 새로운 커밋을 만들어 브랜치를 병합하는 것과 비슷한 결과를 내는 다른 방법으로는
C3에서 변경된 사항을 Patch로 만들고 이를 다시 C4에 적용시키는 방법이 있다. Git에서는 이런 방식을 Rebase라고 한다.
rebase 명령으로 한 브랜치에서 변경된 사항을 다른 브랜치에 적용할 수 있다.

image
그림 37. C4의 변경사항을 C3에 적용하는 Rebase 과정

두 브랜치가 나뉘기 전인 공통 커밋(C2)으로 이동하고 나서 그 커밋부터 지금 Checkout 한 브랜치(C4)가 가리키는 커밋까지
diff를 차례로 만들어 어딘가에 임시로 저장해 놓는다. Rebase 할 브랜치(experiment)가 합칠 브랜치(master)가 가리키는 커밋을
가리키게 하고 아까 저장해 놓았던 변경사항을 차례대로 적용한다.

image
그림 38. master 브랜치를 Fast-forward시키기

그러고 나서 master 브랜치를 Fast-forward시킨다.

Merge든 Rebase든 둘 다 합치는 관점에서는 서로 다를 게 없다.
하지만, rebase가 좀 더 깨끗한 히스토리를 만든다. rebase한 브랜치의 log를 살펴보면 히스토리가 선형이다.
일을 병렬로 동시에 진행해도 rebase하고 나면 모든 작업이 차례대로 수행된 것처럼 보인다.

이제 아래 링크로 가서 Sourcetree를 다운받고 브랜치 실습을 해보자.
https://www.sourcetreeapp.com/

Sourcetree 실습

다음과 같이 Add 메뉴에서 탐색을 통해 로컬에 만들어둔 깃 저장소를 추가한다. image

그러면 아래처럼 그래프와 커밋 메시지가 뜨고 커밋에 대한 상태(해시값 등)를 보여준다. image

vscode로 이동하여 파일을 수정해보자.

test.txt 파일을 추가하고 내용을 다음과 같이 입력하였다.
image

그러면 소스트리에는 다음과 같이 커밋하지 않은 변경사항이 있다고 나타나며 아래에 스테이지에 올라가지 않은 파일이라고 뜬다.

image

커밋하기 위해 스테이지에 올리려면 좌측의 파일 상태 탭으로 이동한 후 test.txt 파일을 ‘선택 내용 스테이지에 올리기’ 하거나
위의 ‘스테이지에 올라간 파일’ 영역으로 드래그하면 스테이지 영역에 올라가게 된다.

image

그러면 다음과 같이 나타나며 git add test.txt 명령어가 실행된 것과 같다.
그리고 하단의 커밋 메시지를 입력하고 커밋을 하면 git commit -m “커밋 메시지” 명령어가 실행된다. image

커밋을 하게 되면 파일 상태에는 아무것도 없게 되며 다음과 같이 새 스냅샷이 나타난다. image

git checkout을 통한 버전 이동은 소스트리에서 그래프의 한 스냅샷을 더블클릭하면 진행된다. image

그러고 나서 vscode를 보면 test.txt는 삭제되고 README.md에는 오늘의 깃헙이라는 내용만 나타난다. image

다시 원래 버전으로 돌아간 후 브랜치를 만들어보자.
소스트리에서 브랜치를 만드는 법은 기준점이 되는 브랜치에 마우스 우클릭을 하여 만들 수 있다. image

그러면 창이 하나 뜨는데 브랜치 이름을 입력하고 브랜치를 생성한다. image

소스트리에서 브랜치 이동은 좌측의 브랜치 탭이나 그래프 위의 브랜치를 더블클릭하면 된다. image

그리고 나서 test2.txt를 만들고 아까와 같이 커밋을 하게되면 test_branch에 스냅샷이 하나 만들어진다. image

그 다음 master 브랜치로 이동 후 test3.txt를 만들고 수정해보자.
image

그러면 커밋하지 않은 변경사항이 있다고 뜨며 그래프에 분기점이 생긴다. image

여기서 test3.txt를 스테이지 영역에 올리고 master 브랜치를 커밋하면 다음과 같은 그래프 구조가 나온다. image

master 브랜치에서 test_branch를 merge하는 방법은 마우스 우클릭을 통해 할 수 있다. image

merge를 하게 되면 자동으로 아래와 같은 커밋 메시지가 작성된다. image

필요없어진 test_branch는 상단 브랜치 메뉴를 통해 삭제할 수 있다. image

이렇게 한 작업들을 이제 원격저장소에 푸쉬해보자. 상단 Push 메뉴를 통해 푸쉬할 수 있다. image

원격 저장소를 확인하면 커밋이 잘 된 것을 볼 수 있다. image

git bash에서 git log를 통해 커밋 히스토리를 한번 봐보자.
image

git log는 소스트리와 달리 분기점과 병합점을 한눈에 보기가 어려운데
다음 명령어를 통해 git bash와 같은 CLI환경에서도 그래프 형태로 볼 수 있다.

git log --all --decorate --oneline --graph

git의 모든 커밋에 대해 꾸며진 한줄의 로그들을 그래프의 형태로 보는 명령어이다.

image

CLI 환경에서는 alias라고 자주 쓰는 명령어들을 설정하여 사용할 수 있다.

git config --global alias.adog "log --all --decorate --oneline --graph"

”–all –decorate –oneline –graph”의 앞글자들을 따서 adog로 설정한다고 한다.

image

그러면 다음과 같이 간단하게 명령어를 사용할 수 있다.
image

9. git fetch

git fetch

git fetch는 로컬에는 없지만, 원격 저장소에는 있는 데이터를 모두 가져온다.
git fetch 명령은 리모트 저장소의 데이터를 모두 로컬로 가져오지만, 자동으로 Merge 하지 않는다.
그래서 로컬에서 하던 작업을 정리하고 나서 수동으로 Merge 해야 한다.

10. git pull

git pull

git pull은 원격 저장소로부터 데이터를 내려받아 연결된 브랜치와 자동으로 Merge 한다.
git pull은 git fetch 명령을 실행하고 나서 자동으로 git merge 명령을 수행하는 것이다.

일반적으로 fetch 와 merge 명령을 명시적으로 사용하는 것이 pull 명령으로 한번에 두 작업을 하는 것보다 낫다.

왜냐하면 병렬적으로 일을 하다보면 파일이 서로 겹치는 부분이 생길 수 있고 이런 부분이 합칠 때 문제가 생길 수 있다.

똑같은 파일을 다른 사람이 수정했을 때 뭔가 버전이 안 맞아지는 것, 이런 것들을 충돌(conflict)이라고 하는데
이런 충돌을 방지하기 위해 다른 사람들의 브랜치를 합치기 전에 비교하기 위해서 fetch를 하고 merge를 수행한다.

만약 작업 도중 같은 파일의 같은 부분을 수정했다면 합칠 때 문제가 발생한다. 문제가 발생하였을 때 해결하는 방법은 2가지 있다.

11. git reset

git reset [option] [commit-hash]

git reset은 해당 커밋으로 이동하고 이후 커밋 기록을 없앤다.

이미 원격 저장소에 올라간 경우에는 reset을 하면 안된다. 다른 사람들과 협업을 할 때, reset을 사용하면 다른 사람들이 가지고 있는 git트리 모양과 아예 달라져서 버전이 안맞게 된다.

12. git revert

git revert [commit-hash]

git revert는 해당 커밋의 내용을 되돌리고 지우는 커밋을 추가한다. 해당 커밋의 내용만 삭제되고 커밋의 삭제 이력이 추가된다.

14. git stash

git stash

git stash는 커밋하지 않은 수정사항들을 잠시 스택에 저장해준다.

개발을 하다보면 브랜치를 바꿔야하는 상황이 많이 있다.
브랜치를 이동하면 커밋을 하지 않은 수정사항들은 같이 따라온다.

아직 완성이 덜 되어 커밋하지 않고 나중에 다시 돌아와서 작업을 다시 하고 싶을 때 stash를 사용한다.

revert, reset, pull 실습

git revert를 한번 해보자.
소스트리에서 revert하는 방법은 기준점이 되는 브랜치에 마우스 우클릭을 하여 커밋 되돌리기를 선택하면 된다. image

그러면 다음과 같은 커밋이 하나 추가된다. image

그러면 test.txt 파일만 없어지고 test2.txt와 test3.txt는 그대로 남아있다. image

git reset으로 아예 이전으로 돌려보자.

아래 커밋에서 해시값을 가져오고 리셋을 하자. image

git reset에서 –hard 옵션은 돌아간 커밋 이후의 변경 이력은 모두 삭제한다. image

그러면 다음과 같이 예전으로 돌아간 것을 확인할 수 있다.
image

원격 저장소와 버전이 다르니 git pull을 해보자. 소스트리의 상단 Pull 메뉴를 통해 할 수 있다. image

원래 버전으로 돌아온 것을 확인할 수 있다. image

오픈소스에 기여하기

fork는 다른 사람의 원격 레포지토리를 내 원격 레포지토리로 복사하는 것이다.
fork는 따로 명령어가 없고 github 등의 git 원격 호스팅 웹서비스에서 기능을 제공한다.

오픈소스 레포를 fork하고 로컬에 clone하여 오픈소스 레포(upstream)와 내 원격 레포(origin)에 remote를 설정한다.
이때 나의 수정 권한은 origin 밖에 없어서 origin에서 수정을 하고 upstream으로 요청을 보내는데, 이걸 Pull Request라고 부른다.

Pull Request를 하는 법

  1. Fork
  2. Clone + Remote 설정
  3. Branch 생성
  4. add, commit, push
  5. Pull Request(PR) 생성
  6. Code Review
  7. Merge PR
  8. Merge 이후 branch 삭제 및 동기화

Github Workflow

branch를 효율적으로 관리하기 위한 방법 중 하나로 github workflow가 있다.

  • master branch (배포용 브랜치)
    • hotfix branch (핫픽스 브랜치)
    • realese branches (릴리즈 브랜치)
      • develope branch (개발용 브랜치)
        • feature branaches (기능별 브랜치)

image

참조

댓글남기기