Git 4가지 영역
말보다는 직접 보는 것이 이해하기 쉽습니다. 직접그렸습니다.
Git이 어려운 이유는 머리에 이 4가지 영역의 그림이 그려지지 않기 때문에 어려운 것입니다. 항상 기본적으로 GitHub에 저장소를 만들고 Intellij 또는 이클립스를 통해 코드를 짠 폴더에 들어가서 git init(안하면 그냥 일반 폴더, 하면 깃 명령어를 사용할 수 있는 폴더)을 해서 초기화를 시켜주고 Git Hub Repository에 연결하여 add . -> commit -> push 를 기계마냥 합니다.
그림을 보고 이해하면 그 과정이 훨씬 더 쉽게 다가올 수 있습니다. 작업공간 은 우리가 그 IDE 프로젝트 폴더가 있는 그 공간을 뜻합니다. IDE에서 작업을 하고 저장을 하면 그 폴더에 저장이 되고 유지가 됩니다. 그리고 Git Add 를 하는 순간 곧 커밋 될 작업 저장 공간(Staging Area)에 저장이 됩니다.
여러 파일들을 Staging Area에 올렸고 이번 Version (Commit)에 더 이상 파일을 올릴 필요가 없을 때, Commit을 하고 내 컴퓨터에 커밋된 저장 공간(Local Repository) 에 올립니다.
마지막으로 여러 Version(Commit)을 나의 컴퓨터가 아닌 Git Hub Respository(Remote)에 Push를 하고 저장시켜줍니다.
이 4가지 영역만 잘 이해하면 전부 다 안다고 해도 무방하다고 말은 못하지만 앞으로의 명령어들이 이해하기가 쉬울겁니다.
곧 커밋 될 작업 저장 공간 ? (Staging Area)
잠깐 ! 곧 커밋 될 작업 저장 공간 ?
처음에 접하면 의아할 것이다. 곧바로 작업 공간에서 작업을 하고 Commit을 하면 될텐데 왜 이렇게 중간에 임시 저장 공간이 필요할까?
저도 궁금해서 찾아보았습니다. 여러 글을 읽어보면 간단하게 결론은 하나입니다. 작업 공간에서 작업한 모든 파일을 Commit하고 싶지 않다. 간단 명료하다. 좀 더 얘기를 해보자면 Commit을 하면서 Version 관리를 하는 데 어떠한 파일은 이 Version에 넣기 싫은 것. 그럼 그 작업 내용만 냅두고 당장의 Version에 올릴 파일들만 곧 커밋 될 작업 저장 공간에 넣는 것 입니다.
origin, upstream에 대한 이해


자, upstream을 알기 전에 origin 부터 설명하겠습니다. origin 은 즉, remote 입니다. 여기서 remote는 우리 컴퓨터의 local이 아닌 실제 git hub에 프로젝트의 저장 공간을 뜻합니다. origin은 remote입니다. ( 그림으로 직관하기 위해서는 맨 위에 구름의 빨간 박스 라고 생각하시면 쉽습니다. )
이제 origin은 무엇인지 알았는데.. upstream은 무엇일까요? upstream에 대한 것을 느끼기 위해 그림을 봅시다.


자, 느낌이 오시나요? 🤭 local - origin(local의 remote) - upstream(origin의 remote) 느낌입니다. 혼란스러운 이유는 딱 한가지입니다. origin 처럼 다른 이름으로 명명하면 되는데 upstream이라는 상대적인 이름을 아예 박아버렸기에 헷갈리는 겁니다. 차라리 A - B - C 하고 각 관계에서 upstream downstream으로 했으면 얼마나 편했을까요?
branch에 대한 이해 (origin, remote update)
이제 branch에 대해 공부하도록 하겠습니다. 음.. 정말 간단히 얘기하면 복사를 당한 또 다른 코드라고 생각하면 됩니다. 즉슨, 코드인데 branch라는 것은 그 코드에 대한 복제라고 생각하면 됩니다. 그럼 원래의 원본과 복제가 여러개 있겠죠? 복제를 만드는 이유는 원본 코드에 영향을 가지않기 위해 독립적으로 개발하기 위해 branch 라는 개념이 생겼습니다. 현재의 branch에서 복제를 하기 위해서는 'git branch 복제이름'으로 복제를 하면 됩니다. ( 복제본에 대한 복제를 또 만들 수 있겠죠? 즉, 상대적인 개념입니다. 🤭) 상대적으로 원본과 복제가 있지만 뿌리 그 자체는 main, master 로 생각하시면 될 것 같습니다. git init 을 통해 초기화를 할 때 제일 먼저 생기는 branch 니깐요.

