注:本文主要基于Datawale组队学习git篇,若想快速入门git,可阅读第二、三、六章,当然,官方文档也是非常重要的参考资料。
一,git安装
详见官网
二,基础命令
1.获取git仓库
有两种方法可以获取仓库:本地目录转git仓库 和 其他服务器克隆一个git仓库 先来看看本地怎么创建仓库: 首先进入到需要版本管理的文件夹,使用cmd命令
git init
该命令会初始化一个.git的子目录 与远程仓库关联
git remote add origin https://github.com/xxxx/axxxx.git
看看怎么从其他服务器克隆一个git仓库,需要使用git clone命令,这个命令会把远程仓库的所有文件的所有版本都克隆下来
git clone https://github.com/yang-yun-gang/spring.git
首先在github建立一个名为spring的仓库 本地新建一个文件夹clone,然后在这个文件夹里执行git clone命令,可以看到spring这个项目就被克隆了下来,这种方式的好处是当远程仓库遇到问题不能使用后,也能把本地的传上去,因为本地保留了所有版本信息。 注:以上的远程获取仓库方法基于https协议,在github上还能看到其他诸如ssh等协议,也可以使用。
2.更新记录到仓库
在git看来,我们的文件分为两种:已跟踪和未跟踪。 首先要明确,只有已经git跟踪的文件才能被git看到和管理,未跟踪的文件git无法操作。 当文件被修改后,比如我们这里的readme.md,git会把它标记为已修改文件,我们需要把它提交到暂存区,然后再提交。
2.1 检查当前文件状态
可以用git status命令查看当前文件的状态,比如我们刚克隆下来的spring仓库
git status
如果我们新建一个文件之后呢,这里我们新建一个hello.md文件,再使用这个命令看看 可以看到,git把这个文件标记了出来,说明它是没有被追踪的文件(之前的版本没有这个文件),如果需要对它做管理,则需要手动跟踪。
2.2 跟踪新文件
git add hello.md
我们再一次查看仓库状态,可以看到它变为了to be committed,说明为暂存状态。
2.2 暂存已修改的文件
现在先不急提交,我们把readme.md修改下再看看。 可以看到,修改过后,readme变为了已修改,提示表明,它是not stage for commit,需要我们手动添加到暂存区。
git add readme.md
可以看到这个命令既适用于追踪新文件,也适用于修改过后的文件添加至暂存区,其实把它理解为“将内容添加到下一次提交种”更合适。 可以看到两个文件都已暂存(Changes to be committed),如果这个时候,你又去修改了readme会发生什么呢? 可以看到,它竟然出现在了两个地方,用版本号的知识想想,其实暂存区的版本不是最新的,还是我们这一次修改之前的版本。同样需要再一次把readme添加到暂存区。
2.3 忽略文件
有时候我们会不想让某些文件出现在未追踪列表,比如自动生成的日志文件或者编译生成的文件,这种情况创建一个名为.gitignore的文件,列出需要忽略的文件模式。
*.[ao]
上述表达式表示忽略所有以a或o结尾的文件。 更多例子如下:
*.a
!lib.a
/TODO
build/
doc/*.txt
doc/**/*.pdf
想探索更多使用方式,参考github的文档
2.4 查看未暂存和已暂存的修改
首先我们将hello.md再次修改,用git status命令可以看到未暂存的有hello.md文件,已暂存的有其余三个文件。 那么怎么去查看它们所做的更改呢? 首先查看未暂存的更改
git diff
可以看到,添加了#### hello 然后查看已暂存文件的更改
git diff --staged
2.5 提交更新
现在把所有文件都放入暂存区,全部提交
git commit
这个命令会生成一个文本编辑,注释包含一个git status的输出,开头的空行输入提交注释,提交之后,注释包含的内容并不会提交,只会提交我们写入的部分。 当然,还有一个更简洁的方式,不用再用vim编辑,太麻烦,就是在提交的时候,直接写入注释
git commit -m "second commit"
2.6 跳过使用暂存区域
每次都要把修改的文件移动到暂存,再提交,有点麻烦,有一种方式可以把暂存区和修改的文件全部提交
git commit -a -m "third commit"
2.7 移除文件
如果想要删除一个文件,这里想移除掉hello.md,可以直接使用
git rm hello.md
这时,hello就会从磁盘抹去,并且被移动到暂存区。 下一次提交后,就会完全从git删除。
但如果我们先从磁盘删除了它,会怎么样呢?用git status可以看到,它被标记为deleted,且处于not staged for commit。 这时,再使用git rm命令,hello.md会被移动到暂存区,提交就可以了。
如果仅仅只是想从git管理里面删除,并不想动文件,怎么办呢?rm命令直接把文件都删没了。
git rm --cached hello.md
2.8 查看提交历史
git log
这个命令有很多衍生功能,比如
git log -p
它会显示出每次提交的差异 而使用下面这个
git log --stat
可以统计每次提交的文件数
3.撤销操作
3.1 重新提交
如果发现提交信息写错了,或者说还有几个文件要在同一批次提交而未加上,可以使用以下命令重新提交上次的内容(会再一次提交暂存区的内容),覆盖掉上次提交的信息,也就是说,第二次提交将代替第一次提交的结果。
git commit --amend
这样可以避免多次“修正”提交扰乱版本信息。
3.2 撤销暂存
假如我们增加了两个文件,bbb.txt和bye.txt,并且把它们都加入了暂存区 这时,想要把bye.txt撤销,使用如下这个命令
git reset bye.txt
这样,它就回到之前的未被追踪状态了,当然,如果是修改操作就回到not staged for commit状态。
3.3 撤销对文件的修改
如果不想保留bbb.txt文件的更改怎么办?其实git status已经做足了提示了
git restore bbb.txt
这样更改就被revert了。(危险!因为撤销的东西都将不复存在!)
3.4 回退到某个版本
当程序出了问题,需要回退到历史的某个稳定版本时,可以使用以下命令
git revert <commit>
commit为提交的hash值。
4.远程仓库的使用
4.1 查看远程仓库
前面第1节,我们通过git clone获得了一个名叫spring的项目,在本地,我们可以通过以下命令查看远程仓库信息
git remote -v
origin是远程仓库的默认名字。
4.2 添加远程仓库
前面已经讲解了git clone方式的添加,现在讲解另一种方法
git remote add ct https://github.com/yang-yun-gang/coursera-test.git
ct代表本地起的仓库名 可以看到,现在存在两个远程仓库了,我们把ct仓库的东西拉下来。 有两种拉法,fetch和pull,前者仅仅只是拉取本地没有的文件,不会和本地文件合并,要想合并,只能用后者(需要设置远程分支跟踪)。
git fetch ct
4.3 推送到远程仓库
刚才对spring项目做了那么多操作,是时候提交今天一天的成果了
git push
也可以指定仓库名和分支
git push origin master
本地名和远程名不一样时
git push origin 本地名:远程名
5.标签
git可以给仓库的提交历史打标签,以标记像是版本号之类的东西,标签分为两种,一种是轻量标签(lightweight),一种是附注标签(annotated),我们先不解释意思,直接实践看看它们俩的区别。 先来看看附注标签,它最常用
git tag -a v1.0 "my version_v1.0"
-a表示打上附注标签,它会给上一个提交打上名为“v1.0”的标签,标签内容是“my version_v1.0”。现在看看log,前一个提交已经有标黄的v1.0字样了。 附注标签可以保存打标签的人,以及该次提交的基本信息,通过以下命令查看
git show v1.0
如果不加-a,就会创建轻量标签,轻量标签少了标签内容这个信息 前面是对最近的一次提交打标签,那么怎么对过去的其他历史这样做呢? 在末尾加上校验和
git tag -a v0 b2d4ac79fc73d8eb1632609c154a12396b5f77b0
对了,有加就有删除,有查看
git tag -d v0
git tag
一般情况,将代码提交到远程仓库的时候是不会带有标签的,相当于是本地皮肤,要想添加标签,只能在推送的时候输入–tags。
git push origin baseline_v1.0 --tags
可以在github看到,有了这些标签了。 有时候不想全部提交,就自己重写一个指定呗。
git push origin baseline_v1.0 v1.0
三、git分支管理
1.分支的相关操作
1.1 分支的创建
使用以下命令可以查看和创建分支,不带参数时,为查看分支
git branch
D:\渤海大学\学习资料\github\clone\spring>git branch
* main
创建分支很简单
D:\渤海大学\学习资料\github\clone\spring>git branch
baseline_v1.0
* main
带*表示当前分支在main上,我们可以切换分支
git checkout baseline_v1.0
D:\渤海大学\学习资料\github\clone\spring>git checkout baseline_v1.0
Switched to branch 'baseline_v1.0'
D:\渤海大学\学习资料\github\clone\spring>git branch
* baseline_v1.0
main
尝试在分支创建文件试试
type nul>baseline_v1.0.md
git add baseline_v1.0.md
git commit -m "update baseline_v1.0.md"
type nul>baseline_v1.0.html
git add baseline_v1.0.html
git commit -m "update baseline_v1.0.html"
这里在baseline_v1.0创建了两个文件,并分别提交,使用log命令看一看 这里可以明显看出分支的不同。 在两个分支查看文件列表,主分支显然无法看到这两个新创建的文件
1.2 分支的合并
在分支完成任务开发后,需要合并到主分支上
git checkout main
git merge baseline_v1.0
合并过程中,如果产生了冲突,且无法自动合并时,会提示CONFLICT,这时可以用git status查看冲突文件,解决办法有
分支的合并方式 分支有三种合并方式,–ff,–no-ff和–squash,要想知道三种合并方式区别,要先了解分支的基本原理。 首先,HEAD是什么? 我们可以在log里面看到HEAD字样,也可以在.git文件里看到HEAD这个文件,它表示当前代码所指向的分支,参考第五节,可以看到.git里的HEAD存放的是一个ref(如ref: refs/heads/baseline_v1.0),指向的是.git/refs/heads的一个分支名文件,而这个分支名文件存的是最新一次提交的hash码,也就是说,可以用下图表示这种关系, 其实,heads目录下的分支名文件,存放的也是指向最近提交记录的hash字符。 理解了这个,我们再来理解分支的合并,以下是三种分支的合并方式。
- -ff(fast-forward)。不带参默认的合并方式,如果主分支顺着节点走能到达另外一个待合并分支,就会简单的将HEAD和master后移。
- --no-ff。取消ff这种模式,不管主分支能不能走到另外一个分支,都创建一个commit信息。
- -squash。如果待合并分支的提交过于凌乱,就将他们合并。
一般开发中,使用--no-ff这种方式,因为ff这种方式会将待合并分支的提交历史混入到主分支中,导致我们在做版本回退的时候,受到干扰。
1.3 分支推送到远程
指定仓库和分支进行推送
git push origin baseline_v1.0
注意,多人开发的时候,需要先pull试图合并,再推送上去。
1.4 分支删除
删除本地分支
git branch -d branchName
删除远程分支
git push origin --delete branchName
1.5 分支重命名
git branch -m oldBranchName newBranchName
当我们想要将改名后的分支推送到远程时,只能先改名,再推送,然后删除远程旧分支
git branch -m oldBranchName newBranchName
git push origin newBranchName
git push --delete origin oldBranchName
1.6 分支的作用
一般来说,main主分支都是稳定的代码,放在远程,本地拉去的都是它的分支,待代码稳定之后,再合并到主分支上。
四,git工具
1.引用修订版本
1.1 引用commit记录
使用git log可以看到,commit后都有一个40个字符的串,它能够保证多年后,重新checkout某个commit时,一定和当时的状态一模一样。 先要查看某次提交的信息,可以
git show 0daa48589a136b2c36cc0d0cf0dadecc440f4317
git show 在无歧义的情况下,支持最左匹配。
1.2 引用分支
前面说过,查看本地分支可以通过git branch查看,当然我们也可以查看远程分支
git branch -r
也可以查看指定分支最后一次的提交信息
git show baseline_v1.0
1.3 引用日志
可以查看git的head变化和提交历史。
git reflog
2.交互式暂存
2.1 暂存,取消文件
如果运行 git add 后加 -i 的时候,Git 会进入一个交互式命令模式
git add -i
可以看到,分为了暂存区和未暂存区两个部分,并且也有指令提示,what now在等待交互式输入。 比如,现在要将baseline_v1.0.md存入暂存区,首先输入u,然后输入暂存的编号,这里是1,可以看到有个*代表等待确认,最后回车即可提交。也可以输入3或者r来取消暂存。 这样,就可以很方便的操作暂存区了。
2.2 暂存补丁
git可以暂存文件的特定部分,在交互式界面输入5或p
3.储藏与清理
3.1 储藏当前工作信息
文件被修改了很多,这时需要切换分支,但我又不想提交,怎么办呢?可以先把变更推送到栈上
git stash
可以看到,原先的文件没有了,这时可以任意切换分支工作。 工作处理完成后,想把那个文件拿回来咋办?首先查看栈列表
git stash list
可以通过git stash apply 拿到最后的变更,也可以通过 git stash apply stash@{n} 中的 n 来获取指定的的变更。 通过 git stash drop 或者 git stash pop 来删除 stash 的内容。
3.2 清理工作目录
- git clean。移除未被跟踪的文件。
- git stash --all。移除所有文件并保存到栈上。
4.打包
git可以将数据打包到一个bundle文件中,这个文件是一个二进制文件,可以发送给别人,其他人就可以解包到仓库。 打包命令如下,需要指定HEAD,如果不指定,那么解包的时候就需要手动指定。
git bundle create repo.bundle HEAD main
解包命令如下,类似于从远程仓库拉取代码。如果打包没有加HAED,就需要在后面指定分支(如-b main)
git clone repo.bundle repo
五,git内部管理
1 .git目录结构
目录结构如下(后续章节会对 *开头 的目录详细介绍):
├── *config 配置信息(比如本地repo是否大小写敏感, remote端repo的url, 用户名邮箱等)
├── description 无需关心(仅供GitWeb程序使用)
├── *HEAD 目前被检出的分支
├── index 保存暂存区信息
│
│
├── hooks/ 钩子脚本(执行Git命令时自动执行一些特定操作)
├── info/ 包含一个全局性排除文件
│ └── exclude 放置不希望被记录在 .gitignore 文件中的忽略模式
├── logs/ 记录所有操作
├── *objects/ 存储所有数据内容
│ ├── SHA-1/ 保存git对象的目录(三类对象commit, tree和blob)
│ ├── info/
│ └── pack/
└── *refs/ 存储指向数据(分支、远程仓库和标签等)的提交对象的指针
├── heads/
├── remotes/
└── tags/
2 objects目录 —— 对象存储
初始化仓库时,该目录只有两个空文件夹,pack和info,当使用一段时间后,会增加很多子目录 这些子目录存的文件如下所示 这些新加的文件夹代表什么呢?这里,就要谈及git的存储方式了。 git以对象的方式存储数据,主要分为三种对象:数据对象(blob),树对象(tree)和提交对象(commit),git会根据对象内容生成一个40个字符的SHA-1哈希值,例如ee2b8364542e6512c6ff1d906cfa3787731f3ec2,git会截取前两个字符,作为文件夹名字,后38个字符作为文件名。这样就形成了上图所示的结构。
3 objects目录 —— 包文件的存储机制
使用以下命令,看看会发生什么
git gc
再次进入objects文件夹,发现很多对象文件不见了,而info和pack目录非空 其实,这个命令实现了将对象打包,将版本库中松散的对象包在一起,在推送的时候也会这样做,而这个.pack就是刚才打包的对象内容。
4 refs目录 —— 引用
refs目录存在三个文件夹,heads、remotes、和tags。
.git/refs
├── heads 记录本地分支的最后一次提交
│ ├── baseline_v1.0 记录最后一次提交的commitHash
├── remotes 记录远程仓库各分支的最后一次提交
│ └── origin
│ └── HEAD 被检出的分支
│ └── baseline_v1.0 记录最后一次提交的commitHash
├── tags
│ └── v1.0 记录commitHash
│ └── v1.1
│ └── v1.2_lw
└── stash
关于head,有两个地方可以看到这个东西: 第一个地方在.git/HEAD文件,里面存放的是当前代码所处的分支(ref: refs/heads/baseline_v1.0); 第二个地方在.git/refs/heads文件夹,目录包含了本地分支的最后一次提交 baseline_v1.0存放的是提交的hash字符(032a42c7b63a93ce5dbd733d0e3f5e0bf62683d0)。
六,GitFlow工作流实战
1.工作流简介
工作中,通常会经常见到以下几个分支
分?名称 | 作? | ?命周期 | 提交or合并 | 起?点 |
---|
Feature分? | ?于某个功能的 | 临时分 ?、开发 阶段 | 可提交代码 | 由Develop分?产?, 最终合并到Develop 分? | Develop分? | 记录历史开发功 能 | 贯穿整个 项? | 不能提交,由Feature分 ?、Bugfix分?、Release 分?、Hotfix分?合并代码 | 整个项? | Release分? | ?于本次Release 如?档、测试、 bug修复 | 临时分 ?、发版 阶段 | 可提交代码 | 由Develop分?产?, 最终合并到Develop 分?和Master分支 | Hotfix分? | ?于解决线上bug | 临时分 ?、紧急 修复阶段 | 可提交代码 | 由Master分?产?, 最终合并到Develop 分?和Master分支 | Master(Production) 分? | 记录历史发布版 本 | 贯穿整个 项? | 不能提交,由Release、Hotfix分?合并代码 | 整个项? |
分支的进一步理解:
-
?命周期 Master分?和Develop分?贯穿项?;其他分?均为承担特定指责的临时分?。 -
项?阶段 开发阶段主要涉及Feature分?、Develop分?; 发布阶段 主要涉及Release分?、Production分?、Develop分?; 紧急修复阶段 主要涉及Hotfix分?、Production分?、Develop分?。 -
成员关注点 开发?员 关注Develop分?、Feature分?以及特殊阶段关注Hotfix、Release分?的bug修复; 测试?员 关注 Release分?、Hotfix分?的功能测试;项?经理 关注Production分?、Release分?。
2.初始化项目,创建develop分支
初始化一个项目 创建Develop分支,并切换过去
git branch develop
git checkout develop
3.模拟开发阶段过程
开发过程简介:在develop分支上创建新功能Feature分支,实现一个用户登录模块,然后合并到develop分支,删除功能分支。 1.在develop分支上创建新功能Feature分支
git branch develop
git checkout feature-login
2.实现一个用户登录模块 新建LoginUser.html文件,内容如下所示 同样,新建LoginUser.js文件,内容为"hi this is user js"。 3.提交新开发的模块 这里需要分两次提交
git add LoginUser.html
git commit -m "feat: add LoginUser.html"
git add .
git commit -m "feat: add LoginUser.js"
4.将feature-login上所作的开发合并到develop上,并删除feature-login 注意,需要切回要合并的主分支
git checkout develop
git merge --no-ff feature-login
git branch -d feature-login
4.模拟Release阶段过程
过程简介:创建Release分?、进?bug修复、合并到Master分?与Develop分? Release分?基于Develop分?创建,修复LoginUser.html的bug如下 过程如下:
git branch release-v0.1
git checkout release-v0.1
git add .
git commit -m "fix: bugfix for LoginUser.html"
git checkout master
git merge --no-ff release-v0.1
git tag v0.1
git checkout develop
git merge --no-ff release-v0.1
git branch -d release-v0.1
5.模拟线上故障,创建Hotfix分支
创建Hotfix分支、进行bug修复、合并到Production分?与Develop分支 流程如下:
git checkout master
git branch hotfix-v0.1.1
git checkout hotfix-v0.1.1
git add .
git commit -m "hotfix: do something for LoginUser.html"
git checkout master
git merge --no-ff hotfix-v0.1.1
git tag v0.1.1
git checkout develop
git merge --no-ff hotfix-v0.1.1
git branch -d hotfix-v0.1.1
七,Git提交规范
参考Angular的提交标准:Commit Message Format 一个commit通常包含以下信息
- commit message - 提交的内容相关描述
- author & committer - 作者及提交者
- changed files - 修改的文件
- hash & parent - 提交内容的hash及在提交树上的位置
1.Commit Message
当前提交的功能相关信息,一般可以包括header,body,footer,其中header是必填的(建议50个字符以内),也是最为重要的内容。
<type>(<scope>): <short summary>
│ │ │
│ │ └─? 提交的简短总结
│ │
│ └─? 提交范围(改动的影响范围): animations|bazel|benchpress|common|compiler|compiler-cli|core...
│
└─? 提交类型: build|ci|docs|feat|fix|perf|refactor|test
在header里面,type和summary都是必填,提交类型意思如下
build : 涉及构建相关的改动ci : 持续集成相关的改动docs : 文档feat : 新功能fix : bug修复perf : 性能相关改动refactor : 重构相关(非bug、非新功能)test : 测试相关,包括新增测试或者更改已有测试
body和footer都是选填,body为summary更为详细的描述,footer是对破坏性改动,功能弃用的说明。 这些规范的提交信息,最后可以自动化生成文档或发布日志。 对于提交信息,git提供了校验方式,在.git/hooks文件夹,具体参考官方文档,如果校验不通过,则不会提交成功。
2.Author & Committer
Git中,Author表示原始纂写该提交的作者,Committer表示应用该提交的人,如合并Pull Request 的项目管理员。 在企业开发时,可以针对不同的仓库,设置不同的用户和邮箱,比如全局设置个人github账户,企业内部设置企业邮箱。
git config --global user.email "<github email>"
git config --global user.name "<github username>"
git config user.email "<enterprise email>"
git config user.name "<real name>"
3.Changed files
文件提交规则:
- 提交前使用
git diff 查看文件的改动,使用git add 添加期望进入提交的文件, 使用git status 查看文件状态,最终使用git commit 进行提交 - 单次提交仅提交相关的改动,例如修复两个不同的bug应该使用两次独立的提交
- 鼓励经常性的提交,这样可以更快的分享实现的功能,并且减少代码丢失的风险
- 在主分支或者协作的功能分支不能提交半成品,提交之前需要进过测试
- 编译输出,日志,中间产物等,不要引入到提交中,使用
.gitignore 进行相关文件的排除,不同语言 或者操作系统有一些通用的排除配置,参考github/gitignore - 密码、授权凭证、密钥等,不要提交。如AWS的certificate.csv文件或内容,
GCP的Service Account文件等,泄露到公开仓库会导致资源被不法分子使用,造成损失。同时由于Git的特性, 想从历史提交中移除这类文件会较为困难,参考GitHub官方相关文档及描述 - 对于配置文件(如数据库连接信息等),一般使用配置模板,个人维护本地文件,且该文件在
.gitignore 中配置。或者使用git update-index --[no-]assume-unchanged <file> 来忽略某些文件的改动 - 其他一些常用命令(请在明确知道其含义后使用)
git reset <file> - 移除被添加的文件(提交之前),reset 命令的其他可以查看帮助文档git clean -f - 移除较多的未被追踪的中间文件git checkout <file> - 回退对某个文件的改动(提交之前)
八,github仓库界面介绍
- star,代表点赞
- fork,代表别人从当前分支又分出去的分支,多用于协同合作,对应的是Pull requests
- watch,可以设置什么时候向邮箱推送仓库的推送信息
- Issues,别人给你提的问题,通常是bug,新功能推荐(不是讨论)
- Pull requests,拉取请求,别人fork你的项目后,最后完成了新功能开发,这时候就要请求你进行主动的合并
- Actions,GitHub推出的自动化构建工具
- Projects,针对某一仓库的项目板(看板)
- wiki,用于一些介绍性的内容,答疑等
- Security,安全相关
- Insights,项目的提交数据,每个人的贡献量
|