Overview

한 프로젝트를 여러 사람이 작업하면 각자의 feature 브랜치에서 수정한 내용을 하나의 통합 브랜치 (main) 에 합치는 방식으로 진행합니다.

이렇게 브랜치를 통합할 때 사용하는 명령어가 git merge 입니다.

이 merge 는 각 브랜치의 상황에 따라 다르게 동작하고 방법도 다양하기 때문에 어떤 방법들이 있는지 알아봅니다.


1. Git Merge

CLI 또는 GUI 에서 사용하는 경우입니다.

크게 Merge, Fast-Forward, Squash, Rebase 가 있습니다.


1.1. Merge

$ git switch main
$ git merge feature

main 브랜치에 추가 작업 내역이 있다면 새로운 Merge Commit 을 만들게 됩니다.

가장 일반적인 Merge 방법입니다.

feature 의 모든 커밋 로그와 하나로 합친 Merge Commit 로그가 전부 남습니다.


1.2. Fast-Forward

$ git switch main
$ git merge feature # main 에 추가 작업 내역 없음

feature 브랜치를 딴 이후로 main 브랜치에 아무런 커밋이 없다면 merge 할 때 Fast-Forward 방식으로 합쳐집니다.

Fast-Forward 를 그대로 직역하면 "빨리감기" 라는 뜻입니다.

이 말 그대로 별도의 Merge 기록 없이 원래 main 에서 작업한 것처럼 로그가 남습니다.

병합하려는 main 브랜치에 커밋이 존재한다면 Fast-Forward Merge 가 되지 않습니다.


1.3. No Fast-Forward (--no-ff)

$ git switch main
$ git merge --no-ff feature # main 에 추가 작업 내역 없지만 머지 커밋 생성

만약 main 에 추가 작업 내역이 없어도 새로운 Merge Commit 을 만들고 싶다면 --no-ff 옵션을 추가합니다.

feature 브랜치의 존재를 남기고 싶을 때 사용할 수 있습니다.


1.4. Squash (--squash)

$ git switch main
$ git merge --squash feature
$ git commit -m "Merge Squash feature/squash"

Squash Merge 는 feature 의 모든 커밋을 하나의 커밋으로 만들어 main 에 머지합니다.

feature 에서 리뷰 반영, 버그 수정 등으로 쓸데없는 커밋이 많아진 경우 이를 다 기록하지 않고 하나의 새로운 커밋으로 남길 수 있습니다.

대신 feature 브랜치의 수정사항이 큰 경우 하나의 커밋으로 전부 표현하기 보다 커밋을 잘개 쪼개는게 알아보기 더 편할 수 있기 때문에 신중히 사용해야 합니다.


1.5. Rebase

$ git switch main
$ git rebase feature

main 에 아무런 추가 커밋이 없다면 Fast-Forward 와 동일하게 HEAD 만 이동합니다.

하지만 다른 커밋이 있다면 이름 그대로 커밋을 재배치 합니다.

재배치 하고 나면 현재 브랜치의 커밋이 rebase 하려는 브랜치의 뒤로 이동합니다.

main 브랜치에서 git rebase feature 를 했다면 feature 의 커밋 내역이 먼저 찍히고 이후 main 브랜치의 커밋이 찍힙니다.

만약 같은 범위를 수정해서 rebase 과정에서 충돌이 발생한다면 각 커밋 별로 충돌을 해결해야 합니다.

별도의 Merge Commit 이 남지 않는다는 점은 Fast-Forward 와 동일하지만 Rebase 는 각 브랜치에 다른 커밋이 있어도 하나의 줄기로 합쳐줄 수 있다는 장점이 있습니다.


위 사진과 같이 어디 브랜치에서 시작하냐에 따라 커밋의 순서가 바뀝니다.

현재 checkout 한 브랜치의 커밋이 가장 최신에 위치하는 걸 볼 수 있습니다.


2. Github Merge

Github 에서도 Merge 를 할 수 있습니다.

아마 Github 에서 Pull Request 로 코드 리뷰를 받은 후에 Merge 하는 경우가 더 많을 것 같습니다.

Github 에서 지원하는 Merge 는 크게 세종류입니다.


2.1. Create a merge commit

Create a merge commit 을 사용하면 main 브랜치에 커밋이 있건말건 무조건 --no-ff 옵션으로 머지됩니다.

커밋 로그가 전부 남으며 새로운 Merge Commit 이 함께 만들어집니다.


2.2. Squash and merge

Git 과 마찬가지로 feature 의 커밋 이력들 대신 새로운 Merge Commit 하나만 남깁니다.

저는 리뷰 수정사항이 많아서 기능에 비해 커밋 수가 너무 많을 때 사용하는 방법입니다.


2.3. Rebase and merge

Rebase 는 feature 의 커밋 로그를 main 브랜치 커밋 로그 뒤에 붙여줍니다.

위에서 설명할 때 rebase 를 하면 현재 브랜치의 커밋이 대상 브랜치의 커밋 뒤로 이동한다고 했습니다.

이 특성을 이용해서 우선 feature 브랜치에서 main 브랜치를 rebase 한 뒤, feature -> main 으로 Fast-Forward Merge 한 셈입니다.

Git 명령어로 나타내면 아래와 같습니다.


# feature 브랜치로 이동
$ git switch feature

# main 브랜치의 커밋내역을 feature 브랜치 이전으로 끼워넣기
# 이렇게 하면 최신 main 브랜치에서 feature 를 딴 뒤 수정한 것처럼 됨
$ git rebase main 

# 다시 main 브랜치로 이동
$ git switch main

# main 에 feature 브랜치 머지
# rebase 를 했기 때문에 HEAD 만 이동하는 fast-forward merge 실행
$ git merge feature

이렇게 하면 깔끔하게 main 브랜치 뒤에 feature 브랜치 커밋 로그를 남길 수 있습니다.

다만, feature 브랜치의 커밋이 엄청 많은 경우 전부 rebase merge 해버리면 트리만 봤을 때 작업의 큰 줄기가 잘 보이지 않는다는 단점이 있습니다.


Conclusion

그래서 어떤걸 사용하는게 좋냐? 라고 한다면 정해진 답은 없습니다.

여러 개의 커밋을 남기고 싶다면 --no-ff 머지를 사용하고 하나만 깔끔하게 남긴다면 Squash 또는 Rebase 를 사용합니다.

현재 제가 사용하는 방식을 그림으로 나타내면 아래와 같습니다.


저는 대부분의 머지를 PR 에서 하기 때문에 PR 을 최대한 작은 단위로 나눈 후 전부 Squash Merge 하는 걸 선호했습니다.

코드리뷰를 받다보면 추가 수정 사항이 발생하고 자잘한 커밋들을 전부 남기면 지저분하게 느껴서 없애고 싶었어요.

회사에 와서 git rebase main 으로 feature 브랜치를 최신화 하고 --no-ff 옵션으로 Merge Commit 을 남기는 방법을 알게 되었는데 굉장히 깔끔한 것 같습니다.

여러 회사들의 기술 블로그를 보면 각 팀마다 사용하는 Merge 전략이 있는데 여러 가지를 찾아보고 본인이 느끼기에 가장 좋아보이는 전략을 선택하면 됩니다.

'공부 > Git' 카테고리의 다른 글

Gitmoji (for Git Commit Convention)  (0) 2022.06.18
Git Directory 이름 변경  (0) 2020.04.26

Overview

Gitmoji 란 Git + Emoji 입니다.

여러 사람이 커밋 메시지를 작성하다보면 일관성이 없고 나중에는 히스토리를 알아보기 힘들어집니다.

Gitmoji 는 이모지를 사용하여 커밋 메시지를 일정하게 작성하도록 도와주는 툴입니다.

커밋 메시지 타이틀 앞에 특정 이모지를 넣으면서 이모지만 보고도 어떤 목적으로 한 커밋인지 알아볼 수 있습니다.

gitmoji 에 대한 설명은 gitmoji 공식에서 볼 수 있지만 사용하기 위해서는 gitmoji-cli 를 참고해야 합니다.


1. Install

# use brew
$ brew install gitmoji

# use npm
$ npm i -g gitmoji-cli

brew 또는 npm 을 사용해서 설치할 수 있습니다.


2. Configuration

gitmoji 를 사용하기 전에 미리 설정을 해두는게 좋습니다.

gitmoji -g 명령어를 사용해서 여러가지 옵션을 설정할 수 있습니다.

저는 대부분 기본값을 사용하는데 Select how emojis should be used in commits 옵션만 text 대신 emoji 를 선택했습니다.


Github 에서 볼 때는 별 문제 없으나 이렇게 이모지를 지원하지 않는 외부 툴에서는 Text 그대로 노출됩니다.

그래서 이모지 자체를 커밋 메시지에 넣을 수 있도록 설정했습니다.


3. Usage

gitmoji 의 사용법은 크게 어렵지 않습니다.

그냥 평범한 사용법에서 git commit 대신 gitmoji -c 를 입력해주면 됩니다.


3.1. Choose Gitmoji

gitmoji -c 를 입력하면 위 그림처럼 이모지 선택이 나옵니다.

위아래 방향키를 사용해서 다른 이모지들을 찾아볼 수도 있고, 직접 원하는 기능을 검색할 수도 있습니다.


