Git rebase 分支与所有父分支(或依赖子分支)
是否可以使用 Git 来对分支及其所有父分支进行变基? (我认为“父分支”是在这里使用的正确形式。根据您的观点,您也可以将它们称为依赖子分支。但是,遵循提交的父指针将让您到达这些分支,所以恕我直言称它们为“父分支”是公平的)。
我经常使用分支作为快速/可变标签/检查点来标记某些提交。 所有父分支/父引用都完全包含在要重新设置基础的分支中;仅在父分支中没有提交。
* master
*
* featureA-finished
*
* origin/master
现在我想将 rebase -i
master
更改为 origin/master
来更改/重写提交 featureA-finished^
在 git rebase -i --onto origin/master origin/master master 之后,我基本上希望历史是:
* master
*
* featureA-finished
* (changed/reworded)
* origin/master
但我得到的是:
* master
*
* (same changeset as featureA-finished)
* (changed/reworded)
| * featureA-finished
|.* (original commit i wanted to edit)
* origin/master
有没有办法解决它,或者我是否坚持重新创建所有父分支(更具体地说是分支标签)都在新的、重新基础的提交上?
这个问题与 Rebasing abranch including all itschildren 相关,但仍然有很大不同。
Is it possible to rebase a branch with all its parent branches with Git? (I think "parent branches" is the correct form to use here. Depending on your viewpoint, you might also call them dependent sub-branches. Yet, following the parent-pointers of the commits will get you to those branches, so IMHO it is fair to call them "parent branches").
I often use branches as quick/mutable tags/checkpoints to mark certain commits.
All parent branches/parent refs are fully included in the branch-to-be-rebased; there are no commits only in the parent branches.
* master
*
* featureA-finished
*
* origin/master
Now I want to rebase -i
master
onto origin/master
to change/reword the commit featureA-finished^
After git rebase -i --onto origin/master origin/master master
, I basically want the history to be:
* master
*
* featureA-finished
* (changed/reworded)
* origin/master
but what I get is:
* master
*
* (same changeset as featureA-finished)
* (changed/reworded)
| * featureA-finished
|.* (original commit i wanted to edit)
* origin/master
is there a way around it, or am I stuck with recreating all parent branches – more specifically the branch labels – on the new, rebased commits?
This question is related to, but still very different from Rebasing a branch including all its children.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
看起来这个功能正在慢慢进入 Git。
rebase
将获得选项--rebase-refs
,它将完全按照我原来的答案要求的操作。对于建议的补丁系列,请参阅线程 rebase: command "ref" and options - gmane 上的 -rewrite-{refs,heads,tags}。2022 年更新:
选项
- -update-refs
终于登陆了 Git v2.38.0,它现在可以完全执行 12 年前最初问题中所要求的操作:)此功能已与 commit 3d8e3dc4fc22fe41f8ee1184f085c600f35ec76f。万岁!
Looks like this feature is slowly getting into Git.
rebase
will gain the option--rebase-refs
which will do exactly what my original answer asked. For the proposed patch series see the thread rebase: command "ref" and options --rewrite-{refs,heads,tags} on gmane.Update 2022:
The option
--update-refs
has finally landed in Git v2.38.0, which can now do exactly what was asked in the initial question more than 12 years ago :)This feature was merged with commit 3d8e3dc4fc22fe41f8ee1184f085c600f35ec76f in August. Hooray!
根据 git 的 对象模型 如果您只更改提交的元数据(即提交消息)而不是其中包含的基础数据(“树”),那么它的树哈希将保持不变。
除了编辑提交消息之外,您还执行变基,这将更改历史记录中每个提交的树哈希,因为从
origin/master
拉取的任何更改都会影响您的 re- 中的文件。书面历史记录:这意味着您的提交指向的某些文件(blob)已更改。因此,没有万无一失的方法可以做你想做的事。
也就是说,使用 rebase -i 编辑提交通常不会更改提交的时间戳和作者,因此您可以使用它来唯一标识 rebase 操作之前和之后的提交。
在进行变基之前,您必须编写一个脚本,根据这些“时间戳:作者”标识符记录所有分支起点,然后找到具有相同“时间戳:作者”ID 的重写提交,并在其上对分支进行变基。
遗憾的是,我现在没有时间尝试自己编写这个脚本,所以我只能祝你好运!
编辑:您可以使用以下方式获取作者电子邮件地址和时间戳:
并且您可以根据提交哈希获取每个分支的分支列表:
注意每个提交的多个分支,共同祖先< code>d4214a2 属于两个分支!
According to git's Object Model if you only change the meta-data of a commit (i.e. commit message) but not the underlying data ("tree(s)") contained within it then it's Tree hash will remain unchanged.
Aside from editing a commit message, you are also performing a rebase, which will change the Tree hashes of each commit in your history, because any changes pulled from
origin/master
will affect the files in your re-written history: which means some of the files (blobs) that your commit points to have changed.So there is no bullet-proof way to do what you want.
That said, editing a commit with
rebase -i
does not usually alter the commit's timestamp and author, so you could use this to uniquely identify your commits before and after a rebase operation.You would have to write a script which records all the branch start-points against these "timestamp:author" identifier before doing a rebase, and then find the rewritten commits with the same "timestamp:author" ID and rebase the branch on it.
Sadly, I don't have time to try writing this script myself now, so I can only wish you the best of luck!
Edit: You can obtain the author email address and timestamp using:
And you can obtain a list of branches for each of these based on their commit hash:
Watch out for multiple branches per commit, the common ancestor
d4214a2
belongs to both branches!我不确定你到底是如何到达那里的,但是:
应该足以用正确的历史记录重置你的
featureA-finished
分支。I am not sure how exactly you got there, but:
should be enough to reset your
featureA-finished
branch with the right history.我建议首先将
featureA-finished
重新设置为origin/master
。然后进行改写步骤。之后,将master
重新设置为featureA-finished
。这将为您带来您想要的最终结果。请注意,您需要在两个变基上使用
-i
,并且可能必须在第二个变基中删除原始featureA-finshed
中的所有提交。如果需要,您可以编写一个脚本,通过保存中间分支并将其用作新版本的 rebase--on
基础来消除此问题。如果你写得正确的话,它甚至可以处理一系列这样的“子分支”。如果您需要帮助,我可以尝试帮您解决。What I'd advise is to rebase
featureA-finished
ontoorigin/master
first. Do the rewording step then. After that, rebasemaster
ontofeatureA-finished
. This will net you the end result you are wanting.Note that you'll need to use
-i
on both rebases, and may have to delete all the commits from the originalfeatureA-finshed
down in the second rebase. If you wanted, you could write a script that would eliminate this by saving off the intermediate branch and using that as the base for a rebase--onto
the new version. It could even handle a sequence of such 'subbranches' if you wrote it right. If you need help I can attempt to bang one out.