如何将修订后的提交推送到远程Git存储库?


662

当我处理完源代码后,我做了通常的事情提交,然后将其推送到远程存储库。但是后来我发现我忘记了在源代码中组织导入。因此,我执行了amend命令来替换先前的提交:

> git commit --amend

不幸的是,无法将提交推回存储库。像这样被拒绝:

> git push origin
To //my.remote.repo.com/stuff.git/
 ! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to '//my.remote.repo.com/stuff.git/'

我该怎么办?(我可以访问远程存储库。)


如果我的--amend仅更改提交消息怎么办?是否可以单独编辑最后的提交消息(如果已将其提交到远程)?我在Github上这样做,并得到了关于非快进的相同信息。然后我在下面应用了一个解决方案,但合并仅在顶部添加了更多提交消息

7
@faB:我认为这是一个常见问题解答。提交消息会与提交一起进行哈希处理,因此对其进行更改会更改revid(哈希)。如果不清楚,不可以。IIRC可以在笔记中存储带外信息(因此您可以注释现有提交而无需更改它们)。要标注具体的提交,使用标签
sehe

1
您很快就会(2013年第4季度git1.8.5)能够做得git push -force更加谨慎
VonC

3
这是牛仔风格。不要学习任何进一步的知识,也不要寻找任何方法来撤消之前的git修改。只需添加一些占位符代码,我的意思是,添加一些注释,清除一些代码,或仅添加一些破折号dash...。现在进行真正的提交并将其推送到远程。完成!
nehem 2015年

@ user58777如果您的-amend仅用于更改提交消息,并且此后没有进行任何其他本地提交,则可以将本地分支重置为在修改提交消息之前推送的远程提交。
Scott Ahten

Answers:


504

实际上,我曾经推过--force.git存储库,并被Linus BIG TIME责骂。通常,这会给其他人带来很多问题。一个简单的答案是“不要这样做”。

我看到其他人仍然给出了这样做的诀窍,因此在此不再赘述。但是,您使用--force(或+ master)推出修订后的提交之后,这里有一条提示可以使您从这种情况中恢复过来。

  1. git reflog找旧承诺,你的修正(调用它old,我们将调用新的承诺创建通过修改new)。
  2. old和之间创建合并new,记录的树new,例如git checkout new && git merge -s ours old
  3. 将其与您的主人合并 git merge master
  4. 使用以下结果更新您的母版 git push . HEAD:master
  5. 将结果推出。

那么谁是不幸的足够多的人在提交你抹杀通过修改,并迫使一推就会看到最后的合并结果会看到你的青睐已经根据他们的工作newold。他们后来合并将不会看到之间的冲突old,并new导致从修正这一点,所以他们没有受到影响。


17
我非常清楚,当您强行推送修订的提交(通过破坏历史记录)时会发生什么。幸运的是,我是该项目中唯一的开发人员,远程回购在网络驱动器上,因此这没什么大不了的。我从未考虑过合并修订提交,因此我会对此表示赞同。
Spoike

61
在我们公司中,我们非常有规律地强制推送...由个人开发的功能分支。
OndraŽižka2012年

2
来自Linus的责骂是因为您使用force选项擦除了历史记录,而不是因为您不应该这样做。GabrielleV的解决方案可以正常工作,因为它不会更改历史记录。
user411279 2013年

2
请,由于这个答案的作者(gitster)似乎已经不复存在,所以任何人都可以帮助澄清项目编号1:找到旧提交。如果没有备份,在哪里可以找到?修改和强行推销不会销毁它吗?也许他指的是从仍然在树上保留它的朋友/合作伙伴那里获得它?
Beco博士

2
您可以使用Breco博士git reflog找到它
Simon Zyx '16

269

您正在看到Git安全功能。Git拒绝用您的分支更新远程分支,因为分支的head提交不是您要推送到的分支的当前head提交的直接后代。

如果不是这种情况,那么两个人几乎同时推送到相同的存储库将不知道同时有新的提交,而最后推送的人将丢失前一个推送器的工作而没有任何一个他们意识到这一点。

如果您知道自己是唯一推送的人,并且想要推送修订的提交或推送回退分支的提交,则可以使用-f开关“强制” Git更新远程分支。

git push -f origin master

甚至这可能也不起作用,因为Git允许远程存储库通过使用configuration变量在远端拒绝非快进推送receive.denynonfastforwards。如果是这种情况,拒绝原因将如下所示(请注意“远程拒绝”部分):

 ! [remote rejected] master -> master (non-fast forward)

为了解决这个问题,您需要更改远程存储库的配置,或者作为肮脏的黑客,您可以删除并重新创建分支,从而:

git push origin :master
git push origin master

通常,最后一个git push使用format的参数<local_ref>:<remote_ref>,其中local_ref是本地存储库remote_ref上分支的名称,是远程存储库上分支的名称。该命令对使用两个速记。:master具有一个空的local_ref,这意味着将一个空分支推送到远程端master,即删除远程分支。分支名称绝对不能:将具有给定名称的本地分支推送到具有相同名称的远程分支。master在这种情况下是简写master:master


