Git을 실무에 활용하기 2탄

저번시간에는 모두 로컬 데이터베이스 기반으로 동작하는 git명령어들에 대해 알아 보았습니다. Git은 저장소(Repository)를 전부 복제한 복제물을 사용하기 때문에 로컬파일에 대하여 변경이 이루어지며 따라서 네트워크속도에 영향을 받지 않고 때문에 히스토리를 조회하거나 변경사항을 확인할때 리모트에 있는 서버에 접근 할 필요가 없어 그 속도 또한 매우 빠르다고 얘기 하였습니다. 자, 그렇다면 코드변경의 공유는 어떻게 이루어 지는걸까요? 오늘 Git을 실무에 활용하기 2탄에서는 다른사람들과 협업시 꼭 필요한 원격저장소와 브랜치의 개념, 충돌시 대처할 수 있는 기능에 대하여 자세히 알아 보겠습니다.

[원격저장소란]

원격저장소란 인터넷이나 네트워크 어딘가에 있는 저장소입니다. 커밋은 로컬저장소에만 업데이트 되기 때문에 로컬 데이터베이스에만 변경사항이 저장되는데요. 이를 원격저장소에 업데이트하여 로컬저장소에 커밋한 내용을 다른사람들과 공유할수 있는 곳입니다.

git remote

현재 프로젝트에 등록된 원격 저장소를 확인할 수 있습니다. 원격 저장소를 clone하면 기본값으로 origin을 볼 수 있습니다.

참고>>

원격 저장소목록과 url을 함께 보고 싶다면 -v옵션을 사용해보세요.

git remote -v

git push [원격저장소 이름] [로컬 브랜치 이름]:[원격 브랜치 이름]

로컬 저장소에 커밋한 코드의 변경사항을 원격저장소로 업데이트 하여 프로젝트를 공유하고 싶을때 사용합니다. 처음 clone을 통해 원격 저장소로부터 소스를 복제하였다면 origin이라는 이름이 자동으로 생성됩니다.

참고>>

옵션을 통해 원격저장소와 로컬저장소를 지정할 수 있습니다.

git push origin master #(=git push origin master:master) master로컬 브랜치를 origin서버의 master리모트 브랜치에 코드변경사항을 반영하겠다. 만약 원격저장소에 master라는 리모트브랜치가 없다면 바로 생성하여 master로컬브랜치의 내용을 반영 할 수 있음.
git push origin :old-branch #원격저장소에 있는 old-branch리모트 브랜치 삭제.

git pull [원격저장소 이름] [원격 브랜치 이름]:[로컬 브랜치 이름]

원격 저장소의 최신 내용을 로컬 저장소로 반영합니다. 즉, 다른 사람이 자신의 로컬 저장소에 코드의 변경사항을 커밋하고 push를 통하여 원격저장소에 업데이트 한 내용을 자신의 로컬 저장소로 가져와 변경된 내용을 확인 할 수 있습니다. 이때 코드변경이 중복되어(사용자간 동일파일 변경시) 충돌이 생기게 되면 자동으로 머지 혹은 수동으로 머지할 수 있습니다.

참고>>
git pull origin master:jh #원격저장소의 master브랜치의 내용을 jh로컬 브랜치에 업데이트 한다.
git pull #.git/config의 설정대로 동작. (git conflig --list로 설정 내용을 확인할 수 있다.

git feach

원격 저장소의 데이터를 모두 로컬로 가져오지만, 자동으로 머지하지는 않습니다.

참고>>
git feach

[브랜치]

코드를 통째로 복사하고 나서 원래 코드와는 상관없이 독립적으로 개발을 진행하기 위하여 사용합니다. Git에서 브랜치를 생성하는 것은 소스 코드를 통째로 복사 하는 것이 아닌 현재 저장소의 스냅샷을 별도로 저장해 두는 것입니다. 브랜치의 이동은 그 때 저장된 스냅샷을 이동하는 것입니다. 여기서 브랜치는 커밋사이를 이동할 수 있는 어떤 포인터 같은 것이라 하겠습니다. 지금 작업하는 로컬 브랜치는 HEAD라고하는 특수 포인터가 가리키고 있습니다. 현재 가리키고 있는 브랜치에서 파일의 생성/수정/삭제 등의 모든 코드 변경작업이 이루어 지게 됩니다.

  • 리모트 브랜치 : 원격저장소에서 생성된 브랜치.
  • 로컬 브랜치 : 로컬 저장소에서 사용하는 브랜치. 원격 저장소와 통신할 수 없다.

git branch [브랜치명]

로컬 브랜치를 생성합니다. 참고로, 원격 저장소로부터 소스를 복제하면 기본적으로 origin이라는 원격저장소와 master브랜치가 생성됩니다.

참고>>

git checkout명령어를 통해 브랜치를 이동하거나, 브랜치생성 이동을 동시에 할수 있습니다. 제가 "이동"이라고 표현했지만 실제로는 특수 포인터 "HEAD"가 해당 브랜치를 가르키고 있는 것입니다.

git checkout jh #jh로컬 브랜치로 이동. (=특수 포인터 "HEAD"가 jh로컬 브랜치를 가르킨다.)
git checkout -b jh #jh브랜치를 생성함과 동시에 jh브랜치로 이동.

브랜치 옵션은 다음과 같이 사용할 수 있습니다.

git branch #로컬저장소에 있는 브랜치목록 확인한다.
git branch -r #원격 저장소에 있는 브랜치목록 확인한다.
git branch -a #로컬저장소와 원격 저장소에 있는 브랜치목록 확인한다.
git branch -d old-branch # 로컬 저장소에 있는 old-branch를 삭제한다.
git branch -t [remote/branch] #리모트 브랜치를 로컬브랜치로 받는다.

