社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Git

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

腾讯IMWeb团队 • 4 年前 • 311 次点击  
阅读 37

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

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

原文作者:李佳,来自IMWeb团队。未经同意,禁止转载。

基础命令

如果你还是刚刚接触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变基

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

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

1. merge

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

git checkout master; git merge bugFix
复制代码

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

image

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

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

git checkout bugFix; git merge master
复制代码

image

2. rebase

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

git checkout bugFix; git rebase master
复制代码

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

image

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

注意:提交记录 C3 依然存在(树上那个半透明的节点),而 C3' 是我们 rebase 到 master 分支上的 C3 的 副本(内容是一样的,只是commitid更新了)。(如果master和bugFix之间没有其他commit,rebase后commitid不会更新。如果master已经有了自己新的commit,此时rebase后commitid就会更新。)

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

git checkout master; git rebase bugFix
复制代码

image

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

3. rebase的延伸用法

3.1 省去切换分支即可rebase

git rebase targetBranch originBranch
复制代码

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

3.2 修改某几次提交

git rebase -i commitid
复制代码

image
如上图标注的,传的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 -i 做了 r,e,s,d操作后产生的结果

image

注意: 如果想要恢复这一次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

5. 总结

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

二、git cherry-pick 选择

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

git checkout master; git cherry-pick C2
复制代码

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

image

三、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

  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)
复制代码

四、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系列文章

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/57195
 
311 次点击