Git 中文参考(七)(3)https://developer.aliyun.com/article/1565813
用于合并的 diff 格式
“git-diff-tree”,“git-diff-files”和“git-diff --raw”可以使用-c
或--cc
选项为合并提交生成 diff 输出。输出与上述格式的不同之处如下:
- 每个父母都有一个冒号
- 还有更多“src”模式和“src”sha1
- status 是每个父级的连接状态字符
- 没有可选的“得分”号码
- 单路径,仅适用于“dst”
例:
::100644 100644 100644 fabadb8 cc95eb0 4866510 MM describe.c
请注意,_ 组合 diff_ 仅列出从所有父项修改的文件。
使用-p 生成补丁
当“git-diff-index”,“git-diff-tree”或“git-diff-files”使用-p
选项运行时,“git diff”不带--raw
选项或“git log”使用“-p”选项,它们不会产生上述输出;相反,他们生成一个补丁文件。您可以通过GIT_EXTERNAL_DIFF
和GIT_DIFF_OPTS
环境变量自定义此类修补程序的创建。
-p 选项产生的内容与传统的 diff 格式略有不同:
- 它前面有一个“git diff”标题,如下所示:
diff --git a/file1 b/file2
- 除非涉及重命名/复制,否则
a/
和b/
文件名是相同的。特别是,即使是创建或删除,/dev/null
也是 _ 而不是 _ 来代替a/
或b/
文件名。
当涉及重命名/复制时,file1
和file2
分别显示重命名/复制的源文件的名称和重命名/复制的文件的名称。 - 它后跟一个或多个扩展标题行:
old mode <mode> new mode <mode> deleted file mode <mode> new file mode <mode> copy from <path> copy to <path> rename from <path> rename to <path> similarity index <number> dissimilarity index <number> index <hash>..<hash> <mode>
- 文件模式打印为 6 位八进制数,包括文件类型和文件权限位。
扩展标头中的路径名不包括a/
和b/
前缀。
相似性指数是未更改行的百分比,相异性指数是更改行的百分比。它是一个向下舍入的整数,后跟一个百分号。因此,100%的相似性索引值保留用于两个相等的文件,而 100%的相异性意味着旧文件中的任何行都不会成为新文件。
索引行包括更改前后的 SHA-1 校验和。 <模式>如果文件模式没有改变,则包括在内;否则,单独的行表示旧模式和新模式。 - 具有“异常”字符的路径名被引用,如配置变量
core.quotePath
所述(参见 git-config [1] )。 - 输出中的所有
file1
文件在提交之前引用文件,并且所有file2
文件在提交之后引用文件。将每个更改顺序应用于每个文件是不正确的。例如,此补丁将交换 a 和 b:
diff --git a/a b/b rename from a rename to b diff --git a/b b/a rename from b rename to a
组合差异格式
在显示合并时,任何差异生成命令都可以使用-c
或--cc
选项生成 _ 组合差异 _。当显示与 git-diff [1] 或 git-show [1] 的合并时,这是默认格式。另请注意,您可以为这些命令中的任何一个提供-m
选项,以强制使用合并的各个父项生成差异。
_ 组合 diff_ 格式如下所示:
diff --combined describe.c index fabadb8,cc95eb0..4866510 --- a/describe.c +++ b/describe.c @@@ -98,20 -98,12 +98,20 @@@ return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1; } - static void describe(char *arg) -static void describe(struct commit *cmit, int last_one) ++static void describe(char *arg, int last_one) { + unsigned char sha1[20]; + struct commit *cmit; struct commit_list *list; static int initialized = 0; struct commit_name *n; + if (get_sha1(arg, sha1) < 0) + usage(describe_usage); + cmit = lookup_commit_reference(sha1); + if (!cmit) + usage(describe_usage); + if (!initialized) { initialized = 1; for_each_ref(get_name);
- 它前面有一个“git diff”标题,看起来像这样(当使用
-c
选项时):
diff --combined file
- 或者像这样(当使用
--cc
选项时):
diff --cc file
- 它后跟一个或多个扩展标题行(此示例显示了与两个父项的合并):
index <hash>,<hash>..<hash> mode <mode>,<mode>..<mode> new file mode <mode> deleted file mode <mode>,<mode>
- 只有当< mode>中的至少一个出现时,
mode ,..
行才会出现。与其他人不同。具有关于检测到的内容移动(重命名和复制检测)的信息的扩展标题被设计为与两个< tree-ish>的差异一起工作。并且不会被组合 diff 格式使用。 - 接下来是两行的文件/文件头
--- a/file +++ b/file
- 与传统 _ 统一 _ diff 格式的双行标题类似,
/dev/null
用于表示创建或删除的文件。 - 修改了块头格式以防止人们意外地将其馈送到
patch -p1
。创建组合差异格式用于审查合并提交更改,并不适用于应用。此更改类似于扩展 _ 索引 _ 标头中的更改:
@@@ <from-file-range> <from-file-range> <to-file-range> @@@
- 组合 diff 格式的块头中有(父项数+ 1)
@
个字符。
与传统的 _ 统一 _ 差异格式不同,后者显示两个文件 A 和 B,其中一列具有-
(减去 - 出现在 A 中但在 B 中删除),+
(加 - 缺少 A 但是添加到 B)或" "
(空格 - 未更改)前缀,此格式将两个或多个文件 file1,file2,…与一个文件 X 进行比较,并显示 X 与每个文件 N 的不同之处。每个 fileN 的一列被添加到输出行之前,以指示 X 的行与它的不同之处。
N 列中的-
字符表示该行出现在 fileN 中,但它不会出现在结果中。列 N 中的+
字符表示该行出现在结果中,而 fileN 没有该行(换句话说,从该父项的角度添加了该行)。
在上面的示例输出中,函数签名已从两个文件中更改(因此,file1 和 file2 中的两个-
删除加上++
表示添加的一行未出现在 file1 或 file2 中)。另外八行与 file1 相同,但不出现在 file2 中(因此以+
为前缀)。
当由git diff-tree -c
显示时,它将合并提交的父项与合并结果进行比较(即 file1…fileN 是父项)。当由git diff-files -c
显示时,它将两个未解析的合并父项与工作树文件进行比较(即 file1 是阶段 2 又名“我们的版本”,file2 是阶段 3 又名“他们的版本”)。
其他差异格式
--summary
选项描述新添加,删除,重命名和复制的文件。 --stat
选项将 diffstat(1)图形添加到输出。这些选项可以与其他选项结合使用,例如-p
,用于人类消费。
当显示涉及重命名或副本的更改时,--stat
输出通过组合路径名的公共前缀和后缀来紧凑地格式化路径名。例如,修改 4 行时将arch/i386/Makefile
移动到arch/x86/Makefile
的更改将显示如下:
arch/{i386 => x86}/Makefile | 4 +--
--numstat
选项提供 diffstat(1)信息,但设计用于更容易的机器消耗。 --numstat
输出中的条目如下所示:
1 2 README 3 1 arch/{i386 => x86}/Makefile
也就是说,从左到右:
- 添加的行数;
- 标签;
- 删除的行数;
- 标签;
- pathname(可能带有重命名/复制信息);
- 换行符。
当-z
输出选项生效时,输出格式为:
1 2 README NUL 3 1 NUL arch/i386/Makefile NUL arch/x86/Makefile NUL
那是:
- 添加的行数;
- 标签;
- 删除的行数;
- 标签;
- NUL(仅在重命名/复制时存在);
- 原像中的路径名;
- NUL(仅在重命名/复制时存在);
- postimage 中的路径名(仅在重命名/复制时存在);
- 一个 NUL。
在重命名的情况下,preimage 路径之前的额外NUL
是允许读取输出的脚本判断正在读取的当前记录是单路径记录还是重命名/复制记录而无需提前读取。读取添加和删除的行后,读取NUL
将产生路径名,但如果是NUL
,则记录将显示两个路径。
运营模式
您可以选择是否完全信任索引文件(使用--cached
标志)或要求 diff 逻辑显示任何与 stat 状态不匹配的文件为“暂时更改”。这两项操作确实非常有用。
缓存模式
如果指定了--cached
,则可以询问:
show me the differences between HEAD and the current index contents (the ones I'd write using 'git write-tree')
例如,假设您已经处理了工作目录,更新了索引中的一些文件并准备提交。你想要确切地看到你将提交什么,而不必编写新的树对象并以这种方式进行比较,为此,你只需要做
git diff-index --cached HEAD
示例:假设我已将commit.c
重命名为git-commit.c
,并且我已经完成了update-index
以使其在索引文件中生效。 git diff-files
根本不会显示任何内容,因为索引文件与我的工作目录匹配。但是做一个 git diff-index 会:
torvalds@ppc970:~/git> git diff-index --cached HEAD -100644 blob 4161aecc6700a2eb579e842af0b7f22b98443f74 commit.c +100644 blob 4161aecc6700a2eb579e842af0b7f22b98443f74 git-commit.c
你可以很容易地看到以上是重命名。
实际上,git diff-index --cached
应该总是完全等同于实际执行 _git 写树 _ 并进行比较。除了这个,你只想检查你的位置的情况要好得多。
因此,当你问自己“我已经标记了什么以及与之前的树有什么区别”时,做一个git diff-index --cached
基本上非常有用。
非缓存模式
“非缓存”模式采用不同的方法,并且可能更有用,因为它的作用不能用 git write-tree + _git diff-模拟树 _。这就是默认模式。非缓存版本会询问以下问题:
show me the differences between HEAD and the currently checked out tree - index contents _and_ files that aren't up to date
这显然是一个非常有用的问题,因为它告诉你可以提交什么。同样,输出将 git diff-tree -r 输出与 tee 匹配,但有一个扭曲。
扭曲的是,如果某个文件与索引不匹配,我们就没有后备存储的东西,我们使用神奇的“全零”sha1 来表示。所以,假设你已经编辑了kernel/sched.c
,但实际上还没有对它进行 git update-index - 没有与新状态相关的“对象”,你得到:
torvalds@ppc970:~/v2.6/linux> git diff-index --abbrev HEAD :100644 100664 7476bb... 000000... kernel/sched.c
即,它表明树已经改变,kernel/sched.c
不是最新的,可能包含新的东西。全零 sha1 意味着要获得真正的差异,您需要直接查看工作目录中的对象,而不是执行对象到对象的差异。
| 注意 | 与此类型的其他命令一样, git diff-index 实际上根本不查看文件的内容。所以也许kernel/sched.c
实际上并没有改变,只是你碰到了它。在任何一种情况下,都需要注意 git update-index 才能使索引同步。 |
| 注意 | 您可以将文件混合显示为“已更新”和“在工作目录中仍然是脏的”。您总是可以告诉哪个文件处于哪个状态,因为“已更新”的文件显示有效的 sha1,而“与索引不同步”的文件将始终具有特殊的全零值 sha1。 |
GIT
部分 git [1] 套件
git-for-each-ref
名称
git-for-each-ref - 每个参考的输出信息
概要
git for-each-ref [--count=<count>] [--shell|--perl|--python|--tcl] [(--sort=<key>)…] [--format=<format>] [<pattern>…] [--points-at=<object>] (--merged[=<object>] | --no-merged[=<object>]) [--contains[=<object>]] [--no-contains[=<object>]]
描述
迭代匹配的所有引用并根据给定的
显示它们,然后根据给定的
集对它们进行排序。如果给出
,则在显示许多参考后停止。
中的插值可以选择引用指定主语言中的字符串文字,允许直接用该语言进行评估。
OPTIONS
<pattern>…
如果给出一个或多个模式,则仅显示与至少一个模式匹配的 refs,使用 fnmatch(3)或字面意思,在后一种情况下完全匹配或从开头到斜线。
--count=<count>
默认情况下,该命令显示与匹配的所有引用。此选项使其在显示许多引用后停止。
--sort=<key>
要排序的字段名称。前缀-
按值的降序排序。未指定时,使用refname
。您可以使用–sort =< key>选项多次,在这种情况下,最后一个键成为主键。
--format=<format>
一个字符串,用于插入显示的 ref 及其指向的对象的%(fieldname)
。如果fieldname
以星号(*
为前缀)并且 ref 指向标记对象,请使用标记对象引用的对象中的字段值(而不是标记对象中的字段)。未指定时,默认为
%(objectname) SPC %(objecttype) TAB %(refname)
。它还将%%
插入到%
,%xx
其中xx
是十六进制数字,插入到十六进制代码xx
的字符中;例如%00
内插到\0
(NUL),%09
到\t
(TAB)和%0a
到\n
(LF)。
--color[=<when>]
尊重--format
选项中指定的任何颜色。 字段必须是
always
,never
或auto
之一(如果不存在,则表现得好像
always
一样)。
--shell
--perl
--python
--tcl
如果给定,则替换%(fieldname)
占位符的字符串将被引用为适合指定宿主语言的字符串文字。这是为了生成一个可以直接“评估”的 scriptlet。
--points-at=<object>
仅列出指向给定对象的引用。
--merged[=<object>]
仅列出可从指定提交(HEAD,如果未指定)可访问的引用的 refs,与--no-merged
不兼容。
--no-merged[=<object>]
仅列出其指针无法从指定的提交(如果未指定,则为 HEAD)可访问的 refs,与--merged
不兼容。
--contains[=<object>]
仅列出包含指定提交的引用(如果未指定,则为 HEAD)。
--no-contains[=<object>]
仅列出不包含指定提交的引用(如果未指定,则为 HEAD)。
--ignore-case
排序和过滤 refs 不区分大小写。
字段名称
来自引用对象中的结构化字段的各种值可用于插入到结果输出中,或作为排序键。
对于所有对象,可以使用以下名称:
refname
ref 的名称($ GIT_DIR /之后的部分)。对于 ref 附加:short
的非模糊短名称。选项 core.warnAmbiguousRefs 用于选择严格的缩写模式。如果附加lstrip=
(rstrip=
),从参考号的前面(后面)剥离斜线分离的路径分量(例如
%(refname:lstrip=2)
将refs/tags/foo
变为foo
并且%(refname:rstrip=2)
变为refs/tags/foo
进入refs
)。如果为负数,则从指定端剥离尽可能多的路径组件以留下
-
路径组件(例如%(refname:lstrip=-2)
将refs/tags/foo
变为tags/foo
而%(refname:rstrip=-1)
将refs/tags/foo
变为refs/tags/foo
COD17])。当 ref 没有足够的组件时,如果使用正< N>进行剥离,则结果将变为空字符串,或者如果使用负< N>进行剥离,则结果将变为完整的 refname。两者都不是错误。
strip
可以用作lstrip
的同义词。
objecttype
对象的类型(blob
,tree
,commit
,tag
)。
objectsize
对象的大小(与 git cat-file -s 报告相同)。附加:disk
以获取对象占用磁盘的大小(以字节为单位)。请参阅下面CAVEATS
部分中有关磁盘大小的说明。
objectname
对象名称(又名 SHA-1)。对于对象名称的非模糊缩写,附加:short
。对于具有所需长度的对象名称的缩写,附加:short=
,其中最小长度为 MINIMUM_ABBREV。可能会超出长度以确保唯一的对象名称。
deltabase
如果将其存储为 delta,则会扩展为给定对象的 delta base 的对象名称。否则它会扩展为空对象名称(全为零)。
upstream
本地引用的名称,可以被视为显示引用的“上游”。以与上述refname
相同的方式尊重:short
,:lstrip
和:rstrip
。另外尊重:track
以显示“[前 N,后 M]”和:trackshort
以显示简洁版本:“>” (提前),“<” (后面),“<>” (前后)或“=”(同步)。每当遇到未知的上游引用时,:track
也会打印“[gone]”。附加:track,nobracket
以显示没有括号的跟踪信息(即“在 N 之前,在 M 之后”)。
对于任何远程跟踪分支%(upstream)
,%(upstream:remotename)
和%(upstream:remoteref)
分别指代远程名称和被跟踪远程 ref 的名称。换句话说,远程跟踪分支可以通过使用 refspec %(upstream:remoteref):%(upstream)
从%(upstream:remotename)
获取来显式和单独更新。
如果 ref 没有与之关联的跟踪信息,则无效。除nobracket
之外的所有选项都是互斥的,但如果一起使用,则选择最后一个选项。
push
本地引用的名称,表示显示的引用的@{push}
位置。与upstream
一样,:short
,:lstrip
,:rstrip
,:track
,:trackshort
,:remotename
和:remoteref
选项。如果未配置@{push}
ref,则生成空字符串。
HEAD
* 如果 HEAD 匹配当前 ref(检出的分支),否则。
color
更改输出颜色。后跟:
,其中颜色名称在 git-config [1] 的“CONFIGURATION FILE”部分的值下描述。例如,%(color:bold red)
。
align
左,中,或右对齐%(对齐:…)和%(结束)之间的内容。 “对齐:”之后是以逗号分隔的任何顺序的width=
和position=
,其中是左,右或中间,默认为左,
是内容的总长度对齐。为简洁起见,可以省略“width =”和/或“position =”前缀,并且< width>和< position>用来代替。例如,
%(align:,)
。如果内容长度大于宽度,则不执行对齐。如果与--quote
一起使用,则引用%(align:…)和%(end)之间的所有内容,但如果嵌套,则只有最顶层执行引用。
if
用作%(if)…%(然后)…%(结束)或%(如果)…%(然后)…%(否则)…%(结束)。如果在%(if)之后有一个带有值或字符串文字的原子,则打印%(then)之后的所有内容,否则如果使用%(else)原子,则打印%(else)之后的所有内容。我们在%(然后)之前评估字符串时忽略空格,当我们使用打印“*”或“”的%(HEAD)原子并且我们想要仅在条件下应用 _ 时这很有用 HEAD 参考。附加“:equals =< string>”或“:notequals =< string>”比较%(if:…)和%(then)原子与给定字符串之间的值。_
symref
给定符号 ref 引用的引用。如果不是符号引用,则不打印任何内容。以与refname
相同的方式尊重:short
,:lstrip
和:rstrip
选项。
除上述内容外,对于提交和标记对象,标题字段名称(tree
,parent
,object
,type
和tag
)可用于指定标题字段中的值。
对于提交和标记对象,特殊的creatordate
和creator
字段将对应于committer
或tagger
字段中的相应日期或名称 - 电子邮件 - 日期元组,具体取决于对象类型。这些用于处理带注释和轻量级标签的混合。
将 name-email-date 元组作为其值(author
,committer
和tagger
)的字段可以后缀name
,email
和date
以提取指定的组件。
提交和标记对象中的完整消息是contents
。它的第一行是contents:subject
,其中 subject 是提交消息的所有行的连接,直到第一个空行。下一行是contents:body
,其中 body 是第一个空白行之后的所有行。可选的 GPG 签名是contents:signature
。使用contents:lines=N
获得消息的第一N
行。另外,由 git-interpre-trailers [1] 解释的预告片作为trailers
(或通过使用历史别名contents:trailers
)获得。使用trailers:only
可以省略拖车块中的非拖车线。可以从预告片中删除空格连续,以便每个预告片单独出现在一行上,其全部内容为trailers:unfold
。两者可以一起用作trailers:unfold,only
。
出于排序目的,具有数值的字段按数字顺序排序(objectsize
,authordate
,committerdate
,creatordate
,taggerdate
)。所有其他字段用于按字节值顺序排序。
还有一个按版本排序的选项,这可以通过使用 fieldname version:refname
或其别名v:refname
来完成。
在任何情况下,引用不适用于 ref 引用的对象的字段的字段名称不会导致错误。它返回一个空字符串。
作为日期类型字段的特殊情况,您可以通过添加:
后跟日期格式名称来指定日期的格式(请参阅 git-rev-list [1]的--date
选项的值需要)。
像%(对齐)和%(如果)这样的原子总是需要匹配的%(结束)。我们称它们为“开放原子”,有时将它们表示为%($ open)。
当特定于脚本语言的引用生效时,顶级开放原子与其匹配的%(结束)之间的所有内容都根据开放原子的语义进行评估,并且仅引用顶级开放原子的结果。
例子
直接生成格式化文本的示例。显示最近 3 个标记的提交:
#!/bin/sh git for-each-ref --count=3 --sort='-*authordate' \ --format='From: %(*authorname) %(*authoremail) Subject: %(*subject) Date: %(*authordate) Ref: %(*refname) %(*body) ' 'refs/tags'
一个简单的例子,展示了在输出中使用 shell eval,演示了如何使用–shell。列出所有头的前缀:
#!/bin/sh git for-each-ref --shell --format="ref=%(refname)" refs/heads | \ while read entry do eval "$entry" echo `dirname $ref` done
关于标签的更详细的报告,证明格式可能是整个脚本:
#!/bin/sh fmt=' r=%(refname) t=%(*objecttype) T=${r#refs/tags/} o=%(*objectname) n=%(*authorname) e=%(*authoremail) s=%(*subject) d=%(*authordate) b=%(*body) kind=Tag if test "z$t" = z then # could be a lightweight tag t=%(objecttype) kind="Lightweight tag" o=%(objectname) n=%(authorname) e=%(authoremail) s=%(subject) d=%(authordate) b=%(body) fi echo "$kind $T points at a $t object $o" if test "z$t" = zcommit then echo "The commit was authored by $n $e at $d, and titled $s Its message reads as: " echo "$b" | sed -e "s/^/ /" echo fi ' eval=`git for-each-ref --shell --format="$fmt" \ --sort='*objecttype' \ --sort=-taggerdate \ refs/tags` eval "$eval"
显示%(if)…%(然后)…%(else)…%(end)的用法的示例。这为当前分支添加星号前缀。
git for-each-ref --format="%(if)%(HEAD)%(then)* %(else) %(end)%(refname:short)" refs/heads/
显示%(if)…%(然后)…%(结束)的用法的示例。这将打印 authorname(如果存在)。
git for-each-ref --format="%(refname)%(if)%(authorname)%(then) Authored by: %(authorname)%(end)"
CAVEATS
请注意,磁盘上对象的大小是准确报告的,但应该注意得出哪些引用或对象负责磁盘使用的结论。打包的非 delta 对象的大小可能远大于对其增量的对象的大小,但是选择哪个对象是基础并且 delta 是任意的并且在重新打包期间可能会发生变化。
还要注意,对象的多个副本可能存在于对象数据库中;在这种情况下,未定义将报告哪个副本的大小或增量基数。
也可以看看
GIT
部分 git [1] 套件
Git 中文参考(七)(5)https://developer.aliyun.com/article/1565815