Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Git 几个特殊命令 #64

Open
pfan123 opened this issue Apr 20, 2020 · 0 comments
Open

Git 几个特殊命令 #64

pfan123 opened this issue Apr 20, 2020 · 0 comments

Comments

@pfan123
Copy link
Owner

pfan123 commented Apr 20, 2020

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 之后,会有类似的输出:

commit 19b7d40d2ebefb4236a8ab630f89e4afca6e9dbe 
Merge: b0ef24a cca45f9 ......

其中,Merge 这一行代表的是这个合并 parents它可以用来表明 merge 操作的线索

举个例子,通常,我们的稳定代码都在 master 分支,而开发过程使用 dev 分支,当开发完成后,再把 dev 分支 merge 进 master 分支:

a -> b -> c -> f -- g -> h (master)           
           \      /            
            d -> e  (dev)

上图中,g 是 merge commit,其他的都是常规 commit。g 的两个 parent 分别是 fe

Revert a Merge Commit

当你使用 git revert 撤销一个 merge commit 时,如果除了 commit 号而不加任何其他参数,git 将会提示错误:

$ git revert g error: Commit g is a merge but no -m option was given. fatal: revert failed

在你合并两个分支并试图撤销时,Git 并不知道你到底需要保留哪一个分支上所做的修改。从 Git 的角度来看,master 分支和 dev 在地位上是完全平等的,只是在 workflow 中,master 被人为约定成了「主分支」。

于是 Git 需要你通过 mmainline 参数来指定「主线」。merge commit 的 parents 一定是在两个不同的线索上,因此可以通过 parent 来表示「主线」。m 参数的值可以是 1 或者 2,对应着 parent 在 merge commit 信息中的顺序。

以上面那张图为例,我们查看 commit g 的内容:

$ git show g commit g Merge: f e

那么,$ 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 checkout feature
git rebase 

git cherry-pick

cherry-pick可以选择某个分支中的一个或几个 commit 来进行操作。假设我们有个稳定版本的分支,叫 v2.0,另外还有个开发版本的分支 feat,我们不能直接把两个分支合并,这样会导致稳定版本混乱,但是又想增加 feat 中的部分功能到 v2.0 中,这里就可以使用 cherry-pick 了,其实也就是对已存在的 commit 进行再次提交。

git cherry-pick <commit id>

git cherry-pick <commit id>:单独合并一个提交

git cherry-pick  -x <commit id>:同上,不同点:保留原提交者信息。
 Git从1.7.2版本开始支持批量cherry-pick,就是一次可以cherry-pick一个区间的commit。

git cherry-pick <start-commit-id>..<end-commit-id> (左开右闭,不包含start-commit-id)

git cherry-pick <start-commit-id>^..<end-commit-id> (闭区间,包含start-commit-id)

示例, 代码仓库有 masterfeature 两个分支, 现在将提交 f 应用到 master 分支:

    a - b - c - d   Master
         \
           e - f - g Feature

  # 切换到 master 分支
  $ git checkout master
  
  # Cherry pick 操作
  $ git cherry-pick f

git merge 和 git merge --no-ff

通常合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。

如果要强制禁用Fast forward模式,Git就会在 merge 时生成一个新的 commit,这样从分支历史上就可以看出分支信息。

git merge --no-ff

git merge –no-ff 可以保存你之前的分支历史。能够更好的查看 merge历史,以及branch 状态。

git merge 则不会显示 feature,只保留单条分支记录。

Other Resources

Git 撤销合并

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant