这篇博客没有图….(当然不是因为我懒, 而是因为这个编辑器不支持直接粘贴拖拽, 哼,下次我来写一个 !)
前:
使用git或用eclipse中的Egit时, 拉取分支或合并提交时常常会看到rebase和merge这两个哥们 ?
其实他们是双胞胎, 干的都是合并分支的事.
注:
(1)本文所有的 ,敲黑板, 是所有的git代码中, origin是远程库的名字.什么? 远程库是啥? 我怎么知道,别闹.
不过看你骨骼惊奇, 我这里还有一篇博客你可以带回趁没人时拿出来翻翻.
http://blog.youkuaiyun.com/yellowsun_a/article/details/78009197
要是敢在上厕所时看那……那你真是个爱学习的好孩子, 在厕所待着不看完别出来了-_^
(2) fast–forward, 这是git的一个非常厉害(?)的特性,
它叫做快速推进, 因为某种原因(测试, buginx), 你需要一个临时分支(用完就扔的那种), 然后你在远程库remote tracked repo的master分支上创建了一个分支dev, 然后再这个dev分支上进行工作. 噼里啪啦一顿操作…. 你这个临时分支办完事了要提交, 灰常幸运的是,这个过程中没有人往master分支提交或修改任何东西, 这个时候 你一个merge, 就直接上去了.这个时候你在dev分支上新做的提交就直接上去了, 这个时候再把dev分支删了, 我跟你赌我全部身家再没有人知道这个dev分支存在过.
我全部身家就这几篇博客了….
当然也有方法让你能看到这个分支,下回分解.
正:
merge
先说merge吧, 可能是因为这个是弟弟?
merge有两种命令形式:
$ git merge origin
这种无脑合并的最喜欢了, 简单粗暴.
就是将你现在的local branch 和远程跟踪库remote tracked repo合并, 并形成一个的commit(也就是一个true merge).
假设在本地拉取后, 这两个分支(origin, mywork)各自往前走了几个提交吧.
然后就分叉了, 这个时候merge就是这样
$ git lg
通过上面这条命令(lg是alias哦), 你会看到你的历史记录就有两条灰常难看的线(又称分叉). 这就很难受,尿分叉不知道有没有这么难受…
什么? 为什么难看?
因为你可能完全就是同一个分支为什么要两条线来污染历史图谱呢? 我需要一个干净的提交历史啊!
那个谁say过一句鹦哥绿洗:
it is not only useless but downright counter-productive for this branch to remain visible in the history graph, as an identifiable “railroad switch.”
如果你不是这种情况, 那请继续你的操作.
$ git merge origin --no-ff
这种就是为了保存那种 注 里面的第(2)种情况的分支dev, 以这种方式merge出来的提交历史还是会有你的dev分支存在的.
总结: 除非在你创建分支和提交分支之间没有人动过你的远程分支(一般是不可能的), 否则你以merge方式提交都会有历史遗留痕迹.
使用技巧:
1:如果是你的私人分支, 可以随意改动的,而且只是临时分支, 直接merge就好.
$ git rebase -i dev #处理你的分支dev上的提交
$ git merge origin
2:如果是很重要的分支(如修改bug分支buginx), 但又可能会因为fast-forward特性导致合并后在主分支上丢失该分支记录,使用 –no-ff强制关闭该特性.
$ git merge origin --no-ff
rebase
rebase, 我百度了一下, 是变基的意思.
没错, rebase就是可以把分支的祖先强行改变
$ git rebase origin master
可以把master分支自上次拉取或上次提交后做的提交, 全部拿出来在origin上重新跑(run)一遍, 你的master分支的历史就没了, 而且注意一点, git中每个提交(commit)有一个独一无二的hash码, rebase命令会为每个新增(相对origin来说)的提交重新生成一个hash码.
$ git rebase origin mywork
执行后主提交历史就是这样了:
加餐
- 整理历史
如果你正确地使用git,相信我们都会频繁地做一些原子commit.我们也要铭记以下警句:不要落入SVN人员的行为模式:commit+push,这是集中式版本控制系统的最常见工作模式:每一个commit都立即push到server上。事实上,如果那样做的话,你就失去了分布式版本控制系统的灵活性:只要我们没有push,我们就有足够的灵活性。所有我们本地的commits只要没有push都是我们自己的,所以我们有完全的自由来清理这些commit,甚至删除取消某些commits。为什么我们要那么每个commit都频繁地Push从而失去我们应该有的灵活性呢?
from:https://www.cnblogs.com/kidsitcn/p/5339382.html
执行下述命令
$ git rebase -i dev
直接运行rebase会打开默认的编辑器, 让你看到一些提交.我这里开始做两个提交:
$ vim a.txt
$ git add a.txt
$ git commit -m "a1"
$ vim a.txt
$ git add a.txt
$ git commit -m "a2"
$ git rebase -i origin/dev #这里要是跟踪分支
得到如下结果
然后就可以编辑了.先介绍一下我git默认编辑器vim的使用吧:
// 等下再写一篇介绍下vim
继续.
这里有三个参数
pick e356e4e a1
第一个是操作命令, 第二个是每个提交的hash码, 第三个是提交信息.
这里看看第一个就好:
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
p : 按命令顺序执行
这个命令会按顺序提交推送
s : 合并到前一个提交, 一起提交(比如你几个提交才能解决一个问题)
这个命令, 会在push的时候,要你重新输入提交信息.并告诉你是哪两个提交以及它们的提交信息,修改后提交就行.
注意是在第一行回车后输入.
r : 重新编辑提交信息(之前提交信息写错了)
这个命令的提交会在被推送到远程库时让你修改提交信息.
d : 删除该提交, push时这条提交会被过滤掉.
这个命令的提交会在被推送到远程库时自动跳过, 不直接删除可能是为了要让其他人在提交前还要看一下.
主要就用这几个就行了.
2 pull操作
pull = fetch + merge
所以你pull下来的主提交历史会有很多不干净的地方.
$ git pull --rebase
$ git pull --rebase=preserve
搞定, 收工.
2017-12-30 21:30
在master分支做了一次提交a1, 然后在master创建了一个dev分支
master做两次提交a2, a3
dev 分支做两次提交 d1, d2
所以, 现在master的分支是这样的:
a1 <-- a2 <-- a3
dev分支上是这样的
a1 <-- d1 <-- d2
现在执行这样的rebase操作:
(在master分支上执行)
[master]$ git rebase -i dev
然后可能会有冲突, 导致合并中断, 然后你可以处理冲突. 解决后add一下(千万不要commit), 然后继续.
$ git add .
$ git rebase --continue
解决后没有add, continue失败:
add之后 可以继续合并:
然后我们来看下这两个分支现在的历史提交记录:
dev:
a1 <-- d1 <-- d2
master:
a1 <-- d1 <-- d2 <-- a2 <-- a3
结论:
1 rebase [源分支] [目标分支]
2 rebase -i [源分支] , 在哪个分支下执行的命令就将哪个分支上一次pull或push后的提交在源分支最新的提交上一个一个跑一遍, 形成新的提交记录.
over.