包含合并的目录的 Git 日志

  • 本文关键字:Git 日志 合并 包含 git
  • 更新时间 :
  • 英文 :


我正在编写一个脚本,该脚本将路径作为参数并输出该路径的 Git 提交,类似于 GitHub 在某个文件夹中单击"历史记录"按钮时所做的(下面是一个示例)。本质上,我想这样写脚本:

git log -10 --oneline -- "$directory"

但是,我很难让它可靠地用于根文件夹和子目录,以及follow行为的各种配置。在下面的实验之后,我也认为我首先误解了git log如何使用各种标志,所以如果有人能帮助我理解这一点,那就太好了。

注意:在我们的例子中,我们有时需要传递多个目录,这就是为什么我试图使pathspec工作,而不是像cd subdirectory && git log这样的东西。

这些示例来自versionpress/versionpress存储库(处于 2071052a 状态),我已经在 Windows 2.17.1.windows.2 的 Git 和带有 Git 2.14.1 的 Linux 上对其进行了测试。

首先,docs文件夹的基本日志:

$ git log -10 --oneline -- docs
81554a46 Small updates of Dev-Setup.md
84d3229e Updated intro message to mention beta instead of alpha
8244d42a Added link to announcement blog post
da97c7c3 Merge branch 'master' into 1263-pre-4.0beta-polish
5c99bc30 Merge pull request #1270 from versionpress/4.0-beta-release-notes
f22b0e27 4.0-beta release notes updated, are now close to final
f0de171f Specific WordPress version used in dev-env Dockerfile, Dev-Setup slightly updated
bcd6d4e8 package-lock JSONs updated for npm 5.1 (there were some issues reported with 5.0)
1438bc43 Documented running tests by picking a test suite from phpunit.xml, the "other tests" documented in more detail
5af500d4 Better instructions on running specific tests from CLI, tests' docker-compose.yml cleaned up, various other testing "readme" updates

很好,这与GitHub上相同。

现在,根目录也是如此:

$ git log -10 --oneline -- .
94084136 Typo in the activation message
8a15a8b1 Added error when re-activating VP with WP CLI
6ad07b7d package-lock.json updated
e7e356f8 Updated WP and WP-CLI versions in ext-libs
777e2d05 Disable event propagation after click on the commit table checkbox
81554a46 Small updates of Dev-Setup.md
32d6dbe2 Installed WordPress version bumpted to 4.9
459c2e6d package-lock.json updated for npm 5.5
77ad593c Link to Gitter and support repo in ISSUE_TEMPLATE.md
84d3229e Updated intro message to mention beta instead of alpha

不好,缺少合并提交。我可以删除路径规范来获取它们:

$ git log -10 --oneline
2071052a (HEAD -> master, temp/master, origin/master, origin/HEAD) Merge pull request #1318 from aidik/master
94084136 Typo in the activation message
129bf972 Merge pull request #1314 from x1024/master
8a15a8b1 Added error when re-activating VP with WP CLI
288e305d Merge pull request #1310 from versionpress/1307-wp-update-fixes
6ad07b7d package-lock.json updated
e7e356f8 Updated WP and WP-CLI versions in ext-libs
f8d22592 Merge pull request #1309 from versionpress/1308-fix-commits-table-checkboxes
777e2d05 Disable event propagation after click on the commit table checkbox
06208405 Merge pull request #1307 from versionpress/wp-4.9-for-test-sites

但这对我的脚本来说是不切实际的,而且我认为我做错了什么,因为我相信git loggit log -- .的输出应该是相同的,不是吗?

从我的实验来看,--full-history标志似乎在.目录上运行时添加了合并提交:

