상세 컨텐츠

본문 제목

[git] Centralized Workflow 예시

git

by 메타샤워 2023. 7. 18. 18:30

본문

 git workflow 중 centralized 방식에 대해 step-by-step 으로 실제 사례를 보도록 하겠습니다.

 간단한 시나리오는 다음과 같습니다.

 여러분과 함께할 두 명의 개발자, 철수와 영희가 고용되었습니다. 철수와 영희는 각각에 대한 기능을 개발할 것이고, 철수가 먼저 완성시키고 영희는 철수보다 늦은 죄로 conflict 를 경험하게 됩니다. 이를 해결하며 어떻게 중앙저장소의 commit history를 유지하는지 같이 보도록 합시다.

 

1. 프로젝트 시작하기

가장 먼저해야할 것은 중앙 저장소를 서버에 만들기입니다. 만약 새로운 프로젝트라면 빈 저장소를 초기화시킬 수 있습니다. 원래 진행하던 프로젝트라면 존재하는 git 또는 SVN 저장소를 import해야합니다.
 
 중앙 저장소는 다음처럼 만들어야합니다만, github, bitbucket 등을 사용하여 웹상으로 만들수도 있습니다
ssh user@host
git init --bare /path/to/repo.git
 이 작업이 끝나면 .git 라는 이름을 가진 숨겨진 폴더가 저장소 안에 생길 것입니다. 이 안에 git 설정 파일들이 들어가게 됩니다.
2. 중앙저장소(Central repository) clone 하기
 
이제 철수와 영희가 중앙저장소를 clone할 차례입니다. 이는 git clone 명령어로 실행되어집니다.
git clone ssh://user@host/path/to/repo.git
 여러분이 저장소를 clone 할 때, git는 자동으로 origin 이라는 단축어를 추가하는데, 이 origin은 중앙저장소를 가리키고 있다고 보면 됩니다.
3. 철수가 새 기능 개발을 맡다.
 

철수는 자기 컴퓨터, 즉 local 저장소에서 git commit 프로세스(edit, stage, commit)를 통하여 새로운 기능을 개발할 수 있습니다.
git status # View the state of the repo
git add # Stage a file
git commit # Commit a file
 
위의 명령어가 local commit을 만들어냅니다. 그리고 철수는 중앙 저장소가 어떻게 돌아가는지에 대한 걱정없이 원하는 만큼 위 과정을 반복할 수 있다는 것을 꼭 기억해둡시다. (위 명령어는 중앙 저장소에 영향을 끼치지 않습니다)
4. 영희가 새 기능 개발을 맡다.

영희도 역시 철수와 마찬가지 형태로 또다른 새로운 기능을 개발하기 시작했습니다. 영희 역시 철수와 마찬가지로 중앙저장소에 대해 신경 쓸 필요없이, 또한 철수가 그의 local 저장소에서 뭘 하는지 신경 쓰지 않아도 됩니다. 모든 local 저장소는 private으로 유지됩니다.
5. 철수가 개발을 마치다.
 

철수가 개발을 끝냈습니다. 이제 철수는 local commit 들을 중앙 저장소로 보내야합니다. 그래야 다른 팀원들이 접근할 수 있겠습니다. 아래 git push 명령어로 이 작업을 수행할 수 있습니다.
git push origin master
 origin은 아까 설명했다시피 git가 자동으로 만들어준 중앙저장소로 연결해주는 remote 단축어입니다. 이해가 안되시는 분은 git remote -v 를 누르면 보다 이해가 쉬울 것입니다.
 master 인자는 git에게 "origin의 master branch 를 지금 local에서 쓰는 master 처럼 만들어라"고 알려주는 역할을 합니다. 중앙저장소가 그 사이 누군가에의해 업데이트되지 않았다면 push 는 성공적으로 수행될 것입니다.
 
6. 영희가 개발을 마치다. 그런데...?

 이제 마침 영희도 개발을 끝냈습니다. 영희는 다음처럼 철수와 똑같이 push 하려고 시도할 것입니다.

git push origin master

결국 push는 실행되지 않습니다. 어떻게 해야할까요?

 다음으로 영희가 할 일은 철수의 update 를 자기의 local 저장소로 당겨와야합니다.(pull) 그리고 local 변화를 통합한 후 새로 시도하는 것이 해결책입니다. 다음을 보면서 얘기도록 하겠습니다.

 

7. 영희의 rebase

영희는 git pull 을 사용하여 자신의 local 저장소에 중앙저장소의 최신 흐름 (여기서는 철수가 push한 commit들) 을 불러올 수 있습니다. 이 명령어는 svn update 와 유사하게 동작합니다.

 

git pull --rebase origin master

 --rebase 옵션은 아래 그림과 같이, 중앙저장소로부터의 변경사항을 동기화 시키고 난 후 영희(Mary)의 모든 commit을 master branch로 옮길 것을 미리 지정하는 역할을 합니다.

이 옵션을 쓰지 않아도 pull 은 잘 동작합니다. 그러나 나중에 매번 불필요한 "merge commit"을 해야할 수도 있으므로 --rebase 옵션을 추천합니다. 이번 Centralized workflow에서는 merge commit 보다는 rebase가 항상 더 좋은 결과를 냅니다. (commit history 를 선형으로 유지하기 쉽기 때문입니다)

 

 

8. 영희의 conflict 해결법

 

 Rebase는 각각의 local commit을 master branch로 하나씩 전송하면서 동작합니다. 이는 곧 하나의 큰 merge commit에 대한 conflict를 해결하는 것 보다는 조그만 commit을 베이스로 conflict를 잡아내고 수정하는 것이 더 나음을 의미합니다. 또한 Rebase는 여러분의 commit에 좀 더 포커스를 맞추고, 프로젝트 history를 깨끗하게 만들어줍니다. 버그가 발생했을 때, 가능한 작은 임팩트를 주는 곳으로 roll back 하는 것이 훨씬 버그를 잡는데 유용합니다.

 설명이 길어졌는데, 결론은 commit을 자주 하라는 것입니다.

 

 다시 본론으로 돌아와서, 철수와 영희가 서로 관련없는 기능들을 개발했다면 위와 같은 rebase 과정들이 conflict를 만들어내진 않을 것입니다. 그러나 겹치는 부분이 있다면, git는 현재 commit에서 rebase 를 멈추고 다음과 같은 메시지를 내보일 것입니다.

 

CONFLICT (content): Merge conflict in <some-file>

 git의 장점 중 하나는, 누구나 merge conflict를 해결할 수 있다는데에 있습니다. 흔히 git status 명령어를 사용하면 어디가 문제인지 알 수 있는데, conflict가 생긴 파일은 다음처럼 unmerged path section 에 나타날 것입니다.

# Unmerged paths:

# (use "git reset HEAD <some-file>..." to unstage)

# (use "git add/rm <some-file>..." as appropriate to mark resolution)

#

# both modified: <some-file>>

그러고난 후 영희는 그녀가 원하는대로 해당 파일을 수정할 것입니다. 수정이 끝난 후 아래처럼 다시 git add를 통해 파일을 stage 상태로 만들고, git rebase로 나머지 작업을 마무리 짓습니다.

 

git add <some-file> 
git rebase --continue </some-file>

 여러분이 여기까지 오셨는데도 이해를 거의 못했다고해서 당황할 필요는 없습니다. 단지 아래 명령어를 실행하는 것만으로도 여러분은 시작점으로 쉽게 돌아갈 수 있습니다. git pull --rebase

 

git rebase --abort

9. 마무리

위와 같이 영희의 동기화 작업이 끝나면, 그 변경작업들이 성공적으로 push 되어질 수 있을 것입니다.

 

git push origin master