我面对使用Git分支问题。我发PR合并开发分支到主分支,但它包含不必要的提交。我想从公关删除这些。
我不得不创建从主关注的分支。这是我的错误:(
───M1───M2───M3───S────M4 (master)
└────D1───D2───┘ (develop)
└────F1───F2 (feature)
我怎么只包括F1和F2承诺除了D1和D2?
Rene's answer是正确的,但所有这些略显花哨的(采用箱字符集 - )图是有点过了,开始用自己的:
───M1───M2───M3───S────M4 (master) └────D1───D2───┘ (develop) └────F1───F2 (feature)
原因是这样的:
...我合并的开发分支使用“南瓜和合并”的主人。
在clicky图形用户界面的命令行上的“南瓜和合并”按钮,或git merge --squash
,使得一个新的承诺,是不是合并。代替:
...--M1--M2--M3--S--M4 <-- master
\ /
D1-----D2 <-- develop
你实际得到的是:
...--M1--M2--M3--S--M4 <-- master
\
D1--D2 <-- develop
有S
和任何D
s之间没有祖先/后代关系,也没有任何M
但M1
和任何D
s之间。这正是出游好以后的Git操作。如果你做一个实际的使用合并平原git merge
,或git merge --no-ff
,或非熟透的GitHub clicky按钮,然后S
(因此M4
以及)将D1
和D2
的后裔。
但是,这不是我们所拥有的。所以,当我们看feature
和master
,我们看到:
...--M1--M2--M3--S--M4 <-- master
\
D1--D2--F1--F2 <-- feature
我们看到,feature
有四个提交其尖端到达提交(包括端提交自身)不是来自master
,即D1-D2-F1-F1
到达。不管是不是有一些名字指向D2
,这四个提交是四个是在feature
是不是也master
。 (提交M1
是两个分支机构,是一切的离开了。)
我想,想到了一个很好的办法就是“南瓜合并”具有杀死刚合并分支的副作用。提交D1
和D2
现在,实际上,“死”的,必须考虑至少轻微放射性。作为Ahmad Khundaqji said,他们往往会在年底无害。但是,他们可以让你的提交历史看起来很丑陋,在为什么这个会两次,一次是作为两个独立的提交,后来成为一个更大的吗?如果feature
实际上,合并,而不是squash-“合并” - 和在最坏的情况,他们可以在以后会引起冲突,由于一些变化的承诺是S
的后裔。
由于合并后的分支现在是“死的”,它应该被删除。也就是说,你应该运行git branch -D develop
。但在此之前,请务必提交D1
和D2
是不包含在任何其他部门,这当然,你的情况,他们是自己。如果它们包含在其他部门,则必须按照变种不再有这两个提交重建这些分支。
请注意,“重订和合并”(在GitHub上,实际上这三个组合成一个内部下拉一个按钮,另一clicky按钮,但是这仅仅是表达三种不同按键的方式),还具有杀死分支的副作用,因为底垫真正意义的老提交复制到新的,然后停止支持新副本的使用旧的提交。
我谨提请后git rebase --onto master develop feature
图这种方式,保持“死” develop
中的图片:
F1'-F2' <-- feature
/
...--M1--M2--M3--S--M4 <-- master
\
D1--D2 <-- develop
\
F1--F2 [abandoned]
这使得它更清晰的是F1
和F2
下其独特的提交哈希标识依然存在。他们只是不再容易找到,因为没有名字,我们可以用它来找到them.1从名字feature
开始,我们先找到补发F2'
,我们是用的,而不是F2
,然后F1'
,我们应该使用地方F1
,那么M4
,然后S
,等等,倒退到过去。 Git命令状git log
不会发现我们已经闪亮新的,从F2'
而不是从M1
下降取代了旧沉闷的提交。
(而且,现在它是安全的删除develop
,只要没有其他分支还包括D1
。需要注意的是,包括D2
自动包括D1
所以这就是我们要在这里提到的唯一一个。)
在长篇git rebase --onto master develop feature
命令,我们有三个有趣的论点(加上选项当然关键字--onto
)。从年底开始和向后工作,因为Git是wont做,我们有:
feature
作为一个额外的参数,它the git rebase
documentation调用[<branch>]
:告诉git rebase
做git checkout feature
启动。如果你这样做你自己,你可以在最后一个参数离开了。这真的只是传递给git checkout
,2所以它应该永远是一个分支名称。develop
作为git rebase
文档所说[<upstream>]
:告诉git rebase
其承诺不会复制。如果忽略此参数,Git使用任何被配置为目标(或电流)分支的上游。这个名字是通过git rev-parse
通过,因此它几乎可以为任何:生哈希ID,标签名,git describe
输出,分支机构的名称,如HEAD~2
相对操作,等等。--onto master
作为git rebase
文档所说<newbase>
:告诉git rebase
放在哪里提交复印件,并最终引导它在哪里重新点的分支,一旦复制完成。如果你离开了这一点,它默认为<upstream>
,像<upstream>
它是通过git rev-parse
通过。所以这个命令行git rebase
命令的意思是:
检查出
feature
后,复制所有提交从分支的末端到达,排除也可到达从呈交由develop
确定任何承诺,也不包括任何其他提交你,git rebase
,觉得有必要omit.3做副本正确的拓扑排序的顺序,以便早期,依赖较少的提交首先复制,后来,更多的依赖提交稍后复制。将每个副本使得第一拷贝自带提交后立即提交由master
标识。当你复制的最后一次提交,猛拉分支名feature
周围,使其指向最后复制的提交,或者如果没有提交被复制,直接将提交由master
标识。
当Git的完成这样做,你最终提交看起来我们吸引他们的方式。 (你也分支feature
,除非Git的人有固定的我认为在一个小错误git rebase
,好像如果你告诉衍合做git checkout feature
开始,但你,比如说,master
,它应该离开你关于到底master
,而不是feature
。当然,如果底垫必须停止与冲突,它将停止在“分离的头”模式,但是当你git rebase --continue
或git rebase --abort
继续或终止操作,它最终应该把你回来你在哪里,即使这不是feature
。)
1还有是通过它可以发现,原来F2
和F1
,存储在Git的reflogs名字。任何引用名的引用日志,包括那些分支名称,包含日志,其中承诺确定了分支名,通过哈希值来标识,因为一些特定的时间戳的。每次更新一个引用,通过git update-ref refs/heads/feature
例如做,一直在引用日志的前值,并与时新价值刚刚写入的时间戳(和引用日志消息,作为对正在发生的事情)增加了新的价值。
运行git reflog feature
看到了refs/heads/feature
的引用日志条目。没有为HEAD
本身的附加引用日志。运行git reflog
或git reflog HEAD
看到一个。需要注意的是旧的条目最终到期;更多关于这一点,看看git reflog expire
子命令和the git reflog
documentation。
需要注意的是git reflog show
,这是你使用的子命令在这里,真的只是运行git log -g
,所以你可以在这里改用git log -g
的git reflog
。
删除任何分支删除其引用日志,但在HEAD
引用日志条目保持。有计划,来保存从删除分支reflogs在将来的某个Git版本中能够“不删除”的一个分支服务,但这些计划还没有茸毛而散尚未,并有实现的一些问题。
2AT一点字面上这里的词是从字面上正确的,因为git rebase
是一个很大的shell脚本。但现在git rebase
许多地方是用C写的git checkout
命令也用C写的,当你建立Git,那么建立一个分享一些后端实现代码的二进制文件。如果git rebase
是调用相同的后端代码否则,单独git checkout
二进制的C代码,是从字面上叫git checkout
,或者是现在比喻?哪些词字面这里的正确的语义?如果字面只需要匹配的前端和后端,或匹配后端?
3The承诺是git rebase
忽略自身有:
git rebase
将根据需要重新进行合并。这些模式是旧--preserve-merges
和新奇的,改进的--rebase-merges
;两者都是棘手,我不会试图在这里描述它们。<upstream>..HEAD
复制的底垫文档会谈,它实际上使用<upstream>...HEAD
找到两套提交的对称差:从HEAD
那些可到达,但不是从上游的说法,而那些到达距离上游参数而不是从HEAD
。最后这部分采用git rev-list --left-right
命令的区分哪个“方”这样的提交来自能力:可复制的提交是从HEAD
右可达但不能从<upstream>
。然而,在这个对称差的左侧的是那些“过去的分界点”,但到达从<upstream>
。在这种特殊情况下,这些提交都会被S
本身M4
。所以Git的计算补丁ID为这两个提交,使用git patch-id
。它还计算补丁ID对每个考生的复制,在这种情况下F1
和F2
。如果任一复制候选人的修补程序ID匹配的任何的另一半,Git的结论,他们必须已樱桃采摘到<upstream>
,应该在复制过程中被省略。
这个结论通常是正确的,但在某些情况下,它可能是错的!它总是以测试的任何Git的自动化操作的结果是一个好主意。出了问题的方法是,例如,如果一个人本身承诺修复线路上的杂散}
,并且对上游系列独占一行的另一杂散}
。这两个修补程序是在不同的源极线,并且可以具有不同的缩进为好,但以git patch-id
,它们是相同的变化,作为补丁ID通过去除行号和一些白空间的构成。
因为你做了南瓜,你的第一个PR合并,Git不会知道,D1和D2已经包含在主分支。
您需要将特性分支rebase --onto
到(最新)提交主分支:
git checkout feature
git rebase develop --onto master
其结果将是这样的:
───M1───M2───M3───S────────────M4 (master)
└────D1───D2──┘ (develop) └────F1───F2 (feature)
现在,您可以push --force
的特性分支,并更新你的PR。或关闭旧PR,并创建一个新的与当前的特性分支。
BTW:从你的分支名称我假设你使用的是一种GitFlow分支模式。在这种模式下,你不应该合并develop分支与壁球合并主,因为你总是有已经合并提交这个问题。
只要D1,D2的变化已经被合并到主会有通过新的拉动请求重新发送它们在没有问题的(D1,D2不会考虑改变)
但是,你在你的情况需要衍合与M1开发分公司提交,这样你的PR与一切更新,GIT检测F1和F2,因为只有新的东西。
最简单的方法,就是从主创建一个PR开发,并将其合并在拔出后更新。
问PR的作者(在你的仓库或分支目标)来创建最新的主的另一个分支
作者必须采摘樱桃的提交要求,如果需要做南瓜和承诺
作者将一个新的PR