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

Spo*_*ike 624 git git-amend git-commit

当我使用我的源代码工作时,我做了我惯常的事情提交,然后我推送到远程存储库.但后来我注意到我忘了在源代码中组织我的导入.所以我做了修改命令来替换以前的提交:

> git commit --amend
Run Code Online (Sandbox Code Playgroud)

不幸的是,提交不能被推回到存储库.这被拒绝了:

> 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/'
Run Code Online (Sandbox Code Playgroud)

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

小智 479

我实际上曾经--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.他们后来合并将不会看到之间的矛盾oldnew起因于您的修正,所以他们没有受到影响.

  • 莱纳斯说了什么? (525认同)
  • 在我们公司,我们经常强制推动...在个人开发的功能分支上. (53认同)
  • 我非常清楚当你强行推送一个修改过的提交(通过破坏历史)时会发生什么.幸运的是,我是该项目中唯一一个远程仓库在网络驱动器上的开发人员,所以这并不是什么大不了的事.我从来没有想过合并修改提交,所以我会提出这个问题. (17认同)
  • 其他人指出,但只是想更加强调这一点:如果您正在功能分支上进行开发 - 那么在大多数情况下重写该分支的历史记录不会对任何人或任何其他事物产生影响。事实上,在功能分支的单独工作期间,人们可能会经常使用强制推送。 (3认同)
  • 来自Linus的责骂是因为你用力量选项抹去了历史,而不是因为你不应该这样做.GabrielleV的解决方案很好,因为它不会改变历史. (2认同)
  • 关于强制推送到功能分支,如果您正在个人功能分支上工作,这不应该被认为是可以的吗?你正在重写的历史只是你自己的,你完全清楚这一点。例如,我和我的团队成员相应地命名个人分支,例如develop_<功能>_<开发人员名称>。这就是分布式修订管理的全部意义,我们可以在自己的沙箱上做任何想做的事情,只是不要弄乱主线中的历史记录。 (2认同)
  • 请,因为这个答案的作者(gitster)似乎不再存在,任何人都可以帮助澄清项目编号1:找到旧的提交.如果您没有备份,您会在哪里找到它?修改和强制推动不会被破坏吗?也许他指的是从朋友/合作者那里得到它仍然在树上? (2认同)
  • Breco博士你可以使用`git reflog`找到它 (2认同)
  • @Linus 应该责备自己没有想出一种方法来自动重新连接分离的头部。 (2认同)

CB *_*ley 260

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

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

如果你知道你是唯一一个推动你想要推送修改后的提交或推送一个回退分支的提交的人,你可以"强迫"Git使用该-f开关来更新远程分支.

git push -f origin master
Run Code Online (Sandbox Code Playgroud)

即使这可能也行不通,因为Git允许远程存储库通过使用配置变量来拒绝远端的非快速推送receive.denynonfastforwards.如果是这种情况,拒绝原因将如下所示(请注意'远程拒绝'部分):

 ! [remote rejected] master -> master (non-fast forward)
Run Code Online (Sandbox Code Playgroud)

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

git push origin :master
git push origin master
Run Code Online (Sandbox Code Playgroud)

通常,git push使用格式的最后一个参数<local_ref>:<remote_ref>,其中local_ref是本地存储库remote_ref上的分支的名称,并且是远程存储库上的分支的名称.此命令对使用两个shorthands.:master具有null local_ref,这意味着将空分支推送到远程端master,即删除远程分支.无分支名称:将具有给定名称的本地分支推送到具有相同名称的远程分支.master在这种情况下是短暂的master:master.

  • 这不适用于github,它给了我以下消息:[远程拒绝] master(禁止删除当前分支) (2认同)

小智 206

快速咆哮:这里没有人发布简单答案的事实证明了Git CLI表现出的绝望的用户敌意.

无论如何,假设你还没有试图强行推动,那么"明显"的做法是先拉.这会拉动您修改的更改(因此不再具有),以便您再次使用它.

解决任何冲突后,您可以再次推送.

所以:

git pull
Run Code Online (Sandbox Code Playgroud)

如果你在pull中出错,可能是你的本地存储库配置有问题(我在.git/config分支部分有一个错误的引用).

之后

git push
Run Code Online (Sandbox Code Playgroud)

也许你会得到额外的提交,主题讲述"琐碎的合并".

  • 虽然从技术上回答了这个问题,但它并没有真正解决这个问题.如你所说,它会产生额外的提交,但人们修改提交的主要原因是避免创建一个新提交.因此,如果海报遵循您的指示,他将无法获得所需的结果.首先不修改提交也是有意义的. (35认同)
  • 这并没有像我预期的那样真正起作用.它创建了两个新提交.一个是旧的复制品,但修改后的变化.一个合并提交与空diff.仍然保持旧提交不变,揭示可能敏感的数据,我试图修改.我相信`git push -f`或`git reset`是唯一的方法. (10认同)
  • 是的,我写了这篇文章,请参阅http://stackoverflow.com/questions/253055/how-do-i-push-amended-commit-to-the-remote-git-repo/1459351#1459351;) (2认同)

mip*_*adi 98

简短的回答:不要将修改后的提交推送到公共回购.

