# 【git教程】快速掌握git

﻿@[TOC](https://github.com/UnderTurrets/notes/blob/master/uncategorized/%E6%96%87%E7%AB%A0%E7%9B%AE%E5%BD%95/README.md)

***

## 1.本地版本控制

### 1.1 在一个目录下建立仓库`git init`

```shell
git init
```

#### 1.1.1 删除仓库

```shell
rm -rf .git
```

### 1.2 暂存区`git add`

### 1.2.1 保存到暂存区

* 保存某个文件的修改到暂存区

```shell
git add <filename>
```

* 全部保存到暂存区

```shell
git add .
```

### 1.2.2 撤销暂存区文件

* 撤销某一个暂存区文件

```shell
git reset HEAD <filename>
```

* 撤销所有暂存区文件

```shell
git reset HEAD~0
```

### 1.3 提交与回退

#### 1.3.1 提交到版本库`git commit`

```shell
git commit -m "附加信息"
```

#### 1.3.2 回退`git reset`

`git reset`有`--soft`、`--mixed`、`--hard`三种参数可选，其中`--mixed`是默认方式，不同含义如下：

* `--soft`：只重置HEAD指针的位置
* `--mixed`：重置HEAD指针的位置，并清空`git add`命令的暂存区
* `--hard`：重置HEAD指针的位置，清空`git add`命令的暂存区，并重置工作空间所有的更改

以下是`git reset`的几种用法：

* 回退项目到指定版本

```shell
git reset <version>
```

* 回退项目到上一个版本

```shell
git reset HEAD~1
```

* 回退单一文件到上个版本

```shell
git reset HEAD~1 <filename>
```

* 回退到上n个版本

```shell
git reset HEAD~n
```

### 1.4 删除

#### 1.4.1 删除未跟踪的文件`git clean`

```shell
# 删除 untracked files
git clean -f
 
# 连 untracked 的目录也一起删掉
git clean -fd
 
# 连 gitignore 的untrack 文件/目录也一起删掉 （慎用，一般这个是用来删掉编译出来的 .o之类的文件用的）
git clean -xfd
 
# 在用上述 git clean 前，强烈建议加上 -n 参数来先看看会删掉哪些文件，防止重要文件被误删
git clean -nxfd
git clean -nf
git clean -nfd
```

#### 1.4.2 删除已跟踪的文件`git rm`

```shell
git rm <filename>
```

### 1.5 检查

#### 1.5.1 查看当前仓库状态`git status`

```shell
git status
```

#### 1.5.2 查看操作日志`git reflog`

```shell
git reflog
```

#### 1.5.3 查看此分支的提交日志`git log`

```shell
git log
```

* **经过回退后，使用"git log"就看不到回退前的版本号了，但使用"git reflog"就可以查看**

### 1.6 分支管理`git branch`

#### 1.6.1 创建分支

```shell
git branch <name of local branch>
```

#### 1.6.2 切换分支

```shell
git switch <name of local branch>
```

#### 1.6.3 查看分支

```shell
git branch
```

#### 1.6.4 合并分支（可能出现冲突，如两个分支都修改了同一文件）

```shell
git merge <name of local branch>
git merge --no-ff -m "附加信息" <name of local branch>
```

#### 1.6.5 删除分支

```shell
git branch -d <name>
git branch -D <name>#强行删除，慎用
```

### 1.7 模块管理`git submodule`

#### 1.7.1 添加子模块

```shell
git submodule add <URL of the submodule> <folder's name of the submodule>
```

使用此命令后，项目根目录下会自动添加`.gitmodules`文件，用来存放子模块的信息；同时，也会自动下载子模块仓库的主分支最新版本并用指定名字的目录去装载，如果未给出指定的名字，则使用子模块仓库的默认名字。

使用子模块的意义在于便捷地引用其他人的库。如果你需要对别人的库进行自己的修改，那么你完全没有必要使用`submodule`，因为你没有修改别人库的权限，你可以直接把别人的库克隆下来之后提交。如果你只是想使用而不需要更改，那么推荐你使用`submodule`，这样的话，在提交时，主项目不会记录子模块的更改。

#### 1.7.2 查看子模块

```shell
git submodule
```

#### 1.7.3 拉取子模块

* 在克隆一个项目时直接拉取：

```shell
git clone https://github.com/yyy/xxx.git --recursive
```

* 在克隆之后再拉取：

```shell
git submodule init
git submodule update
```

这两个命令也可以合并为一个：

```shell
git submodule update --init
```

如果子模块又嵌套了子模块，则需要添加`--recursive`参数

```shell
git submodule update --init --recursive
```

#### 1.7.4 从远程更新子模块

* 法一：直接在子模块目录下拉取

```shell
git pull
```

* 法二：项目根目录下执行：

```shell
git submodule update --remote <name of the submodule which you want to update>
```

若不给出需要更新的子模块名字，则默认更新所有子模块。

拉取之后，记得提交主项目的更改。

#### 1.7.5 删除子模块

先注销并清楚缓存：

```shell
git submodule deinit -f <submodule's name>
git rm --cached <submodule's name>
```

然后检查子模块目录和`.git/module`中的子模块条目是否删除：

```shell
rm -rf .git/modules/<submodule's name>
rm -rf <path/to/submodule>
```

再检查配置文件中的子模块条目是否删除

```shell
gedit .gitmodules
gedit .git/config
```

最后提交即可，示例如下：

```shell
git commit -m "Remove submodule"
```

## 2.远程控制

### 2.1 获取本设备的ssh密钥

```shell
ssh-keygen -t rsa -C "email@*.com"
```

* 密钥在Linux系统中保存于/usr/local/home/.ssh

### 2.2 与远程库建立或删除连接`git remote`

#### 2.2.1 建立连接

```shell
git romote add <name of the remote repository> <SSH offered by the website>
```

#### 2.2.2 删除连接

```shell
git remote rm <name of the remote repository>
```

### 2.3 绑定此分支到远程库的某一分支

```shell
git branch --set-upstream-to <name of local branch> <name of the remote repository >/<name of remote branch>
```

### 2.4 提交到远程库的某一分支`git push`

```shell
git push <name of the remote repository> <name of local branch>
```

* **如果远程库没有对应名字的分支，那么会在远程库自动创建一个同名分支**
* **如果不给定\<name of local branch>参数，那么会按照git branch --set-upstream-to绑定的关系进行推送。如果未绑定，则推送失败**

### 2.5 标签管理`git tag`

#### 2.5.1 打标签

```shell
git tag <name of tag> <version>
git tag -a <name of tag> -m "附加信息" <version> #带说明信息的标签
```

#### 2.5.2 删除标签

```shell
git tag -d <name of tag>
```

#### 2.5.3 查看某一标签

```shell
git show <name of tag>
```

#### 2.5.4 查看所有标签

```shell
git tag
```

#### 2.5.5 推送标签到远程库

```shell
git push <name of the remote repository> <name of tag>
git push <name of the remote repository> --tags #一次性推送所有标签
```

#### 2.5.6 删除远程标签

```shell
git push <name of the remote repository>:refs/tags/<name of tag>
```

### 2.6 克隆`git clone`

#### 2.6.1 克隆默认分支

```shell
git clone <URL>
```

#### 2.6.2 克隆指定分支

```shell
git clone -b <name of remote branch> <URL>
```

## 3.多人协作

### 3.1 版本落后于远程库而推送失败

1. 先用git branch --set-upstream-to 绑定到指定远程分支

```shell
git branch --set-upstream-to <name of local branch> <name of the remote repository >/<name of remote branch>
```

2. 用git pull指令：抓取所绑定分支的最新版本并尝试merge。若出现冲突要手动解决

```shell
git pull <name of remote repository> <name of remote branch>:<name of local branch>
```

3. 最后提交并推送即可

```shell
git commit -m "附加信息"
git push <name of the remote repository>
```

### 3.2 老版本bug修复流程

1. 保存此分支的工作现场

```shell
git stash
```

2. 切换到有bug的分支，从这个有bug的分支创建一个新分支修复bug，然后合并，**保存好合并时给出的版本号**
3. **用这个版本号**，对所有存在这个bug的分支做一次相同的提交

```shell
git cherry-pick <version>
```

4. 回到工作现场，查看贮藏列表并恢复

```shell
git stash list #列出贮藏列表
git stash apply stash@{n} #根据序号n恢复到指定工作现场
git stash drop stash@{n}#根据序号n删除指定工作现场
```
