如何检查提交是否按作者日期顺序排列?

发布于 2025-01-09 19:28:32 字数 1003 浏览 0 评论 0原文

动机

假设我们有这些提交(最近在左侧提交):

EFGHIJKLMN

我们想在另一个分支上发布 E,因此我们选择了它,但出现了冲突,我们发现我们也需要 J。我们采用 J 但仍然存在冲突,因此我们也采用 M,E 以与 J 不同的方式依赖 M。然后它就起作用了。现在,我们在新分支上的历史记录是:

EMJ

这里明显的缺点是提交的顺序与之前的逻辑方式不同,将 EJM 视为嵌入在较长历史记录中的功能。一种解决方案是按日期重新排序 git 提交历史记录。然而,原始本地分支上的变基活动可能意味着 J 实际上有一个早于 M 的作者日期。最坏的情况是,如果我们需要 KL(按照该顺序,因为 K 取决于 L),但 L 在 K 之后有一个作者日期。

一种解决方案是遇到此问题时手动修改作者日期,但这不是这里的重点。

编辑:为什么更喜欢 EJM?

许多评论似乎都集中在动机上,因此也许值得扩展。

假设您在 MJ 之上选择了 E,但它不起作用(冲突)。现在您需要找到您丢失的提交,并将其挑选到正确的位置。如果是 L,那么 LMJ 可能会产生 JLM 不会产生的不必要的冲突。在实际示例中,有超过 50 次提交。

阅读历史记录中的提交也变得更加容易,这些提交的顺序与现实中的顺序相同,尤其是在数月可能不同的项目中。如果新的 EMJ 分支要通过所有测试(并且不会产生冲突),您需要确保您没有错过 {F, G, H, I, K, L} 中的任何错误修复提交。保持提交有序可以帮助您跟踪已审查并包含的提交。

问题

我想检查每次推送之前所有提交是否都按作者日期顺序排列(至少相对于上次推送的提交)。我可能会将其放入 pre-push 挂钩中。有没有一种简单的方法来运行此检查?如果分支机构还没有遥控器,也许会很困难?

它还可能有助于确保新的作者日期都在“最后推送的提交”的作者日期之后,但也许这是一个不同的问题。

Motivation

Let's say we have these commits (most recently committed on the left):

E-F-G-H-I-J-K-L-M-N

We want to release E on another branch, so we cherry-pick it, but a conflict arises and we discover that we need J as well. We take J but still have conflicts so we take M as well, which E depended on in a different way than J. Then it works. Our history on the new branch is now:

E-M-J

The obvious downside here is that the commits aren't ordered in the same logical way they were before, seeing E-J-M as a feature embedded in the longer history. One solution is to reorder git commit history by date. However, rebasing activity on the original local branch may mean that J actually has an author date that is before M. At worst, an interactive rebase to re-sort by author date may not even work if e.g. we needed K-L (in that order, because K depends on L) but L has an author date after K.

One solution is to manually modify author dates when you run into this issue, but that's not the focus here.

Edit: Why prefer E-J-M?

Many comments seem to focus on the motivation, so perhaps it is worth expanding on.

Let's say you cherry-pick E on top of M-J and it doesn't work (conflicts). Now you need to go find the commit you're missing, and cherry-pick it into the right place. If it's L, then L-M-J may create an unnecessary conflict when J-L-M would not have. In the real example there are more than 50 commits.

It's also significantly easier to read commits in a history that were done in the same order as they were done in reality, especially over months of potentially different projects. If the new E-M-J branch is going to e.g. pass all tests (as well as not create conflicts) you need to make sure you didn't miss any bugfix commits in {F, G, H, I, K, L}. Keeping commits in order helps you keep track of what commits you've reviewed for inclusion.

Question

I'd like to check that before every push all commits are in author date order (at least relative to the last pushed commit). I'd probably put this in a pre-push hook. Is there a simple way to run this check? Perhaps it's hard if the branch doesn't have a remote yet?

It may also help to ensure the new author dates are all after the author date of the "last pushed commit" but perhaps that's a different question.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

月隐月明月朦胧 2025-01-16 19:28:32

我认为您需要决定新分支是什么。你说:

我们在新分支上的历史现在是......

该新分支与另一个分支有什么关系?它是一个永远不应该再次合并的新的独立开发线吗?如果:

  • :那么谁在乎提交的顺序是否与某些不相关的旧分支的顺序不同!
  • :那为什么还要挑选呢?只需从另一个分支中分支出来并“拥有一切”即可。无论如何,您将来都会再次合并,并且最好通过“重新建立基础”或“合并到”原始分支来尽可能保持最新。

提示

  1. 恕我直言,只要可能,最佳实践将倾向于合并而不是挑选的后一种选择。
  2. 如果您仍然最终选择樱桃,并且如果您将在存储库中长期拥有新的不同提交 ID 以及源提交,我建议使用 -x 选项来附加原始内容提交 ID 到提交消息。这样,当有人看到它时,更明显的是,它来自存储库中其他地方的另一个提交,该提交可能具有不同的上下文,如果他们愿意,他们可以去查看。

