
이러한 형식을 중앙 집중형이라고 한다면,이 워크플로우는 모든 사람이 마스터 브랜치나 메인 브랜치에서 작업을 하는 것이다. 만약 세명이 깃허브에서 공동작업을 한다고 해보자. 그리고 Pamela, David, Forrest는 모두 깃허브에서 클론을 했다. 그리고 나서 Forrest가 자신의 마스터 브랜치에 커밋을 한 상태라고 했고, 깃허브에 푸쉬까지 한 상태라고 하자. 그러면 아래의 그림과 같은 상태가 된다.

그리고 Pamela도 마찬가지로 자신의 로컬 컴퓨터에서 마스터 브랜치에 커밋을 하였고, 파멜라도 작업한 것을 공유하려고 푸시를 시도한다. 따라서 git push origin master를 했는데 할 수가 없었다.

푸쉬 메시지를 확인하니 "브랜치의 끝이 리모트 브랜치보다 뒤에 있어 업데이트가 거부되었습니다" 라고 나온다. Pamela는 우선 git pull을 해서 업데이트를 했어야한다. 그래서 Pamela는 Forest가 깃허브 마스터 브랜치에 푸시해놓은 내용을 가져온다. 이때 병합이 이루어져야한다. 아래의 그림을 확인하자.

병합이 이루어지고 나서, Pamela는 푸쉬가 가능하다. 이러한 상황에서 David는 홀로 새로운 기능을 개발하고 있었는데 일이 잘 풀리지 않아서 동료들과 상의하고 싶은 상황이다(코드가 엉망진창으로 된 상황). David는 지금까지 작업한 것을 로컬에서 커밋한 후에 동료들과 공유하기 위해서 푸쉬를 하려고 하는데, 이때 아까의 상황처럼 git pull을 하고 그 엉망진창인 코드를 동료들이 깃허브의 마스터 브랜치에 반영해 놓은 내용과 합병을 시킨 후에 푸쉬해야한다. 이 때 David 는 코드 베이스를 건드려 버리는 상황을 발생시켰다. 아래의 그림을 보면 이해가 된다.

중앙 집중형에서는 David는 유일한 브랜치인 마스터 브랜치를 엉망으로 만들 수 밖에 없었다. 따라서 마스터 브랜치에 완벽하게 검증된 코드만 푸쉬하지 않는 이상 협업할 수 있는 방법은 없다.
Feature branch의 핵심은 마스터 브랜치에서 작업하지 말고 피처 브랜치에서 작업하라는 것이다. 항상 피처 브랜치에서만 작업을 하는 것이다. 마스터나 메인 브랜치는 프로젝트의 공식적인 이력을 구별해놓는 브랜치이다.
아까의 예시를 끌어와서 다시 설명하겠다. 우선 Pamela, David, Forrest 모두 git clone을 하고, 그 다음 David가 신규 개발을 위해 새로운 브랜치를 만들어 커밋을 했다고 하자. 아래의 그림을 보면 이해가 된다.

한 30% 정도 구현했는데 현 상태를 팀원들과 공유하고 싶어져서, 특히 Pamela의 도움을 받고 싶어져서, David는 자기가 작업한 Feature 브랜치를 깃허브에 푸쉬한다.