+) -a option을 통해서 모든 branch를 볼 수 있습니다.
여기서 조금 궁금한 부분이 생겼습니다. remotes/origin/HEAD -> origin/main 라는 부분입니다. 다른 두개의 빨간 branch는 origin, upstream에 대한 branch 라서 이해는 합니다만, HEAD라는 부분이 이해가 어려울 수 있습니다. HEAD라는 것은 현재 상태의 포인터를 나타내는 것이며 사진에 있는 것은 현재 origin 저장소에서의 포인터는 origin/main branch 라는 것입니다. 즉슨, 이 포인터를 이용해서 clone할 때 다른 branch를 지정해줄 수 있겠지요?


git branch --set-upstream-to=origin/new_branch new_branch 의 명령어를 이용하여 추적이 가능하게끔 했습니다. 다시 pull을 해보면 오른쪽 그림처럼 잘 갖고와서 데이터를 병합해줍니다. 🤭
이렇게 각 local, origin 에 branch(복제)가 여러 개가 있고 local에서 origin의 branch를 사용할 때 추적이 가능하게 셋팅을 해줘야합니다!
clone에 대한 이해 (non default branch, single branch)
협업을 할 때 제일 먼저 하는 것은 clone입니다. clone에 대해서 공부해보겠습니다. git repository를 clone을 해봤습니다.


