08-30-周六_10-00-03
This commit is contained in:
584
02.git基础.md
Normal file
584
02.git基础.md
Normal file
@@ -0,0 +1,584 @@
|
||||
# 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可以管理的仓库
|
||||
|
||||

|
||||
|
||||
我们也可以发现,在这个文件夹中会创建一个`.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`来查看
|
||||
|
||||

|
||||
|
||||
可以看到在第一行后面加了一个换行符,然后加了一行在下面
|
||||
|
||||
下面我们将其添加,然后查看`status`
|
||||
|
||||

|
||||
|
||||
`git status`告诉我们,将要被提交的修改包括`readme.txt`,下一步,就可以放心地提交了
|
||||
|
||||

|
||||
|
||||
提交后,我们再用`git status`命令看看仓库的当前状态:
|
||||
|
||||

|
||||
|
||||
Git告诉我们当前没有需要提交的修改,而且,工作目录是干净(working tree clean)的
|
||||
|
||||
## 版本回退
|
||||
|
||||
我们创建一个文件叫`game` ,在这个文件中写入以下内容
|
||||
|
||||
```
|
||||
屠龙勇士村来了一个新勇士叫"林克"
|
||||
```
|
||||
|
||||
然后提交,提交的说明就是"新的开始"
|
||||
|
||||

|
||||
|
||||
在文件中追加内容
|
||||
|
||||
```
|
||||
勇士赤手空拳来到了野外
|
||||
```
|
||||
|
||||
然后提交,提交的说明就是"走出新手村"
|
||||
|
||||

|
||||
|
||||
在文件中追加内容
|
||||
|
||||
```
|
||||
勇士林克被Lv1怪物史莱姆一屁股坐死
|
||||
```
|
||||
|
||||
然后提交,提交的说明就是"阵亡"
|
||||
|
||||

|
||||
|
||||
在文件中追加内容
|
||||
|
||||
```
|
||||
勇士林克被公主"塞尔达"所救,丢失全部金币!
|
||||
```
|
||||
|
||||
然后提交,提交的说明就是"复活"
|
||||
|
||||

|
||||
|
||||
下面我们来看下这个悲催的勇士的经历,可以使用`git log`查看历史提交
|
||||
|
||||

|
||||
|
||||
`git log`命令显示从最近到最远的提交日志,我们可以看到3次提交
|
||||
|
||||
如果嫌输出信息太多,看得眼花缭乱的,可以试试加上`--pretty=oneline`参数
|
||||
|
||||

|
||||
|
||||
其实勇士的悲剧完全可以逆转,我们可以**读档**到`新的开始`,让勇士在出门前带把武器
|
||||
|
||||

|
||||
|
||||
Git的版本回退速度非常快,因为Git在内部有个指向当前版本的`HEAD`指针,当你回退版本的时候,Git仅仅是把HEAD从指向`新的开始`:
|
||||
|
||||
```ascii
|
||||
┌────┐
|
||||
│HEAD│
|
||||
└────┘
|
||||
│
|
||||
└──> ○ 复活
|
||||
│
|
||||
○ 阵亡
|
||||
│
|
||||
○ 走出新手村
|
||||
│
|
||||
○ 新的开始
|
||||
```
|
||||
|
||||
改为指向`add distributed`:
|
||||
|
||||
```ascii
|
||||
┌────┐
|
||||
│HEAD│
|
||||
└────┘
|
||||
│
|
||||
│ ○ 复活
|
||||
│ │
|
||||
│ ○ 阵亡
|
||||
│ │
|
||||
│ ○ 走出新手村
|
||||
│ │
|
||||
└──>○ 新的开始
|
||||
```
|
||||
|
||||
在Git中,用`HEAD`表示当前版本,上一个版本就是`HEAD^`,上上一个版本就是`HEAD^^`,当然往上100个版本写100个`^`比较容易数不过来,所以写成`HEAD~100`。
|
||||
|
||||
Git提供了一个命令`git reflog`用来记录你的每一次命令:
|
||||
|
||||
## 工作区和暂存区
|
||||
|
||||
### 工作区
|
||||
|
||||
就是你在电脑里能看到的目录,比如上面的`gitlearn`文件夹
|
||||
|
||||

