핵심 키워드 | 로컬 git 관리, Issue, Project, Merge, PR, 커밋 이력 변경
슬슬 프로젝트를 다시 시작할 때가 되었다. 보다 원활한 협업을 위해서, 책을 통해 다시 git 사용 방법을 정리했다.
Git은 소스 코드를 관리하는 하나의 방법이다.
Git은 원격 저장소와 로컬 저장소로 구분될 수 있다.
로컬 저장소의 작업 방식은 아래와 같다.
먼저 디렉토리에서 git init 을 통해 디렉토리를 git 작업 트리로 설정하게 된다.
이 때 해당 디렉토리의 소스 파일들은 작업 디렉토리에 올라가고, untracked 상태가 된다.
파일을 git add하면, 스테이징 영역에 올라가고, git 에 의해 추적되는 상태가 된다(tracked) .
같은 스테이징 영역에서도 staged, unstaged 상태로 나뉠 수 있는데, staged는 commit으로 기록할 수 있는 상태, unstaged는 파일 변화가 있어 commit으로 기록할 수 없는 상태를 말한다.
staging된 파일에 변경이 생길 경우 해당 파일들은 untracked, unstaged 상태가 된다. 그러나 여전히 스테이징 영역에 있다. 다시 git add를 통해 파일을 staged, tracked 상태로 변경할 수 있다.
git commit을 통해서 staged 상태의 파일들을 지역 저장소(local storage)로 옮기게 된다.
깃허브에서 Issue, Project 등의 작업을 수행할 수 있다.
Issue는 쉽게 말해 최소 단위의 task로, 소스 코드에 대한 수정 사항이나 추가할 점 같은 하나의 목적을 위한 작업 단위이다.
Issue는 이슈 만으로 다루어질 수 있으나, Project에서 Issue를 가져와 다룰 수 있다.
Project는 보다 전체적인 맥락에서 코드를 관리하는 task 관리 방식으로 작업 중인 이슈들 목록, 완료된 이슈들 목록을 카드 단위로 다루게 된다. 이슈는 하나의 task로써 Project에서 작업 중인 이슈로 올라왔다가, 이슈가 해결되면 완료된 이슈로 옮겨지게 된다.
Git은 여러 브랜치를 가질 수 있으며, 두 개의 브랜치가 각자의 코드를 합치는 것을 Merge라고 한다.
여기서는 Merge의 기준이 되는 브랜치를 기준 브랜치, 합쳐지는 브랜치를 작업 브랜치라고 칭하겠다.
→ 작업 브랜치에 변경사항이 있고, 기준 브랜치에는 변경 사항이 없다면, Merge를 할 때 아무 문제가 발생하지 않는다. 이러한 방식을 Fast-Forward라고 한다.
→ 겹치는 부분에 변경 사항이 없을 경우, Auto-Merging 이 수행된다.
→ 이 경우에는 문제가 발생한다. git은 겹치는 부분의 코드를 commit으로 반영하지 않고, 사용자에게 해당 부분을 수정할 것을 요구한다. 이렇게 두 코드 사이에 충돌이 발생한 것을 Conflict라고 한다.
(소스 코드 내...)
같은 코드..
<<< HEAD
기준 브랜치 변경 코드
=================
작업 브랜치 변경 코드
>>> 작업 브랜치 명
같은 코드..
해당 부분을 다음과 같이 수정한다.
(소스 코드 내...)
같은 코드..
취합하여 변경한 코드
같은 코드..
수정된 코드를 다시 add하고, commit 한다. 이 때 git cli는 Resolve Conflict 라는 문구를 반환한다.
Git을 통해 협업을 할 경우, 협업자의 동의 및 리뷰와 함께 Merge를 수행해야 한다.
github에서는 이러한 협업자 로부터의 동의 및 리뷰를 요청할 수 있는 방식을 제공하는데, 이를 Pull Request라고 한다. github 사이트에서 특정 브랜치의 Main 브랜치로의 (혹은 원하는 기준 브랜치로의) merge를 Pull Request 방식으로 수행할 수 있다.
Pull Request가 협업자에게 리뷰되고, 동의(Approve)되면, Pull Request는 Merge될 수 있다. 이는 원격 저장소에서 발생하는 일이고, 이후 협업자들은 지역 저장소로 코드를 가져와야 한다.
변경된 원격 저장소의 내용을 지역 저장소로 가져와 작업을 지속하고자 할 때, Fetch나 Pull을 사용해야 한다.
Pull은 단순히 원격 저장소의 코드를 가져와 로컬 저장소의 브랜치와 병합을 수행한다.(브랜치는 변경할 수 있으나, 원격 저장소와 동일한 것이 더 낫다.) 그러나 코드의 변경 사항에 의해 Conflict가 발생할 경우, Pull은 좋은 방법이 될 수 없다.
그래서 Fetch를 먼저 사용하는 것이 좋은데, Fetch는 원격 저장소의 코드 내역을 복사하여 가져오되, 로컬 저장소의 브랜치와 합치지 않는다. 사용자는 Fetch한 코드 내용을 로컬 저장소의 내용과 비교하여 변경 사항이 어떻게 있는지를 확인할 수 있다. 이 때 Conflict와 같은 상황이 발생하면, 해당 부분에 대한 처리를 수행할 수 있다.
충돌 가능성이 있는 원격 저장소의 코드라면 Fetch를, 충돌 가능성이 없음을 확신하는 코드라면 Pull을 수행하는 것이 좋겠다.
커밋 이력을 수정해야 할 때가 있다. 다음 4가지의 git 명령어를 통해 알아보자.
병합까지는 필요 없고, 특정 시점의 commit data만 필요할 때 cherry-pick 명령어를 수행할 수 있다. 예를 들어 결함이 있는 브랜치의 결함 수정 커밋만 추가하여 브랜치를 수정하고 싶을 때 이 명령어를 사용한다.
현재 브랜치의 커밋을 이전의 커밋으로 돌리고 싶을 때 사용한다. 다만 이 경우 돌아간 커밋 이전의 커밋은 git log에서 사라지고, 다시 참조할 수 없다.
reset과 유사한 기능을 수행하지만, 기존의 커밋을 삭제하지 않으며, 다만 돌아가고자 하는 커밋을 최신 커밋으로 추가하고 이를 Head로 가리킨다.
특정 브랜치의 커밋 이력을 기준으로 작업 브랜치의 커밋을 재정렬할 때 사용한다.
1) 처음 상태
branch | commits
Main | B - B1
Work | B - B2
2) Work branch의 내용을 Main 기준으로 Merge
branch | commits
Main | B - B1 - B'
Work | B - B2 /
3) Work branch의 내용을 Main branch 내용으로 rebase
branch | commits
Main | B - B1 - B'
Work | B - B1 - B''
-> 두 브랜치의 체크섬은 다르나, 내용은 동일하다.
-> 이 때 두 브랜치의 체크섬까지 동일하게 변경하려면,
-> Main이 Work를 기준으로 다시 Merge를 수행해야 한다.
- 책 | 박미정의 깃&깃허브 입문, 박미정