vimdiff를 사용하여 git merge 충돌을 어떻게 해결합니까?


159

방금 git에서 내 마스터로 지점을 병합하고 Automatic merge failed; fix conflicts and then commit the result.지금 git mergetool은 이미지를 실행 하여 vimdiff를 열었습니다. vimdiff를 사용하는 방법을 모르겠습니다. 여기서 각 패널은 무엇을 의미하며 병합 충돌을 해결하려면 어떻게해야합니까?

여기에 이미지 설명을 입력하십시오


3
이 페이지를 참조 하십시오 . 이것이 "올바른"의 의미라면 코드의 현재 상태는 왼쪽 상단에 있습니다.
romainl

@romainl 나는 그것을 읽은 후에도 여전히 혼란 스럽습니다. 바로 가기는 무엇이며 주 분기로 사용할 파일을 어떻게 선택합니까?
Cool Guy Yo


참조 : this
skelliam

답변:


142

네 개의 버퍼는 모두 동일한 파일의 다른보기를 제공합니다. 왼쪽 상단 버퍼 (LOCAL)는 대상 분기에서 파일이 어떻게 보이는지 (병합 대상)입니다. 오른쪽 상단 버퍼 (REMOTE)는 소스 분기 (병합 대상)에서 파일이 어떻게 보이는지입니다. 미들 버퍼 (BASE)는이 둘의 공통 조상입니다 (왼쪽과 오른쪽 버전이 어떻게 다른지 비교할 수 있습니다).

나는 다음과 같은 점에서 착각 할 수 있습니다. 병합 충돌의 원인은 두 파일이 BASE 이후 파일의 동일한 부분을 변경 한 것입니다. LOCAL은 따옴표를 double에서 single로 변경했으며 REMOTE는 동일한 변경을 수행했지만 배경 값을 색상에서 URL로 변경했습니다. (LOCAL에 대한 모든 변경 사항이 REMOTE에도 있음을 알기에는 합병이 현명하지 않다고 생각합니다. LOCAL은 BASE 이후 REMOTE와 동일한 위치에서 변경 한 것을 알고 있습니다).

어쨌든 맨 아래 버퍼에는 실제로 편집 할 수있는 파일 (작업 디렉토리에있는 파일)이 들어 있습니다. 원하는대로 변경할 수 있습니다.vim자동 병합에서 처리 할 수없는 영역 인 각 상단보기와 어떻게 다른지 보여줍니다. REMOTE 변경을 원하지 않으면 LOCAL에서 변경 사항을 가져옵니다. 로컬 변경 사항을 선호하는 경우 REMOTE에서 변경 사항을 가져 오십시오. REMOTE와 LOCAL이 모두 잘못되었다고 생각되면 BASE에서 당기십시오. 더 좋은 아이디어가 있다면 완전히 다른 것을하십시오! 결국 여기에서 변경 한 내용은 실제로 커밋 될 내용입니다.


4
빠른 질문 어떻게 vim에 저장합니까?
Cool Guy Yo

6
:x또는 :w( :x종료) 플러스 '반환'.
Jonathan Leffler

4
Anders : 사용 방법에 익숙하지 않은 경우 사용할 수있는 다른 병합 도구가 있습니다 vim.
chepner

3
@AndersKitson은 Mac OS X를 사용하므로 FileMerge가 완벽하고 무료이며 XCode와 함께 제공됩니다.
romainl

8
왜 공감해야합니까? 실제로 잘못된 것이 있으면 수정하거나 적어도 지적하십시오.
chepner

91

@ chepner의 대답은 훌륭합니다. 질문의 "병합 충돌을 해결하려면 어떻게해야합니까?"에 대한 세부 정보를 추가하고 싶습니다. 이 경우 vimdiff를 실제로 사용하는 방법을 살펴보면 아래에 나와 있습니다.


먼저, "abort everything"옵션을 해결하려면 – "vimdiff"를 사용하지 않고 병합을 중단하려면을 누른 Esc다음을 입력 하고을 누르 :qa!십시오 Enter. (또한 참조 나는 Vim 편집기를 종료하려면 어떻게? ). Git은 병합이 완료되었는지 묻습니다 n.


