[레벨 1 학습] git 정복하기
서론
git은 분명 처음 시작하면 어렵다고 느껴진다. (그냥 어려운거 같기도..?)
하지만 극복해야 할 부분이기 때문에 이번 글을 통해서 확실히 정리를 해두고자 한다. (해당 내용은 우아한테크코스의 미션을 수행하기 위한 과정을 일정 부분 참고하여 글을 작성하였습니다.)
(해당 글에서는 용어에 대한 자세한 설명은 하지 않습니다. 용어에 대한 내용은 구글링으로 참고해주시면 되겠습니다.)
브랜치
브랜치는 어떤 의미일까?? 브랜치란 동일한 소스코드 내에서 독립적으로 어떤 작업을 진행하기 위한 개념을 말한다. 각 브랜치는 다른 브랜치의 영향을 받지 않기 때문에 여러 작업을 동시해 진행할 수 있다.

저장소의 가장 상단에는 'main(master)'라는 브랜치가 있다. 'main' 브랜치는 모든 소스코드의 최상단에 위치하여 있기 때문에 우리는 각자 작업을 위해서 새로운 브랜치를 만들어 주어야 한다.

위의 사진을 보면 `main`브랜치 밑에 `step1`이라는 우리가 작업할 브랜치가 새로 생성된 것을 확인할 수 있다. 하지만 아직 브랜치는 `main`브랜치를 가르키고 있다. 우리는 이제 새로 생성한 `step1`이라는 브랜치로 이동을 수행할 것이다.

`git checkout step1` 이라는 명령어를 통해 우리는 `step1`브랜치로 이동하였다. 이제 우리가 코딩을 하고 해당 내용을 `commit` 하게 되면 작성된 내용이 `step1` 브랜치에 올라가게 될 것이다.

위의 사진을 보면 `commit`을 하니 `step1` 브랜치는 커밋 1을 가르키고 있고 `main` 브랜치는 커밋 0을 가르키고 있다. 이를 통해, 우리는 작업의 환경이 분리되었다는 것을 확인할 수 있다.
브랜치 합쳐보기
Merge
우리는 이제 브랜치를 나누어서 각자 작업을 할 수 있는 능력을 얻게 되었다. 이제 각자 작성된 코드를 하나로 합치는 작업을 한번 수행해보자.

위의 그림은 커밋 1의 코드를 기준으로 `step1`과 `step1-1`이 각 브랜치로 나뉘어 각각 작업을 한 상태이다. 이제 우리는 `step1-1`에서 작업한 내용을 `step1`의 브랜치로 합쳐 하나의 코드로 합치고 싶어한다.
이때 사용되는 방법이 바로 `Merge`이다.

이렇게 `step1-1`에서 작업한 코드가 `step1`의 브랜치로 합쳐진 모습을 확인할 수 있다.
여기서 한 가지의 의문점을 가져야 한다.
'step1'에 `step1-1` 코드가 merge 되었으니 `step1-1 또한 커밋 4를 가르키게 되는가?
위의 그림을 보면 알 수 있듯이 아니다. `step1-1`도 커밋 4를 가르키도록 명령을 수행해주어야 할 것이다.

이렇게 `step1-1`도 `step1`에서 작성된 코드가 합쳐저 커밋 4를 가르키는 것을 확인할 수 있게 된다. (이때 별도의 커밋이 생성되지 않는다.)
Rebase
그렇다면 rebase는 무엇일까? 설명에 앞서서 간단히 설명하면 좀 더 깔끔한 commit 기록을 남길 수 있다는 점이다.
다음 예시들을 통해서 하나씩 살펴보도록 하자.

상황은 merge를 설명할 때 사용한 동일한 조건에서 시작한다. 우리는 `step2`의 커밋 3의 내용을 `step1' 브랜치와 합치고 싶다. 그러면 다음과 같은 작업을 수행하면 된다.

`git rebase step1` 명령어를 통해 `step2`의 내용을 `step1`의 내용과 합치게 되었다.
이때, 유심히 보아야 할 점은 기존 커밋 3이 삭제되고 새로운 커밋 3이 생성된 것이 아니라 기존의 연결을 끊고 기존의 커밋 3을 복사해서 `step1`에 올려 놓은 구조로 움직인다는 것을 알아야 한다.
이후 `step1` 역시 `step2`에 `rebase`를 하게 되면 `step1`, `step2` 전부 같은 곳을 바라보는 구조로 만들 수 있게 된다.

Merge vs Rebase
정리하자면 `Merge`는 병합의 과정이 모두 히스토리에 기록이 남지만, `Rebase`는 새롭게 히스토리를 쓴다는 점이 각각 차이를 보이고 있다.
만약 `conflict`가 발생하게 된다면?
conflict는 협업을 하다보면 어쩔 수 없이 만나야 할 상황이다. 만약, conflict 해결 방법을 모른다면 다음 영상을 추천한다.
branch 병합 시 충돌해결 - 지옥에서 온 Git
수업내용 여기서는 branch를 병합 할 때 git이 자동으로 처리해주는 소중한 작업이 무엇인가를 소개하고, 자동으로 병합할 수 없는 경우에는 어떻게 이를 수동으로 처리해야 하는지를 소개해드립
opentutorials.org
작업 되돌리기
Reset
`reset`는 잘못된 커밋을 지우고 이전의 커밋으로 되돌아 가는 기능을 말한다.
해당 방법은 오로직 로컬에서만 그리고 혼자 작업할때만 사용하는 것을 아주아주 강력하게 권고하다. (이유는 밑에서 설명하겠다.)