|
||||
|
||||
### 版本库
|
||||
|
||||
工作区有一个隐藏目录`.git`,这个不算工作区,而是Git的版本库。
|
||||
|
||||
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支`master`,以及指向`master`的一个指针叫`HEAD`。
|
||||
|
||||

|
||||
|
||||
前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:
|
||||
|
||||
第一步是用`git add`把文件添加进去,实际上就是把文件修改添加到暂存区;
|
||||
|
||||
第二步是用`git commit`提交更改,实际上就是把暂存区的所有内容提交到当前分支。
|
||||
|
||||
因为我们创建Git版本库时,Git自动为我们创建了唯一一个`master`分支,所以,现在,`git commit`就是往`master`分支上提交更改。
|
||||
|
||||
你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
|
||||
|
||||
## 管理修改
|
||||
|
||||
git不是管理文件,而是管理修改的操作。
|
||||
|
||||
我们修改readme.txt,然后add提交到暂存区
|
||||
|
||||

|
||||
|
||||
然后再次修改readme.txt,这次我们直接commit
|
||||
|
||||

|
||||
|
||||
然后查看状态
|
||||
|
||||

|
||||
|
||||
我们会发现第二次修改的并没有被提交
|
||||
|
||||
查看一下工作区的文件和仓库的文件的区别
|
||||
|
||||

|
||||
|
||||
## 撤销修改
|
||||
|
||||
- 当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令`git checkout -- file`。
|
||||
|
||||
- 当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令`git reset HEAD `,就回到了上一种情况,第二步按上一种情况操作操作。
|
||||
|
||||
## 删除文件
|
||||
|
||||
我们将文件从工作区删除
|
||||
|
||||

|
||||
|
||||
git会直接察觉到我们的删除操作,如果这个时候提交,那么就会从版本库中删除该文件
|
||||
|
||||

|
||||
|
||||
但是如果误删除了,可以还原到版本库中的最新版本
|
||||
|
||||

|
||||
|
||||
如果要删除暂存区中的文件,可以使用`git rm`
|
||||
|
||||
# 远程仓库
|
||||
|
||||
注册github
|
||||
|
||||
打开命令行,创建key
|
||||
|
||||

|
||||
|
||||
打开github的个人用户设置
|
||||
|
||||

|
||||
|
||||
在里面找到`SSH and GPG keys`
|
||||
|
||||

|
||||
|
||||
新建一个ssh keys
|
||||
|
||||

|
||||
|
||||
然后按照下图提示填写
|
||||
|
||||

|
||||
|
||||
然后你就成功添加了ssh的key,下次登录github的时候,就会直接被识别出你的身份啦
|
||||
|
||||

|
||||
|
||||
## 添加远程仓库
|
||||
|
||||
首先回到登录之后的页面
|
||||
|
||||

|
||||
|
||||
创建你的仓库
|
||||
|
||||

|
||||
|
||||
根据这边的提示可以将我们本地的仓库和远程的仓库关联起来哦
|
||||
|
||||

|
||||
|
||||
推送成功的画面
|
||||
|
||||

|
||||
|
||||
观察到远程仓库和我们本地仓库已经关联一致
|
||||
|
||||

|
||||
|
||||
要关联一个远程库,使用命令`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`,就能确定当前分支,以及当前分支的提交点:
|
||||
|
||||

|
||||
|
||||
每次提交,`master`分支都会向前移动一步,这样,随着你不断提交,`master`分支的线也越来越长。
|
||||
|
||||
当我们创建新的分支,例如`dev`时,Git新建了一个指针叫`dev`,指向`master`相同的提交,再把`HEAD`指向`dev`,就表示当前分支在`dev`上:
|
||||
|
||||

|
||||
|
||||
你看,Git创建一个分支很快,因为除了增加一个`dev`指针,改改`HEAD`的指向,工作区的文件都没有任何变化!
|
||||
|
||||
不过,从现在开始,对工作区的修改和提交就是针对`dev`分支了,比如新提交一次后,`dev`指针往前移动一步,而`master`指针不变:
|
||||
|
||||

|
||||
|
||||
假如我们在`dev`上的工作完成了,就可以把`dev`合并到`master`上。Git怎么合并呢?最简单的方法,就是直接把`master`指向`dev`的当前提交,就完成了合并:
|
||||
|
||||

|
||||
|
||||
合并完分支后,甚至可以删除`dev`分支。删除`dev`分支就是把`dev`指针给删掉,删掉后,我们就剩下了一条`master`分支:
|
||||
|
||||

