将最近的提交转移到另一个分支

时间:2014-02-09 06:55:54

标签: git

我为一些测试目的创建了一个额外的分支。

在开始工作之前,我切换回主分支,喝完茶后,我开始添加文件并修改master分支中的其他文件。

只有在我提交之后,我才记得我在主分支中,而在开始更改之前我必须切换到我的第二分支。

您是否可以告诉我是否可以将此提交发送到第二个分支并将其从主分支中删除?

感谢

2 个答案:

答案 0 :(得分:8)

如果我理解你,你可以做这些事情:

git checkout master
git log
now check hash commit you want to move - for example: 0123456
git checkout branch
git cherry-pick 0123456
git checkout master
git revert 0123456

就是这样。

答案 1 :(得分:6)

这个问题的答案是"有点像,但也许你不需要"。

复制提交,请使用git cherry-pick commit。这基本上告诉git:"去看看我曾经要求你挑选的提交。无论它做了什么改变,在当前分支上再次进行相同的更改。然后使用相同的提交消息进行新的提交 1 。"

因此,如果您已经在master上提交了提交,而您希望在newbranch上提交提交,则

$ git checkout newbranch
$ git cherry-pick master

此时,您将在newbranch上,并且已经复制了提交。您现在需要对master上的旧提交执行一些操作。

如果您没有在任何地方发布(推送,或让别人拉)这个提交,您只需要"回滚":

$ git checkout master
$ git reset --hard HEAD^  # be careful here! I always run "git status" first

请注意git reset --hard将消除正在进行的任何工作。

如果您发布了提交,则通常应该将其还原(请参阅user2699113's answer)。 A"还原"很像是一个樱桃选择,复制一个提交,除了它反转更改:添加的任何内容然后立即删除,并删除任何被删除的内容。 (并且,与cherry-pick一样,revert将自动提交,除非你告诉它不要。)

(请注意,您可以通过SHA-1 ID指定提交,但如果有名称 - 分支或标记名称或其他引用名称 - 则可以只写出名称。)


1 除非您使用-n--no-commit来抑制它,否则git无法进行相同的更改并告诉您存在冲突并让您自己解决。


关于"这可能是你没有"部分?

这是关于git及其提交和分支的事情。 Git与大多数其他版本控制系统不同,因为当您在分支上执行提交时,分支名称实际上并不是提交的一部分。 2 分配分支名称(或标签,无论你想叫什么),但实际的分支结构 - & #34;结构分支" - 由每个提交的历史形成。

提交时,该提交记录其父提交。分支名称只是标签,它为您(和git)提供了一个起始位置,然后git跟随提交父ID。这意味着我们可以手工绘制提交图(有向无环图或提交的DAG):

A <-- B <-- C     <-- master
            ^
             \
              D   <-- branch

此处,commit D是分支branch的提示,它指向提交C作为其父级。提交C点回B,指向A,这是初始(root,parent-less)提交。

当你是&#34;在分公司大师&#34;并创建一个新的分支,只需创建一个新的标签,它指向您现在所在的位置。所以假设你之前有过AC(这次我用这么多箭头画了这些箭头;假设箭头一般指向左边):

A - B - C      <-- HEAD=master

这一次,我添加了HEAD=,以显示git如何跟踪您在&#34;上的哪个分支。 (HEAD目录中的.git文件只包含分支的名称:cat .git/HEAD,您通常会看到ref: refs/heads/master或其他内容。)如果您现在{{1}你得到这个:

git checkout -b branch

(现在A - B - C <-- master, HEAD=branch 包含.git/HEAD而不是branch)。

当你进行新的提交(任何新提交,包括来自cherry-pick和revert的提交)时,git会查看master以查看您所在的分支以及该分支的用途它的SHA-1 ID。这是分支机构的&#34;提示&#34;。然后Git进行一个新的提交,其父级是旧的分支提示,并将新的提交ID写入分支文件,以便分支名称指向新的提交。 (当然HEAD仍然只有分支名称。)

所以,如果您在分行HEAD&#34;&#34;并进行新的提交branch,这就是你得到的:

D

如果你稍微改了一下,并且在分支A - B - C <-- master \ D <-- HEAD=branch &#34;上是&#34;你会得到这个:

master

但等等,这只是你想要的,除了分支标签。您需要做的就是将名称A - B - C <-- branch \ D <-- HEAD=master 指向master所在的位置,将branch指向branch指向的位置,并切换master以使其显示HEAD代替branch

事实证明,这很简单......好吧,漂亮很容易。 :-)你需要一个临时名称,因为git不会让你有两个同名的分支。首先,重命名分支master以允许您更改branch。然后将master重命名为master,并将branch的新名称重命名为branch

master

第一步将标签$ git branch -m branch temp $ git branch -m master branch $ git branch -m temp master 更改为branch。第二个将temp更改为master(并且您仍然在其上,因此也重写branch)。最后一个将HEAD更改为temp,为您提供最初想要的提交DAG和标签设置。

与其他部分一样,您应该只尝试这种&#34;标签交换&#34;在未发布(未推送)提交。 (原因很简单:当你发布提交时,你可以通过 name-to-commit-ID mapping 来实现。如果你随处乱扔标签并且&#34;重新发布&#34; ,提交ID不会改变,但是名称到ID的映射会有所改变,因此任何选择了master意味着master的先前广告的人现在都会获得一个不是&的新映射。 #34;快进相关&#34;旧的。人和git,期望分支映射改变,但通常只有&#34;快进式#34;。


2 例如,在Mercurial中,分支名称实际上记录在commit-data中。