问题
Assuming I have a text file
alex bob matrix will be removed git repo
and I have updated it to be
alex new line here another new line bob matrix git
Here, I have added lines number (2,3) and updated line number (6)
How can I get these line numbers info using git diff or any other git command?
回答1:
git diff --stat
will show you the output you get when committing stuff which is the one you are referring to I guess.
git diff --stat
For showing exactly the line numbers that has been changed you can use
git blame -p <file> | grep "Not Committed Yet"
And the line changed will be the last number before the ending parenthesis in the result. Not a clean solution though :(
回答2:
Here's a bash function to calculate the resulting line numbers from a diff:
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 }
It can produce output such as:
$ 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);
from a diff like this:
$ 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);
If you only want to show added/removed/modified lines, and not the surrounding context, you can pass -U0
to 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);
It's robust against ANSI color codes, so you can pass --color=always
to git diff to get the usual color coding for added/removed lines.
The output can be easily grepped:
$ 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);
In your case git diff -U0
would give:
$ 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
If you just want the line numbers, change the echo "$path:$line:$REPLY"
to just echo "$line"
and pipe the output through uniq
.
回答3:
I use the --unified=0
option of git diff
.
For example, git diff --unified=0 commit1 commit2
outputs the diff:

Because of the --unified=0
option, the diff output shows 0 context lines; in other words, it shows exactly the changed lines.
Now, you can identify the lines that start with '@@', and parse it based on the pattern:
@@ -startline1,count1 +startline2,count2 @@
Back to the above example, for the file WildcardBinding.java, start from line 910, 0 lines are deleted. Start from line 911, 4 lines are added.
回答4:
I had this same problem so I wrote a gawk script that changes the output of git diff to prepend the line number for each line. I find it useful sometimes when I need to diff working tree, although it's not limited to that. Maybe it is useful to someone here?
$ 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
You can download it from here:
https://github.com/jay/showlinenum
回答5:
Line numbers of all uncommitted lines (added/modified):
git blame <file> | grep -n '^0\{8\} ' | cut -f1 -d:
Example output:
1 2 8 12 13 14
回答6:
Configure an external diff tool which will show you the line numbers. For example, this is what I have in my git global config:
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"
See this answer for more details: https://stackoverflow.com/q/949242/526535
回答7:
Here's a bash function I cobbled together:
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
And it ends up looking like this:
views.py: 403,404,533-538,546-548,550-552,554-559,565-567,580-582
回答8:
You can use git diff
coupled with shortstat
parameter to just show the no of lines changed.
For the no of lines changed (in a file that's already in the repo) since your last commit
git diff HEAD --shortstat
It'll output something similar to
1 file changed, 4 insertions(+)
回答9:
Not exactly what you were asking for, but git blame TEXTFILE
may help.
回答10:
This is probably a fairly accurate count of changed lines:
git diff --word-diff <commit> |egrep '(?:\[-)|(?:\{\+)' |wc -l
Also, here is a solution for line numbers in your diff: https://github.com/jay/showlinenum
来源:https://stackoverflow.com/questions/8259851/using-git-diff-how-can-i-get-added-and-modified-lines-numbers