目录
一、简介
1. Git 是什么?
2. 集中式和分布式
二、Git 环境搭建
1. Linux 下安装
2. Windows 下安装
三、创建版本库
四、把文件添加到版本库
1. 添加并提交
2. 仓库状态
3. 版本回退
(1)查看提交日志
(2)版本回退/前进
(3)工作区和暂存区
4. 撤销修改
5. 删除文件
五、远程仓库
六、 分支管理
1. 创建与合并分支
2. 解决冲突
七、标签管理
1. 创建标签
2. 操作标签
小结
Git 是目前世界上最先进的分布式版本控制系统。
集中式版本控制系统,版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。
分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件 A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
和集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。
(1)下载地址:Index of /pub/software/scm/git/ (kernel.org)
下载当前最新的版本:git-2.9.5.tar.gz
(2)上传至服务器:
(3)提前安装依赖
yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel gcc-c++ perl-ExtUtils-MakeMaker
(4)解压并安装
tar -zxvf git-2.9.5.tar.gz
cd git-2.9.5
make configure
./configure --prefix=/usr/local/git
make profix=/usr/local/git
make install
(5)将 Git 加入环境变量
vim /etc/profile
#在文件底部加入
export GIT_HOME=/usr/local/git
export PATH=$PATH:$GIT_HOME/bin
source /etc/profile
(6)查看安装结果
[root@zy-host git-2.9.5]# git --version
下载地址:Git - Downloading Package (git-scm.com)
下载完成后按默认选项安装即可,安装好后,右键可以看到git命令:
版本库也就是仓库(repository),可以理解成他是一个目录,目录中所有的文件都可以被git管理起来,每个文件的修改、删除,git都可以跟踪。
(1)创建一个文件夹,名字自定义:
(2)通过 git init 命令把这个目录编程 git 课管理的仓库
$ git init
Initialized empty Git repository in D:/Java_Dev/IDEA_Projects/code-repository/git-learn/.git/
这样仓库就建好了,在目录下会多出一个 .git 的文件(默认是隐藏文件)
注意:所有的版本控制系统,只能跟踪文本文件的改动。对于图片或视频这些二进制文件,版本控制系统只能知道大小发生变化,但是里面改了什么,版本控制系统不知道。
(1)在仓库中新建一个 readme.txt文件,内容如下:
(2)打开git命令行窗口
git add 添加命令,如果要添加全部,可以使用 git add .
git commit 命令, -m 后面输入的是本次提交的说明
$ git add readme.txt #将文件添加到仓库
$ git commit -m "提交了一个新文件!" #将文件提交到仓库
[master (root-commit) e038a32] 提交了一个新文件!
1 file changed, 2 insertions(+)
create mode 100644 readme.txt
刚才已经把readme.txt文件提交到了版本库中,现在对文件进行修改,添加一行:
运行 git status 命令看看结果:
可以看到提示 readme 已经被修改了,但是还没有提交修改。
使用git diff 查看文件变化,git diff 顾名思义就是查看 difference
再次提交到仓库中:
zhangyin@LAPTOP-NQ7TQU22 MINGW64 /d/Java_Dev/IDEA_Projects/code-repository/git-learn (master)
$ git add readme.txt #添加到仓库
zhangyin@LAPTOP-NQ7TQU22 MINGW64 /d/Java_Dev/IDEA_Projects/code-repository/git-learn (master)
$ git status #查看仓库当前状态,可以看到readme.txt将被提交
On branch master
Changes to be committed:
(use "git restore --staged ..." to unstage)
modified: readme.txt
zhangyin@LAPTOP-NQ7TQU22 MINGW64 /d/Java_Dev/IDEA_Projects/code-repository/git-learn (master)
$ git commit -m "第二次提交!" #提交到仓库
[master 0246a95] 第二次提交!
1 file changed, 2 insertions(+), 1 deletion(-)
zhangyin@LAPTOP-NQ7TQU22 MINGW64 /d/Java_Dev/IDEA_Projects/code-repository/git-learn (master)
$ git status #再次查看仓库的状态
On branch master
nothing to commit, working tree clean
#当前没有需要提交的修改,而且,工作目录是干净的
使用 git log 查看提交日志:
$ git log
commit 035cf6ad5e341bba4c0d409775bc5a3bdbfa760d (HEAD -> master)
Author: zhangyin_0116 <[email protected]>
Date: Thu Jan 19 14:01:27 2023 +0800
第三次修改提交!
commit 0246a95af8837f1ba379f87f60a013d9b4a61fa2
Author: zhangyin_0116 <[email protected]>
Date: Thu Jan 19 13:47:20 2023 +0800
第二次提交!
commit e038a323fc72804c34cdb7e770dda22b84df80b0
Author: zhangyin_0116 <[email protected]>
Date: Thu Jan 19 09:56:13 2023 +0800
提交了一个新文件!
查看精简日志:前面是 commit id(版本号)
$ git log --pretty=oneline
035cf6ad5e341bba4c0d409775bc5a3bdbfa760d (HEAD -> master) 第三次修改提交!
0246a95af8837f1ba379f87f60a013d9b4a61fa2 第二次提交!
e038a323fc72804c34cdb7e770dda22b84df80b0 提交了一个新文件!
首先,Git 必须知道当前版本是哪个版本,在 Git 中,用 HEAD 表示当前版本,也就是最新的,上一个版本就是 HEAD^ ,上上一个版本就是 HEAD^^ ,当然 往上 100 个版本写 100 个 ^ 比较容易数不过来,所以写成 HEAD~100。
现在回退到上一个版本,先看一下当前版本文件内容:
$ git reset --hard HEAD^
HEAD is now at 0246a95 第二次提交!
现在版本已经回到上一个了,查看一下文件的内容,可以看到最后一行不在了:
使用 git log 查看:
$ git log
commit 0246a95af8837f1ba379f87f60a013d9b4a61fa2 (HEAD -> master)
Author: zhangyin_0116 <[email protected]>
Date: Thu Jan 19 13:47:20 2023 +0800
第二次提交!
commit e038a323fc72804c34cdb7e770dda22b84df80b0
Author: zhangyin_0116 <[email protected]>
Date: Thu Jan 19 09:56:13 2023 +0800
提交了一个新文件!
再次回到第三次提交的状态,需要知道版本号:
$ git reset --hard 035cf6ad5e341bba4c0d409775bc5a3bdbfa760d #版本号可以不用写全
HEAD is now at 035cf6a 第三次修改提交!
现在再查看文件,可以看到最后一行又加上了:
如果忘记版本号,可以使用 git reflog 来查看命令历史,以及每次提交后的 commit id(版本号):
$ git reflog
035cf6a (HEAD -> master) HEAD@{0}: reset: moving to 035cf6ad5e341bba4c0d409775bc5a3bdbfa760d
0246a95 HEAD@{1}: reset: moving to HEAD^
035cf6a (HEAD -> master) HEAD@{2}: commit: 第三次修改提交!
0246a95 HEAD@{3}: commit: 第二次提交!
e038a32 HEAD@{4}: commit (initial): 提交了一个新文件!
工作区:就是在电脑里能看到的目录。
版本库:工作区有一个隐藏目录 .git ,这个不算工作区,而是 Git 的版本库。 Git 的版本库里存了很多东西,其中最重要的就是称为 stage(或者叫 index)的暂存区,还有 Git 为我们自动创 建的第一个分支 master,以及指向 master 的一个指针叫 HEAD。
前面讲了我们把文件往 Git 版本库里添加的时候,是分两步执行的:
第一步是用 git add 把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用 git commit 提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建 Git 版本库时,Git 自动为我们创建了唯一一个 master 分支,所以,现在, git commit 就是往 m aster 分支上提交更改。
命令 git checkout -- readme.txt 意思就是,把 readme.txt 文件在工作区的修改全部撤销,这里有两种情况:
第一种情况演示:
(1)在文件中添加一行:
(2)在没有 git add 之前,使用git check -- file,文件就会把修改撤销:
#查看状态,可以看到文件被修改的提示
$ 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: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
#撤销修改
$ git checkout -- readme.txt
#撤销修改之后,再次查看状态,可以看到文件恢复到了修改前状态
$ git status
On branch master
nothing to commit, working tree clean
文件恢复到了修改前状态:
第二种情况演示:
(1)文件中添加一行
(2)使用git add 将修改添加到暂存区
$ git add readme.txt
(3)再次修改,再添加一行
(4)执行 git checkout -- readme.txt
$ git status
On branch master
Changes to be committed:
(use "git restore --staged ..." to unstage)
modified: readme.txt
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git restore ..." to discard changes in working directory)
modified: readme.txt
$ git checkout -- readme.txt
$ git status
On branch master
Changes to be committed:
(use "git restore --staged ..." to unstage)
modified: readme.txt
可以看到,文件恢复到了添加到暂存区之后的状态,也就是说,把添加到暂存区之后再进行的修改都撤销了:
考虑:如果我们修改了之后,还把它用 git add 添加到了暂存区,现在又后悔了?怎么把暂存区的修改也撤销呢?
演示:
(1)在文件中添加一行
(2)添加到暂存区
$ git add readme.txt
(3)查看状态
$ git status
On branch master
Changes to be committed:
(use "git restore --staged ..." to unstage)
modified: readme.txt
(4)撤销修改
git reset HEAD file 可以把暂存区的修改撤销掉(unstage),重新放回工作区(相当于从暂存区移出去)
$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt
这里也可以使用:$ git restore --staged readme.txt 和 git reset HEAD readme.txt 作用一样。
再执行 git checkout -- readme.txt,将文件恢复到修改前状态:
$ git checkout -- readme.txt
新建一个test.txt 文件,添加并提交到仓库
$ git add test.txt
$ git commit -m "add test.txt"
删除 test.txt 文件,使用 git status 查看状态:
现在有两个选择,一是确定要从版本库中删除该文件,那就用命令 git rm 删掉,并且 git commit
$ git rm test.txt
$ git commit -m "remove test.txt"
另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:
$ git checkout -- test.txt
git checkout 其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
添加远程仓库可以看我这篇博客:使用码云Gitee创建代码仓库并提交代码
要关联一个远程库,使用命令 git remote add origin git@server-name:path/repo-name.git ;
关联后,使用命令 git push -u origin master 第一次推送 master 分支的所有内容;
此后,每次本地提交后,只要有必要,就可以使用命令 git push origin master 推送最新修改;
(1)在码云上新建一个 git-learn 仓库
(2)把本地代码推送到远程仓库
(3)查看远程仓库
可以看到文件都已经推送到远程仓库。
在版本回退里,每次提交,Git 都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在 Git 里,这个分支叫主分支,即 master 分支。HEAD 严格来说不是指向提交,而是指向 master,master 才是指向提交的,所以,HEAD指向的就是当前分支。
一开始的时候,master 分支是一条线,Git 用 master 指向最新的提交,再用 HEAD 指向 master,就能确定当前分支,以及当前分支的提交点:
当我们创建新的分支,例如 dev 时,Git 新建了一个指针叫 dev,指向 master 相同的提交,再把 HEAD 指向 dev,就表示当前分支在 dev 上:
不过,从现在开始,对工作区的修改和提交就是针对 dev 分支了,比如新提交一次后,dev 指针往前移动一 步,而 master 指针不变:
假如我们在 dev 上的工作完成了,就可以把 dev 合并到 master 上。Git 怎么合并呢?最简单的方法,就是直接 把 master 指向 dev 的当前提交,就完成了合并:
合并完分支后,甚至可以删除 dev 分支。删除 dev 分支就是把 dev 指针给删掉,删掉后,我们就剩下了一条 master 分支:
实战:
(1)首先,我们创建 dev 分支,然后切换到 dev 分支:
$ git checkout -b dev
git checkout 命令加上 -b 参数表示创建并切换,相当于以下两条命令:
$ git branch dev
$ git checkout dev
(2)用 git branch 命令查看当前分支:
(3)在dev分支上做修改,添加一行:
(4)切换回 master 分支
可以看到刚才添加的那句话在主分支上看不到了:
git checkout master
(5)们把 dev 分支的工作成果合并到 master 分支上
git merge 命令用于合并指定分支到当前分支
$ git merge dev
(6)合并完成后,就可以放心地删除 dev 分支了
小结:
查看分支:git branch
创建分支:git branch
切换分支:git checkout
创建+切换分支:git checkout -b
合并某分支到当前分支:git merge
删除分支:git branch -d
准备新的分支branch01,在新的分支上开发:
$ git checkout -b branch01
Switched to a new branch 'branch01'
修改 readme.txt 最后一行,
在 branch01 分支上提交:
$ git add readme.txt
$ git commit -m "branch01分支上提交!"
切换到主分支:
$ git checkout master
再修改 readme.txt 文件,添加这句:
在主分支上提交:
$ git add readme.txt
$ git commit -m "主分支上提交!"
现在,master 分支和 branch01 分支各自都分别有新的提交,变成了这样:
这种情况下,git无法执行快速合并,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,我们试试看:可以看到产生了冲突
查看状态:
查看 readme.txt 文件的内容:
再次提交
$ git add readme.txt
$ git commit -m "解决冲突!"
现在,master 分支和 branch01 分支变成下图所示:
用带参数的 git log 也可以看到分支的合并情况:
最后删除 branch01分支:
发布一个版本时,我们通常先在版本库中打一个标签,这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。
创建标签过程:
(1)切换到打标签的分支上
$ git checkout master
(2)打标签 默认标签是打在最新提交的 commit 上的
$ git tag v1.0
(3)查看所有标签
$ git tag
v1.0
有时候,如果忘了打标签,比如,现在已经是周五了,但应该在周一 打的标签没有打,怎么办?
方法是找到历史提交的 commit id ,然后打上就可以了:
$ git log --pretty=oneline --abbrev-commit
4cb0cf3 (HEAD -> master, tag: v1.0) 解决冲突!
59ce512 主分支上提交!
77e523b feature1提交!
5ef1329 解决冲突!
966ec25 主分支上提交!
088aa6f branch01分支上提交!
a89eb37 branch test
ab84ebe (origin/master) 提交test.txt
a4f2ab7 remove test.txt
a7a41ed add test.txt
b86291b git checkout 测试后提交
035cf6a 第三次修改提交!
0246a95 第二次提交!
e038a32 提交了一个新文件!
在第一次提交的时候补打标签:
$ git tag v0.1 e038a32
如果标签打错了,也可以删除:
$ git tag -d v0.1
Deleted tag 'v0.1' (was e038a32)
如果要推送某个标签到远程,使用命令 git push origin :
$ git push origin v1.0
或者,一次性推送全部尚未推送到远程的本地标签:
$ git push origin --tags
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
$ git tag -d v0.9
然后,从远程删除。删除命令也是 push,但是格式如下:
$ git push origin :refs/tags/v0.9
- 命令 git push origin 可以推送一个本地标签;
- 命令 git push origin --tags 可以推送全部未推送过的本地标签;
- 命令 git tag -d 可以删除一个本地标签;
- 命令 git push origin :refs/tags/ 可以删除一个远程标签。