git diff에서 출력을 읽는 방법은 무엇입니까?


270

의 매뉴얼 페이지 git-diff는 다소 길며 초보자에게는 필요하지 않은 많은 경우를 설명합니다. 예를 들면 다음과 같습니다.

git diff origin/master

1
다른 텍스트 편집기를 사용하여 줄 번호에 대한 @ ... @ 범위 표기법이 분명해졌습니다.
poseid

어떤 텍스트 편집기?
Jus12

답변:


488

git history에서 고급 diff 예제를 살펴 봅시다 ( git.git repository의 commit 1088261f에서 ).

diff --git a/builtin-http-fetch.c b/http-fetch.c
similarity index 95%
rename from builtin-http-fetch.c
rename to http-fetch.c
index f3e63d7..e8f44ba 100644
--- a/builtin-http-fetch.c
+++ b/http-fetch.c
@@ -1,8 +1,9 @@
 #include "cache.h"
 #include "walker.h"

-int cmd_http_fetch(int argc, const char **argv, const char *prefix)
+int main(int argc, const char **argv)
 {
+       const char *prefix;
        struct walker *walker;
        int commits_on_stdin = 0;
        int commits;
@@ -18,6 +19,8 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix)
        int get_verbosely = 0;
        int get_recover = 0;

+       prefix = setup_git_directory();
+
        git_config(git_default_config, NULL);

        while (arg < argc && argv[arg][0] == '-') {

이 패치를 한 줄씩 분석 할 수 있습니다.

  • 첫 줄

    diff --git a / builtin-http-fetch.cb / http-fetch.c
    형식의 "git diff"헤더입니다 diff --git a/file1 b/file2. a/b/이름 변경 / 복사가 (우리의 경우처럼) 참여하지 않는 파일 이름은 동일합니다. 는 --git그 DIFF는 "자식"은 diff 형식으로 의미하는 것입니다.

  • 다음은 하나 이상의 확장 된 헤더 행입니다. 처음 세

    유사도 95 %
    builtin-http-fetch.c에서 이름을 바꿉니다.
    http-fetch.c로 이름을 바꿉니다.
    파일을 이름을 바꿀 것을 우리에게 builtin-http-fetch.chttp-fetch.c그 두 개의 파일 (이 이름 변경을 감지하는 데 사용 된) 95 % 동일하다는 것을.

    확장 된 diff 헤더의 마지막 행
    인덱스 f3e63d7..e8f44ba 100644
    주어진 파일의 모드에 대해 알려주십시오 ( 100644예를 들어 파일이 symlink가 아니라 일반 파일이며 실행 권한 비트가 없음을 의미합니다). 변경 후 파일 버전). 이 줄은 git am --3way패치 자체를 적용 할 수없는 경우 3 방향 병합을 시도하는 데 사용 됩니다.

  • 다음은 두 줄의 통합 된 diff 헤더입니다

    --- a / builtin-http-fetch.c
    +++ b / http-fetch.c
    diff -U결과 와 비교하여 소스 (사전 이미지) 및 대상 (사후 이미지) 파일 이름 후 파일 수정 시간 또는 파일 수정 시간이 없습니다. 파일이 작성된 경우 소스는 /dev/null; 파일이 삭제 된 경우 대상은 /dev/null입니다.
    를 설정하면 diff.mnemonicPrefix대신에 true로 구성 변수를, a/그리고 b/이 두 줄의 헤더에 접두어 대신 할 수 있습니다 c/, i/, w/o/각각 비교할 무엇을 접두사로; 볼 (1)을 구성 - 자식

  • 다음에는 하나 이상의 차이점이 있습니다. 각 덩어리는 파일이 다른 하나의 영역을 보여줍니다. 통합 형식 덩어리는 다음과 같은 줄로 시작합니다.

    @@ -1,8 +1,9 @@
    또는
    @@ -18,6 +19,8 @@ int cmd_http_fetch (int argc, const char ** argv, ...
    형식 @@ from-file-range to-file-range @@ [header]입니다. 시작 파일 범위는 형식 -<start line>,<number of lines>이며 종료 파일 범위는 +<start line>,<number of lines>입니다. 시작 줄과 줄 수는 각각 사전 이미지와 사후 이미지에서 덩어리의 위치와 길이를 나타냅니다. 행 수가 표시되지 않으면 0임을 의미합니다.

    선택적 헤더는 C 파일 ( -pGNU diff의 옵션 과 같은 )이거나 다른 유형의 파일에 해당 하는 경우 각 변경이 발생하는 C 함수를 보여줍니다 .

  • 다음은 파일의 차이점에 대한 설명입니다. 두 파일에 공통 인 줄은 공백 문자로 시작합니다. 두 파일간에 실제로 다른 행은 왼쪽 인쇄 열에 다음 표시기 문자 중 하나를 갖습니다.

    • '+'-여기에 첫 번째 파일에 줄이 추가되었습니다.
    • '-'-첫 번째 파일에서 한 줄이 제거되었습니다.


    예를 들어 첫 덩어리

     #include "cache.h"
     #include "walker.h"
    
    -int cmd_http_fetch(int argc, const char **argv, const char *prefix)
    +int main(int argc, const char **argv)
     {
    +       const char *prefix;
            struct walker *walker;
            int commits_on_stdin = 0;
            int commits;
    

    cmd_http_fetch로 대체되었으며 main해당 const char *prefix;줄이 추가 되었음을 의미합니다 .

    다시 말해, 변경 전에 'builtin-http-fetch.c'파일의 적절한 조각은 다음과 같습니다.

    #include "cache.h"
    #include "walker.h"
    
    int cmd_http_fetch(int argc, const char **argv, const char *prefix)
    {
           struct walker *walker;
           int commits_on_stdin = 0;
           int commits;
    

    변경 후이 'http-fetch.c'파일 의이 조각은 대신 다음과 같습니다.

    #include "cache.h"
    #include "walker.h"
    
    int main(int argc, const char **argv)
    {
           const char *prefix;
           struct walker *walker;
           int commits_on_stdin = 0;
           int commits;
    
  • 있을 수 있습니다

    \ 파일 끝에 줄 바꿈 없음
    행이 존재합니다 (예를 들어 diff가 아님).

으로 DONAL 휄로우 말했다 그것은 당신이 변경 한 것을 알고 실제 사례에 읽기 차이점을 연습하는 것이 가장 좋습니다.

참고 문헌 :


1
@Geremia : Git은 유사성 기반 휴리스틱을 사용하여 이름 변경 감지 ... 및 코드 이동 및 복사 감지에도 git blame -C -C작동 방식을 사용합니다. Git 디자인 결정입니다. git diff 형식은 사용자와의 유사성 (또는 비 유사성) 색인을 보여줍니다.
Jakub Narębski

1
@ Geremia : 더 정확하게 말하면, [header]덩어리 앞에 함수의 시작과 같이 가장 근접한 선행입니다. 대부분의 경우이 줄에는 diff 덩어리가있는 함수의 이름이 포함됩니다. 이렇게하여 구성 할 diffDIFF 드라이버 gitattribute 세트 포함 DIFF 드라이버 xfuncname구성 변수.
Jakub Narębski

1
@AnthonyGeoghegan : 행이 삭제되거나 (포스트 이미지의 행 수가 0 임) 추가되거나 (그러면 사전 이미지의 행 수가 0 임)
Jakub Narębski

1
@KasunSiyambalapitiya : Git이 사용하는 통합 diff 형식 (컨텍스트 diff 형식 ^ [1]과 반대)은 수정 된 행과 제거 및 추가 된 행을 구분하지 않습니다. [1] : gnu.org/software/diffutils/manual/html_node/Context-Format.html
Jakub Narębski

1
@ JakubNarębski : 줄 수는 0이 아닌 1로 기본 설정됩니다. 그렇게 간단합니다. 실제로는 표시 할 컨텍스트가 없기 때문에 단일 행 파일의 경우 "-1"및 / 또는 "+1"로만 나타납니다.
귀도 Flohr

68

@@ -1,2 +3,4 @@ diff의 일부

이 부분은 이해하는 데 시간이 걸렸으므로 최소한의 예를 만들었습니다.

형식은 기본적으로 diff -u통합 된 diff 와 동일합니다 .

예를 들어 :

diff -u <(seq 16) <(seq 16 | grep -Ev '^(2|3|14|15)$')

여기에서 2, 3, 14 및 15 행을 제거했습니다. 출력 :

@@ -1,6 +1,4 @@
 1
-2
-3
 4
 5
 6
@@ -11,6 +9,4 @@
 11
 12
 13
-14
-15
 16

@@ -1,6 +1,4 @@ 방법:

  • -1,6이 첫 번째 파일은 1 행에서 시작하여 총 6 행을 나타냅니다. 따라서 1 행에서 6 행까지 표시됩니다.

    1
    2
    3
    4
    5
    6
    

    -일반적으로로 호출하므로 "오래된"을 의미합니다 diff -u old new.

  • +1,4이 두 번째 파일은 1 행에서 시작하여 총 4 행을 나타냅니다. 따라서 1 행부터 4 행까지가 표시됩니다.

    + "신규"를 의미합니다.

    2 줄이 제거 되었기 때문에 6 줄 대신 4 줄만 있습니다! 새로운 덩어리는 다음과 같습니다.

    1
    4
    5
    6
    

@@ -11,6 +9,4 @@ 두 번째 덩어리는 비슷합니다.

  • 이전 파일에는 이전 파일의 11 번째 줄부터 6 줄이 있습니다.

    11
    12
    13
    14
    15
    16
    
  • 새 파일에는 새 파일의 9 행에서 시작하여 4 행이 있습니다.

    11
    12
    13
    16
    

    그 선 주 112와 3 : 우리는 이미 이전의 덩어리에 2 개 라인을 제거했기 때문에 새 파일의 9 라인입니다.

헝크 헤더

당신의 자식 버전과 구성에 따라, 당신은 또한 옆에 코드 라인을 얻을 수 @@, 라인 예를 func1() {에 :

@@ -4,7 +4,6 @@ func1() {

이것은 -pplain 플래그로 도 얻을 수 있습니다 diff.

예 : 오래된 파일 :

func1() {
    1;
    2;
    3;
    4;
    5;
    6;
    7;
    8;
    9;
}

line을 제거 6하면 diff에 다음이 표시됩니다.

@@ -4,7 +4,6 @@ func1() {
     3;
     4;
     5;
-    6;
     7;
     8;
     9;

이에 대한 올바른 라인이 아니라는 것을 참고 func1:이 라인을 생략 1하고 2.

이 멋진 기능은 종종 각 덩어리가 어떤 함수 또는 클래스에 속하는지 정확하게 알려주므로 diff를 해석하는 데 매우 유용합니다.

헤더를 선택하는 알고리즘이 정확히 작동하는 방식은 다음에서 논의됩니다. git diff hunk 헤더의 발췌 부분은 어디입니까?


11
아직 이해하지 못한 사람을위한 것입니다. 에서 @@ -1,6 +1,4 @@PLS 읽지 않는 -1minus one또는 +1같은 plus one대신으로이 글을 읽을 line 1 to 6오래된 (첫번째) 파일입니다. 여기서 - implies "old"마이너스가 아닙니다. BTW, 설명해 주셔서 감사합니다 ... 해쉬.
dkjain

@@ -1,8 +1,9 @@에서 실제로 발생한 일을 해석 할 수 있습니다. 예를 들어 1) 한 줄이 추가되었습니다. 2) 한 줄이 수정되고 있고 한 줄이 추가되고 있습니다. 또는 git diff correclty가 코드에서 수정 된 행을 식별하기 때문에 다른 방법으로 얻을 수 있습니다. 내가 정말로 이것을
정리할

위의 답변에서이 진술은 정확하지 않고 잘못 오도한다는 점에 유의하십시오. " +1,4이 작품은 두 번째 파일의 1-4 행에 해당합니다 ". +1,4비 조건부 컨텍스트 라인을 참조 할 수 있기 때문 입니다. 오히려, 무엇을 " +1,4"실제로 의미하는 것입니다 " 가있는 4파일의 '버전'의 라인 (즉, 상황에 맞는 라인) ". 의 의미를 이해하는 것이 중요합니다 +, -그리고 <whitespace>그것은 심술쟁이의 해석에 적용, 그 라인의 시작 부분에. 보다 시각적 인 예 : youtube.com/watch?v=1tqMjJeyKpw
Damilola Olowookere

23

다음은 간단한 예입니다.

diff --git a/file b/file 
index 10ff2df..84d4fa2 100644
--- a/file
+++ b/file
@@ -1,5 +1,5 @@
 line1
 line2
-this line will be deleted
 line4
 line5
+this line is added

여기에 설명이 있습니다 (자세한 내용은 여기 참조 ).

  • --git 명령이 아닙니다. 이것은 diff의 git 버전임을 의미합니다 (unix 아님).
  • a/ b/디렉토리는 실제가 아닙니다. 동일한 파일을 처리 할 때 편리합니다 (제 경우에는 a /는 색인에 있고 b /는 작업 디렉토리에 있습니다)
  • 10ff2df..84d4fa2 이 두 파일의 BLOB ID입니다
  • 100644 "모드 비트"는 파일이 일반 파일 (실행 파일이 아니라 심볼릭 링크가 아님)임을 나타냅니다.
  • --- a/file +++ b/file빼기 부호는 a / 버전의 행을 표시하지만 b / 버전에서는 누락됩니다. 더하기 기호는 a /에 누락되었지만 b /에있는 줄을 보여줍니다 (제 경우 --- 삭제 된 줄을 의미하고 + ++는 b /에 추가 된 줄을 의미하고 작업 디렉토리의 파일을 의미합니다)
  • @@ -1,5 +1,5 @@이것을 이해하려면 큰 파일로 작업하는 것이 좋습니다. 다른 장소에 두 가지 변경 사항이 있으면 다음과 같은 두 가지 항목이 표시됩니다 @@ -1,5 +1,5 @@. line1 ... line100 파일이 있고 line10을 삭제하고 새로운 line100을 추가한다고 가정하면 다음과 같은 이점이 있습니다.
@@ -7,7 +7,6 @@ line6
 line7
 line8
 line9
-this line10 to be deleted
 line11
 line12
 line13
@@ -98,3 +97,4 @@ line97
 line98
 line99
 line100
+this is new line100

감사. "100644는 모드 비트로, 일반 파일 (실행 파일이 아니라 심볼릭 링크가 아님)을 나타냅니다." "모드 비트"는 Linux 또는 Git의 개념입니까?
Tim

@Tim 자식에 한정되지 않습니다. 오른쪽 3 자리 ( 644)는 8 진수 (값 : 각각 1, 2, 4, eXecute, Write 및 Read 권한)로 읽히고 그 순서대로 소유자 (사용자), 그룹, 기타 권한에 해당합니다. 간단히 말해 , 644symbolicaly u=rw,og=r라고 쓰면 모든 사람이 읽을 수 있지만 소유자 만 쓸 수 있습니다. 왼쪽의 다른 숫자는 심볼릭 링크와 같은 다른 정보를 인코딩합니다. 값은 github.com/git/git/blob/… 에서 볼 수 있습니다 .이 위치의 첫 번째 1은 "일반 파일"입니다.
Patrick Mevzek

15

기본 출력 형식 (원래 diff추가 정보를 찾고자 하는 프로그램에서 나온 것 )을 "통합 diff"라고합니다. 기본적으로 4 가지 유형의 라인이 포함됩니다.

  • 단일 공백으로 시작하는 컨텍스트 라인
  • 삽입 된 선을 나타내는 삽입 선은로 시작합니다 +.
  • 로 시작할 삭제 라인, -
  • 어떤 파일에 대해 이야기하고 있는지, diff를 생성하는 데 사용 된 옵션, 파일의 사용 권한 변경 여부 등과 같은 상위 수준의 항목을 설명하는 메타 데이터 줄

변경 한 내용을 정확히 알고있는 두 버전의 파일간에 차이를 읽는 것이 좋습니다. 당신이 그것을 볼 때 무슨 일이 일어나고 있는지 인식 할 수 있습니다.


5
+1 : 연습에 대한 제안은 매우 좋은 것입니다. 아마도 문서를 강박 적으로 읽는 것보다 훨씬 빠를 것입니다.
Cascabel

6

내 Mac에서 :

info diff그런 다음 Output formats-> Context-> Unified format-> Detailed Unified: 를 선택하십시오 .

또는 같은 섹션으로 같은 경로를 따라 gnu에서 온라인 남자 diff :

파일 : diff.info, 노드 : 상세 통합, 다음 : 통합 예, 위쪽 : 통합 형식

통합 형식에 대한 자세한 설명 ......................................

통합 출력 형식은 다음과 같은 두 줄 헤더로 시작합니다.

 --- FROM-FILE FROM-FILE-MODIFICATION-TIME
 +++ TO-FILE TO-FILE-MODIFICATION-TIME

타임 스탬프는 '2002-02-21 23 : 30 : 39.942229878 -0800'과 같이 날짜, 소수 초 단위의 시간 및 시간대를 나타냅니다.

`--label = LABEL '옵션으로 헤더의 내용을 변경할 수 있습니다. * 참고 대체 이름 ::을 참조하십시오.

다음에는 하나 이상의 차이점이 있습니다. 각 덩어리는 파일이 다른 하나의 영역을 보여줍니다. 통합 형식 덩어리는 다음과 같습니다.

 @@ FROM-FILE-RANGE TO-FILE-RANGE @@
  LINE-FROM-EITHER-FILE
  LINE-FROM-EITHER-FILE...

두 파일에 공통 인 줄은 공백 문자로 시작합니다. 두 파일간에 실제로 다른 행은 왼쪽 인쇄 열에 다음 표시기 문자 중 하나를 갖습니다.

`+ '여기에 첫 번째 파일에 줄이 추가되었습니다.

`- '첫 번째 파일에서 한 줄이 제거되었습니다.


1
git은 버전 제어 시스템에 적합하지 않으므로 'XXX-FILE-MODIFICATION-TIME'부분을 인쇄하지 않습니다. 파일 시스템에서 파일을 비교하기 위해 타임 스탬프는 "가난한"버전 제어 기능을 할 수 있습니다.
Jakub Narębski

3

diff의 어떤 부분이 혼란 스러울 지 확실하지 않습니다. 실제 diff 또는 추가 헤더 정보 git가 인쇄합니다. 만일을 위해 헤더에 대한 간단한 개요가 있습니다.

첫 번째 줄은 다음과 같습니다 diff --git a/path/to/file b/path/to/file-분명히 diff 의이 섹션이 어떤 파일인지 알려줍니다. 당신은 부울 설정 변수를 설정하는 경우 diff.mnemonic prefixa과는 b같이 더 자세한 설명 문자로 변경됩니다 cw(커밋 작업 트리).

다음으로, "모드 라인"이 있는데, 파일의 내용을 변경하지 않는 변경 사항에 대한 설명을 제공하는 라인입니다. 여기에는 새 / 삭제 된 파일, 이름이 바뀐 / 복사 된 파일 및 권한 변경이 포함됩니다.

마지막으로와 같은 줄이 index 789bd4..0afb621 100644있습니다. 당신은 아마 신경 쓰지 않을 것이지만, 6 자리 16 진수는이 파일에 대한 이전 및 새로운 blob의 약식 SHA1 해시입니다 (blob은 파일 내용과 같은 원시 데이터를 저장하는 git 객체입니다). 물론 100644파일의 모드는 마지막 세 자리는 분명히 권한입니다. 처음 세 개는 추가 파일 메타 데이터 정보를 제공합니다 ( SO post 설명 ).

그 후에는 표준과 같은 표준 통합 diff 출력을 사용 diff -U합니다. 그것은 덩어리로 나뉘어져 있습니다-덩어리는 변경 사항과 컨텍스트를 포함하는 파일의 섹션입니다. 각 덩어리가 쌍으로 선행 ---하고 +++해당 파일을 나타내는 선 후 실제 DIFF 세의 양쪽 컨텍스트 라인 (기본값)이다 -+제거 / 추가 선과 선.


++ index라인. 로 확정git hash-object ./file
치로 틸리郝海东冠状病六四事件法轮功
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.