위 그림처럼 refactor 를 검색하면 그에 맞는 이모지를 띄워줍니다.


3.2. Input Commit Message

원하는 이모지를 선택했다면 Commit Title, Message 를 입력합니다.

Message 는 생략해도 됩니다.

전부 입력 후 엔터를 누르면 커밋이 완료됩니다.

이후에는 똑같이 git push 를 사용해서 원격 저장소에 반영할 수 있습니다.


3.3. Repository 확인

이제 커밋 로그를 확인하면 이렇게 이모지가 잘 들어간 것을 볼 수 있습니다.

제가 실제로 두번 커밋한거고 중복해서 로그가 쌓인건 아닙니다.


4. Plugin 및 GUI

IntelliJ 는 Plugin, VSCode 는 Extension 으로 지원하기도 합니다.

IDE 에서 직접 커밋 메시지를 작성하는 스타일이었다면 이용해보는 게 좋습니다.

Source Tree, GitKraken, Git Fork 등등 별도 GUI 를 사용할 때는 아쉽게도 지원되지 않는 것 같아요.

개인적으로 CLI 대신 GUI 를 많이 사용하기 때문에 이 부분이 참 아쉬웠습니다.

그래서 그냥 add, push, pull 등은 전부 GUI 를 이용하고 오로지 커밋만 gitmoji -c 를 사용합니다.

만약 이게 싫다면 이모지를 직접 복사해서 GUI 커밋 메시지에 붙여넣는 방법도 가능합니다.

Gitmoji Dev 사이트에서 원하는 이모지를 검색할 수 있고 그림을 누르면 자동으로 복사되기 때문에 GUI 에서 작성하는 경우 편리하게 이용할 수 있습니다.


5. 장단점

가장 큰 장점은 커밋 로그를 시각적으로 확인할 수 있다 입니다.

단점은 이모지가 뭘 의미하는지 알고 있어야 하고 GUI 와 같이 쓰기 번거롭다는 점인것 같아요.

Gitmoji 를 처음 봤을 때 생각난건 feat:, fix:, refactor: 등을 사용하는 Angular Git Commit Guidelines 였는데요.

시각적으로는 그림인 이모지가 더 잘들어오긴 하지만 가독성은 개인에 따라 다르기 때문에 뭐가 더 낫다고 단언할 수는 없을 것 같아요.

Angular Convention 과 비교했을 때 가장 큰 장점을 뽑자면 Search 기능이라고 생각합니다.

파일을 수정하고 어떤 prefix 를 붙여야할 까 고민될 때 gitmoji 는 대충 이런 목적이다~ 검색을 하면 그에 맞는 이모지를 추천해줍니다.


Conclusion

사실 Gitmoji 가 뭔지 잘 모르다가 회사에서 사용하면서 알게 되었는데요.

처음에는 CLI 와 GUI 를 왔다갔다 하는게 불편했지만 적응해보니 생각보다 쓸만한 것 같습니다.

특히 Search 기능이 강력해서 적당히 입력해도 알아서 추천해주니 큰 고민 없이 넣을 수 있다는게 좋았습니다.


Reference

'공부 > Git' 카테고리의 다른 글

Git Merge (feat. Github)  (0) 2022.06.20
Git Directory 이름 변경  (0) 2020.04.26

Git Directory 이름 변경

Algorithm repo 에서 디렉토리 이름을 변경할 필요가 생겼습니다.


별거 아닌 이유지만 boj -> BOJ 로 leetcode -> LeetCode 로 변경하고 싶었습니다.


우선 Github 에서 디렉토리 이름을 변경하는 방법을 검색했습니다.


  1. 이름을 변경하려는 디렉토리의 상위로 이동
  2. git mv oldName newName 입력
  3. git add git commit 하면 반영



그런데 막상 사용하려니 문제점이 하나 있었습니다.


바로 대소문자를 구분하지 않는다 는 점


$ git mv boj BOJ
fatal: bad source, source=boj, destination=BOJ



해결법은 단순했습니다.


다른 이름으로 변경 후 다시 변경하면 됩니다.


$ git mv boj baekjoon
$ git mv baekjoon BOJ
$ git add .
$ git commit -m "Rename boj to BOJ"

[master 9f7487f] Rename boj to BOJ
 68 files changed, 0 insertions(+), 0 deletions(-)
 rename {boj => BOJ}/1005.java (100%)
 rename {boj => BOJ}/1057.java (100%)
 rename {boj => BOJ}/1074.java (100%)
 .
 .
 .
 rename {boj => BOJ}/image/5397_4.PNG (100%)


'공부 > Git' 카테고리의 다른 글

Git Merge (feat. Github)  (0) 2022.06.20
Gitmoji (for Git Commit Convention)  (0) 2022.06.18

+ Recent posts