rebase的两种用法
你可能出现过对同一处代码进行多次处理的场景。这会导致如下提交记录:
$ git log --pretty=format:'%h: %s'
d2399da: feat: modify c
0134695: feat: modify b
eb63848: feat: modify b
51c0bca: feat: modify b
4cb600e: feat: modify a
d29f331: Initial commit
其实, 中间的对b的3次提交 完全可以合并成一次commit, 这个时候 rebase就很有用了。
git rebase -i 4cb600e
注意 git rebase -i [startPonit] [endPoint]
前开后闭 区间 这里的 [startPonit] 是指需要合并的commit的前一个commit (即当前示例中的 “4cb600e: feat: modify a”)。 因为, 三个commit肯定要基于上一个commit合并成了新的commit。谨慎使用[endPoint] 省略, 即默认表示从起始commit一直到最后一个,但是一旦你填写了, 则表示 [endPoint]后面的commit全部不要了!终端会进入选择交互界面, 让你进行变基选择操作:

说明

接下来会弹出第二个页面, 分别展示三个commit的提交信息

这里三个信息都是一样的, 我们选用第一个的提交信息, 将其余的全部注释掉,重复上述步骤, 保存退出即可

会发现原三个一样的提交现在合并成了一个新的commit。
| 命令 | 缩写 | 含义 |
|---|---|---|
| pick | p | 保留该commit |
| reword | r | 保留该commit,但需要修改该commit的注释 |
| edit | e | 保留该commit, 但我要停下来修改该提交(不仅仅修改注释) |
| squash | s | 将该commit合并到前一个commit |
| fixup | f | 将该commit合并到前一个commit,但不要保留该提交的注释信息 |
| exec | x | 执行shell命令 |
| drop | d | 丢弃该commit |
接下来, 我将用实际示例和场景, 来分析rebase是如何解决分叉合并的, 在此之前, 我先做如下规定:
a 、b、…等(a需求最早, b其次, 以此类推。)a 变基之后(hashId改变) 叫 a'
此时的合并有两点好处:
其实这种情况下, rebase和merge的效果是一样的。
请大家记住这个场景, 后面所有的rebase都是奔着这个目标来的。
develop 新增需求a: “feat: a”
feature 新增需求b: “feat: b”

会出现以下结果:


会出现以下结果:

# feature分支
git fetch origin
git rebase develop
# 或者 直接一个命令
git pull develop --rebase

会出现以下结果:
到这里, 你应该有所察觉了!: 没错! 这一步相当于 回到了场景1的模式, 我当前的feature相当于先把需求b 拎出来, 同步完最新的develop, 再把需求b放在了最后面。
所以, 接下来merge的时候 就很舒服了~!
# develop分支
git merge rebase_new


而这, 也是rebase为什么不会产生多余的commit记录的原因了。
注意! 不是commit ! 不是commit ! 不是commit !先引用官网上的一段话:
如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。
如果你遵循这条金科玉律,就不会出差错。 否则,人民群众会仇恨你,你的朋友和家人也会嘲笑你,唾弃你。
因为变基最强大也是最危险之处, 就在于, 它能改变原commit的hashId, 而一旦你对历史提交做出改变, 那么 从变基那个节点开始往后的所有节点的commit id 都会发生变化。 这对线上环境来说, 是不可控的!

如果feature在写完新需求b后, 切了新分支 feature_B, 然后又rebase了develop, 那么新分支feature_B无论是合进develop 还是 合进 feature 都会有冲突, 出现重复的b(其实是b和b’)


除非 你能百分百确保 你的分支已经完成新需求, rebase操作结束之后, 再切新分支, 这时 他们才是同步的。
首先, 自己的分支, 如果想对已经推送的commit进行修改, 可以在修改完后, 使用 git push -f 强行push并覆盖远程对应分支。
但是如果这些修改 已经被合到了其他分支(比如主分支), 那又会出现冲突, 因为其他分支保存的是你rebase之前 合进去的commit。

