Git Notes:Git 最酷但最不受欢迎的功能
简单来说:它们适合从自动化系统(如工单系统或构建系统)添加notes,但不适合与其他开发者进行互动交流(至少目前还不行)
– Scott Chacon, GitHub.blog,
2010 年 8 月
Git notes几乎是个秘密。
它们被自身糟糕的易用性所掩盖。
但工程师们在尝试将元数据存储在 Git 中时,会不断重新发现 Git notes。
2022年10月30日 11:05 @simonwGit notes是强大的工具。它们本可以解决许多问题——如果它们能被更多人知晓且更易于使用的话。
🧐 什么是 Git notes?
Git notes的常见用途是为提交添加元数据。
一旦提交被固定在 Git 的历史中——那就完了。无法修改埋藏在仓库日志深处的提交信息1。
但 Git notes允许你在特殊命名空间中修改旧提交的新信息。它们还能做更多事情。
notes 可以存储任何由 Git 跟踪的对象的元数据——任何对象:提交、二进制文件和树。
所有这些操作都不会修改对象本身。
你可以在仓库的最新提交中添加 notes,如下所示:
git notes add -m ‘Acked-by: ’
然后它会在 git log
中显示:
commit 1ef8b30ab7fc218ccc85c9a6411b1d2dd2925a16
Author: Tyler Cipriani
Date: Thu Nov 17 16:51:43 2022 -0700
Initial commit
Notes:
Acked-by:
🥾 Git notes在实际应用中的示例
Git 项目本身提供了一个 Git notes在实际应用中的示例。他们将每个提交与他们在邮件列表中的讨论链接起来。
例如:
提交 00f09d0e4b1826ee0519ea64e919515032966450
作者:
日期: 2010年1月28日 02:05:55 +0100
bash:支持 ‘git notes’ 及其子命令
...
Notes (amlog):
Message-Id:
此提交的 notes 引导用户查看讨论此补丁的线程。
其他人使用 notes 来做以下事情:
- 跟踪每个提交或分支所花费的时间
- 在 git 日志中添加审查和测试信息
- 甚至进行完全分布式的代码审查
📦 将代码审查和测试结果存储在 git notes 中
这是对所有代码仓库平台的呼吁:请将代码审查元数据以离线形式存储在 Git 中。
Gerrit2 的 reviewnotes
插件是一个很好的示例,展示了如何实现这一点。它使查看代码审核信息变得简单:
git fetch origin refs/notes/review:refs/notes/review
git log --show-notes=review
上述命令会显示标准的Git日志信息,同时包含测试运行情况及代码审核人员的信息。这一切无需强制打开浏览器。
commit d1d17908d2a97f057887a4afbd99f6c40be56849
Author: User
Date: Sun Mar 27 18:10:51 2022 +0200
Change the thing
备注(审核):
已验证+1:SonarQube Bot
已验证+2:jenkins-bot
代码审核+2:人工审核员
提交者:jenkins-bot
提交时间:2022年6月14日 21:59:58 +0000
审核日期:https://gerrit.wikimedia.org/r/c/mediawiki/core/+/774005
项目:mediawiki/core
分支:refs/heads/master
💠 分布式代码审查在 Git notes中
有动力的开发者可以修改和扩展 Git notes。将它们用作任何疯狂想法的分布式存储。
谷歌的一位工程师搭建了一个基于 Git notes 的完整代码审查系统,名为 git-appraise。
其作者宣称这是一个“完全分布式代码审查系统”——独立于 GitHub、GitLab 或任何其他代码托管平台。
该系统允许你:
- 请求审查更改
- 评论更改
- 审查并合并更改
你甚至可以在本地计算机上完成所有这些操作,即使 GitHub 不可用。
此外,它还配备了一个刻意不美观的网页界面,如果你喜欢的话。
git-appraise 网页界面,以其>NaN 行号显示的辉煌呈现。
😭没人使用 Git notes
Git 注释很难使用。
而且 GitHub 在 2014 年决定停止显示提交注释 且未做太多解释。
对于提交,你可以通过在 gitconfig3 中使用一些高级选项,让查看和添加注释变得更容易。但对于存储关于 blob 或树的注释?
别想了。你需要先熟悉 Git 的 底层实现才能进行操作。
因此,目前:Git notes被遗忘在角落里。永远受限于一个晦涩且笨重的界面和有限的采用率——我经常忘记它们的存在。
🗽 独立于代码托管平台
Git 是一个分布式代码审查系统。但 Git 仓库的大部分价值最终被锁定在代码托管平台中,如 GitHub。
Git 笔记是通向替代方案的道路。
Git 分布式代码的历史。Git notes可能使分布式整个项目历史成为可能。
- 无需忍受强制推送的风险
- 无需承受强制推送的风险,
无论如何。↩︎ - 用于一个 几个 较大 项目的代码审查系统。↩︎
- 值得注意的是,它会自动获取
注释并通过以下方式在git log
中显示:$ git config --add \ remote.origin.fetch \ ‘+refs/notes/*:refs/notes/*’ $ git config \ notes.displayRef \ ‘refs/notes/*’
另一个鲜为人知的功能是 Git trailers 信息:
https://alchemists.io/articles/git_trailers
这些是键值结构数据,可以在提交创建时包含在提交中。这些数据被某些系统用于附加元数据。例如,Gerrit 就是利用此功能附加其 Change-Id。
另一个来自不同系统的类似功能:PostgreSQL COMMENT
这允许你在 PostgreSQL 中为各种数据库对象附加文本。
我希望 PostgreSQL 能够拥有一个更类似于结构化键值数据库对象元数据的功能,并且可以进行编辑。
这是一个很棒的功能,但 GitHub 的解析器无法处理它。
比较:
https://github.com/jchester/spc-kit/blob/eb2de71d815b0057e20…
致:
https://github.com/jchester/spc-kit/blob/main/sql/02-spc-int…
基本上,原始的渲染方式让我看起来像个外行。而且像JetBrains IDE这样的工具可以自动识别哪些注释属于哪个DDL。
“版本控制系统的网页界面无法正确解析here-string”并不是对PostgreSQL扩展的批评。这是语法高亮功能的bug。
COMMENT功能甚至不是视图、过程或函数的好选择,因为这些对象已经在服务器端的支持对象定义中内联注释。不,主要好处是为不保留注释的对象添加注释,如表、列、约束、角色等。
我喜欢 PostgreSQL 的 COMMENT 功能。我为朋友用 Supabase 搭建了一个原型应用,并在每个表中添加了 COMMENT。
我讨厌它。我曾用它来精心整理元数据(来源等)到我数十个表的集合中,但有人备份/恢复了数据库,所有这些都丢失了。
在Supabase中几乎是必不可少的。但通过迁移添加注释有些繁琐,除非你直接编写SQL。就像你知道的,用Supabase就是这样。
MS SQL有一个类似的功能叫扩展属性,但API相当繁琐。
我喜欢 PostgreSQL 的功能。我曾在一款商业产品中使用过它们,其中表和列的注释会包含元数据。该产品现已停用。我将此事件视为一个警示故事:当我们作为开发者感到非常强大时,往往会忽视市场需求。
我使用 git notes 来标记分支中哪些提交已运行单元测试(因此脚本会跳过这些提交)。这在与开源上游协作时非常有用,因为你可以通过 git rebase -i 将分支打磨到完美状态。
现在看来,git trailers可能是放置此类信息的更合适位置。
关于更改 ID:我希望 git 本身能支持这些 ID,这样工具也能理解它们。通过提交消息识别提交非常脆弱,尤其是在为合并请求更新提交消息时。虽然提交 ID 能以唯一方式标识提交,但当相同更改可能被移动到其他提交之上时,它就不再是有效的标识符。
编辑:哦,看起来它们实际上是提交的一部分,而notes不是,所以它不会是我用途的良好替代品。
> 关于更改 ID:我希望 Git 本身具备这些 ID,这样工具也能理解它们。通过提交消息识别提交非常脆弱,尤其是在为合并请求更新提交消息时。虽然提交 ID 确实以唯一方式标识提交,但当相同更改可能被移动到其他提交之上时,它就不再是一个有用的标识符。
对于将可变更改作为工作单元的项目,正在努力标准化这一点:https://lore.kernel.org/git/CAESOdVAspxUJKGAA58i0tvks4ZOfoGf…
它们不需要 Git 支持,但未来可能成为第一类支持。
在频繁进行 rebase 的工作流程中运行测试的一个技巧是,使用提交的树哈希作为缓存键,而不是将提交本身的元数据附加到缓存中。
– 这样,当提交内容相同时时,测试将被跳过,同时对提交消息的更改或合并操作保持无感。
– 但在重新排序提交的情况下,测试会重新运行(仅针对重新排序的范围,之后对任何未更改的提交,缓存将再次生效)。我认为这很重要,因为注释会跟随提交一起移动,即使由于重新排序导致逻辑内容发生变化?修改提交或合并两个不相邻的提交也可能导致意外行为,如果它合并了双方的注释并未能无效化缓存?
– 这是我的
git test
命令的工作方式 https://github.com/arxanas/git-branchless/wiki/Command:-git-…—
我还看到一些用例可能更倾向于在缓存键中添加其他内容:
– 提交信息:我最近的工作流程涉及将某些测试命令嵌入到提交信息中,因此当测试命令发生变化时,我确实希望重新运行测试。
– 补丁 ID:如果你在与主分支进行 rebase/merge 操作时,或以其他方式重新排序提交时,不希望重新运行测试。
遗憾的是,目前我还没有好的解决方案。
在我的情况下,我希望在重新排列提交时无效化 notes,因为更改顺序可能会引入 bug,但同时希望有一个单一命令确保所有提交在发送拉取请求前已通过测试。我认为可能以前是这样工作的(在重新基础时移除 notes),但如果不是,那么我怀疑我只是将 git 提交 ID 添加到注释中,这可以有效地用于有效性检查。
当然,如果notes机制不存在,我也可以使用本地文件。但能在Git日志中看到这些消息还是很方便的。
不过,这两种键对于这个目的都很有用,具体取决于实际需求。
我最近了解到 GitHub 将其用作替代 [skip ci] 的方案,我推测这是为了让下游消费者更容易移除提交消息 https://docs.github.com/en/actions/managing-workflow-runs-an…
我不明白为什么他们规定它必须是最后一个尾部,除非是为了正则表达式的原因
有趣,我之前不了解这个功能。
我是常规提交的忠实拥护者,而尾部信息似乎是添加此类元数据的更好方式。
手动在提交信息中添加尾部信息与使用
--trailer
标志在功能上等同吗?我喜欢常规提交的想法,但缺乏许多有用的类别确实是个麻烦,导致我不得不自己创建,而工具当然无法识别。将某种东西称为“常规”提交本身似乎有点反直觉。
> 手动将它们添加到提交消息中是否与使用
--trailer
标志功能等同?是的。该标志非常适合脚本,但它与手动添加文本完全等同。
虽然我通常会顺应潮流,但我还是感到沮丧,因为像尾部这样的功能本可以更自然地与问题跟踪系统集成,但它们离问题跟踪系统的理想路径太远,不值得去实现。
我认为问题在于问题跟踪系统追随潮流;更常见的是使用当周流行的版本;而该版本远未功能完善;新功能的添加速度缓慢如冰川。
我想这是一种冗长的表达方式,用来描述我对基于线性工单标题生成的分支名称用于跟踪目的的厌烦,我希望能够使用其他形式的元数据将提交与问题关联,这样我就能拥有更有意义的PR标题(被迫使用线性分支名称作为标题)。
不过我得承认,这是一个更适合在网上抱怨而非试图改变的问题。
你所反对的一切都是惯例,而非本质。如果你有更好的方法,就那样做。或者说服你的雇主那样做。
是的,我喜欢预告片。我记得曾尝试用notes处理某些事情,但它们使用起来相当麻烦(尽管我已记不清具体遇到了哪些障碍)。预告片完美满足了我的需求。
哦,我用过这个,之前没听说过
这太棒了。这可以大大增强CI功能,比如添加工单编号等。
附带一提:我真的很怀念在谷歌工作时认识的Gerritt,但说实话,2020年代的部署流程真是糟糕透顶。我尝试在本地运行一个实例,并希望将其与我托管在GitHub上的仓库集成,结果却一团糟。
有没有什么类似的工具——在跟踪提交变化等方面比GitHub做得更好——而且开发更活跃、与GitHub集成更友好的?我对GitHub的代码审查工具恨之入骨。
GitLab正在积极开发对堆叠差异工作流的原生支持。在GitLab 17中,创建堆叠的CLI支持已经实现,现在他们正在为其开发代码审查工作流。
不过,说实话,我发现使用Jujutsu创建多个分支,然后手动链式提交请求是最简单的。这就是glab在后台使用glab堆叠命令所做的事情。期待未来版本中的代码审查工具。
对于 GitHub,我认为 Graphite 是我目前看过最好的工具,但我在工作中使用 GitLab,因此缺乏在 GitHub 上大规模使用工具的经验,无法做出最佳判断。
暂且不提堆叠差异,我坦率地说,只要能跨不同提交哈希跟踪评论,我就很满意了。这是 GitLab 和 GitHub 都无法实现的功能:
Gerrit 对此流程没有问题。GH 和 GL 都无法实现。
GH 希望强制你提交一堆“修复”提交,然后要么进行合并提交(呕),要么将整个内容压缩为一个提交(在某些情况下并不理想)。
我认为 Phabricator 在其存在期间做得还不错,但据我所知,它后来被放弃并分叉了,所以不知道现在情况如何。
追踪元数据历史的最佳方式是将其嵌入版本控制系统(VCS)中,因此 Mercurial 是首选。Heptapod(一个友好的 GitLab 分支,旨在支持 Mercurial 仓库和概念)似乎在这方面做得很好,因为它被用于 Mercurial 自身的开发(在他们从邮件列表过渡到 Gerrit,再到 Phabricator,最后到 Heptapod 之后)。
自版本10(今年1月发布)起,Forgejo也支持此功能:
这很棒,感谢分享!
听起来很酷,但 notes 与“历史重写”功能(如 amend、rebase 等)如何配合使用?这些功能会将提交替换为修改后的副本。似乎 notes 是与特定提交(或树、块)ID 绑定的。Git rebase等操作是否足够智能,能够将notes复制到新提交中,还是它们会消失?
在交互式rebase中会发生什么,例如将多个提交合并为一个?
我发现将notes附加到blob和树时也存在相同问题: 它并不像你想象的那样工作:它“感觉上”会将元数据附加到仓库中的文件或目录上,但实际上它将元数据附加到特定的“内容”上:
例如,如果你有一个 blob 编码了字符串“Hello world!”并将其注释附加到该 blob 上,Git 会将该注释与所有包含该内容的文件关联吗?
此外,如果你将一个文件改为 “Hello, world!”,它会失去 notes 吗?
> Git rebase 等操作是否足够智能,也能将 notes 复制到新提交中…
这是可配置的。默认情况下,amend 和 rebase 操作会将它们复制到新提交中。请参阅 git-config(1) 中的
notes.rewrite
。啊,好的。这样听起来更好。感谢信息!
我在当前工作中大量使用 Git 注释。最初作为实验,用于跟踪内部代码审查,避免在提交消息中堆砌内容或为每件事创建 PR。我为每个提交添加上下文标签,包括对应的工单、基础设施限制,以及如果是修复则链接到事件线程。所有内容都保存在仓库中。这避免了需要通过 Slack 或 Jira 搜索来了解某行代码为何更改的麻烦。一旦你开始大规模使用它,你会意识到你几乎不需要平台的用户界面。我们一直在谈论构建的可重复性,但从未谈论过意图的可重复性。也许这就是开始的地方
这不应该是提交信息吗?还是说目标是向前链接,例如“我们意识到这个提交引入了 bug #123”?
哈哈,你真的会从头到尾阅读长篇提交信息(超过一行)吗?比如逐行阅读。我认为提交信息就像推文,而 Git 注释就像博客文章。
在我从事的领域,一个 bug 可能导致数百万美元的损失。我会阅读它们。我会写长篇的。我希望我的同事们也开始写更长的提交信息。
如果你不期望人们阅读提交信息,为什么期望他们会阅读 notes?
这似乎比在提交信息中添加内容要复杂得多。Git 并非没有用于在读取提交信息时进行截取的标志(–oneline)。
Git 注释(notes)只有在您经常在提交完成后向提交中添加文本且该文本对他人可见时才有用。
Acked-By 和邮件列表讨论链接的示例似乎不是很好的例子。这两者在提交时很可能已经为人所知。而且 Git 提交信息基本上可以有无限长度,因此你可以将发生在代码库上的所有关于该提交的讨论直接复制到提交信息中。
我认为一个更好的示例用例是向一个后来被撤销的提交添加 Git 注释。
常见的失败模式是提交信息自豪地宣称修复了某个 bug,但实际上并未修复。并将修复过程中产生的连锁 bug 归因于同一个 bug。
也许我就是这样的人。我见过太多同事根本不看注释来提醒自己当初为何编写这段代码。他们只会冒险一试,希望没人将问题追溯到他们身上。但一旦你处理过一个焦急等待 bug 修复的愤怒客户,结果却在短时间内再次出现相同 bug,你可能会对 bug 修复更加谨慎。
通常需要重构来一次性修复多个 bug。重构往往能带来新功能机会或性能提升。
> Acked-By 和邮件列表讨论链接的示例似乎不是很好的例子。这两者在提交时很可能已经为人所知。
关于提交的讨论(即:审查)和对提交的认可不能在提交之前发生。
> 我认为一个更好的例子可能是向一个后来被撤销的提交添加一个 Git 注释。
提交消息更适合此用例。当你查看文件的修改历史时,它会显示该文件的最新修改。如果一个提交撤销了另一个提交的修改,那么撤销较旧提交的较新提交将在修改历史中显示。
> 有关提交的讨论(即:审查)和对提交的确认不能在提交完成之前进行。
在功能分支上提交前无法进行,但在将提交合并回主开发分支前可以进行。鉴于在代码审查完成后,通常需要通过rebase或合并提交来整合功能分支的更改,我不明白为何此类信息不能在合并前添加(甚至要求必须存在)。
rebase 导致的历史记录破坏问题本身就是一个值得探讨的话题。
我并不完全认同这种观点。在功能分支上工作时,我倾向于频繁提交,而这些提交内容并不适合包含在主开发分支的历史记录中, 我利用rebase功能在合并前将所有内容整理成我实际需要的提交(通常分两次进行:第一次在提交代码审查前,确保差异更易于阅读,例如需要包含其他分支的更改或对代码库进行与当前工作无关但对我的更改有用的修改), 然后在代码审查完成后再次进行,如果需要进行不属于单独提交的额外更改(因为我发现代码审查在rebase操作不在审查过程中进行时会更清晰,而需要进行一两次后续提交的代码审查通常是因为存在需要通过离线讨论解决的问题,我可以在之后回来进行结构性更改,使现有差异不再相关)。在我看来,在开发过程中必须保留提交的精确历史记录是一件坏事,因为这要么需要将大量无用的提交纳入主开发分支的历史记录,要么会抑制频繁提交的习惯,这两种情况我都认为是错误的。
我部分同意你的观点,即Git在这些方面的用户体验并不理想,这导致大多数人实际上并不以这种方式使用Git。如果手动整理提交以清理功能分支历史记录的过程更加直观,那么我预测历史破坏性rebase的问题将基本不复存在; 每个人都会在审查前以我们期望的方式呈现提交,然后我们可以无缝地将分支合并到主开发分支,而不会遇到任何问题。问题在于,由于 Git 命令行界面(CLI)的 ergonomics 较差,事后进行此类结构调整并不容易学习,因此对几乎所有人来说都既繁琐又容易出错。我的观点是,围绕 Git 中修改历史的担忧大多源于被非预期更改所困扰,而避免此类问题的流程(如合并提交)本质上是一种妥协,通过接受主开发分支历史中一定程度的冗余来规避风险。我不会责怪任何人使用这些工作流,因为使 rebase 工作流更困难的问题非常真实,但我认为 rebase 修改历史本身并非核心问题,而是它为潜在问题提供了表现机制。
这是 Git 的 UI 问题,使得隐藏的提交(rebase 前)难以被发现。提交并未被删除,只是被隐藏了。Jujutsu CLI 很好用,因为它解决了这个 UI 问题。
Rebase 本身也常被用来绕过 git log 的 UI 问题,以呈现一个“干净的历史记录”。
你能详细说明吗?我使用 rebase 是为了避免历史记录的破坏或模糊化。你是指 squash 吗?如果是的话,我同意。
嗯,squash 也有它的用途。有时我犯了一个简单的拼写错误,所以我创建另一个提交来修复错误,并 squash 最后两个提交。
你把提交视为原子,但在基于补丁的 Git 场景(如 Linux)中,这并不成立。
我们大多数人并不这样工作,但他们仍然这样做。我们大多数人通常只需要处理三方合并,而不是八方合并。虽然我开玩笑地称“修复一个错误的三方合并”为“五方合并”,因为你最终需要做一个星形模式的差异来重新解决代码,以保留三个版本的意图。A 合并到 HEAD~,B 合并到 HEAD~,合并到 HEAD~,A 合并到 HEAD~ 和 B 合并到 HEAD~
我不太确定你是什么意思。Git 将提交视为原子(不可更改)的,因此它们是原子(不可分割的)。这与补丁无关,除非你指的是部分应用补丁系列。你能详细说明你的意思吗?
提交创建后,讨论仍可继续。
这是 UI 问题,而非知识不足问题。如果 GitHub 的 UI 显示 notes,它们的使用率会立即大幅提升。
是的,我希望GitHub支持这些功能
如他们在过去的帖子中所述:
它没有说明为什么他们取消了该功能。
Git 有许多“最酷但最被忽视的功能”,例如:bisect、pickaxe、reflog、range-diff、archive、annotated tags 等。遗憾的是,这些功能常被遗忘,因为许多人仅将 Git 视为一个高级版的 Google Drive…
Git notes 是多余的,因为你需要一个更高层次的项目管理工具来跟踪功能。路线图、功能层次结构和非技术细节。想想任何大型跟踪器或 Jira。
我认为这没问题。Unix 哲学是专注于一件事并做好它。
使用notes的项目管理工具会让IDE集成更容易。
我隐约记得曾将notes视为解决问题的方案。我可能记错了部分细节,但据我所记得,notes的问题在于它们并非“开箱即用”。如果设置简单且不会复杂化开发流程,说服开发者使用新工具会更容易。notes 未能通过这一测试。应将其默认启用,并让其在拉取时自动下载、在推送时自动上传,而非作为独立操作。
哈哈,我本以为会知道你列出的功能,结果被 pickaxe 意外袭击。这是什么情况?看来我不能太自信了
pickaxe 不是 Git 命令,而是
git log
提供的标志(具体为-S
和-G
)。无耻推荐: 我最近做了一个网络研讨会,讲解镐头选项如何优于
git-blame
,你可以在这里找到:https://nofluffjuststuff.com/webinar/142/level_up_your_git_g… (注:需要提供邮箱地址)。一旦开始使用它,我几乎不再使用blame了
在许多情况下,这是因为这些功能实际上并不那么有用,它们只是围绕着一个工作马的浮华装饰。
我只在事情变得一团糟时才会使用工具的许多功能。人们欣赏我能迅速解决问题。但他们不欣赏的是,当他们在日常活动中污染这些工具时,我会对他们发火。比如,通过错误地重命名文件来破坏Git历史。
很难向他们解释,像“mis en place”这样的事情并不是强迫症,而是进行复杂活动的基本要求。
当我向其他人展示我列出的这些功能时,他们开始说如果他们之前就知道这些功能该多好,并立即开始使用。
因此,尽管我明白有些工具功能过多,但我认为这里的情况并非如此。
这不是最酷但最不受欢迎的功能。这是一个花哨的功能,可能在某些非常特定的情况下很酷,比如由开发人员组成的团队运营整个公司。
无论需要什么都写入提交信息,而引用其他系统中的工单是功能而非 bug——因为 JIRA 或其他系统用于与非开发人员沟通。例如,业务分析师根本无法访问代码或仓库,或者支持人员无法访问仓库和代码。
是的,我可以理解有人可能会编写前端界面,让非开发人员能够查看或编辑notes,但这仍然没有意义,因为业务分析师/支持人员并不关心具体的提交,而一个功能可能适合一个提交,但大多数情况下并不适合。更糟糕的是,当你有多个仓库且功能涉及多个服务时,Git 注释就变得毫无用处,因为此时你真的需要引用外部系统。
> 例如,业务分析师根本无法访问代码或仓库,或者支持人员无法访问仓库和代码。
是的,但这难道不疯狂吗?将自己的产品视为黑盒子有什么好处?然而,这就是主流做法。有时,我会遇到一位分析师(她不在我的团队中,但与我们共享单一代码库的团队中的一员)向我提出的问题,这些问题实际上可以用一行代码来回答。而她是一位技术型人才,了解SQL等技术。我们编写的是非常符合惯例、高层次的代码。但无论如何,文化无法在自身效率低下导致消亡之前发生改变。
这似乎是一个值得探索的有趣方向,用于为编码代理添加额外上下文。
我大约在2020年发现了man页面中的notes功能,但并未使用,因为它主要是一个本地仓库特性。默认情况下,它们不会被推送或拉取。当然,可以配置使其被推送和拉取,但这是团队决策,而我的团队并未投票支持。
一个关于在GitLab中支持notes的9年旧功能请求最近被关闭
遗憾的是,你需要登录才能阅读它,但任何gitlab.com账户都应有效。
还有一个包含更完整提案的议题
为了避免大家疑惑,该请求因被放弃而非完成而关闭:
> 由于当前工作重点不在此领域,该功能请求被关闭。
我编写了一个基于常规提交的版本控制小工具,该工具使用 Git 注释进行版本覆盖。如果您希望强制使用特定版本而非自动检测的版本,可以添加包含所需版本的 Git 注释。
在将某项功能迁移到独立仓库并希望保留历史时,这非常有用。但在切换到新版本控制方案的新仓库中,向提交中添加这些强制版本标签会显得非常凌乱。
在 LibreOffice 项目中,Git 注释被用于跟踪每个提交到 Apache OpenOffice 仓库(LibreOffice 将其作为分支镜像到自己的 Git 仓库)的提交,以确定该提交是否不相关(例如,对构建系统的更改,而 LibreOffice 早已用更好的系统替换了它), 是否与 LibreOffice 中已存在的更改重复(通常是多年以前的更改),或者,最不常见的情况,该提交是否被 LibreOffice 接受(以及哪个提交进行了 cherry-pick)。您仍可自行查看该工具的示例:https://cgit.freedesktop.org/libreoffice/core/log/?h=aoo/tru…(该 Git 前端仍会显示 notes)。
(他们几年前就停止跟踪这些更改,可能是因为Apache OpenOffice的更改速度放缓, cherry-pick这些少量更改已无太大意义。)
为什么 GitHub 取消了对它们的支持,我们如何逆转这一决定?
我认为答案在链接中。
使 Git 注释更易于使用将使从 GitHub 迁移变得更容易。这将使你不再那么依赖于它。
如果将包含带有notes注释的提交的分支进行rebase,会发生什么情况?
默认情况下,notes 会从原始提交复制到重写后的提交。参见 https://git-scm.com/docs/git-notes#Documentation/git-notes.t… 获取详细信息。
但我 IRC 日志中有以下内容:
< _jwilk> 今天学到:在 rebase 过程中使用 git-notes 进行修改时,重写功能无法正常工作。:/
是的,我认为这是一个相当严重的问题。如果每次合并或重新创建提交时,git notes 都会丢失,那么在代码审查中使用它将不会很有趣。
不过有一件事会非常有用——如果能让 Git notes 告诉 Git 默认不要下载某些二进制文件,那将非常棒。这将解决“五年前有人向这个项目添加了 100 MB 的二进制文件,然后又删除了它们”的问题。
不过这太有用处了,所以我不会抱太大希望。
查看 https://git-scm.com/docs/git-notes#Documentation/git-notes.t… 中的 notes.rewrite 配置选项 此外还有notes.rewriteRef。你可以使用这些选项配置Git,使其在修改/重新基准时携带你的notes。
我尝试使用 git notes 进行分布式安全审查,但在合并时遇到了障碍。这是一个好主意,但其局限性限制了其采用
有哪些局限性?
该帖子链接到一个 GitHub 页面,其中包含以下内容:
> 我刚刚在 [Pro Git 博客](死链) 上发布了一篇关于新 git-notes 功能的博文
该链接已存档在 https://web.archive.org/web/20100828155504/http://progit.org…
我在Our World In Data的公共数据管道项目中曾有一个很好的应用场景:一个仓库存放管道代码,另一个使用Git LFS的仓库存放管道的构建输出。通过在代码管道的提交中添加Git注释,可以记录构建数据的哈希值。
整体而言,这种方案显得简洁优雅,且配置完成后无需维护,但坦白说它从未被实际使用。我认为回溯历史的需求比预期更少,而Git注释默认隐藏也未提升其可见性。
我猜这可能已存在,但如果由Git本身维护一个纯文本问题跟踪器呢?
参见最近的讨论:
以及更早的讨论:
> 我猜这可能已经存在,但如果由 Git 本身维护一个纯文本问题跟踪器呢?
我有一个可以添加到项目中的问题跟踪器文件。虽然它在技术上是纯文本,但文件的界面确保了使用特定格式,而该格式确保更改仅反映单个工单。
只要没有人使用其他程序编辑该文件,它就能正常工作。
不过我认为没人会使用它。
也可以看看fossil-scm.org
是的,我正想说,如果你觉得这很酷,那你看到fossil后会更惊讶!
它甚至还有聊天功能!
实际上,我从引用提交哈希值中获得了很大价值。如果我修复了之前提交中引入的问题(例如,提交版本号,但忘记在某个地方更新它),我的修复会说“amends ab12cd34”。
这样,当我需要 cherry-pick 那个提交,或者做类似的事情(再次更新版本)时,我可以搜索我正在查看的提交的哈希值,以找到可能缺失的内容。
UI 比 git-notes 差,但不需要额外的设置来同步它们。
你基本上是在手动完成 git commit –fixup 可以为你做的事情,而 git rebase -i 可以自动完成。
在协作环境中,rebase 无法正常工作。
如果不使用 rebase,由于 –fixup 仅包含提交信息而非哈希值,这对于此场景并不理想。
原帖指出这些注释未被使用是因为界面不够友好,但我认为如果在文本中记录发布相关笔记,可以轻松将这些笔记通过管道传输到 Git 提交注释中。这对我来说似乎很简单。我是否遗漏了什么?
我认为将提示(或提示摘要)作为每条提交的注释添加会很有意思。这样,大语言模型(LLM)就可以在以后回过头来检查注释以挖掘要求,并在再次更改代码时将这些要求考虑在内,从而对每行代码进行推理。
或者直接将提示信息写入提交信息中,毕竟这是人类对提交内容的描述
有没有一份关于 Git 的一些不太为人所知的功能的列表(如 Git 注释、Git 尾注等)?我使用 Git 已有数十年,但尚未遇到过这两种功能。
如果只是为了最后一次提交,是否可以直接修改最后一次提交的提交信息,添加任何备注?这样就不用记住另一个命令选项了。
我使用 Git 已经有大约 10 年了,但之前并不知道 Git 支持 notes 功能。太棒了!
> 这是对所有代码托管平台的呼吁:让代码审查元数据在Git中离线可用。
我认为对于像GitHub这样的商业代码托管平台来说,这可能不会得到重视,因为正如你自己所观察到的:
> 但Git仓库的大部分价值最终都被锁定在代码托管平台中,比如GitHub。
营利性企业通常不热衷于将自身增值服务商品化。这并非针对 GitHub 的批评——我认为 GitHub 做得很好(提供优质服务、慷慨的免费层级,并允许通过 API 提取所有数据以更换服务商)。这只是商业运营的本质。
你必须启动一个新服务,将该功能作为其差异化卖点之一,然后竞争对手可能会添加该功能(重新添加)以赶上。
Forgejo/Codeberg 为何不能/不会采用此方案?
我发现的唯一与git-notes相关的问题是。所以,可能是因为没有人提出过这个问题。
这似乎是一个先有鸡还是先有蛋的问题。因为大多数提供商不支持它们,所以没有人知道它们,而因为没有人知道它们,提供商就没有压力去添加对它们的支持。
我认为Zawinski的软件包络定律在这里找到了实证支持。
太棒了!我怎么会不知道这个?我最喜欢的日子就是学习新知识的时候。更棒的是当我意识到自己错了并改变想法以提升思维时。太有深度了!
Git notes 非常适合标注包含提交哈希值的提交,这些哈希值可作为面包屑,告知开发者(通常是几个月后的我)之前工作的上下文。这些哈希值可能因 rebase 或使用重写历史的磁盘空间优化工具(如这些工具)而发生变化:
参见:
https://stackoverflow.com/questions/5613345/how-to-shrink-th…
https://stackoverflow.com/questions/1398919/make-git-consume…
https://stackoverflow.com/questions/2116778/reduce-git-repos…
https://stackoverflow.com/questions/3119850/is-there-a-way-t…
https://stackoverflow.com/questions/38789265/git-delete-some…
https://stackoverflow.com/questions/16057391/git-free-disk-s…
https://stackoverflow.com/questions/31423525/how-to-reduce-d…
https://stackoverflow.com/questions/16854425/compact-reposit…
https://stackoverflow.com/questions/13999191/trimming-huge-g…
https://stackoverflow.com/questions/4515580/how-do-i-remove-…
这些方法各有各的糟糕之处。很可能是我的操作失误。我需要以下技术:
1. 选择一组提交哈希值(或某个提交之前的哈希值)并删除它们。这在拆分仓库时可能有用,例如在最初为后端+前端项目的场景中,当前端被分叉到新仓库时,需要从旧后端部分中移除相关提交以确保安全/隐私。
2. 将所有分支(包括跨越已删除部分的分支)进行rebase,以保留其结构但尽可能从最近的提交开始/结束。可选地丢弃在已删除部分内创建并合并的分支,除非它们是其他分支的主干,且这些分支在已删除部分之后进行合并。
3. 在提交消息中搜索旧的提交哈希,并在rebase过程中将其更新为新的哈希。
4. 額外加分項:更新名稱中包含提交哈希值的暫存區(或其他 Git 功能)。此外,可導入/導出重要提交哈希值清單以用於專案管理,例如在 Jira 等看板系統的評論中更新哈希值。
5. 搜索大型文件(如 app.js 或其他构建 artifacts)以从分支的提交中移除它们,最好不要在主干分支(如 master)上进行。
如果你已经跟到这里,我还可以使用一种技术,将合并的分支重新基底化,使其形成一系列D形结构而非重叠的B形结构(这在git bisect过程中非常有用)。理想情况下,这种操作应自动进行,或通过GitHub和GitLab等平台的规则强制执行。我总是会在合并前重新基底化分支,但其他人却懒得这么做。
我的想法是:我在自己的分支中不断使用 git reset 和 git cherry-pick,以便每个分支都有像主干一样干净的工作历史。我将此称为“量子提交”,因为我不断探索问题空间,直到找到一个解决方案,使其合并到历史中。
问题是,Git图形界面工具无法满足这一需求。我需要能够剪切/复制/粘贴提交、拖放提交以重新排序等功能。它还应自动生成使提交与分支(或文件夹)匹配所需的提交差异,而非直接抛出冲突提示,从而像苹果的Time Machine一样运行。如果我拥有这个应用程序,我可以简单地选择所有想要删除的提交,它会提示我“这将重写历史,确定吗?”,然后删除它们并正确处理受影响的分支。它还应具备由 Git reflog 驱动的无限撤销功能。
核心理念是提交哈希不应优先于信息本身。我们不应被仓库状态所束缚,因为这会引发焦虑。
因此,我们缺乏一个像Kubernetes管理Docker那样管理Git的工具。
最酷的?这只是额外的注释……
为什么我要选择将此类信息存储在 Git 注释中,而不是直接附加到提交消息本身?
因为你不想每次想要存储额外信息时,都从想要存储信息的提交开始,重新编写整个 Git 历史……
将信息附加到提交本身会创建一个新提交,而所有基于该提交的提交也必须相应更改。
啊;所以 notes 不会影响提交哈希?这是一个充分的理由。
是的,据我所知,Git 注释会被存储在自己的隐藏分支中,通过哈希引用原始提交。也就是说,Git 注释指向提交,而不是相反。
差不多。结构相同,你可以查看,但实际上它位于“refs”目录下的第三个目录中——另外两个是“heads”(分支)和“tags”。这样可以避免在隐藏分支或与用户创建的分支名称冲突时进行特殊处理。
当Apache OpenOffice项目还活跃时,LibreOffice项目使用git notes来跟踪每个提交到Apache OpenOffice的提交,以确定该提交是否被忽略(通常是因为它与已过时的openoffice.org构建系统相关)、与LibreOffice的提交重复(通常是因为LibreOffice项目已在几年前以更好的方式修复了相同问题),或被 cherry-picked 到LibreOffice树中 (这是最罕见的情况;在后两种情况下,它还会指向相关的 LibreOffice 提交);没有 git notes 的 aoo 提交意味着它尚未被审查。虽然 LibreOffice 项目几年前就停止了这种做法(可能是因为 aoo 仓库中不再有值得关注的动态), 你仍然可以查看他们用来镜像Apache OpenOffice代码库的分支,该分支仍保留git注释,地址为(点击父链接查看更多,或本地克隆仓库并使用gitk查看该分支,gitk也会显示git注释)。
这是一个很好的补充,谢谢。我之前在原文中缺少更多实际示例。
同样,libav 从 ffmpeg 拉取提交(或者反过来?)。
没错,情况恰好相反。据我所知,libav开发者对ffmpeg态度较为敌对,拒绝从其仓库拉取任何内容,而ffmpeg维护者在分叉后很长一段时间内仍在从libav中挑选代码。
我认为这很可能是libav如今几乎停滞不前的主要原因。
我多年来尝试过使用git notes,但不幸的是notes与特定的提交哈希绑定。这既是福也是祸。
对于某些类型的审查系统,或用于“标记”与部署相关的事物,notes在主分支/主分支上的提交上工作得很好,而这些提交不会被重新基础化?太棒了,它们确实有效。
但你无法在分支上轻松使用它们:一旦包含notes的分支被重新基准化且SHA值发生变化,与“先前”SHA值关联的notes就消失了 :/
你需要执行
git config notes.rewriteRef refs/notes/commits
[1]吗?[1]
我完全不知道这种情况存在,我自己也遇到过与注释相关的问题!这似乎应该成为默认设置。
看起来像是 Git 的标准操作:有一个以特定方式运行的流程,但这种方式并不“实用”,而且还有一个无法发现的设置来配置该流程。
这就是为什么人们一直在为 Git 构建用户界面和封装工具吗?
拥有大量配置是可行的,甚至是有益的,只要你提供合理的默认值。坦率地说,大多数开源软件在这方面表现不佳,而 Git 就是其中最大的罪魁祸首。
Git 拥有如此众多的用户,更改默认值相当棘手。他们过去确实做过,但通常需要多个发布周期,并设置一个弃用窗口。
也许他们应该引入一个选项,用于配置使用哪一套默认设置。
例如:
defaults=traditional 采用当前默认设置(以最大程度兼容旧版本)
defaults=latest 采用最新推荐的默认设置(提供更好的开箱即用体验,但可能破坏依赖于传统设置的功能)
这样至少只需更改一个设置即可获得合理的默认值。
甚至可以考虑 defaults=VERSION 以获取该版本的最新默认值。
> 也许他们应该引入一个选项来配置使用哪一套默认设置。
> …
> 这样至少只需更改一个设置即可获得合理的默认值。
我怀疑,就像C++一样,关于什么是合理的默认设置,将会有激烈的争论。
也许可以有一个“C++风格的默认设置”配置集,作为默认设置?
啊,就像Nginx的默认设置仍然假装自己处于2000年代初,所有人都使用拨号上网,而且没有人可能希望自己的网站每小时处理超过几个请求。
就像Apache的默认设置对一个每分钟不超过一个访客的网站来说效果很好。
没错。默认选项通常都是错误的。
这要看情况。你也可以将这些视为备注,并希望它们在 rebase 后自动消失,以便内置无效化功能(例如准备更改)。
我的猜测是,这最初是一个疏忽,后来添加了这个选项,但默认关闭以避免“破坏性更改”。翻阅更改日志和提交历史以了解具体情况会很有趣。
是的,完全可以这样推测。就我所知,rebase 时的引用重写是一个较早的想法,但除了 rebase 本身就是为了重写提交引用外,我对此一无所知。而其他所有内容——包括 git-note 引用——都需要从默认行为中显式配置。这在更广泛的意义上支持你的论点,因为默认情况下不期望其他引用被重写,因此 git-note 也不应例外,即使它们最初是通过配置选项引入的。
不完全确定,但似乎可以通过预 rebase 钩子解决。
另一个不应进行 rebase 的理由。
说到 Git 的底层实现,这是我找到的最佳指南。它让一切变得简单。我之前不知道 Git 只是由 blobs 和树组成的列表,仅此而已。当别人这么说时,我并不明白其中的含义。
Blobs = 任何文件,通过 SHA1 值进行索引。也包括提交(指向树的指针)。也包括树(blobs 的列表)。
Refs(即分支):指向特定的提交。
我敢打赌,notes 只是一个指向提交的 blob。
人们很容易陷入对磁盘上数据去重方式的纠结,但 Git 更像是一大堆 ZIP 文件,可能比你想象的更简单。
> 我猜 notes 只是一个指向提交的 blob。
这样会让它们无法使用,因为你必须读取所有 notes 才能知道某个提交是否包含一个。
notes 消息是一个 blob,但笔记本身是一个树条目(条目的名称就是被指向/注释的提交)。
这导致了重新提交:
感谢你的回答。我问之前也查过字典。正如其他评论指出的,它确实有“相邻”或“对比”的意思,我猜这种用法就是由此而来。然而,即使有这个含义,我仍然觉得有一种对抗性的意味。“对比”本身就是对抗性的,对吧?因为它源于比较。例如,在“椅子靠在墙上”中,我可以想象椅子对墙施加力量,而墙以相同强度和相反方向进行反应(牛顿第三定律)。然而,在威尔逊的推文中,我无法想象类似的情景会从Git仓库和Git笔记中产生,因此我才发表了那条评论。
作为补充,我的母语是葡萄牙语,这个词的直接翻译是“contra”¹,它符合《韦氏词典》中“against”的所有含义,除了“相邻”这一含义。我从未在实际使用中看到“contra”被用于这个含义,我想这就是我对此感到有些不适并从未在英语交流中使用它来表达这个含义的原因。
¹
比较两个物体或测试一个物体与另一个物体的物理行为通常涉及某种物理接触或接近,因此即使在测试某些代码时,英语中自然会类比使用“against”一词。但你在这点上是正确的,即“against”在测试行为中具有显著的对抗性含义:通常会引入压力场景或边界案例,这些可能导致某些软件失败。测试在很大程度上是对被测对象的对抗性行为。
捷克语也是如此(我假设所有斯拉夫语言都是这样?)。追踪这个含义的词源发展会很有趣。
我不确定最终是否可以在葡萄牙语中说“contra o muro”(关于椅子)。在意大利语中可以这样说。
在葡萄牙语中可以这样说,完全正确,但似乎比“junto ao muro”(意为“紧靠墙壁/与墙壁相邻”)使用频率低得多。尽管在这种用法中正确,但“contra”一词带有强烈的对抗性语境。也许这就是原帖作者对“against”一词使用感到奇怪的原因。
但我认为“against”和“next to”之间的区别在于,一般来说,“against”暗示着比“next to”或“adjacent to”更紧密的接触。例如在椅子例子中,“靠墙”意味着将椅子尽可能贴近墙壁,而“靠近墙壁”则意味着将椅子放在墙壁附近,但不一定与墙壁接触。如果是一把折叠椅,有人让我把它“靠墙”,我会理解为“将它折叠起来并靠在墙上”。
我可以确认,在你的例子中,德语“Stell die Sessel gegen die Wand”也是有效的且易于理解的,但带有轻微的口语化和老派的表达方式。
有趣的是,对称接触的概念可以被视为一种积极或消极的关系。
我有一个与帖子完全无关的问题,但最终决定因为它而提出。
在博客帖子顶部的 Simon Willson 的推文中,他使用了“against”一词:
开始尝试使用“git notes”针对一个新仓库[...]
英语不是我的母语,但我总是将这个介词的使用理解为在两者之间建立一种对抗关系,一种对立关系。因此,有时我发现它在与编程相关的上下文中被使用的方式有些奇怪。以下是一些我所指的例子:
- “to program against a standard” 而不是 “to program based on a standard” - “to match against a pattern” 而不是 “to match the pattern onto the thing” - “to compare against a list” 而不是 “to compare with items from a list” - “to file an issue against the repository” 而不是 “file an issue at the repository”
我的提议可能(而且很可能)在语法上甚至在语义上都是错误的,但我觉得“against”在这些例子中是被正确使用的,因为我能看出其中两者之间存在一丝对立,而且我能理解有些人甚至可能在那里发现一种对抗关系。然而,在西蒙·威尔逊(Simon Willson)的推文中,“against” 的用法听起来更加不妥,因为我无法将仓库和 Git 笔记视为对手或相互对立的关系。所以问题是:只有我这个非母语者觉得这种用法(不仅是威尔逊的,还有例子中的)有点奇怪,还是母语者也有类似的感觉?888/1/bacon_waffle
我是英语母语者,也认为这是语言中一个略显奇怪的角落——谢谢你的提问!
“against”也可以表示“相邻于”或“接触于”,比如“把椅子靠在这面墙上”。
当用于描述过程时,它可以是一种物理类比:
– “将手推向墙壁” – “将磨床压在金属上” – “将模具压在陶土上”
这里涉及牛顿第三定律的原理,即两物体相互推挤并相互影响。
对于“按照标准进行编程”,我设想的是可塑性的计算机代码被推压在坚硬的模具或形式上,直到其符合预期的形状(即标准)。这与TDD(测试驱动开发)的原理相似。
在我看来,第二个和第三个例子属于“比较与对比”的范畴,后者正是你提到的“对立关系”。
大声思考,“对仓库提交问题”在语法上类似于“对某人提起诉讼”,两者都涉及对某个问题提出投诉。
你的例子:
> – “根据标准编程”而不是“基于标准编程”
两者在语法上都足够正确
> – “与模式匹配”而非“将模式匹配到事物上”
第二个读起来非常奇怪,我不确定你的意思,第一个是_非常_符合语法规范
> – “与列表比较”而非“与列表中的项目比较”
第二个感觉有点奇怪,因为感觉用词过多
> – “向仓库提交问题” 而不是 “在仓库提交问题”
第二个感觉不对,第一个正确但有点奇怪,“on” 可能是我的写法;如果你在处理官僚主义事务,也可以用 ‘with’,比如提交税务表格时用 “with” IRS
我认为“against”在此处的用法通常是正确的,但:
> 开始尝试将x与新仓库进行对比
仍然感觉奇怪。虽然不是错误,但感觉作者应该在这里使用“in”。
非母语者,但“against”有许多含义,并非都暗示对抗或竞争。例如,它还表示“与……比较或对比”,这涵盖了你提到的搜索和比较的例子。
“against”有一个罕见的含义是“相邻”。例如,我们说“将某物靠在另一物上”。英语真是奇怪。
我是git-bug的作者,分享一下我的看法。坦白说,我在最初的设计过程中就了解git notes,但觉得它们不够灵活。我意识到仅靠它们无法完成冲突解决,因此我决定创建自己的数据结构,使用常规的二进制块、树和提交。但一旦有了这种结构,使用notes就几乎没有意义了,因为这只会增加你需要维护的功能。如果我想将git-bug移植到Mercurial或其他未来版本呢?即使是元数据(notes 的自然应用点)也更适合在同一独特数据结构中表达。此外,只需对这些提交进行签名即可加密锁定所有内容。
我认为最大的问题是它们默认不会被拉取,因此你不希望将重要内容放在其中,因为克隆你仓库的人中有一半都看不到它们。
围绕notes的所有这些糟糕的默认设置,以及GitHub不显示它们,让我担心它实际上已被废弃。
如果目的是为了添加自动化元数据,我觉得这是一个不错的默认设置。
你说得对,但这样名字就变得误导了(应该改为“Git 元数据”或类似名称)
解决此问题的最佳方式可能是将该功能别名到具有更好默认设置的其他名称,并希望GitHub/GitLab和主要图形界面采用该别名
也许只需为notes添加命名空间(如果它尚未拥有)。这样就可以订阅部分而忽略其他部分。
让用户在 Git 配置文件中添加 remote.origin.fetch=‘+refs/notes/*:refs/notes/*’,之后这些注释就会被拉取,但确实很烦人的是,这并不是新克隆时的默认设置。
如帖子中所述,Git notes 可用于代码审查,我希望代码审查系统能有一个前端系统,最终将其编码到源代码控制本身中:想想每次你需要找到引入特定行代码的第一个提交,然后追溯到批准该更改的代码审查时的情景。即使在 Git 外部,这也可以得到优化,但由于它们是耦合的,对我来说,它们应该一起存在并像每个提交一样离线可用。
我认为 Gerrit 通过他们的 Note DB 实现了这一点: https://gerrit-documentation.storage.googleapis.com/Document…
这不就是帖子中提到的git-appraise吗?
没错,git-appraise似乎采用了这种方法(我之所以说“似乎”是因为我从未使用过它),但与几乎所有其他针对Git的代码审查系统相比,它是个例外。我确信这种例外有其合理原因,但我猜其中一个原因可能是供应商锁定。
感谢上帝,我的个人项目使用 Fossil [1] 进行源代码管理(是的,管理不仅包括版本控制,还包括记录和文档)。
[1]:
除了 SQLite 之外,还有哪些大型项目(无论是闭源还是开源)在使用 Fossil?
在我看来,Fossil 似乎解决了 Git 许多可用性问题,而且它更加有主见。我更喜欢有主见的工具和框架,生活中需要做出的(不必要且琐碎)决策越少越好。
Fossil似乎非常适合公司内部长期运行的项目。但问题是,你需要强迫人们学习Fossil而不是Git,而公司(或许有道理)不愿花钱让员工去摸索一个不熟悉的系统。
Tcl/Tk也是较大的项目之一。但我想大多数项目都是较小且个人性质的。
LibreCMC 曾经使用 Fossil,直到他们对人们抱怨它不是 Git 感到厌倦。
你在哪里托管你的 Fossil 仓库(或者你根本不集中托管它们)?
Fossil 非常容易自行托管,所以我就是这么做的(在 MeLE 无风扇迷你电脑上)。
但如果你想要托管解决方案,也有其他选择。
对于 CI,我自行托管了一个实例。
我是在一个相当便宜的 VPS 上自行托管的。也可以在 GitHub 上镜像。还有 chiselapp.com
这些 notes 似乎不被 GUI 工具(如 Sourcetree、Fork 等)或网页工具(如 Bitbucket)支持,甚至大多数命令行用户都不知道它们的存在……这相当有趣,你可以用它们来制作 ASCII 艺术、开玩笑,或者干脆胡闹。或许在遥远的未来,有人会发现这些notes。
我将把票号通过figlet处理,然后将其放入每个提交的注释中。
如果我们重新实现整个GitHub界面,但所有内容都存储在Git中,会怎样?
Git notes允许在PR的任何行上附加评论。
问题可以是一个已知的分支和模式。问题评论就是Git notes。
维基、项目管理和发布也是如此
你真的希望 JRandomUser 能够向你的仓库添加 notes 吗?为了允许 JRandomUser 向提交添加注释但不创建新提交,你需要设置和维护哪些额外的权限和钩子?… 但他们需要能够在已知分支上创建提交以添加问题。他们能否通过向所有提交添加notes或极大问题导致镜像空间耗尽?拥有强制推送权限的人是否应能重写任何人作为问题或笔记撰写的内容?
这条路会导致混乱。我确信这在技术上可行……但这些不是我想要面对的难题。
如果拥有提交权限的人能够直接在GitHub的提交中添加notes,那将非常方便。
> 你真的希望JRandomUser能够向你的仓库添加notes吗?
我希望他们通过网页界面评论的程度并不比这低。
> 他们能否通过在所有提交中添加notes或极大问题导致镜像空间不足?
解决这个问题比目前不镜像评论更好。如果你想这样做,可以选择让镜像不获取notes。
GitHub 维基已通过 Git 在独立仓库中提供访问,如通过“本地克隆此维基”侧边栏链接所示:例如,维基 可从 克隆。
(当然,人们也开发了各种基于 Git 的网络编辑工具,从内容管理系统到维基,但我尚未见过真正成功的案例——Git 的功能似乎过于强大,难以在合理的网络编辑器中驯服。我见过最优雅的从网站链接到其 Git 版本历史的方式,是在 Yannik Sander 的博客[1]上。)
[1] 例如:https://blog.ysndr.de/posts/internals/2021-01-01-flake-ifica…
它被称为 Fossil:
这基本上就是 Gerrit 进行代码审查的方式。
我见过一些gitops持续交付管道的实现,它们使用git notes作为发布元数据的存储,并用于促进镜像推广。我理论上喜欢这种做法,但担心git notes是可变的。
我目前的做法是将构建版本作为其原始提交的编号引用,然后在顶部添加一个包含构建协议的版本。
思考:部分问题源于代码审查结果,此外一些自动化检查系统也存在局限性,因此可变性可能不像最初预期的那样成为问题。Git Notes 可能足够轻量级,不会引入过多繁琐流程。
我之前从未听说过这些,但这是我立即想到的用例。似乎非常有用,而且如果只是插入一些几乎是临时性的内部元数据,可变性可能不是问题。
哇,我算是团队里的“Git专家”,但之前从未听说过Git notes。真是个鲜为人知的功能。
另一个实用功能是patch-id,它能识别出因各种原因导致哈希值不同的相同补丁。
我负责公司从SVN到Git的迁移工作,因此对Git notes比较熟悉,因为KDE的svn2git程序[1]支持使用Git notes来存储信息。
不幸的是,我们不得不立即使用
git-lfs
和git filter-repo
重写一切,因此所有关联都丢失了,我们只能将所有内容填入提交消息中,以便人们能够实际看到它。[1]
Git 有很多功能,即使是经验丰富的用户也能发现新东西。你听说过 git bisect 吗?
Git bisect是高级用户功能吗?我刚入行时,一位资深工程师教我使用Git,这是他向我展示的第一个“能救你一命”的工具。
我认为这很大程度上取决于项目类型。
如果你正在开发一个可以快速二分查找并重新测试每个新版本的网页应用,这确实是个神奇的工具。
但如果你在处理一堆大型服务器应用,构建时间超过 1 小时,且启动流程复杂,那么 Git Bisect 可能完全派不上用场。
1小时以上的构建时间很可能是因为没有优化构建流程,比如修复#include文件的混乱、确保没有冗余编译、启用缓存以及升级硬件。
但即使你的构建时间如此离谱,git bisect仍然有用,因为它不仅仅是恒定时间的改进——从n次构建减少到log(n)次构建,无论每次构建需要多长时间,都会有所帮助。
我多次看到 git bisect 在 Linux 内核开发中被有效使用,因此我不确定构建时间是否真的是个大问题……
如果考虑完整的内核构建,在 Deen 硬件上,构建时间最多也就 5 分钟吧?
我见过一些项目,其链接时间比从头开始构建整个 Linux 内核还要长(而在进行二分法时,增量构建在后期步骤中能为你节省大量时间)。
你可以使用除 make 之外的其他命令进行二分法
我认为git bisect的实用性很大程度上取决于良好的提交纪律,因此许多新手git用户可能不会觉得它有用(在“修复问题”“添加内容”“aasdfasdfljser”等提交中识别出有问题的提交,而这些提交都是+1000/-1000,这并不会带来太大帮助)。
确实如此。尤其是当你合并 PR 时,这个工具几乎毫无用处。我曾尝试使用 bisect 工具定位问题,并成功缩小到引入 bug 的 PR,但该 PR 由数百个提交压缩为一个。因此,我们知道问题出现在哪个 PR 中,这并不令人意外,因为该 PR 涉及数十个文件和数百行代码,甚至可能上千行。这个PR是一个落地PR,即人们在 staging 分支中创建PR,然后最终将该PR合并到主线。
如果提交没有被合并,我们可以缩小到引入(影响收入的)错误的单个提交,并可能相对快速地修复问题。据我所知,无论提交有多少,任何git-bisect操作都不应超过约12次尝试即可找到导致问题的提交。至少我们知道问题是由哪个PR引起的,但我们不得不选择要么回滚整个新功能,要么逐一查看所有更改以找到问题,而不是直接修复可能只需一行代码的热修复。
合并提交并不是问题。你应该做的是尽量让每个提交成为最小的原子变更单元。rebase是一个实现这一目标的有用工具——合并、拆分,无论哪种方式。git add/commit -p也适用于此。
这就是为什么我们中许多人坚决反对合并的原因。但如果你仍然保留了PR的原始引用,你可以运行bisect来缩小范围——假设这些单独的提交是(某种程度)一致的状态,可以构建。
“高级用户”是一个相对且定义模糊的概念,但我认为我从未遇到过一个 Git 用户至少没有听说过 Git bisect。
我遇到过一些每天使用 Git 的人,他们甚至没有听说过 bisect,甚至更“常见”的命令如 stash/rebase/reset。
有大量用户将Git的使用视为完成其他任务时必要的背景操作,因此他们只掌握一两项add/commit/push类型的操作流程。我曾听许多人说:“偶尔遇到无法理解的Git错误时,我就会直接删除整个目录并重新克隆。”
实际上,我认识很多不了解 stash/rebase 的人,但他们听说过 git bisect。所以不确定“更常见”是否是一个公平的评估。不知道有没有相关的统计数据。
确实,但很少有机会使用它。
最终,作者指出:“因此,目前:git notes 被遗忘在角落里。永远受限于一个晦涩且笨重的界面和有限的采用率——我经常忘记它们的存在。”那么,读完后,我应该忘记它吗?
Git确实需要一个‘git bug’来跟踪 bug,就像其他工具一样,但我更希望它能直接内置到 Git 中。
为什么不创建一个 issues/ 目录,每个问题对应一个文件?将评论放在那里,通过提交作者来跟踪它们。将它们视为分支或发布的一部分。(这样一个问题可以在一个分支中修复,而不在另一个分支中。)
与git-bug的解决方案相比,这会带来显著的摩擦,而收益却不大。首先,将这些数据与代码存储在一起意味着需要所有人都同意使用该工具(这是一个相当高的要求)。然后,这意味着在发生冲突时,你需要让git合并这些数据,这让你有两个选择:合并失败,或要求用户修复问题。以上任何一种情况都不可接受,这也是之前许多尝试失败的原因。
感谢回复,很有意思。关于“所有人都同意”这一点,难道使用项目方法进行缺陷跟踪不是理所当然的吗?如果有桥梁,也可以为这个目的实现它们。关于合并,如果合并某个修复或检测缺陷的分支,难道不需要先修正缺陷定义吗?所以我认为明确合并更好?不是说这一定好,但我忍不住想尝试看看是否可行。
一个“分支感知”的缺陷跟踪系统,能够追踪问题起源、修复位置等信息,这(以及我认为)应与数据存储方式和冲突解决机制分开考虑。这里所说的冲突解决是指:当两个用户在不同机器上编辑问题,然后状态被合并时会发生什么?如果你将这些数据存储在某种格式(比如 JSON)中,并依赖 Git 自动合并,最终会导致格式损坏。相反,你可以将所有操作都放在自己的分支中,不污染正常代码,也不让 Git 进行任何合并。这样,你的 bug 跟踪系统仍然可以理解分支并跟踪这些信息。
我理解将存储与功能解耦是有用的。关于合并,我再次将存储与功能关联,但每个问题存储一个文件可以缓解这个问题。两个用户在同一个问题上工作时,无论如何都需要同步。嗯,也许这很愚蠢,可能行不通,我同意。
Git似乎有很多我不知道的功能。去年有人向我展示了git bisect,它可能至少为我节省了一整天的压力和提交调整时间。Git要么存在严重的可发现性用户体验问题,要么我只是对每天使用的工具不加质疑。
无论如何,也许是时候看看Git的man手册了
我用这个来存储我对已发布提交的个人笔记。主要是关于我做过的测试。
对于私有提交,如果它们是临时性的,我可能会直接将它们存储在提交消息中,然后在推送前删除。
本地工作时的可用性还不错。但推送和拉取时有点麻烦。
Git 笔记比在仓库中存储一个或多个 .txt 文件更好吗?
你可以将它们附加到已创建的提交上,例如文章中的代码审查示例。如果你将这些数据存储在 HEAD 处的提交中,其他包含该提交的分支将无法访问这些数据。
你可以在日志中看到它,并且仅在相关提交中可见。
无需通过 git show 命令查看仓库中 .txt 文件的对象 ID 来查看消息。
根据 TFA,您可以在提交后添加 git 注释
确实,但您也可以添加一个 .txt 文件并在文本中引用该提交。
它们可以在事后创建,而不会影响现有提交的 SHA-1 值。
这是否意味着它们在源代码控制中并非以相同方式管理?即是否相当于一个包含 SHA->文本映射的共享文本文件?
它们是版本化的,可以通过在
ref/
目录下的notes命名空间中使用git log
命令查看其更改日志。你可以存储皮卡丘的图片。你的.txt文件能做到这一点吗?
(这不是我的作品,摘自 )
玩得不错 🙂
你也可以将皮卡丘的图片存储在 Git 仓库中。
真正的答案是,notes 并非提交哈希的一部分,而是可变的,这意味着你可以将其用于临时信息和/或事后添加 notes。
我尝试使用 git-notes 实现 Git 的 m-of-n 多签名:
“它们适合从自动化系统(如工单或构建系统)追加 notes,但不适合与其他开发者进行互动式对话”
读完整个内容后,我仍然不太清楚为什么它们不适合与其他开发者进行对话。
你甚至可以创建一个自动化系统,将 GitHub 提交评论与仓库中的 git notes 同步。
你只需要确定一个固定的格式。
很多评论提到将git-notes与CI/CD系统结合使用。有人能详细说明这是如何实现的吗?比如可以存储哪些元数据。如果有相关参考资料,会非常有帮助。
我之前从未听说过这个功能,但很难看出它有什么用处。它似乎没有在提交信息已经允许的内容之外添加任何实质性内容。
我觉得你可能错过了博客文章中一个重要的部分。这里是该部分中的一句话:
> 一旦提交被固定在 Git 的历史中——那就这样了。无法修改埋藏在仓库日志深处的提交信息。
虽然很少见,但确实可以修改提交并保留其SHA值。
这能否替代标签作为CI构建标记?自动为每个CI构建打标签会迅速积累成数千个标签,污染标签列表并导致Git变慢。
我假设这样会失去将它们作为标签使用的功能?
git checkout v0123
git difftool v0123 v0158
这些命令非常有用。没想到会对性能产生影响。
有道理。但可能还是值得的。当获取所有标签时,仅几千个构建后就会变得荒谬。
我目前只到大约2000个,但尚未遇到速度变慢或其他问题。
可能是因为某些设置会始终获取标签?在获取时将分支写入控制台似乎需要一段时间。
在 WebStorm IDE 中,我可以选择一个(Git)提交并选择“编辑提交消息”。
这是同一功能,还是通过 Git 注释实现的?
不,这不是同一功能,实际上这会执行 Git rebase,修改该提交本身以及之后的所有提交。这几乎与你想要的完全相反!
IntelliJ 产品试图为所有“版本控制系统”(VCS)操作提供统一的界面和命名,无论是 Git、Mercurial 等。但实际上这会掩盖实际的 Git 操作,并要求学习另一套 IntelliJ 特定的“抽象”名称来表示相同功能。我希望他们能停止这样做,这真的很令人困惑且不准确。
他们确实提供了一个名为“编辑提交信息”的菜单。我无需知道在命令行中输入哪些命令和选项来实现这一功能。
既然我们已经有了git commit,为什么还需要git notes?对我来说这似乎是多余的。
git notes的常见用途是为提交添加元数据。
一旦提交被固定在 Git 的历史记录中——那就这样了。无法修改深埋在仓库日志中的提交信息。
但 Git 笔记允许你在特殊命名空间中修改旧提交的新信息。而且它们还能做更多事情。
文章在第二段中对此有回答。
如果进行 cherry-pick 操作,是否会包含该提交的 notes?
默认情况下不会。cherry-pick 类似于单个提交的 rebase 操作。你实际上是在其他位置重写提交的更改,因此会生成一个新的 SHA 以反映新位置。
由于 Git 注释与特定的 SHA 绑定,因此不会被包含。
不过你可以配置 Git 使其包含注释。如评论中其他地方提到的,这里有一个很好的 Stack Overflow 答案解释了如何操作:
https://stackoverflow.com/questions/14585613/is-there-a-way-…
毫无附加价值。
让我来当反对的声音。这是一个纯粹的极客插件,对普通用户毫无价值。我查看了所有使用示例,甚至包括本帖中的示例。毫无附加价值。你可以通过链接、指向、存储等方式访问你的提交,效果完全相同。