Git 7. 병합과 충돌

6403 단어 gitgit

1. 병합

분리된 브랜치를 한 브랜치로 합치는 작업

1) 수동 병합

  • 양쪽 파일을 일일이 비교하여 바뀐 점을 찾아서 적응해야 해서 매우 복잡하다.

2) 자동 병합

  • 원본을 기준으로 두 파일의 변경 이력을 비교하고 변경된 파일 내용이 발견되면 자동으로 수정된 코드 내용을 병합한다.
  • 브랜치를 기준으로 실행하므로 브랜치 안에서 수정 작업을 해야 한다.

2. Fast-Forward 병합 (빨리 감기)

  • 주로 혼자 개발할 때 사용 => 변경 사항이 순차적으로 진행되기 때문에!

  • 순차적 커밋에 맞추어 병합을 처리하는 방법

  • 작업한 브랜치의 시작 커밋을 원본 브랜치 이후의 커밋으로 가리킨다. (단순히 커밋 위치를 최신으로 옮기는 것과 비슷)

  • 병합 위치 : merge 명령어는 현재 브랜치를 기준으로 다른 브랜치의 모든 커밋을 병합하기 때문에 기준이 되는 브랜치로 이동해 병합해야 한다.

$ git merge 브랜치이름

// 예시
$ git checkout master

$ git merge feature // feature 브랜치 병합
Updating f121324...332dafd
Fast-forward // 병합 방식 표시
  index.html | 6  ++++++
  1 file changed, 6 insertions(+)

3. 3-way 병합

여러 개발자와 협업으로 작업하는 경우 사용

  • 공통 조상 커밋 : Fast-Forward 방식과 달리 각각 갈라진 브랜치를 병합하기 위해서 분할 기준인 공통 커밋을 찾아야 한다. 공통 조상 커밋을 포함하는 브랜치, 새로운 두 브랜치 이렇게 3개를 하나로 병합해야 한다.
  • 깃은 두 브랜치에서 공통 조상 커밋을 자동으로 찾아 주며, 공통 조상 커밋을 기준으로 브랜치를 병합한다. 그리고, 병합을 성공적으로 완료한 후에는 새로운 커밋을 추가로 하나 생성한다. 이때 새로 생성된 커밋을 병합 커밋이라고 한다. 병합 커밋은 부모 커밋이 2개라는 특징이 있다.
    // 예시
    
    // 현재 기준 브랜치 -> master
    $ git merge hotfix // 기준 브랜치에 hotfix 병합
    Auto-merging index.html
    Merge made ny the 'recursive' strategy. // 3-way 병합
     index.html | 3 +++
     1 file changed, 3 insertions(+)
    ``

- 병합 메시지

-> 깃은 두 브랜치를 병합 한 후에 새로운 커밋을 하면서 동시에 메시지를 자동 작성하는데, 그 외에 직접 커밋 메시지를 작성할 수 있다.

$ git merge 브랜치이름 --edit
$ git merge 브랜치이름 -e

4. 브랜치 삭제

지속적으로 통합과 개발을 해야 하는 브랜치는 병합 후에도 남겨두지만 필요 없는 브랜치는 삭제한다.

- 깃 플로(git flow)

-> 브랜치 관리 기법으로 기본적으로 master, feature, develop, release, hotfix 브랜치가 있으며 develop 브랜치는 병합 후에도 삭제하지 않고 계속 유지한다. 이처럼 오랫동안 유지하는 브랜치를 long-running 브랜치라고 한다.

- 병합 후 삭제

$ git branch -d 브랜치이름 // 병합을 완료한 브랜치만 삭제할 수 있다.
$ git branch -D 브랜치이름 // 병합을 완료하지 않은 브랜치 강제 삭제

5. 충돌

- 충돌이 생기는 상황

  • 대부분 같은 위치의 코드를 동시에 수정할 때 발생한다.
  • 이때 깃은 충돌 오류라고 알려주고, 개발자에게 직접 수정하여 충돌을 해결하라고 요청한다.
// 예시

// 현재 기준 브랜치 master
$ git merge footer // 병합 실행
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result. // 충돌 발생

