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
स्टेट केवल यह प्रदर्शित करता है कि कितनी लाइनें डाली / डिलीट / अपडेट की गई हैं। लेकिन मुझे यह जानने की जरूरत है कि कौन सी लाइन नंबर
महमूद खालिद

यह एक कठिन समस्या लग रहा था की तुलना में यह होना चाहिए, लेकिन मैं इसे git दोष और grep का उपयोग करके प्राप्त करने में कामयाब रहा। मेरा अद्यतन उत्तर देखें
सेड्रिक

1
यदि आउटपुट को अन्य प्रोग्राम जैसे 'awk' या 'grep' द्वारा संसाधित किया जाना है, तो आमतौर पर 'git blame -p' को कॉल करना चाहिए।
मिक्को रैंटलैनेन

8
गिट दोष हटाए गए लाइनों को नहीं
पकड़ेंगे

2
यह क्यों सही के रूप में चिह्नित है जब यह नहीं करता है जो ओपी के लिए पूछा?
शारजज Shar

27

यहाँ एक बश फ़ंक्शन एक परिणामी पंक्ति संख्या को एक अंतर से गणना करने के लिए है:

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);

इस तरह से एक अंतर से:

$ 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 -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);

यह एएनएसआई रंग कोड के खिलाफ मजबूत है, इसलिए आप --color=alwaysजोड़ा / हटाए गए लाइनों के लिए सामान्य रंग कोडिंग प्राप्त करने के लिए जीआईटी भिन्नता पास कर सकते हैं ।

उत्पादन आसानी से पकड़ा जा सकता है:

$ 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


मैं बैश कलर एस्केप कोड कैसे पास कर सकता हूं? यह बहुत अच्छा है, लेकिन आने वाले रंग कोड के git diff --colorमाध्यम से नहीं आते हैं। या क्या आपको लगता है कि इस फ़ंक्शन से वापसी में रंग से बचने को जोड़ना बेहतर होगा?
न्यू अलेक्जेंड्रिया

2
मैंने फ़ंक्शन को अपडेट किया इसलिए विभिन्न रेगीक्स एएनएसआई रंग कोड के लिए मजबूत हैं। git diff --color | diff-linesअब उम्मीद के
मुताबिक

1
यह समाधान कमाल का काम करता है! इसे उत्तर के रूप में चिह्नित किया जाना चाहिए क्योंकि यह वास्तव में वही करता है जो ओपी ने पूछा था। अगर यह आपके लिए काम करता है तो कृपया इसे वोट करें ताकि हम इसे लोकप्रिय उत्तर बना सकें :)
markdrake

