왜 git이 인접한 줄을 충돌없이 병합하지 않습니까?


25

최근에 git에서 두 개의 브랜치를 병합 할 때 인접한 두 줄 에 변경 사항이 있으면 git 이이 충돌을 선언 한다는 것을 알았습니다 . 예를 들어, 파일 test.txt에이 내용이있는 경우 :

Line 1: A
Line 2: B
Line 3: C
Line 4: D

그리고 지점에서 master우리는 이것을

Line 1: A
Line 2: B1
Line 3: C
Line 4: D

지점에서 testing우리는 이것을

Line 1: A
Line 2: B
Line 3: C1
Line 4: D

다음 병합을 시도 testing으로 master, 자식은 병합 충돌을 선언합니다. 필자의 순진한 기대는 합병이 충돌없이 발생하고 이것을 산출 할 것이라는 것이었다.

Line 1: A
Line 2: B1
Line 3: C1
Line 4: D

git이 이런 식으로 병합되지 않는 좋은 이유가 있다고 확신합니다. 누군가이 이유를 설명 할 수 있습니까?


저도 지난주에 이걸 눈치 notice습니다. 아마도 우리는 같은 튜토리얼을하고 있었을 것입니다.
detly

5
git의 병합 능력은 실제로 매우 열악합니다. IMO
James

@ 제임스 인내 알고리즘을 사용해 보셨습니까? 특히 덩어리가 분할되는 위치를 처리 할 때 (예 : 두 기능 대신 하나의 기능 바디를 잡는 경우) 더 나은 결과를 얻을 수 있습니다. git가 마음에 들지 않으면 직접 사용할 수도 있습니다 ( 예 : blog.wuwon.id.au/2010/09/… 참조 ).
deterb

1
근본 원인은 git이 병합을 특수 도구로 분해하는 대신 자체 병합을 시도하기 때문입니다. 유닉스 철학이 아닙니다. 소스 파일의 경우 실제로 언어 문법을 사용하여 차이점을 안정적으로 결정할 수 있습니다.
MSalters

공통 컨텍스트는 A와 D 뿐이므로 A / C1 / B1 / D가 올바른 병합이 아닌 이유는 무엇입니까?
이즈 카타

답변:


13

이 코드 스 니펫이 있다고 가정

x=0
x+=1 if foo
x+=1 if bar
return x

한 지점에서 이것으로 변경되었습니다

x=0
x+=1 if foo && xyzzy
x+=1 if bar
return x

그리고 다른 지점에서

x=0
x+=1 if foo
x+=1 if bar && xyzzy
return x

그런 다음 git이 이것을 병합하지 않기를 원합니다.

x=0
x+=1 if foo && xyzzy
x+=1 if bar && xyzzy
return x

날 놀라게하지 않고

이러한 문제를 피하기 위해 git은 일반적으로 근처 라인에 닿은 변경 사항을 자동으로 병합하지 않습니다. 프로그램 논리가 깨 졌는지 여부를 확인할 수 있습니다.

이 예는 사소한 것이지만 거대한 가지를 병합 할 때 비슷한 "논리적"충돌의 위험이 훨씬 더 큽니다. 때로는 문맥이 현재보다 더 커지기를 바랍니다.


5
그러나 그것은 그 둘과 아무런 관련이 없습니다. 단순히 그 둘 사이에 변경되지 않는 줄을 추가하고 갑자기 문제없이 그것들을 병합합니다.
Darkhogg

예,이 답변을 얻지 못했습니다. 모든 자동 병합을 피하기 위해 동일한 논리를 사용할 수 있습니다.
Mehrdad

보안과 유용성 사이에 선이 있어야합니다. 자동 병합은 대답에 표시하려고하는 것처럼 프로그램 흐름을 손상시킬 위험이 있지만 git이 병합을 거부하면 쓸모가 없게됩니다. git의 제작자는 상황에 따라 방금 결정했으며, 대부분의 "위험한"사례를 포착 할 것입니다. 변경되지 않은 행을 추가하면 (Darkhogg에서 알 수 있듯이) 바보가 병합을 수행하는 것이 안전하다고 생각합니다.
Arsen7

11

이 자식 전용 동작입니까?

동료와 토론 한 후 방금 시도했지만 SVN은 문제없이 처리합니다 . 두 줄을 수정했습니다.

바자, darcs, 자식 및 수은에 대해 여러 VCS의 병합 기능이 여기에서 테스트됩니다 : https://github.com/mndrix/merge-this

darcs만이 "인접한 줄"사례를 성공적으로 병합 한 것 같습니다.

파일에 인접한 변경 사항을 적용하는 것은 어려운 문제가 아닙니다. 이 행동은 의도적으로 선택되었다고 생각합니다.

인접한 줄을 수정하면 충돌이 발생한다고 누가 결정합니까?

나는 이것이 당신이 그것을 보도록 강요하는 것이라고 생각 합니다 .

int max = MAX_ITEMS;
for(unsigned int i = 0; i < max; i++)
    do_stuff(i);