答案很长:一些Git命令,比如git commit --amendgit rebase,实际上重写了历史图.只要你没有公布你的更改,这很好,但是一旦你做了,你真的不应该在历史上徘徊,因为如果有人已经得到你的改变,那么当他们试图再次拉动时,它可能会失败.您应该只使用更改进行新的提交,而不是修改提交.

但是,如果你真的想要推送修改后的提交,你可以这样做:

$ git push origin +master:master
Run Code Online (Sandbox Code Playgroud)

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

  • @bentford:它与`git push -f`基本相同. (8认同)
  • @mipadi,那么我想说为了简单起见,最好使用更明确的 git push -f (6认同)
  • 这与git push -f有什么不同(更好还是更差)?谢谢! (5认同)

小智 48

在您完成以下操作后,这是一种非常简单而干净的方式来推动您的更改commit --amend:

git reset --soft HEAD^
git stash
git push -f origin master
git stash pop
git commit -a
git push origin master
Run Code Online (Sandbox Code Playgroud)

具体如下:

  • 将分支头重置为父提交.
  • 存放最后一次提交.
  • 强制推送到远程.远程现在没有最后一次提交.
  • 弹出你的藏匿处.
  • 干得好.
  • 推送到远程.

如果将其应用于其他分支或远程,请记住更改"origin"和"master".

  • 2句话:-如果您正在处理另一个分支,请确保更改分支的名称-在提交包含更改之前,我必须使用`git add`。 (2认同)
  • “一种非常简单和干净的方式..” cit。此过程包括强制推送。鉴于上述答案中的所有批评,我不确定这个程序是否实际上是一个干净的程序。 (2认同)

bar*_*ara 22

我通过放弃我的本地修改提交并在顶部添加新更改来解决它:

# 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
Run Code Online (Sandbox Code Playgroud)

  • 这是最简单的版本! (2认同)

M-R*_*avi 16

如果要更改的消息是针对存储库的最新提交,则需要执行以下命令:

git commit --amend -m "New message"

git push --force repository-name branch-name
Run Code Online (Sandbox Code Playgroud)

注意:不建议使用 --force ,除非您绝对确定在最新提交后没有其他人克隆您的存储库。

更安全的替代方法是使用:

git push --force-with-lease repository-name branch-name
Run Code Online (Sandbox Code Playgroud)

与 不同--force,它将破坏其他人推送到分支的任何更改,--force-with-lease如果存储库有上游更改,则会中止。

  • 我知道必须有一个明智的选择,以便不删除其他人的工作,同时让您在没有其他人在此期间做出任何事情的情况下逃脱惩罚。感谢您挖掘出这一点! (2认同)

小智 8

您可以通过以下方式以简单且安全的方式完成此操作:

  1. 修改您的最后一次提交git commit --amend以及您需要添加的任何选项
  2. git pull将本地存储库与远程存储库同步。
  3. pull之后,本地和远程就会产生冲突。您只需通过接受当前更改并再次提交来解决它们。
  4. git push

现在您的本地和远程存储库已更新,无需更改存储库历史记录。


dav*_*sca 7

我有同样的问题.

  • 意外修改了已推送的最后一次提交
  • 在本地做了很多改变,承诺了五次
  • 试图推,得到一个错误,恐慌,合并远程,得到了很多不是我的文件,推,失败等.

作为Git-newbie,我认为这是完整的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
Run Code Online (Sandbox Code Playgroud)

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


Pra*_*thi 6

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

 git commit --amend -m "Your new message"
Run Code Online (Sandbox Code Playgroud)

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

git commit --amend -m "BRANCH-NAME: new message"
Run Code Online (Sandbox Code Playgroud)

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

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

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

git push -f origin BRANCH-NAME                # Not a best practice. Read below why?
Run Code Online (Sandbox Code Playgroud)

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

 git commit --amend -m "BRANCH-NAME : your new message"
 git pull origin BRANCH-NAME
 git push -f origin BRANCH-NAME
Run Code Online (Sandbox Code Playgroud)

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


小智 6

如果您使用的是 Visual Studio Code,则可以尝试使用此扩展来简化操作。

https://marketplace.visualstudio.com/items?itemName=cimdalli.git-commit-amend-push-force

顾名思义,就是连续执行命令

  • git commit --amend
  • git push --force


Pra*_*wan 5

您收到此错误是因为 Git 远程已具有这些提交文件。您必须强制推动分支才能使其工作:

git push -f origin branch_name
Run Code Online (Sandbox Code Playgroud)

还要确保您从远程提取代码,因为您团队中的其他人可能已推送到同一分支。

git pull origin branch_name
Run Code Online (Sandbox Code Playgroud)

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


Sha*_*rly 5

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

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

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


小智 5

在这种情况下,你应该--force。

基于:

如果是个人项目,我会这样做: git push origin <branch-name> -f

如果您正在与您的团队合作,或者其他同行正在审查和使用您的代码,force则不建议使用该标志。主要是因为你总是想要一个干净的 git 历史记录。

我会做什么?

  1. 如果更多的人在同一个分支工作或其他人审查您的代码,我会git commit --amend然后git push -f ...让人们知道他们需要git pull --rebase能够看到您的更改。
  2. 如果在审查 PR 或 MR 时发生类似情况,请添加新的干净提交并在最后squash清理历史记录。