Git 프로젝트 시작하기 (심화)
Git을 사용하여 commit을 관리해보자
  • Github

Branch 생성

branch란 무엇일까? branch는 현재 작업하고있는 공간을 말한다. Git은 스냅샷으로 수정사항을 저장하는데, 이 변경사항들을 branch라고하는 내 현재 작업공간에 저장시킨다.

branch를 여러개 사용하면 1개의 프로젝트내에서 한번에 여러기능을 간섭없이 개발할 수 있다.

branch의 생성은 간단하다

$git branch {bracnh이름}

그리고 해당 branch로 이동한다.

$git checkout {branch이름}

branch생성 그리고 이동. 간단하다.
생성과 동시에 이동은 -b옵션을 이용하여 한 줄로도 가능하다.

$git checkout -b {branch명}

branch의 merge 혹은 rebase

branch하나를 만들어서 작업이 끝났다면 다른 branch와 합쳐야한다. 이 합치는 과정을 merge또는 rebase라고 한다. (실제로 동작하는 과정을 다르지만, 소스를 합친다는 입장에서는 동일하다)
(merge와 rebase의 차이점)

다음과 같이 사용한다.

$git checkout {본 branch}
$git merge {merge할 branch}

위와같이 실행하면 {머지할 branch}의 내용이 {본 branch}로 들어가면서 합쳐진다.

작업이 끝난, 즉 필요없는 branch는 삭제해주자.

git bracn -D {삭제할 branch}

Conflict

다수의 개발자가 한 프로젝트에서 각 기능개발을 하다보면 동일한 파일을 수정하는 경우는 반드시 있다.

동일한 파일을 각각의 branch에서 작업하고 본branch에서 합치다 보면 동일한 파일이 수정되었기 때문에
git은 누구의 소스로 합쳐야할지 모르는 상황이 생긴다. 이런 경우를 Conflict가 생겼다고 하고 git은 이를 알려준다.

git merge를 할 때 Conflict가 발생하면 다음과같은 메세지가 출력된다

Auto-merging test.js
CONFLICT (content): Merge conflict in test.js
Automatic merge failed; fix conflicts and then commit the result.

해당 파일을 열어보자

1. init
2. <<<<<<< HEAD
3. init2
4. =======
5. init222222
6. >>>>>>> test

이와같이 <<< HEAD, =======, >>>>>>> 라는 이상한 문자열이 생겨났다!

한줄한줄 살펴보자.
24번 라인 (<<<HEAD ~ ==== 사이) 현재 내 branch의 파일 내용이다.
4
6번 라인 (====== ~ {branch명})은 merge하려는 branch의 파일내용이다.

작업자는 위 3가지의 문자열을 삭제하고 올바르게 최신의 소스로 만들어주면 된다.

완료되었다면 git merge --continue를 실행해주자. merge로 실행했다면 3-way-merge로 잘 merge된것을 확인할 수 있다.

(git log)

*   commit 6e5eda061260ea0a80b034d039ea335cbef73ab5 (HEAD -> master)
|\  Merge: 5a90d20 6e3f217
| | Author: 변경연 <kissob4905@gmail.com>
| | Date:   Thu Oct 17 18:52:39 2019 +0900
| | 
| |     Merge branch 'test'
| | 
| * commit 6e3f21784603485f8fb2e31492c96d98d6da984d (test)
| | Author: 변경연 <kissob4905@gmail.com>
| | Date:   Thu Oct 17 18:49:23 2019 +0900
| | 
| |     add line2
| | 
* | commit 5a90d200d7b4d136305fb71a00e5e20cdfb2ddb9
|/  Author: 변경연 <kissob4905@gmail.com>
|   Date:   Thu Oct 17 18:48:29 2019 +0900
|   
|       add line2
| 
* commit 937139a33251c39aa3e0cd39dd1425f98cb970dd
  Author: 변경연 <kissob4905@gmail.com>
  Date:   Thu Oct 17 18:34:59 2019 +0900
  
      init

rebase를 이용한 commit 관리

1. 이러한 상황을 가정해보자.

  1. 해당 함수를 다 만들어서 commit을 하였다.
  2. 다음 함수를 만들어서 commit을 하였다.
  3. 생각해보니 1번과 2번의 기능은 하나의 커밋으로 합치고싶다.