동시에 Pamela는 본인이 맡은 신규 기능을 추가했다고 하자. 그때 Pamela는 David의 연락을 받았다. add-darkmode 브랜치에 코드가 있으니 깃허브에서 pull해서 확인하고 의견을 달아주거나 필요하면 코드를 추가해도 된다는 내용이었다. David가 말한대로 Pamela는 add-darkmode 브랜치를 pull해서 당겨간다. 그 다음 Pamela는 일부를 개선하고 해당 피처 브랜치에 커밋을 한다. 그 다음 깃허브의 add-dark-theme 브랜치에 푸쉬를 한다. 그 다음 David는 깃허브에 있는 코드(Pamela가 개선한 코드)를 Pull 한 뒤에 작업을 한뒤, 만약 add-dark-theme 브랜치에서 하고있는 작업이 승인받으면 그때 마스터 브랜치로 합병한다. 그 다음에 푸쉬를 하면 다른 개발자들 모두 마스터 브랜치에 합병된 내용을 가질 수 있게 된다.
방금의 작업은 각자의 브랜치에서 작업을 하고 푸쉬했지만 그 누구의 작업도 메인 브랜치에 반영된 것은 아니었다. 방법이 두 가지 있다. 하나는 누구든지 자기가 합병하고 싶은 코드를 메인에 합병하는 것이고 또 다른 하나는 팀원과 충분한 토론을 거친 후 메인에 병합하는 것이다. 그리고 그 두가지에 포함되지 않는 하나의 방법은 pull requests이다. 이것은 나중에 설명하도록 하겠다. 합병을 맡기로 한 사람이 자신의 git에서 합병을 진행한 후에 git push를 한다.\
언젠가는 main 브랜치로 merge 하게 되어있다. 모두가 자유롭게 merge 하는 것보다는 특히 조직에서 절대적으로 코드를 무결하게 유지해야한다. pull request 는 깃의 기능이 아니다. 풀 리퀘스트는 개발자가 새로운 작업을 브랜치에 올렸을 때 팀원 이나 공동 작업자들에게 검토를 요청하고 머지를 승인 혹은 반려해달라고 요청하는 장치이다. 여러분 제가 새로운 새로운 기능을 구현해서 새 브랜치에 깃허브에 올려놨으니 확인부탁드립니다 라고 하는 것과 같다.