[Stash]

현재 브랜치에서 워킹디렉터리에 있는 수정된 내용(로컬 저장소에 커밋되기 전)을 임시로 저장하고 싶은 경우 사용합니다. 백업용도로 많이 사용하는 기능입니다. Stash를 사용하면 변경사항을 임시로 스택에 저장해 두고 나중에 꺼내어 적용할 수 있습니다. 사용 후에는 워킹디렉터리는 처음 변경사항이 없던 상태로 보여집니다.

git stash

워킹디렉토리에서 변경된 파일들을 stash스택에 저장합니다. 기본적으로는 Tracked상태(staged상태+unstaged상태)의 파일만을 저장합니다.

참고>>

Untracked파일을 함께 스택에 저장하고 싶다면 -u옵션을 사용해보세요.

git stash -u #Untracked파일을 함께 스택에 저장한다.

git stash list

저장한 stash목록을 확인한다.

참고>>

아래와 같이 stash목록을 확인할 수 있어요.

stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log

git stash apply

stash목록 중 가장 마지막에 저장한 내용을 워킹디렉토리에 적용합니다. 적용시에는 Staged상태를 기억하여 복원하지 않기 때문에 Staged상태를 반영하고 싶다면 --index옵션을 추가적으로 해 주어야 합니다. 또한, apply명령어는 적용만 할뿐 stash스택에서 지워지지는 않습니다.

참고>>

가장 마지막에 저장한 내용이 아닌 stash스택에 저장된 특정 인덱스 내용을 적용하는 방법은?

git stash apply stash@{1}

git stash drop

stash스택에 저장된 내용을 지우고 싶을때 사용합니다. stash@{#number}을 사용하면 원하는 stash스택 내용을 지정할수 있습니다.

참고>>
git stash dropstash@{1}

git stash pop

stash스택에 있는 내용을 적용 후 스택에서 제거해줍니다. stash@{#number}을 사용하면 원하는 stash스택 내용을 지정할수 있습니다.

참고>>
git stash popstash@{1}

git stash clear

백업 리스트 모두 지웁니다.

git stash sava [스택에 저장할 이름]

stash 스택에 저장할때 이름을 함께 지정할수 있습니다.

[Merge]

기본 브랜치(기본 master)로 부터 기능개발을 위한 새로운 브랜치를 생성하여 작업이 완료되었다면 기본브랜치와 새로운 브랜치의 내용을 합쳐주는 작업이 필요합니다. 브랜치끼리의 작업을 합치는 방법은 두가지가 있는데요. 첫번째로 알아볼 기능은 Merge기능입니다. 먼저 Merge의 종류 2가지를 알아 봅시다.

  • fast-forward : merge할 브랜치가 가리키고 있던 커밋이 현 브랜치가 가리키는 것보다 앞으로 진행한 커밋이기 때문에 master브랜치 포인터는 최신 커밋으로 이동. 앞으로 진행한 커밋이라는 의미는 동일한 커밋히스토리를 가지고 있음을 의미한다. (현재 브랜치가 가리키는 커밋이 Merge 할 브랜치의 조상인 경우.)
  • 3-way merge: 서로다른 커밋내역을 가지고 있는 경우 (현재 브랜치가 가리키는 커밋이 Merge 할 브랜치의 조상이 아닌 경우.) 공통조상을 찾아 커밋내용을 하나로 합쳐준 후 브랜치 포인터가 합쳐진 커밋을 가르키도록 한다.

git merge [대상 브랜치명] [to브랜치명]

브랜치의 커밋내용을 합쳐줍니다.

참고>>
git merge jh #현재 브랜치에 jh브랜치를 합친다.
git merge jh master #jh브랜치를 master브랜치에 합친다.

[Rebase]

브랜치끼리의 작업을 합치는 두번째 방법입니다. Rebase는 기본적으로 커밋들을 모아서 복사하여 내용을 합칩니다. Rebase를 하면 서로 다른 브랜치에서 작업하여도 커밋들 작업이력들의 흐름을 보기 좋게 한 줄로 만들 수 있다는 장점이 있습니다. 브랜치를 합치는 두가지 방법에서 먼저 Rebase의 경우, 브랜치의 변경사항을 순서대로 다른 브랜치에 적용하면서 합치고 Merge의 경우는 두 브랜치의 최종 결과만을 가지고 합친다는 차이점이 있습니다.

git rebase [to브랜치명] [대상 브랜치명]

새로운 기능 개발 브랜치에서의 작업을 기본 브랜치(master)로 직접 옮겨 놓으려고 할때 사용합니다. 그렇게 하면, 실제로는 두 기능을 따로따로 개발했지만, 마치 순서대로 개발한 것처럼 작업이력의 흐름을 볼 수 있습니다. 저장소의 커밋 로그와 이력을 깨끗하게 관리하고 싶을때 사용합니다.

참고>>
git rebase jh #현재 브랜치를 jh브랜치에 합친다.
git rebase jh master #jh브랜치에 master브랜치를 합친다.

마치며

지금까지 실무에 활용할수 있는 Git에 대해 알아 보았습니다. 개념적인 부분보다는 실제로 많이 사용할수 있는 명령어 위주로 알아 보았는데요. 마지막으로 git의 브랜치를 활용하는 대표적인 work flow와 git명령어를 연습해 볼수 있는 사이트를 공유해 드릴게요. 개발시에 많은 도움이 되었으면 합니다.

alt text

Git 연습하러 가기