Sto*_*ace 1 git version-control branch commit git-commit
我想从某个提交开始创建一个新分支。但是,我希望之后提交的所有提交也成为该分支的一部分。
让我们假设这是branch-D所有提交。
> branch-D
commit-A ---- commit-B ---- commit-C ---- commit-D
Run Code Online (Sandbox Code Playgroud)
我想删除所有内容并commit-B创建一个新的branch,让我们命名它branch-C,然后只commit-A继续branch-D
> branch-D
commit-A
> branch-C
commit-B ---- commit-C ---- commit-D
Run Code Online (Sandbox Code Playgroud)
我还没有将任何内容推送到远程存储库。有没有办法做到这一点?
Git 的奇特之处在于分支名称不会影响您的提交历史记录中的内容,除了它们可以让您\xe2\x80\x94 和其他任何人(这非常重要)\xe2\x80\x94找到提交。秘密在于,在 Git 中,提交可能会同时在许多分支上进行。
\n\n但重要的是,任何提交一旦做出就无法更改。它可以复制到(新的,略有不同的)提交,但不能更改。
\n\n此外,虽然任何分支名称都可以被迫指向任何提交,但分支名称移动有一个“正常方向”:通常,它们只会前进。正如我们稍后将看到的,前进意味着无论他们过去指向什么提交,仍然位于该分支“上”。因此,一旦你将你的提交交给其他人\xe2\x80\x94一些其他 Git\xe2\x80\x94 并要求他们调用这些提交branch-D,就很难让其他Git 撤回它。因此:
\n\n\n我还没有将任何内容推送到远程存储库。有没有办法做到这一点?
\n
是的,可能有一种非常简单的方法:“尚未推送任何内容”意味着您是唯一拥有这些提交的人,因此无论您如何找到它们,这就是每个人找到它们的方式,因为你是“每个人”。:-) 没有必要让其他人改变任何事情。
\n\n只要它们已经按照您想要的方式布局,您只需重新安排查找这些提交的方式即可。
\n\n让我们用“Git Way”绘制现有的一系列提交:
\n\n... <--A <--B <--C <--D <-- branch-D\nRun Code Online (Sandbox Code Playgroud)\n\n在 Git 中,每个提交都由其哈希 ID 唯一标识。这些东西又大又丑,而且显然是随机的(尽管它们实际上是完全确定性的),所以我们几乎从不使用它们,或者使用像d1c9d3a. 相反,我们只调用最后一次提交D。
在 commit 内部D,有另一个哈希 ID,用于标识D其父提交。假设它是c033bae,但我们称之为“提交C”。所以我们说D 指向 C。
类似地,C指向B,指向A,指向 ... 好吧,也许master\xe2\x80\x94 的提示提交你没有说,但现在让我们假设:
...--o--o <-- master\n \\\n A--B--C--D <-- branch-D\nRun Code Online (Sandbox Code Playgroud)\n\n这是一种更紧凑的绘制方式。提交总是必然向后指向,所以我们并不真正需要内部箭头\xe2\x80\x94,我们知道它们总是向后指向。然而,分支名称,例如master“和branch-D”……好吧,我们可以在任何地方指出这些点。我们想要做的是让它们指向分支的“提示提交”。
Git 通过从分支名称指向的提交开始查找提交:D、 forbranch-D或o第一行的最后一个 for master。然后它查看当前提交的父级,以向后移动。然后它查看父级的父级,依此类推。因此,这两个o提交都在master 和 branch-D上:我们可以通过从 开始找到它们master,或者我们可以通过从 开始branch-D并向后移动四个步骤来找到它们。
这意味着我们想要的图片可能看起来像这样:
\n\n...--o--o <-- master\n \\\n A <-- branch-D\n \\\n B--C--D <-- branch-C\nRun Code Online (Sandbox Code Playgroud)\n\n在这里,打开的提交master也在两个分支上,并且A现在是 的尖端的commit 也branch-D仍然处于打开状态branch-C。这已经不再是小窍门branch-C了。
另一方面,也许我们想要的图片是这样的:
\n\n ?--?--? <-- branch-C\n /\n...--o--o <-- master\n \\\n A <-- branch-D\n \\\n B--C--D <-- ???\nRun Code Online (Sandbox Code Playgroud)\n\n也就是说,我们需要回答一个问题。该名称branch-C将指向某个特定的提交。当我们退后三步时,我们应该到达 commit 吗A?或者我们应该到达最后一次提交master?
如果第一张图片是正确的,答案很简单:创建新名称 ,branch-C指向 commit D;然后强制现有名称branch-D移回 commit A。去做这个:
git branch branch-C branch-D # copy the hash ID from branch-D to new branch-C\nRun Code Online (Sandbox Code Playgroud)\n\n然后,根据现在签出的分支,执行以下任一操作:
\n\ngit reset --hard <hash-of-A> # move current branch; re-set index and work-tree\nRun Code Online (Sandbox Code Playgroud)\n\n或者:
\n\ngit branch -f branch-D <hash-of-A> # force branch-D to point to A\nRun Code Online (Sandbox Code Playgroud)\n\n请注意,在使用之前git reset --hard,最好确保您没有任何要保存的修改。虽然提交几乎是永久性的(您可以将它们取回,通常至少 30 天,即使您将它们从所有分支名称中删除),但索引和工作树并不是git reset --hard破坏者。
如果您想要第二张图片,尽管 \xe2\x80\x94 如果您希望提交的父级B不是提交A\xe2\x80\x94,则必须将提交复制B到一个新的、不同的提交,那就是“喜欢B,但是……”。B原始文件和副本之间的差异将包括更改的父哈希 ID。
为此,您将需要使用git cherry-pick或等效项(例如git rebase,这基本上是复制大量提交的集体挑选操作)。为此,您可以:
git checkout -b branch-C master\nRun Code Online (Sandbox Code Playgroud)\n\n给予:
\n\n...--o--o <-- branch-C (HEAD), master\n \\\n A--B--C--D <-- branch-D\nRun Code Online (Sandbox Code Playgroud)\n\n然后运行三个git cherry-pick命令来复制B、C、 和D;或更简单的\xe2\x80\x94这使用<commit>~<number>符号:
git cherry-pick branch-D~3..branch-D\nRun Code Online (Sandbox Code Playgroud)\n\n一次复制所有三个。这会产生:
\n\n B\'-C\'-D\' <-- branch-C (HEAD)\n /\n...--o--o <-- master\n \\\n A--B--C--D <-- branch-D\nRun Code Online (Sandbox Code Playgroud)\n\nbranch-D此时,强制指向 commit是安全的A:
git branch -f branch-D branch-D~3\nRun Code Online (Sandbox Code Playgroud)\n\n您也可以通过哈希 ID 来完成此操作,如前面的示例所示:
\n\ngit branch -f branch-D <hash-of-A>\nRun Code Online (Sandbox Code Playgroud)\n\n我们所做的branch-D~3就是告诉 Git:倒数三个父步骤,一次一个父步骤。所以我们从 开始D,倒数一步到C,再倒数一步到B,倒数第三步到A。
| 归档时间: |
|
| 查看次数: |
4434 次 |
| 最近记录: |