git diff를 사용하여 줄 번호를 추가하고 수정하려면 어떻게해야합니까?


80

텍스트 파일이 있다고 가정

alex
bob
matrix
will be removed
git repo

그리고 나는 그것을 업데이트했습니다

alex
new line here
another new line
bob
matrix
git

여기에서 줄 번호 (2,3)을 추가하고 줄 번호 (6)을 업데이트했습니다.

git diff 또는 다른 git 명령을 사용하여 이러한 줄 번호 정보를 어떻게 얻을 수 있습니까?

답변:


78

git diff --stat 내가 생각하기에 당신이 언급하는 것을 커밋 할 때 얻는 출력을 보여줄 것입니다.

git diff --stat

변경된 줄 번호를 정확하게 표시하려면 다음을 사용할 수 있습니다.

git blame -p <file> | grep "Not Committed Yet"

그리고 변경된 줄은 결과에서 끝 괄호 앞의 마지막 숫자가됩니다. 그래도 깨끗한 해결책은 아닙니다 :(


3
stat는 삽입 / 삭제 / 업데이트 된 줄 수만 표시합니다. 하지만 어떤 줄 번호를 알아야합니다
Mahmoud Khaled 2011

이것은 당연한 것보다 더 어려운 문제인 것 같았지만 git blame 및 grep을 사용하여 문제를 해결했습니다. 내 업데이트 된 답변보기
Sedrik 2011

1
출력이 'awk'또는 'grep'과 같은 다른 프로그램에서 처리되는 경우 일반적으로 'git blame -p'를 호출해야합니다.
Mikko Rantalainen

8
자식 비난이 제거 된 라인을 잡을 것입니다
비탈리

2
OP가 요청한 것을 수행하지 않는데 왜 이것이 올바른 것으로 표시됩니까?
Shardj

27

다음은 diff에서 결과 줄 번호를 계산하는 bash 함수입니다.

diff-lines() {
    local path=
    local line=
    while read; do
        esc=$'\033'
        if [[ $REPLY =~ ---\ (a/)?.* ]]; then
            continue
        elif [[ $REPLY =~ \+\+\+\ (b/)?([^[:blank:]$esc]+).* ]]; then
            path=${BASH_REMATCH[2]}
        elif [[ $REPLY =~ @@\ -[0-9]+(,[0-9]+)?\ \+([0-9]+)(,[0-9]+)?\ @@.* ]]; then
            line=${BASH_REMATCH[2]}
        elif [[ $REPLY =~ ^($esc\[[0-9;]+m)*([\ +-]) ]]; then
            echo "$path:$line:$REPLY"
            if [[ ${BASH_REMATCH[2]} != - ]]; then
                ((line++))
            fi
        fi
    done
}

다음과 같은 출력을 생성 할 수 있습니다.

$ git diff | diff-lines
http-fetch.c:1: #include "cache.h"
http-fetch.c:2: #include "walker.h"
http-fetch.c:3: 
http-fetch.c:4:-int cmd_http_fetch(int argc, const char **argv, const char *prefix)
http-fetch.c:4:+int main(int argc, const char **argv)
http-fetch.c:5: {
http-fetch.c:6:+       const char *prefix;
http-fetch.c:7:        struct walker *walker;
http-fetch.c:8:        int commits_on_stdin = 0;
http-fetch.c:9:        int commits;
http-fetch.c:19:        int get_verbosely = 0;
http-fetch.c:20:        int get_recover = 0;
http-fetch.c:21: 
http-fetch.c:22:+       prefix = setup_git_directory();
http-fetch.c:23:+
http-fetch.c:24:        git_config(git_default_config, NULL);
http-fetch.c:25: 
http-fetch.c:26:        while (arg < argc && argv[arg][0] == '-') {
fetch.h:1: #include "config.h"
fetch.h:2: #include "http.h"
fetch.h:3: 
fetch.h:4:-int cmd_http_fetch(int argc, const char **argv, const char *prefix);
fetch.h:4:+int main(int argc, const char **argv);
fetch.h:5: 
fetch.h:6: void start_fetch(const char* uri);
fetch.h:7: bool fetch_succeeded(int status_code);

다음과 같은 diff에서 :

$ git diff
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/fetch.h b/fetch.h
index 5fd3e65..d43e0ca 100644
--- a/fetch.h
+++ b/fetch.h
@@ -1,7 +1,7 @@
 #include "config.h"
 #include "http.h"

-int cmd_http_fetch(int argc, const char **argv, const char *prefix);
+int main(int argc, const char **argv);

 void start_fetch(const char* uri);
 bool fetch_succeeded(int status_code);

추가 / 제거 / 수정 된 줄만 표시하고 주변 컨텍스트는 표시하지 않으 -U0려면 git diff에 전달할 수 있습니다 .

$ git diff -U0 | diff-lines
http-fetch.c:4:-int cmd_http_fetch(int argc, const char **argv, const char *prefix)
http-fetch.c:4:+int main(int argc, const char **argv)
http-fetch.c:6:+       const char *prefix;
http-fetch.c:22:+       prefix = setup_git_directory();
http-fetch.c:23:+
fetch.h:4:-int cmd_http_fetch(int argc, const char **argv, const char *prefix);
fetch.h:4:+int main(int argc, const char **argv);

ANSI 색상 코드에 대해 강력 --color=always하므로 git diff에 전달 하여 추가 / 제거 된 행에 대한 일반적인 색상 코딩을 얻을 수 있습니다.

출력은 쉽게 그릴 수 있습니다.

$ git diff -U0 | diff-lines | grep 'main'
http-fetch.c:4:+int main(int argc, const char **argv)
fetch.h:4:+int main(int argc, const char **argv);

귀하의 경우에는 다음 git diff -U0을 제공합니다.

$ git diff -U0 | diff-lines
test.txt:2:+new line here
test.txt:3:+another new line
test.txt:6:-will be removed
test.txt:6:-git repo
test.txt:6:+git

그냥 줄 번호를 원하는 경우, 변경 echo "$path:$line:$REPLY"단지를 echo "$line"통해 파이프를 출력 uniq.


bash 색상 이스케이프 코드를 어떻게 전달할 수 있습니까? 이것은 훌륭하지만 색상 코드가 나오지 git diff --color않습니다. 아니면이 함수의 반환에 색상 이스케이프를 추가하는 것이 더 나을 것이라고 생각하십니까?
New Alexandria

2
다양한 정규식이 ANSI 색상 코드에 견고하도록 함수를 업데이트했습니다. git diff --color | diff-lines이제 예상대로 작동합니다. :)
John Mellor

1
이 솔루션은 훌륭하게 작동합니다! OP가 요청한 것을 실제로 수행하므로 답변으로 표시되어야합니다. 그것이 당신을 위해 효과가 있었다면 우리가 그것을 대중적인 대답으로 만들 수 있도록 그것을 위로 투표하십시오 :)
markdrake

zsh를 사용하여이 오류가 계속 발생합니다. zsh: parse error near `]+m'아이디어가 있습니까? 오류는 다음 줄에서 발생합니다.elif [[ $REPLY =~ ^($esc\[[0-9;]+m)*([\ +-]) ]]; then
Hosh Sadiq 2014

@HoshSadiq 단순히 정규식을 인용하면 효과가있는 것 같습니다.
Koobz

20

--unified=0옵션을 사용합니다 git diff.

예를 들어, git diff --unified=0 commit1 commit2diff를 출력합니다.

* 여기에 이미지 설명 입력 *

--unified=0옵션 때문에 diff 출력은 0 개의 컨텍스트 행을 표시합니다. 즉, 변경된 라인을 정확하게 보여줍니다 .

이제 '@@'로 시작하는 줄을 식별하고 패턴을 기반으로 구문 분석 할 수 있습니다.

@@ -startline1,count1 +startline2,count2 @@

위의 예로 돌아가서 WildcardBinding.java 파일의 경우 910 행에서 시작하면 0 행이 삭제됩니다. 911 번 줄부터 시작하여 4 줄이 추가됩니다.


1
어떤 경우 @@ -910,10,+911,15@@ 라도, 우리가 줄 정확히 얼마나 많은 수를 추가, 삭제 또는 수정되는 말을 어떻게
Kasun Siyambalapitiya

1
OP와 같은 목록에 줄 번호를 출력하는 좋은 방법이 있습니까?
Shardj

7

나는 이와 같은 문제가 있었기 때문에 git diff의 출력을 변경하여 각 줄의 줄 번호를 앞에 추가하는 gawk 스크립트를 작성했습니다. 작업 트리를 비교해야 할 때 유용하다고 생각하지만, 이에 국한되지는 않습니다. 여기 누군가에게 유용할까요?

$ git diff HEAD~1 |showlinenum.awk
diff --git a/doc.txt b/doc.txt
index fae6176..6ca8c26 100644
--- a/doc.txt
+++ b/doc.txt
@@ -1,3 +1,3 @@
1: red
2: blue
 :-green
3:+yellow

여기에서 다운로드 할 수 있습니다 :
https://github.com/jay/showlinenum


매우 편리해 보입니다. 이 코드는 GPL 라이센스의 장점 (또는 단점)이 있음을 명심하십시오.
BlackVegetable

git diffn이 작업도 작성 했으며 터미널 색상을 완전히 유지하고 왼쪽에 이전 파일과 오른쪽에 새 파일의 줄 번호를 모두 표시합니다.
Gabriel Staples 2011

4

커밋되지 않은 모든 라인의 라인 번호 (추가 / 수정) :

git blame <file> | grep -n '^0\{8\} ' | cut -f1 -d:

출력 예 :

1
2
8
12
13
14

변경된 줄의 내용은 어떻습니까?
anon58192932

2

줄 번호를 표시하는 외부 비교 도구를 구성하십시오. 예를 들어, 이것은 내 git 전역 구성에있는 것입니다.

diff.guitool=kdiff3
difftool.kdiff3.path=c:/Program Files (x86)/KDiff3/kdiff3.exe
difftool.kdiff3.cmd="c:/Program Files (x86)/KDiff3/kdiff3.exe" "$LOCAL" "$REMOTE"

자세한 내용은이 답변을 참조하십시오 : https://stackoverflow.com/q/949242/526535


diff 도구를 사용하지 않고 이러한 정보를 얻을 수있는 다른 방법이 없습니다. git 명령 만 사용하십니까?
Mahmoud Khaled 2011

1

다음은 내가 함께 만든 bash 함수입니다.

echo ${f}:
for n in $(git --no-pager blame --line-porcelain $1 |
        awk '/author Not Committed Yet/{if (a && a !~ /author Not Committed Yet/) print a} {a=$0}' |
        awk '{print $3}') ; do
    if (( prev_line > -1 )) ; then
        if (( "$n" > (prev_line + 1) )) ; then
            if (( (prev_line - range_start) > 1 )) ; then
                echo -n "$range_start-$prev_line,"
            else
                echo -n "$range_start,$prev_line,"
            fi
            range_start=$n
        fi
    else
        range_start=$n
    fi
    prev_line=$n
done
if (( "$range_start" != "$prev_line" )) ; then
    echo "$range_start-$prev_line"
else
    echo "$range_start"
fi

그리고 그것은 다음과 같이 보입니다.

views.py:
403,404,533-538,546-548,550-552,554-559,565-567,580-582


0

정확히 무엇을 요청했는지는 아니지만 git blame TEXTFILE도움이 될 수 있습니다.


0

당신이 사용할 수있는 git diff결합 shortstat단지 쇼에 매개 변수 없이 변경 라인.

마지막 커밋 이후 변경된 줄 수 (이미 저장소에있는 파일에서)

git diff HEAD --shortstat

다음과 유사한 출력이 표시됩니다.

1 file changed, 4 insertions(+)

질문은 변경된 총 라인 수가 아니라 변경된 각 라인의 라인 번호를 묻습니다.
Pro Q


0

다음은 수정 / 제거 된 줄의 줄 번호를 가져 오는 Python 카피 파스타입니다.

줄 번호를 수정하고 추가하는 것으로 수정하는 것은 매우 쉽습니다.

Windows에서만 테스트했지만 크로스 플랫폼이어야합니다.

import re
import subprocess

def main(file1: str, file2: str):
    diff = get_git_diff(file1, file2)
    print(edited_lines(diff))

def edited_lines(git_diff: str):
    ans = []
    diff_lines = git_diff.split("\n")
    found_first = False
    # adjust for added lines
    adjust = 0
    # how many lines since the start
    count = 0
    for line in diff_lines:
        if found_first:
            count += 1
            if line.startswith('-'):
                # minus one because count is 1 when we're looking at the start line
                ans.append(start + count - adjust - 1)
                continue

            if line.startswith('+'):
                adjust += 1
                continue

        # get the start line
        match = re.fullmatch(r'@@ \-(\d+),\d+ \+\d+,\d+ @@', line)
        if match:
            start = int(match.group(1))
            count = 0
            adjust = 0
            found_first = True

    return ans


def get_git_diff(file1: str, file2: str):
    try:
        diff_process: subprocess.CompletedProcess = subprocess.run(['git', 'diff', '--no-index', '-u', file1, file2], shell=True, check=True, stdout=subprocess.PIPE)
        ans = diff_process.stdout
    # git may exit with 1 even though it worked
    except subprocess.CalledProcessError as e:
        if e.stdout and e.stderr is None:
            ans = e.stdout
        else:
            raise

    # remove carriage at the end of lines from Windows
    ans = ans.decode()
    ans.replace('\r', '')
    return ans


if __name__ == "__main__":
    main("file1.txt", "file2.txt")
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.