본문 바로가기

git/github

[Git] git merge - fast forward, 3-way-merge

최근 회사에서 git을 사용하게 되면서 progit책을 구입하여 다시 git을 공부하고 있습니다.

github을 통해서 개인적으로는 git을 계속 써오긴했으나 사용하는 명령어가 clone, push, fetch, pull, commit등 주로 혼자 사용하게 되는 명령어로 한정이 되어있던데다가... 지금 회사처럼 많은 개발자가 동시에 사용해본 경험도 없어서 아무래도 한계가 금방 다가오더군요...


progit책에 대한 리뷰는 곧 쓸 예정이긴한데요.. 내용중 merge에 대한 내용을 직접 실습해보면서

정리를 할겸 블로그에 포스트를 남겨봅니다.


merge는 크게 fast-forward와 3-way merge로 나뉘어집니다.


저는 처음에 git에서의 merge가 각 파일의 수정사항을 하나하나 비교하면서 직접 파일의 내용을 가감하는줄 알았습니다. 근데 fast-forward의 경우 그런식의 merge가 아니더라구요..


즉, 아래와 같이 commit이 있을 때..


             master

                 |

C1 - C2 - C3


issue1 branch를 생성하면 아래와 같이 되고..


             master

                 |

C1 - C2 - C3

                 |

              issue1


issue1에서 commit을 하게되면 아래와 같이 커밋히스토리가 생성됩니다.


              master

                 |

C1 - C2 - C3 - C4

                        |

                       issue1


git에서의 commit을 svn처럼 각 파일의 변경내용과 그에따른 리비전 번호가 아닌 repository의 스냅샷입니다.

따라서, C4의 commit에는 이미 C3까지의 commit 내용이 담겨있는 상태입니다. 이상태에서 master로 merge라고 함은.. master의 포인터를 최신 커밋을 가르키고있는 issue1의 포인터로 이동시키는 것입니다. 


                      master

                         |

C1 - C2 - C3 - C4

                         |

                      issue1


이제 master 브랜치에서 다시 작업을 진행(C5 commit) 하고, merge가 되어 불필요한 브랜치인 issue1은 삭제를 합니다.


                           master

                               |

C1 - C2 - C3 - C4 - C5


위와 같은 방식으로 작동하는 merge가 fast-forward입니다.


3-way merge는 조금 다르게 작동합니다. issue1 브랜치를 만든 상태로 다시 돌아가보겠습니다.

              master

                 |

C1 - C2 - C3 - C4

                        |

                       issue1


그러다가, 다른 이슈가 급하게 들어와서 그걸 처리해야 할 일이 생겼습니다. 다시 master 브랜치로 돌아가서 issue2 브랜치를 생성합니다.


               master

               issue2

                 |

C1 - C2 - C3 - C4

                        |

                       issue1


그리고, issue2 브랜치에서 작업을 진행하고 commit을하면 아래와 같은 형태가 됩니다.


            master  issue2

                |       |

C1 - C2 - C3 - C5

                |

               C4

                |

               issue1


issue1과 issue2의 커밋 히스토리가 갈라졌습니다. 이 상태에서 급한게 처리한 issue2를 master에 merge해 적용합니다. 이 경우에는 앞에서 작성한 fast-forward 방식으로 merge가 진행됩니다.


                     master

                     issue2

                        |

C1 - C2 - C3 - C5

                 \

                    C4

                      |

                     issue1


issue2 브랜치를 삭제하고, 다시 issue1으로 돌아가 작업을 진행합니다.


                     master

                        |

C1 - C2 - C3 - C5

                 \

                    C4 - C6

                             |

                          issue1


작업이 모두 끝나고 이제 다시 issue1을 master로 merge합니다. master 브랜치에서 merge issue1을 실행하는 것인데요.. 현재 master의 커밋이 merge할 브랜치의 조상이 아닙니다. C5는 C4, C6과는 아무런 관련이 없죠. 때문에, 두 커밋의 공통 조상을 찾아 (C3) 3-way merge를 진행하고 그 결과를 새로운 커밋으로 만들어 master 브랜치의 포인터가 그 커밋을 가르키도록 합니다.


                                  master

                                       |

C1 - C2 - C3 - C5 ------ C7

                  \                /

                       C4 - C6 

                                |

                             issue1


여기서는 C3, C5, C6이 merge할 커밋으로 선택되어 merge가 되고, 그 결과를 C7 커밋으로 생성하여 master 브랜치의 포인터를 C7으로 옮겼습니다.


위 내용은 모두 pro-git 책이나 progit 사이트에 더 잘 정리가 되어있는 내용입니다. 다만, 처음 git을 사용하면서 merge와 branch의 작동 방식에 대해서 명령어와 결과만 알고 있었지 이렇게 그 원리를 알지는 못 했다가 이번에 책을 보면서 스스로 한번 정리를 해보기위해서 작성해보았습니다.


git을 사용하신다면 progit 책이나 사이트는 꼭 읽어보시면 좋을것 같습니다.


다음엔 rebase를 가지고.. 또 공부해봐야겠네요.. 사실 혼자 github으로 쓸때는 정말 쓸일이 거의 없던것이 rebase였는데...