git原理与使用心得

时间:2022-02-06 16:37:01

简介

  • 2005年由Linus Torvalds为管理Linux Kernel代码而开发
  • 随着GitHub等开源社区网站的推动,Git已经统治代码管理工具市场
  • 基于Git衍生出了众多高效的工作流程与研发管理平台

特点

离线

  • 分布式代码库,每个本地库都是远程仓库的克隆(clone)
  • 提交到暂存区,查看历史版本记录,创建项目分支等都不需要联网
  • 进行所有代码库操作,开发者拥有极大*

存储方式

  • 内容按元数据方式存储
  • 资源控制系统都是把文件的元信息隐藏在一个类似.svn,.cvs等的文件夹里,体积很小

并行

  • 一个任务一个本地分支,开发新功能不耽误加入紧急bug修复的任务
  • 大家都可以有自己的分支,改完推到服务器合并,不必受一条主干的约束

数据完整性

  • 使用 SHA-1 算法计算数据的校验和,通过对文件的内容或目录的结构计算出一个 SHA-1 哈希值,作为指纹字符串。
  • 所有保存在 Git 数据库中的东西都是用此哈希值来作索引的,而不是靠文件名。

  • 分支、切换、合并,查看历史,diff均为毫秒级响应
  • 直接记录快照,而非差异比较。若文件没有变化,Git 不会再次保存。

重要操作和心得

本地分支/远程分支/跟踪分支/远程仓库

  • 远程分支:对远程仓库的引用(指针),如果不与远程仓库通信,不会更新。
  • 远程仓库:远程服务器
  • 本地分支:在本地自己创建的分支,我们在本地分支上工作。
  • 跟踪分支:本地分支与远程分支之间,建立的一种追踪关系。比如,在git clone的时候,所有本地分支默认与远程主机的同名分支,建立追踪关系,也就是说,本地的master分支自动”追踪”origin/master分支。
  • git branch -vv
  • git branch --set-upstream
  • HEAD指针:指向正在工作的本地分支,即指向最新的提交。进行checkout切换分支,其实就是修改的HEAD指针的指向而已。

git fetch/git pull

  • git fetch从远程获取最新版本,也就是更新远程分支,与远程仓库同步。
  • git pull从远程获取最新版本并merge到本地。
  • git pull = git fetch + git merge
  • 对代码不是很了解时不是太建议直接使用git pull
  • 如果当前分支只有一个追踪分支,后面的参数可省略。

git merge/git rebase

merge和rebase都是用来合并分支的,但原理稍有不同

  • 使用merge命令合并分支,解决完冲突,执行git addgit commit -m'fix conflict'这个时候会产生一个commit。
  • 使用rebase命令合并分支,解决完冲突,执行git addgit rebase --continue,不会产生额外的commit。这样的好处是‘干净’,分支上不会有无意义的解决分支的commit。
  • 采用merge和rebase后,git log的区别,merge命令不会保留merge的分支的commit

合并前:

          D---E master
         /
    A---B---C---F origin/master
    

使用 merge 合并后:

          D--------E  
         /          \
    A---B---C---F----G   master, origin/master
    

如果是 rebase 的方式,就不会有 G 合并点:

    A---B---C---F---D'---E'   master, origin/master
    
  • rebase会把"master"分支里的每个提交(commit)取消掉,并且把它们临时 保存为补丁(patch)(这些补丁放到".git/rebase"目录中),然后把"master"分支更新 为最新的"origin/master"分支,最后把保存的这些补丁应用到"master"分支上。
  • 注意到,其中 D’, E’ 的 commit SHA 序号跟本來 D, E 是不同的,应为算是砍掉重新 commit 了。而且commit的时间先后顺序也不同。

git stash

  • 当你正在做一项复杂的工作时, 发现了一个和当前工作不相关但是又很讨厌的bug. 你这时想先修复bug再做手头的工作, 那么就可以用 git stash 来保存当前的工作状态, 等你修复完bug后,执行'反储藏'(git pop/git stash apply)操作就可以回到之前的工作里。
  • 不需要先commit手头工作之后再去修复bug,从而减少不必要的commit记录。

git cheery pick

  • 可以选择某一个分支中的一个或几个commit来进行操作
  • 用法:git cherry-pick commitID
  • 通过git log查看文档,找出要使用的commitID
  • 若出现冲突,就跟普通的冲突一样,手工解决

同名但不同意义

  • git checkout -- file 撤销对工作区修改
  • git reset HEAD -- file 清空add命令向暂存区提交的关于file文件的修改(Ustage)
  • git reset --hard 回退到之前的commit(版本回退)

冲突

不管是svn还是git都要处理好冲突。
git pull
git merge
git rebase
git pop
git stash apply
等操作都可能产生冲突。处理冲突的方法都是一样的。
举个栗子:
如果系统中有一些配置文件在服务器上做了配置修改,然后后续开发又新添加一些配置项的时候,

在发布这个配置文件的时候,会发生代码冲突:

error: Your local changes to the following files would be overwritten by merge:
        protected/config/main.php
Please, commit your changes or stash them before you can merge.

1.修复实名认证需求个人中心页面渲染和订阅邮箱bug
2.完成工单系统最大字数限制优化的需求
如果希望保留生产服务器上所做的改动,仅仅并入新配置项, 处理方法如下:

git stash
git pull
git stash pop

然后可以使用Git diff -w +文件名 来确认代码自动合并的情况.

此时提示产生冲突的话
git status查看
冲突产生后,文件系统中冲突了的文件里面的内容会显示为类似下面这样:

 a123
<<<<<<< HEAD
b789
=======
b45678910
>>>>>>> 6853e5ff961e684d3a6c02d4d06183b5ff330dcc

其中:冲突标记<<<<<<< (7个<)与=======之间的内容是我的修改,=======与>>>>>>>之间的内容是别人的修改。
之后再 git add, git commit

git 自定义命令

git config --global alias.co checkout
git config --global alias.ci commit
git config --global alias.br branch
git config --global alias.st status

git revert/git reset

  • git revert是生成一个新的提交来撤销某次提交,此次提交之前的commit都会被保留。HEAD指针继续前进
  • git reset是回到某次提交,提交及之前的commit都会被保留,但是此次之后的修改都会被退回到暂存区。HEAD指针向后移动
  • git reset –soft回退到某个版本,只回退了commit的信息,不会恢复到index file一级。如果还要提交,直接commit即可
  • git reset –hard彻底回退到某个版本,本地的源码也会变为上一个版本

git clean

  • 用来从你的工作目录中删除所有没有tracked过的文件
  • 经常和git reset –hard一起结合使用。reset只影响被track过的文件, 所以需要clean来删除没有track过的文件。 结合使用这两个命令能让你的工作目录完全回到一个指定的状态