vimdiff를 사용하려는 경우 유용한 바로 가기가 있습니다. 이것은 Vim의 기본 사항을 알고 있다고 가정합니다 (탐색 및 삽입 / 정상 모드).

  • 하단 버퍼로 이동 (병합 결과) : Ctrl-W j
  • 와 다음 DIFF로 이동 j/ k; 또는 더 나은 방법을 사용 ] c하여 [ c각각 다음 및 이전 diff로 이동하십시오.
  • 사용하다 z o더 많은 내용을 보려면 접을 때 하여여십시오
  • @chepner의 답변에 따라 각 diff에 대해 로컬, 원격 또는 기본 버전에서 코드를 가져 오거나 적절하게 수정하고 다시 실행할 수 있습니다
    • 로컬 버전에서 가져 오려면 :diffget LO
    • 원격에서 : :diffget RE
    • 기초에서 : :diffget BA
    • 또는 코드를 직접 편집하려면 먼저 로컬 / 원격 /베이스에서 버전을 가져온 다음 삽입 모드로 이동하여 나머지를 편집하십시오.
  • 완료되면 병합 결과를 저장하고 모든 창을 종료하십시오 :wqa
  • 일반적으로 git은 병합이 이루어 졌음을 감지하고 병합 커밋을 만듭니다.

복사 붙여 넣기 또는 사용자 정의 바로 가기없이 로컬 및 원격 충돌 덩어리를 모두 추가 할 수없는 것 같습니다 : /vi/10534/is-there-a-way-to-take-both- add add는 일반적인 충돌 유형이므로 부끄러운 when-using-vim-as-merge-tool 입니다.

vimdiff가 시작할 때마다 Enter를 누르라고 요구하지 않도록하려면 다음에 추가하십시오 .vimrc.

set shortmess=Ot

/vi/771/how-can-i-suppress-the-press-enter-prompt-when-opening-files-in-diff-mode 에서 언급했듯이

인터넷에서 다른 vimdiff 바로 가기를 검색 할 수 있습니다. 나는 이것이 유용한 것을 발견했다 : https://gist.github.com/hyamamoto/7783966


10
이것은 x1000 번 상향 조정되고 더 나은 답변으로 받아 들여 져야합니다.
안드레이 포트노이

다음 충돌로 빠르게 넘어가려면 ===을 검색하십시오. "/ ==="을 입력합니다
APIT 존 이스마일

를 사용하여 둘 이상의 일치 항목을 찾은 경우이 게시물 ( stackoverflow.com/questions/51520705/… )을 참조하십시오 :diffget.
제이슨

7

vimdiff를 대체하는 최고의 mergetool

이것은 뺨의 혀이지만, vimdiff를 시도한 후에 비머로 수렴하게되었습니다.

병합 충돌을 해결하려면 거의 항상 필요한 것은 다음과 같습니다.

  • 현지
  • 두 개의 차이점 :
    • 기본베이스 차이
    • 기본베이스 차이

그런 다음 두 가지를 합치려고합니다.

vimdiff가 화면에 BASE, LOCAL 및 REMOTE를 표시하는 동안 :

    +--------------------------------+
    | LOCAL  |     BASE     | REMOTE |
    +--------------------------------+
    |             MERGED             |
    +--------------------------------+

나는 왼쪽에서 오른쪽으로 왼쪽을 여러 번 보면서 내가 필요로하는 두 개의 차이점을 명확하게 보여주는 방법을 모르겠습니다.

또한 LOCAL과 REMOTE는 이미 git merge 충돌 마커에 표시되어 있으므로 다시 표시하는 도구에서 많이 얻지 못합니다.

따라서 대신 내가 놓친 diff를 실제로 보여주는 작은 "difftool"을 만들었습니다.

~ / bin / cirosantilli- 병합 도구

#!/usr/bin/env bash
BASE="$1"
LOCAL="$2"
REMOTE="$3"
diff --color -u "$BASE" "$LOCAL"
diff --color -u "$BASE" "$REMOTE"
exit 1

GitHub의 상류 .

그리고 다음과 같이 설치하십시오 :

git config --global mergetool.cirosantilli-mergetool.cmd 'cirosantilli-mergetool $BASE $LOCAL $REMOTE'
git config --global mergetool.cirosantilli-mergetool.trustExitCode true
# If you want this to become your default mergetool.
#git config --global merge.tool 'cirosantilli-mergetool'

이제 할 때 :

git mergetool -t cirosantilli-mergetool

그것은 터미널에서 내가 원하는 두 개의 diff를 보여줍니다.

--- ./src/dev/arm/RealView_BASE_15560.py        2019-12-27 13:46:41.967021591 +0000
+++ ./src/dev/arm/RealView_LOCAL_15560.py       2019-12-27 13:46:41.979021479 +0000
@@ -994,7 +994,7 @@                                                              

     def setupBootLoader(self, cur_sys, loc):
         if not cur_sys.boot_loader:                           
-            cur_sys.boot_loader = [ loc('boot_emm.arm64'), loc('boot_emm.arm') ]
+            cur_sys.boot_loader = [ loc('boot.arm64'), loc('boot.arm') ]
         cur_sys.atags_addr = 0x8000000                  
         cur_sys.load_offset = 0x80000000                    

@@ -1054,7 +1054,7 @@                                           
             ]                                                     

     def setupBootLoader(self, cur_sys, loc):
