브랜치 또는 특정 commit 내용을 현재 브랜치에 병합하는 것
git merge <branch> or <commit>
주가 되는 브랜치로 이동해서(checkout) 합치려는 브랜치 또는 commit <branch> or <commit>
위치에 적어주면 된다.
Merge는 fast-forward 방식과 3-way-merge방식이 있다.
merge할 대상 브랜치의 commit이 현재 브랜치보다 앞으로 진행한 commit인 경우,
두 브랜치를 합칠 때는 현재 브랜치의 포인터를 merge시키려고 한 브랜치로 이동만 시켜주면 된다.
master 브랜치에 commit이 몇번 되어있는 상태이다. 현재는 c2가 가장 마지막 commit이다.
master 브랜치에서 iss53 브랜치를 생성해 작업을 진행하고 commit하면 iss53은 앞으로 나아가게 된다.
이 때 당연히 master에는 아무런 영향이 없다.
위의 상황에서 iss53 브랜치를 master에 merge시키면 fast-forward 방식으로 merge될 것이다.
iss53은 master 브랜치의 모든 내용을 기반으로 추가적인 작업만 진행된 상태이기 때문에 별다른 merge 과정 없이 그저 브랜치 포인터만 이동시켜주면 된다.
git checkout master
를 통해 master 브랜치로 이동 후
git merge iss53
을 해보면
합쳐지면서 Fast-forward
라는 메세지가 출력되는 것을 볼 수 있다.
두 브랜치의 공통 조상을 찾아서 새로운 commit을 만드는 방식
Master 브랜치가 c2 commit을 가리키고 있는 상태에서
Master브랜치 기반으로 Iss53 브랜치를 생성 후 열심히 작업해서 현재는 C5를 가리키고 있다고 하자!
그 와중에 Master에서도 하나의 commit이 만들어져서 C4로 이동되었다.
이 상황에서 Master 브랜치에 Iss53을 merge하려고 하면,아까 fast-forward와는 상황이 다르다.
Iss53이 가리키는 commit의 조상이 Master와 다르기 때문에 fast-forward 방식으로는 merge할 수 없다.
이 때 merge 시키는 방법은 각 브랜치가 가리키는 commit(C4, C5)과 그 두 개의 공통 조상이 되는 commit(C2)을 찾아서 합치는 방식으로 merge해야한다.
그래서 3-way-merge라고 하는 것이다.
3-way-merge로 merge를 시도했는데 같은 부분에 다른 내용이 있을 경우 merge conflict가 발생한다.
<<<<<<< HEAD
내가 작업한 내용
======= // 충돌난 코드 구분자
merge시키려고 한 브랜치의 내용
>>>>>> dafdf29df8adf0 // merge시키려고 한 브랜치의 체크섬
위의 표시 내용을 보고 어떤 코드로 합칠건지 선택해서 충돌된 것을 수정해주면 된다.
*바이너리 파일의 conflict 해결법
텍스트 파일이 아닌 이미지 파일 같은 경우에도 충돌이 발생할 수 있는데,
이때 git checkout
을 사용해 해결할 수 있다.
warning: Cannot merge binary files: myImage.jpg (HEAD vs. adfelkb02343sdfa53d6sf42eg6)
위의 경고문구가 떴을 때
git checkout HEAD myImage.jpg
git add myImage.jpg
git commit -m "내가 작업한 이미지 파일 사용"
git checkout adfelkb0 myImage.jpg
git add myImage.jpg
git commit -m "원격지에서 받아온 이미지 파일 사용"
git checkout HEAD myImage.jpg // 내 작업 파일로 이동
git mv myImage.jpg originalMyImage.jpg // 내 파일 이름 변경
git checkout adfelkb0 myImage.jpg // 원격지 작업 파일로 이동
git mv myImage.jpg remoteMyImage.jpg // 원격지 파일 이름 변경
git rm myImage.jpg // tracked된 파일 삭제
git add originalMyImage.jpg
git add remoteMyImage.jpg
git commit -m "두 개의 이미지 모두 사용"
git merge <branch> // 현재 브랜치에 대상 브랜치 병합
git merge --squash <branch> // 대상 브랜치를 병합시킬 때 commit 이력을 하나로 만들어서 합침
git merge --no-ff <branch> // fast-forward로 병합될 코드라도 merge commit을 만들어 병합시킴
base를 다른 브랜치의 commit으로 변경 후 병합
Rebase도 브랜치를 병합해주는 또 다른 방법이라고 할 수 있다.
merge를 하면 base가 바뀌지는 않지만, rebase는 단어 그대로 base를 바꿔서 병합시켜준다.
다시 말해서, rebase는 병합하려는 브랜치의 제일 마지막 commit을 base로 해서 병합시키는 것이다.
master 브랜치로부터 feature 브랜치를 생성해서 진행 후 rebase하려는 상황을 생각해보자!
git checkout feature
git rebase master
git checkout feature
일단 먼저 feature 브랜치로 이동한다.
git rebase master
feature 브랜치의 base를 master 브랜치로 해서 병합시킨다. (이게 바로 rebase!)
이 명령어를 실행시키면 다음과 같이 진행된다.
HEAD 포인터를 master로 옮긴다.(rebase 대상의 마지막 commit 포인터 = master브랜치 포인터)
임시 저장해둔 변경사항을 차례대로 적용시킨다.
feature 브랜치가 F2'를 가리키도록 한다.
git checkout master
git merge feature
feature 브랜치를 master로 병합시켜 마무리 한다.
Merge, Rebase 모두 브랜치를 병합시키는 것은 같지만, commit history가 달라진다.
Merge는 commit ID가 보존되고, Rebase는 새로운 Commit이 생성되어 Commit Id가 변경된다.
Merge의 경우 commit 내역에 merge commit이 남게 되므로 브랜치가 생성되는 것부터 병합되는 것까지의
모든 작업 내용을 그대로 기록해두고 볼 수 있다.
Rebase의 경우는 병합할 때 merge commit이 남지 않으므로 원래부터 하나의 브랜치였던 것처럼
깔끔한 commit history를 만들 수 있다.
어떤 방법을 사용해 병합하는지는 팀이나 프로젝트의 성격에 달라질 수 있다.
하지만 이미 원격 저장소에 push된 커밋은 Rebase를 하지 않는 것이 일반적이라고 한다.
로컬 브랜치에서 작업할 때는 히스토리 정리를 하기 위해 Rebase를 사용할 수도 있지만,
리모트 등 어딘가에 push로 내보낸 commit에 대해서는 rebase를 하지 말아야한다고 공식에서 말하고 있다!
참고
- git 공식 사이트
- https://velog.io/@godori/Git-Rebase
- https://ssabi.tistory.com/54
- https://antilog.tistory.com/17?category=734368
- https://www.zehye.kr/git/2019/11/22/11git_merge_conflict/
- https://www.tuwlab.com/ece/22218
- https://dongminyoon.tistory.com/9
정말 깔끔하게 정리 잘하셨네요!!
공부하는데 많은 도움이 되었습니다^^