1、git介绍
Git 是一个开源的分布式版本控制系统,用于敏捷
高效地处理任何或小或大的项目。
Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本
控制软件。
Git 与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,
不必服务器端软件支持
2、git与svn的区别
1、GIT 是分布式的,SVN 不是:这是 GIT 和其它非分布式的版本控制系统,例如 SVN,
CVS 等,核心的区别。
2、GIT 把内容按元数据方式存储,而 SVN 是按文件:所有的资源控制系统都是把文件
的元信息隐藏在一个类似.svn,.cvs 等的文件夹里。
3、GIT 分支和 SVN 的分支不同:分支在 SVN 中一点不特别,就是版本库中的另外的一
个目录。
4、GIT 没有一个全局的版本号,而 SVN 有:目前为止这是跟 SVN 相比 GIT 缺少的大
的一个特征。
5、GIT 的内容完整性要优于 SVN:GIT 的内容存储使用的是 SHA-1 哈希算法。这能确保
代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏
3、Git的安装
方法一:使用yum进行安装(安装的版本是1.8的)
yum -y install git
方法二:使用编译安装
1.安装依赖
yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel gcc perl-ExtUtils-MakeMaker -y
1.下载最新的安装包
wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.9.5.tar.gz
2.解压并进行安装
make prefix=/application/git all
make prefix=/application/git install
m /usr/bin/git
ln -s /application/git/bin/git /usr/bin/git
git --version
其它系统安装过程见官方文档:https://git-scm.com/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%AE%89%E8%A3%85-Git
#配置git使用用户
[root@git-node1 ~]# git config –global user.name “liu”
#配置git使用邮箱
[root@git-node1 ~]# git config –global user.email “liu@qq.com”
#语法高亮
[root@git-node1 ~]# git config –global color.ui true
#查看git仓库信息
[root@git-node1 ~]# git config –list
user.name=liu
user.email=liu@qq.com
color.ui=true
4、Git的配置
Git的配置从上到下分为三层system/global/local,使用三个不同的参数进行设置,每个层次的配置存储在不同的位置
1)/etc/gitconfig 文件:包含了适用于系统所有用户和所有库的值。如果你传递参数选项’--system’ 给 git config,它将明确的读和写这个文件。
2)~/.gitconfig 文件 :具体到你的用户。你可以通过传递--global 选项使 Git 读或写这个特定的文件。
3)位于 git 目录的 config 文件 (也就是 .git/config) :无论你当前在用的库是什么,特定指向该单一的库。每个级别重写前一个级别的值。因此,在.git/config 中的值覆盖在/etc/gitconfig 中的同一个值。
mkdir /git_test
#仓库初始化
git init
#设置本地仓库的配置信息(用户名与邮箱)
git config --local user.name oldboy
git config --local user.email oldboy@qq.co
#查看local层次的config配置信息
git config --list
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
user.name=oldboy
user.email=oldboy@qq.com
通常我们只配置global级别
[root@ci-node1 git_test]# git config --global user.name liu
[root@ci-node1 git_test]# git config --global user.email liu@qq.com
[root@ci-node1 git_test]#git config --global color.ui true #语法高亮
[root@ci-node1 git_test]# git config --list
user.name=liu
user.email=liu@qq.com
5、Git仓库初始化
#建立一个空仓库
[root@ci-node1 /]# mkdir /git_test
[root@ci-node1 /]# cd git_test/
#初始化仓库
[root@ci-node1 git_test]# git init
Initialized empty Git repository in /git_test/.git/
#空仓库创建完成后 git_test 文件夹下会生成一个.git 隐藏文件夹。仓库默认包含一个主分支,即 master,默认操作都是在主分支 master 上进行的
[root@ci-node1 git_test]# ll -a
total 0
drwxr-xr-x 3 root root 18 Mar 28 10:16 .
dr-xr-xr-x. 20 root root 273 Mar 28 10:16 ..
drwxr-xr-x 7 root root 119 Mar 28 10:16 .git
5.1、设置过虑文件
有了仓库,我们便可以在 git_test 文件夹下的工作区做文件增删修改工作了,但很多时候,我们只在意开发过程中的源文件,并不需要管理自动产生的其他临时文件。这时候我们便需要一个过滤文件,在这个文件中设置过滤规则,让 Git 能够自动过滤掉那些临时文件,这个文件便是.gitignore 文件
[root@ci-node1 git_test]# touch .gitignore
[root@ci-node1 git_test]# vim .gitignore
[root@ci-node1 git_test]# cat .gitignore
test.txt #过滤text.txt文件
/text/ #过滤text目录
*.txt #过滤所有txt结尾的文件
常用的通配规则:
以斜杠“/”开头表示目录
以星号“*”通配多个多个字符
以问号“?”通配单个字符
以方括号“[]”包含单个字符的匹配列表
以叹号“!”表示不忽略(跟踪)匹配到的文件或目录
6、Git仓库的基础操作
6.1、Git的四个区域
Workspace:工作区(他持有实际文件)
Index / Stage / Cached:暂存区(它像一个结存区域,临时保存你的改动)一般存放在 ".git 目录下" 下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)
Repository:本地仓库工作区有一个隐藏目录.git,这个不算工作区,而是 Git 的版本
库。
Remote:远程仓库
6.2、Git的四个状态
Untracked:新增的文件的状态,未受 Git 管理,记录在工作区
Modified:受 Git 管理过的文件的改动状态(包括改动内容、删除文件),记录在工作
区
Staged:将记录在工作区的文件变动状态通知了 Git,记录在暂存区
nmodified:受 Git 管理中的文件状态(没有变动),记录在本地仓库/远程仓库
6.3、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 对象
6.4、Git基础操作
6.4.1、Git提交数据
我们可以简单的把工作目录理解成是一个被Git服务程序管理的目录,Git会时刻的追踪目录内文件的改动,另外在安装好了Git服务程序后,默认就会创建好了一个叫做master的分支,我们直接可以提交数据到了
#创建空仓库
[root@ci-node1 ~]# mkdir /git_data/
#进入目录
[root@ci-node1 ~]# cd /git_data/
#初始化仓库
[root@ci-node1 git_data]# git init
Initialized empty Git repository in /git_data/.git/
#创建文件
[root@ci-node1 git_data]# touch {a..c}.txt
#查看仓库的状态(未跟踪状态)
[root@ci-node1 git_data]# git status
On branch master
Initial commit
Untracked files:
(use "git add <file>..." to include in what will be committed)
#发现新建的三个文件(红色显示)
a.txt
b.txt
c.txt
nothing added to commit but untracked files present (use "git add" to track)
#将工作目录文件添加到暂存区
[root@ci-node1 git_data]# git add .
#查看git状态
[root@ci-node1 git_data]# git status
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
#此时新建的文件已经变成绿色
new file: a.txt
new file: b.txt
new file: c.txt
#git commit提交暂存区文件至git版本仓库
[root@ci-node1 git_data]# git commit -m "the first commit"
[master (root-commit) 2b47557] the first commit
3 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 a.txt
create mode 100644 b.txt
create mode 100644 c.txt
6.4.2、Git移除数据
有些时候会向把已经添加到暂存区的文件移除,但仍然希望文件在工作目录中不丢失,换句话说,就是把文件从追踪清单中删除。
#先进行重命名文件
[root@ci-node1 git_data]# mv a.txt aaa.txt
#删除git里的快照文件
[root@ci-node1 git_data]# git rm a.txt
rm 'a.txt'
[root@ci-node1 git_data]# git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: a.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
aaa.txt
#再将改名后的文件提交到暂存区
[root@ci-node1 git_data]# git add aaa.txt
[root@ci-node1 git_data]# git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: a.txt -> aaa.txt
#再将暂存区的文件提交到本地仓库
[root@ci-node1 git_data]# git commit -m "重命名a文件为aaa"
[master 21faebf] 重命名a文件为aaa
1 file changed, 0 insertions(+), 0 deletions(-)
rename a.txt => aaa.txt (100%)
方法二:使用git mv直接进行改名
#使用git mv直接进行改名操作
[root@ci-node1 git_data]# git mv aaa.txt a.txt
#查看git状态
[root@ci-node1 git_data]# git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: aaa.txt -> a.txt
#提交到git本地仓库
[root@ci-node1 git_data]# git commit -m "rename aaa.txt to a.txt"
[master 1c2c7fc] rename aaa.txt to a.txt
1 file changed, 0 insertions(+), 0 deletions(-)
rename aaa.txt => a.txt (100%)
#删除工作目录文件与暂存区文件
[root@ci-node1 git_data]# touch c
[root@ci-node1 git_data]# git add c
[root@ci-node1 git_data]# git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: c
git rm -f data将文件数据从git暂存区和工作目录一起删除
[root@ci-node1 git_data]# git rm -f c
rm 'c'
[root@ci-node1 git_data]# ls
a.txt b.txt c.txt
#将文件从暂存区的追踪列表状态移除(并不会删除当前工作目录内的文件)
[root@ci-node1 git_data]# touch test.txt
[root@ci-node1 git_data]# git add test.txt
[root@ci-node1 git_data]# git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
#提交到暂存区后文件名变成绿色
new file: test.txt
#从暂存区追踪列表移除
[root@ci-node1 git_data]# git rm --cached test.txt
rm 'test.txt'
[root@ci-node1 git_data]# git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
#从追踪状态移除后,变成红色
test.txt
nothing added to commit but untracked files present (use "git add" to track)
6.4.3、Git查看历史记录
git log #→查看提交历史记录
git log -2 #→查看最近几条记录
git log -p -1 #→-p显示每次提交的内容差异,例如仅查看最近一次差异
git log --stat -2 #→--stat简要显示数据增改行数,这样能够看到提交中修改过的内容,对文件添加或移动的行数,并在最后列出所有增减行的概要信息
git reflog #→查看所有历史记录
git log --oneline --decorate #→查看更详细的内容
git log --pretty=oneline #→--pretty根据不同的格式展示提交的历史信息
git log --pretty=fuller -2 #→以更详细的模式输出提交的历史记录
git log --pretty=fomat:"%h %cn" #→查看当前所有提交记录的简短SHA-1哈希字串与提交者的姓名,其他格式见备注。
fomat参数:
%s 提交说明。
%cd 提交日期。
%an 作者的名字。
%cn 提交者的姓名。
%ce 提交者的电子邮件。
%H 提交对象的完整SHA-1哈希字串。
%h 提交对象的简短SHA-1哈希字串。
%T 树对象的完整SHA-1哈希字串。
%t 树对象的简短SHA-1哈希字串。
%P 父对象的完整SHA-1哈希字串。
%p 父对象的简短SHA-1哈希字串。
%ad 作者的修订时间。
6.4.4、Git还原数据
[root@ci-node1 git_data]# cat test.txt
#在test文件中添加内容,进行提交到git本地仓库
[root@ci-node1 git_data]# echo "test" > test.txt
#提交到暂存区
[root@ci-node1 git_data]# git add test.txt
#提交到本地仓库,提交后发现写错了
[root@ci-node1 git_data]# git commit -m "modified test.txt"
[master 52e43ab] modified test.txt
1 file changed, 1 insertion(+)
#查看git历史记录
[root@ci-node1 git_data]# git log --oneline --decorate
52e43ab (HEAD -> master) modified test.txt
e689c97 修改a.txt文件内容
1c2c7fc rename aaa.txt to a.txt
21faebf 重命名a文件为aaa
1d90ad7 将文件a.txt重命名a
c0c3ef7 文件重命名
31ec23f 将文件a.txt重命名为a
2b47557 the first commit
Git服务程序中有一个叫做HEAD的版本指针,当用户申请还原数据时,其实就是将HEAD指针指向到某个特定的提交版本,但是因为Git是分布式版本控制系统,为了避免历史记录冲突,故使用了SHA-1计算出十六进制的哈希字串来区分每个提交版本,另外默认的HEAD版本指针会指向到最近的一次提交版本记录,而上一个提交版本会叫HEAD^,上上一个版本则会叫做HEAD^^,当然一般会用HEAD~5来表示往上数第五个提交版本。
#还原历史到上一次版本
[root@ci-node1 git_data]# git reset --hard e689c97
HEAD is now at e689c97 修改a.txt文件内容
#此时文件内容已还原
[root@ci-node1 git_data]# cat test.txt
#此时又想将数据还原至最新的版本,但是发现再查看历史记录的时候看不到最新的历史记录了,这就需要使用到另外一个命令git reflog(查看所有的历史记录)
[root@ci-node1 git_data]# git log --oneline --decorate
e689c97 (HEAD -> master) 修改a.txt文件内容
1c2c7fc rename aaa.txt to a.txt
21faebf 重命名a文件为aaa
1d90ad7 将文件a.txt重命名a
c0c3ef7 文件重命名
31ec23f 将文件a.txt重命名为a
2b47557 the first commit
#查看所有的历史版本记录,显示最新的前4行
[root@ci-node1 git_data]# git reflog -4
e689c97 HEAD@{0}: reset: moving to e689c97
52e43ab HEAD@{1}: commit: modified test.txt
e689c97 HEAD@{2}: reset: moving to e689c97
20b1b34 HEAD@{3}: commit: wirte test
#还原到最新的一个版本
[root@ci-node1 git_data]# git reset --hard 52e43ab
HEAD is now at 52e43ab modified test.txt
#此是文件内容已还原到最新的版本
[root@ci-node1 git_data]# cat test.txt
test
如是只是想把某个文件内容还原,就不必这么麻烦,直接用git checkout命令就可以的
[root@ci-node1 git_data]# echo "bbb" >> a.txt #追加一句话
[root@ci-node1 git_data]# git add a.txt #提交到暂存区,突然发现写错了
[root@ci-node1 git_data]# git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: a.txt
[root@ci-node1 git_data]# git reset HEAD #取消追踪状态
Unstaged changes after reset:
M a.txt
[root@ci-node1 git_data]# git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: a.txt
no changes added to commit (use "git add" and/or "git commit -a")
[root@ci-node1 git_data]# git checkout -- a.txt #使用checkout进行回退
[root@ci-node1 git_data]# cat a.txt
a
6.4.5、Git对比数据(git diff)
[root@ci-node1 git_data]# echo "bbb" >> a.txt #追加内容
[root@ci-node1 git_data]# git diff a.txt #对比工作目录中a.txt的文件内容
diff --git a/a.txt b/a.txt
index 23165a3..fcb3b3e 100644
--- a/a.txt
+++ b/a.txt
@@ -1,2 +1,3 @@
a
aaaa
+bbb
[root@ci-node1 git_data]# git add a.txt #提交到暂存区
[root@ci-node1 git_data]# git status #查看git状态
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: a.txt
[root@ci-node1 git_data]# git diff --cached a.txt #工作目录与暂存区的内容是一致的,与本地仓库不一致
diff --git a/a.txt b/a.txt
index 23165a3..fcb3b3e 100644
--- a/a.txt
+++ b/a.txt
@@ -1,2 +1,3 @@
a
aaaa
+bbb
[root@ci-node1 git_data]# git status #查看GIT仓库状态,如里内容错误可以使用git reset HEAD进行回滚
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: a.txt
7、Git分支结构管理
7.1、分支结构介绍
在实际的项目开发中,尽量保证master分支稳定,仅用于发布新版本,平时不要随便直接修改里面的数据文件。
那在哪干活呢?干活都在dev分支上。每个人从dev分支创建自己个人分支,开发完合并到dev分支,最后dev分支合并到master分支。
所以团队的合作分支看起来会像下图那样。
7.2、创建分支
#创建分支
[root@ci-node1 git_data]# git branch tesing
#切换分支
[root@ci-node1 git_data]# git checkout tesing
M a.txt
Switched to branch 'tesing'
#查看分支
[root@ci-node1 git_data]# git branch
master
* tesing
#在分支上删除test文件
[root@ci-node1 git_data]# git rm -f test.txt
rm 'test.txt'
[root@ci-node1 git_data]# ls
a.txt b.txt c.txt
#提交暂存区
[root@ci-node1 git_data]# git add .
[root@ci-node1 git_data]# git status
On branch tesing
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: a.txt
modified: c.txt
deleted: test.txt
#提交本地仓库
[root@ci-node1 git_data]# git commit -m "delete test.txt"
[tesing 9707315] delete test.txt
3 files changed, 2 insertions(+), 1 deletion(-)
delete mode 100644 test.txt
#切换到主分支
[root@ci-node1 git_data]# git checkout master
Switched to branch 'master'
#此时发现主分支的内容还是没有变化
[root@ci-node1 git_data]# ls
a.txt b.txt c.txt test.txt
7.3、合并分支
现在,我们想把linux的工作成果合并到master分支上了,则可以使用”git merge”命令来将指定的的分支与当前分支合并
[root@ci-node1 git_data]# git branch #查看是否在主分支上,不在需切换为主分支
* master
tesing
[root@ci-node1 git_data]# git merge tesing #进行合并分支
Updating b22789b..9707315
Fast-forward
a.txt | 1 +
c.txt | 1 +
test.txt | 1 -
3 files changed, 2 insertions(+), 1 deletion(-)
delete mode 100644 test.txt
[root@ci-node1 git_data]# ls #合并后的内容变化
a.txt b.txt c.txt
[root@ci-node1 git_data]# git branch -d tesing #确认合并内容无误后,删除分支
Deleted branch tesing (was 9707315).
[root@ci-node1 git_data]# git branch
* master
7.4、分支冲突
但是Git并不能每次都为我们自动的合并分支,当遇到了内容冲突比较复杂的情况,则必须手工将差异内容处理点
[root@ci-node1 git_data]# git branch tesing #创建分支
[root@ci-node1 git_data]# git branch #查看分支
* master
tesing
[root@ci-node1 git_data]# git checkout tesing #切换到tesing分支上
Switched to branch 'tesing'
[root@ci-node1 git_data]# git branch
master
* tesing
[root@ci-node1 git_data]# echo "aabb" >> a.txt #追加内容
[root@ci-node1 git_data]# git add a.txt #提交到暂存区
[root@ci-node1 git_data]# git commit -m "modfied to a" #提交到本地仓库
[tesing eda39cc] modfied to a
1 file changed, 1 insertion(+)
[root@ci-node1 git_data]# git checkout master #切换到主分区
Switched to branch 'master'
[root@ci-node1 git_data]# git branch
* master
tesing
[root@ci-node1 git_data]# echo "abca" >> a.txt #修改同一个文件
[root@ci-node1 git_data]# git add a.txt #提交到暂存区
[root@ci-node1 git_data]# git commit -m "modfied to a.txt" #提交到本地仓库
[master 6c7e8b3] modfied to a.txt
1 file changed, 1 insertion(+)
#将tesing分支合并到主分支,那么此时,我们在master与linux分支上都分别对中readme文件进行了修改并提交了,那这种情况下Git就没法再为我们自动的快速合并了,它只能告诉我们readme文件的内容有冲突,需要手工处理冲突的内容后才能继续合并
[root@ci-node1 git_data]# git merge tesing
Auto-merging a.txt
CONFLICT (content): Merge conflict in a.txt
Automatic merge failed; fix conflicts and then commit the result.
[root@ci-node1 git_data]# vim a.txt # 修改好文件
[root@ci-node1 git_data]# git add a.txt # 提交到暂存区
[root@ci-node1 git_data]# git commit -m "modfied to a.txt1" # 提交到本地仓库
[master 746b436] modfied to a.txt1
8、Git管理标签
标签也是版本库的一个快照。Git 的标签虽然是版本库的快照,但其实它就是指向某个commit 的指针
如果你达到一个重要的阶段,并希望永远记住那个特别的提交快照,你可以使用 git tag 给它打上标签。
比如说,我们想为我们的 项目发布一个"1.0"版本。 我们可以用 git tag -a v1.0 命令给新一次提交打上(HEAD)"v1.0"的标签。-a 选项意为"创建一个带注解的标签"。 不用 -a 选项也可以执行的,但它不会记录这标签是啥时候打的,谁打的,也不会让你添加个标签的注解。
[root@ci-node1 git_data]# git tag -a v1.0 #给当前的版本打上标签
[root@ci-node1 git_data]# git tag # 查看所有标答
v1.0
[root@ci-node1 git_data]# git show v1.0 # 查看v1.0版本的内容
commit 746b4369fa266df7280a2bac31478b033ae24eb9
Merge: 6c7e8b3 eda39cc
Author: liu <liu@qq.com>
Date: Fri Mar 29 14:03:10 2019 +0800
modfied to a.txt1
diff --cc a.txt
index d1a1ff7,d06535f..ba9b346
--- a/a.txt
+++ b/a.txt
@@@ -1,4 -1,4 +1,5 @@@
a
aaaa
bbb
+abca
+ aabb
[root@ci-node1 git_data]# git tag v1.2 -m "version 1.2 release is test" # #创建带有说明的标签,-a指定标签名字,-m指定说明文字
[root@ci-node1 git_data]# git tag -d v1.0 # 我们为同一个提交版本设置了两次标签,删除之前的v1.0
Deleted tag 'v1.0' (was 746b436)
[root@ci-node1 git_data]# git tag
v1.2
[root@ci-node1 git_data]# ls
a.txt b.txt c.txt
[root@ci-node1 git_data]# touch test.txt #创建一个文件
[root@ci-node1 git_data]# git add test.txt # 提交暂存区
[root@ci-node1 git_data]# git commit -m "add test" #提交到本地仓库
[master 30ec358] add test
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test.txt
[root@ci-node1 git_data]# git log --oneline --decorate # 查看提交历史记录
30ec358 (HEAD -> master) add test
746b436 (tag: v1.2) modfied to a.txt1
6c7e8b3 modfied to a.txt
eda39cc (tesing) modfied to a
9707315 delete test.txt
[root@ci-node1 git_data]# git reset --hard v1.2 # 使用标签进行还原操作
HEAD is now at 746b436 modfied to a.txt1
[root@ci-node1 git_data]# ls
a.txt b.txt c.txt