0

我有代码myscript.pymain我正在尝试将其移动到现有分支branchA

% git branch
  branchA
* main 

myscript.py已开启main,我怎样才能将其移至branchA以使其不再出现main

4

2 回答 2

1

代码——或者更准确地说,文件——驻留在commits中。

分支——或者更准确地说,分支名称——<em>选择提交。更准确地说,分支名称包含一个特定提交的原始哈希 ID 。由于该特定提交,分支中的所有其他提交都在分支中。

任何提交,一旦做出,就永远无法改变。但是存储在分支名称中的原始哈希 ID始终可以更改。事实上,这就是分支名称的全部意义所在:存储一个不断变化的哈希 ID。

当我们进行新的提交时,Git:

  • 打包一个新的源快照;
  • 添加一些元数据,或者关于我们现在正在进行的新提交的信息;
  • 将所有这些作为提交写出,获得一个新的、唯一的哈希 ID;和
  • 提交的哈希 ID写入分支名称

因为 Git 在第二步中添加的一部分元数据是当前提交的哈希 ID,正如我们运行时存储在分支名称中的那样git commit,这使得的提交链接回到了以前的当前提交。如果我们从带有哈希 ID 的提交链开始,我们用单个大写字母表示原始哈希 ID 以保持我们的个人理智,我们可能会有这样的事情:

... <-F <-G <-H

这里H代表当前(到目前为止,最后一次!)提交的哈希 ID。分支名称main存储此原始哈希 ID,因此名称main 指向commit H

... <-F <-G <-H   <-- main

同时,commit 中存储的元数据包含先前H提交的原始哈希 ID G,因此我们说H指向G. 那是从 中射出的箭矢H。CommitG当然是一个提交,所以它有一个存储的哈希 ID,在这种情况下它指向更早的提交F,依此类推。

现在,再一次,没有任何现有的提交可以改变。我们对 Git 的正常使用是添加新的提交,如下所示:

...--G--H   <-- main, somebranch

注意我们有两个名字——<code>main 和somebranch——都指向 commit H

我们运行git checkout mainor git switch main,编辑代码,运行git add,然后运行git commit​​。Git 打包一个新快照并进行新的提交,我们将调用I. 因为我们已经main签出,Git 将新的哈希 ID 写入 name main。为了记住我们检查了哪一个,让我们将名称附加HEADmain,并绘制新的提交:

...--G--H   <-- somebranch
         \
          I   <-- main (HEAD)

请注意如何main 移动,而somebranch没有。如果我们现在git checkout somebranchgit switch somebranch,我们得到:

...--G--H   <-- somebranch (HEAD)
         \
          I   <-- main

来自 commit vanish文件,取而代之的是来自 commit 的文件。Git 已经删除了那些与提交相关的内容——它们安全地存储在快照中——并将它们替换为来自.I HIIH

我们现在可以解决一种方法来回答您的问题:

myscript.py已开启main,我怎样才能将其移至branchA以使其不再出现main

我们应该画出你所拥有的。我不确定你的branchA选择是什么,也不知道你的选择是什么main,所以我不得不猜测:你自己的绘图会更好,或者你可以运行来自Pretty Git branch graphsgit log --all --decorate --oneline --graph的任何其他花哨的命令。但是假设我们有:

       G--H   <-- branchA
      /
...--F
      \
       I   <-- main (HEAD)

让我们进一步假设所有文件都已提交(因为如果没有,您有更多选择)。

您可以简单地运行:

git rm myscript.py
git commit

缺少该文件的提交:main

       G--H   <-- branchA
      /
...--F
      \
       I--J   <-- main (HEAD)

提交J不再具有该文件。现在您可以git switch branchA切换到现有分支branchA并提交H

       G--H   <-- branchA (HEAD)
      /
...--F
      \
       I--J   <-- main

您现在可以看到来自 commit 的所有文件H,这当然意味着您不到myscript.py. 但是我们知道它被永久保存在 commit 中I,所以我们需要告诉 Git:去从这个现有的 commit 中获取这个保存的文件

有多个命令可以做到这一点;我通常推荐的是git restore,带有--sourceand-SW选项:

git restore --source main~1 -SW -- myscript.py

这有点冗长,并且与旧命令执行相同的操作:

git checkout main~1 -- myscript.py

也就是说,它使用main带后缀的名称~1先查找提交J( main),然后退一步 ( ~1) 提交Imyscript.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完全相同,只是它添加了一个新文件。

请注意,这些分支中的这些提交历史记录。通过 commit 向上提交F两个分支中。Git 查找这些提交的方式是使用分支名称来查找最后一个提交,然后向后工作。

还有更多选择

如果您还没有提交该文件,那么它目前只在您的工作树中,也可能在 Git 的暂存区域中。请参阅joshmeranda 的回答,但请注意git switch -c尝试创建一个分支;你想要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)

我们决定不喜欢commit I。我们所做的是最初不理会它,并使用它将文件复制myscript.py到我们添加到的新提交中branchA

       G--H--J   <-- branchA (HEAD)
      /
...--F
      \
       I   <-- main

使用相同的git restore技术(尽管这次我们使用--source main, 不是--source main~1,因为我们没有在 上进行新的提交 main

然后,我们git switch返回main并运行:

git reset --hard HEAD~1

或者:

git reset --hard main~1

后缀的~1作用和以前一样:找到提交,然后后退一跳。这将定位 commit F。我们可以运行git log并使用鼠标剪切和粘贴 commit 的原始哈希 ID F

git reset --hard <hash>

这里。接下来,git reset

  • 分支名称移动到我们选择的提交;
  • 重置 Git 的索引/暂存区;和
  • 使您的工作树匹配(由于--hard)。

这给我们留下了:

       G--H--J   <-- branchA
      /
...--F   <-- main (HEAD)
      \
       I   ???

请注意如何不再有任何名称可以用来查找commit I。如果你已经记住了它的哈希 ID,或者把它写在纸上,或者其他东西,你仍然可以这样找到它。Git 还提供了其他方法来恢复它,默认情况下至少 30 天。但大多数情况下,它似乎已经消失了,就好像它从未存在过一样。

所以现在看起来最后一次提交main是 commit F,而不是 commit I。只要没有其他人提交I——你从未将它发送到其他 Git 存储库——“摆脱”这样的提交是安全的。如果你确实将它发送到某个地方,它可能会从那里回来,因为 Git 真的很喜欢添加提交,并且会像病毒一样传播它们,只要有一半的机会。因此,一旦您将提交(git push通常使用 )“回退”或“删除”提交,通常是不明智的。

于 2021-09-08T02:18:35.920 回答
0

如果您还没有提交文件,您可以简单地移动新分支并继续:

git switch -c branchA

如果您已经提交了文件,则可以在将其移动到新分支之前将其恢复到某个提交:

git restore -s <commit> myscript.py
git switch -c branchA
于 2021-09-08T02:00:26.390 回答