Git 中文参考(三)(3)https://developer.aliyun.com/article/1565822
使用-p 生成补丁
当“git-diff-index”,“git-diff-tree”或“git-diff-files”使用-p
选项运行时,“git diff”不带--raw
选项或“git log”使用“-p”选项,它们不会产生上述输出;相反,他们生成一个补丁文件。您可以通过GIT_EXTERNAL_DIFF
和GIT_DIFF_OPTS
环境变量自定义此类修补程序的创建。
-p 选项产生的内容与传统的 diff 格式略有不同:
- 它前面有一个“git diff”标题,如下所示:
diff --git a/file1 b/file2
- 除非涉及重命名/复制,否则
a/
和b/
文件名是相同的。特别是,即使是创建或删除,/dev/null
也是 _ 而不是 _ 来代替a/
或b/
文件名。
当涉及重命名/复制时,file1
和file2
分别显示重命名/复制的源文件的名称和重命名/复制的文件的名称。 - 它后跟一个或多个扩展标题行:
old mode <mode> new mode <mode> deleted file mode <mode> new file mode <mode> copy from <path> copy to <path> rename from <path> rename to <path> similarity index <number> dissimilarity index <number> index <hash>..<hash> <mode>
- 文件模式打印为 6 位八进制数,包括文件类型和文件权限位。
扩展标头中的路径名不包括a/
和b/
前缀。
相似性指数是未更改行的百分比,相异性指数是更改行的百分比。它是一个向下舍入的整数,后跟一个百分号。因此,100%的相似性索引值保留用于两个相等的文件,而 100%的相异性意味着旧文件中的任何行都不会成为新文件。
索引行包括更改前后的 SHA-1 校验和。 <模式>如果文件模式没有改变,则包括在内;否则,单独的行表示旧模式和新模式。 - 具有“异常”字符的路径名被引用,如配置变量
core.quotePath
所述(参见 git-config [1] )。 - 输出中的所有
file1
文件在提交之前引用文件,并且所有file2
文件在提交之后引用文件。将每个更改顺序应用于每个文件是不正确的。例如,此补丁将交换 a 和 b:
diff --git a/a b/b rename from a rename to b diff --git a/b b/a rename from b rename to a
组合差异格式
在显示合并时,任何差异生成命令都可以使用-c
或--cc
选项生成 _ 组合差异 _。当显示与 git-diff [1] 或 git-show [1] 的合并时,这是默认格式。另请注意,您可以为这些命令中的任何一个提供-m
选项,以强制使用合并的各个父项生成差异。
_ 组合 diff_ 格式如下所示:
diff --combined describe.c index fabadb8,cc95eb0..4866510 --- a/describe.c +++ b/describe.c @@@ -98,20 -98,12 +98,20 @@@ return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1; } - static void describe(char *arg) -static void describe(struct commit *cmit, int last_one) ++static void describe(char *arg, int last_one) { + unsigned char sha1[20]; + struct commit *cmit; struct commit_list *list; static int initialized = 0; struct commit_name *n; + if (get_sha1(arg, sha1) < 0) + usage(describe_usage); + cmit = lookup_commit_reference(sha1); + if (!cmit) + usage(describe_usage); + if (!initialized) { initialized = 1; for_each_ref(get_name);
- 它前面有一个“git diff”标题,看起来像这样(当使用
-c
选项时):
diff --combined file
- 或者像这样(当使用
--cc
选项时):
diff --cc file
- 它后跟一个或多个扩展标题行(此示例显示了与两个父项的合并):
index <hash>,<hash>..<hash> mode <mode>,<mode>..<mode> new file mode <mode> deleted file mode <mode>,<mode>
- 只有当< mode>中的至少一个出现时,
mode ,..
行才会出现。与其他人不同。具有关于检测到的内容移动(重命名和复制检测)的信息的扩展标题被设计为与两个< tree-ish>的差异一起工作。并且不会被组合 diff 格式使用。 - 接下来是两行的文件/文件头
--- a/file +++ b/file
- 与传统 _ 统一 _ diff 格式的双行标题类似,
/dev/null
用于表示创建或删除的文件。 - 修改了块头格式以防止人们意外地将其馈送到
patch -p1
。创建组合差异格式用于审查合并提交更改,并不适用于应用。此更改类似于扩展 _ 索引 _ 标头中的更改:
@@@ <from-file-range> <from-file-range> <to-file-range> @@@
- 组合 diff 格式的块头中有(父项数+ 1)
@
个字符。
与传统的 _ 统一 _ 差异格式不同,后者显示两个文件 A 和 B,其中一列具有-
(减去 - 出现在 A 中但在 B 中删除),+
(加 - 缺少 A 但是添加到 B)或" "
(空格 - 未更改)前缀,此格式将两个或多个文件 file1,file2,…与一个文件 X 进行比较,并显示 X 与每个文件 N 的不同之处。每个 fileN 的一列被添加到输出行之前,以指示 X 的行与它的不同之处。
N 列中的-
字符表示该行出现在 fileN 中,但它不会出现在结果中。列 N 中的+
字符表示该行出现在结果中,而 fileN 没有该行(换句话说,从该父项的角度添加了该行)。
在上面的示例输出中,函数签名已从两个文件中更改(因此,file1 和 file2 中的两个-
删除加上++
表示添加的一行未出现在 file1 或 file2 中)。另外八行与 file1 相同,但不出现在 file2 中(因此以+
为前缀)。
当由git diff-tree -c
显示时,它将合并提交的父项与合并结果进行比较(即 file1…fileN 是父项)。当由git diff-files -c
显示时,它将两个未解析的合并父项与工作树文件进行比较(即 file1 是阶段 2 又名“我们的版本”,file2 是阶段 3 又名“他们的版本”)。
例子
git log --no-merges
显示整个提交历史记录,但跳过任何合并
git log v2.6.12.. include/scsi drivers/scsi
显示自版本 v2.6.12 以来更改include/scsi
或drivers/scsi
子目录中的任何文件的所有提交
git log --since="2 weeks ago" -- gitk
在过去两周内将更改显示到文件 gitk 。 --
是必要的,以避免与名为 gitk 的分支混淆
git log --name-status release..test
显示“test”分支中但尚未在“release”分支中的提交,以及每个提交修改的路径列表。
git log --follow builtin/rev-list.c
显示更改builtin/rev-list.c
的提交,包括在文件被赋予其当前名称之前发生的提交。
git log --branches --not --remotes=origin
显示任何本地分支中的所有提交,但不显示 _ 原点 _ 的任何远程跟踪分支中的所有提交(您的原点没有)。
git log master --not --remotes=*/master
显示本地主服务器中但不在任何远程存储库主分支中的所有提交。
git log -p -m --first-parent
显示包含更改差异的历史记录,但仅显示“主分支”透视图,跳过来自合并分支的提交,并显示合并引入的完整更改差异。只有遵循严格的策略,在停留在单个集成分支上时合并所有主题分支才有意义。
git log -L '/int main/',/^}/:main.c
显示文件main.c
中的函数main()
如何随时间演变。
git log -3
将要显示的提交数限制为 3。
讨论
Git 在某种程度上是字符编码不可知的。
- blob 对象的内容是未解释的字节序列。核心级别没有编码转换。
- 路径名以 UTF-8 规范化形式 C 编码。这适用于树对象,索引文件,ref 名称,以及命令行参数,环境变量和配置文件中的路径名(
.git/config
(参见 git) -config [1] ), gitignore [5] , gitattributes [5] 和 gitmodules [5] )。
请注意,核心级别的 Git 仅将路径名称视为非 NUL 字节序列,没有路径名称编码转换(Mac 和 Windows 除外)。因此,即使在使用传统扩展 ASCII 编码的平台和文件系统上,使用非 ASCII 路径名也会起作用。但是,在此类系统上创建的存储库将无法在基于 UTF-8 的系统(例如 Linux,Mac,Windows)上正常工作,反之亦然。此外,许多基于 Git 的工具只是假设路径名为 UTF-8,并且无法正确显示其他编码。 - 提交日志消息通常以 UTF-8 编码,但也支持其他扩展 ASCII 编码。这包括 ISO-8859-x,CP125x 和许多其他,但 _ 不是 _ UTF-16/32,EBCDIC 和 CJK 多字节编码(GBK,Shift-JIS,Big5,EUC-x,CP9xx 等。 )。
虽然我们鼓励提交日志消息以 UTF-8 编码,但核心和 Git 瓷器都不是为了强制项目使用 UTF-8。如果特定项目的所有参与者发现使用遗留编码更方便,Git 不会禁止它。但是,有一些事情需要牢记。
- git commit 和 git commit-tree 发出警告,如果提供给它的提交日志消息看起来不像有效的 UTF-8 字符串,除非你明确说你的项目使用了遗产编码。说这个的方法是在
.git/config
文件中使用 i18n.commitencoding,如下所示:
[i18n] commitEncoding = ISO-8859-1
- 使用上述设置创建的提交对象在其
encoding
标题中记录i18n.commitEncoding
的值。这是为了帮助其他人以后再看。缺少此标头意味着提交日志消息以 UTF-8 编码。 - git log , git show , git blame 和朋友们查看提交对象的
encoding
头,并尝试将日志消息重新编码为除非另有说明,否则为 UTF-8。您可以使用.git/config
文件中的i18n.logOutputEncoding
指定所需的输出编码,如下所示:
[i18n] logOutputEncoding = ISO-8859-1
- 如果您没有此配置变量,则使用
i18n.commitEncoding
的值。
请注意,我们故意选择在提交以在提交对象级别强制使用 UTF-8 时不重新编写提交日志消息,因为重新编码为 UTF-8 不一定是可逆操作。
组态
对于核心变量,请参见 git-config [1] ,对于差异生成,请参见 git-diff [1] 。
format.pretty
--format
选项的默认值。 (参见上面的 _ 漂亮格式 _。)默认为medium
。
i18n.logOutputEncoding
显示日志时使用的编码。 (参见上面的 _ 讨论 _。)如果设置,则默认为i18n.commitEncoding
的值,否则为 UTF-8。
log.date
人类可读日期的默认格式。 (比较--date
选项。)默认为“默认”,表示写入Sat May 8 19:35:34 2010 -0500
等日期。
如果格式设置为“auto:foo”并且正在使用寻呼机,则格式“foo”将用于日期格式。否则将使用“默认”。
log.follow
如果true
,git log
将像单个<路径>一样使用--follow
选项。给出。这与--follow
具有相同的限制,即它不能用于跟踪多个文件,并且在非线性历史记录上不能很好地工作。
log.showRoot
如果false
,git log
和相关命令不会将初始提交视为大创建事件。 git log -p
输出中的任何根提交都将显示没有附加差异。默认值为true
。
log.showSignature
如果true
,git log
和相关命令的作用就像传递了--show-signature
选项一样。
mailmap.*
见 git-shortlog [1] 。
notes.displayRef
除了core.notesRef
或GIT_NOTES_REF
设置的默认值之外,还使用log
系列命令显示提交消息时的注释。见 git-notes [1] 。
可以是未缩写的引用名称或 glob,可以多次指定。将为不存在的引用发出警告,但是会自动忽略与任何引用不匹配的 glob。
可以通过--no-notes
选项禁用此设置,由GIT_NOTES_DISPLAY_REF
环境变量覆盖,并由--notes=
选项覆盖。
GIT
部分 git [1] 套件
git-stash
名称
git-stash - 将更改存储在脏工作目录中
概要
git stash list [<options>] git stash show [<stash>] git stash drop [-q|--quiet] [<stash>] git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>] git stash branch <branchname> [<stash>] git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] [-u|--include-untracked] [-a|--all] [-m|--message <message>] [--] [<pathspec>…]] git stash clear git stash create [<message>] git stash store [-m|--message <message>] [-q|--quiet] <commit>
描述
如果要记录工作目录和索引的当前状态,但想要返回到干净的工作目录,请使用git stash
。该命令将保存您的本地修改并恢复工作目录以匹配HEAD
提交。
此命令隐藏的修改可以使用git stash list
列出,使用git stash show
进行检查,并使用git stash apply
恢复(可能在不同的提交之上)。不带任何参数调用git stash
等同于git stash push
。默认情况下,存储被列为“ branchname 上的 WIP …”,但您可以在创建存储时在命令行上提供更具描述性的消息。
您创建的最新存储存储在refs/stash
中;在此引用的 reflog 中可以找到较旧的 stashes,并且可以使用通常的 reflog 语法命名(例如stash@{0}
是最近创建的 stash,stash@{1}
是之前的那个,stash@{2.hours.ago}
也是可能的)。也可以通过仅指定存储索引来引用状态(例如,整数n
等同于stash@{n}
)。
OPTIONS
push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>…]
将本地修改保存到新的 _ 存储条目 _ 并将它们回滚到 HEAD(在工作树和索引中)。 < message> part 是可选的,并提供描述以及 stashed 状态。
要快速创建快照,可以省略“推送”。在此模式下,不允许使用非选项参数来防止拼写错误的子命令生成不需要的存储条目。对此的两个例外是stash -p
,它作为stash push -p
和 pathspecs 的别名,在双连字符--
之后允许消除歧义。
当 pathspec 被赋予 git stash push 时,新的存储条目仅记录与 pathspec 匹配的文件的修改状态。然后,索引条目和工作树文件也仅针对这些文件回滚到 HEAD 中的状态,从而保留与 pathspec 不匹配的文件。
如果使用--keep-index
选项,则已添加到索引的所有更改都将保持不变。
如果使用--include-untracked
选项,所有未跟踪的文件也会被隐藏,然后使用git clean
清除,使工作目录处于非常干净的状态。如果使用--all
选项,则除了未跟踪的文件外,还会隐藏和清除被忽略的文件。
使用--patch
,您可以交互式地从 HEAD 和工作树之间的差异中选择要存储的数据。构建存储条目,使其索引状态与存储库的索引状态相同,并且其工作树仅包含您以交互方式选择的更改。然后,从您的工作树中回滚所选更改。请参阅 git-add [1] 的“交互模式”部分,了解如何操作--patch
模式。
--patch
选项意味着--keep-index
。您可以使用--no-keep-index
覆盖它。
save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]
不推荐使用此选项,而使用 git stash push 。它与“stash push”的不同之处在于它不能采用 pathspecs,并且任何非选项参数都构成了消息。
list [<options>]
列出您当前拥有的存储条目。列出每个 _ 存储条目 _ 及其名称(例如stash@{0}
是最新条目,stash@{1}
是之前的条目,等等),条目的当前分支名称,以及条目所基于的提交的简短描述。
stash@{0}: WIP on submit: 6ebd0e2... Update git-stash documentation stash@{1}: On master: 9cc0589... Add git-stash
该命令采用适用于 git log 命令的选项来控制显示的内容和方式。参见 git-log [1] 。
show [<stash>]
将存储条目中记录的更改显示为隐藏内容与首次创建存储条目时的提交之间的差异。如果没有给出,则显示最新的一个。默认情况下,该命令显示 diffstat,但它将接受 git diff 已知的任何格式(例如,
git stash show -p stash@{1}
以补丁形式查看第二个最新条目)。您可以使用 stash.showStat 和/或 stash.showPatch 配置变量来更改默认行为。
pop [--index] [-q|--quiet] [<stash>]
从存储列表中删除单个隐藏状态并将其应用于当前工作树状态之上,即执行git stash push
的反向操作。工作目录必须与索引匹配。
应用国家可能会因冲突而失败;在这种情况下,它不会从隐藏列表中删除。您需要手动解决冲突并随后手动调用git stash drop
。
如果使用--index
选项,则尝试不仅恢复工作树的更改,还尝试恢复索引的更改。但是,如果存在冲突(存储在索引中,因此您无法再像以前那样应用更改),则可能会失败。
如果没有给出,则假定为
stash@{0}
,否则必须是
stash@{}
形式的参考。
apply [--index] [-q|--quiet] [<stash>]
与pop
类似,但不要从隐藏列表中删除状态。与pop
不同,可能是任何看似由
stash push
或stash create
创建的提交的提交。
branch <branchname> [<stash>]
创建并检出一个名为的新分支,从最初创建
的提交开始,将
中记录的更改应用于新的工作树和索引。如果成功,
是
stash@{}
形式的参考,则它会丢弃。如果没有给出
,则应用最新的一个。
如果运行git stash push
的分支已经发生了足够的变化,使得git stash apply
因冲突而失败,这将非常有用。由于存储条目应用于git stash
运行时 HEAD 的提交之上,因此它恢复原始存储状态而没有冲突。
clear
删除所有存储条目。请注意,这些条目将进行修剪,并且可能无法恢复(请参阅下面的 _ 示例 _ 以获取可能的策略)。
drop [-q|--quiet] [<stash>]
从存储条目列表中删除单个存储条目。如果没有给出,它将删除最新的一个。即
stash@{0}
,否则必须是
stash@{}
形式的有效存储日志引用。
create
创建一个存储条目(这是一个常规提交对象)并返回其对象名称,而不将其存储在 ref 命名空间中的任何位置。这对脚本非常有用。它可能不是你想要使用的命令;看到上面的“推”。
store
存储通过 _git stash 创建的给定存储创建 _(这是一个悬空的合并提交)在存储引用中,更新存储 reflog。这对脚本非常有用。它可能不是你想要使用的命令;看到上面的“推”。
讨论
存储条目表示为提交,其树记录工作目录的状态,其第一个父项是创建条目时HEAD
的提交。第二个父树的树在创建条目时记录索引的状态,并且它成为HEAD
提交的子代。祖先图如下所示:
.----W / / -----H----I
其中H
是HEAD
提交,I
是记录索引状态的提交,W
是记录工作树状态的提交。
例子
Pulling into a dirty tree
当您处于某种状态时,您会发现存在可能与您正在进行的操作相关的上游更改。当您的本地更改不与上游的更改冲突时,一个简单的git pull
将让您继续前进。
但是,在某些情况下,您的本地更改会与上游更改发生冲突,git pull
会拒绝覆盖您的更改。在这种情况下,您可以隐藏您的更改,执行拉动,然后取消暂停,如下所示:
$ git pull ... file foobar not up to date, cannot merge. $ git stash $ git pull $ git stash pop
Interrupted workflow
当你处于中间状态时,你的老板会进来并要求你立即修理。传统上,您将提交临时分支以存储您的更改,并返回到原始分支以进行紧急修复,如下所示:
# ... hack hack hack ... $ git checkout -b my_wip $ git commit -a -m "WIP" $ git checkout master $ edit emergency fix $ git commit -a -m "Fix in a hurry" $ git checkout my_wip $ git reset --soft HEAD^ # ... continue hacking ...
您可以使用 git stash 来简化上述操作,如下所示:
# ... hack hack hack ... $ git stash $ edit emergency fix $ git commit -a -m "Fix in a hurry" $ git stash pop # ... continue hacking ...
Testing partial commits
如果要从工作树中的更改中进行两次或更多次提交,并且希望在提交之前测试每个更改,则可以使用git stash push --keep-index
:
# ... hack hack hack ... $ git add --patch foo # add just first part to the index $ git stash push --keep-index # save all other changes to the stash $ edit/build/test first part $ git commit -m 'First part' # commit fully tested change $ git stash pop # prepare to work on all other changes # ... repeat above five steps until one commit remains ... $ edit/build/test remaining parts $ git commit foo -m 'Remaining parts'
Recovering stash entries that were cleared/dropped erroneously
如果您错误地删除或清除了存储条目,则无法通过正常的安全机制恢复它们。但是,您可以尝试以下咒语来获取仍在存储库中但不再可访问的存储条目列表:
git fsck --unreachable | grep commit | cut -d\ -f3 | xargs git log --merges --no-walk --grep=WIP
也可以看看
git-checkout [1] , git-commit [1] , git-reflog [1] , git-reset [1]
GIT
部分 git [1] 套件
Git 中文参考(三)(5)https://developer.aliyun.com/article/1565824