01.什么是 GIT
概念
Git(读音为/g ɪt/)是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。也是 Linus Torvalds
为了帮助管理 Linux 内核开发而开发的一个开源的版本控制软件。
版本控制工具是践行 devops
理念,CI/CD
中的一个环节,是自动化测试工程师不可或缺的一门技术。
github,gitee,gitlab 的区别
GitHub 是一个面向开源及私有软件项目的托管平台,因为只支持 Git 作为唯一的版本库格式进行托管,故名 GitHub。
Gitee 是开源中国(OSChina)推出的基于 Git 的代码托管服务,是国内的 GitHub。
GitLab 是一个用于代码仓库管理系统的开源项目,使用 Git 作为代码管理工具,并在此基础上搭建起来的 Web 服务。
02.GIT的使用
本地操作
如果你想在 Linux 上用二进制安装程序来安装基本的 Git 工具,可以使用发行版包含的基础软件包管理工具来安装。以 Fedora 为例,如果你在使用它,你可以使用 dnf
:
$ sudo dnf install git-all
如果你在基于 Debian 的发行版上,如 Ubuntu,请使用 apt
:
$ sudo apt install git-all
要了解更多选择,Git 官方网站上有在各种 Unix 发行版的系统上的安装步骤,网址为 https://git-scm.com/download/linux。
在 Mac 上安装 Git 有多种方式。最简单的方法是安装 Xcode Command Line Tools。Mavericks (10.9) 或更高版本的系统中,在 Terminal 里尝试首次运行 Git 命令即可。
$ git --version
如果没有安装过命令行开发者工具,将会提示你安装。
在 Windows 上安装 Git 也有几种安装方法。官方版本可以在 Git 官方网站下载。打开 https://git-scm.com/download/win,下载会自动开始。双击下载的安装文件,按照引导程序安装即可。
安装完 Git 之后,要做的第一件事就是设置你的用户名和邮件地址。这一点很重要,因为每一个 Git 提交都会使用这些信息,它们会写入到你的每一次提交中,不可更改,在终端运行如下命令:
git config --global user.name "xinlan"
git config --global user.email "[email protected]"
加了 --global
表示全局设置,且只需要设置一次。
如果你有一个尚未进行版本控制的项目目录,想要用 Git 来控制它,那么首先需要进入该项目目录中。之后执行命令:
$ git init
该命令将创建一个名为 .git
的子目录,这个子目录含有你初始化的 Git 仓库中所有的必须文件,这些文件是 Git 仓库的骨干。请不要修改它。
2.4 添加文件进行跟踪
上面的操作,我们仅仅是做了一个初始化的操作,项目里的文件还没有被跟踪。
如果在一个已存在文件的文件夹(而非空文件夹)中进行版本控制,现在应该开始追踪这些文件了。可以通过 git add
命令来指定所需的文件来进行追踪。
$ git add *.py
$ git add LICENSE
要将上一个步骤中追踪的文件提交到仓库,运行命令 git commit
。这样会启动文本编辑器来输入提交说明。
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
#
# Initial commit
#
# Changes to be committed:
# new file: LICENSE
# new file: test.py
#
~
~
~
~
~
~
~
~
~
~
"C:/Users/men85/Desktop/study/.git/COMMIT_EDITMSG" [unix] 12L, 251C
也可以在 commit
命令后添加 -m
选项,将提交信息与命令放在同一行
git commit -m "init"
Git 有三种状态,你的文件可能处于其中之一:已提交(committed)、已修改(modified) 和 已暂存(staged)。
已修改表示修改了文件,但还没保存到数据库中。
已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。
已提交表示数据已经安全地保存在本地数据库中。
这会让我们的 Git 项目拥有三个阶段:工作区、暂存区以及 Git 目录。
工作区即是项目的根目录,是你工作的区域,是对项目的某个版本独立提取出来的内容。这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。
暂存区是一个文件,保存了下次将要提交的文件列表信息,一般在 Git 仓库目录中。按照 Git 的术语叫做“索引”,不过一般说法还是叫“暂存区”。
Git 仓库目录是 Git 用来保存项目的元数据和对象数据库的地方。这是 Git 中最重要的部分,从其它计算机克隆仓库时,复制的就是这里的数据。
基本的 Git 工作流程如下:
在工作区中修改文件。
将你想要下次提交的更改选择性地暂存,这样只会将更改的部分添加到暂存区。git add
提交更新,找到暂存区的文件,将快照永久性存储到 Git 目录。git commit
你工作目录下的每一个文件都不外乎这两种状态:已跟踪 或 未跟踪。已跟踪的文件是指那些被纳入了版本控制的文件,在上一次快照中有它们的记录,在工作一段时间后, 它们的状态可能是未修改,已修改或已放入暂存区。简而言之,已跟踪的文件就是 Git 已经知道的文件。
编辑过某些文件之后,由于自上次提交后你对它们做了修改,Git 将它们标记为已修改文件。在工作时,你可以选择性地将这些修改过的文件放入暂存区,然后提交所有已暂存的修改,如此反复。
可以用 git status
命令查看哪些文件处于什么状态。如果所有文件没有修改,且都已经提交到本地数据库,也及时工作区,暂存区,Git 仓库一致,你会看到类似这样的输出:
$ git status
On branch master
nothing to commit, working tree clean
现在,让我们在项目下创建一个新的 README
文件。如果之前并不存在这个文件,使用 git status
命令,你将看到一个新的未跟踪文件:
$ git status
On branch master
Untracked files:
(use "git add
..." to include in what will be committed) README
nothing added to commit but untracked files present (use "git add" to track)
现在我们来修改一个已被跟踪的文件。如果你修改了一个名为 test.py
的已被跟踪的文件,然后运行 git status
命令,会看到下面内容:
$ git status
On branch master
Changes not staged for commit:
(use "git add
..." to update what will be committed) (use "git restore
..." to discard changes in working directory) modified: test.py
Untracked files:
(use "git add
..." to include in what will be committed) README
no changes added to commit (use "git add" and/or "git commit -a")
我们在练习一下 Git 的工作流程,将增加的文件和修改的内容提交到 Git 仓库。
$ git add .
$ git commit -m "练习"
[master 2852e80] 缁冧範
2 files changed, 1 insertion(+)
create mode 100644 README
当想要跟踪目录下所有的文件时可以运行命令 git add .
在提交了若干更新,你也许想回顾下提交历史。完成这个任务最简单而又有效的工具是 git log
命令。例如在我的带班课件项目中运行 git log
命令时,可以看到下面的输出:
$ git log
commit 304b472cab3fcff5c220bf3e8e91a2e2fa642003 (HEAD -> master, origin/master)
Author: xinlan <[email protected]>
Date: Thu Aug 26 14:05:00 2021 +0800
日常
commit 65f23a537366f35bd99047438c40547278294028
Author: xinlan <[email protected]>
Date: Fri Aug 6 21:18:35 2021 +0800
haha
commit eca023381f42ce0428ab45c0a8b33621dd2cc6f8
Author: xinlan <[email protected]>
Date: Sat May 29 19:19:24 2021 +0800
py38 day43
不传入任何参数的默认情况下,git log
会按时间先后顺序列出所有的提交,最近的更新排在最上面。git log
命令还有很多参数,用来搜索和显示。
其中一个非常有用的参数是 --pretty
。这个参数可以使用不同于默认格式的方式展示提交历史。这个选项有一些内建的子选项供你使用。比如 oneline
会将每个提交放在一行显示,在浏览大量的提交时非常有用。另外还有 short
,full
和 fuller
选项,它们展示信息的格式基本一致,但是详尽程度不一:
$ git log --pretty=oneline
304b472cab3fcff5c220bf3e8e91a2e2fa642003 (HEAD -> master, origin/master) 日常
65f23a537366f35bd99047438c40547278294028 haha
eca023381f42ce0428ab45c0a8b33621dd2cc6f8 py38 day43
1b174b1486bae0554ff8a79acca55369387480f9 py41 day2
5ae08fa293a9a6bd7eddf8cb365e07cc221f0c07 py38day42
6fe8725de1151455f25e069ad80357edf5c4d6b0 'py38day41'
2effcc5dc6670a23cdbf4049321923b735ae3f16 add 41
03.远程操作
远程仓库是指托管在因特网或其他网络中的你的项目的版本库。
要创建自己的远程仓库,最简单的方法是在 gitee(码云),或 GitHub 上创建一个远程仓库。这里推荐使用码云,中文且速度快,下面以码云为例。码云地址 https://gitee.com/,注册账号请自理。
注册并登录码云后,点击右上角的加号,选择新建仓库
进入新建仓库页面,填写必要选项后,点击创建
仓库创建成功后会出现下面的页面,包含仓库的地址和一些帮助信息
运行 git remote add
添加一个新的远程 Git 仓库,同时指定一个方便使用的简写。运行
$ git remote add origin [email protected]:wcflove/study.git
这会给当前本地仓库添加一个远程仓库,地址为 [email protected]:wcflove/study.git
,远程仓库地址的简写为 origin
(你可以取你想要的名字)。
运行 git remote -v
命令可以查看远程仓库信息,一个本地仓库可以有多个远程仓库
$ git remote -v
gitee [email protected]:wcflove/study.git (fetch)
gitee [email protected]:wcflove/study.git (push)
通过命令 git push
可以将你的本地项目推送到远程仓库。当你想要将 master
分支(关于分支我们后面再详细讨论)推送到 origin
服务器时(再次说明,克隆时通常会自动帮你设置好那两个名字), 那么运行这个命令就可以将你所做的备份到服务器:
$ git push origin master
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 8 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 481 bytes | 481.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0), pack-reused 0
remote: Powered by GITEE.COM [GNK-6.1]
To gitee.com:wcflove/study.git
* [new branch] master -> master
注意:这一步操作需要验证你的权限,如果在添加远程仓库时,使用的是 https
协议的地址,那么需要你输入用户名和密码。如果使用的是 ssh
协议地址,那么需要配置 ssh
的公钥(详见码云帮助文档)。
推送成功后刷新你的远程仓库,你会看到刚刚推送上去的文件。
3.4 从远程仓库中拉取
从远程仓库中获得数据,可以执行:
$ git pull
这个命令会访问远程仓库,从中拉取所有你还没有的数据,并自动合并该远程分支到当前分支。
运行命令 git clone
会将远程仓库下载到当前目录。例如:
git clone [email protected]:wcflove/study.git
这会在当前目录创建 study
文件夹,并在这个目录下初始化一个 .git
文件夹,自动将地址 [email protected]:wcflove/study.git
添加为远程仓库并默认以 “origin” 为简写, 自动设置本地 master 分支跟踪克隆的远程仓库的 master
分支,并从远程仓库拉取 master 分支下所有数据放入 .git
文件夹,然后从中读取最新版本的文件的拷贝。
04.分支操作
几乎所有的版本控制系统都以某种形式支持分支。使用分支意味着你可以把你的工作从开发主线上分离开来,以免影响开发主线。
为了真正理解 Git 处理分支的方式,我们需要回顾一下 Git 是如何保存数据的。Git 保存的不是文件的变化或者差异,而是一系列不同时刻的 快照 。在进行提交操作时,Git 会保存一个提交对象(commit object)。该提交对象会包含一个指向暂存内容快照的指针,还包含了作者的姓名和邮箱、提交时输入的信息以及指向它的父对象的指针。首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象, 而由多个分支合并产生的提交对象有多个父对象。
Git 的分支,其实本质上仅仅是指向提交对象的可变指针。Git 的默认分支名字是 master
。在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master
分支。 master
分支会在每次提交时自动向前移动。
创建分支非常简单,它只是为你创建了一个可以移动的新的指针。比如,创建一个 testing 分支, 你需要使用 git branch
命令:
$ git branch testing
这会在当前所在的提交对象上创建一个指针。
Git 中有一个名为 HEAD
的特殊指针,指向当前所在的本地分支(译注:将 HEAD
想象为当前分支的别名)。在本例中,你仍然在 master
分支上。因为 git branch
命令仅仅 创建 一个新分支,并不会自动切换到新分支中去。
要切换到一个已存在的分支,你需要使用 git checkout
命令。我们现在切换到新创建的 testing
分支去:
$ git checkout testing
这样 HEAD
就指向 testing
分支了。
当我们在 testing 分支上工作并形成了一些列提交后,可以切换回 master 分支,然后运行 git merge
命令:
$ git checkout master
$ git merge testing
将其合并到 master 分支上。
有时候合并操作不会如此顺利。如果你在两个不同的分支中,对同一个文件的同一个部分进行了不同的修改,Git 就没法干净的合并它们。
$ git merge testing
Auto-merging test.py
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
此时 Git 做了合并,但是没有自动地创建一个新的合并提交。Git 会暂停下来,等待你去解决合并产生的冲突。你可以在合并冲突后的任意时刻使用 git status
命令来查看那些因包含合并冲突而处于未合并(unmerged)状态的文件:
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add
..." to mark resolution) both modified: test.py
no changes added to commit (use "git add" and/or "git commit -a")
任何因包含合并冲突而有待解决的文件,都会以未合并状态标识出来。Git 会在有冲突的文件中加入标准的冲突解决标记,这样你可以打开这些包含冲突的文件然后手动解决冲突。出现冲突的文件会包含一些特殊区段,看起来像下面这个样子:
<<<<<<< HEAD:test.py
print('hello world!')
=======
print("hello world!")
>>>>>>> dev:test.py
这表示 HEAD
所指示的版本(也就是你的 master
分支所在的位置,因为你在运行 merge 命令的时候已经切换到了这个分支)在这个区段的上半部分(=======
的上半部分),而 dev
分支所指示的版本在 =======
的下半部分。为了解决冲突,你必须选择使用由 =======
分割的两部分中的一个,或者你也可以自行合并这些内容。
例如,你可以通过把这段内容换成下面的样子来解决冲突
print("hello world!")
上述的冲突解决方案仅保留了其中一个分支的修改,并且 <<<<<<<
, =======
, 和 >>>>>>>
这些行被完全删除了。在你解决了所有文件里的冲突之后,对每个文件使用 git add
命令来将其标记为冲突已解决。一旦暂存这些原本有冲突的文件,Git 就会将它们标记为冲突已解决。
你可以再次运行 git status
来确认所有的合并冲突都已被解决:
$ git status
On branch master
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: test.py
如果你对结果感到满意,并且确定之前有冲突的的文件都已经暂存了,这时你可以输入 git commit
来完成合并提交。
本文参考和节选自Pro GIT