从变基那个节点开始往后的所有节点的commit id 都会发生变化。这个就不再赘述了。
所以可以想象一下, master上有100个commit, 你悄悄改了第50个commit, 那从50—100的所有commit全部改变了, 这时, 别人的分支合进来, 就会有51个冲突, 解决完冲突之后, 就会产生51*2个相同的提交记录, 恐怖如斯!
总的原则是,只对尚未推送或未分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式(rebase 和merge)带来的便利。
我正在学习Ruby,遇到了inject。我正处于理解它的风口浪尖,但当我是那种需要真实世界的例子来学习一些东西的人时。我遇到的最常见的例子是人们使用inject来添加一个(1..10)范围的总和,我不太关心这个。这是一个任意的例子。在实际程序中我会用它做什么?我正在学习,所以我可以继续使用Rails,但我不必有一个以Web为中心的示例。我只需要一些我可以全神贯注的目标。谢谢大家。 最佳答案 inject有时可以通过它的“其他”名称reduce更好地理解。它是一个对Enumerable进行操作(迭代一次)并返回单个值的函数。它有许多有
我在尝试使用Faraday将文件上传到网络服务时遇到问题。我的代码:conn=Faraday.new('http://myapi')do|f|f.request:multipartendpayload={:file=>Faraday::UploadIO.new('...','image/jpeg')}conn.post('/',payload)尝试发布后似乎没有任何反应。当我检查响应时this是我所看到的:#:post,:body=>#,#,@opts={}>,#],@index=0>>,#>],@ios=[#,#,@opts={}>,#],@index=0>,#],@index=0>
我使用raise(ConfigurationError.new(msg))引发错误我试着用rspec测试一下:expect{Base.configuration.username}.toraise_error(ConfigurationError,message)但这行不通。我该如何测试呢?目标是匹配message。 最佳答案 您可以使用正则表达式匹配错误消息:it{expect{Foo.bar}.toraise_error(NoMethodError,/private/)}这将检查NoMethodError是否由privateme
目录ChatGPT简介技术原理应用未来发展ChatGPT的10 种用法ChatGPT简介ChatGPT是一种基于深度学习的大型语言模型,由OpenAI公司开发。技术原理GPT是GenerativePre-trainedTransformer的缩写,意为生成式预训练变压器。它的技术原理是使用了一个基于注意力机制的变压器(Trans
我找不到任何使用Rack::Session::Cookie的简单示例,并且希望能够将信息存储在cookie中,并在以后的请求中访问它并让它过期.这些是我能找到的唯一示例:HowdoIset/getsessionvarsinaRackapp?http://rack.rubyforge.org/doc/classes/Rack/Session/Cookie.html这是我得到的:useRack::Session::Cookie,:key=>'rack.session',:domain=>'foo.com',:path=>'/',:expire_after=>2592000,:secret=
我是Ruby的新手,发现以下几对令人困惑示例同样有效:File.included_modulesFile::included_modulesFile.stat('mbox')#Returnsa'#'objectFile::stat('mbox')File.new("foo.txt","w")File::new("foo.txt","w")"asdf".size#Aninstancemethod"asdf"::size2+32::send(:+,3)#AnextremeexampleFile::new,尤其是我经常遇到的东西。我的问题:如果我永远避免使用::运算符来限定除类、模块和常量之
如果数组只包含一个值,我想返回数组的第一个元素。目前,我使用:vals.one??vals.first:vals.presence因此:vals=[];vals.one??vals.first:vals.presence#=>nilvals=[2];vals.one??vals.first:vals.presence#=>2vals=[2,'Z'];vals.one??vals.first:vals.presence#=>[2,"Z"]是否有内置的东西可以做到这一点,或者是否有更好的设计考虑?我的用例是特定的,涉及知道从方法(将实现上述代码)中期望什么的演示者。如果这些演示者将所有返回
moduleAdefself.funcputs"func"endend>>A.funcfunc>>A::funcfunc为什么.和::都存在?为什么不仅是.? 最佳答案 作用域解析运算符(::)可以解析常量、实例方法和类方法,因此只要我们在正确的位置查找,我们就可以将该运算符用于基本上任何方法。此外,由于方法“func”被定义为模块A的类方法(通过self.func,类似于“静态”方法)它直接属于模块(即本身是一个对象)所以它可以用点运算符调用,模块作为接收者。请注意,模块A的实例对“func”没有任何可见性,因为它是一个类方法:a
在SOquestion2068165一个答案提出了使用这样的东西的想法:params[:task][:completed_at]&&=Time.parse(params[:task][:completed_at])作为DRYer的说法params[:task][:completed_at]=Time.parse(params[:task][:completed_at])ifparams[:task][:completed_at]paramsHash将来自(Rails/ActionView)表单。这是众所周知的||=习语的一种推论,如果LHS不是nil/false则设置值。像这样使用&&
我在这里冒着手掌到额头的风险,但我不太清楚如何使用Rails的ActiveRecord糖来做到这一点。我有一个tickets表,它有两列(submitter_id和assignee_id),每列都应该引用来自的不同用户users表(特别是users表中的id列)。我希望能够使用ActiveRecord的关联来执行诸如ticket.submitter.name和ticket.assignee.email之类的事情。提交者和受让人只是不同关联名称下的用户对象。我发现的唯一接近我正在做的事情是使用多态关联,但最后我相当确定这不是我真正需要的。我不会有多种类型,提交者和受让人都是用户,很可能是