2
这在github上不起作用,它给了我以下消息:[远程拒绝] master(禁止删除当前分支)
vedang 2010年

我不想强行推送(我知道可以解决该问题),但是现在我想我别无选择。
吠陀

1
这是唯一适用于我的使用Assembla的仓库的解决方案。
贾斯汀

1
删除远程主分支会释放远程仓库中的空间吗?
Mr_and_Mrs_D 2012年

1
@Mr_and_Mrs_D:不是立即,但是git gc一旦reflog过期,旧对象将被修剪。分支更新后,克隆存储库的任何人都不会获得任何不再可访问的对象。
CB Bailey

211

快速说明:这里没有人发布简单答案的事实表明,Git CLI表现出了极度的用户敌意。

无论如何,假设您没有尝试强制执行此操作,“显而易见”的方法是先拉。这会拉出您修改的更改(因此不再更改),以便您再次拥有它。

解决所有冲突后,您可以再次推送。

所以:

git pull

如果在拉取过程中遇到错误,则可能是本地存储库配置中有问题(我在.git / config分支部分中使用了错误的引用)。

之后

git push

也许您会获得与主题有关“临时合并”的额外承诺。


2
是的,我写了一篇关于这一点,见stackoverflow.com/questions/253055/... ;)
Spoike

10
这确实不像我预期的那样工作。它创建两个新的提交。它是旧版本的复制品,但已进行了更改。和一个合并提交与一个空的差异。仍然保持旧提交不变,显示了我试图修改的可能敏感数据。我相信git push -f或是git reset前往这里的唯一方法。
thnee

40
从技术上回答问题时,它并不能真正解决问题。如您所说,它将产生一个额外的提交,但是人们修改一个提交的主要原因是避免创建一个新的提交。因此,如果张贴者按照您的指示进行操作,他将不会获得预期的结果。不首先修改提交也很有意义。
丹·琼斯

102

简短的回答:不要将修订的内容推送到公共回购中。

长答案:一些Git命令(例如git commit --amendgit rebase)实际上重写了历史记录图。只要您还没有发布更改,就可以了,但是一旦您发布了更改,您就真的不应该对历史进行修改,因为如果有人已经获得了更改,那么当他们再次尝试进行更改时,它可能会失败。除了修改提交外,您还应该对更改进行新的提交。

但是,如果您确实要推送修订的提交,则可以这样进行:

$ git push origin +master:master

前导+符号将强制进行推送,即使它不会导致“快进”提交。(当您要推送的更改是公共存储库中更改的直接后代时,会发生快速提交。)


5
这与git push -f有什么不同(更好或更糟)?谢谢!
bentford'2

11
@bentford:与基本上相同git push -f
mipadi 2012年

54

在完成更改后,这是一种非常简单干净的方法来推送更改commit --amend

git reset --soft HEAD^
git stash
git push -f origin master
git stash pop
git commit -a
git push origin master

请执行以下操作:

  • 将分支头重置为父提交。
  • 存储最后一次提交。
  • 强制推送到远程。遥控器现在没有最后一次提交。
  • 藏起来
  • 干净地提交。
  • 推送到远程。

如果将其应用于其他分支或远程,请记住要更改“来源”和“主”。


3
2句话:-如果您正在处理另一个分支,请确保更改分支的名称- git add在提交更改之前,我不得不使用该分支。
SylvainB

1
在Windows CMD中,应转义第一个命令:git reset --soft "HEAD^"。其余的工作正常。
MrMister

2
“一种非常简单和干净的方式。” 此过程包括强制推送。鉴于以上“答案”中的所有批评,我不确定该程序实际上是否干净。
Na13-c

24

我已经解决了它,方法是放弃本地修改的提交,并在顶部添加新的更改:

# Rewind to commit before conflicting
git reset --soft HEAD~1

# Pull the remote version
git pull

# Add the new commit on top
git add ...
git commit
git push

2
这是最简单的版本!
mknaf

添加另一个“更改”提交比弄乱重写历史记录更好。我同意@mknaf
sdkks

8

我有同样的问题。

  • 不小心修改了已经推送的最后一次提交
  • 在本地做了很多更改,做了五次
  • 尝试推送,出现错误,惊慌失措,合并远程,收到很多非我的文件,推送,失败等。

作为一名新手,我认为它是完整的FUBAR

解决方案:有点像@bara建议+创建了本地备份分支

# Rewind to commit just before the pushed-and-amended one.
# Replace <hash> with the needed hash.
# --soft means: leave all the changes there, so nothing is lost.
git reset --soft <hash>

# Create new branch, just for a backup, still having all changes in it.
# The branch was feature/1234, new one - feature/1234-gone-bad
git checkout -b feature/1234-gone-bad

# Commit all the changes (all the mess) not to lose it & not to carry around
git commit -a -m "feature/1234 backup"

# Switch back to the original branch
git checkout feature/1234

