基础篇

github术语

Repository:简称Repo,可以理解为“仓库”,我们的项目就存放在仓库之中。也就是说,如果我们想要建立项目,就得先建立仓库;有多个项目,就建立多个仓库。

Issues:可以理解为“问题”,举一个简单的例子,如果我们开源一个项目,如果别人看了我们的项目,并且发现了bug,或者感觉那个地方有待改进,他就可以给我们提出Issue,等我们把Issues解决之后,就可以把这些Issues关闭;反之,我们也可以给他人提出Issue。

Star:可以理解为“点赞”,当我们感觉某一个项目做的比较好之后,就可以为这个项目点赞,而且我们点赞过的项目,都会保存到我们的Star之中,方便我们随时查看。在 GitHub 之中,如果一个项目的点星数能够超百,那么说明这个项目已经很不错了。

Fork:可以理解为“拉分支”,如果我们对某一个项目比较感兴趣,并且想在此基础之上开发新的功能,这时我们就可以Fork这个项目,这表示复制一个完成相同的项目到我们的 GitHub 账号之中,而且独立于原项目。之后,我们就可以在自己复制的项目中进行开发了。

Pull Request:可以理解为“提交请求”,此功能是建立在Fork之上的,如果我们Fork了一个项目,对其进行了修改,而且感觉修改的还不错,我们就可以对原项目的拥有者提出一个Pull请求,等其对我们的请求审核,并且通过审核之后,就可以把我们修改过的内容合并到原项目之中,这时我们就成了该项目的贡献者。

Merge:可以理解为“合并”,如果别人Fork了我们的项目,对其进行了修改,并且提出了Pull请求,这时我们就可以对这个Pull请求进行审核。如果这个Pull请求的内容满足我们的要求,并且跟我们原有的项目没有冲突的话,就可以将其合并到我们的项目之中。当然,是否进行合并,由我们决定。

Watch:可以理解为“观察”,如果我们Watch了一个项目,之后,如果这个项目有了任何更新,我们都会在第一时候收到该项目的更新通知。

Gist:如果我们没有项目可以开源或者只是单纯的想分享一些代码片段的话,我们就可以选择Gist。不过说心里话,如果不翻墙的话,Gist并不好用。

配置用户名和邮箱

使用git前配置用户名和邮箱,这样才能够识别出来是谁提交的内容

1
2
3
4
5
6
7
git config --global user.name "keqiudi" #配置用户名
git config --global user.email "1244381125@qq.com" #配置邮箱

git config --global --list #查看配置
参数:
--global:全局配置,对所有仓库生效,一般使用
--system:系统配置,对所有用户生效,一般不适用

创建仓库

方式一:git init

先找到找到合适位置的目录,进入该仓库

1
2
3
4
5
6
7
git init #初始化该仓库

# 成功会提示初始化了一个空的仓库,并且出现分支
# 在该文件夹内出现隐藏文件夹.git

git init my-repo
# 添加了一个参数后,将指定my-repo为git仓库,而不是该目录

方式二:git clone

先在github上常见仓库,再使用git clone

1
git clone https://github.com/keqiudi/keqiudi.github.io

工作区域和文件状态

git本地数据管理分为三个区域:

  • 工作区:英文名working directory,即资源管理器中看到的文件夹,实际操作的目录
  • 暂存区:英文名staging area/index,用于保存即将提交到git仓库的修改内容,git版本控制中重要区域
  • 本地仓库:英文local repository,通过git init创建的本地仓库,包含完整的项目历史和源数据

流程

  • 修改工作区文件后,需要将他们添加到暂存区
  • 再将暂存区中的修改提交到本地仓库中

git文件状态分为四种:

  • 未跟踪:新创建没有被git管理起来的文件

  • 未修改:已经被git管理的文件但文件内容没有被修改过

  • 已修改:已经被git管理的文件但文件内容被修改过,没有添加到暂存区的文件

  • 已暂存:已经被git管理的文件但文件内容被修改过,已经添加到暂存区的文件

添加提交文件

  • 查看当前仓库状态,查看分支、文件等等
1
2
3
4
5
6
git status

# 红色文件代表未被跟踪状态,未进入暂存区
# 绿色文件代表已经被添加到了暂存区

# 注意git不会将空文件夹纳入版本控制中,如果创建一个空文件夹再使用git status将不会有区别
  • 添加文件到暂存区
1
2
3
4
5
6
7
8
9
10
git add fileName

