Py学习  »  Git

Git原理与高级使用(2)

Desmonddai583 • 5 年前 • 387 次点击  

Git原理与高级使用(2)

上一篇中我们介绍了git的基础概念,这篇我们就来说说分支

分支

git中的分支其实只是一个指针指向一个commit对象,而不是像传统的版本控制系统一样把整个当前版本复制一份出来。它背后其实就是一个文件,我们可以去.git/refs/heads文件夹下面查看,里面的每个文件其实就是一个分支,而内容其实就是一串SHA1值,而这个SHA1值又是什么呢,其实就是一个commit id,以下图为例,其实此时master分支文件存放的就是master分支上的最后一次commit id,而分支背后代表的就是一条commit对象链。

而HEAD又是什么呢,其实它也是一个指针,指向着是当前分支,而不是commit对象。在.git目录下有一个HEAD文件,里面就是记录着HEAD指向的分支。

分支合并

接下来就用一个例子来介绍一下git分支合并的过程,首先假设我们处于master分支上

接着我们从当前master上创建一个新分支dev,并且换到当前分支上git checkout -b dev
下一步我们在dev分支上修改并提交一个新的commit
接着我们回到master分支并执行git merge dev合并分支
这里要注意的是merge默认采用的是fast-forward快进模式,它代表着就是直接将master指针指向最新的commit id,中间master分支不会做任何的修改,而没有创建任何新的commit,但是实际上不是任何情况下我们都可以直接这样快进的,合并时修改的不是同一个文件的同一个内容是可以直接fast-forward合并,但是因为两个分支都有过commit,所以合并的时候就一定会产生一个新的commit对象,同时当我们修改的是同一个文件同一个内容时,合并是会产生冲突的,这是后我们就必须要手动修复冲突,解决后通过git add标示冲突已解决并用git commit提交,也一样不可避免会产生一个新的commit。在合并之后,反过来如果被merge的分支想要去merge已经merge完的分支,就直接fast-forward就可以了,以为两条分支已经有了一个交汇点,所以直接快进至交汇点即可,所以这里其实是可以总结一条规律的,什么情况下可以快进呢,就是当当前的commit对象链可以从当前想要merge的分支走到要merge到的commit点,那就可以直接快进了。
那说完快进模式后,自然也就有非快进模式,非快进模式模式在上面提到的情况时即便没有冲突,两个分支也没有同时进行修改也会产生一个新的commit,在我们merge时我们只要加上一个--no-ff即可,git merge --no-ff dev

Reset

git reset其实有3中模式,mixed, soft和hard,默认不写的话会调用mixed模式,那么3者的区别是什么呢,mixed其实就是会将reset之后的commit与原commit之间的修改转到工作区,而soft则是转到暂存区,最后hard就是直接丢弃掉,所以可以看出其实reset与它的字面意思有些不同的,我们经常会误会它是重新设定把之后的commit砍掉,其实它只是回到之前的状态。

Stash

git stash的作用是什么呢,假设当我们在feature1上做事时,突然需要紧急去feature2上做事,此时就需要将feature1上的事情暂时用git stash先存起来然后去feature2上做事,做完再回feature1上通过git stash pop将之前保存的修改取出。需要注意的是git stash会记住目前的commit id,所以如果同一个commit下stash两次对于同一文件同一行内容的修改,恢复完第一次并且提交过后,在执行第二次恢复就会有冲突。

Tag

tag就是我们之前提到的其实就是一个标签对象,它也是指向某一个commit对象,它与分支的区别就在于当有commit发生时,分支会跟着一起向前移,但是标签一旦定下来就不会再移动了,所以它通常是用于我们项目到了一个milestone,需要发布一个新版本时使用。git标签分为两种轻量级标签(lightweight)和附注标签(annotated),就如同字面上的意思,轻量级于附注标签的区别就是一个有描述信息一个没有。

Diff

git diff背后其实就是利用了linux自带的diff模块用来比较文件之间的差别,有兴趣的可以去了解一下

指令

  1. 查看分支列表

    git branch

  2. 创建分支

    git branch 分支名

  3. 切换分支

    git checkout 分支名

  4. 切换到上次处于的分支中

    git checkout -

  5. 删除分支()

    git branch -d 分支名

    这里需要注意不能删除当前处于的分支,如果非master分支有改动但还未merge的话也不可以,除非使用git branch -D 分支名

  6. 创建新分支并切换到新分支

    git checkout -b 分支名

  7. 显示当前分支最近的一条提交消息

    git branch -v

  8. 将分支合并到当前分支

    git merge 分支名

  9. 禁用fast-forward,会多一个commit id

    git merge --no-ff 分支名

  10. 回退到上一次提交(基于当前的commit)

    git reset --hard HEAD^

  11. 回退到上上一次提交(都是基于当前的commit)

    git reset --hard HEAD^^

  12. 回退到当前分支上的前n次(从当前commit往前n次)的提交

    git reset --hard HEAD~n

  13. 回退到指定commit

    git reset --hard commit信息的前几位

  14. 修改分支名

    git branch -m 原分支名 新分支名

  15. 将工作区的修改保存

    git stash

  16. 列出所有的保存

    git stash list

  17. 手动设置stash描述

    默认执行git stash返回的描述信息是

    其实就是包含了当前最新commit的消息,那么我们可以通过以下命令来修改描述信息 git stash save 'hello basic'

  18. 恢复最近一次的保存,并且会把这次保存在列表中删除

    git stash pop

  19. 恢复最近一次的保存,但是不会在列表中删除

    git stash apply

  20. apply特定一个版,并且会把这次保存在列表中删除

    git stash apply stash@{0}

  21. 手动删除指定的一个保存版本

    git stash drop stash@{0}

  22. 创建轻量标签

    git tag v1.0.1

  23. 创建附注标签

    git tag -a v1.0.2 -m 'release 1.0.2'

  24. 查看所有标签

    git tag

  25. 查找标签

    git tag -l 'v1.0' 里面可以使用pattern,例如'v*', 代表v开头的所有标签

  26. 删除标签

    git tag -d 标签名

  27. 列出每一行都是谁在什么时间哪个commit修改的

    git blame 文件名

  28. 比较算入暂存区修改的当前文件与工作区文件之间的区别

    git diff

  29. 比较当前最新commit与工作区的区别

    git diff HEAD

  30. 比较某个commit与工作区的区别

    git diff commit_id

  31. 比较最新提交与暂存区的区别

    git diff --cached

  32. 比较某个commit与暂存区的区别

    git diff --cached commit_id

场景

  1. 当我们使用git reset --hard指令回退到之前的commit时,执行git log只能看到当前commit及其之前的commit,那如果我想回到之后的某个commit,我要怎么获取commit id呢?

    我们可以通过执行git reflog来查看操作日志,看到我们使用git的指令的历史,这样就可以找回我们之前的commit id了

Q&A

  1. git checkout commit-idgit reset --hard commit-id 有什么区别呢?

    两者都可以回到对应的commit点,但是checkout与reset不同的是它会处于游离状态,任何的修改如果不做提交就会有警告不允许我们跳去其他的commit,同时修改完我们可以通过git branch 分支名 当前checkout的commit-id来创建一个新分支。


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/Aw5oiyTkGL
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/10289
 
387 次点击