移动创建分支的提交
Moving what commit a branch was created on
好的,这就是交易。我从提交 (2f6ea37) 创建了一个分支 (master),然后从 master 创建了另一个分支 (develop)。在开发中进行了更改。问题是,master 实际上应该是根据之前的提交 (df7992e) 而不是 (2f6ea37) 创建的。
如何在不丢失致力于开发的新内容的情况下更改创建 master 的位置?
现在是这样的:
branch1 --> <2f6ea37> --> <df7992e>
\
master
\
develop --> <new_commit>
应该是这样的:
branch1 --> <2f6ea37> --> <df7992e>
\
master
\
develop --> <new_commit>
TL;DR
你可能只需要三个 git branch -f
命令来做你想做的事:
git branch -f master 2f6ea37
git branch -f branch1 df7992e
git branch -f develop 2f6ea37
但是要使用 git branch -f
执行此操作,您必须在除这三个中的任何一个之外的某个分支名称上,因此您可能需要一个 git reset --hard
或其他命令。如果 develop
已经有额外的提交,你有一个更大的问题。请参阅下面的详细说明。
长
首先(这有点小,但确实很重要),图中的箭头是错误的,因为它们是向前的。 :-) Git 做所有事情都是倒退的。因此,像 df7992e
这样的提交将 向后 指向其前身 2f6ea37
.
像 master
和 develop
这样的分支名称只包含一个原始哈希 ID,即它们直接指向特定的提交。所以我会把它画成:
2f6ea37 <-- branch1
\
df7992e <-- master
\
C <-D <-E <-- develop
为了避免弄乱不可读的哈希 ID,我会调用 2f6ea37
A
和 df7992e
B
:
A <-- branch1
\
B <-- master
\
C--D--E <-- develop
现在,关于 Git 中的分支名称的事情是,您可以 always 将新的哈希 ID 填充到 any分店名称。该分支现在立即指向您提供的哈希 ID。
随着时间的推移,预期 分支名称的移动方式是为了积累新的提交:
A--H <-- branch1
\
B--F--G <-- master
\
C--D--E--I <-- develop
例如以"expected"方式移动了所有三个分支名称:branch1
现在用散列H
标识提交,它指向回散列[=33=的提交],branch1
较早确定。所以没关系。类似的论点适用于其他两个。
您显然希望名称 master
标识提交 A
,名称 branch1
标识提交 B
。 (我们将在下一节中讨论 develop
!)您可以通过将正确的哈希 ID 强行插入每个名称来实现此部分:
A <-- master
\
B <-- branch1
\
C--D--E <-- develop
但是如果我们将此与刚才的状态进行比较,master
这个名字已经朝着 "wrong" 的方向移动了。它曾经命名为 commit B
,现在命名为 commit A
。名称 branch1
已向 "right" 方向移动(向前,与内部向后箭头相反)。
像这样向后移动分支名称会混淆 other Git 存储库(and/or 他们的用户)if他们之前已经看到 your master
识别提交 B
。请记住,所有 Git 都共享原始哈希 ID,因此如果任何其他 Git 提交了 B
,他们的一些名字可能会记住它。他们可能有他们的 origin/master
指向他们共享提交的副本 B
,因此,他们可能有他们自己的 master
也指向 B
。
如果没有其他人见过这个,那你就没事了。只需使用 git branch -f
and/or git reset --hard
将正确的哈希 ID 填充到正确的分支名称中即可。
潜在的大刺在这里
最后一期是分支名称develop
。在这里,我将其绘制为指向提交 E
,E
指向 D
,后者指向 C
,后者指向 B
。
我相信,目前——根据你绘制初始图表的方式——你真正拥有的看起来更像这样:
A <-- branch1
\
B <-- master, develop
也就是说,提交 C-D-E
根本不存在。如果是这样,我们只需要移动 develop
也直接指向 A
,移动 develop
"backwards" 的注意事项与移动 master
相同同理:
A <-- master, develop
\
B <-- branch1
如果您现在 git checkout develop
并进行新的提交 C
,新的 C
将指向 A
:
C <-- develop (HEAD)
/
A <-- master
\
B <-- branch1
这里的附件(HEAD)
表示您此时签出的分支是develop
.
但是 如果您已经有现有的提交怎么办 C-D-E
? 也就是说,如果您当前的图表是:
A <-- branch1
\
B <-- master
\
C--D--E <-- develop (HEAD)
这里的问题是现有提交 C
已经指向现有提交 B
。 任何提交都不能更改 一旦提交。所以你根本不能改变 C
。在这种情况下,您需要做的是 copy C
,因此也 D
和 E
到新的和改进的提交。它们的新之处和改进之处在于新的 C
——我们称它为 C'
——指向 A
,并使用 A
作为其源库。同样,新的 D'
指向 C'
而新的 E'
指向 D'
,给我们这个:
C'-D'-E' <-- develop (HEAD)
/
A <-- branch1
\
B <-- master
\
C--D--E [abandoned]
这也以意想不到的方式改变了名称 develop
:现在我们不仅备份了 B
,我们先备份了,放弃了,E
,然后 D
然后 C
也是。 (现有提交 B
仍然可以通过某些分支名称找到,因此不会被放弃。)
实现这一切的命令是git rebase
。将 HEAD
牢固地附加到 develop
,您将 运行:
git rebase --onto 2f6ea37 df7992e
使用原始哈希 ID 表示 排除提交 B
和更早版本,从当前提交向后复制所有提交,新提交在提交 2f6ea37
之后。然后移动名称 develop
以指向最后一个这样复制的提交。 排除意味着要复制的提交集恰好是正确的集 - C-D-E
- 所以我们得到我们上面画的。
现在是使用两个 git branch -f
命令交换其他两个分支名称的时候了,而我们仍在开发中。或者,我们可以在开始 git rebase
.
之前交换它们
如果您没有要复制的提交 C-D-E
,但在 develop
上怎么办?
假设现在的实际画面可以这样画:
A <-- branch1
\
B <-- master, develop (HEAD)
您可以使用 git branch -f
交换两个名称 branch1
和 master
,而无需以任何方式更改任何其他提交。但现在你还剩下:
A <-- master
\
B <-- branch1, develop (HEAD)
使用git branch -f develop
会报错:
fatal: Cannot force update the current branch.
但是你还需要移动develop
。有很多方法可以做到:
Using git rebase
:git rebase --onto master branch1
:这从复制中排除了从 B
开始的提交,即所有提交;在提交 A
之后复制零提交;然后将您当前的分支名称移动到指向提交 A
.
使用git reset
:git reset --hard master
:这会丢弃索引和工作树中所有正在进行的工作,重新设置它们以匹配提交A
相反,并将您当前的分支名称 develop
移动到指向提交 A
。这样做的好处是它快速而简单,并且可以做你想做的事。缺点是它会清除您忘记保存在某处的任何正在进行的工作。 rebase 命令会警告你。
使用 git checkout
:git checkout master; git branch -f develop master; git checkout develop
。这与 rebase 和 reset 命令一样有效,但需要输入三个单独的命令。在某些情况下,它确实能够在您的索引和工作树中携带未提交的工作(有关详细信息,请参阅 Checkout another branch when there are uncommitted changes on the current branch)。
结论
分支名称可以很容易地移动。要移动你所站的树枝,要么离开它(git checkout
其他东西),要么使用 git reset --hard
或其他偷偷摸摸的方法。请记住,git reset --hard
会破坏未提交的工作。
您不能修改任何现有的提交。如果你想对分支名称进行的调整可以在没有这个的情况下完成,你可以简单地调整这些分支名称。其他任何人——例如,您提供提交的其他 Git 存储库——可能会被 "unusual" 分支名称移动弄糊涂,因此请确保其他 Git 存储库及其用户已做好准备为此。
如果您需要复制一些提交,git rebase
将完成这项工作。这也可能会以其他 Git 跟踪您的分支名称(和您的提交)的人可能需要准备的方式调整您的分支名称。
好的,这就是交易。我从提交 (2f6ea37) 创建了一个分支 (master),然后从 master 创建了另一个分支 (develop)。在开发中进行了更改。问题是,master 实际上应该是根据之前的提交 (df7992e) 而不是 (2f6ea37) 创建的。
如何在不丢失致力于开发的新内容的情况下更改创建 master 的位置?
现在是这样的:
branch1 --> <2f6ea37> --> <df7992e>
\
master
\
develop --> <new_commit>
应该是这样的:
branch1 --> <2f6ea37> --> <df7992e>
\
master
\
develop --> <new_commit>
TL;DR
你可能只需要三个 git branch -f
命令来做你想做的事:
git branch -f master 2f6ea37
git branch -f branch1 df7992e
git branch -f develop 2f6ea37
但是要使用 git branch -f
执行此操作,您必须在除这三个中的任何一个之外的某个分支名称上,因此您可能需要一个 git reset --hard
或其他命令。如果 develop
已经有额外的提交,你有一个更大的问题。请参阅下面的详细说明。
长
首先(这有点小,但确实很重要),图中的箭头是错误的,因为它们是向前的。 :-) Git 做所有事情都是倒退的。因此,像 df7992e
这样的提交将 向后 指向其前身 2f6ea37
.
像 master
和 develop
这样的分支名称只包含一个原始哈希 ID,即它们直接指向特定的提交。所以我会把它画成:
2f6ea37 <-- branch1
\
df7992e <-- master
\
C <-D <-E <-- develop
为了避免弄乱不可读的哈希 ID,我会调用 2f6ea37
A
和 df7992e
B
:
A <-- branch1
\
B <-- master
\
C--D--E <-- develop
现在,关于 Git 中的分支名称的事情是,您可以 always 将新的哈希 ID 填充到 any分店名称。该分支现在立即指向您提供的哈希 ID。
随着时间的推移,预期 分支名称的移动方式是为了积累新的提交:
A--H <-- branch1
\
B--F--G <-- master
\
C--D--E--I <-- develop
例如以"expected"方式移动了所有三个分支名称:branch1
现在用散列H
标识提交,它指向回散列[=33=的提交],branch1
较早确定。所以没关系。类似的论点适用于其他两个。
您显然希望名称 master
标识提交 A
,名称 branch1
标识提交 B
。 (我们将在下一节中讨论 develop
!)您可以通过将正确的哈希 ID 强行插入每个名称来实现此部分:
A <-- master
\
B <-- branch1
\
C--D--E <-- develop
但是如果我们将此与刚才的状态进行比较,master
这个名字已经朝着 "wrong" 的方向移动了。它曾经命名为 commit B
,现在命名为 commit A
。名称 branch1
已向 "right" 方向移动(向前,与内部向后箭头相反)。
像这样向后移动分支名称会混淆 other Git 存储库(and/or 他们的用户)if他们之前已经看到 your master
识别提交 B
。请记住,所有 Git 都共享原始哈希 ID,因此如果任何其他 Git 提交了 B
,他们的一些名字可能会记住它。他们可能有他们的 origin/master
指向他们共享提交的副本 B
,因此,他们可能有他们自己的 master
也指向 B
。
如果没有其他人见过这个,那你就没事了。只需使用 git branch -f
and/or git reset --hard
将正确的哈希 ID 填充到正确的分支名称中即可。
潜在的大刺在这里
最后一期是分支名称develop
。在这里,我将其绘制为指向提交 E
,E
指向 D
,后者指向 C
,后者指向 B
。
我相信,目前——根据你绘制初始图表的方式——你真正拥有的看起来更像这样:
A <-- branch1
\
B <-- master, develop
也就是说,提交 C-D-E
根本不存在。如果是这样,我们只需要移动 develop
也直接指向 A
,移动 develop
"backwards" 的注意事项与移动 master
相同同理:
A <-- master, develop
\
B <-- branch1
如果您现在 git checkout develop
并进行新的提交 C
,新的 C
将指向 A
:
C <-- develop (HEAD)
/
A <-- master
\
B <-- branch1
这里的附件(HEAD)
表示您此时签出的分支是develop
.
但是 如果您已经有现有的提交怎么办 C-D-E
? 也就是说,如果您当前的图表是:
A <-- branch1
\
B <-- master
\
C--D--E <-- develop (HEAD)
这里的问题是现有提交 C
已经指向现有提交 B
。 任何提交都不能更改 一旦提交。所以你根本不能改变 C
。在这种情况下,您需要做的是 copy C
,因此也 D
和 E
到新的和改进的提交。它们的新之处和改进之处在于新的 C
——我们称它为 C'
——指向 A
,并使用 A
作为其源库。同样,新的 D'
指向 C'
而新的 E'
指向 D'
,给我们这个:
C'-D'-E' <-- develop (HEAD)
/
A <-- branch1
\
B <-- master
\
C--D--E [abandoned]
这也以意想不到的方式改变了名称 develop
:现在我们不仅备份了 B
,我们先备份了,放弃了,E
,然后 D
然后 C
也是。 (现有提交 B
仍然可以通过某些分支名称找到,因此不会被放弃。)
实现这一切的命令是git rebase
。将 HEAD
牢固地附加到 develop
,您将 运行:
git rebase --onto 2f6ea37 df7992e
使用原始哈希 ID 表示 排除提交 B
和更早版本,从当前提交向后复制所有提交,新提交在提交 2f6ea37
之后。然后移动名称 develop
以指向最后一个这样复制的提交。 排除意味着要复制的提交集恰好是正确的集 - C-D-E
- 所以我们得到我们上面画的。
现在是使用两个 git branch -f
命令交换其他两个分支名称的时候了,而我们仍在开发中。或者,我们可以在开始 git rebase
.
如果您没有要复制的提交 C-D-E
,但在 develop
上怎么办?
假设现在的实际画面可以这样画:
A <-- branch1
\
B <-- master, develop (HEAD)
您可以使用 git branch -f
交换两个名称 branch1
和 master
,而无需以任何方式更改任何其他提交。但现在你还剩下:
A <-- master
\
B <-- branch1, develop (HEAD)
使用git branch -f develop
会报错:
fatal: Cannot force update the current branch.
但是你还需要移动develop
。有很多方法可以做到:
Using
git rebase
:git rebase --onto master branch1
:这从复制中排除了从B
开始的提交,即所有提交;在提交A
之后复制零提交;然后将您当前的分支名称移动到指向提交A
.使用
git reset
:git reset --hard master
:这会丢弃索引和工作树中所有正在进行的工作,重新设置它们以匹配提交A
相反,并将您当前的分支名称develop
移动到指向提交A
。这样做的好处是它快速而简单,并且可以做你想做的事。缺点是它会清除您忘记保存在某处的任何正在进行的工作。 rebase 命令会警告你。使用
git checkout
:git checkout master; git branch -f develop master; git checkout develop
。这与 rebase 和 reset 命令一样有效,但需要输入三个单独的命令。在某些情况下,它确实能够在您的索引和工作树中携带未提交的工作(有关详细信息,请参阅 Checkout another branch when there are uncommitted changes on the current branch)。
结论
分支名称可以很容易地移动。要移动你所站的树枝,要么离开它(git checkout
其他东西),要么使用 git reset --hard
或其他偷偷摸摸的方法。请记住,git reset --hard
会破坏未提交的工作。
您不能修改任何现有的提交。如果你想对分支名称进行的调整可以在没有这个的情况下完成,你可以简单地调整这些分支名称。其他任何人——例如,您提供提交的其他 Git 存储库——可能会被 "unusual" 分支名称移动弄糊涂,因此请确保其他 Git 存储库及其用户已做好准备为此。
如果您需要复制一些提交,git rebase
将完成这项工作。这也可能会以其他 Git 跟踪您的分支名称(和您的提交)的人可能需要准备的方式调整您的分支名称。