PS:本篇是个长篇,但是阅读完,可以基本了解 Git 在实际开发中的绝大部分常用操作。
前言:什么是Git
我们在日常工作 / 学习时,对于某些文档 / 代码,可能会存在多个版本需要维护,但是随着版本的增多,我们很难记得每个版本都修改了什么,难以维护好这每一个版本。
这时候就需要版本控制器来更便于我们管理这些不同版本的文件;所谓版本控制器,就是一个可以记录工程的每一次改动与版本迭代的管理系统,同时也便于多人协同作业。
当前最主流的版本控制器,就是 Git。
Git 可以控制电脑上所有格式的文件,对于开发人员来说,Git 最主要的就是可以帮助我们管理软件开发项目中的源代码文件。
(PS:所有的版本控制系统,都只能跟踪文本文件的改动,即版本控制系统可以告诉我们文本每次的改动;但对于类似图片、视频这些二进制文件,虽然也能管理,但只能知道大小的改变,具体改动了什么,不得而知)
一、Git 的基本操作
1、创建 Git 本地仓库
只有在仓库中的文件,才能被 Git 进行追踪管理,因此我们在对文件进行版本控制之前,必须创建一个仓库出来。(为了便于管理,这个本地仓库也应该放置在与需要版本控制的文件的目录下)
创建 Git 本地仓库的命令是:
git init
这个命令的作用是在当前目录下创建一个 Git 本地仓库,因此这个命令建议放在需要版本控制的文件的目录下。
调用 git init 命令后,当前目录下就会多出一个 ,git 的隐藏目录,这个隐藏目录是 Git 用来跟踪管理仓库的,不要手动修改这个目录中的文件,否则会造成错误!
2、配置 Git 本地仓库
在创建完本地仓库后,首先要做的事情就是配置用户名和邮箱地址这两个配置项,以防出错。
配置用户名和邮箱地址的命令是:
# 配置用户名
git config [--global] user.name "你的用户名"# 配置邮箱地址
git config [--global] user.email "你的邮箱地址"
配置完毕,也可以删除对应的配置,删除配置的命令是:
# 删除用户名配置
git config [--global] --unset user.name# 删除邮箱配置
git config [--global] --unset user.email
其中 --global 是一个可选选项。如果使用了该选项,这台机器上的所有 git 仓库都会使用该配置;如果不希望所有的 git 仓库都用这个配置,就不要添加 --global 选项。
(值得注意的是,如果某一配置项添加了 --global 成为全局配置项,在删除配置的时候也必须添加 --global 指令方可删除)
(PS:执行配置命令的时候,也必须要在 .git 隐藏目录所在的目录下执行)
配置完后,可以查看配置,查看配置的命令为:
git config -l
3、Git原理:认识工作区、暂存区、版本库
从图中我们可以看到,Git 内部主要细分为工作区和版本库,其中版本库内部又有许多细分。
3.1 工作区
工作区其实就是我们创建的 .git 隐藏目录所在的那个目录,即我们存放欲进行版本控制的代码 / 文件的所在目录。
3.2 版本库
所谓版本库其实就是那个 .git 隐藏目录,因此又称作仓库,其不属于工作区,是真正意义上的 git 仓库。版本库中的所有文件都可以被 git 管理起来;每个文件的修改与删除,git 也都可以跟踪,以便在任何时刻都能追踪 / 还原。
Git 的版本库内部存放着很多东西,主要有:暂存区(即图中的 stage,又称 index)、HEAD指针、唯一 master 分支、还有图中未标明的 objects 对象库。
暂存区:
又称索引,一般存放在 .git 目录下的 index 文件中,是版本库中最重要的组成部分。在我们对工作区中修改 / 新增 /删除的文件执行了 git add 命令后,工作区中所有修改了的内容都会被添加进版本库的暂存区中,暂存区目录树的文件索引会被更新。
(PS:新建的 .git 本地仓库中是没有暂存区的,必须在第一次 git add 之后,本地仓库中才会出现暂存区目录)
objects 对象库:
objects 对象库中存放着大量的 git 对象。在执行了 git add 命令后,工作区中修改的内容会被写入对象库中的一个新的 git 对象中,进而实现所有版本的控制与维护。
master 分支与 HEAD指针:
在创建 Git 版本库时,git 会为我们自动创建一个唯一的 master 分支,以及指向 master 分支的一个 HEAD指针。这个后面会详述。
当执行提交操作 git commit 后,master 分支会做响应的更新,这时暂存区的目录树才会被真正写入 git 仓库中进行维护。
从上述描述中可知,往工作区中添加文件,其实并没有真正添加进 git 仓库,必须通过 git add 命令添加进仓库的暂存区中,再使用 git commit 命令真正把文件添加进 git 仓库进行管理!
(PS:我们不能去手动修改 .git 仓库目录,只能通过 git add + git commit 进行添加,因为内部需要维护索引结构,手动修改极易导致整个仓库的损坏!)
4、添加文件进 Git 仓库
添加文件进 Git 仓库分为两步:
1、使用 git add 命令把修改后的文件添加进版本库的暂存区:
# 添加一个/多个文件到暂存区(git add 后面可以跟一个/多个文件)
git add 文件名1 文件名2 ……# 添加某个子目录到暂存区
git add 子目录名# 添加当前目录下的所有文件到暂存区
git add .
2、再使用 git commit 命令把暂存区的内容真正添加进本地仓库中:
# 把暂存区中的所有内容提交进本地仓库
git commit -m "message"# 把暂存区中的指定文件提交进本地仓库(git commit 后面可以一次性指定一个/多个文件)
git commit 文件名1 文件名2 …… -m "message"
值得注意的是,这个 message 是用来记录每一次提交的提交细节的(比如版本修改了什么等等),绝对不能省略,并且要好好描述,这是给开发人员看的。
我们还可以多次 git add 不同的文件,然后只需要 git commit 一次即可提交所有的文件。(因为需要提交的文件被全部放在了暂存区中,git commit -m "message" 是把暂存区中的所有文件提交到本地仓库)
在提交至本地仓库后,我们还可以通过 git log 命令来查看历史提交记录:
值得注意的是,第一行会有一长串十六进制数字,这是 commit id,每次提交都会有一个独特的 commit id,是一个经过哈希计算后的独特十六进制数字。
如果嫌输出信息太多,我们可以加上 --pretty=oneline 参数,把提交记录一行打印,但会省略掉一些细节:
5、如何通过 Git 查看哪些文件发生了修改
Git 相较于其它版本控制器优秀的地方,就是 Git 跟踪并管理的是修改,而非文件,只有对文件发生了修改,Git 才会跟踪并管理到。
当我们对文件进行修改后,可以通过 git status 命令查看在上次提交后,工作区是否对文件进行了修改。
(PS:只能查看哪些文件被修改了,但是修改的内容不得而知)
使用 git status 命令,只能知道文件被修改,想知道哪些文件被修改,就要使用 git diff 命令:
# 以 Unix 通用的 diff 格式显示暂存区和工作区文件的差异
git diff 文件名# 以 Unix 通用的 diff 格式查看版本库文件和工作区文件的区别
git diff HEAD -- 文件名
5.1 git diff 命令示例
让我们逐行解析这段 `diff` 输出:
第一行:`diff --git a/file1 b/file1`
diff --git :这是 Git 特有的标记,表示接下来的差异是由 Git 生成的。
a/file1 和 b/file1 :这里的 `a/` 和 `b/` 分别表示旧版本和新版本的文件路径。`file1` 是文件名,表示这个差异是针对 `file1` 文件的。
第二行:`index e69de29..2e3c1c7 100644`
index:表示文件的 Git 对象 ID(SHA-1 校验和),用于唯一标识文件的内容。
e69de29:这是旧版本文件的校验和(在 `a/file1` 中)。
2e3c1c7:这是新版本文件的校验和(在 `b/file1` 中)。
100644:这是文件的权限模式,表示这是一个普通文件(非执行)。`100644` 是八进制表示的权限,相当于 `rw-r--r--`。
第三行:--- a/file1
---:表示旧版本文件的开头。`a/file1` 表示这是旧版本的 `file1`。
第四行:`+++ b/file1`
+++:表示新版本文件的开头。`b/file1` 表示这是新版本的 `file1`。
第五行:`@@ -0,0 +1 @@`
@@:表示差异块的开始。
0,0 :表示旧版本文件中从第 0 行开始的 0 行内容(即旧文件为空)。
+1:表示新版本文件中从第 1 行开始的 1 行内容被添加了。
@@:整个行表示这是一个差异块的上下文信息,帮助定位差异的具体位置。
第六行:`+hello world:`
- **`+`**:表示这一行是在新版本文件中添加的。
- **`hello world:`**:这是实际添加的内容,即新版本文件的第一行是 `hello world:`。
6、.git 目录结构介绍
我们给出 .git 目录的树状结构:
tree .git/
.git/
├── branches
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── prepare-commit-msg.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ └── update.sample
├── index
├── info
│ └── exclude
├── logs
│ ├── HEAD
│ └── refs
│ └── heads
│ └── master
├── objects
│ ├── 48
│ │ └── 03c48e7fe98a55687af5c3270265a46ab69ab7
│ ├── 74
│ │ └── 5172e8950af7753d61460930102e01a5685e62
│ ├── af
│ │ └── b1be315f37830ae2f2ea32e9f11b4437a09df3
│ ├── c7
│ │ └── fba63dbbd842e27890a361ec6ccb68645e539b
│ ├── e6
│ │ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│ ├── info
│ └── pack
└── refs├── heads│ └── master└── tags17 directories, 23 files
其中:
index:就是暂存区,git add 后,修改的内容都添加在这里。
HEAD:默认指向 master 分支的指针
知道 commit id 后,我们便可以通过 git cat-file -p 命令来查看版本库对象的内容:
7、如何通过 Git 回退历史版本(重要)
版本控制器重要的能力就是能够管理文件的历史版本,可以实现历史版本的回退。
7.1 Git 中的回退指令:git reset
Git 中的回退指令叫做 git reset ,值得注意的是,Git 中的版本回退,本质上是把版本库中的内容进行了回退,至于工作区和暂存区中的内容是否回退,要根据 git reset 的命令参数决定:
# git reset 版本回退命令的语法格式
git reset --mixed/--soft/--hard HEAD + [文件名]
我们介绍一下各个参数:
__mixed:
默认选项,使用该参数,会把版本库和暂存区中的内容回退至指定版本,工作区文件保持不变。(由于 --mixed 是默认选项,因此如果想使用 --mixed,可以不带参数)
--soft:
只把版本库回退到指定版本,工作区和暂存区的内容都保持不变。
--hard:
把版本库、暂存区、工作区全都退回至指定版本。 (使用的时候一定要谨慎,如果工作区中还有代码,以 --hard 参数进行版本回退,工作区中未提交的代码都会消失!)
HEAD:
可以直接写 commit id,表示指定退回的版本(通常与 git log 命令搭配使用,通过 git log 查询历史提交记录来找到各个版本的 commit id)
直接写 HEAD,表示回退到当前版本;HEAD^,表示回退到上一版本;HEAD^^,表示回退到上上个版本,以此类推。(也可以用数字来表示,HEAD~0 表示当前版本,HEAD~1 表示上一版本,HEAD~2表示上上个版本,以此类推)
文件名:
文件名可以加可以不加,如果加了文件名,就只是把这个文件回退到指定版本,而不是整个项目。
如果在回退之后,突然后悔了怎么办?
只要有回退前版本的 commit id,就可以回退到回退前的版本。
那么这个回退前版本应该怎么找呢?
1、从终端往上找找之前的记录,看看是否能找到。
7.2 Git 回退指令执行很快,其原理是什么?
8、如何通过 Git 撤销修改,恢复至之前版本
场景1:只对工作区修改了代码,没有 git add 和 git commit
1、可以直接删除修改的代码 / 通过 git diff 对比删除,但是在遇到代码量较大的情况下,其实很麻烦。
2、Git 为我们提供了一种更好的方式,可以让工作区的文件恢复到最近一次 add / commit 时的状态:
# 让文件恢复到最近一次 add / commit 的状态
git checkout -- 文件名
值得注意的是,-- 不可省略,如果省略这个命令就变成别的意思了
场景2:已经把代码 add 到暂存区中了,但是还没有 commit 到版本库中
这个时候,我们就可以使用前面所说的 git reset --mixed HEAD + [文件名]进行回退了。
场景3:已经把代码 add 到暂存区中,也 commit 到版本库中了
这个时候,能回退的前提必须是代码没有 push 到远端仓库才能回退,因为日后控制代码大部分都是在远端仓库上,回退的目的就是为了不影响远端仓库,因此只能在本地仓库上回退。
回退同样是用 git reset 进行回退,git reset -- head HEAD + [ 文件名 ]
9、删除文件
前言:删除也是修改操作。
如果我们直接使用 rm 命令删除文件,实际上仅删除了工作区文件,版本库中的文件并没有删除。因此,应该以 rm 命令删除工作区文件搭配 git rm 命令把版本库和暂存区中的文件都删除,最后不要忘记 git commit,因为删除也是修改。
二、Git 基本操作命令总结
1、创建本地 git 仓库
git init
2、配置 git 的用户名和邮箱两大配置项
git config [--global] user.name "用户名"git config [--global] user.email "邮箱地址"
3、删除 git 的用户名和邮箱两大配置项
git config [--global] --unset user.namegit config [--global] --unset user.email
4、查看 Git 仓库配置
git config -l
5、把工作区修改文件提交进暂存区 + 把暂存区文件真正提交至本地仓库(通常搭配使用,重要)
# 把工作区修改文件提交进暂存区
# 1、添加一个/多个修改文件进暂存区
git add 文件名1 文件名2……# 2、添加某个子目录进暂存区
git add 目录名# 3、添加当前目录下的所有修改文件进暂存区
git add .# 把暂存区文件真正提交至本地仓库
# 1、提交暂存区中的全部内容提交进本地仓库
git commit -m "提交细节"# 2、提交暂存区中的指定文件至本地仓库
git commit 文件名1 文件名2…… -m "提交细节"
6、查看历史提交记录
git log
7、查看版本库中某个对象的内容(须知道其 commit id)
# -p 是更优雅的打印,也可以不写
git cat-file -p 对象的commit_id
8、查看仓库状态
# 只能查看哪些文件修改了,但是修改的具体内容不得而知
# 可以查看上次提交之后,是否对文件还进行了修改
git status
9、查看某个文件在暂存区和工作区的区别
git diff 文件名
10、查看某个文件版本库和工作区的区别
git diff HEAD -- 文件名
11、版本回退(重要)
git reset --soft/--mixed/--hard HEAD [文件名]
# 文件名可以不写,就是整个工程回退
# HEAD可以写commit id,也可以通过 HEAD^ / HEAD~0等等不同版本回退
# --soft:默认选项,回退版本库和暂存区的内容
# --mixed:只回退版本库的内容
# --hard:版本库、暂存区、工作区的内容全部回退
12、把工作区的文件回到最近一次 add / commit 的状态
git checkout -- 文件名
13、把文件从暂存区和工作区中删除
git rm 文件名
三、Git 的分支管理
1、什么是分支
在之前的 Git 学习中,我们知道了,每次的 Git 提交,Git 都会把它们穿成一条提交时间线,而这一条提交时间线可以称作一个分支。
之前,我们只有一条提交时间线,也就是只有一条分支,这条分支叫做 master 分支(主分支)
而 HEAD 指针指向的就是当前正在工作的 master 分支(HEAD 指针指向的是当前正在工作的分支,可以是 master 分支,也可以是其它)
每次在 master 分支中提交,master 分支都会向前移动一步,这样随着不断提交,master 的分支就会越来越长。
2、如何创建一个新的分支
Git 支持我们创建和查看分支,对应的命令是:
# 查看分支信息
git branch# 基于当前分支新的一个分支
git branch 分支名
新建的分支,是基于当前的分支创建的,所以一开始指向的 commit id 与当前分支一致:
3、如何切换分支
# 切换到对应分支
git checkout 分支名
可以发现, 之前把工作区的文件回到最近一次 add / commit 的状态是 git checkout -- 文件名,而 git checkout 分支名,就是切换分支。
我们在 dev 分支上为 file 文件写一段内容,然后切换回 master 主分支:
可以发现,dev 分支上提交的代码,并不会在 master 分支中展现:
4、合并分支
在前文中,我们发现, 不同分支的提交互相是看不到的。
为了让 dev 分支上提交的信息可以让 master 分支看见,我们需要把 dev 分支合并到 master 分支上。(要把 dev 分支合并到 master 分支上,就要切换到 master 分支上进行合并)
# 合并某个分支到当前分支上
git merge 分支名
我们可以发现,merge 之后,有一 Fast-forward 字段,这是一种合并模式,叫做“快进模式”,快进模式下的合并,是直接把 master 分支指向 dev 分支指向的 commit id,合并速度很快。
(还有其它的合并模式,后文会介绍)
5、删除分支
合并分支后,dev 分支就没什么用了,可以删除了:(注意,删除某一分支,不能在当前分支下)
git branch -d 分支名
由于创建、合并与删除分支比较简单,所以推荐使用分支完成某个任务,然后合并、删除分支,这样和在 master 分支上工作是一样的,但是过程比较安全。
6、合并冲突
在实际合并的时候, 其实并不是想合并成功就能合并成功的,因为有时候会出现代码冲突问题。
我们创建一个 dev1 分支,在 dev1 分支和 master 分支的同一行写下不同的代码:
(注意:如果在当前分支上做了修改但还没有提交,Git 会在你切换分支时保留这些未提交的更改。这意味着你可以在不同分支之间看到相同的未提交文件,除非这些文件在目标分支上有冲突)
# -b 选项可以完成创建并切换至 dev 分支的效果
git checkout -b dev
这时,我们用 cat file 查看一下文件:
这时候只能手动修改冲突代码,然后再次提交。(一定要再次提交!)
此时可以使用 git log 的一种方法,进行可视化展示分支提交时间图:
# --graph:可视化选项
# --pretty=oneline:简洁的单行模式打印
# --abbrev-commit:缩短commit id的格式
git log --graph --pretty=oneline --abbrev-commit
7、分支合并模式
通常进行分支合并的时候,Git 会尽可能采用 Fast-forward 模式。
在 Fast-forward 模式下,分支合并后,在查看分支历史时,会丢掉分支信息,从分支信息无法得知这个提交是由其它分支合并而来,还是自己提交的。
我们在合并的时候,可以添加 --no-ff 选项,表示非快速模式:
# --no-ff:非 Fast-forward 模式
# -m:禁用Fast-forward模式后,合并会创建一个新的提交,因此要 -m 后面需要写提交信息
git merge --no-ff -m "提交信息(建议同时写上合并信息)" 分支名
在普通模式提交后,查看分支历史,就可以看见来自哪里的信息。
8、分支使用策略
在实际的开发过程中,master 分支通常被认为是稳定的,仅用来发布新版本,而不用来进行研发;研发都在 dev 分支上,dev 分支被认为是不稳定的。
因此,我们在开发中,也应该在 dev 分支上进行开发,等到代码稳定了,再合并到 master 分支上。
9、修复 bug 的建议和bug 分支:储藏工作区信息
9.1 建立临时 bug 分支来修复 bug
如果在某一个分支上进行开发的过程中,我们被告知 master 分支上有 bug,应该如何解决?
在 Git 中,每一个 bug 都可以通过建立一个临时的 bug 分支来解决;bug 修复后合并到 master 分支上,然后把这个临时分支进行删除。
那么在原来那个分支上的代码正在开发,还不能提交,这时又要去修 bug ,那这些个代码应该怎么办呢?
Git 为我们提供了 git stash 命令,可以把当前工作区中的信息保存到 stash 文件中,在未来需要的时候还可以恢复出来。
(PS:保存的这些工作区文件必须曾经被 add, commit 过,否则 Git 无法追踪管理)
# 把工作区文件储存起来
git stash# 查看 stash 文件中储存了哪些文件
git stash list
bug 修复后,如何恢复工作区的文件呢?
# 恢复工作区文件,并在恢复的同时把 stash 也删除
git stash pop# 恢复工作区文件,但是不删除 stash 文件
git stash apply# 删除 stash 文件
git stash drop
不过值得注意的是,在 dev2 分支恢复后,修复bug的内容并不会在 dev2 上显示。因为 Master 分支目前最新的提交,时间线上是要领先于新建 dev2 分支时的 master 的分支的:
9.2 主 master 分支合并 dev 分支时的建议
我们的最终目的是让主 master 分支合并 dev 分支的,但是由于 dev 分支时基于 bug 尚未修复时期的 master 建立的,所以由一定风险会把错误代码合并到 master 分支上,造成合并冲突:
解决这个问题,有一个好的建议:
最好在自己的分支上合并下 master,再让自己的这个分支去合并 dev ,这样有冲突可以在自己的这个本地分支上去解决,不会影响到 master 主稳定分支。
10、删除临时分支
如果某些临时分支,干到一半不要了,又不能提交,这个时候,git branch -d 命令是无法删除的,只会在指定分支已经成功合并到当前分支的情况下删除该分支。如果分支未合并,Git 会阻止删除操作,以避免丢失工作。
我们可以使用 git branch -D 命令强制删除。
11、分支的总结
分支在实际中有什么用呢?
假设准备开发⼀个新功能,但是需要两周才能完成,第⼀周写了 50% 的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能工作了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。
现在有了分支,就不用怕了。
我们创建⼀个属于自己的分支,不合并之前,别人看不到,还继续在原来的分支上正常工作;而我们在自己的分支上工作,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。
并且 Git 无论创建、切换和删除分支,Git 在1秒钟之内就能完成!无论版本库中有一个文件还是一万个文件。
13、分支常用命令总结
# 查看分支信息
git branch# 基于当前分支新的一个分支
git branch 分支名# 切换到对应分支
git checkout 分支名# 创建并切换到该分支
git checkout -b 分支名# 合并分支(快速模式)
git merge 分支名# 合并分支(普通模式)
git merge --no-ff 分支名# 合并并提交(快速模式)
git merge -m "提交信息" 分支名# 合并并提交(普通模式)
git merge --no-ff "提交信息" 分支名# 可视化展示 git 提交时间图
git log --graph --pretty=oneline --abbrev-commit# 暂存工作区文件
git stash# 查看 stash 文件中暂存了哪些文件
git stash list# 恢复工作区文件并删除 stash
git stash pop# 恢复工作区文件,但不删除 stash
git stash apply# 删除 stash 文件
git stash drop# 删除分支(该分支已被当前分支合并)
git branch -d 分支名# 强制删除未合并分支
git branch -D 分支名
四、Git 的远程操作
1、前言:理解分布式版本控制系统
之前所介绍的版本控制系统,都是在本地上的,而 Git 实际上是一个分布式的版本控制系统。
所谓分布式版本控制系统,其实就是同一个仓库,可以分布到不同机器的版本控制系统。
分布式版本控制系统有一个一直不断电的中央服务器,内部有着自己的中央服务器仓库,并不保存在本地(因此又称远程仓库)
每一个本地服务器,每一台主机都可以把远程仓库克隆到本地,也可以自己的修改推送到中央服务器仓库中,从而达成不同用户之间互相不影响,也便于交流与修改。x
远程仓库是不是需要我们自己搭建一个中央服务器呢?其实不需要,在互联网上为我们提供了许多基于 Git 的代码托管平台,这些都可以算作远程仓库。
其中最有名的就是 github>github 和 gitee(码云),其中 github>github 由于是国外网站,速度较慢,所以笔者用的最多的是 gitee,后面演示也使用 gitee。
2、新建远程仓库
我们来逐行介绍
仓库名称:
和本地仓库一样,远程仓库同样要有自己的名称,起名要围绕这个仓库的代码内容进行。
归属:
给仓库在网站一个后缀
仓库介绍:
介绍这个仓库里面的代码内容,可以开源,可以私有。
初始化仓库:
选择语言:为这个仓库里面的代码选择语言。
.gitignore 文件:可以选择模板,也可以自己写,主要用来让某些文件不被 git 追踪,上传的时候会被忽视,增强代码安全性和可读性,后面会详细介绍。
开源许可证:仓库开源的时候有用。
设置模板:
Readme 文件:介绍项目。
Issue 模板文件 / pull request 模板文件:可以帮助用户快速填写必要的信息,减少沟通成本,加快问题解决和代码审核的速度。
选择分支模型:
与本地仓库的分支一样,可以提前设置好多个分支,也可以只设置一个 master 主分支,后续再创建。 这里只创建 master 主分支。
3、克隆远程仓库到本地
克隆到本地,需要 git clone 命令:
git clone 远端仓库链接
远端仓库链接可以直接从仓库里面找到:
克隆仓库的时候,Git 提供了多种数据传输协议,其中最常见的是 SSH 协议 和 HTTPS 协议。
SSH 协议克隆
SSH协议为了保证其安全性和实用性,使用了公钥加密和公钥登录机制,因此,使用此协议需要我们将公钥放到远端仓库进行管理:
1、在本地仓库创建 SSH 秘钥
我们先在用户主目录下查看有没有 .ssh 目录,如果有,再查看这个目录下有没有 id_rsa(私钥)和 id_rsa.pub(公钥)两个文件。如果没有,需要创建 SSH 秘钥。
# 创建 SSH 秘钥
ssh-keygen -t rsa -C "配置的邮箱"
# SSH 协议克隆
git clone 远端仓库提供的SSH协议链接
找到一个合适的目录,把远端仓库克隆下来:
https 协议克隆
使用 https 协议克隆的时候,不需要配置秘钥,直接克隆即可
4、向远端仓库推送文件
在把原地仓库克隆下来后,我们可以进行修改,git add,git commit,那么应该如何推送至远端呢?就需要使用到 git push 命令。
# 把本地克隆仓库的某个分支上传到远程仓库的某个分支并合并(远程主机名默认叫做 origin)
git push 远程主机名 本地分支名:远程分支名# 如果本地分支名和远程分支名相同,也可以省略“:远程分支名”
git push 远程主机名 本地分支名
在推送的时候,SSH 协议和 HTTPS 协议也有所区别:
SSH协议:因为提前配置好了秘钥,所以每次推送不需要输入账号密码
HTTPS协议:每次推送都要输入账号密码,相对而言有些麻烦。
5、从远端仓库拉取新版本文件
如果我们在远端仓库在线修改了文件(强烈不建议,最好是克隆到本地修改再推送上去)或者其它开发者更新了这个仓库中的文件,这个时候远端仓库就领先于本地仓库一个版本。
Git 提供了 git pull 命令,用来从远端获取代码并合并本地版本。
# 从远端获取代码合并到本地某个分支上
git pull 远程主机名 拉取的远端分支名:想合并到本地哪个分支上# 如果拉取的远程分支是和当前所在分支合并,可以省略“:想合并到本地哪个分支上”
git pull 远程主机名 拉取的远端分支名
6、查看远端仓库信息
git 为我们提供了两个命令,来查看克隆到本地后的远端仓库信息
# 仅查看远端仓库名
git remote# 查看远端仓库详细信息
git remote -v
这个 origin ,就是远端仓库名,在推送和拉取的时候都要用到。
后面跟着的 fetch 和 push,只有拥有这两个权限的本地克隆仓库,才有权拉取和推送。
远端仓库名也可以更改:
git remote rename 原远端仓库名 新远端仓库名
7、忽略特殊文件:.gitignore 文件
前文我们已经说过,我们有些文件不想 / 不应该提交到远端(比如保存了密码的配置文件),这时候我们就需要在 Git 工作区的根目录下创建一个 .gitignore 文件,然后把要忽略的文件名填进去,Git 就会自动忽略这些文件了。
可以不从头写,gitee 在创建仓库的时候选择模板可以为我们生成:
如果当时没有选择这个,我们可以在工作区创建一个,然后推送到远端:
不过,我们也可以使用 gid add -f 命令把被 Git 忽略的文件强制添加。
如果有时候,我们发现某些文件被忽略了,想知道是 ,gitignore 文件中的哪个规则导致的,可以使用 git check-ignore -v 被忽略的文件名 来检查:
我们也可以把指定的文件排除在 .gitignore 规则外,可以在 .gitignore 文件里面写:
# 假设不排除 .gitignore
!.gitignore# 排除对应文件
!文件名
8、给命令配置别名
在使用 Git 的时候,有些命令会比较长,敲起来比较麻烦,这个时候我们可以为命令起个别名
(比如之前的可视化展示提交时间图:git log --graph --pretty=oneline --abbrev-commit)
核心命令叫做 alias:
# 简化命令
# --global 代表全局生效
# 注意:如果原命令包含空格 / 比较复杂,要拿 '' 括起来
git config [--global] alias.要起的别名 原命令名
# 重点注意:只能为命令取别名,也就是说命令别名只能跟在 git 后面
但是,对于初学者,不建议取别名,多练习练习 git 命令总归是有好处的。
9、给某一次提交加标签
提交的标识是 commit id,比较复杂且难记;这时候,我们可以为这次提交打个 tag(标签),给予容易记住且有意义的名字,也便于定位版本进行回退。
1、切换到需要打标签的分支上
2、git tag 标签名 即可打上标签
# 打标签
git tag 标签名# 查看所有标签
git tag# 查看标签对应提交的具体信息
git show 标签名
标签默认是打在最新提交的 commit 上的,如果要给指定的某次提交打标签,就需要查到其 commit id:
# 给某一个特定提交打标签
git tag 标签名 commit_id
Git 还提供了创建带有说明的标签:
# 创建带有说明的信息
git tag -a 标签名 -m "标签说明" [commit_id]
如果标签打错了,也可以删除:
git tag -d 想删除的标签名
因为创建的标签都只存储在本地,不会自动推送到远程,所以打错的标签可以在本地手动安全删除。
如果想要推送某个标签到远程:
git push 默认主机名(origin) 标签名
也可以一次性全部推送:
# 一次性推送全部标签到远端
git push origin --tags
如果标签已经推送到远程,想删除,就要先从本地删除,再:
# 删除远端标签
git push origin :refs/tags/标签名
当然也可以在 gitee 下直接删除,不过不建议这么做。
10、Git 远端操作命令合集
前提:先在 gitee 上创建好远程仓库,SSH协议需要提前构建好秘钥,HTTPS不需要
# HTTPS协议克隆远端仓库至本地
git clone gitee提供的HTTPS链接# SSH协议克隆准备:用户主目录下创建SSH公钥和私钥
ssh-keygen -t -rsa --C "邮箱"# SSH协议克隆远端仓库至本地
git clone gitee提供的SSH克隆链接# 查看远端仓库名
git remote# 查看远端仓库详细信息
git remote -v# gid add,git commit 之后向远端仓库推送某个分支合并到远端某个分支
git push 远程主机名 本地分支名:远程分支名# 如果相同,可以省略远程分支名
git push 远程主机名 本地分支名# 拉取远程仓库的某个分支合并到本地某个分支上
git pull 远程主机名 远程分支名:本地分支名# 如果相同,可以省略本地分支名
git push 远程主机名 远程分支名# 检查某个文件因为 .gitignore 文件中的哪些规则被忽略
git check-ignore -v a.so# 强制添加某个文件(无视.gitignore文件限制)
git add -f 文件名# 给命令配置别名(别名必须跟在 git 之后,不能分开取别名;命令间有空格需要‘’扩住)
git config [--global] alias.别名 原命令名# 给某个提交打标签(不加 commit id 默认给最近一次提交打)
git tag 标签名 commit_id# 查看所有标签
git tag# 查看某个标签的详细信息
git show 标签名# 创建带有说明的标签
git tag -a 标签名 -m "说明信息" [commit_id]# 删除标签
git tag -d 标签名# 把标签推送到远端仓库
git push 远端主机名(origin) 标签名# 把远端仓库的标签删除(先删除本地标签)
git push 远端主机名(origin) :refs/tags/标签名