-        cur_sys.boot_loader = [ loc('boot_emm_v2.arm64') ]
+        cur_sys.boot_loader = [ loc('boot_v2.arm64') ]
         super(VExpress_GEM5_V2_Base,self).setupBootLoader(
                 cur_sys, loc)                             

--- ./src/dev/arm/RealView_BASE_15560.py        2019-12-27 13:46:41.967021591 +0000
+++ ./src/dev/arm/RealView_REMOTE_15560.py      2019-12-27 13:46:41.991021366 +0000
@@ -610,10 +610,10 @@           
     def attachIO(self, *args, **kwargs):              
         self._attach_io(self._off_chip_devices(), *args, **kwargs)

-    def setupBootLoader(self, cur_sys, loc):
-        cur_sys.boot_loader = loc('boot.arm') 
-        cur_sys.atags_addr = 0x100                           
-        cur_sys.load_offset = 0       
+    def setupBootLoader(self, cur_sys, boot_loader, atags_addr, load_offset):
+        cur_sys.boot_loader = boot_loader      
+        cur_sys.atags_addr = atags_addr     
+        cur_sys.load_offset = load_offset

터미널에서 덤프 된 두 개의 diff를 볼 수 있습니다.

  • RealView_BASE_15560.py vs RealView_LOCAL_15560.py
  • RealView_BASE_15560.py vs RealView_REMOTE_15560.py

차이가 크면 tmux superpowers로 검색해 보겠습니다 .

예, vimdiff가 제공하는 몇 가지 단축키를 잃어 버릴 수 있지만 일반적으로 충돌을 해결하려면 두 버전에서주의 깊게 복사 붙여 넣기가 필요합니다 .git 충돌 마커가있는 일반 vim 세션에서 잘 수행 할 수 있습니다.

파일 관찰 및 확산 vimdiff실행 중

앉아서 완벽한 설정을 자동화하기 전에 cirosantilli-mergetool 이것이 필요한 두 개의 diff를 얻기 위해 수행 한 작업입니다.

git mergetool실행 하는 동안 vimdiff,라는 파일에 충돌이 main.py발생하면 git은 다음과 같이 이름이 지정된 각 버전에 대해 파일을 생성합니다.

main_BASE_1367.py
main_LOCAL_1367.py
main_REMOTE_1367.py

같은 디렉토리에 main.py어디 1367에서 언급 한 바와 같이, 따라서 "임의"정수 자식 mergetool의 PID, 그리고 : 자식 병합 충돌에서 생성 된 백업, BASE, 로컬 및 원격 파일을 무엇입니까?

따라서 원하는 diff를 보려면 먼저로 생성 된 파일을 git status찾은 다음 새 터미널을 열고 관심있는 파일 쌍 사이에서 vimdiff를 수행하십시오.

vim -d main_BASE_1367.py main_LOCAL_1367.py
vim -d main_BASE_1367.py main_REMOTE_1367.py

와 함께 git mergetool이 정보를 하면 ALOT이 빠르게 진행되는 상황을 파악할 수 있습니다.

또한 mergetool이 실행되는 동안에도 파일을 열 수 있습니다.

vim main.py

더 큰 편집기 창에서 더 쉬울 것이라고 생각되면 직접 편집하십시오.

충돌을 병합하기 위해 직접 점프

]cvimdiff 내부의 다음 차이점으로 점프하는 동안 병합 충돌이 항상있는 것은 아닙니다.

이를 돕기 위해 나는 ~/.vimrc:

# Git Merge conflict
nnoremap <leader>gm /\v^\<\<\<\<\<\<\< \|\=\=\=\=\=\=\=$\|\>\>\>\>\>\>\> /<cr>

직접 충돌을 찾습니다.

git imerge

아마 최선의 선택은 vimdiff를 사용하여 포기하고 일반 정력에 의존하는 것입니다 + 자식 imerge 에 언급 된 : 어떻게 망할 놈의 원인 충돌을 범하는 찾을 수 있습니까? vimdiff의 학습 곡선은 성가 시며 가장 필요한 기능을 수행하지 않기 때문입니다.


1
공감. 나는 9 년 전에 stackoverflow.com/a/3052118/6309 에서 언급했다고 생각 합니다. (답변의 마지막 부분 참조)
VonC 2016 년

@VonC 예, 당신이 이겼다고 생각합니다! XD
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.