예를 들어 git 및 diff3에서 중복된 여러 줄 그룹을 바꾸는 방법

예를 들어 git 및 diff3에서 중복된 여러 줄 그룹을 바꾸는 방법

레거시 코드를 리베이스하고 있는데 스크립트(보통 코드 포맷터)로 인해 발생하는 많은 충돌을 발견했습니다. 변경 사항은 간단하고 예측 가능하므로 스크립트를 쉽게 다시 실행하여 코드에 변경 사항을 적용할 수 있습니다. 그러면 일반적으로 git의 diff 마커로 둘러싸인 3개의 동일한 "스니펫"이 남게 됩니다.

세 개의 일치하는 조각과 차이점 마커를 찾아 단일 조각으로 변환하는 스크립트를 어떻게 작성합니까?

예:

git rebase다음을 생성합니다.

<<<<<<< HEAD
    ACA
    BCB
||||||| parent of 0cfd85b8e3... Beautify.
    AAA
    BBB
=======
    AAC
    BBC
>>>>>>> 0cfd85b8e3... Beautify.

포맷터를 다시 실행하면 다음과 같은 결과가 나타납니다.

<<<<<<< HEAD
    ACC
    BCC
||||||| parent of 0cfd85b8e3... Beautify.
    ACC
    BCC
=======
    ACC
    BCC
>>>>>>> 0cfd85b8e3... Beautify.

나는 그것을 다음과 같이 변환하고 싶습니다 :

    ACC
    BCC

나는 grep(새 줄로 어려움을 겪음)과 pcregrep(역참조/캡처 그룹으로 어려움을 겪었음)을 포함하여 아주 많은 것을 시도했습니다. 어떤 아이디어가 있나요?

답변1

이 문제에 대해 상태 저장 awk 프로그램을 사용하면 다음과 같이 명확하게 알 수 있습니다.

awk '/^<<<<<<</ { state = 1; next }
     /^=======/ { state = 2; next }
     /^>>>>>>>/ { state = 0; next }
     state == 0 || state == 2' data
foo
prolog
    AAC
    BBC
epilog
bar

여기에는 다음이 data포함됩니다.

foo
prolog
<<<<<<< HEAD
    ACA
    BCB
||||||| parent of 0cfd85b8e3... Beautify.
    AAA
    BBB
=======
    AAC
    BBC
>>>>>>> 0cfd85b8e3... Beautify.
epilog
bar

state == 0아직 초기화되지 않은 경우 true이므로 처음에는 상태 0에 있습니다 . state우리는 그것을 볼 때 상태 1로 전환하고 <<<<<<, 그것을 볼 때 상태 2로 전환 =======한 다음, 종료 마커를 볼 때 상태 0으로 다시 전환합니다 >>>>>>>. 매우 간단합니다.

초기 상태 0(충돌 토큰 외부) 또는 상태 2(충돌 토큰의 마지막 부분)에 있는 경우에만 줄을 인쇄합니다.

모든 경우에 명령은 next실패 동작이 발생하지 않도록 보장합니다. 마지막 사례만 아무것도 인쇄하므로 처음 세 사례는 아무 것도 인쇄하지 않고 충돌 표시를 식별하고 상태를 변경하는 것 외에는 아무것도 수행하지 않는다는 것을 알고 있습니다. 따라서 어떤 상태에 있든 충돌 플래그는 인쇄되지 않습니다. 상태 2에서 다시 상태 0으로 돌아가면 실수로 =======or >>>>>>>줄이 인쇄되지 않습니다.

첫 번째 작업에서는 인쇄되지 않는 상태 1로 전환되므로 꼭 필요한 것은 아니지만 next포함하는 것이 일관성을 유지하는 데 좋습니다. 또한 효율성: 충돌 마커는 상호 배타적입니다. =======이미 감지한 경우 테스트해야 합니다 <<<<<<<.

답변2

TxRLisp의 awk매크로는 전통적인 Awk보다 더 강력한 범위 표현을 가지고 있기 때문에 상태 변수 없이 이 문제를 해결할 수 있습니다.

  • 범위 표현식은 다른 표현식과 결합될 수 있습니다. 예를 들어, 범위 표현식은 다른 범위의 시작이나 끝일 수 있습니다.

  • awk범위 표현식은 주절 조건뿐만 아니라 매크로의 어느 곳에서나 사용할 수 있습니다 .

  • 범위 표현식이 들어옵니다.아홉 가지 맛시작과 끝에서 레코드를 제외하거나 더 많은 레코드를 포함하도록 범위를 확장하는 데 사용됩니다.

dataAwk의 답변과 동일한 파일을 사용합니다 .

$ txr awk.tl data
foo
prolog
    AAC
    BBC
epilog
bar

코드는 다음 위치에 있습니다 awk.tl.

(awk
  (:let (beg (f^ #/<<<<<<</))
        (mid (f^ #/=======/))
        (end (f^ #/>>>>>>>/)))
  ((-rng- mid end))            ; print lines between ===...>>>, exclusive
  ((not (rng beg end))))       ; print lines outside <<<...>>>

분해:

먼저(:let ...)양식 범위 내에서 일부 어휘 변수를 바인딩하는 절입니다 awk. 단일 인수 익명 함수인 변수 beg, mid및 를 소개합니다. end예를 들어(f^ /abc/)abc문자열을 가져 와서 문자열의 시작 부분에 고정된 정규식과 일치하는 함수를 생성합니다 . diff3 충돌 마커의 시작, 중간, 끝을 일치시키는 함수를 정의하고 있습니다.

뒷면에는 :let두 개의 절이 있습니다 (condition action). 절도 없으므로 action기본 작업은 인쇄입니다. 이는 Awk의 한 형태이므로 동일한 규칙이 적용됩니다.

범위는 태그에서 까지의 (-rng- mid end)레코드 와 일치합니다. 이 변형은 범위의 내부 레코드에 대해서만 true를 생성하며 첫 번째 및 마지막 레코드에 대해서는 false를 생성합니다. 이것이 바로 우리가 원하는 것입니다. 우리는 이 줄을 포함하지 않고 와 사이의 모든 줄을 인쇄하고 싶습니다. awk에는 범위에서 끝점을 제외하는 기능이 없습니다.midend-rng-======>>>>>>>

두 번째 규칙의 조건은 입니다 (not (rng beg end)). 이 조건은 begto end범위 내에 있지 않은 레코드 , 즉 diff3 충돌 주석 내에 있지 않은 경우에 해당됩니다. 우리는 그것들을 모두 인쇄하고 싶습니다. awk에는 그러한 기능도 없습니다. 범위 표현식은 다른 연산자(예: !부정)와 결합할 수 없습니다.

TXR Lisp의 범위 기능으로 인해 awk이 솔루션에는 상태 변수가 필요하지 않으며 다음 레코드 처리를 계속하기 위해 암시적 루프에서 명시적으로 분기해야 하는 규칙이 없습니다.

관련 정보