我有一个分支应该对其他贡献者可用,并且应该始终保持与主分支最新。
不幸的是,每次我使用 'git rebase' 然后尝试推送时,都会出现“非快速向前”(non-fast forward)消息并中止推送。唯一的方法是使用 --force 强制推送。这是否意味着如果我的分支已经发布并且其他人正在上面工作,我应该使用 'git merge' 而不是 rebase?
关于 git 工作原理的一些说明(非技术性):
当你进行变基操作时,git 会将涉及到的提交重新提交在一个干净的历史记录顶部。这样做是为了防止历史记录出现:
Description: tree -> mywork -> merge -> mywork -> merge -> mywork -> merge
Commit SHA1: aaaa -> bbbb -> cccc -> dddd -> eeee -> ffff -> gggg
在 rebase 后,可能看起来像这样(或类似):
Description: tree -> rebase
Commit SHA1: aaaa -> hhhh
问题在于你正在尝试推送的新提交不是你要推送到的分支顶部提交的子代。
现在,你知道提交中包含相同的信息,但git负责不仅覆盖那些已存在的提交(如上面的bbbb-gggg)。
共享仓库模型
如果你正在使用一个共享的仓库,那么像这样的事情可能会变得非常混乱。让我解释一下为什么。假设另一个开发者拉取了该分支,并在他们的分支中拥有aaaa -> gggg提交。然后他们创建了一个提交iiii。
同时,您进行了变基并强制推送,导致树看起来像这样:
Description: tree -> rebase
Commit SHA1: aaaa -> hhhh
当另一个开发者尝试推送时,会收到一个“非快进”的消息。当他进行合并时,两个历史记录将被重新链接在一起,并且你最终会得到一个混乱的结果。
类似这样(混乱):
Description: tree -> rebase -> mywork -> merge -> mywork -> merge -> mywork -> merge -> devwork -> merge
Commit SHA1: aaaa -> hhhh -> bbbb -> cccc -> dddd -> eeee -> ffff -> gggg -> iiii -> jjjj
换句话说,如果其他人正在推送和拉取,最好使用git merge,或者在重置之后避免push(并且仅重置您的工作)。
公开可见的仓库模型
也许你正在使用一个不同的(更符合git的)模型,你只想让人们从你的仓库中拉取。在这种情况下,git push --force 不太糟糕,因为然后他们可以处理跟进。他们可以将他们的更改重新基于您的更改,然后将他们的补丁提交给您。它可以防止您的仓库出现混乱。
但是,也许还有更好的方法。git push --mirror
来自 http://www.kernel.org/pub/software/scm/git/docs/git-push.html
不需要命名每个要推送的引用,只需指定$GIT_DIR/refs/(其中包括但不限于refs/heads/、refs/remotes/和refs/tags/)下的所有引用都被镜像到远程仓库。本地新创建的引用将被推送到远程端,本地更新的引用将在远程端强制更新,并且已删除的引用将从远程端删除。如果设置了配置选项remote..mirror,则这是默认设置。
Git的一个伟大之处在于它非常灵活,可以支持许多不同的工作流程。但是,它真正的优势在于它是分布式的模型,因此我认为最有收益的方法是使用它。
git fetch
和git rebase origin/master
命令,将本地分支和中央(master)分支上的冲突解决后,只推送向前移动的纯净提交。使用git pull --rebase
也有类似的工作流程。这是一种强大的选项,但需要小心使用,因为对错误的内容进行rebase可能会重写已经在origin/master中的提交。例如,除非其他分支已经在当前的origin/master上进行了rebase操作,否则不要对其进行rebase。 - Kzqai