이러한 경우에 우리는 2개의 commit을 합치는 기능을 사용할 수 있다.

rebase를 사용하는데 사용방법은 간단하다.

$git rebase -i HEAD~{number}

{number} 자리에 해당하는 만큼의 최근 commit을 가져온다. 그리고 합쳐야할 commit중 최신 commit의 상태를 s 혹은 squash로 바꾸고 저장하고 빠져나온다.

항상 최근 commit이 이전 commit으로 합쳐진다는것을 기억하자.

그러면 git은 자동으로 commit메세지를 수정할 수 있는 화면으로 이동한다.

# This is a combination of 2 commits.
# The first commit's message is:

test third

# This is the 2nd commit message:

test second

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# HEAD detached at 494f0f2
# You are currently editing a commit while rebasing branch 'master' on '4278bb2'.
#
# Changes to be committed:
#   (use "git reset HEAD^1 <file>..." to unstage)
#
#       modified:   test.js
#

위 내용 중

test third

# This is the 2nd commit message:

test second

이 부분을 수정하여 한줄로 commit메세지를 작성한다.

저장하고 빠져나와서 git log를 확인해보자. 2개의 commit이 1개로 합쳐진것을 확인할 수 있다.

2. 이러한 상황을 가정해보자.

  1. 해당 함수를 다 만들어서 commit을 하였다.
  2. 다음 함수를 만들어서 commit을 하였다.
  3. 생각해보니 1번과 2번의 커밋 순서를 변경하고싶다.

이러한 경우에 우리는 2개의 commit의 순서를 조정할 수 있다.
이번 역시 rebase를 사용한다.

$git rebase -i HEAD~{number}

순서 변경은 합치는것보다 더 간단하다. 출력되는 순서에서 문서의 순서만 편집해주면 된다.
단 순서조정하는 commit이 conflict가 난다면 조정이 불가능하다.

(필자는 이러한경우에는 git reset HEAD^를 사용하여 최근 커밋을 삭제하고 다시 커밋하는 방식을 사용한다.)

cherry-pick을 이용한 commit 가져오기

branch를 작업하다보면 한 branch에서 너무 많은 작업을 했다거나, 다른 branch에서의 작업을 가져와 함께 pr하고싶은 경우가 생긴다.

이런 경우 git의 cherry-pick이란 기능을 사용할 수 있다.

git log명령어를 통해 commit history를 확인해보자

* commit 067fb6e04d1272cacac2e26d7d2dfacb575984d3 (HEAD -> master, origin/master, origin/HEAD)
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Fri Nov 15 15:47:57 2019 +0900
| 
|     커밋메시지 테스트3
| 
* commit cab73767d9ce702cb546c4144efc18c6cfb58344
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Fri Nov 15 13:18:41 2019 +0900
| 
|     커밋메시지 테스트2
| 
* commit 14fb14306c09e096d50dd90f5641ccd6a78ff5bb
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Thu Nov 14 19:13:55 2019 +0900
| 
|     커밋메시지 테스트1
| 

아래 더 많이 있지만 최근 3개만 보면 위와 같다.
기본적으로 log에는 헤더, 브랜치의 위치, 커밋 메세지와 시간 그리고 중요한 hash값이 있다.
이 hash값을 이용해 우리는 다른 branch의 commit을 가져올 수 있다.

다른 브랜치로 이동하여 간단한 commit을 만들어보자.

git checkout -b fix/main-table-style

1개의 commit을 새로 하였다. 그리고 log을 다시 확인해보자.

* commit 2ba365f8ceb1cf92875b06afdea69d0d020b3ad1 (HEAD -> fix/main-table-style)
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Fri Nov 15 17:03:20 2019 +0900
| 
|     커밋메시지 테스트4
| 
* commit 067fb6e04d1272cacac2e26d7d2dfacb575984d3 (origin/master, origin/HEAD, master)
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Fri Nov 15 15:47:57 2019 +0900
| 
|     커밋메시지 테스트3
| 
* commit cab73767d9ce702cb546c4144efc18c6cfb58344
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Fri Nov 15 13:18:41 2019 +0900
| 
|     커밋메시지 테스트2
| 
* commit 14fb14306c09e096d50dd90f5641ccd6a78ff5bb
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Thu Nov 14 19:13:55 2019 +0900
| 
|     커밋메시지 테스트1
| 

