这都是中等难度的(实际难度取决于环境和你对 Git 的熟悉程度)。
如果文件在E
and F
确实相同,做到这一点的(或)简单方法是放入移植物(用git replace
或移植文件),以便 Git 假装G
的父提交是提交E
。也就是说,你有:
A--B--C--D--E <-- master
F-------------G--H--I <-- refs/remotes/rem/P1
and git diff master rem/P1~4
根本不产生输出(master
名称提交E
, rem/P1~4
名称提交F
,以及两棵树E
and F
完全匹配)。
You wish,至少作为一个中间产品,你有这个:
A--B--C--D--E <-- master
\
F G--H--I <-- refs/remotes/rem/P1
也就是说,您希望 Git 假装(至少出于某些目的和一段时间)提交G
已提交E
作为其父级。
Using git replace
模仿旧的可怕的黑客移植
Git 移植正是这样做的:它们告诉 Gitpretend某些提交的父级是其他一些提交。但这些已被弃用,取而代之的是更通用的git replace https://www.kernel.org/pub/software/scm/git/docs/git-replace.html。您可以使用git replace
进行新的提交G'
类似于(但至少取代了大多数 Git 命令)G
,唯一的区别是G'
has E
作为其父级。
然后你可以使用git filter-branch
重新复制存储库中的提交,以便此替换变得真实且永久,而不仅仅是副本。当然,您将获得新提交的新提交哈希值(G'
可以保留它的哈希值,但你必须得到一个新的H'
and I'
). See Jakub Narębski 的回答 https://stackoverflow.com/a/3811028/1256452, 进而git 移植和替换有何不同? (移植现在已经被废弃了吗?) https://stackoverflow.com/q/6800692/1256452,其中 VonC 链接到 Jakub 的答案。
(Git 移植仍然有效,你可以将提交的哈希值放在G
and E
into .git/info/grafts
: echo $(git rev-parse rem/P1~3) $(git rev-parse master) > .git/info/grafts
, 例如。但他们are这是一个可怕的黑客行为,如果你做了这种伎俩,最好是事后立即运行你的过滤器分支,正如 Jakub 指出的那样。)
Using git rebase
您还可以使用git rebase --onto
,正如您所尝试的那样,但是您必须使用现有的(普通的,本地的)分支名称来启动此变基(我不确定在哪里emptybranch
来自这里)指向提交I
。我认为您可能缺少的步骤可能是制作这个常规的普通本地分支名称:
git checkout -b rewrite rem/P1
例如,假设名称rem/P1
决心承诺I
. Or git checkout -b rewrite <hash-of-I>
,如果您面前有该哈希值以便于剪切/粘贴。那时你会得到这个:
A--B--C--D--E <-- master
F-------------G--H--I <-- HEAD -> rewrite, rem/P1
也就是说,您现在正在使用这个新的rewrite
分支,指向提交I
。现在你可以git rebase --onto master HEAD~3
复制当前分支上最近的 3 个提交 -G
, H
, and I
。副本将是G'
, H'
, and I'
,与父母G'
being E
——承诺master
点——以及H'
being G'
等等:
G'-H'-I' <-- HEAD -> rewrite
/
A--B--C--D--E <-- master
F-------------G--H--I <-- rem/P1
现在您可以删除远程及其远程跟踪分支,因为您拥有所需的提交链。您还可以快进master
指向提交I'
任何时候,如果这是你想要的。