git add *.txt # 所有以.txt结尾的文件
git add . # 将所有未被跟踪的文件加入暂存区,根据.gitignore做过滤
git add * # 将所有未被跟踪的文件加入暂存区,不根据.gitignore做过滤



git ls-files # 查看暂存区中的文件内容
git rm --cached <file>...# 将添加到暂存区的文件取消
  • 提交文件
1
2
3
4
5
6
7
8
9
git commit -m "提交信息"

# 注意git commit只会提交暂存区中的文件,不会提交工作区中的文件

# 不加上-m参数将会进入交互式状态,默认使用vim编辑提交信息

git commit -a -m "提交信息"
git commit -am "提交信息"
# 加上-a参数可以同时完成添加暂存和提交两个动作
  • 查看提交记录
1
2
3
4
5
git log

# 显示ID,日期,提交者和邮箱

git log --oneline # 查看简介的提交记录,只会显示版本ID和提交信息

回退版本

git reset命令用于回退版本,可以退回到之前某一个提交状态,有三种模式

  • 表示回退到某一个版本,并且保留工作区和暂存区的所有修改内容,即所有工作区和暂存区在回退版本之后的修改都会保留
1
git reset --soft 版本ID
  • 表示回退到某一个版本,并且丢弃工作区和暂存区的所有修改内容,即所有在工作区和暂存区在回退版本之后的修改都不会保留,完全回到当时版本的工作区和暂存区
1
2
3
4
git reset --hard 版本ID

# 版本ID中 代表上一个版本
git reset --hard HEAD^
  • 表示回退到某一个版本,并且只保留工作区修改的内容,丢弃暂存区修改的内容,即暂存区在回退版本之后的修改都不会保留,而工作区会保留到最新版本的工作区内容
1
2
3
git reset --mixed 版本ID

# 不加参数时默认为mixed

一般只使用soft和mixed,谨慎使用hard,但若误操作也没关系,git中的命令是可以回溯的,当我们误操作的时候只需要使用git reflog命令查看操作历史记录,找到误操作之前的版本号,再使用git reset回退到这个版本就可以了

查看文件差异

git diff命令可以用于查看文件在工作区、暂存区、本地仓库之间的差异,也可以查看不同版本,不同分支中文件的差异。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 红色代表删除的内容,绿色是添加的内容

git diff
# 无参数默认比较工作区和暂存区之间的差异内容

git diff HEAD
# HEAD参数表示工作区和版本库之间的差异

git diff --cached
# cached比较暂存区和版本库的差异

git diff ID1 ID2
# 比较不同版本的差异时,只需要在后面加上比较的两次版本ID,就可以比较两次版本的差异内容

git diff HEAD~ HEAD
# 比较当前版本和上一个版本的区别

git diff HEAD~2 HEAD
# 比较当前版本和最新提交前2个版本的区别

git diff HEAD~ HEAD file3.txt
# 只比较file3文件最新版本和上一个版本区别,没有则不显示


HEAD是Git中的一个非常重要的概念,指向分支最新提交结点,而HEAD~/HEAD^可以表示上一个版本,通常用于比较当前版本和上一个版本区别。我们还可以在HEAD波浪线后加上数字代表提交之前的几个版本

删除文件

从版本库中删除文件一共有两种方法:

  • 直接删除文件后提交
1
2
3
4
5
6
rm file1.txt # 只删除了工作区文件,未更新暂存区文件

git add . #更新暂存区
git ls-files #查看暂存区文件

git commit -m "commit" #再次提交
  • 使用git rm删除(更简单)
1
2
3
4
5
6
7
8
9
10
11
git rm file2.txt
# 将工作区和暂存区文件同时删除

git rm --cached <file>
# --cached参数,将文件从暂存区删除,但保留在当前工作区中

git rm -r *
# 递归删除某个目录下的所有子目录和文件

git commit -m "commit"
#注意删除后不要忘记提交

.gitignore文件

在git中有个特殊文件,叫忽略文件,可以忽略掉一些不应该加入版本库中的文件,可以让我们的版本库体积更小,更干净

一般来说遵循下面的原则

  • 系统或者软件自动生成的文件
  • 编译产生的中间文件和结果文件
  • 运行时产生的日志文件、缓存文件、临时文件
  • 涉及身份、密码、口令、密钥等敏感信息文件

先创建.gitignore文件,在通过vim对.gitignore文件进行设置过滤文件

1
2
3
touch .gitignore

vim .gitignore

假设下方为.gitignore文件内容

1
2
3
access.log #代表忽略access.log文件

*.log # 代表忽略所有.log文件

