日常开发中用的最多的是git add、git commit、git pull、git fetch、git push等,不过当出现一些稍复杂一点的场景,如果具备相应的git知识储备,就很有可能脱颖而出。本文首先阐述git的一些基本原理,然后对开发中比较常遇到的合并和撤销等场景做讲解,避免死记硬背。

前言

版本控制工具采用的存储方式:

  1. SVN存储差异
    存储base文件,之后的版本存储base文件的更改,想要获取某个版本的内容,就需要在base文件的基础上依次累加到当前版本的修改

  2. Git存储快照
    每次更改都存储一个新文件,对于没修改的文件则保存 前一快照的引用(想到了immutable)

内部原理

.git目录包含了远程仓库所有内容的克隆。先来认识下 .git 目录下几个比较重要的文件:

config:仓库的配置文件HEAD:当前所在的位置,指向具体分支refs/:存储的是引用文件,如本地分支,远端分支,标签等(其内容为40位hash,指向commit节点)objects/:数据文件的存储目录hooks/: 钩子目录,在特定的重要动作发生时触发自定义脚本

这里重点介绍下objects,仓库中每个文件都有对应的hash值,包括3种数据类型:文件(blob)、文件夹(tree)、提交(commit),其内容分别如下:

1. blob文件:具体文本2. tree文件:100644 blob 47c6340d6459e05787f644c2447d2595f5d3a54b      simplegit.rb3. commit文件:tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579author Scott Chacon  1243040974 -0700committer Scott Chacon  1243040974 -0700

first commit

可以看到,git对文件的管理是通过记录的文件hash,然后通过hash查找对应文件内容的方式。
最后看一张git仓库的原理图:[注] HEAD:指向当前所在的分支;ref/head/:指向当前的commit版本;ci:commit节点,包含当前版本的文件引用

理解commit节点间的引用关系,对理解分支的新建、切换、合并、撤销等至关重要。

由于每个分支 ref 指向的是 commit 节点,而commit通过 parent 指针指向前一次提交节点,实现链式提交记录的回溯

总结:git操作时,关键还是指针的移动,这也是为什么git又名 - 内容寻址系统

理解了上面的基本知识,下面对合并和撤销操作做讲解就会简单很多。

合并

部分提交

//合并某个提交git cherry-pick //合并多个提交git cherry-pick //合并连续提交(不含A)git cherry-pick A..B//合并连续提交(含A)git cherry-pick A^..B

代码冲突时:

1. 解决冲突//解决冲突后git add .git cherry-pick --continue2. 退出合并git cherry-pick --abort

全部提交

merge
git merge [待合并的分支名]# 3种模式-fast-forward:默认方式,如果待合并的分支在当前分支的下游,即也就是说没有分叉时,会发生快速合并–no-ff:在当前分支上新建一个提交节点,从而完成合并–squash:和no-ff非常类似,区别只有一点不会保留对合入分支的引用

代码冲突时:

1. 解决冲突//解决冲突后git add .git commit -m 'xx'2. 退出合并git merge --abort
rebase
git rebase [作为合并基准的分支名]//一般使用:比如feature要合并到master1)先在feature分支rebase master,即将feature的提交应用到master节点后2)再checkout到master使用merge移动master指针到最新节点(fast-forward)

代码冲突时:

1. 解决冲突//解决冲突后git add .git rebase --continue2. 退出合并git rebase --abort
两者的区别

假定当前分支情况如下

   {master}      |A--B--C   |   D--E      |  {feature}

merge
1)合并待合并分支的提交信息后,生成一个新的提交节点
2)保留分支的提交合并记录,便于掌握历史操作记录

//在master分支使用mergefeature> git merge master

      {master}         |A--B--C--F   |    /   D--E      |  {feature}

rebase
1) 指定目标分支作为基准点,将当前分支的节点依次patch到目标分支最新提交后
注意这里仅改变了待合并分支的指针位置,需要checkout到目标分支使用merge,则会直接将目标分支指针移动到最新提交节点
2) 不会删除或复用待合并的提交,而是依次创建新的提交应用到目标分支
3) 不会保留合并记录,使得提交记录线性化

//在feature分支使用rebasefeature> git rebase master

  {master} {feature}      |      |A--B--C--D'--E'   |   D--E

至于在开发中是何时使用merge,何时使用rebase,这个见仁见智。(个人觉得主分支保持清爽很重要,但是特殊情况下撤销merge的分支合并更方便)

撤销

工作区内容撤销

//使用暂存区内容覆盖工作区git checkout -- fileName

暂存区内容撤销

reset

主要用途:回退版本内容
一般格式