그럼 !? main branch가 아닌 test branch만 갖고오려면 어떻게 해야할까요?
git clone -b {origin_branch_name} --single-branch {origin_url} 🧐🧐
실습을 해보니 현재 tracking 되고 있는 branch가 아닌 test branch 라는 단 하나의 branch를 갖고 오게 됩니다.
fetch에 대한 이해
git fetch에 대해서 공부를 해보겠습니다. 우리는 Add 명령어를 통해 스테이징 영역에 보관을 해놓고 Push를 통해 Remote(Origin)에 저장합니다. 근데 만약 ! ! 그 Remote(Origin)에 있는 저장된 데이터들이 우리(Local)에서는 모르고 있으면 어떻게 될까요? 즉슨, 협업을 통해서 하나의 저장소에 동기화를 시켜주고 서로 데이터를 저장해야하는 데 동기화가 되어있지않다면 밑에 사진과 같이 Push가 먹히지 않습니다.
경고창에 보면 보통은 Pull을 사용합니다. ( + Pull = Fetch + Merge ) 😁😁 맞습니다. Pull을 쓰면 됩니다. 하지만 Pull을 알고 쓰기 위해서는 Fetch를 알아야겠죠? Fetch를 잘쓰지않지만 Fetch를 공부해봅시다.
Fetch는 단순하게 '변경된 내용을 알고 싶을 때, 로컬에 임시로 갖고 온다.' 그러면 Pull이라는 것은 Fetch + Merge 기에 해석을 하자면 변경된 내용을 알고 합친다 ! 라고 해석이 되겠죠?
곧바로 실습해보겠습니다! git fetch origin을 통해 우선 변경된 내용을 로컬로 갖고옵니다. 그리고 git checkout FETCH_HEAD로 이동한다음 ! ! 이력을 확인해봅시다.
변경된 내용을 갖고와서 확인을 할 수 있습니다. 자! 이제 마무리를 하겠습니다.
Push가 안되던 Branch로 다시 돌아가서 Merge를 시켜줬습니다. 물론 Pull만 해도 됩니다. 👏👏
Merge 대한 이해
Merge 같은 경우에는 영어의 뜻 처럼 하나의 브랜치에서 다른 브랜치를 합치는 겁니다.
자 ! 우리는 상대적인 개념으로 원본이라는 브랜치가 존재한다고 가정해봅시다. 그리고 이 원본 브랜치를 복제한 브랜치가 있구요! 그 복제브랜치에서 하나 하나 코드를 고치거나 추가하면서 Commit 을 합니다 ! 이 수정, 추가된 코드를 원본에 Merge ! 합쳐버리면 어떤 상황이 일어날까요 ?
당연히 아무 이상없이 잘 합쳐질 겁니다. 충돌이 나는 경우를 만들어봅시다. 🤔🤔
충돌이 납니다. 두 개의 브랜치가 같은 부분을 수정하고 merge를 했기 때문에 충돌이 난 것입니다. 하지만 먼저 merge를 실행한 issue1_branch는 Fast-forward가 나오면서 원본 브랜치에 자동으로 merge가 되었습니다. 이 Fast-forward는 무엇일까요? 원본은 그대로 있습니다. 딱히 무엇을 하지 않았어요. 그냥 바라만 볼뿐. 원본 브랜치에서 복제브랜치가 그대~로 앞으로 간 것 뿐입니다. 딱히 어떠한 Merge Commit을 할 필요없이 빠르게 Merge가 된것을 뜻합니다.
자. 그럼 우선 충돌된 부분을 고쳐보도록 하겠습니다.
현재 충돌난 파일을 확인하고 어느 부분에서 충돌이 나는 지 확인해봤습니다. <<<<, >>>>> 이 부분이 충돌난 부분 입니다. 이 부분을 수동으로 GUI로 수정했고 다시 스테이징에 넣어 Commit을 해봤습니다.
main|MERGING 상태에서 main으로 변했습니다. 🙏
Log를 보면 issue 브랜치 2 수정에 대한 이력과 충돌 해결한 부분에 대한 이력이 같이 올라가있습니다.
origin을 fork하고 upstream에 업데이트를 했을 때
기존 저장소에서 fork를 하고 나서 그 fork 한 저장소로 clone을 합니다. 이제 local에서 코드를 수정하고 orgin에 push를 한다음 upstream에 PR을 날리는데요 ! 🤔🤔
만약 !! Upstream에 누군가 PR을 날려서 우리의 Orgin 버전과 Upstream이 다르면 어떻게 할까요? 동기화를 시켜줘야합니다. 하지만 우리 Local에서는 Orgin에 대한 Clone만 했을 뿐. Upstream 에 대한 정보가 없는데요.
이럴 때 우리는 Upstream을 셋팅해줘야합니다. ** git remote add upstream [ 브랜치 명 ]** 을 해주면 됩니다. 반대로 !? 만약 orgin이 었다면 ** git remote add orgin [ 브랜치명 ]** 을 해주면 됩니다.
밑에 실습입니다. 추가를 시켜줬고 ! git remote -v 을 통해서 확인해본 결과 upstream 또한 추가 된 것을 볼 수 있습니다.

orgin 에서 single branch clone 했을 때, 다른 branch를 못갖고온다! ( remote update not working ! )
회사에서 겪었던 일이다 ! 보통은 git clone 하고 갖고 온다. 그리고 협업을 할 때 팀원 아무나 origin에 branch 을 새로 팠을 때 나는 이 branch 를 갖고 와야한다. git remote update 를 해보자. 어? 안되네..
뚜둥 !! 되지않는다. 🧐🧐 ( 그냥 git clone 으로 모든 브랜치를 갖고 왔다면 git remote update로 가능하다 ! )
자 ! 이제 해결해보자. 나는 origin의 main branch를 갖고 오고 싶다!
git remote set-branches --add origin main 으로 먼저 ! 지정해주자.
아무일도 일어나지 않는다. 하지만 이미 셋팅이 되어있는 것.
짜잔 ! 그리고 **git fetch orgin main : main ** 해주면 ? 새로운 브랜치를 갖고 올 수 있다.
Rebase 에 대한 이해
git pull 안될 때 ( init 당시 히스토리를 서로 모를 때 )
git pull origin 브런치명 --allow-unrelated-histories