假设我有一个文本文件
alex
bob
matrix
will be removed
git repo
我已将其更新为
alex
new line here
another new line
bob
matrix
git
在这里,我添加了行号(2,3)并更新了行号(6)
如何使用 git diff 或任何其他 git 命令获取这些行号信息?
git diff --stat
将向您显示提交内容时获得的输出,我猜这就是您所指的内容。
git diff --stat
为了准确显示已更改的行号,您可以使用
git blame -p <file> | grep "Not Committed Yet"
更改的行将是结果中结束括号之前的最后一个数字。但这不是一个干净的解决方案:(
这是一个 bash 函数,用于根据 diff 计算结果行号:
diff-lines() {
local path=
local line=
while read -r; 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);
fetch.h:7:\ No newline at end of file
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);
\ No newline at end of file
+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);
fetch.h:7:-bool fetch_succeeded(int status_code);
fetch.h:7:\ No newline at end of file
fetch.h:7:+bool fetch_succeeded(int status_code);
它对 ANSI 颜色代码具有鲁棒性,因此您可以将
--color=always
传递给 git diff 以获得添加/删除行的常用颜色编码。
可以轻松地对输出进行 grep:
$ 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
管道输出。
我使用
--unified=0
的 git diff
选项。
例如,
git diff --unified=0 commit1 commit2
输出差异:
由于
--unified=0
选项,diff 输出显示 0 条上下文行;换句话说,它显示确切地显示了更改的行。
现在,您可以识别以“@@”开头的行,并根据模式对其进行解析:
@@ -startline1,count1 +startline2,count2 @@
回到上面的例子,对于WildcardBinding.java文件,从第910行开始,删除了0行。从第911行开始,添加了4行。
我遇到了同样的问题,所以我编写了一个 gawk 脚本,该脚本更改 git diff 的输出以在每行前面添加行号。我发现有时当我需要比较工作树时它很有用,尽管它不限于此。也许对这里的人有用?
$ 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
所有未提交行的行号(添加/修改):
git blame <file> | grep -n '^0\{8\} ' | cut -f1 -d:
输出示例:
1
2
8
12
13
14
您可以将
git diff
与 shortstat
参数结合使用,仅显示已更改的 no of 行。
自上次提交以来更改的行数(在存储库中已有的文件中)
git diff HEAD --shortstat
它会输出类似于
的内容1 file changed, 4 insertions(+)
配置一个外部比较工具,它将显示行号。例如,这是我的 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
这是我拼凑而成的 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
这可能是更改行的相当准确的计数:
git diff --word-diff <commit> |egrep '(?:\[-)|(?:\{\+)' |wc -l
此外,这里还有一个差异中行号的解决方案:https://github.com/jay/showlinenum
我正在寻找一种使用 git diff 仅输出每个文件更改的行的方法。 我的想法是将这个输出提供给 linter 进行类型检查。 这对我有帮助
不完全是您所要求的,但
git blame TEXTFILE
可能会有所帮助。
这里有一些 Python copypasta,用于获取修改/删除行的行号,以防您在寻找此问题时遇到此问题。
将其修改为也可以获取修改和添加的行号的内容应该相当容易。
我只在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")
也许这要归功于 Jakub Bochenski - 带有行号的 Git diff(带有行号的 Git log)
git diff --unified=0 | grep -Po '^\+\+\+ ./\K.*|^@@ -[0-9]+(,[0-9]+)? \+\K[0-9]+(,[0-9]+)?(?= @@)'