git - Git - 快进 1 或 N 次提交
问题描述
我返回了一些提交:
> git reset --hard e7aec0fea8ed66e17c277298eebecae58ff044aa
> git status
On branch some-branch
Your branch is behind 'origin/some-branch' by 51 commits, and can be fast-forwarded.
我想合并一个较新的提交,但不是最新的。概念上是这样的:
> git ???
> git status
On branch some-branch
Your branch is behind 'origin/some-branch' by 50 commits, and can be fast-forwarded.
理想情况下,它将允许选择步数:
Your branch is behind 'origin/some-branch' by 50 commits, and can be fast-forwarded.
> git ??? --steps 2
> git status
On branch some-branch
Your branch is behind 'origin/some-branch' by 48 commits, and can be fast-forwarded.
这在git中可能吗?
为什么不平分呢?
可能 看起来 我 想要git bisect
, 但 很难 决定 什么 时候git bisect good
什么 时候git bisect bad
. 我想从某个已知点开始,并逐步向原点提交进行。
为什么不是这个线程(“git fast-forward one commit”)?
该线程的解决方案允许 ff 到指定的提交而不是主提交,但您必须手动指定提交哈希。我正在寻找一种不需要哈希的方法。
解决方案
我已经更新了您链接到的问题的答案,请注意git mff
( git merge --ff-only
)不需要哈希 ID。但是您的特定目标——移动到没有特定名称的给定提交——确实需要哈希 ID或相对表达式。正如ElpieKay 所指出的,任何相关表达式都必须考虑提交图的“形状”。
我喜欢水平而不是垂直地绘制我的提交图。git log --decorate --oneline --graph
Git 将它们垂直绘制,将更新的提交放在顶部,从而产生ElpieKay 显示的那种输出。我用较新的提交来绘制它们,以强调单个分支内分支和合并的并行性质:
I--J
/ \
...--G--H M--N <-- branch
\ /
K--L
假设您已提交G
签出,作为分离的HEAD
. 您可能希望“前进”一次提交。这很简单:一个更接近于 commit 的提交N
,在 branch 的顶端branch
,是 commit H
。因此,如果您向前推进一个提交,那就是您结束的地方。
但是哪个提交是向前迈出的一步H
?是 commitI
还是 commit K
?或者它可能是两个提交I
和 K
?
(剧透:两者兼而有之。)
这意味着您实现 1 或 N 次提交的目标可能是不可能的。如果这里有一个分支和合并的泡沫,你必须选择一个“边”去旅行。当然,您也可以返回并尝试另一边,但您需要知道您已经遇到了这种情况。
如果你没有这个问题,你仍然可以有一个相关的问题。假设我们有这个图:
I--J <-- branch1
/
...--G--H
\
K--L <-- branch2
如果您在 commit 时处于分离的 HEAD 上G
,则下一个 commit forward 是 commit H
,但在那之后,下一个 commit forward 需要一个in the direction of子句:我们是否正试图走向branch1
,即 commit J
?或者我们是否正试图走向branch2
,即承诺L
?
在这种特殊情况下,git rev-list --ancestry-path
可以来拯救我们。我们可以将向某个方向推进一个提交的想法自动化,因为:
git rev-list --topo-order --ancestry-path HEAD..branch1
将按照 Git 的自然(向后)顺序列出当前提交(HEAD
)“之间”的提交,branch1
它们是:
HEAD
(不包括HEAD
其自身)的后代,以及- 的祖先
branch1
(包括由 name 标识的提交branch1
)
这种约束——的后代HEAD
和祖先branch1
——正是--ancestry-path
意味着什么。
在我们的示例中,意味着我们将列出 commits H-I-J
,但顺序相反。所以列出的最后一个提交哈希 ID 是我们想要的。1 因此,我们可以创建一个别名,允许我们移动分离的 HEAD或当前分支名称,无论我们在哪个位置,朝着某个给定分支名称的方向前进一步,其中:
target=$(git rev-list --topo-order --ancestry-path $endpoint | tail -n 1)
if [ "$target" = "" ]; then
echo "we have reached the endpoint $endpoint"
else
git merge --ff-only $target
fi
您可以将其包装成一个小脚本,让您一次推进一个提交。使其前进n步(n > 1)所需的工作留作练习。
1在此添加--reverse
和很-n 1
容易,但是很可惜,这不起作用。您可以使用--reverse
andhead -n 1
而不是 using tail -n 1
,但我不喜欢这可能导致的潜在断管错误。
该--topo-order
选项主要是偏执狂,可能不是必需的,但我还没有向自己证明这一点,所以我把它留在了这里的答案中,因为它有点神奇。
推荐阅读
- ios - 如何在 Swift 中为 PDF 绘制签名或添加图像签名
- ios - 为这个 iOS 应用程序编程页面的最佳方式 - Swift
- c# - 从 MenuStrip 访问用户控件
- android - Flutter - android_alarm_manager 不能在其他屏幕上工作,除了 android 中的主要方法
- python-3.x - 你能停止或增加 Prefect 的 Lazarus 进程的时间间隔吗?
- google-sheets - 根据搜索条件从单元格中提取内容
- javascript - 将道具传递给反应中的孩子的孩子(2级下)
- c# - 在 C# 控制台中确认是或否
- c# - 角度将列表值传递给 JSON 主体 - .Net Core 和多对多关系
- python - 由于错误“pkg_resources.DistributionNotFound: The 'psutil == 5.6.7' distribution was not found”,无法在 Ubuntu 19.10 上运行 GNS3 的问题