$ git log -10 --oneline --full-history -- .
2071052a (HEAD -> master, temp/master, origin/master, origin/HEAD) Merge pull request #1318 from aidik/master
94084136 Typo in the activation message
129bf972 Merge pull request #1314 from x1024/master
8a15a8b1 Added error when re-activating VP with WP CLI
288e305d Merge pull request #1310 from versionpress/1307-wp-update-fixes
6ad07b7d package-lock.json updated
e7e356f8 Updated WP and WP-CLI versions in ext-libs
f8d22592 Merge pull request #1309 from versionpress/1308-fix-commits-table-checkboxes
777e2d05 Disable event propagation after click on the commit table checkbox
06208405 Merge pull request #1307 from versionpress/wp-4.9-for-test-sites

但是,它会"破坏"docs子目录(请注意不应该存在的第一个合并提交):

$ git log -10 --oneline --full-history -- docs
06208405 Merge pull request #1307 from versionpress/wp-4.9-for-test-sites
81554a46 Small updates of Dev-Setup.md
84d3229e Updated intro message to mention beta instead of alpha
8244d42a Added link to announcement blog post
9671af87 (tag: 4.0-beta) Merge pull request #1283 from versionpress/1263-pre-4.0beta-polish
da97c7c3 Merge branch 'master' into 1263-pre-4.0beta-polish
5c99bc30 Merge pull request #1270 from versionpress/4.0-beta-release-notes
f22b0e27 4.0-beta release notes updated, are now close to final
f0de171f Specific WordPress version used in dev-env Dockerfile, Dev-Setup slightly updated
bcd6d4e8 package-lock JSONs updated for npm 5.1 (there were some issues reported with 5.0)

这可以通过添加--simplify-merges来"修复":

$ git log -10 --oneline --full-history --simplify-merges -- docs
81554a46 Small updates of Dev-Setup.md
84d3229e Updated intro message to mention beta instead of alpha
8244d42a Added link to announcement blog post
da97c7c3 Merge branch 'master' into 1263-pre-4.0beta-polish
5c99bc30 Merge pull request #1270 from versionpress/4.0-beta-release-notes
f22b0e27 4.0-beta release notes updated, are now close to final
b8a138ce Fixed path of plugin definition discovery
48333d82 4.0-beta release notes written (some TODOs still remaining)
2c61613f 4.0-alpha1 Markdown file renamed to such (used to be just 4.0) and updated to contain the same info as the GitHub release page
f0de171f Specific WordPress version used in dev-env Dockerfile, Dev-Setup slightly updated

但这也给.目录带来了麻烦:

$ git log -10 --oneline --full-history --simplify-merges -- .
94084136 Typo in the activation message
8a15a8b1 Added error when re-activating VP with WP CLI
6ad07b7d package-lock.json updated
e7e356f8 Updated WP and WP-CLI versions in ext-libs
777e2d05 Disable event propagation after click on the commit table checkbox
81554a46 Small updates of Dev-Setup.md
32d6dbe2 Installed WordPress version bumpted to 4.9
459c2e6d package-lock.json updated for npm 5.5
77ad593c Link to Gitter and support repo in ISSUE_TEMPLATE.md
84d3229e Updated intro message to mention beta instead of alpha

我按照这里的建议尝试了-m标志,但没有区别。

现在,如果用户log.follow在他们的配置中设置为true,还有一些我不完全理解的行为。

$ git config --global log.follow true
(empty output)
$ git log -10 --oneline --merges -- .
(empty output)

根本没有合并提交,即使要求它。我需要添加--no-follow(可能应该记录在 Git 文档中):

$ git log -10 --oneline --merges --no-follow -- .
da97c7c3 Merge branch 'master' into 1263-pre-4.0beta-polish
5c99bc30 Merge pull request #1270 from versionpress/4.0-beta-release-notes
aba96d3f Merge pull request #1277 from versionpress/1274-using-filter-on-init
82a3fd4e Merge pull request #1269 from versionpress/ext-libs-install-locked
ccb74422 Merge pull request #1251 from versionpress/1120-edit-update-action
a94dc0d3 Merge pull request #1246 from versionpress/1176-plugin-definition-discovery
ae530356 Merge pull request #1260 from versionpress/1154-temp-in-zip
ffd7647e Merge pull request #1170 from versionpress/1168-getmenureference-broken
f4a00328 Merge branch 'master' into 1120-edit-update-action
7b29e7ed Merge branch 'master' into 1041-dockerized-dev-setup

