包含 merge 的目录的 Git 日志

标签 git

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

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

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

Note: in our case, we need to pass multiple directories sometimes, which is why I'm trying to make pathspec work, as opposed to something like 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

好的,这是same as on 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

不好,缺少 merge 提交。我可以删除路径规范来获取它们:
$ 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 log 的输出和 git log -- .应该是一样的,不是吗?

从我的实验来看,似乎--full-history标志在 . 上运行时添加 merge 提交目录:
$ 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 子目录(注意不应该存在的第一个 merge 提交):
$ 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按照建议标记 here但没有区别。

现在,是一个用户有log.follow设置为 true在他们的配置中,还有一些我不完全理解的行为。
$ git config --global log.follow true
(empty output)

$ git log -10 --oneline --merges -- .
(empty output)

根本没有 merge 提交,即使在被要求时也是如此。我需要添加 --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会产生预期的输出,但是,在这种情况下它仍然会错过 merge 提交:
$ 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-merges 的组合输出和 git log --merges但指定路径时情况并非如此。

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

更新 :也许问题不在于 merge 提交与普通提交。我在另一个 repo 中尝试过,并比较了未指定路径时与路径为 . 时的输出。 :
$ 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 docs 的一些可能相关的东西:
  • History simplification上有一长段,也许那里有一些答案(还没有完全研究它)。
  • 关于 log.follow配置(重点是我的):如果为真,git log 将就像在给出单个选项时使用了 --follow 选项一样。这与 --follow 具有相同的限制,即它不能用于跟踪多个文件和 不适用于非线性历史 .


  • 添加来自 #git 的一些讨论税务局:

    [16:44] <+borekb> 嗨,应该 git loggit log -- .产生相同的结果?似乎后者有时缺少一些 merge 提交,我不太明白为什么
    [16:45] Borekb:这可能取决于您在哪个目录中?
    [16:45] <+borekb> 我在一个项目的根目录下
    [16:45] <+borekb> 我在这里发布了一些例子:Git log for a directory including merges
    [16:46] <+borekb> 老实说不明白发生了什么:) 我觉得我必须遗漏一些明显的东西,如 git log是这样一个基本命令,我已经使用了大约一百万次,尽管没有路径规范
    [16:48] Borekb:那可能是“历史简化”。它在 man git log 上有描述。
    [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 log 是否公平?和 git 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] Borekb:尝试 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:从内存中,我会说--full-history ...但是你有这个问题吗?
    [17:06] <+borekb> rafasc:是的,--full-history 使更多的提交出现在 git log -- subdirectory

    最佳答案

    你确实被历史简化咬了。请注意,当使用带有 git log 的任何路径名时,默认情况下会启用简化。 .如果您不提供路径名,则默认情况下不会启用它。添加特定选项,例如 --full-history--simplify-*
    (您也可能会被隐含的 --follow 咬住,因为将 log.follow 设置为 true ,但很难看出在这种特殊情况下会发生在哪里。)

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

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

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

    然而,在 merge 时,情况有所不同。提交 C 仍然像往常一样有它的一棵树,但它有多个父提交 Pi。 Git 将为每个父级执行相同的“剥离树”操作。当您不使用时 --full-history ,然后 Git 将比较 C 与每个 Pi 的精简树。如果对任何父级都不是 TREESAME,则 merge 本身包括在内,但如果它对至少一个父级 Pi 是 TREESAME,则 merge 往往会被排除在外(取决于其他选项),并且 Git 仅将该父级放入优先级队列中进行遍历图。如果 C 对多个 Pi Pj Pk ... 是 TREESAME,则默认情况下,Git 会随机选择这些父级之一并丢弃其余的。

    添加 --full-history禁止丢弃除一个 Pi 之外的所有 Pi。所以现在 Git 将遍历 merge 的所有父级。这不会影响是否显示 merge 本身,它只是确保 Git 走 merge 的“两侧”,或者如果是多路 Octopus merge ,则走所有臂。

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

    关于 --follow 的单独说明

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

    的方式--follow有效,这就是它只适用于一个路径名的原因(并且 . 作为路径应该没有问题),是当 Git 执行此操作时,选择是否我们走的提交,因为我们走在提交图,很有趣,因此应该显示测试,它正在做这些 git diff s 每次提交与其父提交。

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

    也就是说,Git 开始寻找 dir/sub/file.ext ,点击提交 C,其中 C 的父级没有 dir/sub/file.ext ,做了一个全面的差异,发现了一个名为 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 的更改.

    这个特殊的技巧不能在所有 merge 中很好地工作:文件可以只在 merge 的各个分支之一中重命名,或者可以在多个分支中重命名,具体取决于谁进行了重命名以及何时进行。 Git 只能查找一个路径名——它不会同时查找两个名称。当然,提供路径名会开启历史简化,所以一般来说,根本不需要担心任何 merge 。仅当您使用像 --full-history 这样的标志时,才会发生 merge 情况。或 --simplify-merges .

    1请注意,如果 History Simplification 从 merge 中选择了一个父级,则在去除除我们关心的文件之外的所有文件后,它选择了一个与 C 相同的 P — 所以根据定义,我们是 --follow C 中的 ing 匹配父 P 中的同名文件。这意味着提交 C 毕竟将变得无趣。

    关于包含 merge 的目录的 Git 日志,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50719083/

    相关文章:

    c# - Restful Versioning - 如何在版本控制中进行版本控制以及如何部署?

    git - 在 git rebase 上将 'pick' 更改为 'squash' 的快捷方式

    javascript - Jasmine '.jshintrc' 文件夹的一部分 'karma.conf.js' 和 'test' 是否应该受版本控制

    javascript - 是否应该将 package-lock.json 文件添加到 .gitignore 中?

    Git 子模块哈希不断引起冲突

    Git 分支在 Pull 或 Fetch 后不显示在 "git branch"但 "git checkout"工作......?

    git - 如何从已经 checkout 的 pull 请求中提取更改?

    git - 如何在 github 上托管我的网站

    git - 使用 git diff 时,这个 "s"命令是什么,如何取消它?

    git - 使用 Phing 从存储库获取最新的 Git 标签