I think you need to make a decision about what the new branch is. You stated:

Our history on the new branch is now...

What is the relationship of that new branch to the other one? Is it a new separate development line that should never be merged again? If:

  • Yes: then who cares if the commits are in a different order than some unrelated older branch!
  • No: then why cherry-pick at all? Just branch off the other branch and "have it all". You're going to be merging again in the future anyway and might as well keep it as up to date as possible by "rebasing onto", or "merging in" the original branch.

Tips:

  1. IMHO best practice would lean towards the latter option of merging instead of cherry-picking, whenever possible.
  2. If you still end up cherry-picking, and if you will have the new different commit IDs in the repo long term along with the source commits, I'd recommend using the -x option to append the original commit ID to the commit message. This way when someone sees it, it's more obvious that this came from another commit somewhere else in the repo that likely had different context, which they could go look at if they wish.
情魔剑神 2025-01-16 19:28:32

只需重做新的分支建设即可。一旦找到了需要挑选以获得所需结果的所有提交,请返回并按照您想要的顺序挑选它们。

您为发现所有依赖项所做的工作:

git cherry-pick E
test test # fails
runaround checking # discover M
git cherry-pick M
test test test # fails again
runaround checking some more # discover J
git cherry-pick J
test test test # success

现在您知道自己需要什么,但您的初稿历史记录是杂乱无章的。因此,请进行重写和清理以创建您想要的可发布历史记录:

git reset --hard E^
git cherry-pick M J E

然后发布它。

要检测无序提交,

git log --first-parent --pretty=%H\ %at\ %as | sort -cnr -k2

即“检查第二个字段(%at,作者时间戳(自纪元以来的秒数))是否采用相反的数字顺序”。


许多项目都使用每个功能分支的历史记录来保存您想要的记录,仅当功能具有可呈现的、可发布的历史记录时才合并功能。这样,Git 就已经保存、发布并自动使用您当前通过难以访问的边带注释管理的记录,并且您的问题显示了向团队成员和 Git 隐藏历史记录的真实结构的成本。

Just redo the new-branch construction. Once you've found all the commits you need to cherry-pick to get the results you want, go back and cherry-pick them in the order you want.

What you did to discover all your dependencies:

git cherry-pick E
test test # fails
runaround checking # discover M
git cherry-pick M
test test test # fails again
runaround checking some more # discover J
git cherry-pick J
test test test # success

Now you know what you need, but your first-draft history is disorganized. So do a rewrite-and-cleanup pass to make the publishable history you want:

git reset --hard E^
git cherry-pick M J E

and publish that.

To detect out-of-order commits,

git log --first-parent --pretty=%H\ %at\ %as | sort -cnr -k2

That's "check that the second field (%at, the author timestamp in seconds-since-epoch) is in reverse numeric order".


Many projects do the record-keeping you're after with branch-per-feature histories, merging features only when they have presentable, publishable histories. This way Git already keeps, and publishes, and automatically uses the records you're currently managing with your less-accessible sideband notes, and your question shows the cost of concealing the real structure of your history from team members and from Git.

黒涩兲箜 2025-01-16 19:28:32

这种方法需要 bash 进行进程替换:

#!/bin/bash

diff_ord=$(diff <(git log --format='%H %at' HEAD --not --remotes | sort -k2 -rn | cut -d" " -f1) \
                <(git log --format='%H'     HEAD --not --remotes))
if [ -n "$diff_ord" ] ; then
    echo "Author timestamps not in commit dependency order:"
    echo "$diff_ord"
    exit 1
fi

假设检查失败。要对未推送的提交重新排序,请参阅下面的脚本(假设没有任何未提交的内容)。在之前运行 git Branch bak 并在之后运行 git diff bak 以检查是否没有任何更改。

#!/bin/bash

new_order=$(git log --format='%H %at' HEAD --not --remotes | sort -k2 -n | cut -d" " -f1)
start_branch=$(git log --format='%H' HEAD --not --remotes | tail -1)
git reset --hard "$start_branch"~
git cherry-pick $new_order

This approach requires bash for process substitution:

#!/bin/bash

diff_ord=$(diff <(git log --format='%H %at' HEAD --not --remotes | sort -k2 -rn | cut -d" " -f1) \
                <(git log --format='%H'     HEAD --not --remotes))
if [ -n "$diff_ord" ] ; then
    echo "Author timestamps not in commit dependency order:"
    echo "$diff_ord"
    exit 1
fi

Let's say the check fails. To reorder the unpushed commits, see the script below (which assumes nothing is uncommitted). Run git branch bak before and git diff bak after to check nothing has changed.

#!/bin/bash

new_order=$(git log --format='%H %at' HEAD --not --remotes | sort -k2 -n | cut -d" " -f1)
start_branch=$(git log --format='%H' HEAD --not --remotes | tail -1)
git reset --hard "$start_branch"~
git cherry-pick $new_order
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文