所以我的希望是添加--no-follow并删除--merges会产生预期的输出,但是,在这种情况下,它仍然会错过合并提交:

$ git log -10 --oneline --no-follow -- .
94084136 Typo in the activation message
8a15a8b1 Added error when re-activating VP with WP CLI
6ad07b7d package-lock.json updated
e7e356f8 Updated WP and WP-CLI versions in ext-libs
777e2d05 Disable event propagation after click on the commit table checkbox
81554a46 Small updates of Dev-Setup.md
32d6dbe2 Installed WordPress version bumpted to 4.9
459c2e6d package-lock.json updated for npm 5.5
77ad593c Link to Gitter and support repo in ISSUE_TEMPLATE.md
84d3229e Updated intro message to mention beta instead of alpha

这与上面的行为一致,但我仍然不明白:我假设git log本质上是git log --no-mergesgit log --merges的组合输出,但指定路径时并非如此。

对此的任何解释将不胜感激。


更新:也许问题不在于合并提交与普通提交。我已经在另一个存储库中尝试过,并在未指定路径时与.路径时比较输出:

$ git log -10 --oneline --no-follow
350df16f6 (HEAD -> master, origin/master, origin/HEAD) Merge pull request #1977 from versionpress/1975-do-not-upgrade-deleted-sites
21db78245 Merge branch 'master' into 1975-do-not-upgrade-deleted-sites
0a4eda432 Upgrading only sites that are not deleted
43cd96ac9 Merge pull request #1971 from versionpress/fix-ui-creation-of-sites
a952ae1c5 Merge pull request #1966 from versionpress/1949-reduce-db-migrate-boilerplate
018e4d3b7 Merge pull request #1969 from versionpress/1964-platform-api-easy-local-run
4515bc242 Fix add a new site button
6e4ecd652 Merge branch 'master' into prod
4229e326a Fixed Makefile of default-backend
fc99e0f19 [hotfix] Disabled removing TLS hosts
$ git log -10 --oneline --no-follow -- .
21db78245 Merge branch 'master' into 1975-do-not-upgrade-deleted-sites
0a4eda432 Upgrading only sites that are not deleted
43cd96ac9 Merge pull request #1971 from versionpress/fix-ui-creation-of-sites
a952ae1c5 Merge pull request #1966 from versionpress/1949-reduce-db-migrate-boilerplate
018e4d3b7 Merge pull request #1969 from versionpress/1964-platform-api-easy-local-run
4515bc242 Fix add a new site button
4229e326a Fixed Makefile of default-backend
fc99e0f19 [hotfix] Disabled removing TLS hosts
d1bcdae2d Replace 'db-migrate-boilerplate' with a custom implementation
c60032144 Kubernetes.ts returned to its original, non-async structure before 36308d3 with the token loading logic moved to `server.ts` (it didn't really belong to Kubernetes.ts).

这只是一组不同的提交,我在这里没有看到包含/排除提交的明确模式......


来自 git-log 文档的一些可能相关内容:

关于
  • 历史简化有很长的一节,也许里面有一些答案(还没有完全研究)。
  • 关于log.follow配置(强调我的):如果为 true,git log 将充当好像在给出单个时使用了 --follow 选项。这与 --follow 具有相同的限制,即它不能用于跟踪多个文件,并且不能很好地处理非线性历史记录

从 IRC#git添加一些讨论:

[16:44] <+borekb> 嗨,git loggit log -- .应该产生相同的结果吗? 似乎后者有时缺少一些合并提交,我不太明白为什么
[16:45] borekb:这可能取决于您所在的目录?
[16:45] <+borekb>我在项目的根目录中[16:45] <+borekb
>我在这里发布了一些示例:包含合并的目录的 Git 日志
[16:46] <+borekb>老实说,:)我觉得我一定错过了一些明显的东西,因为git log是一个我已经使用过一百万次的基本命令,尽管没有路径规范
[16:48] borekb:这可能是"历史简化"。它在 man git 日志上描述。
[16:48] <@gitinfo> Borekb:git-log 手册页可在 https://gitirc.eu/git-log.html
[16:49] Borekb:哦,基于 SO,看起来你已经在正轨上了。
[16:50] <+borekb> rafasc:我也怀疑是(直接链接:https://git-scm.com/docs/git-log#_history_simplification),但假设默认情况下,git loggit log -- .应该"简化"到相同的输出是否公平?
[16:50] <+borekb>当我尝试阅读该部分时,我的头有点爆炸:)
[16:51] 我认为答案是否定的。假设这一点是不安全的。——是历史简化的一种形式。所以你告诉 git 你想要简化。
[16:54] <+borekb>很好[
16:56] <+borekb> 从我的实验来看,看起来-- path当它是某个子文件夹 (git log -- docs) 与当它只是当前目录 (git log -- .时的行为不同。
[16:56] <+borekb> 子文件夹按预期工作,.产生我不太明白的结果
[16:57] borekb:它与手册页上讨论什么是 TREESAME 和什么不是的部分有关。
[16:57] 博雷克布:尝试dummy_folder/..:P
[16:59] <+borekb> up_here:聪明的黑客,但不起作用 :)
[17:01] borekb:不相关,但是当使用联机检查提交时,你可能想要使用 --show-linear-break,以了解提交之间的关系。(注意--graph --online也可能具有误导性,图形至少需要两条线来绘制边缘,--pretty=short在这种情况下很有用)
[17:02] <+Borekb> RAFASC: 哦,这很好
[17:03] <+Borekb> Rafac:你如何估计存在导致git log -- .产生与git log完全相同的输出的标志组合的可能性?在我深入研究 TREESAME 讨论之前,我会问,这对我来说会很痛苦:)
[17:05] borekb:根据记忆,我会说 --完整的历史...但是你对此有问题吗?
[17:06] <+borekb> rafasc:是的,--完整历史记录使更多提交出现在git log -- subdirectory