* 병합 충돌이 발생하면 자동으로 커밋이 생기지 않는다.

- 충돌 상황 해결 과정

1) 깃 상태 확인

$ git status // 상태 확인
On branch master
You have unmerged paths. // 충돌 사항
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   index.html
no changes added to commit (use "git add" and/or "git commit -a")

2) 충돌 해결

  • 충돌 사항 수정시에는 깃에서 표시한 충돌 기호도 함께 삭제해야 한다.
  $ git add index.html // 스테이지에 등록
$ git commit -m "resolve complicit" // 병합 커밋 직접 작성
[master 34332d] resolve complicit

* 방금 실행한 병합 취소 할 때

  $ git merge --abort // 병합 명령 취소

* 충돌한 파일들의 집합 확인 할 때

$ git ls-files -u

6. 브랜치 병합 여부 확인

$ git branch --merged // 브랜치 목록
  feature
  footer
* master
 
$ git branch --no-merged // 병합하지 않은 브랜치 목록

7. 리베이스

커밋 순서를 재배열하는 병합, 커밋의 트리 구조를 재배열한다. (실무에서 더 선호)

  • 베이스 : 새로운 브랜치가 파생되는 커밋 (병합의 공통 조상 커밋)
  • 베이스 변경
    -> 커밋의 진행 모습을 단순화 하기 위해 베이스를 변경한다. 브랜치가 많아지면 커밋을 관리하고 파악하기 어렵다. 리베이스는 코드의 베이스 분기점을 변경하여 마치 하나의 기찻길처럼 만들어 커밋의 진행사항을 쉽게 파악할 수 있다.


🔼 베이스를 커밋6으로 변경하고 모든 브랜치의 커밋들을 커밋6 이후로 재정렬


🔼 커밋 재배치

- 리베이스 명령어

$ git rebase 브랜치

- 리베이스 병합 과정

리베이스는 두 브랜치를 서로 비교하지 않고 순차적으로 커밋 병합을 시도한다. 리베이스는 병합 커밋이 없다.

1) 리베이스 병합 : 리베이스 하면서 커밋 위치가 변경될 때 해시 값 중복 방지를 위해 새로운 커밋 해시를 생성한다.

$ git checkout description // 리베이스 브랜치
Switched to branch 'description'

$ git rebase master // master 브랜치를 리베이스
Successfully rebased and updated refs/heads/description.

2) 병합 브랜치의 HEAD 맞추기 (= 리베이스된 브랜치를 병합해야 한다.)

$ git checkout master // 브랜치 이동
$ git merge description // HEAD 포인터 조정(병합)
Updating 1231dfa...232dfd
Fast-forward // 병합 방식 확인
 index.html | 1 +
 1 file changed, 1 insertion(+)

$ git branch -d description // 필요 없는 브랜치 삭제
Deleted branch description (was 32d3rf).

- 충돌과 해결

병합 충돌과 같은 방식으로 해결
충돌 수정 후에 --continue 명령어 사용

$ git add index.html // 등록
$ git rebase --continue // 계속 진행
Successfully rebased and updated refs/heads/menu. // 충돌 해결

$ git checkout master // 브랜치 이동
Switched to branch 'master'

$ git merge menu // 병합, HEAD 일치
Updating df24324..a232dd
Fast-forward
  index.html | 5 +++--
  1 file changed, 3 insertions(+), 2 deletions(-)

$ git branch -d menu // 브랜치 삭제
Deleted branch menu (was 1dafedf).

- 리베이스 병합 후 여러 커밋을 한 커밋으로 묶을 수 있다. 이때 합친 커밋에는 새 해시 값이 부여된다.

$ git rebase -i HEAD~3 // 커밋 묶기
Successfully rebased and updated refs/heads/master.

✅ 리베이스할 때 저장소를 외부에 공개했다면 공개된 순간부터 커밋은 리베이스를 사용하지 않는 것이 원칙이다.
-> 외부로 코드를 푸시하거나 공개하기 전에 로컬에서만 실행하는 것이 좋다. 외부에 공개된 커밋을 링베이스하면 커밋 위치와 해시 값이 변경되어 너무 혼란스럽기 때문에

좋은 웹페이지 즐겨찾기