如何从不同的分支中的特定提交创建分支

164
我在主分支(master)上进行了几次提交,然后将它们合并到开发分支(dev)上。
我想从开发分支(dev)中的特定提交创建一个新的分支,该提交最初是在主分支(master)上进行的。
我使用了以下命令:
git checkout dev
git branch  <branch name> <commit id>

然而,这创建了一个分支从“master”分支,而不是我预期的“dev”分支。提交ID在“master”分支和“dev”分支中是相同的。 那么,我如何区分不同分支中相同的提交ID呢?
附注:我在GitHub上提供了一个示例。
我使用了以下命令:
git checkout dev
git branch test 07aeec983bfc17c25f0b0a7c1d47da8e35df7af8

我预期测试分支应该包含aa.txtbb.txtcc.txt。然而,测试分支只包含aa.txtcc.txt。很可能是从master分支创建了这个分支。

1
不幸的是,GitHub 上的原始 Git 存储库已不存在,这使得与此相关的问题和答案变得不太有用。 - Rondo
相关链接:*如何从旧提交创建一个新的 Git 分支?*(2011)和 *使用 Git 从以前的提交创建分支*(2010) - Peter Mortensen
5个回答

202

如果你正在使用带有起始点的 branch 命令形式,那么你的 HEAD 处于何处并不重要。

你所做的:

git checkout dev
git branch test 07aeec983bfc17c25f0b0a7c1d47da8e35df7af8
  • 首先,你需要将你的HEAD设置到dev分支上。

  • 其次,你可以在提交记录为07aeec98的位置开始一个新的分支。根据你的 Github 存储库,在这个提交记录中没有名为 bb.txt 的文件。

如果你想要在当前检出的位置开始一个新的分支,你可以直接运行 branch 命令而不指定起始点:

git branch test

或者像其他人已经回答的那样,在一个操作中分支和检出:

git checkout -b test
我认为你可能被误导了,因为07aeec98是分支dev的一部分。确实,这个提交是dev的祖先,需要它的更改才能到达dev的最新提交。但是,还有其他提交需要才能到达最新的dev,这些提交不一定在07aeec98的历史记录中。
例如,添加bb.txt8480e8ae就不在07aeec98的历史记录中。如果你从07aeec98分支,你就无法获得8480e8ae引入的更改。
换句话说:如果你将分支A和分支B合并到分支C中,然后在A的一个提交上创建一个新分支,你将无法获得B引入的更改。
同样,在这里,你有两个平行的分支master和dev,你在dev中合并了它们。从master的一个提交(早于合并)开始分支,将无法提供dev的更改。
如果你想将master中的新更改永久集成到你的特性分支中,你应该将它们合并到特性分支中并继续工作。这将在你的特性分支中创建合并提交,然而。
如果你还没有发布你的特性分支,你也可以在更新后的master上对它们进行变基:git rebase master featureA。准备解决可能出现的冲突。
如果你想要一种在特性分支中自由工作而又不需要合并提交,并且还能与master中的新更改集成的工作流程,我建议采取以下步骤:
- 在master的一个提交上为每个新的特性分支设置基础。 - 在master的一个提交上创建一个dev分支。 - 当你需要查看你的特性分支如何与master中的新更改集成时,将master和特性分支合并到dev中。
不要直接提交到dev,只用它来合并其他分支。
例如,如果你正在处理特性A和B:
a---b---c---d---e---f---g -master
    \       \
     \       \-x -featureB
      \
       \-j---k -featureA
将分支合并到dev分支中,以检查它们是否与新的主分支协作良好:
a---b---c---d---e---f---g -master
    \       \            \
     \       \            \--x'---k' -dev
      \       \             /    /   
       \       \-x----------    /    -featureB
        \                      /
         \-j---k--------------- -featureA