# Pull the from remote (named 'origin'), thus 'repairing' our main problem
git pull origin/feature/1234

# Now you have a clean-and-non-diverged branch and a backup of the local changes.
# Check the needed files from the backup branch
git checkout feature/1234-gone-bad -- the/path/to/file.php

也许这不是一个快速而干净的解决方案,但我失去了历史记录(一次提交而不是5次提交),但是却节省了一天的工作。


6

如果您尚未将代码推送到远程分支(GitHub / Bitbucket),则可以在命令行上更改提交消息,如下所示。

 git commit --amend -m "Your new message"

如果您在特定分支上工作,请执行以下操作:

git commit --amend -m "BRANCH-NAME: new message"

如果您已经用错误的消息推送了代码,则在更改消息时需要小心。即,在您更改提交消息并尝试再次推送它之后,您最终会遇到问题。要使其平滑,请执行以下步骤。

请先阅读完整答案,然后再做

git commit --amend -m "BRANCH-NAME : your new message"

git push -f origin BRANCH-NAME                # Not a best practice. Read below why?

重要说明:直接使用强制推送时,可能会遇到其他开发人员在同一分支上工作的代码问题。因此,为了避免这些冲突,您需要在进行强制推送之前从分支中提取代码:

 git commit --amend -m "BRANCH-NAME : your new message"
 git pull origin BRANCH-NAME
 git push -f origin BRANCH-NAME

这是更改提交消息(如果已被推送)的最佳实践。


1
如果您在上一个示例中成功撤回了提交,那么为什么需要强制推送?标准的推送就不够吗?谢谢
托马斯

托马斯提出的问题实际上是非常有效的。我自己不需要强制跟随拉动。
Na13-c

请不要将其称为“最佳实践”,因为有一种解决方法--force,请参见公认的答案
Farid

5

如果您知道没有人取消您的未修改提交,请使用以下--force-with-lease选项git push

在TortoiseGit中,您可以在“推...”选项“强制:可能丢弃”下并检查“已知更改”下执行相同的操作。

强制(可能会丢弃已知更改)允许远程存储库接受更安全的非快速推送。这可能导致远程存储库丢失提交。小心使用。这样可以防止丢失远程其他人的未知更改。它检查服务器分支是否指向与远程跟踪分支相同的提交(已知更改)。如果是,将执行推力。否则将被拒绝。由于git没有远程跟踪标签,因此无法使用此选项覆盖标签。


4

因为Git远程已经具有这些提交文件,所以您收到此错误。您必须强制推动分支才能起作用:

git push -f origin branch_name

另外,请确保您从远程拉出代码,因为团队中的其他人可能已将其拉到同一分支。

git pull origin branch_name

这是我们必须强制将提交推到远程的情况之一。


为什么这个答案不能解释先前答案中提出的主要评论?
Na13-c

2

这里是一个非常简单和干净的方式把你的改变,你已经做出后git add "your files"git commit --amend

git push origin master -f

要么:

git push origin master --force

我听说那很糟糕,而且我敢肯定。我敢肯定,有一个(好的)原因可以使git默认失败(并要求--force)。
罗尔夫

1

我必须通过从远程存储库中拉出并处理出现,提交然后推送的合并冲突来解决此问题。但是我觉得有更好的方法。


并不是的。问题可能是您尚未从远程存储库更新本地副本。Git不会继续使用它,因为您可能必须手动处理合并。在我的其他答复中,我有一个命令(和说明)将强制执行推送-但请注意,该命令可能会删除遥控器中的更改。
mipadi

1

我只是继续做Git告诉我的事情。所以:

  • 由于修订的提交而无法推送。
  • 我按照建议做拉。
  • 合并失败。所以我手动修复。
  • 创建一个新的提交(标记为“合并”)并推送它。
  • 看来行得通!

注意:修订的提交是最新的提交。


1
如果我有更多的声誉点,我会投下赞成票,所以我在这里礼貌地问,你是谁中的一个?谁修改了?一个人,在修订后的提交中拉扯并在分支上工作?修改之前还是之后?我只是清除了我的所有修改内容,因为我误解了您...幸运的是
......-BartisÁron17年

1

在更改提交的作者和提交者时,以下对我有用。

git push -f origin master

Git很聪明,可以弄清楚这些是相同增量的提交,只是在元信息部分有所不同。

本地和远程负责人都指出了相关的提交。



0

在这里,我如何修复上一次提交中的编辑:

  1. 到目前为止保存您的工作。
  2. 如果进行,请暂时保存您的更改: git stash现在,您的工作副本在上一次提交的状态下是干净的。
  3. 进行编辑和修复。
  4. “修改”模式下提交更改:git commit --all --amend
  5. 您的编辑器将出现,询问一条日志消息(默认情况下为旧的日志消息)。满意时保存并退出编辑器。

    新的更改将添加到旧提交。与git log和自己看看git diff HEAD^

  6. 重新进行已隐藏的更改(如果有): git stash apply

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.