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

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> 十分钟了解 git 那些 “不常用” 命令

  点击上方 **好好学java **,选择 **星标 **公众号


重磅资讯、干货,第一时间送达
今日推荐:Java实现QQ登录和微博登录个人原创+1博客:点击前往,查看更多

链接:https://segmentfault.com/a/1190000022107836

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

基础命令

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

然后你会发现如下基础命令将会成为你之后几乎每天都要用到的80%的命令

  • 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

注意这两个命令的区别


git pull = fetch + merge

git pull --rebase = fetch + rebase

“不常用”命令

一、git rebase 变基

在 Git 中整合来自不同分支的修改主要有两种方法: merge 以及 rebase。在本节中我们将学习什么是“变基”,怎样使用“变基”,并将展示该操作的惊艳之处,以及指出在何种情况下你应避免使用它。——[git-scm变基]:https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%8F%98%E5%9F%BA

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

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

1. merge


merge 合并两个分支时会产生一个特殊的提交记录,它有两个父节点。简单说就是:“我要把这两个父节点本身及它们所有的祖先都包含进来。”


git checkout master; git merge bugFix

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

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

此时的bugFix代码还没和master 同步(颜色不同),我们还需要执行如下代码:


git checkout bugFix; git merge master

2. rebase


rebase 实际上就是取出一系列的提交记录,“复制”它们,然后在另外一个地方逐个的放下去。它的优势就是可以创造更线性的提交历史。


git checkout bugFix; git rebase master

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

bugFix 分支里的内容通过 rebase 直接 复制 到 master 分支上。现在 bugFix 分支上的工作在 master 的最顶端,同时我们也得到了一个更 线性 的提交序列。

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

但是,此时master还没有和bugFix 同步(颜色不同),我们还需要执行如下代码:


git checkout master; git rebase bugFix

由于bugFix继承自master,所以 Git 只是简单的把master分支的引用向前移动了一下而已。

3. rebase的延伸用法

3.1 省去切换分支即可rebase

git rebase targetBranch originBranch

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

3.2 修改某几次提交

git rebase -i commitid

如上图标注的,传的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. 无论是通过变基,还是通过三方合并,整合的最终结果所指向的快照始终是一样的,只不过提交历史不同罢了。变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起。1. 在你自己的分支(非他人共享)的分支进行rebase是可以的,但是如果在公共分支rebase修改提交需要谨慎——最好是先 fetch、再 rebase、最后 push

    二、git cherry-pick 选择


cherry-pick 可以将提交树上任何地方的提交记录取过来追加到 HEAD 上(只要不是 HEAD 上游的提交就没问题)。`


git checkout master; git cherry-pick C2

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

三、git reset VS revert 回滚


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


git reset HEAD~1
git revert HEAD

如下所见,图1是初始状态(需要撤回 C2 提交),图2和3 是从图1分别执行 reset revert 后的结果:

  1. ** reset**执行后,master 分支移回到了 C1;现在我们的本地代码库根本就不知道有 C2 这个提交了1. 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)


### 四、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练习网站]:https://learngitbranching.js.org/,很易懂好用~

原文地址:https://sihai.blog.csdn.net/article/details/109465295

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> 十分钟了解 git 那些 “不常用” 命令


 上一篇
Java SPI 源码解析及 demo 讲解 Java SPI 源码解析及 demo 讲解
  点击上方 **好好学java **,选择 **星标 **公众号 重磅资讯、干货,第一时间送达 今日推荐:Java实现QQ登录和微博登录个人原创+1博客:点击前往,查看更多 作者:JlDang 来源:https://segmentf
2021-04-04
下一篇 
后端程序员必备——书写高质量SQL的30条建议 后端程序员必备——书写高质量SQL的30条建议
 点击上方 **好好学java **,选择 **星标 **公众号 重磅资讯、干货,第一时间送达 今日推荐:Java实现QQ登录和微博登录个人原创+1博客:点击前往,查看更多 前言本文将结合实例demo,阐述30条有关于优化SQL的建议,
2021-04-04