मैं zsh का उपयोग करके यह त्रुटि प्राप्त करता रहता हूं: zsh: parse error near `]+m'कोई विचार? इस रेखा से त्रुटि आती है:elif [[ $REPLY =~ ^($esc\[[0-9;]+m)*([\ +-]) ]]; then
होश सादिक

@ होशादीक बस नियमित अभिव्यक्ति के उद्धरण से लगता है कि काम किया है।
Koobz

20

के --unified=0विकल्प का उपयोग करता हूं git diff

उदाहरण के लिए, git diff --unified=0 commit1 commit2अंतर को आउटपुट करता है:

* यहाँ छवि विवरण दर्ज करें *

वजह से --unified=0विकल्प, diff उत्पादन शो 0 संदर्भ लाइनों; दूसरे शब्दों में, यह बिल्कुल बदली हुई रेखाओं को दिखाता है

अब, आप उन पंक्तियों की पहचान कर सकते हैं जो '@@' से शुरू होती हैं, और इसे पैटर्न के आधार पर पार्स करते हैं:

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

उपरोक्त उदाहरण पर वापस, वाइल्डकार्डबाइंडिंग.जावा फ़ाइल के लिए, लाइन 910 से शुरू, 0 लाइनें हटा दी जाती हैं। 911 लाइन से शुरू करें, 4 लाइनें जोड़ी जाती हैं।


1
यदि @@ -910,10,+911,15@@ या कुछ और, तो हम कैसे कहते हैं कि कितनी संख्या में लाइनों को जोड़ा जा रहा है, हटाया या संशोधित किया जा रहा है
कसुन सियामबलपिटिया

1
क्या आपके पास एक सूची का उत्पादन करने का एक अच्छा तरीका है जैसे ओपी ने पूछा है?
शारजज

7

मुझे भी यही समस्या थी इसलिए मैंने एक gawk स्क्रिप्ट लिखी, जो git के आउटपुट को बदलती है और प्रत्येक लाइन के लिए लाइन नंबर को प्रस्तुत करने के लिए अलग है। मुझे यह कभी-कभी उपयोगी लगता है जब मुझे काम करने वाले पेड़ को अलग करने की आवश्यकता होती है, हालांकि यह उस तक सीमित नहीं है। शायद यह यहाँ किसी के लिए उपयोगी है?

$ 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 लाइसेंस प्राप्त होने का लाभ (या नुकसान) है।
ब्लैकवेटेबल

मैंनेgit diffn ऐसा करने के लिए भी लिखा था , और यह पूरी तरह से टर्मिनल रंगों को बरकरार रखता है और बाईं ओर पुरानी फ़ाइल और दाईं ओर नई फ़ाइल दोनों की लाइन संख्या दिखाता है।
गेब्रियल स्टेपल्स

4

सभी असम्बद्ध लाइनों की लाइन संख्या (जोड़ा / संशोधित):

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

उदाहरण आउटपुट:

1
2
8
12
13
14

लाइनों की सामग्री के बारे में क्या बदला गया था?
आनन

2

एक बाहरी अंतर उपकरण कॉन्फ़िगर करें जो आपको लाइन नंबर दिखाएगा। उदाहरण के लिए, यह वही है जो मेरे पास मेरे वैश्विक वैश्विक विन्यास में है:

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


अलग उपकरण का उपयोग किए बिना इन जानकारी को प्राप्त करने का कोई अन्य तरीका नहीं है। केवल git कमांड का उपयोग कर रहे हैं?
महमूद खालिद 16

1

यहाँ एक बैश फंक्शन है जिसे मैंने एक साथ सिल दिया था:

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

1

यह संभवतः परिवर्तित लाइनों की एक बहुत सटीक गिनती है:

git diff --word-diff <commit> |egrep '(?:\[-)|(?:\{\+)' |wc -l

इसके अलावा, यहां आपके अंतर में लाइन नंबरों के लिए एक समाधान है: https://github.com/jay/showlinenum


0

नहीं बिल्कुल वही जो आप के लिए पूछ रहे थे, लेकिन git blame TEXTFILEमदद कर सकते हैं।


0

आप पैरामीटर git diffके साथ युग्मित का उपयोग कर सकते हैं shortstatबस बदल लाइनों की संख्या दिखाने के लिए ।

आपके अंतिम कमिट के बाद से नहीं बदली गई लाइनों के लिए (एक फ़ाइल जो पहले से ही रेपो में है)

git diff HEAD --shortstat

यह कुछ इसी तरह का उत्पादन करेगा

1 file changed, 4 insertions(+)

प्रश्न प्रत्येक पंक्ति के लिए लाइन संख्या के लिए पूछता है जिसे बदल दिया गया है, न कि कुल कितनी लाइनों को बदल दिया गया है।
प्रो क्यू

0

मैं उत्पादन के लिए एक रास्ता खोज रहा था कि केवल git diff का उपयोग करके प्रत्येक फ़ाइल के लिए लाइनों को बदल दिया जाए। मेरा विचार था कि इस आउटपुट को एक प्रकार की जाँच के लिए एक लाइनर को खिलाया जाए। इससे मुझे मदद मिली


0

यदि आप इस प्रश्न की तलाश में आए थे, तो संशोधित / हटाए गए लाइनों के लिए लाइन नंबर प्राप्त करने के लिए कुछ पायथन कोपिस्टा यहाँ दिए गए हैं।

संशोधित किए गए और जोड़े गए लाइन नंबरों को प्राप्त करने वाली चीज़ों में इसे संशोधित करना काफी आसान होना चाहिए।

मैंने केवल विंडोज पर परीक्षण किया है, लेकिन यह क्रॉस प्लेटफॉर्म भी होना चाहिए।

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")
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.