.gitignore文件还可以忽略文件夹内容,注意文件夹格式是以/结尾,才能正常忽略文件夹

1
2
3
*.log # 代表忽略所有.log文件

temp/ # 代表忽略temp文件夹内容

注意.gitignore文件生效有一个前提,就是这个文件不能先添加到版本库中,若已经添加到版本库中.gitignore文件将不会生效

.gitignore文件的匹配规则

从上到下逐行匹配,每行表示一个忽略模式

Git - gitignore 文档 (git-scm.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
1.空行或者以#开头的行会被git忽略。一般空行用于可读性分隔,#一般用于注释

2.使用标准的Blob模式匹配,例如:
*通配任意个字符
?匹配单个字符
[]表示匹配列表中的单个字符,例如:[abc] 表示a/b/c

3.两个星号**表示匹配任意的中间目录

4.中括号可以使用短中线链接,比如:
[0-9]表示任意一位数字,[a-z]表示任意一位小写字母
5.!表示取反

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 忽略所有的.a文件
*.a

# 在第一条的基础上除去lib.a文件
!lib.a

# 只忽略当前目录下的TODO文件,而不忽略且文件夹的TODO,因为有/表示当前目录
/TODO

# 忽略任意目录下名为TODO的文件夹
TODO/

# 忽略 doc/hello.txt,但不忽略doc/temp/test.txt,因为指定的是doc/目录下的,而不是doc/temp/下的
doc/*.txt

# 忽略所有doc/目录及其所有子目录下的/pdf文件
doc/**/*.pdf

github上提供了各种常用语言的忽略文件的模板,在新建仓库时可以直接使用,也可以根据需要自己修改

以下为链接:

GitHub - github/gitignore: A collection of useful .gitignore templates

SSH绑定git与github

我们就一起完成 Git 和 GitHub 的绑定,体验通过 Git 向 GitHub 提交代码的能力。不过在这之前,我们需要先了解 SSh(安全外壳协议),因为在 GitHub 上,一般都是通过 SSH 来授权的,而且大多数 Git 服务器也会选择使用 SSH 公钥来进行授权,所以想要向 GitHub 提交代码,首先就得在 GitHub 上添加 SSH key配置。

生成SSH key

  1. 输入ssh 查看本机是否安装ssh

  2. 输入ssh-keygen -t rsa -C “your_email”

  • 表示我们指定 RSA 算法生成密钥,然后敲三次回车键,期间不需要输入密码,之后就就会生成两个文件,分别为id_rsa和id_rsa.pub,即密钥id_rsa和公钥id_rsa.pub. 对于这两个文件,其都为隐藏文件,默认生成在以下目录:
    • Linux 系统:~/.ssh
    • Mac 系统:~/.ssh
    • Windows 系统:C:\Documents and Settings\username\.ssh
    • Windows 10 ThinkPad:C:\Users\think.ssh

密钥和公钥生成之后,我们要做的事情就是把公钥id_rsa.pub的内容添加到 GitHub,这样我们本地的密钥id_rsa和 GitHub 上的公钥id_rsa.pub才可以进行匹配,授权成功后,就可以向 GitHub 提交代码啦!

  1. 添加 SSH key
  • 进入github中的settings,再点击SSH and GPG Keys进入此子界面,然后点击New SSH key按钮:
  • 将公钥id_rsa.pub的内容粘贴到Key处的位置(Titles的内容不填写也没事),然后点击Add SSH key 即可。
  1. 验证绑定是否成功

在 Git Bash 中输入ssh -T git@github.com进行测试:

img

结果即为Git 与 GitHub 绑定成功的标志。

通过git将代码提交到github

pull与push

push:该单词直译过来就是“推”的意思,如果我们本地的代码有了更新,为了保持本地与远程的代码同步,我们就需要把本地的代码推到远程的仓库,代码示例:

1
2
3
4
5
6
7
8
9
10
11
git push <远程主机名> <本地分支名>:<远程分支名>


git push origin master
#上面命令表示,将本地的master分支推送到origin主机的master分支。如果后者不存在,则会被新建。

# 如果当前分支与多个主机存在追踪关系,则可以使用-u选项指定一个默认主机,这样后面就可以不加任何参数使用git push。
git push -u origin master
#上面命令将本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了。
git push
#此时指定默认主机后才能不加参数使用

pull:该单词直译过来就是“拉”的意思,如果我们远程仓库的代码有了更新,同样为了保持本地与远程的代码同步,我们就需要把远程的代码拉到本地,代码示例:

1
2
3
4
5
6
7
git pull <远程仓库名> <远程分支名>:<本地分支名>

# 这里的仓库名称和分支名称可以省略,默认拉去别名为origin的main分支即
git pull origin master

git pull -u origin master
git pull

pull request它表示:如果我们fork了别人的项目(或者说代码),并对其进行了修改,想要把我们的代码合并到原始项目(或者说原始代码)中,我们就需要提交一个pull request,让原作者把我们的代码拉到 ta 的项目中,至少对于 ta 来说,我们都是属于远程端的。

一般情况下,我们在push操作之前都会先进行pull操作,这样不容易造成冲突。

提交代码

对于向远处仓库(GitHub)提交代码分为两种情况:

第一种:

  1. 本地没有 Git 仓库,这时我们就可以直接将远程仓库clone到本地。通过clone命令创建的本地仓库,其本身就是一个 Git 仓库了,不用我们再进行init初始化操作啦,而且自动关联远程仓库。我们只需要在这个仓库进行修改或者添加等操作,然后commit即可。
1
git clone https://github.com/guobinhit/mybatis-tutorial.git (仓库链接)
  1. 将需要提交的文件复制到该仓库中

  2. 使用git status、git add、git commit -m " "、git log、git status

  3. 将本地仓库的内容push到远程仓库,输入git push origin master

在第一次向远程仓库提交代码的时候,需要输入账号及密码进行验证,验证成功后即可。

第二种

有本地Git 仓库,并且我们已经进行了多次commit操作。

  1. 进入该仓库,git init初始化操作:
  2. 命令,关联远程仓库(在此,默认大家都知道如何获取远程仓库的地址),其中origin为远程仓库的名字:
1
2
3
4
git remote add origin https://github.com/guobinhit/springmvc-tutorial.git

git remote -v
# 可以查看关联分支和地址
  1. 输入git pull origin master命令,同步远程仓库和本地仓库:
  2. 再回到本地springmvc-tutorial仓库,看看我们是否已经把远程仓库的内容同步到了本地:
  3. 输入git add和git commit命令,将文件添加并提交到springmvc-tutorial仓库:
  4. git push origin master命令,将本地仓库修改(或者添加)的内容提交到远程仓库:

在这个例子中,我们将远程仓库命名为origin,本地仓库名为springmvc-tutorial,其实两者的名字咱们可以随意取,一般来说,我们习惯性将远程仓库命名为origin,不过在需要关联多个远程仓库的时候,就需要我们再取别的名字啦!

在我们向远程仓库提交代码的时候,一定要先进行pull操作,再进行push操作,防止本地仓库与远程仓库不同步导致冲突的问题,尤其是第二种提交代码的情况,很容易就出现问题。

GUI工具

常用的

  • github Desktop
  • GitKraken
  • Sourcetree

分支简介和基本操作

我们可以将分支branch看做代码库中的不同版本,可以独立存在并且有自己的提交记录,分支非常适合团队协作和开发管理,比如多个程序员可以在自己的分支上进行开发工作,我们可以在分支上建立一个新问题的开发或者建立一个问题修复的分支来处理一些bug和缺陷,这样就可以让主线代码仓库处于稳定可用状态。而不会影响到其他功能的开发和测试,能够提高团队开发效率

  • 创建新分支
1
git branch <新分支名>
  • 删除分支
1
2
3
4
5
git branch -d <已经完成合并的分支>
# 小d参数只能删除已经完成合并的分支

git branch -D <未合并的分支>
# 如果要删除未合并分支,需要用大D来强制删除分支
  • 查看有哪些分支
1
2
git branch
# 可以查看到有哪些分支
  • 切换到指定分支/恢复文件或目录状态
1
2
3
4
git checkout <切换的分支名>

# 注意git checkout可以在意外修改文件后,将文件恢复到修改之前的状态,这个时候分支名称和文件名称相同的就会出现歧义,git checkout命令会默认切换分支而不是恢复文件,下面是官网提供的命令用于专门切换分支
git switch <切换的分支名>
  • 合并分支
1
2
3
4
git merge <需要合并的分支名>
# 该命令将不同的分支合并到当前的分支中
# 即合并到的目标分支为当前分支

  • 查看分支图
1
2
3
4
5
6
git log --graph --oneline --decorate --all

# 在命令行中可以用以上命令查看分支图,但是没有在git GUI中看着美观

# 通常使用alias为该命令取别名来简化操作
alias graph="git log --graph --oneline --decorate --all"

解决分支合并冲突

一般情况,**如果两个分支的修改内容没有冲突,git会自动完成合并。**但如果两个分支修改同一文件的同一行代码,那么git就不知道该保留哪个,所以需要我们手动来解决冲突。

当我们和并分支,输入git merge之后,提示存在合并冲突之后,会自动进入处理合并冲突状态,此时如果想取消该次合并只需要输入

1
2
git merge --abort
# 即可打断本次合并

如果想继续合并,现在需要解决冲突

    1. 我们先输入git status或git diff 来查看冲突位置
1
2
3
4
5
6
7
8
9
10
11
12
13
git diff

--- a/main1.txt
+++ b/main1.txt
++<<<<<<< HEAD
+main
+这是在master中修改的内容
++=======
+ main1
+ 这是在test中修改的内容
++>>>>>>> test

# 上面中HEAD代表当前分支,test代表想合并的分支,+代表添加的内容,main1.txt代表冲突的文件
    1. 此时我们只需要再进入冲突的文件删除不想要的地方和保留想要的地方即可,同时把提示内容一并删除(+和<和==等)
    1. 再git add . 和git commit 即可

切记在每个分支修改内容后一定要记得add和commit,否则就会出现修改一同带入到切换到的分支的后果,导致两个分支中同一个文件内容出现同步修改

回退和rebase

我们在删除了分支之后可以用命令将已经删除了的分支恢复到指定版本,命令如下

1
2
3
4
5
6
git checkout -b <恢复的分支名称> <恢复版本的提交ID>

# 该命令可以恢复已经合并后删除的分支,只需要-b参数,版本ID可以通过来查看
git log --graph --oneline --decorate --all

# 一般主分支用git reset恢复

rebase叫做"变基",会将当前所处分支变基到目标分支上,会将两分支共同祖先之后的内容变基到目标分支上,类似嫁接移植,故在不同分支用rebase会产生不同的变基结果,最终都会是一条分支

1
2
git rebase <目标分支>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 以下是一个示例
----------------
rebase前
----------------
* 941b6c7 (HEAD -> master) main:4
| * bd5a88d (test) test:1
|/
* 51f1666 main:3
* 0e7b89e main:2
* 85c4410 main:1
----------------

# 处于main分支下时执行
git rebase test
# 这将会使main与test分支共同祖先之后的内容全部移动到test最新分支之后再合并成一条分支
在rebase test之后变为
----------------
* 941b6c7 (HEAD -> master) main:4
* bd5a88d (test) test:1
* 51f1666 main:3
* 0e7b89e main:2
* 85c4410 main:1
----------------

# 处于test分支下执行
git rebase main

在rebase test之后变为
----------------
* 1d1fee5 (HEAD -> test) test:1
* 941b6c7 (master) main:4
* 51f1666 main:3
* 0e7b89e main:2
* 85c4410 main:1
----------------

Merge

优点:不会破坏原来分支的提交历史,方便回溯和查看

缺点:会产生额外提交结点,分支图较复杂

Rebase

优点:不会新增额外提交记录(合并),形成线性历史,比较直观和干净;

缺点:会改变提交历史,改变了当前分支branch out的节点,应当避免在共享分支中使用,一般不会和共同开发的分支中使用,当确定只有自己在该分支开发时且希望提交历史更加清晰明了则推荐使用。

标签

tag用于在开发阶段创建标签,某个阶段完成了创建一个版本,在开发中可以使用tag来指定软件的一个重要时期,比如版本号更新的时候可以创建一个v1.0,这样回顾的时候比较简单

  • 查看tag
1
2
3
4
git tag
#这样列出的tag是按照字母排序的,和创建时间没有关系,如果只是想查看某些tag的话可以加一些限定:

git tag -l version1.*
  • 创建tag
1
2
3
4
5
git tag version 1.0  #也可以 git tag 1.0

# 带有信息的tag:
git tag -a version1.0 -m "first version"
# 用 -a (译注:取 annotated 的首字母)指定标签名字即可,而 -m 选项则指定了对应的标签说明,Git 会将此说明一同保存在标签对象中。如果没有给出该选项,Git 会启动文本编辑软件供你输入标签说明
  • 删除tag
1
git tag -d <标签名字>

分支命名和管理

分支命名

  • 推荐使用带有意义的描述性名称来命名分支
    • 版本发布分支/tag示例:v1.0.0
    • 功能分支示例:feature-login-page
    • 修复分支示例:hotfix-#issueid-desc

分支管理

  • 定期合并已经成功验证的分支,及时删除已经合并的分支
  • 保持合适的分支数量
  • 为分支设置合适的管理权限