2ba365f8ceb1cf92875b06afdea69d0d020b3ad1 hash값의 커멧메시지 테스트4 가 추가되었다.

master로 돌아가 이번엔 다른 branch를 만들어보자.

git checkout master
git checkout -b fix/main-footer-style

이번엔 커멧메세지 테스트5로 새로운 커밋을 만들어보았다.

* commit 648d6ee06a09cc3513be7e69a3525d21803dc462 (HEAD -> fix/main-footer-style)
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Fri Nov 15 17:03:20 2019 +0900
| 
|     커밋메시지 테스트5
| 
* commit 067fb6e04d1272cacac2e26d7d2dfacb575984d3 (origin/master, origin/HEAD, master)
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Fri Nov 15 15:47:57 2019 +0900
| 
|     커밋메시지 테스트3
| 
* commit cab73767d9ce702cb546c4144efc18c6cfb58344
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Fri Nov 15 13:18:41 2019 +0900
| 
|     커밋메시지 테스트2
| 
* commit 14fb14306c09e096d50dd90f5641ccd6a78ff5bb
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Thu Nov 14 19:13:55 2019 +0900
| 
|     커밋메시지 테스트1
| 

fix/main-table-style, fix/main-footer-style 2개의 브랜치가 생겼다. 이제 PR을 한다고 가정해보자.
가만히 생각을 해보니 2개의 브랜치로 나눌 이유가 없었다. (두 작업이 비슷한 작업이었다고 가정한다)

이런경우 한 브랜치에서 다른 브랜치의 commit을 가져오자.

fix/main-table-style 브랜치에서 fix/main-footer-style 의 마지막 커밋인 커밋메세지 테스트5를 가져올 것이다.
가져오기 위해서는 커밋메세지 테스트5 commit의 hash값을 기억해야 한다. 위에서 보면 648d6ee06a09cc3513be7e69a3525d21803dc462이 값이다.

hash값을 기억했다면 fix/main-table-style으로 이동하자.

git checkout fix/main-table-style

cherry-pick을 이용하여 commit을 가져오자.

git cherry-pick 648d6ee06a09cc3513be7e69a3525d21803dc462

[fix/main-table-style 1831ca4] 커밋메시지 테스트5
 Date: Fri Nov 15 17:05:50 2019 +0900
 1 file changed, 1 insertion(+), 1 deletion(-)

실행 결과를 보면 1개의 커밋을 정상적으로 가져왔다. log을 확인해보자.

* commit 648d6ee06a09cc3513be7e69a3525d21803dc462 (HEAD -> fix/main-footer-style)
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Fri Nov 15 17:03:20 2019 +0900
| 
|     커밋메시지 테스트5
| 
* commit 877571bc3b0788a068b66c665b6dec731931d407
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Fri Nov 15 17:12:41 2019 +0900
| 
|     커밋메시지 테스트4
| 
* commit 067fb6e04d1272cacac2e26d7d2dfacb575984d3 (origin/master, origin/HEAD, master)
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Fri Nov 15 15:47:57 2019 +0900
| 
|     커밋메시지 테스트3
| 
* commit cab73767d9ce702cb546c4144efc18c6cfb58344
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Fri Nov 15 13:18:41 2019 +0900
| 
|     커밋메시지 테스트2
| 
* commit 14fb14306c09e096d50dd90f5641ccd6a78ff5bb
| Author: 변경연 <kissob4905@gmail.com>
| Date:   Thu Nov 14 19:13:55 2019 +0900
| 
|     커밋메시지 테스트1
| 

위 그래프와 같이 1개의 커밋을 가져와서 정상적으로 합쳐졌다!

여러개의 브랜치를 1개로 합쳐 PR을 하고싶은 경우나 혹은 1개의 branch의 commit을 여러개의 branch로 나누어 PR하고싶을 때 사용하면 좋을 듯 하다.