Git 移动在其上创建分支的内容

Git 移动在其上创建分支的内容,git,branch,rebase,Git,Branch,Rebase,好吧,就这么定了。我在commit(2f6ea37)的基础上创建了一个分支(master),然后在master的基础上创建了另一个分支(development)。对开发进行了更改。问题是,实际上应该根据以前的提交(df7992e)而不是(2f6ea37)创建master 我如何在不失去致力于开发的新东西的情况下改变master的创建位置 现在是这样的: branch1 --> <2f6ea37> --> <df7992e>

好吧,就这么定了。我在commit(2f6ea37)的基础上创建了一个分支(master),然后在master的基础上创建了另一个分支(development)。对开发进行了更改。问题是,实际上应该根据以前的提交(df7992e)而不是(2f6ea37)创建master

我如何在不失去致力于开发的新东西的情况下改变master的创建位置

现在是这样的:

branch1 --> <2f6ea37> --> <df7992e>
                                   \ 
                                    master
                                          \
                                           develop --> <new_commit>
branch1-->
\ 
主人
\
开发-->
以下是它应该是什么样子:

branch1 --> <2f6ea37> --> <df7992e>
                     \ 
                      master
                            \
                             develop --> <new_commit>
branch1-->
\ 
主人
\
开发-->
TL;博士 您可能只需要三个
git branch-f
命令即可完成所需操作:

git branch -f master 2f6ea37
git branch -f branch1 df7992e
git branch -f develop 2f6ea37
但要使用
git branch-f
执行此操作,必须使用除这三个分支名称之外的其他分支名称,因此可能需要一个
git reset--hard
或其他命令。如果
develope
已经有了额外的提交,那么您就有了更大的问题。请参阅下面的详细说明

长的 首先(这有点小,但确实很重要),图表中的箭头是错误的,因为它们是向前的。:-)Git做任何事情都是反向的。因此,类似于
df7992e
的提交将向后指向其前身
2f6ea37

master
develope
这样的分支名称只包含一个原始散列ID,即它们直接指向特定的提交。所以我把它画成:

2f6ea37   <-- branch1
    \
  df7992e   <-- master
      \
       C <-D <-E   <-- develop
现在,Git中关于分支名称的事情是,您总是可以在任何分支名称中填充新的哈希ID。该分支现在直接指向您给它的哈希ID

随着时间的推移,分支名称的移动方式是累积新的提交:

A--H   <-- branch1
 \
  B--F--G   <-- master
   \
    C--D--E--I   <-- develop
但如果我们将其与刚才的状态进行比较,则名称
master
已朝“错误”的方向移动。它过去称为commit
B
,现在改为commit
A
。名称
branch1
已向“右”方向移动(向前,与内部向后箭头相对)

如果其他Git存储库(和/或其用户)以前见过您的
master
标识提交
B
,那么像这样向后移动分支名称会使他们感到困惑。记住,任何地方的所有Git都共享原始哈希ID,因此,如果任何其他Git有commit
B
,它们可能会让一些名称记住它。他们可能会让自己的
origin/master
指向共享提交
B
的副本,因此,他们可能也会让自己的
master
指向
B

如果没有其他人见过,你很好。只需使用
git branch-f
和/或
git reset--hard
将正确的哈希ID填充到正确的分支名称中

这里潜在的大麻烦 最后一个问题是分支名称
develope
。在这里,我把它画成指向commit
E
,其中
E
指向
D
,它指向
C
,它指向
B

我相信,目前根据你绘制初始图表的方式,你真正拥有的更像这样:

A   <-- branch1
 \
  B   <-- master, develop
如果您现在
git checkout develope
并进行新的提交
C
,新的
C
将指向
a

  C   <-- develop (HEAD)
 /
A   <-- master
 \
  B   <-- branch1
这里的问题是现有提交
C
已经指向现有提交
B
。一旦提交,任何提交的任何内容都无法更改。因此,您根本无法更改
C
。在这种情况下,您必须将
C
,以及
D
E
复制到新的和改进的提交中。新的和改进的是,新的
C
——我们称之为
C'
——指向
A
,并使用
A
作为其源代码库。类似地,新的
D'
指向
C'
,新的
E'
指向
D'
,这给了我们:

  C'-D'-E'   <-- develop (HEAD)
 /
A   <-- branch1
 \
  B   <-- master
   \
    C--D--E   [abandoned]
它使用原始散列ID表示排除提交
B
和更早版本,从当前提交向后复制所有提交,新提交在提交
2f6ea37
之后。然后移动名称
develope
,指向上次复制的提交。排除意味着要复制的提交集正好是正确的集-
C-D-E
,因此我们得到了上面所画的内容

现在是时候使用两个
git branch-f
命令来交换另外两个分支名称了,而我们仍在开发中。或者,我们可以在启动
git-rebase
之前交换它们

如果您没有要复制的提交
C-D-E
,但正在进行
develope
,该怎么办? 假设现在的实际图片可以这样绘制:

A   <-- branch1
 \
  B   <-- master, develop (HEAD)
使用
git branch-f develope
会给您一个错误:

fatal: Cannot force update the current branch.
但是您仍然需要移动
开发
。有很多方法可以做到这一点:

  • 使用
    git-rebase
    git-rebase--on-master branch1
    :这排除了从
    B
    向后开始的提交,即从复制开始的所有提交;将零提交复制到提交
    A
    之后;然后将当前分支名称移动到提交
    A
    的点

  • 使用
    git reset
    git reset--hard master
    :这将丢弃索引和工作树中所有正在进行的工作,将它们重新设置为与提交
    A
    匹配,并将当前分支名
    develop
    移动到提交
    A
    的位置。这样做的好处是它快速、简单,并且可以做你想做的事情。缺点是它会抹去任何正在进行的工作
    A   <-- branch1
     \
      B   <-- master
       \
        C--D--E   <-- develop (HEAD)
    
      C'-D'-E'   <-- develop (HEAD)
     /
    A   <-- branch1
     \
      B   <-- master
       \
        C--D--E   [abandoned]
    
    git rebase --onto 2f6ea37 df7992e
    
    A   <-- branch1
     \
      B   <-- master, develop (HEAD)
    
    A   <-- master
     \
      B   <-- branch1, develop (HEAD)
    
    fatal: Cannot force update the current branch.