위와 같이 내 로컬 컴퓨터에서 작업을 끝내고 깃허브에 푸시를 한 후 풀 리퀘스트를 생성한다. 풀 리퀘스트 버튼을 누르면 base:master로 compare:my-new-feature를 합병해도 되는지를 물어보는 것이다. 그 다음 풀 리퀘스트 제목과 머지하려는 이유가 무엇인지 변경사항은 무엇인지 쓰고 난 뒤에 pull request를 누르면 된다.
그 후에 책임자가 깃허브에서 Merge pull request 를 누르게 되면 깃허브에서는 합병이 되지만 로컬 저장소에서는 그렇지 않다. 이 과정이 완료되고 나서는 팀원들은 이제 이 작업이 반영된 최신 버전을 pull한다.
만약 Merge pull request를 하는데, 충돌이 발생하면 어떻게 해결할까(Can't automatically merge)? 충돌이 발생하는 상황이라면 pull request를 할 때 Can't automatically merge라는 말이 나온다.

일단은 그 상태에서 Create pull request를 누르면, This branch has conflicts that must be resolved 라는 말이 나온다.

따라서 충돌을 해결하는 사람이 Resolve conflicts를 누르는 대신 아래의 버튼을 누르면 된다.

그러면 instruction 이 나오는 대로 하면 된다.
step 1: From your project repository, bring in the changes and test.
git fetch origin
git switch new-heading
git merge main
fix conflicts
step 2: Merge the changes and update on GitHub.
git switch main
git merge --no-ff new-heading
git push origin main
우선 git fetch origin을 통해서 원격에서 최신변경 사항을 받아온다.(Stevie가 만든 new-heading을 받아온다.) 그 다음에 그 브랜치로 이동을 하면(git switch new-heading) Stevie가 만들어 놓은 커밋으로 갈 수 있다. 그리고 git merge main을 하여 new-heading 브랜치에 병합을 한다. 여기서 main을 new-heading으로 병합하는 이유는 우선 main에 있는 것은 공인된 것이기 때문에 new-heading 브랜치의 커밋을 할 때 고려를 해서 만들어야 하기 때문이다. 그 다음에 main 브랜치로 이동을 해서(git switch main) main 브랜치를 고려한 커밋이 추가된 브랜치 를 main에 합병시킨다.
중앙 저장소가 깃허브에 단 하나 있던 것(origin)과 달리 이번엔 모든 개발자가 각자 깃허브에 자기 저장소를 가진다고 해보자. 개발자는 자유롭게 코드를 작성하고 PR을 생성하기 전에 자기 저장소로 코드를 푸쉬한다고 하자. 주로 관리자나 프로젝트 오너(각자의 저장소를 가지고 있음)가 여럿 있는 프로젝트에서 이런 워크플로우를 도입한다. 포크는 깃의 기능은 아니고 깃허브가 제공하는 서비스이다. 누군가의 저장소를 포크하면 그 저장소를 복사하여 내 깃허브 계정에 복사본을 생성한다. 이 복사본을 원본 저장소의 포크라고 부른다. 저장소에 있는 포크 버튼을 누른다는 것은 깃허브에 내 개인 복사본을 만들어 달라 요청하는 것이다. 예를 들어 어떤 오픈소스 프로젝트에 참여하고 싶은데 공동 작업자가 아니면, 오른쪽 상단의 fork 버튼을 누르면 된다. fork를 누르면 깃허브 계정에 복사본이 만들어진다. 만약에 2048게임 리포지토리를 클론만 했다고 하면 작업한 코드를 로컬에서 커밋은 할 수 있어도 푸쉬는 할 수 없다. 왜냐하면 단순히 깃허브에 있는 원본 리포지토리를 클론만 한다면 원격과의 연결이 깃허브에 있는 원본 리포지토리로 연결되기 때문이다. 따라서 원본을 fork를 하고 clone을 하면 복사본인 내 계정의 리포지토리로 로컬 컴퓨터가 연결되기 때문에, push도 가능하고 공동 작업자도 모아서 작업을 할 수 있다.
fork clone을 한 뒤에 원본 저장소에게 PR이 가능하다. 이러한 방식으로 오픈 소스에 기여가 가능하다. 푸쉬할 권한은 없어도 풀 리퀘스트를 할 권한은 있다. 3명의 공동 작업자가 대형 프로젝트에 참여하고 싶다고 하자. 아래의 상황과 같다.

그 다음에 복사본을 내 로컬 컴퓨터로 클론한다.

이렇게 되면 origin은 내 복사본 리포지토리가 된다. 여기에 원격 저장소를 하나 추가해보자. 이때 보통 upstream 이라는 원격 저장소를 추가하는데 이는 깃허브의 원본 리포지토리와 연결된다 . 아래의 그림을 확인하자.

이렇게 하면 내 복사본 저장소에 푸쉬할 수 있음과 동시에 원본 저장소의 변경사항을 pull 할 수도 있게 된다. 모든 프로젝트에 이 워크플로우를 적용하는 것은 적합하지 않을 수 있다. 그러나 참여하고자 하는 개발자가 많다면 적합한 워크플로우이다. 모든 개발자를 공동 개발자로 등록하지 않고 참여시킬 수 있는 좋은 방법이다.

이 때 upstream이라는 원격 저장소를 추가하는 방법은 다음과 같다. 원 저장소에 가서 git remote add upstream <URL>을 하면 된다.
setting에서 Branches에서 Add branch protection rule을 누른다. 처음 입력할 것은 Branch name pattern이다. 대형 프로젝트에선 푸시되는 브랜치나 Pull Requests를 생성하는 브랜치 수가 매우 많기 때문이다. 예를 들어 /feature/something 이 있다. 그러나 우리의 예시에서는 main이라고 써놓는다. 그 다음 Require pull request reviews before merging 을 클릭한다. 이렇게 한 뒤 깃허브에서 main 브랜치에서 예를 들어 README.MD 파일을 바꾼뒤 커밋하려고 하면 메인 브랜치가 보호되고 있기 때문에 커밋할 수 없다고 나온다. 왜냐하면 main 브랜치를 Protection 하게 되면 그 때부터는 직접적으로 main에 commit을 할 수 없게 되고 다른 브랜치에서 pull request를 통해서 main에 merge하는 방식을 택해야한다. 그래서 pull request를 하게 되면 아까전에 정해놓은 사람 수 만큼의 승인이 있으면 Merging이 가능해진다. 만약 관리자라면 PR에 들어가 Review changes를 클릭한 후 Approval로 바꾼다.