假设我有一个文本文件
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; 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:
$ 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 以获得添加/删除行的常用颜色编码。
输出可以很容易地被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"
为 justecho "$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.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
耦合shortstat
参数来显示更改的行数。
自上次提交以来更改的行数(在存储库中已经存在的文件中)
git diff HEAD --shortstat
它会输出类似于
1 file changed, 4 insertions(+)
这可能是更改行的相当准确的计数:
git diff --word-diff <commit> |egrep '(?:\[-)|(?:\{\+)' |wc -l
此外,这是您的差异中行号的解决方案:https ://github.com/jay/showlinenum
不完全是您所要求的,但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")
我正在寻找一种仅输出使用 git diff 为每个文件更改的行的方法。我的想法是将此输出提供给 linter 以进行类型检查。这对我有帮助
也许这要归功于 Jakub Bochenski - Git diff with line numbers (Git log with line numbers)
git diff --unified=0 | grep -Po '^\+\+\+ ./\K.*|^@@ -[0-9]+(,[0-9]+)? \+\K[0-9]+(,[0-9]+)?(?= @@)'