你可以继续在你的特性分支上工作,并定期将来自主分支和特性分支的新更改合并到dev中。
a---b---c---d---e---f---g---h---i----- -master
    \       \            \            \
     \       \            \--x'---k'---i'---l' -dev
      \       \             /    /         /
       \       \-x----------    /         /  -featureB
        \                      /         /  
         \-j---k-----------------l------ -featureA

当集成新功能时,将特性分支(而不是dev!)合并到主分支。


谢谢。你回答了我的问题。我对git分支模式的理解是错误的。你有什么建议吗?我有一个主分支,它定期从其他人那里同步提交(与Perforce同步)。我有一个dev分支,我在上面进行个人工作。我想要一个包含来自主分支和dev分支的所有提交的分支,然后我可以轻松地基于这个分支创建分支,然后开始特定的工作。 - RolandXu
我无法在评论中回答,因此我更新了我的答案并提供了建议的工作流程。 - Gauthier
嘿,感谢您提供的精彩和详尽的答案!只是好奇:最终为什么要将“特性分支(而不是开发分支)合并到主分支”? - cassi.lup
dev 分支中没有真正的新开发。你应该保持自己的分支具有功能特定性。dev 只包含合并提交。将所有新功能直接合并到 master 更加合理,而不是将这些功能合并后再将结果合并到 master - Gauthier
@Gauthier,您没有回答为什么的问题。对我来说,将具有只有功能A``B``Cdevmaster合并起来,就相当于将单独的A``B``C合并到master中。如果不是这样,那就挑战了我对git工作方式的理解,我很想知道为什么! - Steven Lu
@Steven Lu 文件系统的内容可能是相同的,但当你合并到dev分支时,会创建合并提交,这些提交在历史记录中没有太多意义(假设你不使用快进式合并)。 - Gauthier

79

您的参数顺序错误:

git branch <branch-name> <commit>

对此,不管当前检出的是哪个分支,它都会按照你说的去执行。(如果省略提交参数,则默认在与当前分支相同的位置创建一个分支。)

如果您想在创建新分支时检出它:

git checkout -b <branch> <commit>

如果您省略 commit 参数,则具有相同的行为。


51
你可以在本地做这个,正如大家提到的。
git checkout -b <branch-name> <sha1-of-commit>

或者,您可以在GitHub上完成此操作,请按照以下步骤:

  1. 在存储库中,单击 Commits

  2. 对于您要从中分支的提交,单击 <>以浏览该历史点处的存储库。

    Commits history

  3. 在左上角单击 Tree: xxxxxx。在那里输入新分支名称。单击下方显示的 Create branch xxx

    Create a new branch

现在,您可以从本地提取该分支的更改并继续进行操作。


这正是我所需要的。请问在网站上如何做到呢? - eharo2
1
我从来不知道这一点。这就是了。GUI 真的很棒,我想远离 CLI。 - Rohit Gupta

13

尝试

git checkout <commit hash>
git checkout -b new_branch

在您的代码树中,该提交应仅存在于一处,而不是两个独立的分支中。

这样可以让您检出该特定提交并随意命名。


嗨,我尝试了git log dev和git log master,发现我从master分支合并到dev分支的提交哈希ID是相同的。 - RolandXu
可能使用类似于 gitk 的工具来可视化您的日志,这可能会有所帮助。 - ZMorek
我在Github上新增了一个示例。Gauthier已经回答了我的问题,我误解了git分支模式。谢谢:) - RolandXu
这实际上是我认为的答案。谢谢 - virusss8

11

你需要做:

git branch <branch_name> <commit>

你把分支名称和提交混淆了。

或者你可以这样做:

git checkout -b <branch_name> <commit>

如果你使用分支名称代替 <commit> , 那么你会得到一个基于该分支顶端的分支。


这不是 HEAD 的意思。你可以说“分支的顶端”或“分支指向的提交”来代替。 - Cascabel
@Jefromi - 严谨地说,我们可以只说分支,因为分支本身就是指向分支末端的指针。 - manojlds

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接