git rebase后无法push问题详解 -- 20180124

本文讨论了在Git中使用rebase后的推送问题,特别是当尝试推送已修改历史的分支时遇到的问题及解决方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

stackoverflow上的一个帖子,楼主和后面的回答都详细到位,很好的解释了这个问题

总结git rebase:这是一个 更改历史 的操作,所以不要指望你改了历史然后就顺利把你篡改够的历史提交上去。

 

PS:pro git 上的一句话:

“永远不要衍合那些已经推送到公共仓库的更新。
如果你遵循这条金科玉律,就不会出差错。否则,人民群众会仇恨你,你的朋友和家人也
会嘲笑你,唾弃你。”      看到这句话你大概就知道该怎么用了。至少不会用坏。

 

http://stackoverflow.com/questions/8939977/git-push-rejected-after-feature-branch-rebase

 

1楼

 

OK, I thought this was a simple git scenario, what am I missing?

I have a master branch and a feature branch. I do some work on master, some on feature, and then some more on master. I end up with something like this (lexicographic order implies order of commits):

A--B--C------F--G
       \    
        D--E

I have no problem to git push origin master to keep the remote master updated, nor with git push origin feature (when on feature) in order to maintain a remote backup for my featurework. Up until now, we're good.

But now I wanna rebase feature on top of the F--G commits on master, so I git co featureand git rebase master. Still good. Now we have:

A--B--C------F--G
                 \
                  D--E

(yeah, I know, it's actually D' and E'.)

Problem: the moment I want to backup the new rebased feature branched with git push origin featurethe push is rejected since the tree has changed due to the rebasing. This can only be solved with git push --force origin feature.

I hate using --force without being sure I need it. So, do I need it? Does the rebasing necessarilyimply that the next push should be --forceful?

This feature branch is not shared with any other devs, so I have no problem de facto with the forced push, I'm not gonna lose any data, the question is more conceptual.

 

 

2楼

 

 

The problem is that git push assumes that remote branch can be fast-forwarded to your local branch, that is that all the difference between local and remote branches is in local having some new commits at the end like that:

Z--X--R         <- origin/some-branch (can be fast-forwarded to Y commit)
       \        
        T--Y    <- some-branch

When you perform git rebase commits D and E are applied to new base and new commits are created. That means after rebase you have smth like that:

A--B--C------F--G--D'--E'   <- feature-branch
       \  
        D--E                <- origin/feature-branch

In that situation remote branch can't be fast-forwarded to local. Though, theoretically local branch can be merged into remote (obviously you don't need it in that case), but as git push performs only fast-forward merges it throws and error.

And what --force option does is just ignoring state of remote branch and setting it to the commit you're pushing into it. So git push --force origin feature-branch simply overridesorigin/feature-branch with local feature-branch.

In my opinion, rebasing feature branches on master and force-pushing them back to remote repository is ok as long as you're the only one who works on that branch.

 

3楼

 

One solution to this is to do what msysGit's rebasing merge script does - after the rebase, merge in the old head of feature with -s ours. You end up with the commit graph:

A--B--C------F--G (master)
       \         \
        \         D'--E' (feature)
         \           /
          \       --
           \    /
            D--E (old-feature)

... and your push of feature will be a fast-forward.

In other words, you can do:

git checkout feature
git branch old-feature
git rebase master
git merge -s ours old-feature
git push origin feature

