Git学习之旅
前言:该文章内容仅为git学习笔记,同时博主将git总结出git的思维导图有助记忆学习,如果需要有误或希望增删内容可以下载XMind版的源文件。
一、关于版本控制
1.1本地版本控制
本地版本控制系统 许多人习惯用复制整个项目目录的方式来保存不同的版本,或许还会改名加上备份时间以示区别。这么做唯一的好处就是简单,但是特别容易犯错。有时候会混淆所在的工作目录,一不小心会写错文件或者覆盖意想外的文件。
1.2集中化的版本控制系统
如何让在不同系统上的开发者协同工作?于是,集中化的版本控制系统(Centralized Version Control Systems,简称 CVCS)应运而生。这类系统,诸如 CVS、Subversion 以及Perforce 等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。多年以来,这已成为版本控制系统的标准做法。
1.3分布式版本控制系统
在这类系统中,像Git、Mercurial、Bazaar 以及 Darcs 等,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。因为每一次的克隆操作,实际上都是一次对代码仓库的完整备份。
二、Git简介
git是一个分布式版本控制软件,最初由林纳斯·托瓦兹(Linus Torvalds)创作,于2005年以GPL发布。最初目的是为更好地管理Linux内核开发而设计。
2.1 Git历史
自2002年开始,林纳斯·托瓦兹决定使用BitKeeper作为Linux内核主要的版本控制系统用以维护代码。因为BitKeeper为专有软件,这个决定在社区中长期遭受质疑。在Linux社区中,特别是理查德·斯托曼与自由软件基金会的成员,主张应该使用开放源代码的软件来作为Linux核心的版本控制系统。林纳斯·托瓦兹曾考虑过采用现成软件作为版本控制系统(例如Monotone),但这些软件都存在一些问题,特别是性能不佳。现成的方案,如CVS的架构,受到林纳斯·托瓦兹的批评。
2005年,安德鲁·垂鸠写了一个简单程序,可以连接BitKeeper的存储库,BitKeeper著作权拥有者拉里·麦沃伊认为安德鲁·垂鸠对BitKeeper内部使用的协议进行逆向工程,决定收回无偿使用BitKeeper的授权。Linux内核开发团队与BitMover公司进行蹉商,但无法解决他们之间的歧见。林纳斯·托瓦兹决定自行开发版本控制系统替代BitKeeper,以十天的时间,编写出第一个git版本。
三、Git 工作流程
- Workspace:工作区
- Index / Stage:暂存区
- Repository:仓库区(或本地仓库)
+Remote:远程仓库
3.1工作区
程序员进行开发改动的地方,是你当前看到的,也是最新的。
平常我们开发就是拷贝远程仓库中的一个分支,基于该分支进行开发。在开发过程中就是对工作区的操作。
3.2暂存区
.git目录下的index文件, 暂存区会记录git add添加文件的相关信息(文件名、大小、timestamp...),不保存文件实体, 通过id指向每个文件实体。可以使用git status查看暂存区的状态。暂存区标记了你当前工作区中,哪些内容是被git管理的。
3.3本地仓库
保存了对象被提交 过的各个版本,比起工作区和暂存区的内容,它要更旧一些。
git commit后同步index的目录树到本地仓库,方便从下一步通过git push同步本地仓库与远程仓库的同步。
3.4远程仓库
远程仓库的内容可能被分布在多个地点的处于协作关系的本地仓库修改,因此它可能与本地仓库同步,也可能不同步,但是它的内容是最旧的。
【总结】
- 任何对象都是在工作区中诞生和被修改;
- 任何修改都是从进入index区才开始被版本控制;
- 只有把修改提交到本地仓库,该修改才能在仓库中留下痕迹;
- 与协作者分享本地的修改,可以把它们push到远程仓库来共享。
下面这幅图更加直接阐述了四个区域之间的关系
HEAD
HEAD,它始终指向当前所处分支的最新的提交点。你所处的分支变化了,或者产生了新的提交点,HEAD就会跟着改变。
四、安装Git
4.1环境说明
[root@mico ~]# rpm -qa centos-release
centos-release-7-5.1804.4.el7.centos.x86_64
[root@mico ~]# uname -a
Linux mico 3.10.0-862.11.6.el7.x86_64 #1 SMP Tue Aug 14 21:49:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
[root@mico ~]# getenforce
Disabled
[root@mico ~]# systemctl status firewalld.service
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
Active: inactive (dead)
Docs: man:firewalld(1)
4.2yum安装Git
centos自带git
[root@mico ~]# rpm -qa git
git-1.8.3.1-14.el7_5.x86_64
安装方法
yum install git -y
4.3编译安装
编译安装可以安装较新版本的git
git 下载地址:https://github.com/git/git/releases
# 安装依赖关系
yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel
# 编译安装
tar -zxf git-2.22.0.tar.gz
cd git-2.22.0
make configure
./configure --prefix=/usr
make
make install
五、初次运行Git前的配置
5.1配置Git
命令集
git config --global user.name "mico" #配置git使用用户
git config --global user.email "admin@mico.com" #配置git使用邮箱
git config --global color.ui true #语法高亮
git config --list # 查看全局配置
** 配置过程**
[root@mico ~]# git config --global user.name "mico" #配置git使用用户
[root@mico ~]# git config --global user.email "admin@mico.com" #配置git使用邮箱
[root@mico ~]# git config --global color.ui true #语法高亮
[root@mico ~]# git config --list # 查看全局配置
user.name=mico
user.email=admin@mico.com
color.ui=true
生成的配置文件
[root@mico ~]# cat ~/.gitconfig
[user]
email = admin@mico.com
name = mico
5.2 获取帮助
使用Git时需要获取帮助,有三种方法可以找到Git命令的使用手册:
git help <verb>
git <verb> --help
man git-<verb>
例如,要想获得配置命令的手册,执行
git help config
六、获取Git仓库(初始化仓库)
# 创建目录
mkdir git_data
# 进入目录
cd git_data/
# 初始化
git init
# 查看工作区状态
git status
操作过程
[root@mico practices]# mkdir git_data
[root@mico practices]# cd git_data/
[root@mico git_data]# git init
初始化空的 Git 版本库于 /root/practices/git_data/.git/
[root@mico git_data]# git status
# 位于分支 master
#
# 初始提交
#
无文件要提交(创建/拷贝文件并使用 "git add" 建立跟踪)
七、Git命令常用操作
命令 | 命令说明 |
---|---|
add | 添加文件内容至索引 |
bisect | 通过二分查找定位引入 bug 的变更 |
branch | 列出、创建或删除分支 |
checkout | 检出一个分支或路径到工作区 |
clone | 克隆一个版本库到一个新目录 |
commit | 记录变更到版本库 |
diff | 显示提交之间、提交和工作区之间等的差异 |
fetch | 从另外一个版本库下载对象和引用 |
grep | 输出和模式匹配的行 |
init | 创建一个空的 |
Git | 版本库或重新初始化一个已存在的版本库 |
log | 显示提交日志 |
merge | 合并两个或更多开发历史 |
mv | 移动或重命名一个文件、目录或符号链接 |
pull | 获取并合并另外的版本库或一个本地分支 |
push | 更新远程引用和相关的对象 |
rebase | 本地提交转移至更新后的上游分支中 |
reset | 重置当前HEAD到指定状态 |
rm | 从工作区和索引中删除文件 |
show | 显示各种类型的对象 |
status | 显示工作区状态 |
tag | 创建、列出、删除或校验一个GPG签名的 tag 对象 |
常用操作示意图
文件的状态变化周期
7.1创建文件
[root@mico git_data]# touch README
[root@mico git_data]# git status
# 位于分支 master
#
# 初始提交
#
# 未跟踪的文件:
# (使用 "git add <file>..." 以包含要提交的内容)
#
# README
提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)
7.2添加文件跟踪
[root@mico git_data]# git add ./*
[root@mico git_data]# git status
# 位于分支 master
#
# 初始提交
#
# 要提交的变更:
# (使用 "git rm --cached <file>..." 撤出暂存区)
#
# 新文件: README
#
文件会添加到.git隐藏目录
[root@mico git_data]# tree .git/
.git/
├── branches
├── 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
├── objects
│ ├── e6
│ │ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│ ├── info
│ └── pack
└── refs
├── heads
└── tags
10 directories, 15 files
由工作区提交到本地仓库
[root@mico git_data]# git commit -m "first commit"
[master(根提交) 45a5f78] first commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README
查看git的状态
[root@mico git_data]# git status
# 位于分支 master
无文件要提交,干净的工作区
查看git的状态
[root@mico git_data]# 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
│ ├── 45
│ │ └── a5f78aedaceb9b7082e3f7292f8ab1ac519d02
│ ├── 54
│ │ └── 3b9bebdc6bd5c4b22136034a95dd097a57d3dd
│ ├── e6
│ │ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│ ├── info
│ └── pack
└── refs
├── heads
│ └── master
└── tags
15 directories, 21 files
7.3添加新文件
git add * 添加到暂存区域
git commit 提交git仓库 -m 后面接上注释信息,内容关于本次提交的说明,方便自己或他人查看
修改或删除原有文件:
- 常规方法
git add *
git commit
+简便方法
git commit -a -m "注释信息"
-a 表示直接提交
Tell the command to automatically stage files that have been modified and deleted, but new files you have not told Git about are
not affected.
7.4删除git内的文件
命令说明
没有添加到暂存区的数据直接rm删除即可
已经添加到暂存区数据:
git rm --cached database
#→将文件从git暂存区域的追踪列表移除(并不会删除当前工作目录内的数据文件)
git rm -f database
#→将文件数据从git暂存区和工作目录一起删除
命令实践
[root@mico git_data]# touch 123
[root@mico git_data]# git status
# 位于分支 master
#
# 初始提交
#
# 未跟踪的文件:
# (使用 "git add <file>..." 以包含要提交的内容)
#
# 123
提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)
[root@mico git_data]# git add 123
[root@mico git_data]# git status
# 位于分支 master
#
# 初始提交
#
# 要提交的变更:
# (使用 "git rm --cached <file>..." 撤出暂存区)
#
# 新文件: 123
#
[root@mico git_data]# rm 123 -f
[root@mico git_data]# ls
[root@mico git_data]# git status
# 位于分支 master
#
# 初始提交
#
# 要提交的变更:
# (使用 "git rm --cached <file>..." 撤出暂存区)
#
# 新文件: 123
#
# 尚未暂存以备提交的变更:
# (使用 "git add/rm <file>..." 更新要提交的内容)
# (使用 "git checkout -- <file>..." 丢弃工作区的改动)
#
# 删除: 123
#
[root@mico git_data]# git rm --cached 123
rm '123'
[root@mico git_data]# git status
# 位于分支 master
#
# 初始提交
#
无文件要提交(创建/拷贝文件并使用 "git add" 建立跟踪)
重命名暂存区数据
- 没有添加到暂存区的数据直接 mv/rename 改名即可
- 已经添加到暂存区的数据
git mv <old-file-name> <new-file-name>
7.5查看历史记录
• git log #→查看提交历史记录
• git log -2 #→查看最近几条记录
• git log -p -1 #→-p显示每次提交的内容差异,例如仅查看最近一次差异
• git log --stat -2 #→--stat简要显示数据增改行数,这样能够看到提交中修改过的内容,对文件添加或移动的行数,并在最后列出所有增减行的概要信息
• git log --pretty=oneline #→--pretty根据不同的格式展示提交的历史信息
• git log --pretty=fuller -2 #→以更详细的模式输出提交的历史记录
• git log --pretty=fomat:"%h %cn" #→查看当前所有提交记录的简短SHA-1哈希字串与提交着的姓名。
使用format参数来指定具体的输出格式:
格式 | 说明 |
---|---|
%s | 提交说明。 |
%cd | 提交日期。 |
%an | 作者的名字。 |
%cn | 提交者的姓名。 |
%ce | 提交者的电子邮件。 |
%H | 提交对象的完整SHA-1哈希字串。 |
%h | 提交对象的简短SHA-1哈希字串。 |
%T | 树对象的完整SHA-1哈希字串。 |
%t | 树对象的简短SHA-1哈希字串。 |
%P | 父对象的完整SHA-1哈希字串。 |
%p | 父对象的简短SHA-1哈希字串。 |
%ad | 作者的修订时间。 |
命令实践
[root@mico git_data]# git log
commit c2caa1467c39f006cffbcafa838d575c526f4347
Author: TRsky <625310581@qq.com>
Date: Thu Jul 11 10:07:57 2019 +0800
show test
commit 90370a8eb959ccb2f63f7a75e4334e908315b31b
Author: TRsky <625310581@qq.com>
Date: Thu Jul 11 10:07:22 2019 +0800
the first commit
7.6 还原历史数据
Git服务程序中有一个叫做HEAD的版本指针,当用户申请还原数据时,其实就是将HEAD指针指向到某个特定的提交版本,但是因为Git是分布式版本控制系统,为了避免历史记录冲突,故使用了SHA-1计算出十六进制的哈希字串来区分每个提交版本,另外默认的HEAD版本指针会指向到最近的一次提交版本记录,而上一个提交版本会叫HEAD,上上一个版本则会叫做HEAD^,当然一般会用HEAD~5来表示往上数第五个提交版本。
git reset --hard hash
git reset --hard HEAD^ #→还原历史提交版本上一次
git reset --hard 3de15d4 #→找到历史还原点的SHA-1值后,就可以还原(值不写全,系统会自动匹配)
命令实践
[root@mico git_data]# git log
commit c2caa1467c39f006cffbcafa838d575c526f4347
Author: TRsky <625310581@qq.com>
Date: Thu Jul 11 10:07:57 2019 +0800
show test
commit 90370a8eb959ccb2f63f7a75e4334e908315b31b
Author: TRsky <625310581@qq.com>
Date: Thu Jul 11 10:07:22 2019 +0800
the first commit
还原数据
[root@mico git_data]# git reset --hard 90370
HEAD 现在位于 90370a8 the first commit
[root@mico git_data]# ls
README
[root@mico git_data]#
7.7还原未来数据
什么是未来数据?就是你还原到历史数据了,但是你后悔了,想撤销更改,但是git log已经找不到这个版本了。
git reflog #→查看未来历史更新点
测试命令
[root@mico git_data]# git reflog
90370a8 HEAD@{0}: reset: moving to 90370
c2caa14 HEAD@{1}: commit: show test
90370a8 HEAD@{2}: commit (initial): the first commit
[root@mico git_data]#
7.8标签使用
前面回滚使用的是一串字符串,又长又难记。
git tag v1.0 #→当前提交内容打一个标签(方便快速回滚),每次提交都可以打个tag。
git tag #→查看当前所有的标签
git show v1.0 #→查看当前1.0版本的详细信息
git tag v1.2 -m "version 1.2 release is test" #→创建带有说明的标签,-a指定标签名字,-m指定说明文字
git tag -d v1.0 #→我们为同一个提交版本设置了两次标签,删除之前的v1.0
命令实践
[root@mico git_data]# git reset --hard 90370
HEAD 现在位于 90370a8 the first commit
[root@mico git_data]# git reset --hard c2caa
HEAD 现在位于 c2caa14 show test
[root@mico git_data]# git tag v20190711
[root@mico git_data]# git tag
v20190711
[root@mico git_data]# git show v20190711
commit c2caa1467c39f006cffbcafa838d575c526f4347
Author: Mico <admin@mico.com>
Date: Thu Jul 11 10:07:57 2019 +0800
show test
diff --git a/test b/test
new file mode 100644
index 0000000..e69de29
7.9对比数据
git diff可以对比当前文件与仓库已保存文件的区别,知道了对README作了什么修改后,再把它提交到仓库就放多了。
git diff README
八、分支结构
在实际的项目开发中,尽量保证master分支稳定,仅用于发布新版本,平时不要随便直接修改里面的数据文件。
那在哪干活呢?干活都在dev分支上。每个人从dev分支创建自己个人分支,开发完合并到dev分支,最后dev分支合并到master分支。所以团队的合作分支看起来会像下图那样。
8.1分支切换
[root@mico git_data]# git branch linux
[root@mico git_data]# git branch
linux
* master
[root@mico git_data]# git checkout linux
切换到分支 'linux'
[root@mico git_data]# git branch
* linux
master
[root@mico git_data]#
在Linux分支进行修改
[root@mico git_data]# cat README
[root@mico git_data]# echo "2019年7月11号">>README
[root@mico git_data]# git add .
[root@mico git_data]# git commit -m "2019年7月11号11点0分"
[linux 20cefd6] 2019年7月11号11点0分
1 file changed, 1 insertion(+)
[root@mico git_data]# git status
# 位于分支 linux
无文件要提交,干净的工作区
回到master分支
[root@mico git_data]# git checkout master
切换到分支 'master'
[root@mico git_data]# cat README
[root@mico git_data]# git log -1
commit c2caa1467c39f006cffbcafa838d575c526f4347
Author: TRsky <admin@mico.com>
Date: Thu Jul 11 10:07:57 2019 +0800
show test
合并代码
[root@mico git_data]# git merge linux
更新 c2caa14..20cefd6
Fast-forward
README | 1 +
1 file changed, 1 insertion(+)
[root@mico git_data]# git status
# 位于分支 master
无文件要提交,干净的工作区
[root@mico git_data]# cat README
2019年7月1号
8.2合并失败解决
模拟冲突,在文件的同一行做不同的修改
在master分支进行修改
[root@mico git_data]# cat README
2019年7月1号
[root@mico git_data]# echo "this is master" >> README
[root@mico git_data]# git commit -a -m "mico 2019年7月11日 "
[master 5b3e0ce] mico 2019年7月11日
1 file changed, 1 insertion(+)
切换至linux分支
[root@mico git_data]# git checkout linux
切换到分支 'linux'
[root@mico git_data]# git branch
* linux
master
[root@mico git_data]# cat README
2019年7月1号
this is linux
[root@mico git_data]# git commit -a -m "2019年7月11日 linux"
[linux 1973909] 2019年7月11日 linux
1 file changed, 1 insertion(+)
回到master分支,进行合并,出现冲突
[root@mico git_data]# git checkout master
切换到分支 'master'
[root@mico git_data]# git merge linux
自动合并 README
冲突(内容):合并冲突于 README
自动合并失败,修正冲突然后提交修正的结果。
解决冲突
[root@mico git_data]# cat README
2019年7月1号
<<<<<<< HEAD
this is master
=======
this is linux
>>>>>>> linux
[root@mico git_data]# vim README
[root@mico git_data]# git commit -a -m "2019年7月11号 merge"
[master 67484d9] 2019年7月11号 merg
手动修改冲突的部分并重新提交
8.3删除分支
因为之前已经合并了linux分支,所以现在看到它在列表中。 在这个列表中分支名字前没有 * 号的分支通常可以使用 git branch -d 删除掉;你已经将它们的工作整合到了另一个分支,所以并不会失去任何东西。
查看所有包含未合并工作的分支,可以运行 git branch --no-merged:
git branch --no-merged
testing
这里显示了其他分支。 因为它包含了还未合并的工作,尝试使用 git branch -d 命令删除它时会失败:
git branch -d testing
error: The branch 'testing' is not fully merged.
If you are sure you want to delete it, run 'git branch -D testing'.
如果真的想要删除分支并丢掉那些工作,如同帮助信息里所指出的,可以使用 -D 选项强制删除它。
删除分支
git branch -d 删除分支
git push origin --delete 删除远程分支
命令实践
[root@mico git_data]# git branch
linux
* master
[root@mico git_data]# git branch -d linux
已删除分支 linux(曾为 1973909)。
[root@mico git_data]# git branch
* master
[root@mico git_data]#
【学习整理】