Git使用教程
一、前言
1、简介
git仓库每个节点都是一个独立的版本管理节点,当不需要和其他节点同步时,可以在本地仓库独立开发。而当需要和其他节点同步信息时即多人协作开发,就需要一个中心仓库(Github、Gitee、Gitlab等),合并其他节点的提交,另外的节点再去中心仓库拉取自己需要的其他节点的提交,简而言之,git是一个分布式版本管理系统。
2、名词解释
工作区( Working Directory)
工作区也就是你系统的文件目录,所有修改的东西首先存在你的工作区。这时候的状态是untracked(未追踪)。
暂存区(stage/index)
暂存区是一个添加到版本之前的缓冲区,通过git add 把工作区的修改加到暂存区,状态为Changes to be committed(要提交的变更)。如果已经添加到版本控制的文件对它进行修改也需要git add 重新将修改更新到暂存区。
版本库(commit)
每一个commit都是一个回溯点,通过git commit把暂存区的东西加到版本库。这时候HEAD指针会指向最新的commit。此时状态为nothing to commit(没有需要提交的东西,暂存区是干净的)。
分支(branch)
分支是以commit节点为基础形成的一个概念,可以把整个版本库理解为一棵树,每个commit就是一个节点,把节点串起来的就是分支,就像树枝一样。当任务进行到一个阶段,需要朝不同方向进行时,这时候就需要以某个节点为基础切换分支,就像树一样分叉。当有一天两个方向需要共同前进,这时候就可以把两个分支合并。
二 、准备工作
安装git客户端工具,准备一个远程托管仓库Github或公司搭建的局域网Gitlab。
1、常用配置
1 |
|
2、SSH
git服务器一般使用https和ssh协议,如果使用https协议,客户端在和服务器交互时,比如pull和push就需要填写用户名和密码非常麻烦,所以一般如果长期要用整个服务器的话还是使用ssh协议,把自己的SSH密钥添加到服务器,就可以不用每次输出用户名和密码。
1 |
|
连续回车三次
1 |
|
复制密钥,然后去git服务器添加到你的用户设置里面,就可以直接使用ssh认证方式。
三、开发流程
1、初始化仓库
登陆git服务器,创建远程仓库(test)。然后把本地已经存在的项目(没有建立版本库)新建一个版本仓库,初始化提交,最终推送到远程仓库。
1 |
|
git push [远程仓库] [本地分支]:[远程分支],这是push的一般用法,远程仓库就是git remote add 时添加的远程链接的别名,可以任意。这里push时省略了远程分支,表示默认推送到本地master分支关联的上游分支,如果上游仓库没有整这个分支就会自动创建一个。
1 |
|
从远程直接把原始仓库下载到本地。
1 |
|
当需要将仓库的上游服务器换成新的时,可以先增加新的远程仓库,然后把本地的仓库全部推送到新建的远程。
2、 日常维护
一个人开发的话就不需要考虑合并别人的代码,但是需要考虑同时开发多个功能的问题。这时候就不能直接在master分支开发,需要根据指定commit或者分支切换新的开发分支。等该分支的任务完成之后就可以合并到远程仓库,并删除本地的开发分支(避免本地分支越来越多,忘记当前分支的合并清空)。然后开发新功能时,先从远程更新本地master分支,在从master切开发分支继续开发。
流程图如下:
1 |
|
我这里采取git fetch和git rebase的方式更新远程代码,也可以使用git pull origin –rebase的方式,pull=fetch+merge,pull –rebase=fetch+rebase。fetch只会把远程最新的commit记录更新到.git/refs/remotes/里面,不会更新本地提交。只有merge才会合并到本地分支。
rebase的意思是变基,也就是把自己基线设置到指定分支的HEAD,然后把自己新增的commit放到新起点的后面。下面是不同操作的示意图:
合并前:
merge合并:
rebase合并:
明显看到merge会多生成一个commit节点,分支树会更加复杂一些,优点是保留了分支自己的提交历史,合并冲突比较简单,合并完了直接重新commit就行。rebase不会生成多余的merge提交,维护起来更加简单,但是合并冲突会复杂一点,一般合并完了需要git rebase –continue。
多人开发,就需要注意每个人代码的合并问题,一般采取所有人维护master主干,开发的时候在各自的分支开发,然后合并到master主干分支上,提交前注意git pull 更新最新的代码,因为你的代码提交可能落后master。这种情况适用于共同维护一个远程仓库。
1 |
|
说明:git rebase master 可以理解为合并master分支上进度到当前自己的分支,如果没有冲突,那么直接git push,如果存在冲突,那么根据提示去相应的文件,手动合并冲突,合并完了执行git rebase –continue。git push origin liurui:liurui/dev 其中liurui是你的本地分支名,liurui/dev是你的远程分支名。然后去网站上提交合并申请,然后有master合并权限的用户审核代码,他可以合并本次提交,也可以不合并。
这种模式适用于fork原始仓库,更新维护自己仓库,并将自己的仓库的更新提交merge request到主干仓库。
1 |
|
四、常用功能示例
1、删除具体某个commit
假设功能开发都是在master一个分支进行,这样同时开发几个功能时只能串行提交。假设有一个merge有问题并且包含多个commit,被拒绝合并到主仓库。那么本地需要删除这个commit,然后重新提交。假设有三个commit A,B,C。需要删除B。
1 |
|
输出如下
1 |
|
将B对应的pick改为drop保存退出即可。
这里也可以采取拉新的分支,先将commit-C导出成patch,然后拉取一个分支到commit-A节点,然后在新的分支合并patch。代码如下:
1 |
|
2、版本维护
在大型项目中,需要对某一个节点设置一个版本,用于发布,就可以使用git tag相关指令
1 |
|
3、从版本库中删除文件
1 |
|
4、添加忽略文件
注意事项
添加忽略文件是为了将开发中产生的一些中间文件排除在版本管理之外,方便其他人维护更新。忽略文件只能忽略尚未添加到版本管理中的文件和文件夹。
添加方法
在项目根目录下打开gitbash,创建文件 touch .gitignore,然后编辑文件。
规则
空格不匹配任意文件,可作为分隔符,可用反斜杠转义
#开头的模式标识注释,可以使用反斜杠进行转义
! 开头的模式标识否定,该文件将会再次被包含,如果排除了该文件的父级目录,则使用 ! 也不会再次被包含。可以使用反斜杠进行转义
/ 结束的模式只匹配文件夹以及在该文件夹路径下的内容,但是不匹配该文件
/ 开始的模式匹配项目跟目录
如果一个模式不包含斜杠,则它匹配相对于当前 .gitignore 文件路径的内容,如果该模式不在 .gitignore 文件中,则相对于项目根目录
*匹配多级目录,可在开始,中间,结束
?通用匹配单个字符
[]通用匹配单个字符列表
常用示例
忽略指定文件
project.pro.user 这种方法会忽略根目录下的该文件,其他路径下的同名文件不会忽略
忽略特定后缀的文件
*.o
忽略文件夹及文件夹下的所有内容
build/
忽略某一文件夹下的所有内容但是不忽略特定内容
build/
!build/temp/
5、导出补丁合并补丁
有些场景我们并不能直接提交代码到远程仓库,只能通过补丁的形式,将自己修改的代码合并到仓库当中。有两种形式diff文件和patch文件,diff没有commit信息,而patch存在commit信息,一个commit对应一个patch。
1 |
|
6、合并其他分支的commit
1 |
|
7、不同情况下新建分支
1 |
|
8、查看代码提交信息
1 |
|
结果如下图所示:
前面是commit-id,后面是提交者,时间以及具体代码段
9、查看某个commit所在分支
1 |
|
命令会列举出本地个远程仓库里面包含这个commit的所有分支
10、修改本地分支和远程分支映射关系
1 |
|
11、查看修改
1 |
|
12、重置代码
1 |
|
13、gerrit使用
1 |
|
这里origin是指gerrit上游,如果仓库里面有多个上游需要注意。HEAD表示最前面的提交,所以如果当前存在多个未合并的提交,会把几个提交一起
推送到gerrit,然后会存在依赖关系,合并前面的才能继续合并后面的,所以如果同时开发多个功能最好单独切分支。refs/for的作用表示合并前需要review,如果是refs/heads就不用review。master表示你要推送的分支。