将代码从主分支移动到现有分支
Move code from main to an existing branch
我在 main
上有代码 myscript.py
,我正在尝试将其移至现有分支 branchA
。
% git branch
branchA
* main
myscript.py
在 main
上,我怎样才能将它移动到 branchA
以便它不再出现在 main
上?
如果您还没有提交文件,您可以简单地移动新分支并继续:
git switch -c branchA
如果您已经提交了文件,您可以在将其移动到新分支之前将其恢复到某个提交:
git restore -s <commit> myscript.py
git switch -c branchA
代码——或者更准确地说,文件——驻留在提交.
中
分支——或者更准确地说,分支 names—select 提交。更准确地说,分支名称包含 一个特定提交 的原始哈希 ID。由于该特定提交,分支中的所有其他提交都在分支中。
任何提交,一旦做出,就永远无法更改。但存储在 分支名称 中的原始哈希 ID 可以 始终 更改。事实上,这就是分支名称的全部意义:存储不断变化的哈希 ID。
当我们进行 new 提交时,Git:
- 打包新的源快照;
- 添加一些 元数据 ,或者关于我们现在正在进行的新提交的信息;
- 将所有这些作为提交写出,获得一个新的、唯一的哈希 ID;和
- 将新提交的哈希ID写入分支名称。
因为Git在第二步添加的一个元数据是当前提交的哈希ID,存储在当时的分支名称中我们 运行 git commit
,这使得 new 提交 link 回到以前的当前提交。如果我们从带有哈希 ID 的提交链开始,我们用单个大写字母表示原始哈希 ID 以保持我们的个人理智,我们可能会有这样的东西:
... <-F <-G <-H
此处 H
代表 当前 (到目前为止,最后一个!)提交的哈希 ID。分支名称 main
存储了这个原始哈希 ID,因此名称 main
指向 commit H
:
... <-F <-G <-H <-- main
同时存储在中提交H
的元数据包含早期提交G
的原始哈希ID,所以我们说H
点到 G
。那是从H
出来的箭头。提交 G
当然是一个提交,所以它有一个存储的哈希 ID,在本例中它指向更早的提交 F
,依此类推。
现在,再说一次,任何现有提交都不能更改。我们对Git的正常使用是添加新提交,像这样:
...--G--H <-- main, somebranch
请注意我们有两个名称——main
和 somebranch
——*都指向提交 H
。
我们运行git checkout main
或git switch main
,编辑代码,运行git add
,运行git commit
。 Git 打包一个新的快照并进行一个新的提交,我们称之为 I
。因为我们已经 main
签出,所以 Git 将新的哈希 ID 写入名称 main
。为了记住我们签出的是哪一个,让我们将名称 HEAD
附加到 main
,并绘制新的提交:
...--G--H <-- somebranch
\
I <-- main (HEAD)
注意 main
如何移动 ,而 somebranch
没有。如果我们现在 git checkout somebranch
或 git switch somebranch
,我们得到:
...--G--H <-- somebranch (HEAD)
\
I <-- main
来自提交 I
vanish 的 files,相反,我们有来自提交 H
的文件. Git 删除了提交 I
的那些——它们安全地存储在 I
快照中——并用来自 H
.
的文件替换它们
我们现在可以通过一种方式来回答您的问题:
myscript.py
is on main
, how can I move it to branchA
so that it no longer appears on main
?
我们应该画你有的东西。我不确定你的 branchA
selects 提交了什么,也不知道你的 main
selects 提交了什么,所以我不得不猜测:你自己的绘图会更好,或者您可以 运行 git log --all --decorate --oneline --graph
或来自 Pretty Git branch graphs 的任何其他奇特命令。但是假设我们有:
G--H <-- branchA
/
...--F
\
I <-- main (HEAD)
让我们进一步假设所有文件都已提交(因为如果没有,您有更多选择)。
你可以简单地 运行:
git rm myscript.py
git commit
在 main
上进行 new 提交, 缺少 文件:
G--H <-- branchA
/
...--F
\
I--J <-- main (HEAD)
提交 J
不再有该文件。现在你可以 git switch branchA
切换到现有分支 branchA
并提交 H
:
G--H <-- branchA (HEAD)
/
...--F
\
I--J <-- main
您现在可以看到来自提交 H
的所有文件,这当然意味着您 不会 看到 myscript.py
。但是我们知道它永久保存在提交I
中,所以我们需要告诉Git:从这个现有的提交.[=126=中获取这个保存的文件]
有多个命令可以执行此操作;我一般推荐的是 git restore
,有 --source
和 -SW
选项:
git restore --source main~1 -SW -- myscript.py
有点冗长,和旧命令做同样的事情:
git checkout main~1 -- myscript.py
即使用名称main
后缀~1
先查找提交J
(main
),然后回退一次(~1
) 提交 I
。然后它找到名为 myscript.py
的文件 在 中提交并将该文件复制到两个地方:
-W
将文件复制到您的 工作树 ,您可以在其中查看和编辑它。
-S
将文件复制到 Git 的 暂存区 ,现在可以提交了。
git checkout
命令没有 -S
和 -W
标志:它总是复制到两个地方。
现在你有了这个文件 并且 它已经 git add
-ed,你只需要 运行 git commit
创建一个新的将更新当前 (HEAD
) 分支名称的提交:
G--H--K <-- branchA (HEAD)
/
...--F
\
I--J <-- main
提交 K
与现有提交 H
完全一样,只是它添加了这个新文件。
请注意,这些分支中的这些提交是历史。通过提交 F
的提交在两个分支 中是 。 Git 找到这些提交的方法是使用分支名称找到 last 提交然后向后工作。
还有更多选择
如果您还没有提交该文件,它目前只在您的工作树中,也许也在Git的暂存区中。请参阅 ,但请注意 git switch -c
尝试创建一个 new 分支;你想要 git switch
,它使用 现有分支 .
在这里,我们可以指望由名称 branchA
标识的提交没有 包含名为 myscript.py
的文件。这在实践中变得极其复杂,尽管对于这种情况它很简单。有关所有血腥细节,请参阅 Checkout another branch when there are uncommitted changes on the current branch。
以上所有内容都是关于添加更多提交。在某些情况下,我们有一些提交,但出于某种原因我们不喜欢它们。在这种情况下,我们可以——在限制范围内——告诉Git停止使用这些提交。
考虑我们有的情况:
G--H <-- branchA
/
...--F
\
I <-- main (HEAD)
我们决定不喜欢 提交I
。我们所做的是最初不理会它,并使用它将文件 myscript.py
复制到我们添加到 branchA
:
的新提交中
G--H--J <-- branchA (HEAD)
/
...--F
\
I <-- main
使用相同的 git restore
技术(虽然这次我们使用 --source main
,而不是 --source main~1
,因为我们没有在 [=267] 上进行新的提交=] main
).
然后,不过,我们 git switch
回到 main
和 运行:
git reset --hard HEAD~1
或:
git reset --hard main~1
~1
后缀与以前做同样的事情:找到提交,然后后退一步。这定位提交 F
。我们可以 运行 git log
并使用鼠标剪切和粘贴提交 F
:
的原始哈希 ID
git reset --hard <hash>
在这里。接下来,git reset
:
- 将 分支名称 移动到我们 select 编辑的提交;
- 重置Git的索引/暂存区;和
- 使您的工作树匹配(由于
--hard
)。
这给我们留下了:
G--H--J <-- branchA
/
...--F <-- main (HEAD)
\
I ???
请注意如何不再有任何 name 可以用来 find 提交 I
。如果你记住了它的哈希 ID,或者把它写在纸上,或者什么的,你仍然可以通过这种方式找到它。 Git 提供了其他方法来取回它,默认至少 30 天。但大多数情况下,它似乎消失了,就好像它从未存在过一样。
所以现在看起来 last 在 main
上的提交是提交 F
,而不是提交 I
。只要没有其他人提交 I
——你从未将它发送到其他 Git 存储库——就可以安全地“摆脱”这样的提交。如果你 did 将它发送到某个地方,它可能会从那里返回,因为 Git 真的很喜欢 add 提交并且会像这样传播它们病毒,给一半的机会。因此,一旦提交(通常使用 git push
,通常是 git push
),“倒回”或“删除”提交通常是不明智的。
我在 main
上有代码 myscript.py
,我正在尝试将其移至现有分支 branchA
。
% git branch
branchA
* main
myscript.py
在 main
上,我怎样才能将它移动到 branchA
以便它不再出现在 main
上?
如果您还没有提交文件,您可以简单地移动新分支并继续:
git switch -c branchA
如果您已经提交了文件,您可以在将其移动到新分支之前将其恢复到某个提交:
git restore -s <commit> myscript.py
git switch -c branchA
代码——或者更准确地说,文件——驻留在提交.
中分支——或者更准确地说,分支 names—select 提交。更准确地说,分支名称包含 一个特定提交 的原始哈希 ID。由于该特定提交,分支中的所有其他提交都在分支中。
任何提交,一旦做出,就永远无法更改。但存储在 分支名称 中的原始哈希 ID 可以 始终 更改。事实上,这就是分支名称的全部意义:存储不断变化的哈希 ID。
当我们进行 new 提交时,Git:
- 打包新的源快照;
- 添加一些 元数据 ,或者关于我们现在正在进行的新提交的信息;
- 将所有这些作为提交写出,获得一个新的、唯一的哈希 ID;和
- 将新提交的哈希ID写入分支名称。
因为Git在第二步添加的一个元数据是当前提交的哈希ID,存储在当时的分支名称中我们 运行 git commit
,这使得 new 提交 link 回到以前的当前提交。如果我们从带有哈希 ID 的提交链开始,我们用单个大写字母表示原始哈希 ID 以保持我们的个人理智,我们可能会有这样的东西:
... <-F <-G <-H
此处 H
代表 当前 (到目前为止,最后一个!)提交的哈希 ID。分支名称 main
存储了这个原始哈希 ID,因此名称 main
指向 commit H
:
... <-F <-G <-H <-- main
同时存储在中提交H
的元数据包含早期提交G
的原始哈希ID,所以我们说H
点到 G
。那是从H
出来的箭头。提交 G
当然是一个提交,所以它有一个存储的哈希 ID,在本例中它指向更早的提交 F
,依此类推。
现在,再说一次,任何现有提交都不能更改。我们对Git的正常使用是添加新提交,像这样:
...--G--H <-- main, somebranch
请注意我们有两个名称——main
和 somebranch
——*都指向提交 H
。
我们运行git checkout main
或git switch main
,编辑代码,运行git add
,运行git commit
。 Git 打包一个新的快照并进行一个新的提交,我们称之为 I
。因为我们已经 main
签出,所以 Git 将新的哈希 ID 写入名称 main
。为了记住我们签出的是哪一个,让我们将名称 HEAD
附加到 main
,并绘制新的提交:
...--G--H <-- somebranch
\
I <-- main (HEAD)
注意 main
如何移动 ,而 somebranch
没有。如果我们现在 git checkout somebranch
或 git switch somebranch
,我们得到:
...--G--H <-- somebranch (HEAD)
\
I <-- main
来自提交 I
vanish 的 files,相反,我们有来自提交 H
的文件. Git 删除了提交 I
的那些——它们安全地存储在 I
快照中——并用来自 H
.
我们现在可以通过一种方式来回答您的问题:
myscript.py
is onmain
, how can I move it tobranchA
so that it no longer appears onmain
?
我们应该画你有的东西。我不确定你的 branchA
selects 提交了什么,也不知道你的 main
selects 提交了什么,所以我不得不猜测:你自己的绘图会更好,或者您可以 运行 git log --all --decorate --oneline --graph
或来自 Pretty Git branch graphs 的任何其他奇特命令。但是假设我们有:
G--H <-- branchA
/
...--F
\
I <-- main (HEAD)
让我们进一步假设所有文件都已提交(因为如果没有,您有更多选择)。
你可以简单地 运行:
git rm myscript.py
git commit
在 main
上进行 new 提交, 缺少 文件:
G--H <-- branchA
/
...--F
\
I--J <-- main (HEAD)
提交 J
不再有该文件。现在你可以 git switch branchA
切换到现有分支 branchA
并提交 H
:
G--H <-- branchA (HEAD)
/
...--F
\
I--J <-- main
您现在可以看到来自提交 H
的所有文件,这当然意味着您 不会 看到 myscript.py
。但是我们知道它永久保存在提交I
中,所以我们需要告诉Git:从这个现有的提交.[=126=中获取这个保存的文件]
有多个命令可以执行此操作;我一般推荐的是 git restore
,有 --source
和 -SW
选项:
git restore --source main~1 -SW -- myscript.py
有点冗长,和旧命令做同样的事情:
git checkout main~1 -- myscript.py
即使用名称main
后缀~1
先查找提交J
(main
),然后回退一次(~1
) 提交 I
。然后它找到名为 myscript.py
的文件 在 中提交并将该文件复制到两个地方:
-W
将文件复制到您的 工作树 ,您可以在其中查看和编辑它。-S
将文件复制到 Git 的 暂存区 ,现在可以提交了。
git checkout
命令没有 -S
和 -W
标志:它总是复制到两个地方。
现在你有了这个文件 并且 它已经 git add
-ed,你只需要 运行 git commit
创建一个新的将更新当前 (HEAD
) 分支名称的提交:
G--H--K <-- branchA (HEAD)
/
...--F
\
I--J <-- main
提交 K
与现有提交 H
完全一样,只是它添加了这个新文件。
请注意,这些分支中的这些提交是历史。通过提交 F
的提交在两个分支 中是 。 Git 找到这些提交的方法是使用分支名称找到 last 提交然后向后工作。
还有更多选择
如果您还没有提交该文件,它目前只在您的工作树中,也许也在Git的暂存区中。请参阅 git switch -c
尝试创建一个 new 分支;你想要 git switch
,它使用 现有分支 .
在这里,我们可以指望由名称 branchA
标识的提交没有 包含名为 myscript.py
的文件。这在实践中变得极其复杂,尽管对于这种情况它很简单。有关所有血腥细节,请参阅 Checkout another branch when there are uncommitted changes on the current branch。
以上所有内容都是关于添加更多提交。在某些情况下,我们有一些提交,但出于某种原因我们不喜欢它们。在这种情况下,我们可以——在限制范围内——告诉Git停止使用这些提交。
考虑我们有的情况:
G--H <-- branchA
/
...--F
\
I <-- main (HEAD)
我们决定不喜欢 提交I
。我们所做的是最初不理会它,并使用它将文件 myscript.py
复制到我们添加到 branchA
:
G--H--J <-- branchA (HEAD)
/
...--F
\
I <-- main
使用相同的 git restore
技术(虽然这次我们使用 --source main
,而不是 --source main~1
,因为我们没有在 [=267] 上进行新的提交=] main
).
然后,不过,我们 git switch
回到 main
和 运行:
git reset --hard HEAD~1
或:
git reset --hard main~1
~1
后缀与以前做同样的事情:找到提交,然后后退一步。这定位提交 F
。我们可以 运行 git log
并使用鼠标剪切和粘贴提交 F
:
git reset --hard <hash>
在这里。接下来,git reset
:
- 将 分支名称 移动到我们 select 编辑的提交;
- 重置Git的索引/暂存区;和
- 使您的工作树匹配(由于
--hard
)。
这给我们留下了:
G--H--J <-- branchA
/
...--F <-- main (HEAD)
\
I ???
请注意如何不再有任何 name 可以用来 find 提交 I
。如果你记住了它的哈希 ID,或者把它写在纸上,或者什么的,你仍然可以通过这种方式找到它。 Git 提供了其他方法来取回它,默认至少 30 天。但大多数情况下,它似乎消失了,就好像它从未存在过一样。
所以现在看起来 last 在 main
上的提交是提交 F
,而不是提交 I
。只要没有其他人提交 I
——你从未将它发送到其他 Git 存储库——就可以安全地“摆脱”这样的提交。如果你 did 将它发送到某个地方,它可能会从那里返回,因为 Git 真的很喜欢 add 提交并且会像这样传播它们病毒,给一半的机会。因此,一旦提交(通常使用 git push
,通常是 git push
),“倒回”或“删除”提交通常是不明智的。