|
||||
|
||||
首先,我们创建`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`做个修改,加上一行。
|
||||
|
||||
然后提交
|
||||
|
||||

|
||||
|
||||
切换回`master`分支后,再查看一个`readme.txt`文件,刚才添加的内容不见了!因为那个提交是在`dev`分支上,而`master`分支此刻的提交点并没有变
|
||||
|
||||

|
||||
|
||||
现在,我们把`dev`分支的工作成果合并到`master`分支上:
|
||||
|
||||

|
||||
|
||||
`git merge`命令用于合并指定分支到当前分支。合并后,再查看`readme.txt`的内容,就可以看到,和`dev`分支的最新提交是完全一样的。
|
||||
|
||||
注意到上面的`Fast-forward`信息,Git告诉我们,这次合并是“快进模式”,也就是直接把`master`指向`dev`的当前提交,所以合并速度非常快。
|
||||
|
||||
合并完成后,就可以放心地删除`dev`分支了:
|
||||
|
||||

|
||||
|
||||
删除后,查看`branch`,就只剩下`master`分支了:
|
||||
|
||||

|
||||
|
||||
### 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`分支,继续我们的新分支开发:
|
||||
|
||||

|
||||
|
||||
修改`readme.txt`最后一行
|
||||
|
||||
在`feature1`分支上提交
|
||||
|
||||

|
||||
|
||||
切换到`master`分支,修改`readme.txt`最后一行为别的内容,然后提交
|
||||
|
||||

|
||||
|
||||
现在,`master`分支和`feature1`分支各自都分别有新的提交,变成了这样:
|
||||
|
||||

|
||||
|
||||
Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突
|
||||
|
||||

|
||||
|
||||
Git告诉我们,`readme.txt`文件存在冲突,必须手动解决冲突后再提交。`git status`也可以告诉我们冲突的文件:
|
||||
|
||||

|
||||
|
||||
我们可以直接查看readme.txt的内容:
|
||||
|
||||

|
||||
|
||||
Git用`<<<<<<<`,`=======`,`>>>>>>>`标记出不同分支的内容,我们修改后保存,然后提交:
|
||||
|
||||

|
||||
|
||||
现在,`master`分支和`feature1`分支变成了下图所示:
|
||||
|
||||

|
||||
|
||||
用带参数的`git log`也可以看到分支的合并情况:
|
||||
|
||||

|
||||
|
||||
## 分支策略
|
||||
|
||||
首先,`master`分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活
|
||||
|
||||
所以,团队合作的分支看起来就像这样
|
||||
|
||||

|
||||
|
||||
# 标签管理
|
||||
|
||||
## 创建标签
|
||||
|
||||
首先,切换到需要打标签的分支上:
|
||||
|
||||

|
||||
|
||||
然后,敲命令`git tag `就可以打一个新标签:
|
||||
|
||||

|
||||
|
||||
可以用命令`git tag`查看所有标签:
|
||||
|
||||

|
||||
|
||||
可以给历史的commit id加上标签
|
||||
|
||||

|
||||
|
||||
注意,标签不是按时间顺序列出,而是按字母排序的。可以用`git show `查看标签信息:
|
||||
|
||||

|
||||
|
||||
还可以创建带有说明的标签,用`-a`指定标签名,`-m`指定说明文字:
|
||||
|
||||

|
||||
|
||||
用命令`git show `可以看到说明文字:
|
||||
|
||||

|
||||
|
||||
## 操作标签
|
||||
|
||||
如果标签打错了,也可以删除:
|
||||
|
||||

|
||||
|
||||
因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。
|
||||
|
||||
如果要推送某个标签到远程,使用命令`git push origin `:
|
||||
|
||||

|
||||
|
||||
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
|
||||
|
||||

|
||||
|
||||
然后,从远程删除。删除命令也是push,但是格式如下:
|
||||
|
||||

|
||||
|
||||
- 命令`git push origin `可以推送一个本地标签;
|
||||
- 命令`git push origin --tags`可以推送全部未推送过的本地标签;
|
||||
- 命令`git tag -d `可以删除一个本地标签;
|
||||
- 命令`git push origin :refs/tags/`可以删除一个远程标签。
|
||||
|
Reference in New Issue
Block a user