假设我们在Git中遇到以下情况。
1.一个已创建的仓库。
mkdir GitTest2
cd GitTest2
git init
2.在主目录中进行一些修改并提交。
echo "On Master" > file
git commit -a -m "初始提交"
2.Feature1从主站分支出来,一些工作已经完成。
git branch feature1
git checkout feature1
echo "Feature1" > featureFile
git commit -a -m "Commit for feature1"
3.同时,在主代码中发现了一个bug,建立了一个hotfix-branch
git checkout master
git branch hotfix1
git checkout hotfix1
5.该bug在hotfix分支中被修复,并被合并到主干分支中(可能是经过拉取请求/代码审查)。
echo "Bugfix" > bugfixFile
git commit -a -m "Bugfix Commit"
git checkout master
git merge --no-ff hotfix1
6.功能1的开发继续进行。
git checkout feature1
假设我需要在特性分支中进行热修复,也许是因为该错误也发生在那里。如何才能在不重复提交功能分支的情况下实现这一目标?
我想避免在我的特性分支上得到两个与特性实现无关的新提交。如果我使用拉取请求,这对我来说尤其重要。所有这些提交都将包含在拉取请求中,并需要进行审查,尽管这已经完成了(因为 hotfix 已经在 master 中)。
我不能做git merge master --ff-only
:"fatal: Not possible to fast-forward, aborting.",但我不确定这是否对我有帮助。
我们如何将主干分支合并到特性分支?很简单。
git checkout feature1
git merge master
在这里强行进行快进合并是没有意义的,因为这是不可能的。你同时提交了特性分支和主干分支。现在快进是不可能的了。
请看看 GitFlow。这是一个可以遵循的 git 分支模型,而且你已经不自觉地做到了。它也是Git的一个扩展,为新的工作流程步骤增加了一些命令,可以自动做一些本来需要手动做的事情。
那么你在工作流程中做对了什么?你有两个分支要处理,你的feature1分支基本上是GitFlow模型中的"开发"分支。
你从 master 分支创建了一个 hotfix 分支,并将其合并回来。现在你被卡住了。
GitFlow 模型要求你把 hotfix 合并到开发分支,也就是你的 "feature1"。
所以真正的答案是。
git checkout feature1
git merge --no-ff hotfix1
这将把热修复中的所有修改添加到特性分支中,但仅*这些修改。它们可能会与该分支中的其他开发变更冲突,但如果你最终将特性分支合并到主干分支,它们就不会与主干分支冲突。
重置时要非常小心。只有当你所做的修改停留在你的版本库中,例如你没有推送任何分支到其他版本库时,才可以进行重放。重载是一个很好的工具,可以在推送之前将本地提交的内容安排成一个有用的顺序,但之后的重载对于像你这样的git初学者来说会把事情弄得一团糟。
你应该可以把你的分支重新放在主干上。
git checkout feature1
git rebase master
管理所有出现的冲突。当你到了有bugfixes的提交(已经在master中)时,Git会说没有改动,也许已经应用了。然后你继续重写(同时跳过已经在master中的提交),用
git rebase --skip
如果你在特性分支上执行git log
,你会看到bugfix提交只出现一次,而且是在master部分。
关于更详细的讨论,请看Git书中关于git rebase
的文档(https://git-scm.com/docs/git-rebase),其中涵盖了这个确切的用例。
================ 编辑更多内容 ====================
这个答案是专门针对@theomega的问题提供的,考虑到了他的特殊情况。请注意这一部分。
我想防止在我的特性分支上出现与特性实现无关的[...]提交。
将他的私有分支重新发布到 master 上,恰恰会产生这样的结果。相反,将 master 合并到他的分支中,恰恰是他***特别不希望发生的事情:通过他的分支增加一个与他正在进行的特性实现无关的提交。
对于那些阅读了问题标题,跳过问题的实际内容和背景,然后只盲目地阅读顶部的答案,认为它总是适用于他们(不同的)用例的用户,请允许我详细说明一下。
git merge master
)。最后,如果你对这个答案并不适合你的情况感到不满,尽管它对@theomega来说是最适合的,在下面添加评论也不会有什么帮助。我不能控制哪个答案被选中,只有@theomega可以。
齐米'的回答][1]大致描述了这个过程。 下面是具体内容。
master
的,这样它就会包含最近的热补丁。git checkout master git branch feature1_new git checkout feature1_new
git checkout -b feature1_new master。
git merge feature1
完成! 现在使用新分支继续开发你的功能。
[1]: https://stackoverflow.com/questions/16955980/git-merge-master-into-feature-branch/24122211#24122211
这里有一个脚本,你可以用它来将你的主分支合并到你当前的分支。
这个脚本的操作如下。
将这段代码保存为一个批处理文件(.bat),并将该脚本放在你的仓库中的任何地方。 然后点击它来运行它,你就可以了。
:: This batch file pulls current master and merges into current branch
@echo off
:: Option to use the batch file outside the repo and pass the repo path as an arg
set repoPath=%1
cd %repoPath%
FOR /F "tokens=*" %%g IN ('git rev-parse --abbrev-ref HEAD') do (SET currentBranch=%%g)
echo current branch is %currentBranch%
echo switching to master
git checkout master
echo.
echo pulling origin master
git pull origin master
echo.
echo switching back to %currentBranch%
git checkout %currentBranch%
echo.
echo attemting merge master into %currentBranch%
git merge master
echo.
echo script finished successfully
PAUSE
你也许可以做一个"cherry-pick",把你需要的*确切的提交拉到你的特性分支中。
做一个 git checkout hotfix1
来获取hotfix1分支。然后做git log
,得到相关提交的SHA-1哈希值(随机字母和数字的大序列,唯一标识一个提交)。复制它(或前10个左右的字符)。
然后,git checkout feature1
,回到你的特性分支上。
然后,git cherry-pick <你刚刚复制的SHA-1哈希值>
。
这将会把那个提交,而且*只有那个提交,拉到你的特性分支。这个改动会出现在该分支中--你只是"cherry-pick"了它。然后,继续工作,编辑、提交、推送,等等,尽情享受。
当你最终从一个分支合并到你的特性分支时(反之亦然),Git会意识到你已经合并了那个特定的提交,知道它不需要再次提交,并直接跳过它。