git reset <option> <版本>

常用 option

--hard: //使用指定的提交版本覆盖工作区和暂存区。即删除指定版本后的所有提交内容--soft://将指定提交之后的内容回退到暂存区,工作区不变动--mixed: //将指定提交之后的commit以及暂存区的内容退回到工作区未保存状态

对于本地仓库,都是指针的变更;文件或要舍弃(hard),或要合并提交(soft),或要修改(mixed)

举例
git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区

//把所有暂存区中的修改回退到工作区未保存状态git reset HEAD //默认为--mixedgit rest HEAD file

回退版本的指定

HEAD^: 上一个版本HEAD^^:上上一个版本...HEAD~n: 比如回退到倒数第3个版本,HEAD~3

回退版本后,想要提交到远程仓库,则需要使用 -f 强推:

push -f -u origin master

如果回退版本后,想要回到撤销前的版本,则可以使用git reflog查看对应的commitId。git reflog会列出所有历史提交记录,和git log的差异在于包含删除的提交记录

git reset --hard HEAD@{N}
revert

主要用途:撤销某个提交操作

1) 撤销某个普通commit

对指定的commit进行撤销操作,生成一个新的提交记录

git revert 

2) 撤销某个merge commit

先来看合并两个分支后生成的commit节点信息

git show cs38864commit bd868465569400a6b9408050643e5949e8f2b8f5//有两个parant commit,指明当前commit节点由哪两个commit合并Merge: ba25a9d 1c7036f

执行撤销时,需要指定主线分支,将会撤销另一分支内容

/**  *-m表示是一个merge节点 *parent-number:1 | 2 表示保留哪个parent节点,顺序为上例中Merge中的commit **/ git revert -m parent-number 

对于撤销的合并分支上的提交,后续再合并,撤销的节点也不会被合并;想要将撤销的分支提交重新合并,需对revert生成的commit进行一次撤销。

两者的区别
1.revert:不会删除提交记录,保留每一步操作记录,更安全reset:不包含已删除的合并提交2.revert因为是对指定提交进行取反操作,创建一个新的提交,因此无需强推到远程仓库3.建议:本地reset,公共分支revert4.合并后如果做了操作,reset到合并节点前,会删除之后的提交信息;可以使用reset达到revert的效果,如下:  //回退提交内容到工作区  git reset devb-3    //将工作区的内容暂存stash  git stash  //使用hard改变(删除)指针commit    git reset --hard devb-2  //恢复stash的内容到工作区  git stash pop  //提交  git add & commit & push

拾遗

1.对上一次提交进行修改(打补丁),会创建一个新的commitId

git commit --amend//修改提交信息git commit --amend -m 'xxx'//代码逻辑的修补git commit --amend –-no-edit

2.合并多个提交记录
方式1

git reset --soft commitId  //将制定commit后的提交信息回退到暂存区git commit -m '合并多个commit'

方式2

# (start-commit, end-commit] 前开后闭区间,默认 end-commit 为当前 HEADgit rebase -i [start-commit] [end-commit]

3.查看不同阶段代码的差异

git diff: 查看工作区和暂存区的差异git diff --cached HEAD:暂存区和当前仓库指针的差异

4.git stash

将工作区和暂存区的内容存储起来;默认状态,git stash命令会将工作区和暂存区内容重置为最近一次提交后的内容,并且只能将已经跟踪和非.gitignore忽略的文件储藏,未跟踪的文件不会被存储。如果想要将未跟踪的文件一并存储,使用 -u(--include-untracked)

git stash push -u

The latest stash you created is stored in refs/stash; older stashes are found in the reflog of this reference and can be named using the usual reflog syntax (e.g. stash@{0} is the most recently created stash, stash@{1} is the one before it, stash@{2.hours.ago} is also possible). Stashes may also be referenced by specifying just the stash index (e.g. the integer n is equivalent to stash@{n}).

git stash pop //取出栈顶的暂存信息git stash list //查看暂存区的所有暂存修改git stash apply stash@{X} //取出相应的暂存;不会向pop一样从栈中移除stashgit stash drop stash@{X} //将记录列表中取出的对应暂存记录删除

参考链接

https://dotblogs.com.tw/wasichris/2016/04/29/225157  https://www.liaoxuefeng.com/wiki/896043488029600/900004111093344  https://zhuanlan.zhihu.com/p/80506976?from=singlemessagehttps://yanhaijing.com/git/2017/01/19/deep-git-1/

如果对你有帮助,在看一下吧

