原文:Git Reference 协议:CC BY-NC-SA 4.0
git-revert
原文:
git-scm.com/docs/git-revert
名称
git-revert - 恢复一些现有的提交
概要
代码语言:javascript复制git revert [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>…
git revert --continue
git revert --quit
git revert --abort
描述
给定一个或多个现有提交,还原相关修补程序引入的更改,并记录一些记录它们的新提交。这需要您的工作树是干净的(没有 HEAD 提交的修改)。
注意: git revert 用于记录一些新的提交以反转某些早期提交的效果(通常只有一个错误的提交)。如果你想丢弃工作目录中所有未提交的更改,你应该看到 git-reset [1] ,特别是--hard
选项。如果你想在另一个提交中提取特定文件,你应该看到 git-checkout [1] ,特别是git checkout <commit> -- <filename>
语法。请注意这些替代方案,因为它们都会丢弃工作目录中未提交的更改。
OPTIONS
代码语言:javascript复制 <commit>…
承诺恢复。有关拼写提交名称的更完整列表,请参阅 gitrevisions [7] 。也可以给出提交集,但默认情况下不进行遍历,请参阅 git-rev-list [1] 及其--no-walk
选项。
-e
代码语言:javascript复制 --edit
使用此选项, git revert 将允许您在提交恢复之前编辑提交消息。如果从终端运行命令,则这是默认设置。
代码语言:javascript复制 -m parent-number
代码语言:javascript复制 --mainline parent-number
通常,您无法还原合并,因为您不知道合并的哪一侧应被视为主线。此选项指定主线的父编号(从 1 开始),并允许恢复相对于指定父级的更改。
还原合并提交声明您永远不会希望合并带来的树更改。因此,以后的合并只会带来由不是先前还原的合并的祖先的提交引入的树更改。这可能是也可能不是你想要的。
有关详细信息,请参阅 revert-a-faulty-merge How-To 。
代码语言:javascript复制 --no-edit
使用此选项, git revert 将不会启动提交消息编辑器。
代码语言:javascript复制 -n
代码语言:javascript复制 --no-commit
通常,该命令会自动创建一些提交日志消息,提交哪些提交已被还原。此标志应用将命名提交还原到工作树和索引所需的更改,但不进行提交。此外,使用此选项时,索引不必与 HEAD 提交匹配。恢复是针对索引的开始状态完成的。
在将多个提交效果还原到行中的索引时,这非常有用。
代码语言:javascript复制 -S[<keyid>]
代码语言:javascript复制 --gpg-sign[=<keyid>]
GPG 签名提交。 keyid
参数是可选的,默认为提交者标识;如果指定,它必须粘在没有空格的选项上。
-s
代码语言:javascript复制 --signoff
在提交消息的末尾添加 Sign-by-by 行。有关详细信息,请参阅 git-commit [1] 中的签收选项。
代码语言:javascript复制 --strategy=<strategy>
使用给定的合并策略。应该只使用一次。有关详细信息,请参阅 git-merge [1] 中的 MERGE STRATEGIES 部分。
代码语言:javascript复制 -X<option>
代码语言:javascript复制 --strategy-option=<option>
将合并策略特定选项传递给合并策略。有关详细信息,请参阅 git-merge [1] 。
SEQUENCER SUBCOMMANDS
代码语言:javascript复制 --continue
使用 .git / sequencer 中的信息继续进行中的操作。可以在解决失败的挑选或恢复中的冲突后继续使用。
代码语言:javascript复制 --quit
忘记当前正在进行的操作。在樱桃挑选或恢复失败后,可用于清除顺序器状态。
代码语言:javascript复制 --abort
取消操作并返回到预序列状态。
例子
代码语言:javascript复制 git revert HEAD~3
还原 HEAD 中第四个最后一次提交所指定的更改,并使用还原的更改创建一个新提交。
代码语言:javascript复制 git revert -n master~5..master~2
将提交所做的更改从 master(包含)中的第五个最后一次提交恢复到 master(包含)中的第三个最后一次提交,但不要使用还原的更改创建任何提交。恢复仅修改工作树和索引。
也可以看看
git-cherry-pick [1]
GIT
部分 git [1] 套件
git-bisect
原文:
git-scm.com/docs/git-bisect
名称
git-bisect - 使用二进制搜索来查找引入错误的提交
概要
代码语言:javascript复制git bisect <subcommand> <options>
描述
该命令采用各种子命令,并根据子命令使用不同的选项:
代码语言:javascript复制git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
[--no-checkout] [<bad> [<good>...]] [--] [<paths>...]
git bisect (bad|new|<term-new>) [<rev>]
git bisect (good|old|<term-old>) [<rev>...]
git bisect terms [--term-good | --term-bad]
git bisect skip [(<rev>|<range>)...]
git bisect reset [<commit>]
git bisect (visualize|view)
git bisect replay <logfile>
git bisect log
git bisect run <cmd>...
git bisect help
此命令使用二进制搜索算法来查找项目历史记录中的哪个提交引入了错误。您可以通过首先告诉它已知包含该错误的“错误”提交以及在引入错误之前已知的“良好”提交来使用它。然后git bisect
在这两个端点之间选择一个提交,并询问您所选的提交是“好”还是“坏”。它继续缩小范围,直到找到引入更改的确切提交。
实际上,git bisect
可用于查找更改项目任何属性的提交;例如,修复错误的提交,或导致基准测试性能提高的提交。为了支持这种更普遍的用法,可以使用术语“旧”和“新”代替“好”和“坏”,或者您可以选择自己的术语。有关详细信息,请参阅下面的“替代术语”部分。
基本的 bisect 命令:start,bad,good
例如,假设您正在尝试查找破坏已知在项目的版本v2.6.13-rc2
中工作的功能的提交。您按如下方式启动 bisect 会话:
$ git bisect start
$ git bisect bad # Current version is bad
$ git bisect good v2.6.13-rc2 # v2.6.13-rc2 is known to be good
一旦指定了至少一个错误提交和一个良好提交,git bisect
会在该历史记录范围的中间选择一个提交,将其检出并输出类似于以下内容的内容:
Bisecting: 675 revisions left to test after this (roughly 10 steps)
您现在应该编译已签出的版本并对其进行测试。如果该版本正常工作,请键入
代码语言:javascript复制$ git bisect good
如果该版本被破坏,请键入
代码语言:javascript复制$ git bisect bad
那么git bisect
会回复类似的东西
Bisecting: 337 revisions left to test after this (roughly 9 steps)
继续重复这个过程:编译树,测试它,并根据它是好是运行git bisect good
或git bisect bad
来请求下一个需要测试的提交。
最终将不再需要检查修改,命令将打印出第一个错误提交的描述。引用refs/bisect/bad
将指向该提交。
Bisect 重置
在 bisect 会话之后,要清除二分状态并返回到原始 HEAD,请发出以下命令:
代码语言:javascript复制$ git bisect reset
默认情况下,这会将您的树返回到git bisect start
之前签出的提交。 (一个新的git bisect start
也会这样做,因为它清理旧的二分状态。)
使用可选参数,您可以返回另一个提交:
代码语言:javascript复制$ git bisect reset <commit>
例如,git bisect reset bisect/bad
将检出第一个错误修订,而git bisect reset HEAD
将使您进入当前二等分提交并避免切换提交。
替代术语
有时你不是在寻找引入破坏的提交,而是寻找导致其他“旧”状态和“新”状态之间发生变化的提交。例如,您可能正在寻找引入特定修复的提交。或者您可能正在寻找第一个提交,其中源代码文件名最终都转换为您公司的命名标准。管他呢。
在这种情况下,使用“好”和“坏”这两个词来表示“改变前的状态”和“改变后的状态”可能会非常混乱。因此,您可以分别使用术语“旧”和“新”来代替“好”和“坏”。 (但请注意,您不能在单个会话中将“好”和“坏”与“旧”和“新”混合在一起。)
在这个更一般的用法中,您为git bisect
提供了一个“新”提交,它具有一些属性和一个没有该属性的“旧”提交。每次git bisect
签出提交时,您都会测试该提交是否具有该属性。如果是,请将提交标记为“新”;否则,将其标记为“旧”。完成二分时,git bisect
将报告引入该属性的提交。
要使用“旧”和“新”而不是“好”和坏,您必须运行git bisect start
而不提交参数,然后运行以下命令来添加提交:
git bisect old [<rev>]
表示提交是在寻求更改之前,或
代码语言:javascript复制git bisect new [<rev>...]
表明它是在之后。
要获取当前使用的术语的提醒,请使用
代码语言:javascript复制git bisect terms
您可以使用git bisect terms --term-old
或git bisect terms --term-good
获得旧的(分别为新的)术语。
如果您想使用自己的术语而不是“坏”/“好”或“新”/“旧”,您可以选择任何您喜欢的名称(现有的 bisect 子命令除外,如reset
,start
,… )通过使用开始二分
git bisect start --term-old <term-old> --term-new <term-new>
例如,如果您正在寻找引入性能回归的提交,则可以使用
代码语言:javascript复制git bisect start --term-old fast --term-new slow
或者,如果您正在寻找修复错误的提交,您可以使用
代码语言:javascript复制git bisect start --term-new fixed --term-old broken
然后,使用git bisect <term-old>
和git bisect <term-new>
代替git bisect good
和git bisect bad
来标记提交。
Bisect 可视化/查看
要查看 gitk 中当前剩余的嫌疑人,请在二分过程中发出以下命令(子命令view
可用作visualize
的替代):
$ git bisect visualize
如果未设置DISPLAY
环境变量,则使用 git log 。您还可以提供命令行选项,如-p
和--stat
。
$ git bisect visualize --stat
Bisect 日志和平分重播
将标记的修订标记为好或坏后,发出以下命令以显示到目前为止已完成的操作:
代码语言:javascript复制$ git bisect log
如果发现在指定修订的状态时出错,可以将此命令的输出保存到文件,编辑它以删除不正确的条目,然后发出以下命令以返回到已更正的状态:
代码语言:javascript复制$ git bisect reset
$ git bisect replay that-file
避免测试提交
如果在 bisect 会话的中间,你知道建议的修订版不是一个好的测试版(例如它无法构建,你知道失败与你正在追逐的 bug 没有任何关系),你可以手动选择附近的提交并测试该提交。
例如:
代码语言:javascript复制$ git bisect good/bad # previous round was good or bad.
Bisecting: 337 revisions left to test after this (roughly 9 steps)
$ git bisect visualize # oops, that is uninteresting.
$ git reset --hard HEAD~3 # try 3 revisions before what
# was suggested
然后编译并测试所选的修订版,然后以通常的方式将修订版标记为好或坏。
Bisect 跳过
您可以通过发出命令让 Git 为您执行此操作,而不是自己选择附近的提交:
代码语言:javascript复制$ git bisect skip # Current version cannot be tested
但是,如果你跳过与你正在寻找的提交相邻的提交,Git 将无法准确地确定哪些提交是第一个提交。
您还可以使用范围表示法跳过一系列提交,而不是一次提交。例如:
代码语言:javascript复制$ git bisect skip v2.5..v2.6
这告诉 bisect 进程在v2.5
之后,直到并包括v2.6
,都不应该进行提交。
请注意,如果您还想跳过范围的第一次提交,您将发出命令:
代码语言:javascript复制$ git bisect skip v2.5 v2.5..v2.6
这告诉 bisect 进程应该跳过v2.5
和v2.6
(包括)之间的提交。
通过提供更多参数来平分开始来减少二分
通过在发出bisect start
命令时指定路径参数,如果您知道要跟踪的问题涉及树的哪一部分,则可以进一步减少试验次数:
$ git bisect start -- arch/i386 include/asm-i386
如果您事先知道多个好的提交,则可以通过在发出bisect start
命令时在错误提交后立即指定所有良好提交来缩小平分空间:
$ git bisect start v2.6.20-rc6 v2.6.20-rc4 v2.6.20-rc1 --
# v2.6.20-rc6 is bad
# v2.6.20-rc4 and v2.6.20-rc1 are good
Bisect 运行
如果您有一个可以判断当前源代码是好还是坏的脚本,您可以通过发出命令来平分:
代码语言:javascript复制$ git bisect run my_script arguments
请注意,如果当前源代码是好/旧,则脚本(上例中的my_script
)应该以代码 0 退出,如果当前源代码是当前源代码,则退出时使用 1 到 127(含)之间的代码(125 除外)。坏/新。
任何其他退出代码都将中止 bisect 进程。应该注意的是,通过exit(-1)
终止的程序会留下$? = 255,(参见 exit(3)手册页),因为该值被& 0377
切断。
当无法测试当前源代码时,应使用特殊退出代码 125。如果脚本以此代码退出,则将跳过当前修订(请参阅上面的git bisect skip
)。选择 125 作为用于此目的的最高敏感值,因为 POSIX shell 使用 126 和 127 来指示特定的错误状态(127 表示未找到命令,126 表示找到命令但不可执行 - 这些详细信息不问题,因为它们是脚本中的正常错误,就bisect run
而言。
您可能经常发现在二等分会话期间您希望进行临时修改(例如,s / #define DEBUG 0 / #define DEBUG 1 /在头文件中,或者“没有此提交的修订版需要将此修补程序应用于解决方法另一个问题是这个二分法对于应用于被测试的修订版不感兴趣。
为了应对这种情况,在内部 git bisect 找到要测试的下一个修订版之后,脚本可以在编译之前应用补丁,运行真实测试,然后决定是否修改(可能需要修改) patch)通过了测试,然后将树倒回到原始状态。最后,脚本应该以实际测试的状态退出,让git bisect run
命令循环确定 bisect 会话的最终结果。
OPTIONS
代码语言:javascript复制 --no-checkout
不要在二分过程的每次迭代中签出新的工作树。相反,只需更新名为BISECT_HEAD
的特殊引用,使其指向应测试的提交。
当您在每个步骤中执行的测试不需要签出树时,此选项可能很有用。
如果存储库是裸的,则假定为--no-checkout
。
例子
在 v1.2 和 HEAD 之间自动平分破坏的构建:
代码语言:javascript复制$ git bisect start HEAD v1.2 -- # HEAD is bad, v1.2 is good
$ git bisect run make # "make" builds the app
$ git bisect reset # quit the bisect session
自动平分原点和 HEAD 之间的测试失败:
代码语言:javascript复制$ git bisect start HEAD origin -- # HEAD is bad, origin is good
$ git bisect run make test # "make test" builds and tests
$ git bisect reset # quit the bisect session
自动将破坏的测试用例一分为二:
代码语言:javascript复制$ cat ~/test.sh
#!/bin/sh
make || exit 125 # this skips broken builds
~/check_test_case.sh # does the test case pass?
$ git bisect start HEAD HEAD~10 -- # culprit is among the last 10
$ git bisect run ~/test.sh
$ git bisect reset # quit the bisect session
这里我们使用test.sh
自定义脚本。在此脚本中,如果make
失败,我们将跳过当前提交。如果测试用例通过,check_test_case.sh
应为exit 0
,否则为exit 1
。
如果test.sh
和check_test_case.sh
都在存储库之外,以防止 bisect,make 和测试进程与脚本之间的交互,则更安全。
通过临时修改自动平分(热修复):
代码语言:javascript复制$ cat ~/test.sh
#!/bin/sh
# tweak the working tree by merging the hot-fix branch
# and then attempt a build
if git merge --no-commit hot-fix &&
make
then
# run project specific test and report its status
~/check_test_case.sh
status=$?
else
# tell the caller this is untestable
status=125
fi
# undo the tweak to allow clean flipping to the next commit
git reset --hard
# return control
exit $status
这在每次测试运行之前应用来自热修复分支的修改,例如,如果你的构建或测试环境发生了变化,那么旧版本可能需要修复已经更新的版本。 (确保热修复分支基于您正在二等分的所有修订中包含的提交,以便合并不会过多,或使用git cherry-pick
而不是git merge
。)
自动将破坏的测试用例一分为二:
代码语言:javascript复制$ git bisect start HEAD HEAD~10 -- # culprit is among the last 10
$ git bisect run sh -c "make || exit 125; ~/check_test_case.sh"
$ git bisect reset # quit the bisect session
这表明如果在单行上编写测试,则可以不使用运行脚本。
在损坏的存储库中找到对象图的良好区域
代码语言:javascript复制$ git bisect start HEAD <known-good-commit> [ <boundary-commit> ... ] --no-checkout
$ git bisect run sh -c '
GOOD=$(git for-each-ref "--format=%(objectname)" refs/bisect/good-*) &&
git rev-list --objects BISECT_HEAD --not $GOOD >tmp.$$ &&
git pack-objects --stdout >/dev/null <tmp.$$
rc=$?
rm -f tmp.$$
test $rc = 0'
$ git bisect reset # quit the bisect session
在这种情况下,当 git bisect run 结束时,bisect / bad 将引用具有至少一个父级的提交,其父级的可访问图形在 _git pack 对象 _ 所需的意义上是完全可遍历的。
在代码中寻找修复而不是回归
代码语言:javascript复制$ git bisect start
$ git bisect new HEAD # current commit is marked as new
$ git bisect old HEAD~10 # the tenth commit from now is marked as old
要么:
代码语言:javascript复制$ git bisect start --term-old broken --term-new fixed
$ git bisect fixed
$ git bisect broken HEAD~10
获得帮助
使用git bisect
获取简短的使用说明,使用git bisect help
或git bisect -h
获取长使用说明。
也可以看看
用 git bisect , git-blame [1] 对抗回归。
GIT
部分 git [1] 套件
git-blame
原文:
git-scm.com/docs/git-blame
名称
git-blame - 显示修改版本和作者上次修改文件的每一行
概要
代码语言:javascript复制git blame [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-e] [-p] [-w] [--incremental]
[-L <range>] [-S <revs-file>] [-M] [-C] [-C] [-C] [--since=<date>]
[--progress] [--abbrev=<n>] [<rev> | --contents <file> | --reverse <rev>..<rev>]
[--] <file>
描述
使用最后修改该行的修订版中的信息注释给定文件中的每一行。 (可选)从给定修订开始注释。
当指定一次或多次时,-L
将注释限制为所请求的行。
在整个文件重命名中自动跟踪行的原点(目前没有选项可以关闭重命名 - 关闭)。要跟踪从一个文件移动到另一个文件的行,或跟踪从另一个文件复制和粘贴的行等,请参阅-C
和-M
选项。
该报告没有告诉您有关已删除或替换的行的任何信息;您需要使用 git diff 等工具或以下段落中简要提到的“pickaxe”界面。
除了支持文件注释之外,Git 还支持在更改中发生代码片段时搜索开发历史记录。这使得可以跟踪何时将代码片段添加到文件,在文件之间移动或复制,最终删除或替换。它的工作原理是在 diff 中搜索文本字符串。搜索blame_usage
的 pickaxe 接口的一个小例子:
$ git log --pretty=oneline -S'blame_usage'
5040f17eba15504bad66b14a645bddd9b015ebb7 blame -S <ancestry-file>
ea4c7f9bf69e781dd0cd88d2bccb2bf5cc15c9a7 git-blame: Make the output
OPTIONS
代码语言:javascript复制 -b
为边界提交显示空白 SHA-1。这也可以通过blame.blankboundary
配置选项进行控制。
--root
不要将 root 提交视为边界。这也可以通过blame.showRoot
配置选项进行控制。
--show-stats
在非责任输出结束时包括其他统计数据。
代码语言:javascript复制 -L <start>,<end>
代码语言:javascript复制 -L :<funcname>
仅注释给定的行范围。可以多次指定。允许重叠范围。
<开始>和< end>是可选的。 “-L< start>”或“-L< start>”跨越< start>到文件结束。 “-L,< end>”从文件开头跨越到< end>。
<开始>和< end>可以采取以下形式之一:
- 数 如果< start>或者< end>是一个数字,它指定一个绝对行号(行数从 1 开始)。
- /正则表达式/
此表单将使用与给定 POSIX 正则表达式匹配的第一行。如果< start>是一个正则表达式,它将从前一个
-L
范围的末尾搜索,如果有的话,否则从文件的开头搜索。如果< start>是“^ / regex /”,它将从文件的开头搜索。如果< end>是一个正则表达式,它将从< start>给出的行开始搜索。 -
- offset 或-offset
这仅适用于< end>并将在< start>给出的行之前或之后指定行数。
如果给出“:< funcname>”代替< start>和< end>,它是一个正则表达式,表示从匹配< funcname>的第一个 funcname 行到下一个 funcname 行的范围。 “:< funcname>”从上一个-L
范围的末尾搜索(如果有的话),否则从文件的开头搜索。 “^:< funcname>”从文件的开头搜索。
-l
显示长转速(默认值:关闭)。
代码语言:javascript复制 -t
显示原始时间戳(默认值:关闭)。
代码语言:javascript复制 -S <revs-file>
使用 revs-file 的修订而不是调用 git-rev-list [1] 。
代码语言:javascript复制 --reverse <rev>..<rev>
走向历史而不是落后。这不显示出现一行的修订,而是显示一行存在的最后修订版。这需要一系列的修订,如 START…END,其中指责路径存在于 START 中。为方便起见,git blame --reverse START
被视为git blame --reverse START..HEAD
。
-p
代码语言:javascript复制 --porcelain
以专为机器消耗而设计的格式显示。
代码语言:javascript复制 --line-porcelain
显示瓷器格式,但输出每行的提交信息,而不仅仅是第一次引用提交。意思是 - 瓷器。
代码语言:javascript复制 --incremental
以设计用于机器消耗的格式逐步显示结果。
代码语言:javascript复制 --encoding=<encoding>
指定用于输出作者姓名和提交摘要的编码。将其设置为none
会使非责任输出非转换数据。有关更多信息,请参阅 git-log [1] 手册页中有关编码的讨论。
--contents <file>
当< rev>如果未指定,该命令将从工作树副本开始向后注释更改。此标志使命令假装工作树副本具有指定文件的内容(指定-
以使命令从标准输入读取)。
--date <format>
指定用于输出日期的格式。如果未提供–date,则使用 blame.date 配置变量的值。如果未设置 blame.date 配置变量,则使用 iso 格式。有关支持的值,请参阅 git-log [1] 中–date 选项的讨论。
代码语言:javascript复制 --[no-]progress
默认情况下,当连接到终端时,会在标准错误流上报告进度状态。即使没有附加到终端,该标志也可以进行进度报告。不能将--progress
与--porcelain
或--incremental
一起使用。
-M[<num>]
检测文件中移动或复制的行。当提交移动或复制一行行(例如原始文件有 A 然后是 B,并且提交将其更改为 B 然后 A)时,传统的 _ 指责 _ 算法仅注意到一半的移动和通常会将向上移动(即 B)的行归咎于父级,并将责任归咎于向下移动(即 A)到子提交的行。使用此选项,两组行都通过运行额外的检查通道归咎于父组。
< NUM>是可选的,但它是字母数字字符数的下限,Git 必须在文件中检测为移动/复制,以便将这些行与父提交相关联。默认值为 20。
代码语言:javascript复制 -C[<num>]
除-M
外,检测从同一提交中修改的其他文件移动或复制的行。当您重新组织程序并跨文件移动代码时,这非常有用。当此选项被给出两次时,该命令还会在创建文件的提交中查找其他文件的副本。当此选项被给出三次时,该命令还会在任何提交中查找来自其他文件的副本。
< NUM>是可选的,但它是字母数字字符数的下限,Git 必须检测它们在文件之间移动/复制,以便将这些行与父提交相关联。并且默认值为 40.如果给出多个-C
选项,则< num>最后一个-C
的参数将生效。
-h
显示帮助信息。
代码语言:javascript复制 -c
使用与 git-annotate [1] 相同的输出模式(默认值:关闭)。
代码语言:javascript复制 --score-debug
包括与文件之间的行移动相关的调试信息(参见-C
)和文件中移动的行(参见-M
)。列出的第一个数字是分数。这是检测为在文件之间或文件内移动的字母数字字符数。这必须高于 git blame 的某个阈值才能考虑那些代码行被移动。
-f
代码语言:javascript复制 --show-name
在原始提交中显示文件名。默认情况下,如果由于重命名检测而存在来自具有不同名称的文件的任何行,则会显示文件名。
代码语言:javascript复制 -n
代码语言:javascript复制 --show-number
显示原始提交中的行号(默认值:关闭)。
代码语言:javascript复制 -s
从输出中抑制作者姓名和时间戳。
代码语言:javascript复制 -e
代码语言:javascript复制 --show-email
显示作者电子邮件而不是作者姓名(默认值:关闭)。这也可以通过blame.showEmail
配置选项进行控制。
-w
在比较父版本和子版本时忽略空格以查找行的来源。
代码语言:javascript复制 --abbrev=<n>
不使用默认的 7 1 十六进制数字作为缩写对象名称,而是使用< n> 1 位数。请注意,1 列用于标记边界提交的插入符号。
瓷器格式
在这种格式中,每一行都在标题之后输出;最小的标题有第一行有:
- 该行所属的提交的 40 字节 SHA-1;
- 原始文件中行的行号;
- 最终文件中行的行号;
- 在一行中,该行从与前一个提交不同的提交开始一组行,即该组中的行数。在后续行中,该字段不存在。
对于每个提交,此标题行后面至少跟随以下信息一次:
- 作者姓名(“作者”),电子邮件(“作者邮件”),时间(“作者时间”)和时区(“author-tz”);类似的提交者。
- 提交行中的文件名。
- 提交日志消息的第一行(“摘要”)。
在上面的标题之后输出实际行的内容,以 TAB 为前缀。这是为了允许稍后添加更多标题元素。
瓷器格式通常会抑制已经看到的提交信息。例如,将显示归咎于同一提交的两行,但该提交的详细信息将仅显示一次。这样更有效,但可能需要读者保留更多状态。 --line-porcelain
选项可用于输出每行的完整提交信息,从而允许更简单(但效率更低)的用法,例如:
# count the number of lines attributed to each author
git blame --line-porcelain file |
sed -n 's/^author //p' |
sort | uniq -c | sort -rn
指定范围
与旧版本的 git 中的 git blame 和 _git 注释 _ 不同,注释的范围可以限制为行范围和修订范围。可以多次指定-L
选项,该选项将注释限制为一系列线。
当你有兴趣找到文件foo
的第 40-60 行的原点时,你可以像这样使用-L
选项(它们的意思相同 - 从第 40 行开始要求 21 行):
git blame -L 40,60 foo
git blame -L 40, 21 foo
您还可以使用正则表达式指定行范围:
代码语言:javascript复制git blame -L '/^sub hello {/,/^}$/' foo
它将注释限制在hello
子程序的主体上。
如果您对版本低于 v2.6.18 的更改或对 3 周以上的更改不感兴趣,则可以使用与 git rev-list 类似的修订版本说明符:
代码语言:javascript复制git blame v2.6.18.. -- foo
git blame --since=3.weeks -- foo
当修订范围说明符用于限制注释时,自范围边界以来没有更改的行(在上面的示例中,提交 v2.6.18 或超过 3 周的最近提交)被归咎于该范围边界承诺。
一种特别有用的方法是查看添加的文件是否具有通过现有文件的复制和粘贴创建的行。有时这表明开发人员很草率,并没有正确地重构代码。您可以先找到引入该文件的提交:
代码语言:javascript复制git log --diff-filter=A --pretty=short -- foo
然后使用commit^!
表示法注释提交及其父项之间的更改:
git blame -C -C -f $commit^! -- foo
增量输出
使用--incremental
选项调用时,该命令会在构建时输出结果。输出通常将首先谈论最近提交所触及的行(即,行将不按顺序注释)并且意图由交互式观看者使用。
输出格式类似于 Porcelain 格式,但它不包含正在注释的文件中的实际行。
每个责备条目始终以以下行开头:
代码语言:javascript复制<40-byte hex sha1> <sourceline> <resultline> <num_lines>
行号从 1 开始计算。
第一次提交显示在流中时,它有各种其他有关它的信息,在每行的开头打印出一个单词标记,描述额外的提交信息(作者,电子邮件,提交者,日期,摘要等) )。
与 Porcelain 格式不同,始终给出文件名信息并终止条目:
代码语言:javascript复制"filename" <whitespace-quoted-filename-goes-here>
因此,解析一些面向字和字的解析器(对于大多数脚本语言来说应该很自然)非常容易。
| 注意 | 对于进行解析的人:为了使其更加健壮,只需忽略第一个和最后一个(“< sha1>”和“filename”行)之间的任何行,在这些行中您无法识别标记词(或关注那个特定的词) )在“扩展信息”行的开头。这样,如果有添加的信息(如提交编码或扩展提交注释),责备查看器将无关紧要。 |
映射作者
如果文件.mailmap
存在于存储库的顶层,或者位于 mailmap.file 或 mailmap.blob 配置选项所指向的位置,则它用于将作者和提交者名称以及电子邮件地址映射到规范的真实姓名和电子邮件地址。
在简单形式中,文件中的每一行都包含作者的规范实名,空格和提交中使用的电子邮件地址(由 < 和 > 括起来)映射到名称。例如:
代码语言:javascript复制Proper Name <commit@email.xx>
更复杂的形式是:
代码语言:javascript复制<proper@email.xx> <commit@email.xx>
允许 mailmap 仅替换提交的电子邮件部分,并且:
代码语言:javascript复制Proper Name <proper@email.xx> <commit@email.xx>
它允许 mailmap 替换与指定的提交电子邮件地址匹配的提交的名称和电子邮件,并且:
代码语言:javascript复制Proper Name <proper@email.xx> Commit Name <commit@email.xx>
它允许 mailmap 替换与指定的提交名称和电子邮件地址匹配的提交的名称和电子邮件。
示例 1:您的历史记录包含两位作者 Jane 和 Joe 的提交,其名称以多种形式出现在存储库中:
代码语言:javascript复制Joe Developer <joe@example.com>
Joe R. Developer <joe@example.com>
Jane Doe <jane@example.com>
Jane Doe <jane@laptop.(none)>
Jane D. <jane@desktop.(none)>
现在假设 Joe 希望他的中间名最初使用,而 Jane 更喜欢她的姓氏完全拼写出来。一个合适的.mailmap
文件看起来像:
Jane Doe <jane@desktop.(none)>
Joe R. Developer <joe@example.com>
注意如何不需要<jane@laptop.(none)>
的条目,因为该作者的真实姓名已经正确。
示例 2:您的存储库包含以下作者的提交:
代码语言:javascript复制nick1 <bugs@company.xx>
nick2 <bugs@company.xx>
nick2 <nick2@company.xx>
santa <me@company.xx>
claus <me@company.xx>
CTO <cto@coompany.xx>
然后你可能想要一个看起来像这样的.mailmap
文件:
<cto@company.xx> <cto@coompany.xx>
Some Dude <some@dude.xx> nick1 <bugs@company.xx>
Other Author <other@author.xx> nick2 <bugs@company.xx>
Other Author <other@author.xx> <nick2@company.xx>
Santa Claus <santa.claus@northpole.xx> <me@company.xx>
将哈希 # 用于自己的行或电子邮件地址之后的注释。
也可以看看
git-annotate [1]
GIT
部分 git [1] 套件
git-grep
原文:
git-scm.com/docs/git-grep
名称
git-grep - 打印与图案匹配的线条
概要
代码语言:javascript复制git grep [-a | --text] [-I] [--textconv] [-i | --ignore-case] [-w | --word-regexp]
[-v | --invert-match] [-h|-H] [--full-name]
[-E | --extended-regexp] [-G | --basic-regexp]
[-P | --perl-regexp]
[-F | --fixed-strings] [-n | --line-number] [--column]
[-l | --files-with-matches] [-L | --files-without-match]
[(-O | --open-files-in-pager) [<pager>]]
[-z | --null]
[ -o | --only-matching ] [-c | --count] [--all-match] [-q | --quiet]
[--max-depth <depth>] [--[no-]recursive]
[--color[=<when>] | --no-color]
[--break] [--heading] [-p | --show-function]
[-A <post-context>] [-B <pre-context>] [-C <context>]
[-W | --function-context]
[--threads <num>]
[-f <file>] [-e] <pattern>
[--and|--or|--not|(|)|-e <pattern>…]
[--recurse-submodules] [--parent-basename <basename>]
[ [--[no-]exclude-standard] [--cached | --no-index | --untracked] | <tree>…]
[--] [<pathspec>…]
描述
在工作树中的跟踪文件中查找指定的模式,在索引文件中注册的 blob 或给定树对象中的 blob。模式是由换行符分隔的一个或多个搜索表达式的列表。搜索表达式匹配所有行的空字符串。
组态
代码语言:javascript复制 grep.lineNumber
如果设置为 true,则默认启用-n
选项。
grep.column
如果设置为 true,则默认启用--column
选项。
grep.patternType
设置默认匹配行为。使用 basic ,_ 扩展 , 固定 _ 或 perl 的值将启用--basic-regexp
,--extended-regexp
,--fixed-strings
,或--perl-regexp
选项相应,而值 _ 默认 _ 将返回默认匹配行为。
grep.extendedRegexp
如果设置为 true,则默认启用--extended-regexp
选项。当grep.patternType
选项设置为 _ 默认值 _ 以外的值时,将忽略此选项。
grep.threads
要使用的 grep 工作线程数。如果未设置(或设置为 0),则默认使用 8 个线程(暂时)。
代码语言:javascript复制 grep.fullName
如果设置为 true,则默认启用--full-name
选项。
grep.fallbackToNoIndex
如果设置为 true,如果 git grep 在 git 存储库之外执行,则回退到 git grep --no-index。默认为 false。
OPTIONS
代码语言:javascript复制 --cached
不是搜索工作树中的跟踪文件,而是搜索索引文件中注册的 blob。
代码语言:javascript复制 --no-index
搜索当前目录中不由 Git 管理的文件。
代码语言:javascript复制 --untracked
除了搜索工作树中的跟踪文件外,还可以搜索未跟踪的文件。
代码语言:javascript复制 --no-exclude-standard
同时通过不遵守.gitignore
机制来搜索被忽略的文件。仅适用于--untracked
。
--exclude-standard
不要注意通过.gitignore
机制指定的忽略文件。仅在使用--no-index
搜索当前目录中的文件时有用。
--recurse-submodules
递归搜索已在存储库中初始化和检出的每个子模块。当与< tree>组合使用时选项所有子模块输出的前缀将是父项目的< tree>的名称。宾语。
代码语言:javascript复制 -a
代码语言:javascript复制 --text
处理二进制文件就像它们是文本一样。
代码语言:javascript复制 --textconv
尊重 textconv 过滤器设置。
代码语言:javascript复制 --no-textconv
不要尊重 textconv 过滤器设置。这是默认值。
代码语言:javascript复制 -i
代码语言:javascript复制 --ignore-case
忽略模式和文件之间的大小写差异。
代码语言:javascript复制 -I
与二进制文件中的模式不匹配。
代码语言:javascript复制 --max-depth <depth>
对于每个< pathspec>在命令行上给出,最多下降< depth>目录级别。值-1 表示没有限制。如果< pathspec&gt ;,则忽略此选项包含活动的通配符。换句话说,如果“a *”匹配名为“a ”的目录,则“”字面匹配,因此–max-depth 仍然有效。
代码语言:javascript复制 -r
代码语言:javascript复制 --recursive
与--max-depth=-1
相同;这是默认值。
--no-recursive
与--max-depth=0
相同。
-w
代码语言:javascript复制 --word-regexp
仅在单词边界处匹配模式(从行的开头开始,或者以非单词字符开头;在行的末尾结束或后跟非单词字符)。
代码语言:javascript复制 -v
代码语言:javascript复制 --invert-match
选择不匹配的行。
代码语言:javascript复制 -h
代码语言:javascript复制 -H
默认情况下,该命令显示每个匹配的文件名。 -h
选项用于抑制此输出。 -H
是完整性的,除了它覆盖了之前在命令行中给出的-h
之外什么都不做。
--full-name
从子目录运行时,该命令通常输出相对于当前目录的路径。此选项强制路径相对于项目顶级目录输出。
代码语言:javascript复制 -E
代码语言:javascript复制 --extended-regexp
代码语言:javascript复制 -G
代码语言:javascript复制 --basic-regexp
使用 POSIX 扩展/基本正则表达式来表示模式。默认是使用基本正则表达式。
代码语言:javascript复制 -P
代码语言:javascript复制 --perl-regexp
对模式使用与 Perl 兼容的正则表达式。
对这些类型的正则表达式的支持是可选的编译时依赖性。如果 Git 没有编译并支持它们,那么提供此选项将导致它死亡。
代码语言:javascript复制 -F
代码语言:javascript复制 --fixed-strings
对模式使用固定字符串(不要将模式解释为正则表达式)。
代码语言:javascript复制 -n
代码语言:javascript复制 --line-number
将行号前缀为匹配行。
代码语言:javascript复制 --column
从匹配行的开头开始对第一个匹配的 1 索引字节偏移进行前缀。
代码语言:javascript复制 -l
代码语言:javascript复制 --files-with-matches
代码语言:javascript复制 --name-only
代码语言:javascript复制 -L
代码语言:javascript复制 --files-without-match
不显示每个匹配的行,而是仅显示包含(或不包含)匹配的文件的名称。为了更好地与 git diff 兼容,--name-only
是--files-with-matches
的同义词。
-O[<pager>]
代码语言:javascript复制 --open-files-in-pager[=<pager>]
打开寻呼机中的匹配文件(不是 grep 的输出)。如果寻呼机恰好是“较少”或“vi”,并且用户仅指定了一个模式,则第一个文件将自动定位在第一个匹配位置。 pager
参数是可选的;如果指定,它必须粘在没有空格的选项上。如果未指定pager
,将使用默认寻呼机(参见 git-config [1] 中的core.pager
)。
-z
代码语言:javascript复制 --null
输出 0 而不是通常在文件名后面的字符。
代码语言:javascript复制 -o
代码语言:javascript复制 --only-matching
仅打印匹配行的匹配(非空)部分,每个此类部分位于单独的输出行上。
代码语言:javascript复制 -c
代码语言:javascript复制 --count
而不是显示每个匹配的行,而是显示匹配的行数。
代码语言:javascript复制 --color[=<when>]
显示彩色火柴。该值必须始终为(默认值),never 或 auto。
代码语言:javascript复制 --no-color
关闭匹配突出显示,即使配置文件提供默认的颜色输出。与--color=never
相同。
--break
在不同文件的匹配项之间打印空行。
代码语言:javascript复制 --heading
在该文件中的匹配项上方显示文件名,而不是在每个显示的行的开头。
代码语言:javascript复制 -p
代码语言:javascript复制 --show-function
显示包含匹配函数名称的上一行,除非匹配行是函数名称本身。名称的确定方式与 git diff 计算出补丁程序块标题的方式相同(参见 _ 在 gitattributes [5] 中定义自定义的 hunk-header_ )。
代码语言:javascript复制 -<num>
代码语言:javascript复制 -C <num>
代码语言:javascript复制 --context <num>
显示< num>前导和尾随行,并在连续的匹配组之间放置包含--
的行。
-A <num>
代码语言:javascript复制 --after-context <num>
显示< num>尾随行,并在连续的匹配组之间放置一行包含--
。
-B <num>
代码语言:javascript复制 --before-context <num>
显示< num>引导线,并在连续的匹配组之间放置包含--
的行。
-W
代码语言:javascript复制 --function-context
显示上一行中包含函数名称的周围文本,直到下一个函数名称之前的文本,有效地显示了找到匹配项的整个函数。
代码语言:javascript复制 --threads <num>
要使用的 grep 工作线程数。有关详细信息,请参见 CONFIGURATION 中的grep.threads
。
-f <file>
从< file>中读取模式,每行一个。
代码语言:javascript复制 -e
下一个参数是模式。此选项必须用于以-
开头的模式,并且应该在将用户输入传递给 grep 的脚本中使用。多个模式由 _ 或 _ 组合。
--and
代码语言:javascript复制 --or
代码语言:javascript复制 --not
代码语言:javascript复制 ( … )
指定如何使用布尔表达式组合多个模式。 --or
是默认运算符。 --and
的优先级高于--or
。 -e
必须用于所有模式。
--all-match
当给出多个模式表达式与--or
组合时,指定此标志以限制匹配到具有匹配所有这些行的行的文件。
-q
代码语言:javascript复制 --quiet
不输出匹配的线;相反,当匹配时退出状态 0,当没有匹配时退出非零状态。
代码语言:javascript复制 <tree>…
不是搜索工作树中的跟踪文件,而是搜索给定树中的 blob。
代码语言:javascript复制 --
表示选项的结束;其余参数是< pathspec>限制器。
代码语言:javascript复制 <pathspec>…
如果给定,则将搜索限制为与至少一个模式匹配的路径。两个前导路径匹配,并支持 glob(7)模式。
有关< pathspec>的详细信息语法,请参阅 gitglossary [7] 中的 pathspec 条目。
例子
代码语言:javascript复制 git grep 'time_t' -- '*.[ch]'
在工作目录及其子目录中的所有跟踪的.c 和.h 文件中查找time_t
。
git grep -e '#define' --and ( -e MAX_PATH -e PATH_MAX )
查找具有#define
和MAX_PATH
或PATH_MAX
的行。
git grep --all-match -e NODE -e Unexpected
在具有与两者匹配的行的文件中查找具有NODE
或Unexpected
的行。
git grep solution -- :^Documentation
查找solution
,不包括Documentation
中的文件。
GIT
部分 git [1] 套件
gitattributes
原文:
git-scm.com/docs/gitattributes
名称
gitattributes - 定义每个路径的属性
概要
$ GIT_DIR / info / attributes,.gitattributes
描述
gitattributes
文件是一个简单的文本文件,它为路径名提供attributes
。
gitattributes
文件中的每一行都是以下形式:
pattern attr1 attr2 ...
也就是说,一个模式后跟一个属性列表,用空格分隔。前导空格和尾随空格被忽略。以 # 开头的行将被忽略。以双引号开头的模式以 C 风格引用。当模式匹配相关路径时,该行上列出的属性将被赋予路径。
对于给定路径,每个属性可以处于以下状态之一:
代码语言:javascript复制 Set
该路径具有特殊值“true”的属性;这是通过仅列出属性列表中属性的名称来指定的。
代码语言:javascript复制 Unset
该路径具有特殊值“false”的属性;这是通过在属性列表中列出前缀为短划线-
的属性的名称来指定的。
Set to a value
该路径具有指定字符串值的属性;这是通过列出属性的名称,后跟等号=
及其在属性列表中的值来指定的。
Unspecified
没有模式匹配路径,没有任何说明路径是否具有属性,路径的属性被称为未指定。
当多个模式与路径匹配时,后一行会覆盖较早的行。这个覆盖是按属性完成的。
模式匹配路径的规则与.gitignore
文件中的规则相同(参见 gitignore [5] ),但有一些例外:
- 消极的模式被禁止
- 与目录匹配的模式不会递归地匹配该目录中的路径(因此在属性文件中使用尾部斜杠
path/
语法是没有意义的;使用path/**
代替)
在确定为路径分配了哪些属性时,Git 会查询$GIT_DIR/info/attributes
文件(具有最高优先级),.gitattributes
文件与相关路径位于同一目录中,其父目录最多为工作树的顶层(包含.gitattributes
的目录越远离有问题的路径,其优先级越低)。最后考虑全局和系统范围的文件(它们具有最低优先级)。
当工作树中缺少.gitattributes
文件时,索引中的路径将用作后退。在检出过程中,使用索引中的.gitattributes
,然后将工作树中的文件用作后备。
如果您希望仅影响单个存储库(即,将属性分配给特定于该存储库的一个用户工作流的文件),则应将属性放在GIT_DIR/info/attributes文件中。应该由版本控制并分发到其他存储库的属性(即,所有用户感兴趣的属性)应该进入.gitattributes文件。应该影响单个用户的所有存储库的属性应该放在由core.attributesFile配置选项指定的文件中(参见 git-config [1] )。其默认值为 XDG_CONFIG_HOME / git / attributes。如果 XDG_CONFIG_HOME 未设置或为空,则使用 HOME / .config / git / attributes。系统中所有用户的属性应放在
有时您需要覆盖Unspecified
状态路径的属性设置。这可以通过列出前缀为感叹号!
的属性的名称来完成。
影响
通过为路径分配特定属性可以影响 Git 的某些操作。目前,以下操作是属性感知的。
退房和登记入住
当 git checkout 和 git merge 等命令运行时,这些属性会影响存储库中存储的内容如何复制到工作树文件。它们还会影响 Git 如何在 git add 和 git commit 中存储您在存储库中的工作树中准备的内容。
text
此属性启用并控制行尾标准化。对文本文件进行规范化后,其行结尾将在存储库中转换为 LF。要控制工作目录中使用的行结束样式,请对单个文件使用eol
属性,对所有文本文件使用core.eol
配置变量。请注意,将core.autocrlf
设置为true
或input
会覆盖core.eol
(请参阅 git-config [1] 中这些选项的定义)。
Set
在路径上设置text
属性可启用行尾标准化,并将路径标记为文本文件。在不猜测内容类型的情况下进行行尾转换。
Unset
取消设置路径上的text
属性会告诉 Git 在签入或结帐时不要尝试任何行尾转换。
Set to string value "auto"
当text
设置为“auto”时,路径将标记为自动行结束转换。如果 Git 决定内容是文本,则其行结尾将在签入时转换为 LF。使用 CRLF 提交文件时,不会进行任何转换。
Unspecified
如果未指定text
属性,Git 使用core.autocrlf
配置变量来确定是否应转换文件。
任何其他值都会导致 Git 表现为好像没有指定text
。
eol
此属性设置要在工作目录中使用的特定行结束样式。它可以在没有任何内容检查的情况下实现行尾转换,从而有效地设置text
属性。请注意,在具有 CRLF 行结尾的索引中的路径上设置此属性可能会使路径被视为脏。再次将索引添加到索引将规范化索引中的行结尾。
Set to string value "crlf"
此设置强制 Git 在签入时规范化此文件的行结尾,并在签出文件时将它们转换为 CRLF。
代码语言:javascript复制 Set to string value "lf"
此设置强制 Git 在签入时将行结尾标准化为 LF,并在签出文件时阻止转换为 CRLF。
向后兼容crlf
属性
为了向后兼容,crlf
属性解释如下:
crlf text
-crlf -text
crlf=input eol=lf
行尾转换
虽然 Git 通常单独保留文件内容,但可以将其配置为将行结尾标准化为存储库中的 LF,并且可选地,在检出文件时将它们转换为 CRLF。
如果您只想在工作目录中使用 CRLF 行结尾,而不管您正在使用哪个存储库,则可以设置配置变量“core.autocrlf”而不使用任何属性。
代码语言:javascript复制[core]
autocrlf = true
这不会强制文本文件的规范化,但确保引入存储库的文本文件在添加时将其行结尾标准化为 LF,并且已在存储库中标准化的文件保持规范化。
如果要确保任何贡献者引入存储库的文本文件的行结束标准化,可以将 _ 所有 _ 文件的text
属性设置为“auto”。
* text=auto
这些属性允许细粒度控制,如何转换行结尾。下面是一个示例,它将使 Git 规范化.txt,.vcproj 和.sh 文件,确保.vcproj 文件的 CRLF 和.sh 文件在工作目录中具有 LF,并防止.jpg 文件无论其内容如何都被规范化。
代码语言:javascript复制* text=auto
*.txt text
*.vcproj text eol=crlf
*.sh text eol=lf
*.jpg -text
| 注意 | 使用推送和拉到中央存储库的跨平台项目中启用text=auto
转换时,应对包含 CRLF 的文本文件进行规范化。 |
从干净的工作目录:
代码语言:javascript复制$ echo "* text=auto" >.gitattributes
$ git add --renormalize .
$ git status # Show files that will be normalized
$ git commit -m "Introduce end-of-line normalization"
如果任何不应归一化的文件出现在 git status 中,请在运行 git add -u 之前取消设置text
属性。
manual.pdf -text
相反,Git 未检测到的文本文件可以手动启用规范化。
代码语言:javascript复制weirdchars.txt text
如果core.safecrlf
设置为“true”或“warn”,Git 将验证当前设置core.autocrlf
的转换是否可逆。对于“真实”,Git 拒绝不可逆转的转换;对于“警告”,Git 仅打印警告但接受不可逆转的转换。安全触发器可以防止对工作树中的文件进行此类转换,但也有一些例外情况。即使…
- git add 本身不会触及工作树中的文件,下次检出就会,所以安全触发器;
- git apply 用补丁更新文本文件确实触摸了工作树中的文件,但操作是关于文本文件而 CRLF 转换是关于修复行结尾不一致的,所以安全性不会触发;
- git diff 本身不会触及工作树中的文件,它经常运行以检查你打算下一步的更改 git add 。为了及早发现潜在问题,安全触发。
working-tree-encoding
Git 将以 ASCII 或其中一个超集(例如 UTF-8,ISO-8859-1,…)编码的文件识别为文本文件。以某些其他编码(例如 UTF-16)编码的文件被解释为二进制文件,因此内置的 Git 文本处理工具(例如 git diff )以及大多数 Git web 前端都无法显示内容默认情况下这些文件。
在这些情况下,您可以使用working-tree-encoding
属性告诉 Git 工作目录中文件的编码。如果将具有此属性的文件添加到 Git,则 Git 会将指定编码的内容重新编码为 UTF-8。最后,Git 将 UTF-8 编码内容存储在其内部数据结构中(称为“索引”)。在结帐时,内容将重新编码回指定的编码。
请注意,使用working-tree-encoding
属性可能会有一些陷阱:
- 替代 Git 实现(例如 JGit 或 libgit2)和较旧的 Git 版本(截至 2018 年 3 月)不支持
working-tree-encoding
属性。如果决定使用存储库中的working-tree-encoding
属性,则强烈建议确保使用存储库的所有客户端都支持它。 例如,Microsoft Visual Studio 资源文件(*.rc
)或 PowerShell 脚本文件(*.ps1
)有时以 UTF-16 编码。如果将*.ps1
声明为 UTF-16 文件并添加foo.ps1
并启用working-tree-encoding
Git 客户端,则foo.ps1
将在内部存储为 UTF-8。没有working-tree-encoding
支持的客户端将foo.ps1
签出为 UTF-8 编码文件。这通常会给该文件的用户带来麻烦。 如果不支持working-tree-encoding
属性的 Git 客户端添加新文件bar.ps1
,则bar.ps1
将在内部“按原样”存储(在此示例中可能为 UTF-16)。具有working-tree-encoding
支持的客户端将内部内容解释为 UTF-8 并尝试在检出时将其转换为 UTF-16。该操作将失败并导致错误。 - 将内容重新编码为非 UTF 编码可能会导致错误,因为转换可能不是 UTF-8 往返安全。如果您怀疑您的编码不是往返安全,那么将其添加到
core.checkRoundtripEncoding
以使 Git 检查往返编码(参见 git-config [1] )。已知 SHIFT-JIS(日语字符集)具有 UTF-8 的往返问题,默认情况下会进行检查。 - 重新编码内容需要可能减慢某些 Git 操作的资源(例如 git checkout 或 git add )。
仅当您无法以 UTF-8 编码存储文件并且希望 Git 能够将内容作为文本处理时,才使用working-tree-encoding
属性。
例如,如果您的 * .ps1 文件是带字节顺序标记(BOM)的 UTF-16 编码,并且您希望 Git 根据您的平台执行自动行结束转换,请使用以下属性。
代码语言:javascript复制*.ps1 text working-tree-encoding=UTF-16
如果您的 * .ps1 文件是 UTF-16 小端编码而没有 BOM,并且您希望 Git 在工作目录中使用 Windows 行结尾,请使用以下属性(如果您使用UTF-16-LE-BOM
而不是UTF-16LE
想要带有 BOM 的 UTF-16 小端。请注意,如果使用working-tree-encoding
属性来避免歧义,强烈建议使用eol
明确定义行结尾。
*.ps1 text working-tree-encoding=UTF-16LE eol=CRLF
您可以使用以下命令获取平台上所有可用编码的列表:
代码语言:javascript复制iconv --list
如果您不知道文件的编码,则可以使用file
命令猜测编码:
file foo.ps1
ident
当为路径设置属性ident时,Git 用Id:替换 blob 对象中的Id,后跟 40 个字符的十六进制 blob 对象名称,然后在结帐时使用美元符号。任何以Id:开头并以 worktree 文件中的结尾的字节序列在签入时将替换为Id。
filter
可以将filter
属性设置为字符串值,该值指定配置中指定的过滤器驱动程序。
过滤器驱动程序由clean
命令和smudge
命令组成,其中任何一个都可以不指定。签出时,当指定smudge
命令时,命令从其标准输入中提供 blob 对象,其标准输出用于更新工作树文件。同样,clean
命令用于在签入时转换 worktree 文件的内容。默认情况下,这些命令仅处理单个 blob 并终止。如果使用长时间运行的process
过滤器代替clean
和/或smudge
过滤器,那么 Git 可以在单个 Git 命令的整个生命周期内使用单个过滤器命令调用处理所有 blob,例如git add --all
。如果配置了长时间运行的process
过滤器,则它始终优先于配置的单个 blob 过滤器。有关用于与process
过滤器通信的协议的说明,请参阅以下部分。
内容过滤的一个用途是将内容按摩成对于平台,文件系统和用户更方便使用的形状。对于这种操作模式,这里的关键短语是“更方便”而不是“将某些东西变为无法使用”。换句话说,目的是如果有人取消设置过滤器驱动程序定义,或者没有适当的过滤程序,则该项目仍应可用。
内容过滤的另一个用途是存储无法直接在存储库中使用的内容(例如,引用存储在 Git 外部的真实内容的 UUID,或加密内容),并在检出时将其转换为可用形式(例如,下载外部内容,或解密加密内容)。
这两个过滤器的行为不同,默认情况下,过滤器被视为前者,将内容按摩为更方便的形状。配置中缺少过滤器驱动程序定义,或者以非零状态退出的过滤器驱动程序不是错误,而是使过滤器成为无操作通路。
您可以通过将过滤器< driver> .required 配置变量设置为true
来声明过滤器将自身无法使用的内容转换为可用内容。
注意:每当更改清理过滤器时,repo 应重新规范化:$ git add --renormalize。
例如,在.gitattributes 中,您将为路径分配filter
属性。
*.c filter=indent
然后,您将在.git / config 中定义“filter.indent.clean”和“filter.indent.smudge”配置,以指定一对命令,以便在签入源文件时修改 C 程序的内容(“clean” “运行”并检出(因为命令是“cat”而没有进行任何更改)。
代码语言:javascript复制[filter "indent"]
clean = indent
smudge = cat
为了获得最佳效果,clean
如果运行两次(“清洁→清洁”应相当于“清洁”),则不应进一步改变其输出,并且多个smudge
命令不应改变clean
的输出(“涂抹→涂抹→清洁“应相当于”清洁“)。请参阅下面的合并部分。
“indent”过滤器在这方面表现良好:它不会修改已经正确缩进的输入。在这种情况下,没有污迹过滤器意味着清洁过滤器 _ 必须 _ 接受自己的输出而不修改它。
如果过滤器 _ 必须 _ 成功才能使存储的内容可用,您可以在配置中声明过滤器为required
:
[filter "crypt"]
clean = openssl enc ...
smudge = openssl enc -d ...
required
过滤器命令行上的序列“%f”将替换为过滤器正在处理的文件的名称。过滤器可能会在关键字替换中使用它。例如:
代码语言:javascript复制[filter "p4"]
clean = git-p4-filter --clean %f
smudge = git-p4-filter --smudge %f
请注意,“%f”是正在处理的路径的名称。根据要过滤的版本,磁盘上的相应文件可能不存在,或者可能具有不同的内容。因此,涂抹和清除命令不应该尝试访问磁盘上的文件,而只是作为标准输入上提供给它们的内容的过滤器。
长时间运行的过滤器
如果通过filter.<driver>.process
定义过滤器命令(字符串值),则 Git 可以在单个 Git 命令的整个生命周期内使用单个过滤器调用处理所有 blob。这是通过使用长时间运行的进程协议(在 technical / long-running-process-protocol.txt 中描述)实现的。
当 Git 遇到需要清理或污迹的第一个文件时,它会启动过滤器并执行握手。在握手中,Git 发送的欢迎消息是“git-filter-client”,只支持版本 2,支持的功能是“干净”,“涂抹”和“延迟”。
然后 Git 发送一个以 flush 数据包终止的“key = value”对列表。该列表至少包含 filter 命令(基于支持的功能)以及要相对于存储库根目录进行筛选的文件的路径名。在刷新数据包之后,Git 发送内容分为零个或多个 pkt-line 数据包和一个刷新数据包以终止内容。请注意,过滤器在收到内容和最终刷新数据包之前不得发送任何响应。另请注意,“key = value”对的“值”可以包含“=”字符,而键永远不会包含该字符。
代码语言:javascript复制packet: git> command=smudge
packet: git> pathname=path/testfile.dat
packet: git> 0000
packet: git> CONTENT
packet: git> 0000
期望过滤器响应一个以 flush 数据包终止的“key = value”对的列表。如果过滤器没有遇到问题,则列表必须包含“成功”状态。在这些数据包之后,预期过滤器将在最后发送零个或多个 pkt-line 数据包和一个 flush 数据包的内容。最后,期望用刷新数据包终止的第二个“key = value”对列表。过滤器可以更改第二个列表中的状态,或者将状态保持为空列表。请注意,无论如何,必须使用 flush 数据包终止空列表。
代码语言:javascript复制packet: git< status=success
packet: git< 0000
packet: git< SMUDGED_CONTENT
packet: git< 0000
packet: git< 0000 # empty list, keep "status=success" unchanged!
如果结果内容为空,则期望过滤器以“成功”状态和刷新分组响应以发信号通知空内容。
代码语言:javascript复制packet: git< status=success
packet: git< 0000
packet: git< 0000 # empty content!
packet: git< 0000 # empty list, keep "status=success" unchanged!
如果过滤器不能或不想处理内容,则应该以“错误”状态响应。
代码语言:javascript复制packet: git< status=error
packet: git< 0000
如果过滤器在处理过程中遇到错误,则可以在(部分或完全)发送内容后发送状态“错误”。
代码语言:javascript复制packet: git< status=success
packet: git< 0000
packet: git< HALF_WRITTEN_ERRONEOUS_CONTENT
packet: git< 0000
packet: git< status=error
packet: git< 0000
如果过滤器不能或不想处理内容以及 Git 过程生命周期内的任何未来内容,则期望在协议中的任何点以“中止”状态响应。
代码语言:javascript复制packet: git< status=abort
packet: git< 0000
如果设置了“错误”/“中止”状态,Git 既不会停止也不会重新启动过滤器进程。但是,Git 根据filter.<driver>.required
标志设置其退出代码,模仿filter.<driver>.clean
/ filter.<driver>.smudge
机制的行为。
如果过滤器在通信期间死亡或者不遵守协议,那么 Git 将停止过滤器进程并使用下一个需要处理的文件重新启动它。根据filter.<driver>.required
标志,Git 会将其解释为错误。
延迟
如果过滤器支持“延迟”功能,那么 Git 可以在过滤器命令和路径名之后发送标志“can-delay”。该标志表示过滤器可以通过响应没有内容但具有状态“延迟”和刷新分组来延迟过滤当前 blob(例如,以补偿网络延迟)。
代码语言:javascript复制packet: git> command=smudge
packet: git> pathname=path/testfile.dat
packet: git> can-delay=1
packet: git> 0000
packet: git> CONTENT
packet: git> 0000
packet: git< status=delayed
packet: git< 0000
如果过滤器支持“延迟”功能,则它必须支持“list_available_blobs”命令。如果 Git 发送此命令,那么过滤器应该返回一个路径名列表,这些路径名表示先前已经延迟并且现在可用的 blob。该列表必须以刷新数据包结束,然后是“成功”状态,该状态也以刷新数据包终止。如果延迟路径的 blob 尚未可用,则过滤器应该阻止响应,直到至少有一个 blob 可用。过滤器可以通过发送空列表告诉 Git 它没有更多延迟的 blob。一旦过滤器响应空列表,Git 就会停止询问。 Git 此时未收到的所有 blob 都被视为缺失,并将导致错误。
代码语言:javascript复制packet: git> command=list_available_blobs
packet: git> 0000
packet: git< pathname=path/testfile.dat
packet: git< pathname=path/otherfile.dat
packet: git< 0000
packet: git< status=success
packet: git< 0000
Git 收到路径名后,会再次请求相应的 blob。这些请求包含路径名和空内容部分。如上所述,期望过滤器以通常的方式响应污迹内容。
代码语言:javascript复制packet: git> command=smudge
packet: git> pathname=path/testfile.dat
packet: git> 0000
packet: git> 0000 # empty content!
packet: git< status=success
packet: git< 0000
packet: git< SMUDGED_CONTENT
packet: git< 0000
packet: git< 0000 # empty list, keep "status=success" unchanged!
例
可以在位于 Git 核心存储库中的contrib/long-running-filter/example.pl
中找到长时间运行的过滤器演示实现。如果您开发自己的长时间运行过滤器过程,那么GIT_TRACE_PACKET
环境变量对调试非常有用(参见 git [1] )。
请注意,您不能将现有的filter.<driver>.clean
或filter.<driver>.smudge
命令与filter.<driver>.process
一起使用,因为前者使用的是与后者不同的进程间通信协议。
签入/签出属性之间的交互
在签入代码路径中,首先使用filter
驱动程序转换 worktree 文件(如果指定并定义相应的驱动程序),然后使用ident
(如果指定)处理结果,最后使用text
处理(再次) ,如果指定和适用)。
在签出代码路径中,首先使用text
转换 blob 内容,然后使用ident
转换为filter
。
合并具有不同签入/签出属性的分支
如果您为文件添加了导致该文件的规范存储库格式更改的属性,例如添加 clean / smudge 过滤器或 text / eol / ident 属性,那么合并属性不存在的任何内容通常会导致合并冲突。
为了防止这些不必要的合并冲突,可以告诉 Git 在通过设置merge.renormalize
配置变量解析三向合并时运行文件的所有三个阶段的虚拟签出和签入。当转换后的文件与未转换的文件合并时,这可以防止由签入转换引起的更改导致虚假合并冲突。
只要“涂抹→清洁”产生与“干净”相同的输出,即使对于已经弄脏的文件,此策略也会自动解决所有与过滤器相关的冲突。不以这种方式操作的过滤器可能会导致必须手动解决的其他合并冲突。
生成差异文本
diff
属性diff
影响 Git 如何为特定文件生成差异。它可以告诉 Git 是为路径生成文本补丁还是将路径视为二进制文件。它还可以影响在 hunk header @@ -k,l n,m @@
行上显示的行,告诉 Git 使用外部命令生成 diff,或者在生成 diff 之前让 Git 将二进制文件转换为文本格式。
Set
设置diff
属性的路径被视为文本,即使它们包含通常永远不会出现在文本文件中的字节值,例如 NUL。
Unset
未设置diff
属性的路径将生成Binary files differ
(如果启用了二进制补丁,则生成二进制补丁)。
Unspecified
首先指定diff
属性未指定的路径检查其内容,如果它看起来像文本并且小于 core.bigFileThreshold,则将其视为文本。否则会产生Binary files differ
。
String
使用指定的 diff 驱动程序显示 Diff。每个驱动程序可以指定一个或多个选项,如以下部分所述。 diff 驱动程序“foo”的选项由 Git 配置文件的“diff.foo”部分中的配置变量定义。
定义外部差异驱动程序
diff 驱动程序的定义是在gitconfig
中完成的,而不是gitattributes
文件,所以严格来说这个手册页是一个错误的地方来讨论它。然而…
要定义外部差异驱动程序jcdiff,请在GIT_DIR/config文件(或HOME/.gitconfig文件)中添加一个部分,如下所示:
代码语言:javascript复制[diff "jcdiff"]
command = j-c-diff
当 Git 需要显示diff
属性设置为jcdiff
的路径的 diff 时,它会调用您使用上述配置指定的命令,即j-c-diff
,带有 7 个参数,就像调用GIT_EXTERNAL_DIFF
程序一样。有关详细信息,请参阅 git [1] 。
定义自定义的 hunk-header
文本差异输出中的每组更改(称为“hunk”)都以以下形式的行为前缀:
代码语言:javascript复制@@ -k,l n,m @@ TEXT
这称为 _ 块头 _。默认情况下,“TEXT”部分是以字母,下划线或美元符号开头的行;这匹配 GNU diff -p 输出使用的内容。但是,此默认选择不适用于某些内容,您可以使用自定义模式进行选择。
首先,在.gitattributes 中,您将为路径分配diff
属性。
*.tex diff=tex
然后,您将定义一个“diff.tex.xfuncname”配置来指定一个正则表达式,该表达式与您希望显示为 Hunk 标题“TEXT”的行匹配。在GIT_DIR/config文件(或HOME/.gitconfig文件)中添加一个部分,如下所示:
代码语言:javascript复制[diff "tex"]
xfuncname = "^(\\(sub)*section\{.*)$"
注意。配置文件解析器会使用单级反斜杠,因此您需要将反斜杠加倍;上面的模式选择一个以反斜杠开头的行,然后是sub
后跟section
后跟开放式大括号的零次或多次出现,直到行的末尾。
有一些内置模式可以使这更容易,tex
就是其中之一,因此您不必在配置文件中编写上述内容(您仍然需要通过属性机制通过.gitattributes
启用它])。可以使用以下内置模式:
-
ada
适用于 Ada 语言的源代码。 -
bibtex
适用于带有 BibTeX 编码参考的文件。 -
cpp
适用于 C 和 C 语言的源代码。 -
csharp
适用于 C#语言的源代码。 -
css
适用于级联样式表。 -
fortran
适用于 Fortran 语言的源代码。 -
fountain
适用于 Fountain 文档。 -
golang
适用于 Go 语言的源代码。 -
html
适用于 HTML / XHTML 文档。 -
java
适用于 Java 语言的源代码。 -
matlab
适用于 MATLAB 语言的源代码。 -
objc
适用于 Objective-C 语言的源代码。 -
pascal
适用于 Pascal / Delphi 语言的源代码。 -
perl
适用于 Perl 语言的源代码。 -
php
适用于 PHP 语言的源代码。 -
python
适用于 Python 语言的源代码。 -
ruby
适用于 Ruby 语言的源代码。 -
tex
适用于 LaTeX 文档的源代码。
自定义单词差异
您可以通过在“diff。*。wordRegex”配置变量中指定适当的正则表达式来自定义git diff --word-diff用于分割行中单词的规则。例如,在 TeX 中,反斜杠后跟一系列字母形成一个命令,但是几个这样的命令可以一起运行而不会插入空格。要分隔它们,请在GIT_DIR/config文件(或HOME/.gitconfig文件)中使用正则表达式,如下所示:
代码语言:javascript复制[diff "tex"]
wordRegex = "\\[a-zA-Z] |[{}]|\\.|[^\{}[:space:]] "
为上一节中列出的所有语言提供了内置模式。
执行二进制文件的文本差异
有时需要查看某些二进制文件的文本转换版本的差异。例如,可以将文字处理器文档转换为 ASCII 文本表示,并显示文本的差异。即使这种转换失去了一些信息,生成的差异对人类观看也很有用(但不能直接应用)。
textconv
配置选项用于定义执行此类转换的程序。程序应该采用单个参数,要转换的文件的名称,并在 stdout 上生成结果文本。
例如,要显示文件的 exif 信息的差异而不是二进制信息(假设您已安装 exif 工具),请将以下部分添加到GIT_DIR/config文件(或HOME/.gitconfig文件):
代码语言:javascript复制[diff "jpg"]
textconv = exif
| 注意 | 文本转换通常是单向转换;在这个例子中,我们丢失了实际的图像内容,只关注文本数据。这意味着 textconv 生成的差异是 _ 而不是 _ 适合应用。因此,只有git diff
和git log
系列命令(即 log,whatchanged,show)才能执行文本转换。 git format-patch
永远不会生成此输出。如果你想向某人发送二进制文件的文本转换差异(例如,因为它会快速传达你所做的更改),你应该单独生成它并将其作为注释发送 _ 除了 _ 您可能发送的常用二进制差异。 |
因为文本转换速度很慢,特别是在使用git log -p
进行大量转换时,Git 提供了一种缓存输出并在将来的差异中使用它的机制。要启用缓存,请在 diff 驱动程序的配置中设置“cachetextconv”变量。例如:
[diff "jpg"]
textconv = exif
cachetextconv = true
这将缓存每个 blob 上无限期运行“exif”的结果。如果更改 diff 驱动程序的 textconv 配置变量,Git 将自动使缓存条目无效并重新运行 textconv 过滤器。如果你想手动使缓存失效(例如,因为你的“exif”版本已更新并且现在产生更好的输出),你可以用git update-ref -d refs/notes/textconv/jpg
手动删除缓存(其中“jpg”是差异驱动程序的名称,如上例所示)。
选择 textconv 与外部差异
如果要在存储库中显示二进制或特殊格式的 blob 之间的差异,可以选择使用外部 diff 命令,或使用 textconv 将它们转换为可扩展的文本格式。您选择哪种方法取决于您的具体情况。
使用外部 diff 命令的优点是灵活性。您不一定要找到面向行的更改,输出也不一定要像统一的 diff 那样。您可以以最合适的方式为数据格式定位和报告更改。
相比之下,textconv 更具限制性。您提供了将数据转换为面向行的文本格式,Git 使用其常规 diff 工具生成输出。选择此方法有几个好处:
- 便于使用。编写二进制文本转换通常要比执行自己的 diff 更简单。在许多情况下,现有程序可以用作 textconv 过滤器(例如,exif,odt2txt)。
- Git diff 功能。通过自己仅执行转换步骤,您仍然可以利用 Git 的许多差异功能,包括着色,字差异和合并差异进行合并。
- 缓存。 Textconv 缓存可以加速重复的差异,例如您可能通过运行
git log -p
触发的差异。
将文件标记为二进制文件
Git 通常通过检查内容的开头来正确猜测 blob 是否包含文本或二进制数据。但是,有时您可能希望覆盖其决定,因为 blob 在文件中稍后包含二进制数据,或者因为内容虽然在技术上由文本字符组成,但对于人类读者来说是不透明的。例如,许多 postscript 文件仅包含 ASCII 字符,但会产生嘈杂且无意义的差异。
将文件标记为二进制文件的最简单方法是取消设置.gitattributes
文件中的 diff 属性:
*.ps -diff
这将导致 Git 生成Binary files differ
(或二进制补丁,如果启用了二进制补丁)而不是常规差异。
但是,也可能需要指定其他 diff 驱动程序属性。例如,您可能希望使用textconv
将 postscript 文件转换为 ASCII 表示形式以供人工查看,但另外将其视为二进制文件。您不能同时指定-diff
和diff=ps
属性。解决方案是使用diff.*.binary
配置选项:
[diff "ps"]
textconv = ps2ascii
binary = true
执行三向合并
merge
当git merge
期间需要文件级合并以及git revert
和git cherry-pick
等其他命令时,属性merge
会影响文件的三个版本的合并方式。
Set
内置的 3 路合并驱动程序用于以类似于RCS
套件的 merge 命令的方式合并内容。这适用于普通文本文件。
Unset
将当前分支中的版本作为暂定合并结果,并声明合并存在冲突。这适用于没有明确定义的合并语义的二进制文件。
代码语言:javascript复制 Unspecified
默认情况下,它使用与设置merge
属性时相同的内置 3 向合并驱动程序。但是,merge.default
配置变量可以将不同的合并驱动程序命名为与未指定merge
属性的路径一起使用。
String
使用指定的自定义合并驱动程序执行 3 向合并。可以通过询问“text”驱动程序明确指定内置的 3 路合并驱动程序;可以使用“二进制”来请求内置的“取当前分支”驱动程序。
内置合并驱动程序
定义了一些内置的低级合并驱动程序,可以通过merge
属性询问。
text
通常的 3 向文件级合并文本文件。冲突区域标有冲突标记<<<<<<<
,=======
和>>>>>>>
。分支的版本显示在=======
标记之前,合并分支的版本显示在=======
标记之后。
binary
保留工作树中的分支版本,但保留路径处于冲突状态以供用户进行整理。
代码语言:javascript复制 union
对文本文件运行 3 向文件级别合并,但从两个版本中获取行,而不是留下冲突标记。这往往会以随机顺序在结果文件中保留添加的行,用户应验证结果。如果您不理解其含义,请不要使用此功能。
定义自定义合并驱动程序
合并驱动程序的定义在.git/config
文件中完成,而不是在gitattributes
文件中完成,因此严格来说,这个手册页是一个错误的地方来讨论它。然而…
要定义自定义合并驱动程序filfre,请在GIT_DIR/config文件(或HOME/.gitconfig文件)中添加一个部分,如下所示:
代码语言:javascript复制[merge "filfre"]
name = feel-free merge driver
driver = filfre %O %A %B %L %P
recursive = binary
merge.*.name
变量为驱动程序提供了一个人类可读的名称。
merge.*.driver
变量的值用于构造运行以合并祖先版本(%O
),当前版本(%A
)和其他分支版本(%B
)的命令。在构建命令行时,这三个标记将替换为保存这些版本内容的临时文件的名称。此外,%L 将替换为冲突标记大小(见下文)。
合并驱动程序应该通过覆盖它来将合并的结果留在以%A
命名的文件中,如果它设法干净地合并它们,则退出为零状态,如果存在冲突则为非零。
merge.*.recursive
变量指定当共同驱动器被调用以在共同祖先之间进行内部合并时,要使用的其他合并驱动程序。如果未指定,则驱动程序本身用于内部合并和最终合并。
合并驱动程序可以通过占位符%P
了解合并结果的路径名。
conflict-marker-size
此属性控制冲突合并期间留在工作树文件中的冲突标记的长度。仅将值设置为正整数具有任何有意义的效果。
例如,.gitattributes
中的这一行可用于告诉合并机器在合并文件Documentation/git-merge.txt
导致冲突时留下更长的时间(而不是通常的 7 个字符长)冲突标记。
Documentation/git-merge.txt conflict-marker-size=32
检查空白错误
whitespace
core.whitespace
配置变量允许您定义 diff 和 _ 适用 _ 应该考虑项目中所有路径的空白错误(参见 git-config [1] )。此属性为每个路径提供更精细的控制。
Set
注意 Git 已知的所有类型的潜在空白错误。标签宽度取自core.whitespace
配置变量的值。
Unset
不要注意任何错误。
代码语言:javascript复制 Unspecified
使用core.whitespace
配置变量的值来确定要注意的错误。
String
以与core.whitespace
配置变量相同的格式指定逗号单独的常见空白问题列表。
创建档案
export-ignore
具有export-ignore
属性的文件和目录不会添加到存档文件中。
export-subst
如果为文件设置了属性export-subst,那么在将此文件添加到存档时,Git 将展开多个占位符。扩展取决于提交 ID 的可用性,即,如果 git-archive [1] 已被赋予树而不是提交或标记,则不会进行替换。占位符与 git-log [1] 的选项--pretty=format:的占位符相同,只是它们需要像这样包装:文件中的Format:PLACEHOLDERS。例如。字符串Format:%H将被提交哈希替换。
包装物
delta
对于属性delta
设置为 false 的路径,不会尝试对 blob 进行增量压缩。
在 GUI 工具中查看文件
encoding
此属性的值指定 GUI 工具应使用的字符编码(例如 gitk [1] 和 git-gui [1] )以显示相关文件的内容。请注意,由于性能方面的考虑, gitk [1] 不使用此属性,除非您在其选项中手动启用每个文件编码。
如果未设置此属性或具有无效值,则使用gui.encoding
配置变量的值(参见 git-config [1] )。
使用宏观属性
您不希望应用任何行尾转换,也不希望为您跟踪的任何二进制文件生成文本差异。您需要指定例如
代码语言:javascript复制*.jpg -text -diff
但是当你有很多属性时,这可能会变得很麻烦。使用宏属性,您可以定义一个属性,该属性在设置时还可以同时设置或取消设置许多其他属性。系统知道内置的宏属性binary
:
*.jpg binary
如上所述,设置“binary”属性也会取消设置“text”和“diff”属性。请注意,宏属性只能是“设置”,但设置一个可能具有设置或取消设置其他属性或甚至将其他属性返回到“未指定”状态的效果。
定义宏观属性
自定义宏属性只能在顶级 gitattributes 文件($GIT_DIR/info/attributes
,工作树顶层的.gitattributes
文件或全局或系统范围的 gitattributes 文件)中定义,而不能在.gitattributes
文件中定义。工作树子目录。内置的宏属性“binary”相当于:
[attr]binary -diff -merge -text
例子
如果您有这三个gitattributes
文件:
(in $GIT_DIR/info/attributes)
a* foo !bar -baz
(in .gitattributes)
abc foo bar baz
(in t/.gitattributes)
ab* merge=filfre
abc -foo -bar
*.c frotz
给路径t/abc
的属性计算如下:
- 通过检查
t/.gitattributes
(与相关路径在同一目录中),Git 发现第一行匹配。merge
属性已设置。它还发现第二行匹配,并且未设置属性foo
和bar
。 - 然后它检查
.gitattributes
(在父目录中),并发现第一行匹配,但t/.gitattributes
文件已经决定了如何将merge
,foo
和bar
属性赋予此路径,所以它使foo
和bar
未设置。属性baz
已设置。 - 最后它检查了
$GIT_DIR/info/attributes
。此文件用于覆盖树内设置。第一行是匹配,foo
设置,bar
恢复为未指定状态,baz
未设置。
结果,分配给t/abc
的属性变为:
foo set to true
bar unspecified
baz set to false
merge set to string value "filfre"
frotz unspecified
也可以看看
git-check-attr [1] 。
GIT
部分 git [1] 套件
giteveryday
原文:
git-scm.com/docs/giteveryday
名称
giteveryday - Everyday Git 的一组有用的最小命令
概要
每日 Git 有 20 个命令或者所以
描述
为了在这里描述日常 Git 的一小组有用命令,Git 用户可以大致分为四类。
- 个人开发者(独立)命令对任何提交者都是必不可少的,即使对于单独工作的人也是如此。
- 如果您与其他人一起工作,您还需要个人开发者(参与者)部分中列出的命令。
- 扮演 Integrator 角色的人除了上述之外还需要学习更多命令。
- 存储库管理命令适用于负责 Git 存储库的维护和提供的系统管理员。
个人开发者(独立)
独立的开发人员不会与其他人交换补丁,而是使用以下命令单独在单个存储库中工作。
- git-init [1] 创建一个新的存储库。
- git-log [1] 看看发生了什么。
- git-checkout [1] 和 git-branch [1] 切换分支。
- git-add [1] 来管理索引文件。
- git-diff [1] 和 git-status [1] 看你正在做什么。
- git-commit [1] 推进当前分支。
- git-reset [1] 和 git-checkout [1] (带路径名参数)撤消更改。
- git-merge [1] 在本地分支之间合并。
- git-rebase [1] 维护主题分支。
- git-tag [1] 标记已知点。
例子
代码语言:javascript复制 Use a tarball as a starting point for a new repository.
代码语言:javascript复制$ tar zxf frotz.tar.gz
$ cd frotz
$ git init
$ git add . (1)
$ git commit -m "import of frotz source tree."
$ git tag v2.43 (2)
- 添加当前目录下的所有内容。
- 制作一个轻量级,未注释的标签。
Create a topic branch and develop.
代码语言:javascript复制$ git checkout -b alsa-audio (1)
$ edit/compile/test
$ git checkout -- curses/ux_audio_oss.c (2)
$ git add curses/ux_audio_alsa.c (3)
$ edit/compile/test
$ git diff HEAD (4)
$ git commit -a -s (5)
$ edit/compile/test
$ git diff HEAD^ (6)
$ git commit -a --amend (7)
$ git checkout master (8)
$ git merge alsa-audio (9)
$ git log --since='3 days ago' (10)
$ git log v2.43.. curses/ (11)
- 创建一个新的主题分支。
- 恢复
curses/ux_audio_oss.c
中的拙劣变化。 - 你需要告诉 Git 你是否添加了一个新文件;如果您稍后执行
git commit -a
,将会删除和修改。 - 看看你提出了哪些改变。
- 如您所测试的那样,通过您的签名来承诺所有内容。
- 查看所有更改,包括之前的提交。
- 修改先前的提交,使用原始邮件添加所有新更改。
- 切换到主分支。
- 将主题分支合并到主分支中。
- 审核提交日志;可以组合限制输出的其他形式,包括
-10
(最多显示 10 次提交),--until=2005-12-10
等。 - 仅查看触及
curses/
目录中的内容的更改,因为v2.43
标记。
个人开发者(参与者)
作为组项目参与者的开发人员需要学习如何与他人通信,并且除了独立开发人员所需的命令之外还使用这些命令。
- git-clone [1] 从上游到本地存储库。
- 来自“origin”的 git-pull [1] 和 git-fetch [1] 与上游保持同步。
- git-push [1] 到共享存储库,如果采用 CVS 样式的共享存储库工作流程。
- git-format-patch [1] 准备电子邮件提交,如果采用 Linux 内核式公共论坛工作流程。
- git-send-email [1] 发送您的电子邮件提交而不会被您的 MUA 损坏。
- git-request-pull [1] 创建上游拉动变化的摘要。
例子
代码语言:javascript复制 Clone the upstream and work on it. Feed changes to upstream.
代码语言:javascript复制$ git clone git://git.kernel.org/pub/scm/.../torvalds/linux-2.6 my2.6
$ cd my2.6
$ git checkout -b mine master (1)
$ edit/compile/test; git commit -a -s (2)
$ git format-patch master (3)
$ git send-email --to="person <email@example.com>" 00*.patch (4)
$ git checkout master (5)
$ git pull (6)
$ git log -p ORIG_HEAD.. arch/i386 include/asm-i386 (7)
$ git ls-remote --heads http://git.kernel.org/.../jgarzik/libata-dev.git (8)
$ git pull git://git.kernel.org/pub/.../jgarzik/libata-dev.git ALL (9)
$ git reset --hard ORIG_HEAD (10)
$ git gc (11)
- 从主人那里结帐一个新的分支
mine
。 - 根据需要重复。
- 从你的分支中提取补丁,相对于主人,
- 并发送电子邮件
- 返回
master
,准备好看看有什么新东西 -
git pull
默认从origin
获取并合并到当前分支。 - 拉动后立即查看自上次检查以来上游所做的更改,仅在我们感兴趣的区域内。
- 检查外部存储库中的分支名称(如果未知)。
- 从特定存储库中获取特定分支
ALL
并合并它。 - 恢复拉力。
- 垃圾从恢复的拉动中收集剩余的物体。
Push into another repository.
代码语言:javascript复制satellite$ git clone mothership:frotz frotz (1)
satellite$ cd frotz
satellite$ git config --get-regexp '^(remote|branch).' (2)
remote.origin.url mothership:frotz
remote.origin.fetch refs/heads/*:refs/remotes/origin/*
branch.master.remote origin
branch.master.merge refs/heads/master
satellite$ git config remote.origin.push
refs/heads/*:refs/remotes/satellite/* (3)
satellite$ edit/compile/test/commit
satellite$ git push origin (4)
mothership$ cd frotz
mothership$ git checkout master
mothership$ git merge satellite/master (5)
- motherhip 机器在你的主目录下有一个 frotz 存储库;从中克隆以在卫星机器上启动存储库。
- clone 默认设置这些配置变量。它安排
git pull
来获取和存储母舰机器的分支到本地remotes/origin/*
远程跟踪分支机构。 - 安排
git push
将所有本地分支机构推送到母舰机器的相应分支机构。 - push 将把我们所有的工作都藏在母舰机器上的
remotes/satellite/*
远程跟踪分支上。您可以将其用作备份方法。同样地,你可以假装母舰从你那里“取出”(当访问是单方面时很有用)。 - 在母舰机器上,将卫星机器上完成的工作合并到主分支机构中。
Branch off of a specific tag.
代码语言:javascript复制$ git checkout -b private2.6.14 v2.6.14 (1)
$ edit/compile/test; git commit -a
$ git checkout master
$ git cherry-pick v2.6.14..private2.6.14 (2)
- 基于众所周知(但略微落后)的标签创建一个私有分支。
- 将
private2.6.14
分支中的所有更改转发到master
分支,而不进行正式的“合并”。或者手写git format-patch -k -m --stdout v2.6.14..private2.6.14 | git am -3 -k
备用参与者提交机制使用git request-pull
或拉取请求机制(例如,在 GitHub(www.github.com)上使用)向您的上游通知您的贡献。
积分
作为集体项目中的集成商的相当核心的人接收他人所做的更改,审查和集成他们并发布结果供其他人使用,除了参与者需要的命令之外还使用这些命令。
在 GitHub(www.github.com)上回复git request-pull
或 pull-request 以将其他人的工作整合到他们的历史中的人也可以使用此部分。存储库的子区域中尉既可以作为参与者也可以作为集成者。
- git-am [1] 应用您的贡献者通过电子邮件发送的补丁。
- git-pull [1] 从您信任的副手中合并。
- git-format-patch [1] 准备并发送建议的替代贡献者。
- git-revert [1] 撤消拙劣的提交。
- git-push [1] 发布前沿。
例子
代码语言:javascript复制 A typical integrator’s Git day.
代码语言:javascript复制$ git status (1)
$ git branch --no-merged master (2)
$ mailx (3)
& s 2 3 4 5 ./ to-apply
& s 7 8 ./ hold-linus
& q
$ git checkout -b topic/one master
$ git am -3 -i -s ./ to-apply (4)
$ compile/test
$ git checkout -b hold/linus && git am -3 -i -s ./ hold-linus (5)
$ git checkout topic/one && git rebase master (6)
$ git checkout pu && git reset --hard next (7)
$ git merge topic/one topic/two && git merge hold/linus (8)
$ git checkout maint
$ git cherry-pick master~4 (9)
$ compile/test
$ git tag -s -m "GIT 0.99.9x" v0.99.9x (10)
$ git fetch ko && for branch in master maint next pu (11)
do
git show-branch ko/$branch $branch (12)
done
$ git push --follow-tags ko (13)
- 看看你在做什么,如果有的话。
- 看哪些分支还没有合并到
master
中。对于任何其他集成分支,例如,maint
,next
和pu
(潜在更新)。 - 阅读邮件,保存适用的邮件,并保存其他尚未准备好的邮件(其他邮件阅读器可用)。
- 以交互方式应用它们与您的签字。
- 根据需要创建主题分支并再次应用签名。
- rebase 内部主题分支,尚未合并到主服务器或作为稳定分支的一部分公开。
- 每次从下一次重启
pu
。 - 捆绑主题分支仍在烹饪。
- backport 一个关键修复。
- 创建签名标记。
- 确保主人不会被意外地重绕,而不是已经被推出。
- 在
git show-branch
的输出中,master
应该包含ko/master
的所有内容,next
应该具有ko/next
所具有的所有内容等。 - 推出最前沿,以及指向推动历史的新标签。
在这个例子中,ko
简写点在 kernel.org 的 Git 维护者的存储库中,看起来像这样:
(in .git/config)
[remote "ko"]
url = kernel.org:/pub/scm/git/git.git
fetch = refs/heads/*:refs/remotes/ko/*
push = refs/heads/master
push = refs/heads/next
push = refs/heads/pu
push = refs/heads/maint
存储库管理
存储库管理员使用以下工具来设置和维护开发人员对存储库的访问权限。
- git-daemon [1] 允许从存储库匿名下载。
- git-shell [1] 可以用作共享中央存储库用户的 _ 受限登录 shell_ 。
- git-http-backend [1] 提供了 Git-over-HTTP(“Smart http”)的服务器端实现,允许提取和推送服务。
- gitweb [1] 为 Git 存储库提供了一个 Web 前端,可以使用 git-instaweb [1] 脚本进行设置。
update hook howto 有一个管理共享中央存储库的好例子。
此外,还有许多其他广泛部署的托管,浏览和审查解决方案,例如:
- gitolite,gerrit code review,cgit 等。
例子
代码语言:javascript复制 We assume the following in /etc/services
代码语言:javascript复制$ grep 9418 /etc/services
git 9418/tcp # Git Version Control System
代码语言:javascript复制 Run git-daemon to serve /pub/scm from inetd.
代码语言:javascript复制$ grep git /etc/inetd.conf
git stream tcp nowait nobody
/usr/bin/git-daemon git-daemon --inetd --export-all /pub/scm
实际配置行应该在一行上。
代码语言:javascript复制 Run git-daemon to serve /pub/scm from xinetd.
代码语言:javascript复制$ cat /etc/xinetd.d/git-daemon
# default: off
# description: The Git server offers access to Git repositories
service git
{
disable = no
type = UNLISTED
port = 9418
socket_type = stream
wait = no
user = nobody
server = /usr/bin/git-daemon
server_args = --inetd --export-all --base-path=/pub/scm
log_on_failure = USERID
}
检查你的 xinetd(8)文档和设置,这是来自 Fedora 系统。其他人可能会有所不同
代码语言:javascript复制 Give push/pull only access to developers using git-over-ssh.
例如那些使用:$ git push/pull ssh://host.xz/pub/scm/project
$ grep git /etc/passwd (1)
alice:x:1000:1000::/home/alice:/usr/bin/git-shell
bob:x:1001:1001::/home/bob:/usr/bin/git-shell
cindy:x:1002:1002::/home/cindy:/usr/bin/git-shell
david:x:1003:1003::/home/david:/usr/bin/git-shell
$ grep git /etc/shells (2)
/usr/bin/git-shell
- 登录 shell 设置为/ usr / bin / git-shell,除了
git push
和git pull
之外不允许任何其他内容。用户需要 ssh 访问机器。 - 在许多发行版/ etc / shells 中需要列出用作登录 shell 的内容。
CVS-style shared repository.
代码语言:javascript复制$ grep git /etc/group (1)
git:x:9418:alice,bob,cindy,david
$ cd /home/devo.git
$ ls -l (2)
lrwxrwxrwx 1 david git 17 Dec 4 22:40 HEAD -> refs/heads/master
drwxrwsr-x 2 david git 4096 Dec 4 22:40 branches
-rw-rw-r-- 1 david git 84 Dec 4 22:40 config
-rw-rw-r-- 1 david git 58 Dec 4 22:40 description
drwxrwsr-x 2 david git 4096 Dec 4 22:40 hooks
-rw-rw-r-- 1 david git 37504 Dec 4 22:40 index
drwxrwsr-x 2 david git 4096 Dec 4 22:40 info
drwxrwsr-x 4 david git 4096 Dec 4 22:40 objects
drwxrwsr-x 4 david git 4096 Nov 7 14:58 refs
drwxrwsr-x 2 david git 4096 Dec 4 22:40 remotes
$ ls -l hooks/update (3)
-r-xr-xr-x 1 david git 3536 Dec 4 22:40 update
$ cat info/allowed-users (4)
refs/heads/master alice|cindy
refs/heads/doc-update bob
refs/tags/v[0-9]* david
- 将开发人员放在同一个 git 组中。
- 并使该组可写的共享存储库。
- 使用来自 Documentation / howto /的 Carl 的 update-hook 示例进行分支策略控制。
- alice 和 cindy 可以推入主人,只有 bob 可以推进 doc-update。 david 是发布经理,是唯一可以创建和推送版本标签的人。
GIT
部分 git [1] 套件
gitglossary
原文:
git-scm.com/docs/gitglossary
名称
gitglossary - Git 词汇表
概要
描述
代码语言:javascript复制 alternate object database
通过交替机制,存储库可以从另一个对象数据库(称为“备用”)继承其对象数据库的一部分。
代码语言:javascript复制 bare repository
裸存储库通常是具有.git
后缀的适当命名的目录,该后缀没有在版本控制下的任何文件的本地检出副本。也就是说,隐藏的.git
子目录中通常存在的所有 Git 管理和控制文件都直接存在于repository.git
目录中,并且没有其他文件存在并检出。通常,公共存储库的发布者可以使用裸存储库。
blob object
未输入的对象,例如文件的内容。
代码语言:javascript复制 branch
“分支”是一个积极的发展路线。分支上最近的提交被称为该分支的提示。分支的尖端由分支头引用,其在分支上进行额外的开发时向前移动。单个 Git 存储库可以跟踪任意数量的分支,但您的工作树只与其中一个(“当前”或“已检出”分支)相关联, HEAD 指向那个分支。
代码语言:javascript复制 cache
已废弃:索引。
代码语言:javascript复制 chain
一个对象列表,其中列表中的每个对象包含对其后继者的引用(例如,提交的后继者可能是其父母之一 )。
代码语言:javascript复制 changeset
BitKeeper / cvsps 代表“ commit ”。由于 Git 不存储更改,但是状态,因此在 Git 中使用术语“changesets”实际上没有意义。
代码语言:javascript复制 checkout
用来自对象数据库的树对象或 blob 更新全部或部分工作树的动作,并更新索引和 HEAD 如果整个工作树已指向新的分支。
代码语言:javascript复制 cherry-picking
在 SCM 行话中,“樱桃选择”意味着从一系列更改(通常是提交)中选择更改的子集,并将它们记录为在不同代码库之上的一系列新更改。在 Git 中,这是通过“git cherry-pick”命令执行的,以提取现有提交引入的更改,并根据当前分支的提示将其记录为新提交。
代码语言:javascript复制 clean
工作树是干净的,如果它对应于当前头引用的修订版。另见“脏”。
代码语言:javascript复制 commit
作为名词:Git 历史中的一个点;项目的整个历史记录表示为一组相互关联的提交。 Git 通常在相同位置使用“commit”一词,其他版本控制系统使用“revision”或“version”。也用作提交对象的简写。
作为动词:通过创建表示索引当前状态的新提交并将 HEAD 推进指向新的提交。
代码语言:javascript复制 commit object
对象包含有关特定修订版的信息,如父,提交者,作者,日期和树对象对应到存储修订的顶部目录。
代码语言:javascript复制 commit-ish (also committish)
提交对象或对象,可以递归地解除引用到提交对象。以下是 commit-ishes:提交对象,指向提交对象的标记对象,指向指向提交对象的标记对象的标记对象,等等。
代码语言:javascript复制 core Git
Git 的基本数据结构和实用程序。仅公开有限的源代码管理工具。
代码语言:javascript复制 DAG
有向无环图。 提交对象形成一个有向无环图,因为它们有父对象(有向),而提交对象的图是非循环的(没有链开始和结束相同对象)。
代码语言:javascript复制 dangling object
无法到达的对象即使从其他无法到达的对象也不能到达;悬挂物体没有从存储库中的任何参考或对象引用它。
代码语言:javascript复制 detached HEAD
通常, HEAD 存储分支的名称,并且对历史 HEAD 进行操作的命令表示对通向 HEAD 指向的分支的尖端的历史进行操作。但是,Git 还允许你检查任意提交,这不一定是任何特定分支的提示。处于这种状态的 HEAD 被称为“分离的”。
请注意,在 HEAD 分离时,对当前分支的历史记录进行操作的命令(例如,git commit
以在其上构建新历史记录)仍然有效。他们更新 HEAD 以指向更新历史记录的提示,而不会影响任何分支。更新或查询关于当前分支的信息 _ 的命令(例如设置当前分支与哪个远程跟踪分支集成的git branch --set-upstream-to
)显然不起作用,因为没有(实际)当前分支要求在这种状态下。_
directory
你用“ls”得到的清单:-)
代码语言:javascript复制 dirty
如果工作树包含尚未提交到当前分支的修改,则称其为“脏”。
代码语言:javascript复制 evil merge
邪恶合并是合并,它引入了未出现在任何父中的变化。
代码语言:javascript复制 fast-forward
快进是一种特殊类型的合并你有一个修订并且你正在“合并”另一个分支的变化恰好是一个后代你有什么在这种情况下,你不会进行新的合并 提交,而只是更新到他的修订版。这将在远程存储库的远程跟踪分支上频繁发生。
代码语言:javascript复制 fetch
获取分支意味着从远程存储库获取分支的 head ref ,以找出本地对象数据库中缺少的对象 ],也是为了得到它们。另见 git-fetch [1] 。
代码语言:javascript复制 file system
Linus Torvalds 最初将 Git 设计为用户空间文件系统,即保存文件和目录的基础设施。这确保了 Git 的效率和速度。
代码语言:javascript复制 Git archive
存储库的同义词(适用于拱门人员)。
代码语言:javascript复制 gitfile
位于工作树根目录的纯文件.git
,指向作为真实存储库的目录。
grafts
通过记录提交的伪造祖先信息,移植物可以将两个不同的开发线连接在一起。这样你就可以让 Git 假装父 提交的集合与创建提交时记录的不同。通过.git/info/grafts
文件配置。
请注意,移植机制已过时,可能导致在存储库之间传输对象时出现问题;请参阅 git-replace [1] 以获得更灵活,更强大的系统来执行相同的操作。
代码语言:javascript复制 hash
在 Git 的上下文中,对象名称的同义词。
代码语言:javascript复制 head
在分支的末端命名为提交的参考。磁头存储在$GIT_DIR/refs/heads/
目录中的文件中,除非使用压缩参考。 (参见 git-pack-refs [1] 。)
HEAD
当前分支。更详细:您的工作树通常来自 HEAD 引用的树的状态。 HEAD 是对您的存储库中 之一的引用,除非使用分离的 HEAD ,在这种情况下它直接引用任意提交。
代码语言:javascript复制 head ref
head 的同义词。
代码语言:javascript复制 hook
在几个 Git 命令的正常执行期间,对可选脚本进行调用,允许开发人员添加功能或检查。通常,挂钩允许预先验证并可能中止命令,并允许在操作完成后进行后通知。钩子脚本位于$GIT_DIR/hooks/
目录中,只需从文件名中删除.sample
后缀即可启用。在早期版本的 Git 中,您必须使它们可执行。
index
包含 stat 信息的文件集合,其内容存储为对象。索引是工作树的存储版本。说实话,它还可以包含工作树的第二个甚至第三个版本,这些版本在合并时使用。
代码语言:javascript复制 index entry
有关特定文件的信息,存储在索引中。如果合并已启动但尚未完成(即,如果索引包含该文件的多个版本),则索引条目可以是未合并的。
代码语言:javascript复制 master
默认开发分支。无论何时创建 Git 存储库,都会创建一个名为“master”的分支,并成为活动分支。在大多数情况下,这包含本地开发,虽然这纯粹是按照惯例而不是必需的。
代码语言:javascript复制 merge
作为动词:将另一个分支(可能来自外部存储库)的内容带入当前分支。在合并分支来自不同存储库的情况下,这通过首先获取远程分支然后将结果合并到当前分支来完成。这种获取和合并操作的组合称为 pull 。合并由一个自动过程执行,该过程识别自分支分叉后所做的更改,然后将所有这些更改一起应用。如果更改发生冲突,则可能需要手动干预才能完成合并。
作为名词:除非它是快进,否则成功合并会导致创建表示合并结果的新提交,并具有父合并分支的提示。此提交称为“合并提交”,有时仅称为“合并”。
代码语言:javascript复制 object
Git 中的存储单元。它由 SHA-1 的内容唯一标识。因此,不能改变对象。
代码语言:javascript复制 object database
存储一组“对象”,单个对象由其对象名称标识。对象通常存在于$GIT_DIR/objects/
中。
object identifier
对象名称的同义词。
代码语言:javascript复制 object name
对象的唯一标识符。对象名称通常由 40 个字符的十六进制字符串表示。通俗地称为 SHA-1 。
代码语言:javascript复制 object type
其中一个标识符“提交”,“树”,“标签”或“ blob ”描述 HTG8 的类型对象。
代码语言:javascript复制 octopus
[合并超过两个分支。
代码语言:javascript复制 origin
默认上游存储库。大多数项目至少有一个他们跟踪的上游项目。默认情况下 _ 原点 _ 用于此目的。新的上游更新将被提取到名为 origin / name-of-upstream-branch 的远程跟踪分支中,您可以使用git branch -r
查看。
pack
已压缩到一个文件中的一组对象(以节省空间或有效传输它们)。
代码语言:javascript复制 pack index
包中对象的标识符列表和其他信息,以帮助有效地访问包的内容。
代码语言:javascript复制 pathspec
用于限制 Git 命令中的路径的模式。
Pathspecs 用于命令行“git ls-files”,“git ls-tree”,“git add”,“git grep”,“git diff”,“git checkout”以及许多其他命令以限制范围对树或工作树的某个子集的操作。有关路径是相对于当前目录还是顶层的信息,请参阅每个命令的文档。 pathspec 语法如下:
- 任何路径都匹配自己
- 最后一个斜杠的 pathspec 表示目录前缀。 pathpec 的范围仅限于该子树。
- 其余的 pathspec 是路径名的其余部分的模式。使用 fnmatch(3)将相对于目录前缀的路径与该模式匹配;特别是 * 和 ? _ 可以 _ 匹配目录分隔符。
例如,Documentation / * .jpg 将匹配文档子树中的所有.jpg 文件,包括 Documentation / chapter_1 / figure_1.jpg。
以冒号:
开头的 pathspec 具有特殊含义。在简短形式中,前导冒号:
后跟零个或多个“魔术签名”字母(可选地由另一个冒号:
终止),余数是与路径匹配的模式。 “魔术签名”由 ASCII 符号组成,既不是字母数字,也不是字母,正则表达式,也不是冒号。如果模式以不属于“魔术签名”符号集且不是冒号的字符开头,则可以省略终止“魔术签名”的可选冒号。
在长形式中,前导冒号:
后面是一个左括号(
,一个逗号分隔的零个或多个“魔术词”列表,以及一个括号)
,其余的是与路径相匹配。
仅包含冒号的 pathspec 意味着“没有 pathspec”。此表单不应与其他 pathspec 结合使用。
代码语言:javascript复制 top
即使从子目录中运行命令,魔术字top
(魔术签名:/
)也会使工作树的根模式匹配。
literal
模式中的通配符(如*
或?
)被视为文字字符。
icase
不区分大小写的匹配。
代码语言:javascript复制 glob
Git 将模式视为适合 fnmatch(3)使用 FNM_PATHNAME 标志的 shell glob:模式中的通配符与路径名中的/不匹配。例如,“Documentation / * .html”匹配“Documentation / git.html”,但不匹配“Documentation / ppc / ppc.html”或“tools / perf / Documentation / perf.html”。
与完整路径名匹配的两个连续星号(“**
”)可能具有特殊含义:
- 前导“
**
”后跟斜杠表示在所有目录中匹配。例如,“**/foo
”在任何地方匹配文件或目录“foo
”,与模式“foo
”相同。 “**/foo/bar
”将文件或目录“bar
”匹配在“foo
”目录下的任何位置。 - 尾随“
/**
”匹配内部的所有内容。例如,“abc/**
”匹配目录“abc”内的所有文件,相对于.gitignore
文件的位置,具有无限深度。 - 斜杠后跟两个连续的星号,然后斜杠匹配零个或多个目录。例如,“
a/**/b
”匹配“a/b
”,“a/x/b
”,“a/x/y/b
”等。 - 其他连续星号被视为无效。 Glob 魔法与文字魔法不相容。
attr
在attr:
出现空格分隔的“属性要求”列表之后,必须满足所有这些要求才能将路径视为匹配;这是除了通常的非魔术 pathpec 模式匹配之外。见 gitattributes [5] 。
路径的每个属性要求都采用以下形式之一:
- “
ATTR
”要求设置属性ATTR
。 - “
-ATTR
”要求取消设置ATTR
属性。 - “
ATTR=VALUE
”要求将属性ATTR
设置为字符串VALUE
。 - “
!ATTR
”要求未指定属性ATTR
。 请注意,在对树对象进行匹配时,仍然可以从工作树获取属性,而不是从给定的树对象获取属性。
exclude
在路径匹配任何非排除路径规范后,它将运行所有排除路径规范(魔术签名:!
或其同义词^
)。如果匹配,则忽略该路径。如果没有非排除路径规范,则将排除应用于结果集,就像在没有任何 pathspec 的情况下调用一样。
parent
提交对象包含开发线中的逻辑前任(即其父项)的(可能是空的)列表。
代码语言:javascript复制 pickaxe
术语 pickaxe 是指 diffcore 例程的一个选项,它有助于选择添加或删除给定文本字符串的更改。使用--pickaxe-all
选项,它可用于查看引入或删除的完整变更集,例如特定的文本行。参见 git-diff [1] 。
plumbing
核心 Git 的可爱名称。
代码语言:javascript复制 porcelain
程序和程序套件的可爱名称取决于核心 Git ,提供对核心 Git 的高级访问。与管道相比,瓷器暴露出更多的 SCM 界面。
代码语言:javascript复制 per-worktree ref
根据工作树的参考,而不是全局。目前只有 HEAD 以及以refs/bisect/
开头的任何引用,但后来可能包括其他不寻常的引用。
pseudoref
Pseudorefs 是$GIT_DIR
下的一类文件,其行为类似于 refs 用于 rev-parse,但是由 git 专门处理。伪数据都具有全大写的名称,并且始终以包含 SHA-1 后跟空格的行开头。因此,HEAD 不是伪目标,因为它有时是一个象征性的参考。它们可以选择包含一些其他数据。 MERGE_HEAD
和CHERRY_PICK_HEAD
是示例。与 per-worktree refs 不同,这些文件不能是符号引用,也不会有 reflog。它们也无法通过正常的 ref 更新机器进行更新。相反,它们通过直接写入文件来更新。但是,它们可以被读作好像是参考,因此git rev-parse MERGE_HEAD
将起作用。
pull
拉分支意味着获取它和合并它。另见 git-pull [1] 。
代码语言:javascript复制 push
推动分支意味着从远程存储库获取分支的头部参考,找出它是否是分支的本地头部参考的祖先,并且 case,将可以从本地 head ref 访问的对象和远程存储库中缺失的对象放入远程对象数据库,并更新远程头部 ref。如果远程头不是本地磁头的祖先,则推送失败。
代码语言:javascript复制 reachable
给定提交的所有祖先都被认为是来自该提交的“可达”。更一般地说,一个对象可以从另一个到达,如果我们可以通过链跟随标签到达另一个到它们标记的任何东西,将提交给他们的父母或树木,将树提交给他们所包含的树木或 blob 。
代码语言:javascript复制 rebase
要重新应用从分支到不同基数的一系列更改,并将该分支的头重置为结果。
代码语言:javascript复制 ref
以refs/
开头的名称(例如refs/heads/master
)指向对象名称或另一个 ref(后者称为符号 ref ))。为方便起见,当用作 Git 命令的参数时,ref 有时可以缩写;有关详细信息,请参阅 gitrevisions [7] 。 Refs 存储在存储库中。
ref 命名空间是分层的。不同的子层次结构用于不同的目的(例如,refs/heads/
层次结构用于表示本地分支)。
有一些特殊用途的参考不以refs/
开头。最值得注意的例子是HEAD
。
reflog
reflog 显示 ref 的本地“历史”。换句话说,它可以告诉你 _ 这个 _ 存储库中的第 3 个最后修订是什么,以及昨天晚上 9 点 14 分 _ 这个 _ 存储库中的当前状态是什么。有关详细信息,请参阅 git-reflog [1] 。
代码语言:javascript复制 refspec
fetch 和 push 使用“refspec”来描述远程 ref 和本地 ref 之间的映射。
代码语言:javascript复制 remote repository
存储库,用于跟踪同一个项目但位于其他地方。要与遥控器通信,请参阅获取或按。
代码语言:javascript复制 remote-tracking branch
ref ,用于跟踪来自另一个存储库的更改。它通常看起来像 refs / remotes / foo / bar (表示它在名为 foo 的遥控器中跟踪一个名为 bar 的分支),并且匹配右边 - 已配置的提取 refspec 的手边。远程跟踪分支不应包含直接修改或对其进行本地提交。
代码语言:javascript复制 repository
refs 的集合以及对象数据库,其中包含来自 refs 的可达的所有对象,可能伴随来自一个或多个瓷器的元数据。存储库可以通过交替机制与其他存储库共享对象数据库。
代码语言:javascript复制 resolve
手动修复失败的自动合并留下的动作。
代码语言:javascript复制 revision
commit (名词)的同义词。
代码语言:javascript复制 rewind
抛弃部分开发,即将头分配给早期修订版。
代码语言:javascript复制 SCM
源代码管理(工具)。
代码语言:javascript复制 SHA-1
“安全哈希算法 1”;加密哈希函数。在 Git 的上下文中用作对象名称的同义词。
代码语言:javascript复制 shallow clone
通常是浅存储库的同义词,但该短语使其更明确地表示它是通过运行git clone --depth=...
命令创建的。
shallow repository
一个浅存储库有一个不完整的历史,其中一些提交有父母烧灼(换句话说,Git 被告知假装这些提交没有父母,即使他们被记录在提交对象中)。当您仅对项目的近期历史感兴趣时,这有时很有用,即使上游记录的真实历史要大得多。通过向 git-clone [1] 提供--depth
选项来创建浅存储库,并且可以稍后使用 git-fetch [1] 加深其历史记录。
stash entry
对象用于临时存储脏工作目录的内容和索引以供将来重用。
代码语言:javascript复制 submodule
存储库,用于保存另一个存储库中的单独项目的历史记录(后者称为 superproject )。
代码语言:javascript复制 superproject
存储库,它将工作树中其他项目的存储库作为子模块引用。超级项目知道所包含的子模块的提交对象的名称(但不包含其副本)。
代码语言:javascript复制 symref
符号引用:它不是包含 SHA-1 id 本身,而是格式为 ref:refs / some / thing ,并且在引用时,它递归地取消引用此引用。 _HEAD _ 是 symref 的主要示例。使用 git-symbolic-ref [1] 命令操纵符号引用。
代码语言:javascript复制 tag
refs/tags/
命名空间下的 ref 指向任意类型的对象(通常标签指向标签或提交对象)。与头相反,commit
命令不会更新标签。 Git 标签与 Lisp 标签无关(在 Git 的上下文中称为对象类型)。标记最常用于标记提交祖先链中的特定点。
tag object
包含 ref 的对象指向另一个对象,该对象可以包含类似提交对象的消息。它还可以包含(PGP)签名,在这种情况下,它被称为“签名标记对象”。
代码语言:javascript复制 topic branch
一个常规的 Git 分支,开发人员用它来识别概念的开发线。由于分支非常容易且便宜,因此通常需要具有若干小分支,每个小分支包含非常明确定义的概念或小的增量但相关的变化。
代码语言:javascript复制 tree
工作树或树对象与从属 blob 和树对象(即工作树的存储表示)一起。
代码语言:javascript复制 tree object
包含文件名和模式列表的对象以及对关联的 blob 和/或树对象的引用。 树相当于目录。
代码语言:javascript复制 tree-ish (also treeish)
树对象或对象,可以递归地解除引用到树对象。解除引用提交对象产生对应于修订版的顶部目录的树对象。以下是所有树形图: commit-ish ,树对象,指向树对象的标记对象,指向指向标记对象的标记对象到树对象等
代码语言:javascript复制 unmerged index
索引包含未合并的索引条目。
代码语言:javascript复制 unreachable object
来自分支,标签或任何其他参考的对象不是可到达的。
代码语言:javascript复制 upstream branch
合并到相关分支中的默认分支(或者有问题的分支被重新分配到)。它通过分支配置。< name> .remote 和 branch。< name> .merge。如果 A 的上游分支是 _ 起源/ B_ ,有时我们说“ A 正在追踪 _ 起源/ B_ ”。
代码语言:javascript复制 working tree
实际签出文件的树。工作树通常包含 HEAD 提交树的内容,以及您已经进行但尚未提交的任何本地更改。
也可以看看
gittutorial [7] , gittutorial-2 [7] , gitcvs-migration [7] , giteveryday [7] , Git 用户手册
GIT
部分 git [1] 套件
githooks
原文:
git-scm.com/docs/githooks
名称
githooks - Git 使用的钩子
概要
$ GIT_DIR / hooks / *(或git config core.hooksPath
/ *)
描述
钩子是可以放在钩子目录中的程序,用于在 git 的执行中的某些点触发动作。没有设置可执行位的挂钩将被忽略。
默认情况下,hooks 目录为$GIT_DIR/hooks
,但可以通过core.hooksPath
配置变量进行更改(参见 git-config [1] )。
在 Git 调用钩子之前,它将其工作目录更改为裸存储库中的 GIT_DIR 或非裸存储库中工作树的根。推送期间触发的挂钩例外(_ 预接收 , 更新 , 接收后 , 更新后 _, push-to-checkout )总是在 GIT_DIR 中执行。
钩子可以通过环境,命令行参数和 stdin 获取它们的参数。有关详细信息,请参阅下面每个挂钩的文档。
git init
可能会将挂钩复制到新存储库,具体取决于其配置。有关详细信息,请参见 git-init [1] 中的“TEMPLATE DIRECTORY”部分。当本文档的其余部分引用“默认挂钩”时,它正在讨论 Git 附带的默认模板。
目前支持的钩子如下所述。
挂钩
applypatch-MSG
这个钩子由 git-am [1] 调用。它需要一个参数,即包含建议的提交日志消息的文件的名称。退出非零状态会导致git am
在应用修补程序之前中止。
允许钩子编辑消息文件,并可用于将消息规范化为某种项目标准格式。它还可以用于在检查消息文件后拒绝提交。
默认 applypatch-msg 挂钩,如果启用,则运行 commit-msg 挂钩,如果后者启用的话。
预 applypatch
这个钩子由 git-am [1] 调用。它不需要参数,并且在应用补丁之后但在提交之前调用。
如果它以非零状态退出,则在应用补丁后将不会提交工作树。
它可用于检查当前工作树,如果未通过某些测试则拒绝提交。
默认的 pre-applypatch 挂钩启用时会运行 _ 预提交 _ 挂钩,如果后者启用的话。
后 applypatch
这个钩子由 git-am [1] 调用。它不需要参数,并在应用补丁并进行提交后调用。
此挂钩主要用于通知,不会影响git am
的结果。
预提交
这个钩子由 git-commit [1] 调用,可以用--no-verify
选项旁路。它不需要任何参数,并在获取建议的提交日志消息和进行提交之前调用。退出此脚本的非零状态会导致git commit
命令在创建提交之前中止。
默认的 _ 预提交 _ 挂钩,在启用时,会捕获带有尾随空格的行的引入,并在找到这样的行时中止提交。
如果命令不会调出编辑器来修改提交消息,则使用环境变量GIT_EDITOR=:
调用所有git commit
挂钩。
准备提交-MSG
在准备默认日志消息之后,在编辑器启动之前, git-commit [1] 会调用此挂钩。
它需要一到三个参数。第一个是包含提交日志消息的文件的名称。第二个是提交消息的来源,可以是:message
(如果给出了-m
或-F
选项); template
(如果给出了-t
选项或设置了配置选项commit.template
); merge
(如果提交是合并或.git/MERGE_MSG
文件存在); squash
(如果存在.git/SQUASH_MSG
文件);或commit
,然后是提交 SHA-1(如果给出了-c
,-C
或--amend
选项)。
如果退出状态为非零,则git commit
将中止。
挂钩的目的是在适当的位置编辑消息文件,并且不会被--no-verify
选项抑制。非零退出意味着挂钩失败并中止提交。它不应该用作预提交钩子的替代品。
Git 附带的示例prepare-commit-msg
挂钩删除了在提交模板的注释部分中找到的帮助消息。
提交-MSG
这个钩子由 git-commit [1] 和 git-merge [1] 调用,可以用--no-verify
选项绕过。它需要一个参数,即包含建议的提交日志消息的文件的名称。以非零状态退出会导致命令中止。
允许钩子编辑消息文件,并可用于将消息规范化为某种项目标准格式。它还可以用于在检查消息文件后拒绝提交。
默认的 commit-msg 挂钩启用时会检测到重复的“Signed-off-by”行,如果找到,则中止提交。
提交后
这个钩子由 git-commit [1] 调用。它不需要参数,并在提交后调用。
此挂钩主要用于通知,不会影响git commit
的结果。
前底垫
这个钩子由 git-rebase [1] 调用,可以用来防止分支被重新绑定。可以用一个或两个参数调用钩子。第一个参数是分支系列的上游。第二个参数是重新分支的分支,在重新定位当前分支时不会设置。
后检出
更新工作树后运行 git-checkout [1] 时会调用此挂钩。钩子被赋予三个参数:前一个 HEAD 的 ref,新 HEAD 的 ref(可能已经或可能没有改变),以及一个标志,指示检出是否是分支检出(更改分支,标志= 1)或文件签出(从索引中检索文件,标志= 0)。这个钩子不会影响git checkout
的结果。
它也在 git-clone [1] 之后运行,除非使用--no-checkout
(-n
)选项。给钩子的第一个参数是 null-ref,第二个是新 HEAD 的 ref,而标志总是 1.同样对于git worktree add
,除非使用--no-checkout
。
此挂钩可用于执行存储库有效性检查,如果不同则自动显示与先前 HEAD 的差异,或设置工作目录元数据属性。
后合并
这个钩子由 git-merge [1] 调用,当在本地存储库上完成git pull
时会发生这种情况。钩子接受一个参数,一个状态标志,指定合并是否是一个压缩合并。如果由于冲突导致合并失败,则此挂钩不会影响git merge
的结果,也不会执行。
该钩子可以与相应的预提交钩子一起使用,以保存和恢复与工作树相关联的任何形式的元数据(例如:权限/所有权,ACLS 等)。有关如何执行此操作的示例,请参阅 contrib / hooks / setgitperms.perl。
前推
这个钩子由 git-push [1] 调用,可用于防止发生推动。使用两个参数调用钩子,这两个参数提供目标远程的名称和位置,如果未使用命名远程,则两个值将相同。
有关要推送内容的信息在钩子的标准输入上提供了以下形式的行:
代码语言:javascript复制<local ref> SP <local sha1> SP <remote ref> SP <remote sha1> LF
例如,如果运行命令git push origin master:foreign
,则挂钩将收到如下所示的行:
refs/heads/master 67890 refs/heads/foreign 12345
虽然将提供完整的 40 个字符的 SHA-1。如果外来参考不存在,<remote SHA-1>
将为 40 0
。如果要删除 ref,<local ref>
将作为(delete)
提供,<local SHA-1>
将为 40 0
。如果本地提交是由可以扩展的名称以外的其他东西指定的(例如HEAD~
或 SHA-1),它将按照最初给出的方式提供。
如果此挂钩以非零状态退出,则git push
将在不推送任何内容的情况下中止。可以通过写入标准错误将关于推送拒绝原因的信息发送给用户。
预接收
当 git-receive-pack [1] 对git push
作出反应并更新其存储库中的引用时,将调用此挂钩。在开始更新远程存储库上的 refs 之前,将调用预接收挂钩。其退出状态决定了更新的成功或失败。
该钩子为接收操作执行一次。它不需要参数,但是对于每个 ref 都要更新它在标准输入上接收格式的一行:
代码语言:javascript复制<old-value> SP <new-value> SP <ref-name> LF
其中<old-value>
是存储在 ref 中的旧对象名称,<new-value>
是要存储在 ref 中的新对象名称,<ref-name>
是 ref 的全名。创建新参考时,<old-value>
为 40 0
。
如果钩子以非零状态退出,则不会更新任何引用。如果钩子退出零,则 _ 更新 _ 钩子仍然可以防止更新单个引用。
标准输出和标准错误输出都转发到另一端的git send-pack
,因此您只需为用户输入echo
消息即可。
在git push --push-option=...
的命令行上给出的推送选项的数量可以从环境变量GIT_PUSH_OPTION_COUNT
中读取,选项本身可以在GIT_PUSH_OPTION_0
,GIT_PUSH_OPTION_1
中找到,…如果协商不使用推送选项阶段,不会设置环境变量。如果客户端选择使用推送选项但不传输任何选项,则计数变量将设置为零,GIT_PUSH_OPTION_COUNT=0
。
有关注意事项,请参阅 git-receive-pack [1] 中的“隔离环境”部分。
更新
当 git-receive-pack [1] 对git push
作出反应并更新其存储库中的引用时,将调用此挂钩。在更新远程存储库上的 ref 之前,将调用更新挂钩。其退出状态决定了 ref 更新的成功或失败。
钩子为每个 ref 更新执行一次,并带有三个参数:
- 要更新的 ref 的名称,
- 存储在 ref 中的旧对象名称,
- 以及要存储在 ref 中的新对象名称。
从更新挂钩零退出允许更新 ref。以非零状态退出会阻止git receive-pack
更新该 ref。
此挂钩可用于通过确保对象名称是提交对象来防止 _ 强制 _ 更新某些引用,该提交对象是旧对象名称所指定的提交对象的后代。也就是说,执行“仅限快进”政策。
它还可以用于记录 old…new 状态。但是,它并不知道整个分支集合,所以当天真地使用时,它最终会为每个 ref 发送一封电子邮件。 _ 接收后 _ 钩子更适合这种情况。
在限制用户仅通过线路访问 git 命令的环境中,此挂钩可用于实现访问控制,而不依赖于文件系统所有权和组成员身份。请参阅 git-shell [1] ,了解如何使用登录 shell 限制用户只能访问 git 命令。
标准输出和标准错误输出都转发到另一端的git send-pack
,因此您只需为用户输入echo
消息即可。
默认 _ 更新 _ 挂钩,启用时 - hooks.allowunannotated
配置选项未设置或设置为 false-可防止未注释的标签被推送。
后收到
当 git-receive-pack [1] 对git push
作出反应并更新其存储库中的引用时,将调用此挂钩。在更新所有引用后,它将在远程存储库上执行一次。
该钩子为接收操作执行一次。它不需要参数,但获得的信息与 _ 预接收 _ 钩子在其标准输入上的信息相同。
这个钩子不会影响git receive-pack
的结果,因为它是在完成实际工作后调用的。
这取代了 _ 更新后 _ 钩子,除了它们的名称之外,它还获得了所有引用的旧值和新值。
标准输出和标准错误输出都转发到另一端的git send-pack
,因此您只需为用户输入echo
消息即可。
默认的 post-receive 挂钩是空的,但是在 Git 发行版的contrib/hooks
目录中提供了一个示例脚本post-receive-email
,它实现了发送提交电子邮件。
在git push --push-option=...
的命令行上给出的推送选项的数量可以从环境变量GIT_PUSH_OPTION_COUNT
中读取,选项本身可以在GIT_PUSH_OPTION_0
,GIT_PUSH_OPTION_1
中找到,…如果协商不使用推送选项阶段,不会设置环境变量。如果客户端选择使用推送选项但不传输任何选项,则计数变量将设置为零,GIT_PUSH_OPTION_COUNT=0
。
更新后的
当 git-receive-pack [1] 对git push
作出反应并更新其存储库中的引用时,将调用此挂钩。在更新所有引用后,它将在远程存储库上执行一次。
它需要可变数量的参数,每个参数都是实际更新的 ref 的名称。
此挂钩主要用于通知,不会影响git receive-pack
的结果。
_ 更新后 _ 挂钩可以判断推送的磁头是什么,但是它不知道它们的原始值和更新值是什么,因此它是一个糟糕的做旧日志的地方。 _ 接收后 _ 钩子确实获得了 refs 的原始值和更新值。如果你需要它们,你可以考虑它。
启用后,默认 _ 更新后 _ 挂钩运行git update-server-info
,以使哑传输(例如 HTTP)使用的信息保持最新。如果要发布可通过 HTTP 访问的 Git 存储库,则应该启用此挂钩。
标准输出和标准错误输出都转发到另一端的git send-pack
,因此您只需为用户输入echo
消息即可。
一键检出
当 git-receive-pack [1] 对git push
做出反应并更新其存储库中的引用时,以及当 push 尝试更新当前已检出的分支时,将调用此挂钩并且receive.denyCurrentBranch
配置变量设置为updateInstead
。如果工作树和远程存储库的索引与当前检出的提交有任何差异,则默认拒绝这样的推送;当工作树和索引都与当前提交匹配时,它们会更新以匹配新推送的分支提示。此挂钩用于覆盖默认行为。
钩子接收提交,当前分支的尖端将被更新。它可以以非零状态退出以拒绝推送(当它这样做时,它不能修改索引或工作树)。或者它可以对工作树和索引进行任何必要的更改,以便在当前分支的提示更新为新提交时将它们置于所需状态,并以零状态退出。
例如,钩子可以简单地运行git read-tree -u -m HEAD "$1"
以模拟git push
与git push
反向运行的git fetch
,因为git read-tree -u -m
的双树形式与切换的git checkout
基本相同分支,同时保持工作树中的本地更改不会干扰分支之间的差异。
预自动 GC
该钩子由git gc --auto
调用(参见 git-gc [1] )。它不带参数,从此脚本退出非零状态会导致git gc --auto
中止。
后重写
这个钩子由重写提交的命令调用( git-commit [1] 用--amend
和 git-rebase [1] 调用;当前git filter-branch
执行 _ 不是 _ 打电话给它!)。它的第一个参数表示它被调用的命令:当前amend
或rebase
之一。将来可能会传递更多与命令相关的参数。
钩子以格式接收 stdin 上重写提交的列表
代码语言:javascript复制<old-sha1> SP <new-sha1> [ SP <extra-info> ] LF
extra-info 再次依赖于命令。如果为空,则也省略前面的 SP。目前,没有命令传递任何 extra-info 。
自动注释复制后,钩子总是运行(参见 git-config [1] 中的“notes.rewrite。< command>”),因此可以访问这些注释。
以下特定于命令的注释适用:
代码语言:javascript复制 rebase
对于 _ 壁球 _ 和 fixup 操作,所有被压缩的提交都被列为被重写为压缩的提交。这意味着将有几行共享相同的 new-sha1 。
保证提交按照 rebase 处理它们的顺序列出。
sendemail-验证
这个钩子由 git-send-email [1] 调用。它需要一个参数,即保存要发送的电子邮件的文件的名称。退出非零状态会导致git send-email
在发送任何电子邮件之前中止。
fsmonitor 守卫员
当配置选项core.fsmonitor
设置为.git/hooks/fsmonitor-watchman
时,将调用此挂钩。它需要两个参数,一个版本(当前为 1)和自 1970 年 1 月 1 日午夜以来经过的纳秒时间。
钩子应输出到 stdout 工作目录中可能自请求的时间以来可能已更改的所有文件的列表。逻辑应该具有包容性,以便它不会错过任何潜在的变化。路径应该相对于工作目录的根目录,并由单个 NUL 分隔。
可以包含实际没有更改的文件。应包括所有更改,包括新创建和删除的文件。重命名文件时,应包括旧名称和新名称。
Git 将限制检查更改的文件以及根据给定的路径名检查未跟踪文件的目录。
告诉 git“所有文件都已更改”的优化方法是返回文件名/
。
退出状态确定 git 是否将使用钩子中的数据来限制其搜索。出错时,它将回退到验证所有文件和文件夹。
P4-预提交
该钩子由git-p4 submit
调用。它不需要参数,也不需要标准输入。从此脚本退出非零状态会阻止git-p4 submit
启动。运行git-p4 submit --help
了解详细信息。
GIT
部分 git [1] 套件
gitignore
原文:
git-scm.com/docs/gitignore
名称
gitignore - 指定要忽略的故意未跟踪文件
概要
XDG_CONFIG_HOME / git / ignore, GIT_DIR / info / exclude,.gitignore
描述
gitignore
文件指定 Git 应忽略的故意未跟踪文件。 Git 已经跟踪的文件不受影响;有关详细信息,请参阅下面的注释。
gitignore
文件中的每一行都指定一个模式。在决定是否忽略路径时,Git 通常会检查来自多个源的gitignore
模式,具有以下优先顺序,从最高到最低(在一个优先级内,最后一个匹配模式决定结果):
- 从命令行读取的模式用于支持它们的那些命令。
- 从与路径相同的目录中的
.gitignore
文件读取的模式,或在任何父目录中读取的模式,其中较高级别文件中的模式(直到工作树的顶层)被较低级别文件中的模式覆盖到包含该文件的目录。这些模式相对于.gitignore
文件的位置匹配。项目通常在其存储库中包含此类.gitignore
文件,其中包含作为项目构建的一部分生成的文件的模式。 - 从
$GIT_DIR/info/exclude
读取的模式。 - 模式从配置变量
core.excludesFile
指定的文件中读取。
放置模式的文件取决于模式的使用方式。
- 应该通过克隆进行版本控制并分发到其他存储库的模式(即所有开发人员都希望忽略的文件)应该进入
.gitignore
文件。 - 特定于特定存储库但不需要与其他相关存储库共享的模式(例如,存储在存储库中但特定于一个用户工作流的辅助文件)应该进入
$GIT_DIR/info/exclude
文件。 - 用户希望 Git 在所有情况下忽略的模式(例如,由用户选择的编辑器生成的备份或临时文件)通常会进入用户~/.gitconfig中core.excludesFile指定的文件。其默认值为 XDG_CONFIG_HOME / git / ignore。如果 XDG_CONFIG_HOME 未设置或为空,则使用
底层的 Git 管道工具,如 git ls-files 和 git read-tree ,读取命令行选项指定的gitignore
模式,或者命令行指定的文件选项。更高级别的 Git 工具,例如 git status 和 git add ,使用上面指定的来源的模式。
模式格式
- 空行不匹配任何文件,因此它可以作为可读性的分隔符。
- 以#开头的行作为注释。对于以哈希开头的模式,在第一个哈希值前加一个反斜杠(“
”)。
- 除非用反斜杠(“
”)引用尾随空格,否则将忽略尾随空格。
- 可选的前缀“
!
”否定模式;之前模式排除的任何匹配文件将再次包含在内。如果排除该文件的父目录,则无法重新包含文件。出于性能原因,Git 不会列出排除的目录,因此无论在何处定义,所包含文件的任何模式都不起作用。对于以文字“!
”开头的模式,在第一个“!
”前放置一个反斜杠(“”),例如“
!important!.txt
”。 - 如果模式以斜杠结尾,则为了以下描述的目的将其删除,但它只会找到与目录的匹配项。换句话说,
foo/
将匹配目录foo
和它下面的路径,但不匹配常规文件或符号链接foo
(这与在 Git 中一般使用 pathspec 的方式一致)。 - 如果模式不包含斜杠 / ,Git 会将其视为 shell glob 模式,并检查相对于
.gitignore
文件位置的路径名匹配(相对于工作的顶层)树,如果不是来自.gitignore
文件)。 - 否则,Git 将模式视为 shell glob:“
*
”匹配除“/
”之外的任何内容,“?
”匹配除“/
”之外的任何一个字符,并且“[]
”匹配一个字符选定的范围。有关更详细的说明,请参阅 fnmatch(3)和 FNM_PATHNAME 标志。 - 前导斜杠与路径名的开头匹配。例如,“/ *。c”匹配“cat-file.c”但不匹配“mozilla-sha1 / sha1.c”。
与完整路径名匹配的两个连续星号(“**
”)可能具有特殊含义:
- 前导“
**
”后跟斜杠表示在所有目录中匹配。例如,“**/foo
”在任何地方匹配文件或目录“foo
”,与模式“foo
”相同。 “**/foo/bar
”将文件或目录“bar
”匹配在“foo
”目录下的任何位置。 - 尾随“
/**
”匹配内部的所有内容。例如,“abc/**
”匹配目录“abc
”内的所有文件,相对于.gitignore
文件的位置,具有无限深度。 - 斜杠后跟两个连续的星号,然后斜杠匹配零个或多个目录。例如,“
a/**/b
”匹配“a/b
”,“a/x/b
”,“a/x/y/b
”等。 - 其他连续的星号被认为是常规星号,并且将根据先前的规则匹配。
笔记
gitignore 文件的目的是确保 Git 未跟踪的某些文件保持未跟踪。
要停止跟踪当前跟踪的文件,请使用 git rm --cached 。
例子
代码语言:javascript复制 $ git status
[...]
# Untracked files:
[...]
# Documentation/foo.html
# Documentation/gitignore.html
# file.o
# lib.a
# src/internal.o
[...]
$ cat .git/info/exclude
# ignore objects and archives, anywhere in the tree.
*.[oa]
$ cat Documentation/.gitignore
# ignore generated html files,
*.html
# except foo.html which is maintained by hand
!foo.html
$ git status
[...]
# Untracked files:
[...]
# Documentation/foo.html
[...]
另一个例子:
代码语言:javascript复制 $ cat .gitignore
vmlinux*
$ ls arch/foo/kernel/vm*
arch/foo/kernel/vmlinux.lds.S
$ echo '!/vmlinux*' >arch/foo/kernel/.gitignore
第二个.gitignore 阻止 Git 忽略arch/foo/kernel/vmlinux.lds.S
。
排除除特定目录foo/bar
以外的所有内容的示例(注意/*
- 没有斜杠,通配符也会排除foo/bar
中的所有内容):
$ cat .gitignore
# exclude everything except directory foo/bar
/*
!/foo
/foo/*
!/foo/bar
也可以看看
git-rm [1] , gitrepository-layout [5] , git-check-ignore [1]
GIT
部分 git [1] 套件
gitmodules
原文:
git-scm.com/docs/gitmodules
名称
gitmodules - 定义子模块属性
概要
$ GIT_WORK_DIR / .gitmodules
描述
.gitmodules
文件位于 Git 工作树的顶级目录中,是一个文本文件,其语法与 git-config [1] 的要求相匹配。
该文件包含每个子模块的一个子部分,子部分值是子模块的名称。该名称设置为添加子模块的路径,除非使用 _git 子模块添加 _ 的--name
选项进行自定义。每个子模块部分还包含以下必需的键:
submodule.<name>.path
定义相对于 Git 工作树的顶级目录的路径,其中预期子模块将被检出。路径名称不得以/
结尾。所有子模块路径在.gitmodules 文件中必须是唯一的。
submodule.<name>.url
定义可以从中克隆子模块存储库的 URL。这可以是准备传递给 git-clone [1] 的绝对 URL,或者(如果它以./或…/开头)相对于超级项目的原始存储库的位置。
此外,还有许多可选键:
代码语言:javascript复制 submodule.<name>.update
定义命名子模块的默认更新过程,即超级项目中“git submodule update”命令如何更新子模块。这仅由git submodule init
用于初始化同名的配置变量。这里允许的值是 _ 检出 , rebase , 合并 _ 或 _ 无 _。有关其含义,请参阅 git-submodule [1] 中 update 命令的说明。请注意,出于安全原因,此处有意忽略 _!命令 _ 表单。
submodule.<name>.branch
用于跟踪上游子模块中的更新的远程分支名称。如果未指定该选项,则默认为 master 。 .
的特殊值用于指示子模块中分支的名称应与当前存储库中当前分支的名称相同。有关详细信息,请参阅 git-submodule [1] 中的--remote
文档。
submodule.<name>.fetchRecurseSubmodules
此选项可用于控制此子模块的递归获取。如果此选项也存在于超级项目的.git / config 中的子模块条目中,则该设置将覆盖.gitmodules 中的设置。通过使用“git fetch”和“git pull”的“ - [no-] recurse-submodules”选项,可以在命令行上覆盖这两个设置。
代码语言:javascript复制 submodule.<name>.ignore
定义在什么情况下“git status”和 diff 系列将子模块显示为已修改。支持以下值:
代码语言:javascript复制 all
子模块永远不会被视为已修改(但仍将显示在状态输出中并在提交时提交)。
代码语言:javascript复制 dirty
将忽略对子模块工作树的所有更改,仅考虑子模块的 HEAD 与其在超级项目中的记录状态之间的已提交差异。
代码语言:javascript复制 untracked
只有子模块中未跟踪的文件才会被忽略。将显示对跟踪文件的承诺差异和修改。
代码语言:javascript复制 none
不会忽略对子模块的修改,显示所有已提交的差异以及对已跟踪和未跟踪文件的修改。这是默认选项。
如果此选项也存在于超级项目的.git / config 中的子模块条目中,则该设置将覆盖.gitmodules 中的设置。
可以使用“–ignore-submodule”选项在命令行上覆盖这两个设置。 _git 子模块 _ 命令不受此设置的影响。
代码语言:javascript复制 submodule.<name>.shallow
设置为 true 时,除非用户明确要求非浅层克隆,否则此子模块的克隆将作为浅层克隆(历史深度为 1)执行。
例子
请考虑以下.gitmodules 文件:
代码语言:javascript复制[submodule "libfoo"]
path = include/foo
url = git://foo.com/git/lib.git
代码语言:javascript复制[submodule "libbar"]
path = include/bar
url = git://bar.com/git/lib.git
这定义了两个子模块,libfoo
和libbar
。这些预期将在路径 include / foo 和 include / bar 中检出,并且对于这两个子模块,指定了可用于克隆子模块的 URL。
也可以看看
git-submodule [1] git-config [1]
GIT
部分 git [1] 套件
gitrevisions
原文:
git-scm.com/docs/gitrevisions
名称
gitrevisions - 为 Git 指定修订版和范围
概要
gitrevisions
描述
许多 Git 命令将修订参数作为参数。根据命令,它们表示特定的提交,或者对于遍历修订图的命令(例如 git-log [1] ),表示可以从该提交到达的所有提交。对于遍历修订图的命令,还可以明确指定一系列修订。
另外,一些 Git 命令(例如 git-show [1] 和 git-push [1] )也可以采用表示除提交之外的其他对象的修订参数,例如: blob(“文件”)或树(“文件目录”)。
指定修订
修订参数 < rev> 通常(但不一定)命名提交对象。它使用所谓的 _ 扩展 SHA-1_ 语法。以下是拼写对象名称的各种方法。列表末尾附近列出的名称包含提交中包含的树和 blob。
| 注意 | 本文档显示了 git 看到的“原始”语法。 shell 和其他 UI 可能需要额外的引用来保护特殊字符并避免单词拆分。 |
代码语言:javascript复制 <sha1>, e.g. dae86e1950b1277e545cee180551750029cfe735, dae86e
完整的 SHA-1 对象名称(40 字节十六进制字符串),或存储库中唯一的前导子字符串。例如。如果存储库中没有其他对象以 dae86e 开头的对象,则 dae86e1950b1277e545cee180551750029cfe735 和 dae86e 都命名相同的提交对象。
代码语言:javascript复制 <describeOutput>, e.g. v1.7.4.2-679-g3bee7fb
git describe
的输出;即,最接近的标签,可选地后跟破折号和多次提交,然后是破折号, g 和缩写的对象名称。
<refname>, e.g. master, heads/master, refs/heads/master
一个象征性的引用名称。例如。 master 通常表示 refs / heads / master 引用的提交对象。如果您碰巧同时拥有 _ 磁头/主控 _ 和 _ 标签/主控 ,您可以明确地说 _ 磁头/主控 _ 告诉 Git 您的意思。当含糊不清时,< refname>_ 通过以下规则中的第一场比赛消除歧义:
- 如果 $ GIT_DIR /< refname> 存在,这就是你的意思(这通常只适用于
HEAD
,FETCH_HEAD
,ORIG_HEAD
,MERGE_HEAD
和CHERRY_PICK_HEAD
); - 否则, refs /< refname> 如果存在;
- 否则, refs / tags /< refname> 如果存在;
- 否则, refs / heads /< refname> 如果存在;
- 否则, refs / remotes /< refname> 如果存在;
- 否则, refs / remotes /< refname> / HEAD (如果存在)。 HEAD命名您基于工作树中的更改的提交。 FETCH_HEAD记录您使用上次git fetch调用从远程存储库中获取的分支。 ORIG_HEAD是由以大刀阔斧的方式移动HEAD的命令创建的,用于在操作之前记录HEAD的位置,以便您可以轻松地将分支的尖端更改回运行它们之前的状态。 MERGE_HEAD在运行git merge时记录您要合并到分支中的提交。当您运行git cherry-pick时,CHERRY_PICK_HEAD会记录您正在挑选的提交。 请注意,上述任何 refs / * 情况可能来自
@
单独 @ 是HEAD
的捷径。
<refname>@{<date>}, e.g. master@{yesterday}, HEAD@{5 minutes ago}
引用后跟 @ 后缀为日期规格括号对(例如 {昨天} , {1 个月 2 周 3 天 1 小时 1 秒前} 或 {1979-02-26 18:30:00} )指定先前时间点的 ref 值。此后缀只能在引用名称后立即使用,并且引用必须具有现有日志( $ GIT_DIR / logs /< ref> )。请注意,这会在给定时间查找本地 ref 的状态;例如,上周本地 _ 主 _ 分支机构的内容。如果要查看在特定时间内提交的提交,请参阅--since
和--until
。
<refname>@{<n>}, e.g. master@{1}
后缀为 @ 的后缀为括号对中的序数规范(例如 {1} , {15} )指定第 n 个先验那个参考的价值。例如 master @ {1} 是 master 的前一个值,而 master @ {5} 是 master 的第 5 个先前值]。此后缀只能在引用名称后立即使用,并且引用必须具有现有日志( $ GIT_DIR / logs /< refname> )。
代码语言:javascript复制 @{<n>}, e.g. @{1}
您可以使用带有空参考部分的 @ 构造来获取当前分支的 reflog 条目。例如,如果你在分支 blabla ,那么 @ {1} 意味着与 blabla @ {1} 相同。
代码语言:javascript复制 @{-<n>}, e.g. @{-1}
构造 @ { - < n>} 表示在当前分支/提交之前检出的第 n 个分支/提交。
代码语言:javascript复制 <branchname>@{upstream}, e.g. master@{upstream}, @{u}
后缀 @ {upstream} 到分支机构(简称 < branchname> @ {u} )指的是由 branchname 指定的分支设置为在其上构建的分支(配置为branch.<name>.remote
和branch.<name>.merge
)。缺少的 branchname 默认为当前的。当拼写为大写时,这些后缀也被接受,无论如何它们都意味着相同的东西。
<branchname>@{push}, e.g. master@{push}, @{push}
后缀 @ {push} 报告分支“我们将推送到哪里”如果branchname
在branchname
被检出时运行(或者当前HEAD
如果没有指定分支机构)。由于我们的推送目的地位于远程存储库中,当然,我们报告与该分支对应的本地跟踪分支(即 refs / remotes / 中的内容)。
这是一个让它更清晰的例子:
代码语言:javascript复制$ git config push.default current
$ git config remote.pushdefault myfork
$ git checkout -b mybranch origin/master
$ git rev-parse --symbolic-full-name @{upstream}
refs/remotes/origin/master
$ git rev-parse --symbolic-full-name @{push}
refs/remotes/myfork/mybranch
请注意,在我们设置三角形工作流程的示例中,我们从一个位置拉出并推送到另一个位置。在非三角形工作流程中, @ {push} 与 @ {upstream} 相同,并且不需要它。
拼写为大写时也接受此后缀,无论情况如何都是相同的。
代码语言:javascript复制 <rev>^, e.g. HEAD^, v1.5.1⁰
修订参数的后缀 ^ 表示该提交对象的第一个父级。 ^< n> 表示第 n 个亲本(即 < rev> ^ 等同于 < rev> ^ )。作为特殊规则,< rev> ^ 0 表示提交本身并且在 < rev>时使用。 是引用提交对象的标记对象的对象名称。
代码语言:javascript复制 <rev>~<n>, e.g. master~3
后缀 〜< n> 到版本参数意味着提交对象是指定提交对象的第 n 代祖先,仅跟随第一个父对象。即 < rev>〜 相当于 < rev> ^^^ ,其相当于 < rev> ^ 1 ^ 1 ^ 。请参阅下文,了解此表单的用法。
代码语言:javascript复制 <rev>^{<type>}, e.g. v0.99.8^{commit}
后缀 ^ 后跟括号对中包含的对象类型名称意味着在 < rev>处取消引用对象。 递归地直到 < type>类型的对象为止。找到 _ 或者不再解除引用对象(在这种情况下,barf)。例如,如果 < rev> 是 commit-ish,< rev> ^ {commit}_ 描述了相应的提交对象。类似地,如果 < rev> 是树,< rev> ^ {tree} 描述了相应的树对象。 < rev> ^ 0 是 < rev> ^ {commit} 的简写。
rev ^ {object} 可以用来确保 rev 命名一个存在的对象,而不需要 rev 作为标签,并且不需要解除引用 rev ;因为标签已经是一个对象,所以即使一次到达一个对象也不需要解除引用。
rev ^ {tag} 可用于确保 rev 标识现有标记对象。
代码语言:javascript复制 <rev>^{}, e.g. v0.99.8^{}
后缀 ^ 后跟空括号对意味着该对象可以是标记,并递归取消引用标记,直到找到非标记对象。
代码语言:javascript复制 <rev>^{/<text>}, e.g. HEAD^{/fix nasty bug}
后缀 ^ 到一个修订参数,后跟一个括号对,其中包含一个由斜杠引导的文本,与下面的 _:/ fix 讨厌错误 _ 语法相同,只是它返回可以从 _< rev>到达的最年轻的匹配提交 ^ 之前的 _。
代码语言:javascript复制 :/<text>, e.g. :/fix nasty bug
冒号后跟一个斜杠,后跟一个文本,命名一个提交,其提交消息与指定的正则表达式匹配。此名称返回可从任何 ref 访问的最新匹配提交,包括 HEAD。正则表达式可以匹配提交消息的任何部分。为了匹配以字符串开头的消息,可以使用例如 :/ ^ foo 。特殊序列 :/! 保留用于匹配的修饰符。 :/! - foo 执行负匹配,而 :/ !! foo 匹配文字 ! 字符,然后是 foo 。以 _ 开头的任何其他序列:/!_ 暂时保留。根据给定的文本,shell 的单词拆分规则可能需要额外的引用。
代码语言:javascript复制 <rev>:<path>, e.g. HEAD:README, :README, master:./README
后缀 : 后跟一个路径,命名由冒号前部分命名的树形对象中给定路径上的 blob 或树。 :path (在冒号前面有空部分)是下面描述的语法的特例:在给定路径的索引中记录的内容。以 ./ 或 …/ 开头的路径是相对于当前工作目录的。给定路径将转换为相对于工作树的根目录。这对于从具有与工作树具有相同树结构的提交或树来解决 blob 或树最有用。
代码语言:javascript复制 :<n>:<path>, e.g. :0:README, :README
冒号,可选地后跟一个阶段号(0 到 3)和一个冒号,后跟一个路径,在给定路径的索引中命名一个 blob 对象。缺少的阶段编号(以及其后面的冒号)命名阶段 0 条目。在合并期间,阶段 1 是共同的祖先,阶段 2 是目标分支的版本(通常是当前分支),阶段 3 是正在合并的分支的版本。
以下是 Jon Loeliger 的插图。提交节点 B 和 C 都是提交节点 A 的父节点。父提交从左到右排序。
代码语言:javascript复制G H I J
/ /
D E F
| /
| / |
|/ |
B C
/
/
A
代码语言:javascript复制A = = A⁰
B = A^ = A¹ = A~1
C = A² = A²
D = A^^ = A¹¹ = A~2
E = B² = A^²
F = B³ = A^³
G = A^^^ = A¹¹¹ = A~3
H = D² = B^² = A^^² = A~2²
I = F^ = B³^ = A^³^
J = F² = B³² = A^³²
指定范围
遍历诸如git log
之类的命令的历史操作在一组提交上,而不仅仅是单个提交。
对于这些命令,使用上一节中描述的表示法指定单个修订版意味着来自给定提交的提交reachable
集。
提交的可达集是提交本身和其祖先链中的提交。
提交排除
代码语言:javascript复制 ^<rev> (caret) Notation
要排除从提交可到达的提交,使用前缀 ^ 表示法。例如。 ^ r1 r2 表示从 r2 可到达的提交,但排除可从 r1 (即 r1 及其祖先)到达的提交。
虚线范围符号
代码语言:javascript复制 The .. (two-dot) Range Notation
^ r1 r2 设置操作经常出现,因此有一个简写。如果你有两个提交 r1 和 r2 (根据上面的 SPECIFYING REVISIONS 中解释的语法命名),你可以要求从 r2 可以访问的提交,不包括那些可以从 r1 到达的提交 ^ r1 r2 可以写成 r1…r2 。
代码语言:javascript复制 The … (three-dot) Symmetric Difference Notation
类似的符号 r1 … r2 称为 r1 和 r2 的对称差异,定义为 r1 r2 - not $(git merge) -base --all r1 r2)。它是可以从 r1 (左侧)或 r2 (右侧)中的任何一个到达的提交集,但不是两者都可以。
在这两个简写符号中,您可以省略一端并将其默认为 HEAD。例如,_ 原点…_ 是 origin…HEAD 的简写并询问“自从我从原点分支分叉后我做了什么?”同样, .origin 是 HEAD…origin 的简写,并询问“自从我从它们分叉后,起源做了什么?”注意 … 将意味着 HEAD…HEAD ,这是一个空的范围,既可以从 HEAD 到达又无法到达。
其他< rev> ^父简写符号
存在三个其他的缩写,对于合并提交特别有用,用于命名由提交及其父提交形成的集合。
r1 ^ @ 符号表示 r1 的所有亲本。
r1 ^! 表示法包含 commit r1 但不包括其所有父母。这个符号本身表示单个提交 r1 。
< rev> ^ - < n> 符号包括 < rev> 但不包括第 n 个亲本(即 < rev> ^< n> …< rev> 的简写),< n>如果没有给出, = 1。这通常对于合并提交很有用,您可以通过 < commit> ^ - 来获取合并提交中合并的分支中的所有提交 < commit> (包括 < commit> 本身)。
虽然 < rev> ^< n> 是关于指定单个提交父级,这三个符号也考虑其父级。例如你可以说 HEAD ^ 2 ^ @ ,但你不能说 HEAD ^ @ ^ 2 。
修订范围摘要
代码语言:javascript复制 <rev>
包括可从< rev>到达的提交(即< rev>及其祖先)。
代码语言:javascript复制 ^<rev>
排除可从< rev>到达的提交(即< rev>及其祖先)。
代码语言:javascript复制 <rev1>..<rev2>
包括可从< rev2>到达的提交但不包括那些可以从< rev1>到达的那些。何时< rev1>或者< rev2>省略,默认为HEAD
。
<rev1>...<rev2>
包括可从< rev1>到达的提交或者< rev2>但排除那两个可以访问的。何时< rev1>或者< rev2>省略,默认为HEAD
。
<rev>^@, e.g. HEAD^@
后缀为 ^ 后跟 at 符号与列出 < rev>的所有父项相同。 (意思是,包括从其父母可以访问的任何内容,但不包括提交本身)。
代码语言:javascript复制 <rev>^!, e.g. HEAD^!
后缀为 ^ 后跟感叹号与提交 < rev>相同。 然后它的所有父母都以 ^ 为前缀来排除它们(以及它们的祖先)。
代码语言:javascript复制 <rev>^-<n>, e.g. HEAD^-, HEAD^-2
等同于 < rev> ^< n> …< rev> ,< n>如果没有给出, = 1。
以下是使用上面的 Loeliger 插图的一些示例,其中注释的扩展和选择中的每个步骤都经过仔细说明:
代码语言:javascript复制 Args Expanded arguments Selected commits
D G H D
D F G H I J D F
^G D H D
^D B E I J F B
^D B C E I J F B C
C I J F C
B..C = ^B C C
B...C = B ^F C G H D E B C
B^- = B^..B
= ^B¹ B E I J F B
C^@ = C¹
= F I J F
B^@ = B¹ B² B³
= D E F D G H E F I J
C^! = C ^C^@
= C ^C¹
= C ^F C
B^! = B ^B^@
= B ^B¹ ^B² ^B³
= B ^D ^E ^F B
F^! D = F ^I ^J D G H D F
也可以看看
git-rev-parse [1]
GIT
部分 git [1] 套件
gittutorial
原文:
git-scm.com/docs/gittutorial
名称
gittutorial - Git 的教程介绍
概要
代码语言:javascript复制git *
描述
本教程将介绍如何将新项目导入 Git,对其进行更改以及与其他开发人员共享更改。
如果您主要对使用 Git 获取项目感兴趣,例如,测试最新版本,您可能更喜欢从 Git 用户手册的前两章开始。
首先,请注意您可以获取git log --graph
等命令的文档:
$ man git-log
要么:
代码语言:javascript复制$ git help log
使用后者,您可以使用您选择的手动查看器;有关详细信息,请参阅 git-help [1] 。
在进行任何操作之前,最好使用您的姓名和公共电子邮件地址向 Git 介绍自己。最简单的方法是:
代码语言:javascript复制$ git config --global user.name "Your Name Comes Here"
$ git config --global user.email you@yourdomain.example.com
导入新项目
假设您有初始工作的 tarball project.tar.gz。您可以将它放在 Git 版本控制下,如下所示。
代码语言:javascript复制$ tar xzf project.tar.gz
$ cd project
$ git init
Git 会回复
代码语言:javascript复制Initialized empty Git repository in .git/
您现在已经初始化了工作目录 - 您可能会注意到创建了一个名为“.git”的新目录。
接下来,告诉 Git 使用 git add 拍摄当前目录下所有文件内容的快照(注意 。):
代码语言:javascript复制$ git add .
此快照现在存储在 Git 称为“索引”的临时暂存区域中。您可以使用 git commit 将索引的内容永久存储在存储库中:
代码语言:javascript复制$ git commit
这将提示您提交提交消息。您现在已经在 Git 中存储了项目的第一个版本。
做出改变
修改一些文件,然后将更新的内容添加到索引:
代码语言:javascript复制$ git add file1 file2 file3
你现在准备好了。您可以使用带有–cached 选项的 git diff 查看即将提交的内容:
代码语言:javascript复制$ git diff --cached
(没有–cached, git diff 会显示你已经做过但尚未添加到索引中的任何更改。)您还可以通过 _git status [ _git status 获得有关情况的简短摘要 :
代码语言:javascript复制$ git status
On branch master
Changes to be committed:
Your branch is up to date with 'origin/master'.
(use "git reset HEAD <file>..." to unstage)
modified: file1
modified: file2
modified: file3
如果您需要进行任何进一步调整,请立即执行此操作,然后将任何新修改的内容添加到索引中。最后,提交您的更改:
代码语言:javascript复制$ git commit
这将再次提示您输入描述更改的消息,然后记录项目的新版本。
或者,您可以使用,而不是预先运行 git add
代码语言:javascript复制$ git commit -a
它会自动注意任何修改过的(但不是新的)文件,将它们添加到索引中,然后一步一步地提交。
关于提交消息的注意事项:虽然不是必需的,但最好以一个简短(小于 50 个字符)的行来概括更改开始提交消息,然后是空白行,然后是更全面的描述。提交消息中第一个空白行的文本被视为提交标题,并且该标题在整个 Git 中使用。例如, git-format-patch [1] 将提交转换为电子邮件,它使用主题行上的标题和正文中的其余提交。
Git 跟踪内容而不是文件
许多修订控制系统提供add
命令,告诉系统开始跟踪对新文件的更改。 Git 的add
命令执行更简单和更强大的功能: git add 用于新修改的文件和新修改的文件,在这两种情况下,它都会获取给定文件的快照,并在索引中显示内容,准备好包含在下一次提交中。
查看项目历史记录
您可以随时查看更改的历史记录
代码语言:javascript复制$ git log
如果您还希望在每个步骤中看到完整的差异,请使用
代码语言:javascript复制$ git log -p
通常,变更概述对于了解每个步骤非常有用
代码语言:javascript复制$ git log --stat --summary
管理分支机构
单个 Git 存储库可以维护多个开发分支。要创建名为“experimental”的新分支,请使用
代码语言:javascript复制$ git branch experimental
如果你现在跑
代码语言:javascript复制$ git branch
您将获得所有现有分支的列表:
代码语言:javascript复制 experimental
* master
“experimental”分支是您刚创建的分支,“master”分支是自动为您创建的默认分支。星号标记您当前所在的分支;类型
代码语言:javascript复制$ git checkout experimental
切换到实验分支。现在编辑文件,提交更改,然后切换回主分支:
代码语言:javascript复制(edit file)
$ git commit -a
$ git checkout master
检查您所做的更改是否已不再可见,因为它是在实验分支上进行的,您将返回主分支。
您可以在主分支上进行不同的更改:
代码语言:javascript复制(edit file)
$ git commit -a
在这一点上,两个分支已经分歧,每个分支都有不同的变化。要将实验中所做的更改合并到 master 中,请运行
代码语言:javascript复制$ git merge experimental
如果变化没有冲突,那么你就完成了。如果存在冲突,标记将留在显示冲突的有问题的文件中;
代码语言:javascript复制$ git diff
会表明这一点。一旦编辑了文件以解决冲突,
代码语言:javascript复制$ git commit -a
将提交合并的结果。最后,
代码语言:javascript复制$ gitk
将显示生成的历史记录的精美图形表示。
此时,您可以删除实验分支
代码语言:javascript复制$ git branch -d experimental
此命令可确保实验分支中的更改已在当前分支中。
如果你在一个分支疯狂的想法上发展,那么后悔它,你总是可以删除分支
代码语言:javascript复制$ git branch -D crazy-idea
分支机构既便宜又简单,所以这是尝试一些东西的好方法。
使用 Git 进行协作
假设 Alice 已经在/ home / alice / project 中启动了一个带有 Git 存储库的新项目,并且在同一台机器上有一个主目录的 Bob 想要贡献。
鲍勃开头:
代码语言:javascript复制bob$ git clone /home/alice/project myrepo
这将创建一个新目录“myrepo”,其中包含 Alice 的存储库的副本。克隆与原始项目处于同等地位,拥有自己原始项目历史的副本。
鲍勃然后进行一些更改并提交它们:
代码语言:javascript复制(edit files)
bob$ git commit -a
(repeat as necessary)
当他准备好时,他告诉 Alice 从/ home / bob / myrepo 的存储库中取出更改。她这样做:
代码语言:javascript复制alice$ cd /home/alice/project
alice$ git pull /home/bob/myrepo master
这将 Bob 的“主”分支的更改合并到 Alice 的当前分支中。如果 Alice 在此期间进行了自己的更改,那么她可能需要手动修复任何冲突。
因此,“pull”命令执行两个操作:它从远程分支获取更改,然后将它们合并到当前分支中。
请注意,一般情况下,Alice 会在启动此“拉动”之前希望提交本地更改。如果 Bob 的工作与 Alice 自其历史分歧后所做的工作冲突,Alice 将使用她的工作树和索引来解决冲突,现有的本地更改将干扰冲突解决过程(Git 仍将执行获取,但将拒绝合并 - - 爱丽丝将不得不以某种方式摆脱她的局部变化,并在发生这种情况时再次拉动)。
Alice 可以使用“fetch”命令查看 Bob 在没有合并的情况下做了什么。这允许 Alice 使用特殊符号“FETCH_HEAD”来检查 Bob 做了什么,以确定他是否有任何值得拉动的东西,如下所示:
代码语言:javascript复制alice$ git fetch /home/bob/myrepo master
alice$ git log -p HEAD..FETCH_HEAD
即使 Alice 有未提交的本地更改,此操作也是安全的。范围符号“HEAD…FETCH_HEAD”表示“显示可从 FETCH_HEAD 到达的所有内容,但排除可从 HEAD 访问的任何内容”。 Alice 已经知道了导致她当前状态(HEAD)的所有内容,并且回顾了 Bob 在他的状态(FETCH_HEAD)中没有看到的这个命令。
如果 Alice 想要想象自从他们的历史分叉后 Bob 做了什么,她可以发出以下命令:
代码语言:javascript复制$ gitk HEAD..FETCH_HEAD
这使用了我们之前在 git log 中看到的相同的双点范围表示法。
Alice 可能想要查看他们分叉后他们做了什么。她可以使用三点形式而不是两点形式:
代码语言:javascript复制$ gitk HEAD...FETCH_HEAD
这意味着“显示从任何一个都可以访问的所有内容,但排除可以从它们中访问的任何内容”。
请注意,这些范围表示法可以与 gitk 和“git log”一起使用。
在检查 Bob 做了什么之后,如果没有紧急情况,Alice 可能会决定继续工作而不会从 Bob 那里撤离。如果 Bob 的历史确实有 Alice 会立即需要的东西,那么 Alice 可以选择先将她的工作藏匿在一起,做一个“拉动”,然后在最终的历史记录之上最终取消正在进行的工作。
当您在一个小型紧密结合的小组中工作时,一遍又一遍地与同一个存储库进行交互并不罕见。通过定义 _ 远程 _ 存储库速记,您可以更轻松:
代码语言:javascript复制alice$ git remote add bob /home/bob/myrepo
有了这个,Alice 可以使用 git fetch 命令单独执行“pull”操作的第一部分,而无需将它们与自己的分支合并,使用:
代码语言:javascript复制alice$ git fetch bob
与简写形式不同,当 Alice 使用 git remote 设置的远程存储库速记从 Bob 获取时,所获取的内容存储在远程跟踪分支中,在本例中为bob/master
。所以在此之后:
alice$ git log -p master..bob/master
显示了 Bob 从 Alice 的主分支分支后所做的所有更改的列表。
检查完这些更改后,Alice 可以将更改合并到她的主分支中:
代码语言:javascript复制alice$ git merge bob/master
这merge
也可以通过 _ 从她自己的远程跟踪分支 _ 拉出来完成,如下所示:
alice$ git pull . remotes/bob/master
请注意,无论命令行上给出了什么,git pull 总是合并到当前分支中。
之后,Bob 可以使用 Alice 的最新更改来更新他的回购
代码语言:javascript复制bob$ git pull
请注意,他不需要提供 Alice 的存储库的路径;当 Bob 克隆了 Alice 的存储库时,Git 将她的存储库的位置存储在存储库配置中,该位置用于拉取:
代码语言:javascript复制bob$ git config --get remote.origin.url
/home/alice/project
( git clone 创建的完整配置使用git config -l
可见, git-config [1] 手册页解释了每个选项的含义。)
Git 还以“origin / master”的名义保留了 Alice 的主分支的原始副本:
代码语言:javascript复制bob$ git branch -r
origin/master
如果 Bob 后来决定在不同的主机上工作,他仍然可以使用 ssh 协议执行克隆和拉取:
代码语言:javascript复制bob$ git clone alice.org:/home/alice/project myrepo
或者,Git 有一个原生协议,或者可以使用 http;有关详细信息,请参阅 git-pull [1] 。
Git 也可以用于类似 CVS 的模式,具有各种用户推送更改的中央存储库;见 git-push [1] 和 gitcvs-migration [7] 。
探索历史
Git 历史表示为一系列相互关联的提交。我们已经看到 git log 命令可以列出这些提交。请注意,每个 git 日志条目的第一行也提供了提交的名称:
代码语言:javascript复制$ git log
commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
Author: Junio C Hamano <junkio@cox.net>
Date: Tue May 16 17:18:22 2006 -0700
merge-base: Clarify the comments on post processing.
我们可以将此名称赋予 git show 以查看有关此提交的详细信息。
代码语言:javascript复制$ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
但还有其他方法可以引用提交。您可以使用足够长的名称的任何初始部分来唯一标识提交:
代码语言:javascript复制$ git show c82a22c39c # the first few characters of the name are
# usually enough
$ git show HEAD # the tip of the current branch
$ git show experimental # the tip of the "experimental" branch
每个提交通常都有一个“父”提交,指向项目的先前状态:
代码语言:javascript复制$ git show HEAD^ # to see the parent of HEAD
$ git show HEAD^^ # to see the grandparent of HEAD
$ git show HEAD~4 # to see the great-great grandparent of HEAD
请注意,合并提交可能包含多个父级:
代码语言:javascript复制$ git show HEAD¹ # show the first parent of HEAD (same as HEAD^)
$ git show HEAD² # show the second parent of HEAD
您也可以提交自己的提交名称;跑完之后
代码语言:javascript复制$ git tag v2.5 1b2e1d63ff
您可以通过名称“v2.5”来引用 1b2e1d63ff。如果您打算与其他人共享此名称(例如,识别发布版本),您应该创建一个“标记”对象,并可能签名;有关详细信息,请参阅 git-tag [1] 。
任何需要知道提交的 Git 命令都可以使用任何这些名称。例如:
代码语言:javascript复制$ git diff v2.5 HEAD # compare the current HEAD to v2.5
$ git branch stable v2.5 # start a new branch named "stable" based
# at v2.5
$ git reset --hard HEAD^ # reset your current branch and working
# directory to its state at HEAD^
小心最后一个命令:除了丢失工作目录中的任何更改外,它还将删除此分支的所有后续提交。如果此分支是包含这些提交的唯一分支,则它们将丢失。此外,不要在其他开发人员从中公开可见的分支上使用 git reset ,因为它会迫使其他开发人员进行不必要的合并以清理历史记录。如果您需要撤消已推送的更改,请改用 git revert 。
git grep 命令可以在项目的任何版本中搜索字符串,所以
代码语言:javascript复制$ git grep "hello" v2.5
在 v2.5 中搜索所有出现的“hello”。
如果省略提交名称, git grep 将搜索它在当前目录中管理的任何文件。所以
代码语言:javascript复制$ git grep "hello"
是一种快速搜索 Git 跟踪的文件的方法。
许多 Git 命令也采用提交集,可以通过多种方式指定。以下是 git log 的一些示例:
代码语言:javascript复制$ git log v2.5..v2.6 # commits between v2.5 and v2.6
$ git log v2.5.. # commits since v2.5
$ git log --since="2 weeks ago" # commits from the last 2 weeks
$ git log v2.5.. Makefile # commits since v2.5 which modify
# Makefile
你也可以给 git log 一个“范围”的提交,其中第一个不一定是第二个的祖先;例如,如果分支“稳定”和“主”的提示在一段时间之前偏离了共同的提交,那么
代码语言:javascript复制$ git log stable..master
将列出在主分支中但不在稳定分支中进行的提交
代码语言:javascript复制$ git log master..stable
将显示在稳定分支上但不在主分支上进行的提交列表。
git log 命令有一个缺点:它必须在列表中显示提交。当历史中的发展线分散并然后合并在一起时, git log 呈现这些提交的顺序是没有意义的。
大多数具有多个贡献者的项目(例如 Linux 内核或 Git 本身)经常合并,而 gitk 在可视化其历史方面做得更好。例如,
代码语言:javascript复制$ gitk --since="2 weeks ago" drivers/
允许您浏览在“drivers”目录下修改文件的过去 2 周内提交的任何提交。 (注意:您可以在按下“ - ”或“ ”的同时按住控制键来调整 gitk 的字体。)
最后,大多数采用文件名的命令都可以选择允许您通过提交在任何文件名之前,以指定文件的特定版本:
代码语言:javascript复制$ git diff v2.5:Makefile HEAD:Makefile.in
您也可以使用 git show 查看任何此类文件:
代码语言:javascript复制$ git show v2.5:Makefile
下一步
本教程应足以为您的项目执行基本的分布式版本控制。但是,要完全理解 Git 的深度和强大功能,您需要了解它所基于的两个简单想法:
- 对象数据库是一个相当优雅的系统,用于存储项目文件,目录和提交的历史记录。
- 索引文件是目录树状态的缓存,用于创建提交,检出工作目录,以及保存合并中涉及的各种树。
本教程的第二部分解释了对象数据库,索引文件以及充分利用 Git 所需的其他一些可能性和结果。你可以在 gittutorial-2 [7] 找到它。
如果你不想马上继续这样做,那么在这一点上可能有趣的一些其他离题是:
- git-format-patch [1] , git-am [1] :这些将 git 提交系列转换成电子邮件补丁,反之亦然,对 Linux 内核等项目很有用它严重依赖于电子邮件补丁。
- git-bisect [1] :当项目中存在回归时,追踪错误的一种方法是搜索历史记录以查找应该归咎于的确切提交。 Git bisect 可以帮助您对该提交执行二进制搜索。即使在具有大量合并分支的复杂非线性历史的情况下,它也足够智能地执行接近最优的搜索。
- gitworkflows [7] :概述推荐的工作流程。
- giteveryday [7] :每天 Git 有 20 个命令或者所以。
- gitcvs-migration [7] :适用于 CVS 用户的 Git。
也可以看看
gittutorial-2 [7] , gitcvs-migration [7] , gitcore-tutorial [7] , gitglossary [7] , git-help [1] , gitworkflows [7] , giteveryday [7] , Git 用户手册
GIT
部分 git [1] 套件
gitworkflows
原文:
git-scm.com/docs/gitworkflows
名称
gitworkflows - 使用 Git 推荐的工作流程概述
概要
代码语言:javascript复制git *
描述
本文档试图记下并激发git.git
本身使用的一些工作流程元素。一般而言,许多想法都适用,但涉及较少人员的较小项目很少需要完整的工作流程。
我们制定了一套 _ 规则 _ 供快速参考,而散文则试图激励他们每个人。不要总是从字面上理解它们;你应该重视你的行动的好理由,而不是像这样的联机会。
单独更改
作为一般规则,您应该尝试将更改拆分为小的逻辑步骤,并提交每个更改。它们应该是一致的,独立于任何后期提交,通过测试套件等。这使得审查过程更加容易,并且历史对于以后的检查和分析更有用,例如 git-blame [1 ] 和 git-bisect [1] 。
要实现这一目标,请尝试从一开始就将工作分成小步骤。压缩一些提交总是比将一个大提交分成几个更容易。不要害怕沿途做太小或不完美的步骤。您可以随后返回并在发布之前使用git rebase --interactive
编辑提交。您可以使用git stash push --keep-index
独立于其他未提交的更改运行测试套件;参见 git-stash [1] 的实例部分。
管理分支
有两个主要工具可用于包括从一个分支到另一个分支的更改: git-merge [1] 和 git-cherry-pick [1] 。
合并有许多优点,因此我们尝试仅使用合并来解决尽可能多的问题。樱桃采摘仍然偶尔有用;请参阅下面的“向上合并”以获取示例。
最重要的是,合并工作在分支级别,而樱桃选择在提交级别工作。这意味着合并可以轻松地从 1 次,10 次或 1000 次提交中继承更改,这反过来意味着工作流程可以更好地扩展到大量贡献者(和贡献)。合并也更容易理解,因为合并提交是“承诺”,现在包括来自其所有父项的所有更改。
当然有一个权衡:合并需要更仔细的分支管理。以下小节讨论了重点。
毕业
由于给定的特征从实验到稳定,它也在软件的相应分支之间“毕业”。 git.git
使用以下 _ 集成分支 _:
- maint 跟踪应该进入下一个“维护版本”的提交,即更新最后发布的稳定版本;
- master 跟踪应该进入下一个版本的提交;
- next 旨在作为测试主要稳定性主题的测试分支。
第四个官方分支的使用方式略有不同:
- pu (建议更新)是一个集成分支,用于尚未准备好包含的内容(请参阅下面的“集成分支”)。
四个分支中的每一个通常是其上方的分支的直接后代。
从概念上讲,一旦被认为足够稳定,该特征进入不稳定的分支(通常是 _ 下一个 _ 或 pu ),并且“毕业”到 _ 主 _ 用于下一个版本。
合并向上
然而,上面讨论的“向下分度”不能通过实际向下合并来完成,因为这会将不稳定分支上的 _ 所有 _ 变化合并到稳定分支中。因此如下:
Rule: Merge upwards
始终将修复程序提交到需要它们的最旧的受支持分支。然后(周期性地)将集成分支向上合并到彼此中。
这提供了非常受控制的修复流程。如果您发现自己已将修复程序应用于例如在 maint 中也需要 master ,你需要向下挑选它(使用 git-cherry-pick [1] )。这种情况会发生几次,除非你经常这样做,否则无需担心。
主题分支
任何重要的功能都需要实现几个补丁,并且可能在其生命周期内获得额外的错误修正或改进。
直接在集成分支上提交所有内容会导致许多问题:糟糕的提交无法撤消,因此必须逐个还原,这会在您忘记还原一组更改时创建令人困惑的历史记录和进一步的错误可能性。并行工作混合了变化,造成了进一步的混乱。
使用“主题分支”解决了这些问题。这个名字非常自我解释,但有一个警告来自上面的“合并向上”规则:
Rule: Topic branches
为每个主题(功能,错误修复,…)制作一个侧支。在最旧的集成分支中解决它,您最终希望将其合并到其中。
然后很多事情可以很自然地完成:
- 要将功能/错误修复纳入集成分支,只需将其合并即可。如果主题在此期间进一步发展,请再次合并。 (请注意,您不必首先将其合并到最旧的集成分支。例如,您可以先将错误修复合并到 _ 下一个 _,给它一些测试时间,并合并到 maint 当你知道它是稳定的。)
- 如果您发现需要分支 _ 其他 _ 的新功能继续处理您的主题,请将 _ 其他 _ 合并到 _ 主题 _。 (但是,不要“习惯性地”这样做,见下文。)
- 如果您发现分叉错误的分支并希望“及时”移动它,请使用 git-rebase [1] 。
请注意,最后一点与其他两个点发生冲突:已在其他位置合并的主题不应重新绑定。请参阅 git-rebase [1] 中关于从上游重新恢复的部分。
我们应该指出,“习惯性地”(通常没有任何实际理由)将整合分支合并到您的主题中 - 并且通过扩展,将任何上游的内容合并到下游的任何内容 - 是不赞成的:
Rule: Merge to downstream only at well-defined points
除非有充分的理由,否则不要合并到下游:上游 API 更改会影响您的分支;你的分支机构不再干净地融入上游;等等
否则,合并到的主题突然包含多个(分离良好的)更改。由此导致的许多小合并将极大地混乱历史。后来调查文件历史记录的任何人都必须查明该合并是否会影响开发中的主题。上游甚至可能无意中被合并为“更稳定”的分支。等等。
扔掉一体化
如果您遵循最后一段,您现在将拥有许多小主题分支,偶尔会想知道它们是如何交互的。合并它们的结果可能甚至不起作用?但另一方面,我们希望避免将它们合并到任何“稳定”的位置,因为这样的合并不容易被撤消。
当然,解决方案是进行我们可以撤消的合并:合并到一个扔掉的分支。
Rule: Throw-away integration branches
要测试多个主题的交互,请将它们合并到一个扔掉的分支中。你必须永远不要在这样的分支上做任何工作!
如果你(非常)清楚地知道这个分支将在测试后立即被删除,你甚至可以发布这个分支,例如让测试人员有机会使用它,或者其他开发人员有机会看看他们是否正在进行的工作将是兼容的。 git.git
有一个名为 pu 的官方一次性集成分支。
发布的分支管理
假设您正在使用上面讨论的合并方法,当您发布项目时,您将需要执行一些额外的分支管理工作。
功能发布是从 _ 主 _ 分支创建的,因为 _ 主 _ 跟踪应该进入下一个功能发布的提交。
_ 主 _ 分支应该是 maint 的超集。如果此条件不成立,则 maint 包含一些未包含在 master 中的提交。因此,这些提交所代表的修补程序将不会包含在您的功能发行版中。
要验证 master 确实是 maint 的超集,请使用 git log:
Recipe: Verify master is a superset of maint
git log master..maint
此命令不应列出任何提交。否则,请检查 master 并将 maint 合并到其中。
现在,您可以继续创建功能发布。将标签应用于 master 的尖端,指示发布版本:
Recipe: Release tagging
git tag -s -m "Git X.Y.Z" vX.Y.Z master
您需要将新标记推送到公共 Git 服务器(请参阅下面的“DISTRIBUTED WORKFLOWS”)。这使得其他人可以使用该标签来跟踪您的项目。推送还可以触发更新后挂钩以执行与发布相关的项目,例如构建发布 tar 包和预格式化文档页面。
同样,对于维护版本, maint 正在跟踪要释放的提交。因此,在上述步骤中,只需标记并按 maint 而不是 master 。
功能发布后的维护分支管理
功能发布后,您需要管理维护分支。
首先,如果您希望继续发布在最近版本之前发布的功能版本的维护修补程序,那么您必须创建另一个分支来跟踪该先前版本的提交。
为此,将当前维护分支复制到以先前版本号命名的另一个分支(例如,maint-X.Y。(Z-1),其中 X.Y.Z 是当前版本)。
Recipe: Copy maint
git branch maint-X.Y.(Z-1) maint
现在应该将 maint 分支快速转发到新发布的代码,以便可以跟踪当前版本的维护修复:
Recipe: Update maint to new release
-
git checkout maint
-
git merge --ff-only master
如果合并失败,因为它不是快进,那么可能在功能发布中错过了 maint 的一些修复。如果按照上一节中的描述验证了分支的内容,则不会发生这种情况。
功能发布后的分支管理 for next 和 pu
功能发布后,集成分支 next 可以选择使用 next 上的幸存主题从 master 的尖端重绕并重建:
Recipe: Rewind and rebuild next
-
git checkout next
-
git reset --hard master
-
git merge ai/topic_in_next1
-
git merge ai/topic_in_next2
- …
这样做的好处是 next 的历史将是干净的。例如,合并到 _ 中的一些主题下一个 _ 可能最初看起来很有希望,但后来被发现是不合需要的或者是不成熟的。在这种情况下,主题将从 _ 下一个 _ 中恢复出来,但事实上它仍然存在于曾经合并和还原的历史中。通过重新创建 _ 下一个 _,你可以为这些主题提供另一个版本,以便重试,并且功能发布是历史上的一个好点。
如果你这样做,那么你应该做一个公告,表明[HTG0]下一个被重绕并重建。
对于 pu ,可以遵循相同的倒带和重建过程。如上所述,由于 pu 是丢弃分支,因此不需要公告。
分布式工作流程
在最后一节之后,您应该知道如何管理主题。一般而言,您不会是唯一从事该项目的人,因此您必须分享您的工作。
粗略地说,有两个重要的工作流程:合并和补丁。重要的区别在于合并工作流可以传播完整的历史记录,包括合并,而补丁则不能。两个工作流程都可以并行使用:在git.git
中,只有子系统维护人员使用合并工作流程,而其他人都发送补丁。
请注意,维护者可能会施加限制,例如“签名”要求,所有提交包含的提交/补丁必须遵守。有关更多信息,请参阅项目文档。
合并工作流程
合并工作流程通过在上游和下游之间复制分支来工作。上游可以将贡献合并到官方历史中;下游基地的工作在官方历史上。
有三种主要工具可用于此:
- git-push [1] 将您的分支复制到远程存储库,通常是一个可供所有相关方读取的存储库;
- git-fetch [1] 将远程分支复制到您的存储库;和
- git-pull [1] 一次性获取并合并。
注意最后一点。除非你真的想要合并远程分支,否则 _ 不能 _ 使用 git pull 。
更改很容易:
Recipe: Push/pull: Publishing branches/topics
git push <remote> <branch>
并告诉每个人他们可以从哪里取。
你仍然需要通过其他方式告诉别人,比如邮件。 (Git 提供 git-request-pull [1] 向上游维护者发送预先格式化的拉取请求,以简化此任务。)
如果您只想获得集成分支的最新副本,那么保持最新也很容易:
Recipe: Push/pull: Staying up to date
使用git fetch <remote>
或git remote update
保持最新。
然后简单地从稳定的遥控器中分叉您的主题分支,如前所述。
如果您是维护者并希望将其他人的主题分支合并到集成分支,他们通常会通过邮件发送请求。这样的请求看起来像
代码语言:javascript复制Please pull from
<url> <branch>
在这种情况下, git pull 可以一次性进行获取和合并,如下所示。
Recipe: Push/pull: Merging remote topics
git pull <url> <branch>
有时,维护者在尝试从下游提取更改时可能会发生合并冲突。在这种情况下,他们可以要求下游进行合并并自己解决冲突(也许他们会更好地了解如何解决它们)。这是下游 _ 应该 _ 从上游合并的罕见情况之一。
补丁工作流程
如果您是以电子邮件形式向上游发送更改的贡献者,您应该像往常一样使用主题分支(参见上文)。然后使用 git-format-patch [1] 生成相应的电子邮件(强烈建议手动格式化它们,因为它使维护者的生活更轻松)。
Recipe: format-patch/am: Publishing branches/topics
-
git format-patch -M upstream..topic
将它们转换为预先格式化的补丁文件 -
git send-email --to=<recipient> <patches>
有关更多使用说明,请参阅 git-format-patch [1] 和 git-send-email [1] 联机帮助页。
如果维护者告诉您补丁不再适用于当前的上游,则必须重新定义主题(您不能使用合并,因为您无法格式化补丁合并):
Recipe: format-patch/am: Keeping topics up to date
git pull --rebase <url> <branch>
然后,您可以在 rebase 期间修复冲突。大概你没有通过邮件发布你的主题,所以重新定位它不是问题。
如果您收到这样的补丁系列(作为维护者,或者作为发送给它的邮件列表的读者),将邮件保存到文件,创建一个新的主题分支并使用 git am 导入承诺:
Recipe: format-patch/am: Importing patches
git am < patch
值得指出的一个特性是三向合并,如果遇到冲突可以提供帮助:git am -3
将使用补丁中包含的索引信息来确定合并基础。有关其他选项,请参阅 git-am [1] 。
也可以看看
gittutorial [7] , git-push [1] , git-pull [1] , git-merge [1] , git-rebase [1] , git-format-patch [1] , git-send-email [1] , git-am [ 1]
GIT
部分 git [1] 套件
git-am
原文:
git-scm.com/docs/git-am
名称
git-am - 从邮箱中应用一系列补丁
概要
代码语言:javascript复制git am [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8]
[--[no-]3way] [--interactive] [--committer-date-is-author-date]
[--ignore-date] [--ignore-space-change | --ignore-whitespace]
[--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
[--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
[--[no-]scissors] [-S[<keyid>]] [--patch-format=<format>]
[(<mbox> | <Maildir>)…]
git am (--continue | --skip | --abort | --quit | --show-current-patch)
描述
将邮箱中的邮件拆分为提交日志消息,作者信息和修补程序,并将其应用于当前分支。
OPTIONS
代码语言:javascript复制 (<mbox>|<Maildir>)…
要从中读取修补程序的邮箱文件列表。如果您不提供此参数,则该命令将从标准输入读取。如果您提供目录,它们将被视为 Maildirs。
代码语言:javascript复制 -s
代码语言:javascript复制 --signoff
使用您自己的提交者标识在提交消息中添加Signed-off-by:
行。有关详细信息,请参阅 git-commit [1] 中的签收选项。
-k
代码语言:javascript复制 --keep
将-k
标志传递给 git mailinfo (参见 git-mailinfo [1] )。
--keep-non-patch
将-b
标志传递给 git mailinfo (参见 git-mailinfo [1] )。
--[no-]keep-cr
使用--keep-cr
,使用相同选项调用 git mailsplit (参见 git-mailsplit [1] ),以防止它在行末端剥离 CR。 am.keepcr
配置变量可用于指定默认行为。 --no-keep-cr
可用于覆盖am.keepcr
。
-c
代码语言:javascript复制 --scissors
在剪刀线之前移除体内的所有物体(参见 git-mailinfo [1] )。默认情况下可以使用mailinfo.scissors
配置变量激活。
--no-scissors
忽略剪刀线(见 git-mailinfo [1] )。
代码语言:javascript复制 -m
代码语言:javascript复制 --message-id
将-m
标志传递给 git mailinfo (参见 git-mailinfo [1] ),以便将 Message-ID 标头添加到提交消息中。 am.messageid
配置变量可用于指定默认行为。
--no-message-id
不要将 Message-ID 标头添加到提交消息中。 no-message-id
用于覆盖am.messageid
。
-q
代码语言:javascript复制 --quiet
安静。仅打印错误消息。
代码语言:javascript复制 -u
代码语言:javascript复制 --utf8
将-u
标志传递给 git mailinfo (参见 git-mailinfo [1] )。从电子邮件中获取的建议提交日志消息被重新编码为 UTF-8 编码(配置变量i18n.commitencoding
可用于指定项目的首选编码,如果它不是 UTF-8)。
这在 git 的早期版本中是可选的,但现在它是默认的。您可以使用--no-utf8
覆盖它。
--no-utf8
将-n
标志传递给 git mailinfo (参见 git-mailinfo [1] )。
-3
代码语言:javascript复制 --3way
代码语言:javascript复制 --no-3way
当补丁不能干净地应用时,如果补丁记录了它应该应用的 blob 的身份,则回退到三向合并,并且我们在本地可以使用这些 blob。 --no-3way
可用于覆盖 am.threeWay 配置变量。有关更多信息,请参阅 git-config [1] 中的 am.threeWay。
--ignore-space-change
代码语言:javascript复制 --ignore-whitespace
代码语言:javascript复制 --whitespace=<option>
代码语言:javascript复制 -C<n>
代码语言:javascript复制 -p<n>
代码语言:javascript复制 --directory=<dir>
代码语言:javascript复制 --exclude=<path>
代码语言:javascript复制 --include=<path>
代码语言:javascript复制 --reject
这些标志传递给应用补丁的 git apply (参见 git-apply [1] )程序。
代码语言:javascript复制 --patch-format
默认情况下,该命令将尝试自动检测修补程序格式。此选项允许用户绕过自动检测并指定应将补丁解释为的补丁格式。有效格式为 mbox,mboxrd,stgit,stgit-series 和 hg。
代码语言:javascript复制 -i
代码语言:javascript复制 --interactive
以交互方式运行。
代码语言:javascript复制 --committer-date-is-author-date
默认情况下,该命令将电子邮件中的日期记录为提交作者日期,并使用提交创建时间作为提交者日期。这允许用户使用与作者日期相同的值来说谎提交者日期。
代码语言:javascript复制 --ignore-date
默认情况下,该命令将电子邮件中的日期记录为提交作者日期,并使用提交创建时间作为提交者日期。这允许用户使用与提交者日期相同的值来欺骗作者日期。
代码语言:javascript复制 --skip
跳过当前的补丁。这仅在重新启动已中止的修补程序时才有意义。
代码语言:javascript复制 -S[<keyid>]
代码语言:javascript复制 --gpg-sign[=<keyid>]
GPG 签名提交。 keyid
参数是可选的,默认为提交者标识;如果指定,它必须粘在没有空格的选项上。
--continue
代码语言:javascript复制 -r
代码语言:javascript复制 --resolved
在修补程序失败(例如,尝试应用冲突的修补程序)之后,用户已手动应用它并且索引文件存储应用程序的结果。使用从电子邮件和当前索引文件中提取的作者和提交日志进行提交,然后继续。
代码语言:javascript复制 --resolvemsg=<msg>
当发生补丁失败时,< msg>将在退出前打印到屏幕上。这将覆盖标准消息,通知您使用--continue
或--skip
来处理故障。这仅供 git rebase 和 git am 之间的内部使用。
--abort
恢复原始分支并中止修补操作。
代码语言:javascript复制 --quit
中止修补操作但保持 HEAD 和索引不变。
代码语言:javascript复制 --show-current-patch
显示因“冲突”而停止“git am”时正在应用的补丁。
讨论
提交作者姓名取自消息的“发件人:”行,提交作者日期取自消息的“日期:”行。在剥离公共前缀“[PATCH< anything>]”之后,“Subject:”行被用作提交的标题。 “Subject:”行应该在一行文本中简明地描述提交的内容。
“From:”和“Subject:”行开始正文覆盖从标题中获取的相应提交作者姓名和标题值。
提交消息由从“主题:”获取的标题,空白行和消息正文直到补丁开始的位置形成。每行末尾的多余空格会自动删除。
该补丁预计将是内联的,直接跟在消息之后。任何形式的行:
- 三个破折号和行尾,或
- 以“diff - ”开头的行,或
- 一行以“索引:”开头
被视为补丁的开头,并且在第一次出现这样的行之前终止提交日志消息。
最初调用git am
时,为其指定要处理的邮箱的名称。在看到第一个不适用的补丁时,它会在中间中止。您可以通过以下两种方式之一从中恢复:
- 通过使用
--skip
选项重新运行命令来跳过当前补丁。 - 手解决工作目录中的冲突,并更新索引文件,使其进入补丁应生成的状态。然后使用
--continue
选项运行命令。
该命令在当前操作完成之前拒绝处理新邮箱,因此如果您决定从头开始,请在运行带有邮箱名称的命令之前运行git am --abort
。
在应用任何补丁之前,ORIG_HEAD 设置为当前分支的尖端。如果您遇到多次提交有问题,例如在错误的分支上运行 git am ,或者通过更改邮箱更容易修复提交中的错误(例如“From:”行中的错误),这很有用)。
挂钩
该命令可以运行applypatch-msg
,pre-applypatch
和post-applypatch
挂钩。有关详细信息,请参阅 githooks [5] 。
也可以看看
git-apply [1] 。
GIT
部分 git [1] 套件