你确实被历史简化咬了。 请注意,当将任何路径名与git log一起使用时,默认情况下会启用简化。 如果不提供路径名,则默认情况下启用它。 添加特定选项,如--full-history--simplify-*

(您也可能被将log.follow设置为true的隐含--follow所困扰,但很难看出在这种特殊情况下会在哪里发生。

简化通过执行非常有限的git diff来工作。 请记住,当git log遍历提交图时,它一次处理一个提交C。 每个提交C都有一组父提交。 对于普通(非合并)提交,只有一个父级,因此对于要检查C 中的每个文件(基于您提供的路径名),C中的该文件与其父P中的该文件 100% 相同,或者不同,Git 很容易分辨,因为在两次提交中 100% 相同的路径在提交的附加树中具有相同的blob 哈希

这就是文档中的 TREESAME 表达式的含义:我们采用提交 C 的树,删除所有被检查的路径,留下(在内存中 - 这些都不会影响存储在存储库中的任何内容!)附加到C的骨架树,其中包含正在检查的文件。然后我们采用(单)父P并做同样的事情。 结果要么匹配(C及其父P是 TREESAME),要么不匹配。

提交是"有趣的",如果它很有趣,将显示。 即使它不有趣,Git 仍然会将父P放入图步行优先级队列中以供稍后检查,因为这只是一个普通的提交,Git必须遍历它才能构建历史记录。 (这里有一些奇怪的"父重写",我将跳过,尽管这对--graph很重要。

然而,在合并时,情况有所不同。 提交C仍然像往常一样有一个树,但它有多个父提交Pi。 Git将为每个父级执行相同的"剥离树"操作。 当你不使用--full-history时,Git 会比较C和每个Pi的剥离树。 如果合并本身对任何父级都不是 TREESAME,则包含合并本身,但如果它对至少一个父级Pi是 TREESAME,则合并往往会被排除(取决于其他选项),并且Git将该父级放入优先级队列以遍历图形。 如果C与多个 PiPjPk的 TREESAME 相同,则默认情况下,Git 会随机选择其中一个父项并丢弃其余的父项。

添加--full-history将禁用除一个 P i 之外的所有Pi的丢弃。 所以现在 Git 将遍历合并的所有父级。 这不会影响是否显示合并本身,它只是确保 Git 走合并的"两侧",如果是多路章鱼合并,则走所有手臂。

这里的逻辑是,如果您正在查看的文件在提交C和提交 P i 中是相同的,那么为什么,您不在它们在其他父 P o 中是否不同,因为该文件具有其当前形式由于父 Pi而不是父Po如果您认为您正在查看的文件是正确的,则此逻辑是正确的,但如果您认为它们是错误的并且您正在寻找丢失所需更改的合并,则此逻辑就会崩溃。

关于--follow的单独说明

(因为你的路径名是.,而 Git 通常根本不做目录——使用目录名实际上意味着目录下任何地方的所有文件,递归——这在这里应该无关紧要。 但是,如果您使用文件名,则可能很重要。 请记住,只有当您只查看一个文件时,才会遵守--follow

--follow的工作方式,这就是它仅适用于一个路径名的原因(并且.作为路径应该不是问题),是当 Git 执行此操作时,选择我们在遍历提交图时走过的提交是否有趣,因此应该显示测试, 它在每个提交与其父提交上执行这些git diff

与 TREESAME 差异不同,--follow测试是一个完整的差异 - 它比快速的 100%相同更昂贵,至少对于更有趣的问题案例 - 但它仅限于一个文件,这使得它不会太昂贵。它也仅适用于单父提交,尽管这是在--first-parent(如果您使用它)剥离其他父级之后,或者在-m(如果您使用它)将合并拆分为共享同一树的多个虚拟提交之后,或者在历史记录简化只选择一个父级之后。1在任何情况下,如果父级没有具有您正在记录的(单个)路径名的文件,Git 会对父级和子级进行完全差异,以查看它是否可以在父级中找到一些重命名的文件。 如果它找到这样一个重命名的文件,首先它会显示子文件(因为文件已更改:它至少是重命名的),然后 Git 在遍历到子项的父级时更改它要查找的路径名

也就是说,Git 开始寻找dir/sub/file.ext,命中一个C父级没有dir/sub/file.ext的提交C,做了一个全面的差异,并找到了一个名为path/to/old.name的足够相似的文件。 所以 Git 显示提交C,说R<percent> path/to/old.name -> dir/sub/file.ext,然后转到P——但现在不是寻找对路径dir/sub/file.ext的更改,而是寻找对路径path/to/old.name的更改。

这个特殊的技巧不能在所有合并中很好地工作:文件可以在合并的各个臂之一中重命名,也可以以多个臂重命名,具体取决于谁进行了重命名以及何时重命名。 Git 只能查找一个路径名 — 它不会一直查找两个路径名。 当然,提供路径名会简化历史记录,因此通常无需担心任何合并。 仅当您使用--full-history--simplify-merges等标志时,才会发生合并大小写。


1请注意,如果历史简化从合并中选取了一个父项,则在剥离除我们关心的文件之外的所有文件后,它会选取一个与 C 相同的 P,因此根据定义,我们在C--follow的一个文件与父P中的同名文件匹配。这意味着提交C终究会变得无趣。

最新更新