마스터의 수정 번호 1 :

int max = MAX_ITEMS/2; // Do stuff only on the first half
for(unsigned int i = 0; i < max; i++)
    do_stuff(i);

지점에서 병합 된 수정 번호 2 :

int max = MAX_ITEMS;
for(unsigned int i = 0; i < max/2; i++) // max/2: only on 1st half
    do_stuff(i);

병합 후에는 원하지 않습니다.

int max = MAX_ITEMS/2; // Do stuff only on the first half
for(unsigned int i = 0; i < max/2; i++) // max/2: only on 1st half
    do_stuff(i);

이 동작을 기능으로보기

자식 병합 동작을 유리하게 설정할 수 있습니다. 두 줄의 일관성을 유지해야하지만 컴파일 시간에 (테스트 초기 또는 기타) 감지 할 수없는 경우 두 줄을 결합 할 수 있습니다.

이것을 다시 쓰십시오 ... :

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i);
    // Need to do something else
    do_something_else(r);

...이에:

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i);
    do_something_else(r); // Need to do something else

따라서 Modif 1을 병합하면 ... :

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i)/2; // we need only the half
    do_something_else(r); // Need to do something else

... Modif 2와 함께 ... :

for(unsigned int i = 0; i < max; i++)
    r = do_stuff(i);
    if(r < 0) // do_stuff can return an error
        handle_error(r);
    do_something_else(r/2); // Need to do something else

... git은 충돌을 일으키고 그것을 보도록 강요 할 것입니다.


2
나는 당신의 대답이 완벽하게 합리적이라고 생각하지만, 코드와 소스 검사 간의 소스 제어 사이의 복잡한 구현 정의 상호 작용은 dailywtf.com에 대한 빠른 길입니다. 어쨌든 언어 파서없이 코드를 맹목적으로 병합하는 것은 어쨌든 최선의 노력이며, git이 필요하지 않은 것을 자동으로 병합하고 컴파일조차하지 않는 코드를 생성하는 몇 가지 사례가 있습니다.
Wug

5

나는 대부분 추측하고 있지만, 2 행이 3 행 변경의 컨텍스트로 사용되는 것과 관련이 있다고 생각합니다.

Git은 "C"가있는 다른 줄이있을 수 있기 때문에 "C가있는 줄이 C1을 가진 줄이되었다"고 말할 수 없으므로 "C가있는 줄, 즉 파일이 시작된 직후, A와 B가있는 줄은 이제 C1 "입니다.

"B가있는 행"이 더 이상 존재하지 않으면 일부 컨텍스트가 손실되고 git은 새 행이 어디로 가야하는지 대략적으로 알 수 있습니다.


5
그것은 또한 C가 B에 의존 할 가능성이 매우 높기 때문에 자식이 "어떻게 해야할지"알더라도 순진한 병합은
번거로울

Git은 "알고있는 것"만 믿는다. 힘내는 잘못된 개념의 묘소로 곧게 되려고 노력하고 있습니다!
user3833732

2

여기에있는 다른 대답은 모두 맞았지만 나에게 이것은 항상 불필요한 제한처럼 보였습니다.

다른 사람들이 말했듯이,이 경우 Git이 경고없이 라인을 병합하지 않기를 원할 것입니다.

그러나 나는 경고를받은 후에도 자동으로 수행 할 수있는 옵션을 원했습니다. 그래서 인접한 (또는 개별) 행의 충돌을 대화식으로 병합 할 수있는 사용자 지정 git merge 드라이버를 작성했습니다.

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

사람들이 종종 같은 파일을 작업하고 많은 코드를 리팩토링하는 프로젝트를 관리하므로 시간을 크게 절약 할 수 있습니다.

이 스크립트는 GPLv3 + 라이센스에 따라 GitHub에서 사용할 수 있습니다. 아마도 당신은 그것이 유용하다는 것을 알게 될 것입니다 :

https://github.com/paulaltin/git-subline-merge


4
왜 이것이 다운 다운되었는지 설명해 주시겠습니까? 나는 여기에 상당히 새롭기 때문에 내가 잘못한 일이 있다면 그것이 무엇인지 알고 싶습니다. 그래서 나중에 그것을 피할 수 있습니다. 내 게시물이 요청 된 질문에 정확하게 답변하지는 않지만 여전히 관련이 있으며 여기에 오는 대부분의 사람들은 왜 git이 왜 그런지뿐만 아니라 그들이 할 수있는 일을 알고 싶어한다고 생각합니다 ( Google 검색에서이 질문에 처음 도달했습니다.
deltacrux

나는 그것을 아직 시도하지 않았지만 이것을 자동화하는 방법을 찾고 있었고 여기에서 그것을 발견하게되어 기뻤습니다. 감사합니다 :) 당신은 굉장합니다.
Mehrdad

1
문제 없어! 도움이 되길 바랍니다. 문제가 발생하거나 개선을위한 제안이 있으면 Github에 대한 의견을 남겨주세요. 감사!
deltacrux
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.