Files
Security-base01/02.git基础.md
2025-08-30 10:00:03 +08:00

585 lines
19 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# git简介
## git的诞生
1991年 Linus开创了开源的Linux
2002年以前 Linus手动合并代码
2002年 BitKeeper免费授权
2005年 BitKeeper被尝试破解收回授权
2005年 Linus花了两周时间用C写出了git并且一个月之内将Linux搬迁到git上
2008年 GitHub上线
## 集中式与分布式
集中式
CVS、SVN
分布式
Git
# Git安装
git最新版本没有安装包的话去官方地址下载https://github.com/git-for-windows/git/releases/download/v2.23.0.windows.1/Git-2.23.0-64-bit.exe
一路next直到安装完毕保持默认的选项
安装完毕后打开windows的`cmd` 命令界面,输入如下命令,来设置自己的用户名和邮箱。
```bash
git config --global user.name "Aaron"
git config --global user.email "Aaron@eagleslab.com"
```
# 创建版本库
版本库又名仓库,英文名**repository** 你可以简单的解成一个目录这个目录里面的所有文件都可以被Git管理起来每个文件的修改、删除Git都能跟踪以便任何时刻都可以追踪历史或者在将来某个时刻可以“还原”。
**第一步** 找个空的地方创建一个文件夹
**第二步** 在文件夹中打开`cmd`界面,然后输入`git init` 命令把这个目录变成Git可以管理的仓库
![image-20191026205132429](02.git基础/image-20191026205132429.png)
我们也可以发现,在这个文件夹中会创建一个`.git`的目录, 这个目录是Git来跟踪管理版本库的
## 添加文件到版本库
这边要注意git只能追踪文本文件的改动而二进制文件只能记录大小的变化。
**第一步**
- 在我们的git文件夹中创建一个记事本文件不过注意千万别用windows自带的记事本编辑内容
- 在记事本文件中写一些内容,比如`学前沿IT到英格科技`
- 使用命令`git add`告诉git把文件添加到暂存区中
```git
git add readme.txt
```
执行上面的命令,没有任何显示
**第二步**
用命令`git commit`告诉Git把文件提交到仓库
```git
C:\Users\Aaron\Desktop\gitlearn>git commit -m "write a readme file"
[master (root-commit) 4121352] write a readme file
1 file changed, 1 insertions(+)
create mode 100644 readme.txt
```
`git commit`后面的`-m`是输入本次提交的说明的,可以输入任何内容,最好是自己能看懂的,这样就可以从理事会记录里面方便的找到改动记录。
执行成功后`1 file changed` 一个文件被改动了,也就是我们添加的`readme.txt`
`1 insertions(+)`表示插入了一行内容,我们写的那个`学前沿IT到英格科技`
**注意**
因为在`commit`前需要`add`一下,所以可以一次提交多个文件
```bash
C:\Users\Aaron\Desktop\gitlearn>git add file1.txt
C:\Users\Aaron\Desktop\gitlearn>git add file2.txt
C:\Users\Aaron\Desktop\gitlearn>git commit -m "two files"
[master dc43809] two files
2 files changed, 2 insertions(+)
create mode 100644 file1.txt
create mode 100644 file2.txt
```
# 回滚操作
我们修改上面的文件`readme.txt`
然后使用`git status`查看
```bash
C:\Users\Aaron\Desktop\gitlearn>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: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
```
`git status`命令可以让我们时刻掌握仓库当前的状态,上面的命令输出告诉我们,`readme.txt`被修改过了,但还没有准备提交的修改。
如果想看看具体修改了什么内容,我们可以使用`git diff`来查看
![image-20191026211316876](02.git基础/image-20191026211316876.png)
可以看到在第一行后面加了一个换行符,然后加了一行在下面
下面我们将其添加,然后查看`status`
![image-20191026211507764](02.git基础/image-20191026211507764.png)
`git status`告诉我们,将要被提交的修改包括`readme.txt`,下一步,就可以放心地提交了
![image-20191026211724339](02.git基础/image-20191026211724339.png)
提交后,我们再用`git status`命令看看仓库的当前状态:
![image-20191026211757079](02.git基础/image-20191026211757079.png)
Git告诉我们当前没有需要提交的修改而且工作目录是干净working tree clean
## 版本回退
我们创建一个文件叫`game` ,在这个文件中写入以下内容
```
屠龙勇士村来了一个新勇士叫"林克"
```
然后提交,提交的说明就是"新的开始"
![image-20191026212115336](02.git基础/image-20191026212115336.png)
在文件中追加内容
```
勇士赤手空拳来到了野外
```
然后提交,提交的说明就是"走出新手村"
![image-20191026212310506](02.git基础/image-20191026212310506.png)
在文件中追加内容
```
勇士林克被Lv1怪物史莱姆一屁股坐死
```
然后提交,提交的说明就是"阵亡"
![image-20191026212439959](02.git基础/image-20191026212439959.png)
在文件中追加内容
```
勇士林克被公主"塞尔达"所救,丢失全部金币!
```
然后提交,提交的说明就是"复活"
![image-20191026212614476](02.git基础/image-20191026212614476.png)
下面我们来看下这个悲催的勇士的经历,可以使用`git log`查看历史提交
![image-20191026212755780](02.git基础/image-20191026212755780.png)
`git log`命令显示从最近到最远的提交日志我们可以看到3次提交
如果嫌输出信息太多,看得眼花缭乱的,可以试试加上`--pretty=oneline`参数
![image-20191026212850868](02.git基础/image-20191026212850868.png)
其实勇士的悲剧完全可以逆转,我们可以**读档**到`新的开始`,让勇士在出门前带把武器
![image-20191026213156010](02.git基础/image-20191026213156010.png)
Git的版本回退速度非常快因为Git在内部有个指向当前版本的`HEAD`指针当你回退版本的时候Git仅仅是把HEAD从指向`新的开始`
```ascii
┌────┐
│HEAD│
└────┘
└──> ○ 复活
○ 阵亡
○ 走出新手村
○ 新的开始
```
改为指向`add distributed`
```ascii
┌────┐
│HEAD│
└────┘
│ ○ 复活
│ │
│ ○ 阵亡
│ │
│ ○ 走出新手村
│ │
└──>○ 新的开始
```
在Git中`HEAD`表示当前版本,上一个版本就是`HEAD^`,上上一个版本就是`HEAD^^`当然往上100个版本写100个`^`比较容易数不过来,所以写成`HEAD~100`
Git提供了一个命令`git reflog`用来记录你的每一次命令:
## 工作区和暂存区
### 工作区
就是你在电脑里能看到的目录,比如上面的`gitlearn`文件夹
![image-20191026213858444](02.git基础/image-20191026213858444.png)
### 版本库
工作区有一个隐藏目录`.git`这个不算工作区而是Git的版本库。
Git的版本库里存了很多东西其中最重要的就是称为stage或者叫index的暂存区还有Git为我们自动创建的第一个分支`master`,以及指向`master`的一个指针叫`HEAD`
![image-20191026214144680](02.git基础/image-20191026214144680.png)
前面讲了我们把文件往Git版本库里添加的时候是分两步执行的
第一步是用`git add`把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用`git commit`提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建Git版本库时Git自动为我们创建了唯一一个`master`分支,所以,现在,`git commit`就是往`master`分支上提交更改。
你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
## 管理修改
git不是管理文件而是管理修改的操作。
我们修改readme.txt然后add提交到暂存区
![image-20191026214759593](02.git基础/image-20191026214759593.png)
然后再次修改readme.txt这次我们直接commit
![image-20191026214923112](02.git基础/image-20191026214923112.png)
然后查看状态
![image-20191026214953282](02.git基础/image-20191026214953282.png)
我们会发现第二次修改的并没有被提交
查看一下工作区的文件和仓库的文件的区别
![image-20191026215100477](02.git基础/image-20191026215100477.png)
## 撤销修改
- 当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令`git checkout -- file`
- 当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令`git reset HEAD `,就回到了上一种情况,第二步按上一种情况操作操作。
## 删除文件
我们将文件从工作区删除
![image-20191026220634410](02.git基础/image-20191026220634410.png)
git会直接察觉到我们的删除操作如果这个时候提交那么就会从版本库中删除该文件
![image-20191026220737779](02.git基础/image-20191026220737779.png)
但是如果误删除了,可以还原到版本库中的最新版本
![image-20191026220846139](02.git基础/image-20191026220846139.png)
如果要删除暂存区中的文件,可以使用`git rm`
# 远程仓库
注册github
打开命令行创建key
![image-20191026222146813](02.git基础/image-20191026222146813.png)
打开github的个人用户设置
![image-20191026222232810](02.git基础/image-20191026222232810.png)
在里面找到`SSH and GPG keys`
![image-20191026222304248](02.git基础/image-20191026222304248.png)
新建一个ssh keys
![image-20191026222341875](02.git基础/image-20191026222341875.png)
然后按照下图提示填写
![image-20191026222527219](02.git基础/image-20191026222527219.png)
然后你就成功添加了ssh的key下次登录github的时候就会直接被识别出你的身份啦
![image-20191026222731981](02.git基础/image-20191026222731981.png)
## 添加远程仓库
首先回到登录之后的页面
![image-20191026222810944](02.git基础/image-20191026222810944.png)
创建你的仓库
![image-20191026222939132](02.git基础/image-20191026222939132.png)
根据这边的提示可以将我们本地的仓库和远程的仓库关联起来哦
![image-20191026223058803](02.git基础/image-20191026223058803.png)
推送成功的画面
![image-20191026223328983](02.git基础/image-20191026223328983.png)
观察到远程仓库和我们本地仓库已经关联一致
![image-20191026223401158](02.git基础/image-20191026223401158.png)
要关联一个远程库,使用命令`git remote add origin git@server-name:path/repo-name.git`
关联后,使用命令`git push -u origin master`第一次推送master分支的所有内容
此后,每次本地提交后,只要有必要,就可以使用命令`git push origin master`推送最新修改;
## 从远程仓库克隆
```
git clone <地址>
```
# 分支管理
## 创建与合并分支
一开始的时候,`master`分支是一条线Git用`master`指向最新的提交,再用`HEAD`指向`master`,就能确定当前分支,以及当前分支的提交点:
![image-20191027123341011](02.git基础/image-20191027123341011.png)
每次提交,`master`分支都会向前移动一步,这样,随着你不断提交,`master`分支的线也越来越长。
当我们创建新的分支,例如`dev`Git新建了一个指针叫`dev`,指向`master`相同的提交,再把`HEAD`指向`dev`,就表示当前分支在`dev`上:
![image-20191027123400412](02.git基础/image-20191027123400412.png)
你看Git创建一个分支很快因为除了增加一个`dev`指针,改改`HEAD`的指向,工作区的文件都没有任何变化!
不过,从现在开始,对工作区的修改和提交就是针对`dev`分支了,比如新提交一次后,`dev`指针往前移动一步,而`master`指针不变:
![image-20191027123426946](02.git基础/image-20191027123426946.png)
假如我们在`dev`上的工作完成了,就可以把`dev`合并到`master`上。Git怎么合并呢最简单的方法就是直接把`master`指向`dev`的当前提交,就完成了合并:
![image-20191027123523590](02.git基础/image-20191027123523590.png)
合并完分支后,甚至可以删除`dev`分支。删除`dev`分支就是把`dev`指针给删掉,删掉后,我们就剩下了一条`master`分支:
![image-20191027123606591](02.git基础/image-20191027123606591.png)
首先,我们创建`dev`分支,然后切换到`dev`分支:
```bash
ubuntu@DESKTOP-HQ0R9B5:/mnt/c/Users/Aaron/Desktop/learngit$ git checkout -b dev
Switched to a new branch 'dev'
```
`git checkout`命令加上`-b`参数表示创建并切换,相当于以下两条命令:
```bash
$ git branch dev
$ git checkout dev
Switched to branch 'dev'
```
然后,用`git branch`命令查看当前分支:
```bash
ubuntu@DESKTOP-HQ0R9B5:/mnt/c/Users/Aaron/Desktop/learngit$ git branch
* dev
master
```
`git branch`命令会列出所有分支,当前分支前面会标一个`*`号。
然后,我们就可以在`dev`分支上正常提交,比如对`readme.txt`做个修改,加上一行。
然后提交
![image-20191027124746947](02.git基础/image-20191027124746947.png)
切换回`master`分支后,再查看一个`readme.txt`文件,刚才添加的内容不见了!因为那个提交是在`dev`分支上,而`master`分支此刻的提交点并没有变
![image-20191027124809015](02.git基础/image-20191027124809015.png)
现在,我们把`dev`分支的工作成果合并到`master`分支上:
![image-20191027124912044](02.git基础/image-20191027124912044.png)
`git merge`命令用于合并指定分支到当前分支。合并后,再查看`readme.txt`的内容,就可以看到,和`dev`分支的最新提交是完全一样的。
注意到上面的`Fast-forward`信息Git告诉我们这次合并是“快进模式”也就是直接把`master`指向`dev`的当前提交,所以合并速度非常快。
合并完成后,就可以放心地删除`dev`分支了:
![image-20191027125002911](02.git基础/image-20191027125002911.png)
删除后,查看`branch`,就只剩下`master`分支了:
![image-20191027125038982](02.git基础/image-20191027125038982.png)
### switch
最新版本的Git提供了新的`git switch`命令来切换分支
创建并切换到新的`dev`分支,可以使用:
```
$ git switch -c dev
```
直接切换到已有的`master`分支,可以使用:
```
$ git switch master
```
使用新的`git switch`命令,比`git checkout`要更容易理解。
### 命令总结
Git鼓励大量使用分支
查看分支:`git branch`
创建分支:`git branch `
切换分支:`git checkout `或者`git switch `
创建+切换分支:`git checkout -b `或者`git switch -c `
合并某分支到当前分支:`git merge `
删除分支:`git branch -d `
## 解决冲突
准备新的`feature1`分支,继续我们的新分支开发:
![image-20191027130450579](02.git基础/image-20191027130450579.png)
修改`readme.txt`最后一行
`feature1`分支上提交
![image-20191027130621731](02.git基础/image-20191027130621731.png)
切换到`master`分支,修改`readme.txt`最后一行为别的内容,然后提交
![image-20191027130755666](02.git基础/image-20191027130755666.png)
现在,`master`分支和`feature1`分支各自都分别有新的提交,变成了这样:
![image-20191027130814425](02.git基础/image-20191027130814425.png)
Git无法执行“快速合并”只能试图把各自的修改合并起来但这种合并就可能会有冲突
![image-20191027130908476](02.git基础/image-20191027130908476.png)
Git告诉我们`readme.txt`文件存在冲突,必须手动解决冲突后再提交。`git status`也可以告诉我们冲突的文件:
![image-20191027130931402](02.git基础/image-20191027130931402.png)
我们可以直接查看readme.txt的内容
![image-20191027131016245](02.git基础/image-20191027131016245.png)
Git用`<<<<<<<``=======``>>>>>>>`标记出不同分支的内容,我们修改后保存,然后提交:
![image-20191027131149032](02.git基础/image-20191027131149032.png)
现在,`master`分支和`feature1`分支变成了下图所示:
![image-20191027131204136](02.git基础/image-20191027131204136.png)
用带参数的`git log`也可以看到分支的合并情况:
![image-20191027131309319](02.git基础/image-20191027131309319.png)
## 分支策略
首先,`master`分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活
所以,团队合作的分支看起来就像这样
![image-20191027131459753](02.git基础/image-20191027131459753.png)
# 标签管理
## 创建标签
首先,切换到需要打标签的分支上:
![image-20191027131658489](02.git基础/image-20191027131658489.png)
然后,敲命令`git tag `就可以打一个新标签:
![image-20191027131722212](02.git基础/image-20191027131722212.png)
可以用命令`git tag`查看所有标签:
![image-20191027131746160](02.git基础/image-20191027131746160.png)
可以给历史的commit id加上标签
![image-20191027131848176](02.git基础/image-20191027131848176.png)
注意,标签不是按时间顺序列出,而是按字母排序的。可以用`git show `查看标签信息:
![image-20191027131920369](02.git基础/image-20191027131920369.png)
还可以创建带有说明的标签,用`-a`指定标签名,`-m`指定说明文字:
![image-20191027132037874](02.git基础/image-20191027132037874.png)
用命令`git show `可以看到说明文字:
![image-20191027132118336](02.git基础/image-20191027132118336.png)
## 操作标签
如果标签打错了,也可以删除:
![image-20191027132213310](02.git基础/image-20191027132213310.png)
因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。
如果要推送某个标签到远程,使用命令`git push origin `
![image-20191027132413256](02.git基础/image-20191027132413256.png)
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
![image-20191027132447546](02.git基础/image-20191027132447546.png)
然后从远程删除。删除命令也是push但是格式如下
![image-20191027132513867](02.git基础/image-20191027132513867.png)
- 命令`git push origin `可以推送一个本地标签;
- 命令`git push origin --tags`可以推送全部未推送过的本地标签;
- 命令`git tag -d `可以删除一个本地标签;
- 命令`git push origin :refs/tags/`可以删除一个远程标签。