(Not tested, but I think that's right...)

4楼

 

 

What is wrong with a git merge master on the feature branch? This will preserve the work you had, while keeping it separate from the mainline branch.

A--B--C------F--G
       \         \
        D--E------H

Edit: Ah sorry did not read your problem statement. You will need force as you performed a rebase. All commands that modify the history will need the --force argument. This is a failsafe to prevent you from losing work (the old D and E would be lost).

So you performed a git rebase which made the tree look like (although partially hidden as D andE are no longer in a named branch):

A--B--C------F--G
       \         \
        D--E      D'--E'

So, when trying to push your new feature branch (with D' and E' in it), you would lose D and E.

5楼

 

 

Other's have answered your question. If you rebase a branch you will need to force to push that branch.

Rebase and a shared repository generally do not get along. This is rewriting history. If others are using that branch or have branched from that branch then rebase will be quite unpleasant.

In general, rebase works well for local branch management. Remote branch management works best with explicit merges (--no-ff).

We also avoid merging master into a feature branch. Instead we rebase to master but with a new branch name (e.g adding a version suffix). This avoids the problem of rebasing in the shared repository.

 

原文链接:http://blog.youkuaiyun.com/bigmarco/article/details/7842642

<think>首先,用户的问题是关于理解gitrebasegitmerge的区别及使用方法。我需要基于提供的引用来构建回答。回顾系统级指令:-所有行内数学表达式必须使用$...$格式,但在这个上下文中,没有数学表达式,所以我可以忽略这个。-独立公式必须使用$$...$$格式并单独成段,同样,这里没有数学内容。-LaTeX语法正确:不适用。-使用中文回答:整个回答必须是中文。-生成相关问题:在回答结束时,生成相关问题-引用的段落末尾自然地添加引用标识:例如[^1]。用户可见层:-回答结构清晰,帮助用户逐步解决问题-尽量保证回答真实可靠。-参考站内引用:引用[1]、[^2]、[^3]提供了相关信息。用户的问题:我想理解gitrebasegitmerge的区别及使用方法。请问gitrebasegitmerge命令详解及区别。关键点:-解释gitrebasegitmerge的区别。-提供命令的详解和使用方法。-使用引用内容来支持回答。从引用中提取关键信息:-引用[1]:gitrebase命令格式,如gitrebase[-i|--interactive][options][--onto<newbase>][<upstream>],以及gitrebase--continue|--skip|--abort。还提到交互式变基可以修改提交信息。-引用[2]:gitmerge和gitrebase的区别。merge保留完整提交历史,清晰地显示分支更改和合并点;rebase创建清洁、线性的提交历史。选择取决于需求和团队工作流程:merge适合保留历史,rebase适合保持线性历史。-引用[3]:提供操作实例,如gitrebase-imain来启动交互式变基,修改提交信息等。总结:merge适合多人协作项目,rebase适合个人开发分支更新。结构化回答:1.**介绍**:简要说明gitrebasegitmerge的目的。2.**命令详解**:分别解释gitmerge和gitrebase的用法,包括常见命令格式和示例。3.**区别对比**:详细比较两者的不同之处,如历史记录、冲突处理等。4.**使用场景**:建议何时使用merge,何时使用rebase。5.**总结**:概括关键点。6.**相关问题**:在末尾生成相关问题。确保回答清晰、逐步:-使用中文。-自然地添加引用标识。-生成相关问题。相关问题生成:-基于主题,如进阶用法、常见问题、最佳实践等。最终回答结构:-开头:直接回答用户问题-主体:-gitmerge详解-gitrebase详解-区别-使用建议-结尾:总结和生成相关问题。添加引用:-在引用内容末尾添加[^1]、[^2]、[^3]。确保自然地融入文本。例如:-根据引用[2],gitmerge保留了完整的提交历史...[^2]。生成相关问题-例如:1.如何解决gitrebase过程中的冲突?2.gitrebasegitmerge的性能比较?3.在团队协作中如何选择rebase或merge?</think>### Git RebaseGit Merge 的区别及使用方法详解 Git 是版本控制的核心工具,其中 `git merge` 和 `git rebase` 都是用于整合分支更改的命令,但它们的工作方式、历史记录影响和适用场景有显著区别。以下我将逐步解释两者的命令详解、核心区别及使用方法,帮助您清晰理解。内容基于可靠的 Git 文档和实践经验,并结合站内引用信息进行说明。 --- #### 1. **Git Merge 命令详解** - **什么是 Git Merge?** `git merge` 用于将两个分支的更改合并到一起,创建一个新的“合并提交”(merge commit)。它会保留两个分支的完整历史记录,显示分支的起源和合并点。 - **基本命令格式**: ```bash git merge <branch-name> # 将指定分支合并到当前分支 ``` 例如,将 `feature` 分支合并到 `main` 分支: ```bash git checkout main # 切换到目标分支 git merge feature # 合并 feature 分支 ``` 如果遇到冲突,Git 会提示手动解决,然后使用 `git commit` 完成合并。 - **优点**: - 保留分支的完整历史,便于追踪更改来源和协作上下文。 - 适合多人协作项目,因为它清晰地显示每个分支的更改和合并点[^2]。 - **缺点**: - 历史记录可能变得杂乱(例如,出现多个合并点),影响可读性。 --- #### 2. **Git Rebase 命令详解** - **什么是 Git Rebase?** `git rebase` 用于将一个分支的提交“重放”到另一个分支上,从而创建线性、整洁的提交历史。它不是创建合并提交,而是将提交序列重新应用到目标分支的顶部。 - **基本命令格式**: ```bash git rebase <base-branch> # 将当前分支重放到基础分支上 ``` 例如,将 `feature` 分支的提交重放到 `main` 分支: ```bash git checkout feature # 切换到要变基的分支 git rebase main # 将 feature 的提交重放到 main 分支上 ``` 变基后,使用 `git merge` 或 `git push` 完成整合。 - **交互式模式(Interactive Rebase)**: 可以修改提交历史,例如编辑提交信息、合并提交或删除提交。 命令格式: ```bash git rebase -i <commit-id> # 启动交互式变基 ``` 示例: ```bash git rebase -i main # 变基到 main 分支,并打开编辑器 # 在编辑器中,将 'pick' 改为 'edit' 以修改特定提交 git commit --amend # 修改提交信息 git rebase --continue # 继续变基过程 ``` 如果冲突,使用 `git rebase --abort` 中止或 `git rebase --skip` 跳过当前提交[^1][^3]。 - **优点**: - 创建线性、整洁的历史记录,便于代码审查和调试。 - 适合个人开发分支的更新,或需要保持提交历史简洁的场景[^3]。 - **缺点**: - 变基会重写提交历史,可能导致协作冲突(例如,推送后他人需要强制拉取)。 - 冲突处理更复杂,因为每个提交都可能需要单独解决。 --- #### 3. **Git RebaseGit Merge 的核心区别** 下表总结了关键差异,帮助您一目了然: | 特性 | Git Merge | Git Rebase | |------|-----------|------------| | **历史记录** | 保留分支的完整历史,生成合并提交(merge commit),显示分支点[^2]。 | 创建线性历史,将提交“重放”到目标分支,不产生合并提交[^3]。 | | **冲突处理** | 冲突在合并时一次性解决,通过 `git commit` 完成。 | 冲突在变基过程中逐提交解决,使用 `git rebase --continue` 继续[^1]。 | | **适用场景** | 多人协作项目,需要追踪分支来源(如团队开发)[^2]。 | 个人分支维护、代码整理,或需要简洁历史(如开源贡献)[^3]。 | | **风险** | 历史可能杂乱,但安全(不重写历史)。 | 历史被重写,可能导致协作问题(需谨慎使用 `git push --force`)。 | | **性能** | 高效处理大型分支合并,但历史增长快。 | 历史更紧凑,但变基过程可能耗时(尤其交互模式)。 | - **关键区别总结**: - **历史线性 vs 分支性**:`git rebase` 产生直线历史(如 `A -> B -> C`),而 `git merge` 产生分支历史(如 `A -> B (merge) -> C`)。 - **工作流影响**:在团队中,`git merge` 更安全,因为它避免历史重写;`git rebase` 更适合本地分支整理,以保持提交清洁[^2][^3]。 - **冲突处理**:`git merge` 在合并点一次性处理冲突;`git rebase` 在每次提交重放时可能触发冲突,需逐步解决[^1]。 --- #### 4. **使用建议:何时选择 Merge 或 Rebase?** - **选择 `git merge` 的情况**: - 团队协作环境中,需要保留所有更改记录和合并点。 - 当分支历史复杂时(例如,长期存在的特性分支),避免历史重写风险。 - 引用[^2]强调:如果您希望保留完整的提交历史,清晰地显示每个分支的更改,那么 `git merge` 是更好的选择。 - **选择 `git rebase` 的情况**: - 个人开发分支,需要将本地更改同步到主分支时(例如,`git pull --rebase`)。 - 整理提交历史(如合并多个小提交或修改提交信息)。 - 引用[^3]指出:如果您倾向于保持一个清洁、线性的提交历史,并且团队成员对解决冲突感到舒适,那么可以选择 `git rebase`。 - **最佳实践**: - 在推送分支到远程仓库前使用 `git rebase` 整理历史,避免影响他人。 - 协作时优先用 `git merge`,确保历史可追溯。 - 交互式变基(`git rebase -i`)适合高级用户修改历史,但需备份代码以防意外[^1][^3]。 --- #### 总结 `git merge` 和 `git rebase` 都是强大的分支整合工具:`merge` 注重历史完整性和协作安全,`rebase` 追求历史简洁性和本地效率。选择取决于您的需求:团队项目多用 `merge`,个人分支多用 `rebase`。记住,变基会重写历史,使用前务必理解风险。通过实践和解决冲突,您能更灵活地应用这些命令[^2][^3]。 如果您有具体场景或问题,欢迎进一步描述,我会提供针对性建议。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值