현재 `step1`브랜치는 커밋 3까지 올라간 상태이다. 알고보니 커밋 3에 잘못된 정보가 올라간 것을 확인하고는 완전히 기록을 삭제하고 싶어졌다.

`git reset HEAD~1` 명령어를 입력하면 이전에 커밋했던 기록을 완전히 지우고 그전의 커밋으로 되돌아간다. (정말 완전히는 아니다.)
하지만 해당 방법은 히스토리를 고쳐쓰기 때문에 다른 사람이랑 함께사용하는 `remote` 환경에서는 사용하지 않도록 해야 한다.
reset을 사용하지 않는 이유
루키는 코드를 짜다 코드에 불편한 요소가 보여 과거의 커밋으로 돌아가고자 한다. 그래서 reset 명령을 통해 과거로 돌아가 커밋을 진행했다. 이후 remote repository에 push를 하였는데 conflict가 발생했다. 무엇이 문제인가?
remote repository에는 이전의 커밋이 남아있기 때문이다. 물론 `git push --force`를 하면 가능은 하겠지만 흠.. 상당히 곤란한 상황을 겪을 것이다.
Revert
그럼 `remote` 환경에서는 어떻게 커밋을 뒤로 되돌릴 수 있을까?? 이때 `revert`를 추천한다.

이렇게 `git revert HEAD`를 사용할 경우 이전의 커밋 내용을 돌아가면서 취소한 내역의 히스토리가 남아 안전하게 사용이 가능하다. (즉, 현재 커밋 2는 커밋 1의 내용에 해당한다.)
Push Conflict 해결하기
해결 과정을 적기전에..
사실 이 포스팅을 적게 된 가장 큰 원인이다.
1차 미션을 성공적으로 `Merge`한 다음 정상적으로 `upsteram -> fetch -> rebase` 과정을 문제 없이 수행한 뒤 2차 미션을 진행하였다.




이렇게 `rebase`를 잘 마무리 하고 미션을 수행후 완성된 2차 미션을 원격 저장소 step2로 push 하려고 하는데...
어찌된 일인지 계속 conflict가 발생했다. (이때가 새벽 0시..)
conflict의 원인은 내 원격 저장소의 step2 브랜치에 로컬에서 commit 한 내용이 아닌 다른 크루의 코드가 올라가 있었던 것 때문이였다. 나는 주로 크루들의 코드를 볼때 clone을 하여서 코드를 가져오는데 이때 실수로 내가 착각을 하여 크루의 코드가 있는 IDE창에서 내 원격저장소의 step2로 브랜치를 연결해 push를 해버린 것이였다!!
방법을 찾다가 찾다가 새벽이기도 하고 일단 리뷰를 빠르게 받는게 우선이라는 생각이 들어 결국 step3로 커밋 기록을 이관해서 제출을 하게 되었지만 문제를 해결하지 못했다는 생각이 들어 너무 짜증이났으며 코드를 이관하는 과정도 일일히 수동으로 작성해 commit을 이관하여서 마치 원시인이 따로 없었다.
어떻게 해결 하였는가
너무나 간단한 명령어다.. `git push origin --delete step2`
해당 명령어를 통해 remote repository의 브랜치를 제거할 수 있으며 다시 새로운 step2 브랜치를 만들 수가 있게 된다.
많이들 하는 실수
나는 좀 특이한 케이스의 `conflict`이긴 한데 보통의 `conflict` 사례는 `merge`가 되고나서 `local` 브랜치에 동기화를 하지 않고 진행을 했을 경우가 많은것 같다.
해당 실수를 할 수도 있으니 이번 글에서 해결하는 방법을 정리하려고 한다.
먼저 알아야 할 명령어는 `cherry-pick`이다.
`cherry-pick`은 커밋로그를 내 마음대로 가져올 수 있는 기능을 수행한다. `git cherry-pick`을 터미널에 입력한 뒤 `tab`을 눌러보면 현재 브랜치에서 가져올 수 있는 커밋들을 히스토리로 볼 수 있다. (혹은, `git log`를 통해서도 확인이 가능하다.)

이제 로그에서 가져온 해시 값들을 바탕으로 `cherry-pick`을 수행하면 된다.

만약 한번에 여러개 'cherry-pick'을 하고 싶으면 가져오고 싶은 첫번째 해시 값 ~ 마지막 해시 값을 입력해주면 한번에 cherry-pick이 가능하다.

reference.
https://learngitbranching.js.org/
https://www.lesstif.com/gitbook/git-home-27984628.html
https://opentutorials.org/module/2676/15242