那么,$ git revert -m 1 g 将会保留 master 分支上的修改,撤销 dev 分支上的修改。
撤销成功之后,Git 将会生成一个新的 Commit,提交历史就成了这样:
a -> b -> c -> f -- g -> h -> G (master)
\ /
d -> e (dev)
其中 G 是撤销 g 生成的 commit。通过 $ git show G 之后,我们会发现 G 是一个常规提交,内容就是撤销 merge 时被丢弃的那条线索的所有 commit 的「反操作」的合集。
git rebase
使用 git rebase 命令可以帮助我们的清洁、整理提交记录,方便 代码 review,它可以对某一段线性提交历史进行编辑、删除、复制、粘贴。
注意切勿使用 rebase 对任何已经提交到公共仓库中的commit进行修改
功能一:合并多次提交纪录
# git rebase -i HEAD~4
git rebase -i [startpoint] [endpoint]
1.进入 vi 编辑模式:
pick 9aba15d optaldl Revert "add log"
pick c98d8a3 create http server
pick de9e11b add 调试代码
pick 6333530 print __dirname
# Rebase ec543c9..b75e42a onto 6333530 (4 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
2.异常退出了 vi 窗口
git rebase --edit-todo
git rebase --continue
功能二:变基,减少 master 冲突 commit
通常我们在 master 合入 feature 分支,遇到冲突解决冲突,提交很容易产生污染主干。通过 rebase 可以随时解决冲突,而 merge 必须要到最后合并时才一次性解决。
git revert
Git 的 revert 命令可以用来撤销提交(commit),对于常规的提交来说,revert 命令十分直观易用,相当于做一次被 revert 的提交的「反操作」并形成一个新的 commit,但是当你需要撤销一个合并(merge)的时候,事情就变得稍微复杂了一些。
Merge Commit
在描述 merge commit 之前,先来简短地描述一下常规的 commit。每当你做了一批操作(增加、修改、或删除)之后,你执行
git commit
便会得到一个常规的 Commit。执行git show
将会输出详细的增删情况。Merge commit 则不是这样。每当你使用
git merge
合并两个分支,你将会得到一个新的 merge commit。执行git show
之后,会有类似的输出:其中,Merge 这一行代表的是这个合并 parents,它可以用来表明 merge 操作的线索。
举个例子,通常,我们的稳定代码都在 master 分支,而开发过程使用 dev 分支,当开发完成后,再把 dev 分支 merge 进 master 分支:
上图中,
g
是 merge commit,其他的都是常规 commit。g
的两个 parent 分别是f
和e
。Revert a Merge Commit
当你使用
git revert
撤销一个 merge commit 时,如果除了 commit 号而不加任何其他参数,git 将会提示错误:在你合并两个分支并试图撤销时,Git 并不知道你到底需要保留哪一个分支上所做的修改。从 Git 的角度来看,
master
分支和dev
在地位上是完全平等的,只是在 workflow 中,master
被人为约定成了「主分支」。于是 Git 需要你通过
m
或mainline
参数来指定「主线」。merge commit 的 parents 一定是在两个不同的线索上,因此可以通过 parent 来表示「主线」。m
参数的值可以是 1 或者 2,对应着 parent 在 merge commit 信息中的顺序。以上面那张图为例,我们查看 commit
g
的内容:那么,
$ git revert -m 1 g
将会保留 master 分支上的修改,撤销 dev 分支上的修改。撤销成功之后,Git 将会生成一个新的 Commit,提交历史就成了这样:
其中
G
是撤销g
生成的 commit。通过$ git show G
之后,我们会发现G
是一个常规提交,内容就是撤销 merge 时被丢弃的那条线索的所有 commit 的「反操作」的合集。git rebase
使用
git rebase
命令可以帮助我们的清洁、整理提交记录,方便 代码review
,它可以对某一段线性提交历史进行编辑、删除、复制、粘贴。功能一:合并多次提交纪录
1.进入
vi
编辑模式:2.异常退出了
vi
窗口功能二:变基,减少 master 冲突 commit
通常我们在
master
合入feature
分支,遇到冲突解决冲突,提交很容易产生污染主干。通过rebase
可以随时解决冲突,而merge
必须要到最后合并时才一次性解决。git cherry-pick
cherry-pick可以选择某个分支中的一个或几个
commit
来进行操作。假设我们有个稳定版本的分支,叫v2.0
,另外还有个开发版本的分支feat
,我们不能直接把两个分支合并,这样会导致稳定版本混乱,但是又想增加feat
中的部分功能到v2.0
中,这里就可以使用cherry-pick
了,其实也就是对已存在的commit
进行再次提交。示例, 代码仓库有
master
和feature
两个分支, 现在将提交f
应用到master
分支:git merge 和 git merge --no-ff
通常合并分支时,如果可能,Git会用
Fast forward
模式,但这种模式下,删除分支后,会丢掉分支信息。如果要强制禁用
Fast forward
模式,Git就会在 merge 时生成一个新的 commit,这样从分支历史上就可以看出分支信息。git merge –no-ff 可以保存你之前的分支历史。能够更好的查看 merge历史,以及branch 状态。
git merge 则不会显示 feature,只保留单条分支记录。
Other Resources
Git 撤销合并