一、Git简介
用一句话来说:
Git是目前世界上最先进的分布式版本控制系统(没有之一)
Git有什么特点:简单的来说就是:高端大气上档次
那什么是版本控制系统?
版本控制就是,每次改动时,都有明确的改动时间,和改动了什么东西,能够记录文件的改动
什么是分布式?
每个人的电脑都是一个完整的版本库,这样修改的时候就不需要联网,如果两个人同时修改了文件A,这时你们只需要把修改的传给对方,就可以看到相互修改的内容。
在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。
二 、Git 安装和配置
安装
如果在window上使用,可以从Git官网上直接下载Git安装程序,然后一路默认就可以了
安装完成后,在开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功!
[图片上传失败...(image-235b9a-1562430737358)]
配置
首先在没有创建本地仓库前需要进行全局变量配置:
1,设置和修改用户名和邮箱地址:(这个一步是必须要有的)
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"
注:其中 --global 是对全局进行配置就是在修改 C:\Users\Administrator.gitconfig ,只针对当前计算机用户有用。 git config --system 是针对全部计算机用户 文件位置/etc/gitconfig
2,用户名和邮箱的作用
因为Git是分布式的,所以需要知道你是谁
每次commit 都会用用户名和邮箱来记录
github的contributions统计就是按邮箱来统计的
3,查看用户名和邮箱地址和全部设置:
$ git config user.name
$ git config user.email
$ git config -list
$ git config -l
创建本地版本库
什么是版本库?
版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
创建版本库目录
$ mkdir learngit
$ cd learngit
$ pwd
mkdir 创建目录的意思
cd 进入目录,如果想进入D盘 cd D:
pwd 查看当前目录路径
把这个目录设置成Git可以管理的仓库
$ git init
Git会自动生成一个隐藏的.git的目录,是用来跟踪管理版本库的。现在Git就会对这个文件夹的文件进行版本管理了
三、理解新的概念,文件流转中的三个区
Git 的工作区,暂存区域,以及本地仓库。下图中包括了远程仓库,可以理解为GitHub
[图片上传失败...(image-b32863-1562430737358)]
工作区
工作区就是你干活的地方,你生产的文件都在这个目录中,修改添加,删除等。
工作目录下的文件基本上就两种状态:已经跟踪,未跟踪(untracked)。 注:除了隐藏的.git目录
未跟踪文件(untracked)一般是新建的,它们并没有出现在前面的版本中,也不在当前的暂存区域。
已经跟踪的文件,目前它们的状态可能是未更新(unmodified,查看文件状态时默认是不显示出来的),已修改(modified)或者已放入暂存区(staged)
[图片上传失败...(image-e60212-1562430737358)]
1,$ git status 查看工作区所有文件的状态
$ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
.gitignore
.idea/
nothing added to commit but untracked files present (use "git add" to track)
$ git status 文件的详细状态,和提示。
如下情况:
1,只出现 On branch masternothing to commit, working tree clean,表示目前工作区的文件和最新版本库里的文件 是一样的。没有修改,没有新增加,没有删除
2,Untracked files 表示没有追踪的新建文件,就是从来没有添加过的文件
3,如果版本库或缓存区中有这个文件,就提示Changes not staged for commit 其中分下面几个情况:
new file 第一次提交到缓存区的文件
modified (红色的字) 修改的文件没有提交到缓存区
[图片上传失败...(image-ccd179-1562430737358)]
modified (绿色的字)修改的文件已经提交到缓存区
[图片上传失败...(image-a47e31-1562430737358)]
deleted (红色的字) 就是当前工作区的某个文件已经被删除,版本库中还存在
[图片上传失败...(image-b04a43-1562430737358)]
2,$ git status -s 查看
$ git status -s
?? .gitignore
?? .idea/
会出现状态码 ?就是代表没有管理的没有跟踪的
A: 你添加工作区的文件的文件(版本库上没有).
C: 文件的一个新拷贝.
D: 你本地删除的文件(版本库上还在).
M: 工作区的文件被修改了或者mode被修改了.
R: 文件名被修改了。
T: 文件的类型被修改了。
U: 文件没有被合并(你需要完成合并才能进行提交)。
X: 未知状态(很可能是遇到git的bug了,你可以向git提交bug report)
?:未被git进行管理,可以使用git add file1把file1添加进git能被git所进行管理
3,撤销工作区的文件修改
撤销还没有提交到缓存区的文件修改如下:
[图片上传失败...(image-931a6-1562430737358)]
你可以发现,Git会告诉你,git checkout -- file可以丢弃工作区的修改:
$ git checkout -- readme.txt
命令git checkout -- readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,重新生成这个文件上次的状态。在缓存区或版本库。
4,查看文件是如何被修改的
比如你休假两周从不知道从什么地方回来,第一天上班时,查看了当前文件的状态:
[图片上传失败...(image-6a6ce1-1562430737358)]
发现是被修改过的,但是你又不记得是如何修改的,需要用git diff这个命令看看:
$ git diff xhl.txt
diff --git a/xhl.txt b/xhl.txt
index d3720b6..defa7ea 100644
--- a/xhl.txt
+++ b/xhl.txt
@@ -1 +1,2 @@
-1111111111111111
\ No newline at end of file
+1111111111111111
+222222222222222222
\ No newline at end of file
git diff顾名思义就是查看difference,显示的格式正是Unix通用的diff格式,和当前版本库中的做对比
缓存区
1,添加文件到缓存区
语法:git add 文件名字
$ git add readme.txt
$ git add .
$ git add . 提交工作区的所有修改的文件文件
如果什么都没有提示:就代表添加完成 此时用 git status来看这个文件的状态
[图片上传失败...(image-74fc26-1562430737358)]
在工作区中我介绍的有
2,撤销缓存区的文件
如图:
[图片上传失败...(image-de0db3-1562430737358)]
Git同样告诉我们,用命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回工作区:
$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt
版本库
1,把缓存区文件提交到版本库
每提交一次就是一个新的版本,就会记录一次。
提交到版本库语法:$ git commit -m add "修改信息的描述"
$ git commit -m"初始项目"
[master (root-commit) 92f03d3] 初始项目
3 files changed, 19 insertions(+)
create mode 100644 .gitignore
create mode 100644 readme.txt
create mode 100644 xhl.txt
commit 会把 缓存区中的所有文件添加到版本库中。
2,删除版本库中的文件
上面工作区我们说到如果直接删除文件在查询会提示你当前文件被删除,当你选择,真的在版本库中删除这个文件:
$ git rm xhl.txt
rm 'xhl.txt'
$ git commit -m "remove xhl.txt"
[master d46f35e] remove xhl.txt
1 file changed, 1 deletion(-)
delete mode 100644 xhl.txt
执行上面的命令后这个文件在最新的版本库中就删除掉了。当然可以回退
3,恢复被误删的文件
如果你是不小心把文件给删除了当然也是可以恢复的
$ git checkout -- test.txt
有没觉得很眼熟,对了这个就是 撤销工作区修改时我们用的命令,上面我也说过这个命令就是,重新生成这个文件上次的状态。在缓存区或版本库,如果缓存区中没有这个文件,就到版本库中去找。
4.时光倒流,版本回退
每次commit都是一个版本,你可以选择回到任何一个版本:
首先你要你知道你想要回到那个版本的名字,当然这个名字是GIt帮你生成好的,你需要查看如下命令:
$ git log
git log 是显示空的仓库到目前这个版本,经历了多少个版本的变化。
[图片上传失败...(image-6c23a5-1562430737358)]
这里每条黄色字体后面的一串字符 就是每个版本的名字
HEAD 就是代表指针的意思,Git告诉我们当前版本库中用的是那个版本
如果想清楚一点:
$ git log --pretty=oneline
[图片上传失败...(image-645f25-1562430737358)]
修改指针的指向就是在修改版本如下:
$ git reset --hard HEAD^ #回到上一个版本的意思
$ git reset --hard 92f0 # 后面写上回到那个版本的名字,可以写前几个数字,不能太少,自少有四个
比如我要回到 初始项目的版本 92f03d3720ed4137a408902373fb729e0a68edab 它的名字就是这个,只需要西写前几个就可以了。
会自动帮你创建文件并生成。
[图片上传失败...(image-73b7ee-1562430737358)]
此时的log只有一条记录了。那我如何回到我的最新的版本,别急容我慢慢道来。
你现在可以看到命令行里的记录 然后直接 根据每个版本的名字直接回去就OK了,是不是很简单,但是如果你回到历史版本后,然后关掉了命令窗口,那只能,。。。这样了:
Git提供了一个命令git reflog用来记录你的每一次命令:
$ git reflog
[图片上传失败...(image-f0b251-1562430737358)]
它记录了你每一条命令的执行,然后根据命令回退版本就行。
四、创建远程仓库
添加远程仓库
1,登陆GitHub创建远程版本库,把本地的push上去
首先,登陆GitHub,然后,在右上角找到“Create a new repo”按钮,创建一个新的仓库:
[图片上传失败...(image-e4766e-1562430737358)]
在Repository name填入learngit,其他保持默认设置,点击“Create repository”按钮,就成功地创建了一个新的Git仓库:
[图片上传失败...(image-a50baf-1562430737358)]
目前,在GitHub上的这个learngit仓库还是空的,GitHub告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库。
$ git remote add origin git@github.com:TianHenxuan/learngit.git
这个一步是把本地仓库和远程仓库关联起来
请千万注意,把上面的michaelliao替换成你自己的GitHub账户名,否则,你在本地关联的就是我的远程库,关联没有问题,但是你以后推送是推不上去的,因为你的SSH Key公钥不在我的账户列表中。
或者使用下面的创建:
$ git remote add origin https://github.com/TianHenxuan/learngit.git
添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。
下一步,就可以把本地库的所有内容推送到远程库上:
$ git push -u origin master
把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程。
因为一个本地仓库可以对应多个远程仓库,比如github,码云,自己打架的git服务器等,-u表示指定一个默认的远程仓库,我们在更新origin仓库时,直接使用git push就是向默认的远程仓库更新分支。
其他命令:
$ git push origin dev #提交其他分支
$ git push origin --delete dev #删除远程dev分支
$ git push origin # 默认提交主分支
$ git push -u origin master # 设置默认远程仓库origin 和 master分支
$ git push # 有默认仓库和分支可以直接提交
2,先创建远程仓库,然后在本地clone远程仓库
先在github网站上创建一个远程仓库如下:
[图片上传失败...(image-4b83d0-1562430737358)]
$ git clone git@github.com:TianHenxuan/gitskills.git
$ git clone https://github.com/TianHenxuan/learngit.git
#两种方式都可以,随便用一个
$ git remote #查看远程仓库
$ git remote #查看远程仓库的详细信息
注意:
1,clone 会克隆所有的节点,但是只会克隆一个master分支
2,创建 git clone -b 分支名字 克隆某一个分支
3,git branch -a 查看所有分支
4, git checkout -t origin/dev 创建和远程一样的分支,并关联跟踪,进入分支
6,如果远程的版本比较新,不能顺利的进行融合的话,则需要 $ git pull 然后手动修改 然后在上传
3,创建分支
当主世界(master)我称为大千世界发展到某一时刻时候,你发现太无聊了,想弄一个,小千世界玩玩,于是你使用了这个条命令git branch dev ,创建了名字叫dev的小千世界,Git是如何做的呢
首先Git会把主世界的所有节点的数据复制一份,来作为小千世界的基础数据。
[图片上传失败...(image-649c51-1562430737358)]
首先在git里有一个默认的分支master,默认为主分支。
如何创建新的分支:
$ git branch #列出本地分支列表
$ git checkout -b dev #相当于 git branch 和 git checkout组合 创建并切换分支
$ git branch dev #创建新的分支 dev代表分支名字
$ git checkout dev #切换到 dev的分支
$ git branch -a #查看本地和远程分支
$ git branch -m dev version #修改分支名字
$ git push origin dev #更新当前dev到远程仓库
$ git branch -d dev #删除dev分支
$ git checkout master #先切换到分支
$ git merge dev # 合成分支
4,融合分支
现在,两个世界正常发展,虽然两个世界数据是相同的,但是由于一些不能把控的因素,两个世界都发展出了,除相同的部分,还有了不同的部分。
master--->相同部分 ---> 仙术时代
dev ---->相同部分---->科技时代---->蒸汽时代
你作为宇宙的掌控者,是多么的孤独,你又开始无聊了,不能忍了,想让两个世界融合。
于是你使用了下面的代码:
$ git checkout master #首先你进入了master大千世界
$ git merge dev #你在大千世界里用了某个牛B的神器,把dev小千世界当前状态数据取了出来
$ git merge --no-ff -m "merge with no-ff" dev # 直接commit 然后添加描述信息
[图片上传失败...(image-9f1c11-1562430737358)]
你的神器告诉你,自动融合失败,需要你手动修改xhl.txt的冲突后提交。
[图片上传失败...(image-3b7d05-1562430737358)]
你打开文件后,发现你的神器还是有点用的, 标记出了当前状态的大千世界(master)和小千世界(dev)不同的地方。这时你想还算可以了,不然早就把你给毁灭了消失在无边无际的宇宙中。
你修改完成后,把新的数据融合到大千世界:从此开始了科技仙术时代。
$ git add xhl.txt
$ git commit -m " xhl.txt"
[图片上传失败...(image-910dae-1562430737358)]
或者你可以先把dev世界的状态切换到蒸汽时代,在与master世界融合,这样就开启了 蒸汽仙术时代(这个时代啥样的,咱也不知道。)
5,git每个节点的理解
你的每一次commit,都会创建一个快照,我称为节点。或者融合时的自动commit。
master分支和feature1合并如下图所示:
[图片上传失败...(image-870ee6-1562430737358)]
$ git log --graph #分支合并图
$ git log --graph --pretty=oneline #简洁的分支合并图
$ git log --graph --pretty=oneline --abbrev-commit #简洁的分支合并图
6,bug修复
你可能用到,
Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:
$ git stash #把当前工作区的内容隐藏起来,储存起来
$ git stash list #查看修改的内容
$ git stash pop #恢复工作区的内容,并且删除隐藏的工作区内容
$ git stash apply # 只恢复工作区的内容, 不删除隐藏的工作区的内容。
$ git stash drop # 用这个删除。
$ git stash #多次 stash
$ git stash apply stash@{0} # 可以用序号单独恢复
首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支:
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
(use "git push" to publish your local commits)
$ git checkout -b issue-101
Switched to a new branch 'issue-101'
现在修复bug,然后提交:
$ git add readme.txt
$ git commit -m "fix bug 101"
[issue-101 4c805e2] fix bug 101
1 file changed, 1 insertion(+), 1 deletion(-)
修复完成后,切换到master分支,并完成合并,最后删除issue-101分支
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
(use "git push" to publish your local commits)
$ git merge --no-ff -m "merged bug fix 101" issue-101
Merge made by the 'recursive' strategy.
readme.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
git branch -d issue-101 #删除分支
如果没有进行融合就删除:
git branch -d issue-101 #删除分支
git branch -D issue-101 # 强行删除分支,如果没有融合提示你不能添加删除,就要强行删除
4,rebase
$ git rebase
让输出更美观,直接点。
$ git log --graph --pretty=oneline --abbrev-commit
* 7e61ed4 (HEAD -> master, origin/master) add author
* 3611cfe add comment
* f005ed4 set exit=1
* d1be385 init hello
rebase操作可以把本地未push的分叉提交历史整理成直线;
rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比。
5,创建标签
在Git中打标签非常简单,首先,切换到需要打标签的分支上:
$ git branch
* dev
master
$ git checkout master
Switched to branch 'master'
然后,敲命令git tag <name>就可以打一个新标签:
$ git tag v1.0
可以用命令git tag查看所有标签:
$ git tag
v1.0
默认标签是打在最新提交的commit上的。有时候,如果忘了打标签,比如,现在已经是周五了,但应该在周一打的标签没有打,怎么办?
方法是找到历史提交的commit id,然后打上就可以了:
$ git log --pretty=oneline --abbrev-commit
12a631b (HEAD -> master, tag: v1.0, origin/master) merged bug fix 101
4c805e2 fix bug 101
e1e9c68 merge with no-ff
f52c633 add merge
cf810e4 conflict fixed
5dc6824 & simple
14096d0 AND simple
b17d20e branch test
d46f35e remove test.txt
b84166e add test.txt
519219b git tracks changes
e43a48b understand how stage works
1094adb append GPL
e475afc add distributed
eaadf4e wrote a readme file
比方说要对add merge这次提交打标签,它对应的commit id是f52c633,敲入命令:
$ git tag v0.9 f52c633
再用命令git tag查看标签:
$ git tag
v0.9
v1.0
注意,标签不是按时间顺序列出,而是按字母排序的。可以用git show <tagname>查看标签信息:
$ git show v0.9
commit f52c63349bc3c1593499807e5c8e972b82c8f286 (tag: v0.9)
Author: Michael Liao <askxuefeng@gmail.com>
Date: Fri May 18 21:56:54 2018 +0800
add merge
diff --git a/readme.txt b/readme.txt
...
还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字:
$ git tag -a v0.1 -m "version 0.1 released" 1094adb
命令git tag <tagname>用于新建一个标签,默认为HEAD,也可以指定一个commit id;
命令git tag -a <tagname> -m "blablabla..."可以指定标签信息;
命令git tag可以查看所有标签。
如果标签打错了,也可以删除:
$ git tag -d v0.1
Deleted tag 'v0.1' (was f15b0dd)
因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。
如果要推送某个标签到远程,使用命令git push origin <tagname>:
$ git push origin v1.0
Total 0 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git
* [new tag] v1.0 -> v1.0
或者,一次性推送全部尚未推送到远程的本地标签:
$ git push origin --tags
Total 0 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git
* [new tag] v0.9 -> v0.9
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
$ git tag -d v0.9
Deleted tag 'v0.9' (was f52c633)
然后,从远程删除。删除命令也是push,但是格式如下:
$ git push origin :refs/tags/v0.9
To github.com:michaelliao/learngit.git
- [deleted] v0.9
命令git push origin /<tagname/>可以推送一个本地标签;
命令git push origin --tags可以推送全部未推送过的本地标签;
命令git tag -d /<tagname/>可以删除一个本地标签;
命令git push origin :refs/tags///<tagname/>可以删除一个远程标签。
6,忽略特殊文件
有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件啦,等等,每次git status都会显示Untracked files ...,有强迫症的童鞋心里肯定不爽。
好在Git考虑到了大家的感受,这个问题解决起来也很简单,在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。
不需要从头写.gitignore文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore
忽略文件的原则是:
忽略操作系统自动生成的文件,比如缩略图等;
忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。
举个例子:
假设你在Windows下进行Python开发,Windows会自动在有图片的目录下生成隐藏的缩略图文件,如果有自定义目录,目录下就会有Desktop.ini文件,因此你需要忽略Windows自动生成的垃圾文件:
# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini
# Python:
*.py[cod]
*.so
*.egg
*.egg-info
dist
build
# My configurations:
db.ini
deploy_key_rsa
最后一步就是把.gitignore也提交到Git,就完成了!
有些时候,你想添加一个文件到Git,但发现添加不了,原因是这个文件被.gitignore忽略了:
强制添加文件
$ git add -f App.class
或者你发现,可能是.gitignore写得有问题,需要找出来到底哪个规则写错了,可以用git check-ignore命令检查:
$ git check-ignore -v App.class
.gitignore:3:*.class App.class
忽略某些文件时,需要编写.gitignore;
.gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理!
7,配置别名
有没有经常敲错命令?比如git status?status这个单词真心不好记。
如果敲git st就表示git status那就简单多了,当然这种偷懒的办法我们是极力赞成的。
我们只需要敲一行命令,告诉Git,以后st就表示status:
$ git config --global alias.st status
当然还有别的命令可以简写,很多人都用co表示checkout,ci表示commit,br表示branch:
$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch
以后提交就可以简写成:
$ git ci -m "bala bala bala..."
--global参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有用。
在撤销修改一节中,我们知道,命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回工作区。既然是一个unstage操作,就可以配置一个unstage别名:
$ git config --global alias.unstage 'reset HEAD'
配置一个git last,让其显示最后一次提交信息:
$ git config --global alias.last 'log -1'
甚至还有人丧心病狂地把lg配置成了:
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
配置文件
配置Git的时候,加上--global是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用。
配置文件放哪了?每个仓库的Git配置文件都放在.git/config文件中:
$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "origin"]
url = git@github.com:michaelliao/learngit.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
[alias]
last = log -1
别名就在[alias]后面,要删除别名,直接把对应的行删掉即可。
而当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig中:
$ cat .gitconfig
[alias]
co = checkout
ci = commit
br = branch
st = status
[user]
name = Your Name
email = your@email.com
配置别名也可以直接修改这个文件,如果改错了,可以删掉文件重新通过命令配置。
以上文章参考和转载:
https://www.liaoxuefeng.com/wiki/896043488029600
https://www.yiibai.com/git
https://www.cnblogs.com/wenxuehai/category/1274094.html