简体   繁体   English

GIT:分支功能分支,而不是开发分支

[英]GIT: Branched off feature branch instead of development branch

So normally when we have feature1, feature2, and feature3, they branch off of devel. 因此,通常当我们有feature1,feature2和Feature3时,它们会脱离devel。 I accidentally just continued branching rather than switching back to devel though so feature2 branches off of feature1 and feature3 branches off of feature 2. 我不小心只是继续分支而不是切换回devel,尽管如此,Feature2从Feature1分支出来,Feature3从Feature 2分支出来。

How can I fix this? 我怎样才能解决这个问题?

EDIT for pic: 编辑图片:

I would like this:
---------------
  \
    A - B - C - D - E

to become this:
---------------
  \   \     \
   A   B-C   D-E

As there is only one or two commits per branch, using cherry-pick will be enough (no need to rebase for one or two commits). 由于每个分支只有一两次提交,因此使用cherry-pick就足够了(无需为一两次提交重新设置基准)。

First backup your local repository (do no trust the internet!) 首先备份您的本地存储库(不信任互联网!)

Write down the hash of A, B, C, D and E. Then: 写下A,B,C,D和E的哈希。然后:

Just do: 做就是了:

# Switch to devel
git checkout devel
# Rename branches into temporary branch names
git branch -m feature1 tmp1 && git branch -m feature2 tmp2
                            && git branch -m feature3 tmp3
# Create feature1 branch and cherry-pick the required commit
git checkout -b feature1 && git cherry-pick A
# Switch to devel
git checkout devel
# Create feature2 branch and cherry-pick the required commits
git checkout -b feature2 && git cherry-pick B C
# Switch to devel
git checkout devel
# Create feature3 branch and cherry-pick the required commits
git checkout -b feature3 && git cherry-pick D E
# Switch to devel
git checkout devel
# Delete temporary branches
git branch -D tmp1 tmp2 tmp3

For completeness, here's how to use git rebase (with optional --onto ) to move these commits. 为了完整--onto ,这是使用git rebase (带有可选的--onto )移动这些提交的方法。 First, let's update the "current" drawing to add some specific labels and commits. 首先,让我们更新“当前”图形以添加一些特定的标签和提交。 For ease of rebasing and yet generality, I'll assume that feature1 connects behind the tip of devel , and that you'd like to move the new branches to the tip (the commit marked with * ). 为了便于重新feature1并保持通用性,我将假设feature1连接在devel尖端的后面,并且您想将新分支移动到尖端(用*标记的提交)。

If there are no extra commits (so that * connects directly to A , etc) this all still works. 如果没有多余的提交(因此*直接连接到A ,等等),那么所有这些仍然有效。

If there are extra commits but you want to keep the feature s back from the tip, the --onto destination should be devel~2 in this example. 如果有额外的提交,但你要保持feature从尖端的背部,在--onto目的地应为devel~2在这个例子。

Now: 现在:

...-o--o--*         <-- devel
     \
      A             <-- feature1
       \
        B--C        <-- feature2
            \
             D--E   <-- feature3

Step 1, rebase feature3 interactively onto devel . 第1步, feature3交互方式将feature3 devel What this will do is create a text file with a bunch of pick commands, each of which will do a git cherry-pick . 这样做是使用一堆pick命令创建一个文本文件,每个命令都会执行git cherry-pick You want to pick commits D and E . 您要选择提交DE Tell rebase that the "upstream" (poor name) is devel , and that you want it to start the whole operation by doing git checkout feature3 : 告诉rebase“上游”(名字不好)是devel ,并且您希望它通过执行git checkout feature3来启动整个操作:

$ git rebase -i devel feature3

Here, rebase will find all commits selected by devel..feature3 (this is A through E inclusive, but not either of the two extra commits already on devel ), and will choose as its --onto target, devel . 在这里,变基会发现所有提交选定devel..feature3 (这是A通过E包容性,而不是两个额外提交已经在任devel ),并且将选择作为其--onto目标, devel Then you end up in the editor, where you can delete all but the last two commits ( D and E ). 然后,您进入编辑器,在其中可以删除除最后两个提交( DE )以外的所有提交。 Rebase will then: 重新设定基准将:

  • move to the tip of branch devel , on a new unnamed branch (detached HEAD mode) 在新的未命名分支上移动到分支devel的尖端(分离的HEAD模式)
  • cherry-pick commit D , adding it to the unnamed branch 樱桃选择提交D ,将其添加到未命名分支
  • cherry-pick commit E , adding it to the unnamed branch cherry-pick commit E ,将其添加到未命名分支
  • and last, use the plumbing equivalent of git reset to make feature3 point to the latest commit. 最后,使用相当于git reset的管道等效功能,使feature3指向最新提交。

Now the tree looks like this: 现在树看起来像这样:

            D'-E'   <-- feature3
           /
...-o--o--*         <-- devel
     \
      A             <-- feature1
       \
        B--C        <-- feature2
            \
             D--E   [abandoned, except for reflogs]

(If you add --onto devel~2 to the original git rebase -i , it will grow the D'-E' chain from the commit at devel~2 , which is the leftmost o node. You still need to specify the upstream, which you can list as either devel or devel~2 : it won't matter in this case.) (如果您添加--onto devel~2到原来的git rebase -i ,它会生长的D'-E'从提交链devel~2 ,这是最左边o节点。您仍然需要指定上游,您可以将其列为develdevel~2 :在这种情况下无关紧要。)

Now you can git rebase -i devel feature2 . 现在您可以git rebase -i devel feature2 This works in the same way: check out branch feature2 , find commits in devel..feature2 (which is A through C this time), and open an editor session to let you modify the set of cherry-pick commands that git will run. 这的工作方式相同:检出分支feature2 ,在devel..feature2查找提交(这次是AC ),然后打开一个编辑器会话,让您修改git将运行的cherry-pick命令集。 This time you need only delete one line (for commit A ). 这次您只需要删除一行(对于提交A )。 Git then starts a new detached-HEAD anonymous branch at commit * again, grows it with cherry picks of B and C , and then moves the feature2 branch: 然后,Git在commit *再次启动一个新的HEAD匿名分离分支,并使用BC挑选出它,然后移动feature2分支:

            D'-E'   <-- feature3
           /
...-o--o--*         <-- devel
    |      \
     \      B'-C'   <-- feature2
      |
      A             <-- feature1
       \
        B--C        [abandoned]

Last, you can rebase feature1 . 最后,您可以为feature1 Here you don't need to bother with interaction, as commit A is the only one you want to copy and the only one git rebase will choose. 在这里,您无需打扰,因为提交A是您要复制的唯一提交,并且将选择唯一的git rebase

The result is the same as with git cherry-pick . 结果与git cherry-pick You need somewhat fewer git commands, but a bit more editing for the interactive "pick" sequences. 您需要的git命令要少一些,但是对于交互式“选择”序列需要更多的编辑。

Which way is "better"? 哪种方法更好? Neither, really. 两者都不是。 Renaming the old branches and then deleting them will toss their reflogs, which might be a feature since it enables the original A through E commits to get garbage-collected sooner, or might be a drawback in case you want to look at them again. 重命名旧分支然后删除它们将刷新其reflog,这可能是一个功能,因为它使原始的AE提交能够更快地被垃圾回收,或者如果您想再次查看它们,则可能是一个缺点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM