如何将特定的提交推送到远程仓库,而不是之前的提交?

1068
我已经在不同的文件上做了几次提交,但目前我只想将特定的提交推送到远程仓库。
这是否可能?

8
可能是重复的问题:如何将单个Git提交推送到远程仓库? - mmmmmm
看这里的好技巧:https://dev59.com/wHI-5IYBdhLWcg3wkJMA#1789142 - Benj
8个回答

1425

要将一个给定的提交 推送 上去,你可以这样写:

git push <remotename> <commit SHA>:<remotebranchname>

如果远程仓库中已经存在<remotebranchname>分支(如果不存在,你可以使用git push <remotename> <commit SHA>:refs/heads/<remotebranchname>自动创建它),则可以直接进行推送。

如果要推送一次提交而不包括前面的提交历史记录,你应该首先使用git rebase -i重新排序提交历史记录。


81
git push <remotename> <commit SHA>:<remotebranchname> 可以使用。关键是结合 git rebase -i 命令,将需要的提交作为第一个提交移动,并指定该提交的 commit-sha。 - dminer
38
另一个好的提示是确保在完成rebase -i之后,而不是像我刚才那样在此之前,复制您要推送的提交的SHA。 - estan
48
记住,如果远程分支尚不存在,则此方法会失败。可以使用 git push <remotename> <commit SHA>:refs/heads/<new remote branch name> 命令创建新的远程分支。创建后,按照答案描述进行推送即可。 - Wes Oldenbeuving
42
例如,要使用一些标准名称推送除最后一个提交以外的所有内容 git push origin HEAD~1:master - artless noise
4
请注意,如果您已经将更新的 SHA 推送到该远程分支,则需要强制推送此 SHA。请使用 -f 标志。 - Ian Vaughan
显示剩余10条评论

142
其他答案在重新排序描述方面有所欠缺。
git push <remotename> <commit SHA>:<remotebranchname>

将推送一个单独的提交,但该提交必须是您本地未推送的最旧提交,不要与顶部、第一个或尖端提交混淆,这些都是我个人认为含糊不清的描述。该提交需要是您提交中最旧的,即距离您最近的提交最远的那个。如果它不是最旧的提交,则从您最旧的本地未推送SHA到指定的SHA之间的所有提交都将被推送。要重新排序提交,请使用:
git rebase -i HEAD~xxx

重新排序提交后,您可以安全地将其推送到远程仓库。
总结一下,我使用了
git rebase -i HEAD~<number of commits to SHA>
git push origin <post-rebase SHA>:master

将一个单独的提交推送到我的远程主分支。
参考资料:
  1. http://blog.dennisrobinson.name/push-only-one-commit-with-git/
  2. http://blog.dennisrobinson.name/reorder-commits-with-git/
另请参阅:
  1. git: 本地变基后拉取导致重复提交
  2. git: 推送单个提交,使用变基重新排序,重复提交

3
有些起源似乎不允许这样做。例如,在使用GitLab时,我看到“您不被允许向此项目的受保护分支强制推送代码。”这有点奇怪,因为我并没有认为自己在强制什么,只是进行了普通的推送。你有什么办法可以不用“强制”来完成这个操作吗? - Ed Avis
1
@Ed 不应该需要强制推送。听起来你的 git 设置有问题。也许你已经在远程 HEAD 提交之后进行了变基?我不知道什么是受保护的分支,听起来像是权限问题。 - Samuel
1
Samuel - 这个解释很有道理,但是 git rebase -i 只会显示晚于远程 HEAD 的本地提交记录,所以我不知道我怎么可能做到这一点。 - Ed Avis
1
@Ed,你说“git rebase -i 只会显示晚于远程 HEAD 的本地提交记录”,我不认为这是正确的。我测试过了,可以在远程 HEAD 之后进行 rebase。 - Samuel
1
当你运行 'git rebase -i' 命令时,它只会显示一组特定的提交记录:根据文档,“与 git log <upstream>..HEAD 显示的相同的提交记录集合”。我原以为这意味着无论你对这些提交记录做了什么,你都不能回到比 upstream HEAD 更早的版本,但我想这可能比我想象的更微妙。 - Ed Avis
显示剩余2条评论

28

在推送特定提交时,挑选操作相比其他方法效果最佳。

具体操作如下:

创建一个新的分支 -

git branch <new-branch>

将您的新分支与源分支进行更新 -

git fetch

git rebase

这些操作将确保您的内容与原始内容完全相同。

挑选要推送的sha id -

git cherry-pick <sha id of the commit>

运行以下命令即可获取sha id

git log

将其推送到您的远程仓库 -

git push

运行gitk,以查看一切是否按照您想要的方式显示。


4
如上述解决方案建议的那样,使用git rebase -i将是理想的解决方法。当您想要复制提交时,才需要使用Cherry pick。 - Vinay Bhargav

27

我建议使用git rebase -i; 将要推送的提交移动到你已经做出的提交的顶部。 然后使用git log获取重新基础化提交的SHA,检查它,并推送它。 重新基础化将确保所有其他提交现在都是你推送的提交的子级,因此未来的推送也将正常工作。


4
可以给一个更完整的例子,特别是针对 git log 步骤的部分吗? - Drux
6
假设你有三个相对独立的提交,它们的消息依次为"A"、"B"、"C",现在你想要推送"B"。使用命令'git rebase -i'会打开一个编辑器,列出这三个提交;将"B"移动到最上方,然后保存/退出。使用命令'git log --pretty=oneline -n3',可以列出"B"、"A"、"C"的哈希值以及提交信息,此时"B"应该是最后一个。使用命令'git checkout -b temp $hash_of_B; git push'即可推送"B"。如果你原本就在本地的主分支上,那么接下来你可能需要使用命令'git checkout -b master; git branch -d temp'来回到之前的状态。根据实际情况进行替换。 - Walter Mundt
3
你是否曾在rebase-push-rebase后遭遇过"git神的愤怒"(参考链接https://help.github.com/articles/interactive-rebase)?这可能也会意外发生,对吧? - Drux
3
如果你仔细阅读我的回答,你会发现推送操作只会在变基之后进行,并且变基后的提交只会移动到其他尚未推送的提交之上。一旦提交被推送,通常应该视为不可更改;在未来的变基中请不要修改它。这个技巧只是让你能够将多个本地更改排序后再推送。如果你已经正确设置了跟踪,使用“git rebase -i”命令而不带其他参数将默认不会显示已经推送的提交,因此相比于其他方法更加安全,可以避免出现意外。 - Walter Mundt

19

我认为你需要使用 "git revert" 回到那个提交版本,然后将其推送。或者你可以通过 cherry-pick 将一个提交应用到新分支中,并将其推送到远程仓库上的分支。大概是这样:

git branch onecommit
git checkout onecommit
git cherry-pick 7300a6130d9447e18a931e898b64eefedea19544 # From the other branch
git push origin {branch}

12
git revert 在这里是个不好的选择——它会创建一个新的提交。 - hasen
1
@hasen:接下来你可以只是cherry-pick你想要的提交。 - Josh K
4
回退和挑选提交(commit)都不是好主意。在这里,git rebase -i 是你的朋友,请参考下面 Walter Mundt 的回答。 - Nicolas C
3
@Nicolas,为什么挑拣(cherry-pick)是个不好的想法? - Antoine
3
通常情况下,你希望你的分支与它在远程仓库上所跟踪的分支保持同步。如果你使用 cherry-pick,相当于是进行了复制/粘贴,你将不得不在某个时候处理还未推送的副本。如果你使用交互式变基,相当于是进行了“剪切和粘贴”,并使你的分支与远程分支保持同步,直到你想要的位置。 - Nicolas C

9

最简单的方法是使用两个命令来实现。

首先,将本地目录设置为所需状态。然后,

git push origin +HEAD^:someBranch

只从远程分支中删除上一个提交(commit),而不影响本地分支 someBranch ,可以连续数次执行此操作,或更改 +HEAD^ 来反映您想要批量从远程删除的提交数量。现在您已经恢复了原状,可以像往常一样使用

git push origin someBranch

来更新远程分支。


1
非常好的答案。非常干净的方法来更改远程分支的HEAD而不影响本地分支。最近我不小心将一些WIP提交推送到了远程,这是将远程恢复到先前状态的最简单方法。太棒了。 - camslice
就意外推送而言,这种技术要求您可以强制推送一些远程不允许的内容。 - wheredidthatnamecomefrom

3

你也可以在另一个目录中:

  • 克隆 [你的仓库]
  • 用刚刚克隆的仓库中的 .git 目录覆盖你原来仓库中的 .git 目录。
  • 运行 git add 和 git commit 命令以提交你的原始代码。

0

我刚刚使用了

git cherry-pick '提交的sha id'

然后执行

git push

在我的情况下,本地分支名为'master',远程默认分支名也是'master'。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接