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

如何将修改后的提交推送到远程Git存储库?,git,git-commit,git-amend,Git,Git Commit,Git Amend,当我对我的源代码做了一点工作后,我做了我通常做的事情提交,然后我推到了一个远程存储库。但后来我注意到我忘了在源代码中组织导入。因此,我执行修改命令来替换上一个提交: > git commit --amend 不幸的是,提交无法推回存储库。它是这样被拒绝的: > git push origin To //my.remote.repo.com/stuff.git/ ! [rejected] master -> master (non-fast forward) e

当我对我的源代码做了一点工作后,我做了我通常做的事情提交,然后我推到了一个远程存储库。但后来我注意到我忘了在源代码中组织导入。因此,我执行修改命令来替换上一个提交:

> 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/'
$ git push origin +master:master

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

我必须通过从远程回购中提取来解决这个问题,并处理产生的合并冲突,提交然后推送。但我觉得有更好的办法。

简短的回答:不要推动修改后的承诺进行公开回购

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

但是,如果您真的非常想推动修改后的提交,您可以这样做:

> 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/'
$ git push origin +master:master

前导的
+
符号将强制执行推送,即使它不会导致“快进”提交。(当您正在推送的更改是公共repo中已有更改的直接后代时,会发生快进提交。)

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

如果不是这样的话,那么两个几乎同时推到同一存储库的人将不知道同时有一个新的提交,最后推的人将失去前一推的工作,而他们中的任何一个都没有意识到这一点

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

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

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

git push origin :master
git push origin master

通常,
git push
的最后一个参数使用格式
,其中
local\u ref
是本地存储库上的分支名称,
remote\u ref
是远程存储库上的分支名称。此命令对使用两个速记<代码>:主机具有空本地_ref,这意味着将空分支推送到远程侧
主机
,即删除远程分支。没有
的分支名称:
表示将具有给定名称的本地分支推送到具有相同名称的远程分支
master
在这种情况下是
master:master

的缩写,实际上我曾经用
--force
.git
.repository推过一次,被Linus大牌责骂过。一般来说,这会给其他人带来很多问题。一个简单的答案是“不要这样做”

我看到其他人给出了这样做的秘诀,所以我不会在这里重复。但是在您使用--force(或+master)推出修改后的commit之后,这里有一个技巧可以帮助您从这种情况中恢复过来

  • 使用
    git reflog
    查找您修改的旧提交(称之为
    old
    ,我们将调用您通过修改
    new
    创建的新提交)
  • old
    new
    之间创建一个合并,记录
    new
    的树,如
    git checkout new和&git merge-s ours old
  • 使用
    git Merge master
  • 使用git push将结果更新到master。头:主控
  • 把结果推出来

  • 然后,不幸的是,那些将工作建立在您通过修改和强制推送而删除的提交上的人将看到结果合并,他们将看到您喜欢
    新的
    而不是
    旧的
    。他们以后的合并将不会看到由于您的修改而导致的
    旧的
    新的
    之间的冲突,因此他们不必遭受痛苦。

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

    不管怎么说,假设你没有试着用力推,那么“显而易见”的方法就是先拉。这会拉取您已修改(因此不再具有)的更改,以便您再次拥有它

    一旦解决了任何冲突,就可以再次推送

    因此:

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

    之后

    git push
    

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

    我已经解决了这个问题,放弃了我的本地修改提交,并在顶部添加了新的更改:

    # 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
    

    我也有同样的问题

    • 意外修改了已推送的最后一次提交
    • 在本地做了很多更改,提交了大约五次
    • 尝试推送,出现错误,惊慌失措,合并远程,获取大量非我的文件,推送,失败,等等
    作为一个Git新手,我认为它是完整的

    解决方案:有点像@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
    
    #在推送和修改的文件之前倒带提交。
    #替换为所需的哈希。
    #——软手段:离开
    
     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
    
    git reset --soft HEAD^
    git stash
    git push -f origin master
    git stash pop
    git commit -a
    git push origin master
    
    git push origin master -f
    
    git push origin master --force
    
    git push -f origin branch_name
    
    git pull origin branch_name