git回退commit_Git进阶 温故知新系列相关推荐

  1. mysql 开发进阶篇系列 10 锁问题 (使用“索引或间隙锁”的锁冲突)

    1.使用"相同索引键值"的冲突 由于mysql 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但如果是使用相同的索引键,是会出现锁冲突的.设计时要注意 例 ...

  2. mysql如果索引为uid间隙锁_mysql 开发进阶篇系列 10 锁问题 (使用“索引或间隙锁”的锁冲突)...

    1.使用"相同索引键值"的冲突 由于mysql 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但如果是使用相同的索引键,是会出现锁冲突的.设计时要注意 例 ...

  3. c++类指针赋值表达式必须是可修改的左值_C++进阶教程系列:全面理解C++中的类...

    原标题:C++进阶教程系列:全面理解C++中的类 关注Linux公社 最近刷了一些题,也面试了一些公司,把关于C++中关于类的一些概念总结了一下. 在这里也反思一下,面试前信心满满自以为什么都懂,毫无 ...

  4. git 回退上一个版本

    git 回退上一个版本 在 Git 中,HEAD 指针指向的是当前版本,也就是最新的 commit id,上一个版本是 HEAD^,上上一个版本就是 HEAD^^,上50个版本可以写成 HEAD~50 ...

  5. git回退commit的操作

    git回退commit的操作 1 git reset 1. Git -Log-找到当前commit,即当前第一个 2. 右击选择 Go to parent commit 3. 找到本地的上一次提交 4 ...

  6. Git入门与进阶 - 总览

    Git入门与进阶教程 欢迎加好友一起讨论问题 知识地图: 入门 Git简介 https://blog.csdn.net/lili40342/article/details/128241047 Git安 ...

  7. git 回退远端master/develop分支版本

    git 回退远端master分支版本 1.  切换分支到master git checkout master 2.确认是否正确切换到了master分支上面: git branch(如果master分支 ...

  8. PGL图学习之图神经网络ERNIESage、UniMP进阶模型[系列八]

    PGL图学习之图神经网络ERNIESage.UniMP进阶模型[系列八] 原项目链接:fork一下即可:https://aistudio.baidu.com/aistudio/projectdetai ...

  9. Git 回退撤销相关命令,毫无保留,都在这里了!!!

    Git 回退撤销相关命令 # 恢复暂存区的指定文件到工作区 # 即让 工作区的文件 和 暂存区的保持一致,回到初始状态 git checkout [file]# 恢复某个commit的指定文件到暂存区 ...

最新文章

  1. silverlight 类似百度的图片浏览器,视频播放,附件下载功能,全部后台程序。...
  2. 手机抓包app_Python爬取网站上面的数据很简单,但是如何爬取APP上面的数据呢
  3. 102、如何滚动更新 Service (Swarm09)
  4. resnet50能用cpu跑吗_2020年12月1日更新。性价比最高入门游戏CPU--intel 10100F装机配置推荐。...
  5. USACO-Section1.4 Combination Lock (枚举)
  6. Alphabet旗下自动驾驶部门Waymo将在匹兹堡设立办公室
  7. 狗是不是最和其它动物合得来的一种动物?
  8. 在哪里学python-学Python从哪里开始?
  9. Qt QLabel 文字滚动 滚动字幕
  10. iOS5编程--官方例子代码的研究--2.UICatalog-6
  11. [Swift]判断字符串是否为空
  12. 新路由3 新3 NewifiD2 hanwck的老毛子固件
  13. NLP学习笔记[1] -- 构建词向量模型 -- Word2Vec与词嵌入
  14. 一人顶一个团队的华为天才少年稚晖君,又带来一项硬核黑科技,引起极客圈地震!...
  15. java Selenium 发送126邮件 解决element not visible
  16. Please make sure the -vm option in eclipse.ini is pointing to a JDK and verify that Installed JRE’s
  17. 学术规范作业——心得体会
  18. 10款安卓手机必备APP,能让你的手机更好用!
  19. hive表分区上传数据出现的一个问题及解决思路
  20. 利用群晖nas备份华为手机数据

热门文章

  1. python可以从事什么工作-学Python可以找什么工作或者做什么兼职?
  2. ipad编程软件python-iPad可用的软件编程软件有吗?
  3. python下载文件到指定目录-python – 如何将文件下载到特定目录?
  4. 精通python网络爬虫-精通Python网络爬虫:核心技术、框架与项目实战
  5. python编程案例教程书籍-Python程序设计案例教程
  6. python单词翻译-完成自动查找翻译单词的python源代码
  7. java set集合转数组_Java数组【array】与集合【list】的相互转换
  8. spring中的bean属性相关访问、编辑、转换
  9. spoj450 Enormous Input Test
  10. Model/View 教程