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

当我使用源代码时,我做了通常的提交,然后推送到远程存储库。但是后来我注意到我忘记在源代码中组织我的导入。所以我执行修改命令来替换之前的提交:

> git commit --amend

不幸的是,提交不能被推回到存储库。它被拒绝了,如下所示:

> git push originTo //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/'

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

537669 次浏览

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

简短的回答:不要将修改后的提交推送到公共存储库。

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

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

$ git push origin +master:master

前导+符号将强制推送发生,即使它不会导致“快进”提交。(当您推送的更改是公共存储库中已经存在的更改中的直系后裔时,就会发生快进提交。)

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

如果不是这样,那么两个人在大约相同的时间推送到同一个存储库,就不会知道同时有一个新的提交进来,最后推送的人将失去前一个推送者的工作,而他们中的任何一个都没有意识到这一点。

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

git push -f origin master

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

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

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

git push origin :mastergit push origin master

一般来说,git push的最后一个参数使用格式<local_ref>:<remote_ref>,其中local_ref是本地存储库上分支的名称,remote_ref是远程存储库上分支的名称。这个命令对使用两个简写。:master有一个空local_ref这意味着将一个空分支推送到远程端master,即删除远程分支。没有:的分支名称意味着将具有给定名称的本地分支推送到具有相同名称的远程分支。在这种情况下,mastermaster:master的缩写。

实际上,我曾经使用--force.git存储库并被Linus大时代骂过。一般来说,这会给其他人带来很多问题。一个简单的答案是“不要这样做”。

我看到其他人给出了这样做的秘诀,所以我不会在这里重复它们。但是这里有一个提示,可以从你用--force(或+master)推出修改后的提交的情况之后中恢复过来。

  1. 使用git reflog查找您修改的旧提交(称之为old,我们将调用您通过修改new创建的新提交)。
  2. oldnew之间创建合并,记录new的树,如git checkout new && git merge -s ours old
  3. 将其与git merge master合并到您的主服务器
  4. 使用git push . HEAD:master更新您的主服务器的结果
  5. 把结果推出去。

然后,那些不幸地将他们的工作基于你通过修改和强制推送而删除的提交的人将看到结果合并将看到你支持new而不是old。他们后来的合并不会看到由于你的修改而导致的oldnew之间的冲突,所以他们不必受苦。

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

不管怎么说,最明显的方法是先拉取,假设你没有尝试过强制推,这会拉取你修改过的(所以不再有的)更改,这样你就可以再次得到它。

一旦你解决了任何冲突,你可以再次推动。

所以:

git pull

如果您在拉取中出现错误,可能是您的本地存储库配置中出现了问题(我在. git/config分支部分中的引用错误)。

在那之后

git push

也许你会得到一个额外的提交,主题讲述了一个“琐碎的合并”。

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

# Rewind to commit before conflictinggit reset --soft HEAD~1
# Pull the remote versiongit pull
# Add the new commit on topgit add ...git commitgit push

我也有同样的问题。

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

作为一个Git新手,我认为它是完整的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-badgit checkout -b feature/1234-gone-bad
# Commit all the changes (all the mess) not to lose it & not to carry aroundgit commit -a -m "feature/1234 backup"
# Switch back to the original branchgit checkout feature/1234
# Pull the from remote (named 'origin'), thus 'repairing' our main problemgit 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 branchgit checkout feature/1234-gone-bad -- the/path/to/file.php

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

如果您没有将代码推送到您的远程分支(GitHub/比特桶),您可以在命令行上更改提交消息,如下所示。

 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-NAMEgit push -f origin BRANCH-NAME

这是更改提交消息(如果已推送)时的最佳做法。

这里有一个非常简单和干净的方法来在你已经做了commit --amend之后推送你的更改:

git reset --soft HEAD^git stashgit push -f origin mastergit stash popgit commit -agit push origin master

它执行以下操作:

  • 将分支头重置为父提交。
  • 保存最后一次提交。
  • 强制推送到远程。远程现在没有最后一次提交。
  • 弹出你的藏匿。
  • 干净利落地承诺。
  • 推到遥控器。

如果将其应用于不同的分支或远程,请记住更改originmaster

这里有一个非常简单和干净的方法来在你已经做了git add "your files"git commit --amend之后推送你的更改:

git push origin master -f

或:

git push origin master --force

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

git push -f origin branch_name

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

git pull origin branch_name

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

如果你知道没有人拉你的未修改的提交,使用git push--force-with-lease选项。

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

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

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

  • 无法推送,因为修改了提交。
  • 我按照建议做了一个拉动。
  • 合并失败。所以我手动修复它。
  • 创建一个新的提交(标记为"合并")并按它。
  • 它似乎工作!

注意:修改后的提交是最新的。

在这里,我如何在以前的提交中修复编辑:

  1. 保存到目前为止的工作。

  2. 如果进行了更改,请暂时隐藏您的更改:git stash现在,您的工作副本在上次提交的状态下是干净的。

  3. 进行编辑和修复。

  4. 提交“修改”模式下的更改:git commit --all --amend

  5. 您的编辑器将出现请求日志消息(默认情况下,旧的日志消息)。保存并退出编辑器,当你满意的时候。

    新的更改被添加到旧的提交中。用git loggit diff HEAD^亲自查看

  6. 重新应用隐藏的更改,如果进行了:git stash apply

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

git push -f origin master

Git足够聪明,可以发现这些是相同增量的提交,仅在元信息部分有所不同。

本地和远程负责人都指出了有问题的提交。

如果您使用的是Visual Studio Code,您可以尝试此扩展以使其更容易。

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

正如你可以从它的名字理解,它连续执行命令

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

为了避免强制推送,在远程裸存储库中使用以下方法删除最后一次提交(要修改的):

git update-ref HEAD HEAD^

然后在没有冲突的情况下推送修改后的提交。

注意:这假设在此期间没有人拉出错误的提交。如果有,他们将不得不类似地倒回并重新拉出,可能合并他们自己的更改。

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

git commit --amend -m "New message"
git push --force repository-name branch-name

说明:不建议使用--force,除非您绝对确定在最近一次提交之后没有其他人克隆了您的存储库。

更安全的选择是使用:

git push --force-with-lease repository-name branch-name

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

您可以通过以下简单而安全的方式完成:

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

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

在这种情况下,你应该——强制。

依据:

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

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

我会怎么做?

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