十分钟了解git那些“不经常使用”命令

本文主要是介绍git 不经常使用初期不太会用的命令,但愿你看了能理解这些命令的使用,并在平时使用过程当中一点点地刻意进行练习,逐步熟练并知道什么时候须要用到这些命令去解决你的问题。
( 我也在不断熟练中:D

基础命令

若是你仍是刚刚接触git命令,还不清楚 仓库工做流分支提交 的童鞋能够先看下 git使用简易指南,这个应该是我初学git看的第一份且收藏至今的指南了~ 图解很清晰易懂,真10分钟入门的资料:Dcss

而后你会发现以下基础命令将会成为你以后几乎天天都要用到的80%的命令git

  • git clone git@github.com:nohosts/nohost.git 克隆远程仓库的内容到本地
  • git pull origin master 获取远程分支master并merge到当前分支
  • git branch -a 查看所有分支(远程+本地)
  • git checkout -b bugFix新建bugFix,并切换到到此分支。(若是分支已存在则去掉-b便可)
  • git status 查看当前~~~~版本状态(是否修改)
  • git add . 增长当前子目录~~~~下全部文件更改至暂存区
  • git commit -m 'xxx' 提交暂存区的修改至本地的版本库, 修改备注为xxx
  • git push 将本地版本推送到远程分支
  • git tag v1.0 dfb02e6e4f2f7b573337763e5c0013802e392818 增长v1.0的tag到某个提交上
  • git merge testBranch 合并testBranch分支至当前分支`
  • git stash 暂存本地的当前修改,将本地代码重置为HEAD状态。(若是须要取出修改,命令后加一个pop便可)
  • git log 显示提交日志(若是想每一个提交信息显示在一行,能够加上--pretty=oneline)
  • git show dfb02e6e4f2f7b573337763e5c0013802e392818显示某个提交的详细内容
  • git reset --hard HEAD 将当前版本重置为HEAD

注意这两个命令的区别github

git pull = fetch + merge

git pull --rebase = fetch + rebase

“不经常使用”命令

1、git rebase 变基

在 Git 中整合来自不一样分支的修改主要有两种方法: merge 以及 rebase。 在本节中咱们将学习什么是“变基”,怎样使用“变基”,并将展现该操做的惊艳之处,以及指出在何种状况下你应避免使用它。—— git-scm变基

说明:后面的举例每一个 分支 都有不一样的颜色,*前缀 表示如今所处的分支,而 commitid 都由C0、C一、C2代替每个提交的哈希值,箭头 表示分支的继承ide

咱们以前整合分支用的最多的就是merge了,那merge和rebase有什么区别呢?学习

1. merge

merge 合并两个分支时会产生一个特殊的提交记录,它有两个父节点。简单说就是:“我要把这两个父节点自己及它们全部的祖先都包含进来。”
git checkout master; git merge bugFix

下图中左、右两张图分别是执行以下代码先后的样子:fetch

merge-1

能够看出来,红色圈圈是最主要的改变—— merge 合并分支后,会在master分支上 新增一个C4提交 ,而C4提交里面有master和bugFix代码库全部的修改。网站

此时的bugFix代码还没和master 同步(颜色不一样),咱们还须要执行以下代码:ui

git checkout bugFix; git merge master

merge-2

2. rebase

rebase 实际上就是取出一系列的提交记录,“复制”它们,而后在另一个地方逐个的放下去。它的优点就是能够创造更线性的提交历史。
git checkout bugFix; git rebase master

下图中左、右两张图分别是执行代码先后的样子:spa

变基-1

bugFix 分支里的内容经过 rebase 直接 复制 到 master 分支上。如今 bugFix 分支上的工做在 master 的最顶端,同时咱们也获得了一个更 线性 的提交序列。日志

注意:提交记录 C3 依然存在(树上那个半透明的节点),而 C3' 是咱们 rebase 到 master 分支上的 C3 的 副本(内容是同样的,只是commitid更新了)。

可是,此时master尚未和bugFix 同步(颜色不一样),咱们还须要执行以下代码:

git checkout master; git rebase bugFix

变基-2.png

因为bugFix继承自master,因此 Git 只是简单的把master分支的引用向前移动了一下而已。

3. rebase的延伸用法

3.1 省去切换分支便可rebase

git rebase targetBranch originBranch

表示切换到originBranch,而后执行git rebase targetBranch

3.2 修改某几回提交

git rebase -i commitid

变基-3.png
如上图标注的,传的commitid为你想修改的提交的 前一个commitid。执行命令后进入vi模式,会提示你一些操做命令(p、r、e...)你只须要在最上方修改默认的pick为你想要的操做,而后退出并wq保存便可生效。

具体操做:

  • pick 使用(啥也没变)
  • reword 使用并修改commit msg, 改后commit id也会更新
  • edit 使用并编辑commit时的文件
    编辑后git add . 而后git commit —amend还能够更新最新的commit msg。 git rebase —continue 把后面的内容加进来并解决冲突, 最后提交。最新的commit id也更新
  • squash 合并commit
    选择最新的commit去合并,而后continue发现这一次和上一次的commit msg都有,你能够删除只留下想要的也能够进行修改 而后 continue和push。若是你不删的话会发现所有文本行都组成了一个多行的commit msg
    若是commit再往前已经没有了 就不能再squash,不然会报错( error: cannot 'squash' without a previous commit )。而后 git rebase --edit-todo 能够继续vi编辑
  • fixup 合并commit到前面并且commit,commit msg也没了
  • drop 删除某个commit

注意
若是想要恢复这一次rebase操做,则能够执行 git rebase —abort
若是想彻底恢复本地分支到远程的状态,能够执行 git reset --hard origin/bugFix ,或者你能够 git reflog 找到对应提交记录回滚,可是有点麻烦

4. rebase须要谨慎使用

当你要改写的commit history尚未被提交到远仓库的时候,也就是说,尚未与他人共享以前,commit history是你私人全部的,那么想怎么改写均可以。

而一旦被提交到远程后,这时若是再改写history,那么势必和他人的history长的就不同了。git push 的时候,git会比较commit history,若是不一致,commit动做会被拒绝,惟一的办法就是带上 -f 参数,强制要求commit,这时git会以committer的history覆写远程分支,从而完成代码的提交。虽然代码提交上去了,可是这样可能会形成别人工做成果的丢失,因此使用 -f 参数要慎重。

因此,在不用 -f 的前提下,想维持树的整洁,方法就是:在 git push 以前,先 git fetch,再 git rebase

4. 总结

  1. 不管是经过变基,仍是经过三方合并,整合的最终结果所指向的快照始终是同样的,只不过提交历史不一样罢了。 变基是将一系列提交按照原有次序依次应用到另外一分支上,而合并是把最终结果合在一块儿
  2. 在你本身的分支(非他人共享)的分支进行rebase是能够的,可是若是在公共分支rebase修改提交须要谨慎——最好是先 fetch、再 rebase、最后 push

2、git cherry-pick 选择

cherry-pick 能够将提交树上任何地方的提交记录取过来追加到 HEAD 上(只要不是 HEAD 上游的提交就没问题)。`
git checkout master; git cherry-pick C2

下图中左、右两张图分别是执行代码先后的样子:
是否是有点眼熟:D 没错 这个和rebase的效果蛮像的,这两个命令均可以实现复制提交~

cherry-pick.png

3、git reset VS revert 回滚

git revert HEAD是用一次新的commit来回滚以前的commit, git reset 是直接向上移动分支,删除一些commit看上去像从未提交同样。这二者看似达到的效果是同样的,其实彻底不一样。
git reset HEAD~1
git revert HEAD

以下所见,图1是初始状态(须要撤回 C2 提交),图2和3 是从图1分别执行 resetrevert 后的结果:
image.png

  1. reset
    执行后,master 分支移回到了 C1;如今咱们的本地代码库根本就不知道有 C2 这个提交了
  2. revert
    执行后,在咱们要撤销的提交记录 C2 后面多了一个新提交C2',而C2'引入了更改—— 这些更改是用来撤销C2这个提交的。也就是说C2'的状态与C1是相同的。

注意

  • 若是你已经push到线上代码库, reset 删除指定commit之后, 你git push可能致使不少冲突.可是revert 并不会。
  • 若是此回退的分支合并主干分支时,reset 恢复部分的代码依然会出如今历史分支里,可是revert 方向提交的commit 并不会出如今历史分支里。
# 事例
reset后的123 merge了12345 仍是12345
revert后的12345(-3) merge了12345 是12345(-3)

4、HEAD^n 和 HEAD~n 相对引用

HEAD 是一个对当前检出记录的符号引用 —— 也就是指向你正在其基础上进行工做的提交记录。 HEAD 老是指向当前分支上最近一次提交记录
(若是想看 HEAD 指向,能够经过  cat .git/HEAD 查看, 若是 HEAD 指向的是一个引用,还能够用  git symbolic-ref HEAD 查看它的指向。)

1. 基础使用

  • 使用 ^ 表示向上移动 1 个提交记录。
    n表示第n个父提交,不填默认是1(正上方)
  • 使用 ~<num> 向上移动多个提交记录
    如 ~3

注意:操做符还支持链式操,如HEAD^2~3^

2. 延伸用法
移动分支
能够直接使用 -f 选项让分支指向另外一个提交。例以下面的命令会将 master 分支强制指向 HEAD 的第 3 级父提交。

git branch -f master HEAD~3

此次主要就总结了这几种“不经常使用”git命令,但愿你们和我均可以多多练习,让他变成你须要时就能够自如使用的“经常使用”命令!:D

墙裂推荐一个可视化的git练习网站,很易懂好用~

推荐git系列文章

相关文章
相关标签/搜索