# git 操作
* 基础配置
```js
git config --global user.name xxx
git config --global user.email xxx@136.com
// 创建秘钥
ssh-keyger -t rsa -c 'xxx@136.com'
```
* 工作中常规用法
```js
// 1. git add .
git add . // 提交更改/新增的全部代码(提交到缓存区)
git status // 查看代码状态
git commit -m '提交信息' // 提交到本地仓库
git pull // 拉取远程分支代码
git push // 将本地代码提交到远程上
```
* 工作中常用的命令
```js
// 查看本地和远程分支
git branch -a
// 删除本地分支
git branch -d <branch-name>
// 删除远程分支
git push origin -d <branch-name>
// 切换分支
git checkout <branch-name>
// 拉取远程分支并创建本地分支
git checkout -b develop origin/develop
git fetch origin <branch-name>:<local-branch-name>
```
* 文件暂存 `stash`
1. 添加改动stash
> `git stash save -a 'message'`
2. 恢复改动
> `git stash pop <stash@{ID}>`
3. 查看stash列表
> `git stash list`
4. 删除暂存
> `git stash drop <stash@{ID}>`
5. 删除全部缓存
>`git stash clear`
* 打标签
1. 默认标签是打在最新提交commit 上
> `git tag v1.0`
2. 需要在指定的提交中打标签,需要通过git log 获取到哈希值
> `git tag v1.0 dabiaoqian`
3. 查看所有的标签
> `git tag`
4. 查看标签信息
> `git show <tagname>`
5. 创建带说明的标签
> `git tag -a <标签名> -m '<说明>'`
* 代码撤回
1. 暂缓区代码撤回(git add .)
```js
// 工作区的代码不会受到影响,只是add的状态撤销
// 单个文件
git reset HEAD <文件名>
// 全部文件
git reset HEAD
```
2. 本地仓库代码撤回(git commit -m '提交信息')
```js
// 撤销最近一次的commit(撤销commit,不撤销git add)
git reset --soft HEAD~1
// 撤销最近一次的commit(撤销commit,撤销git add)
git reset --mixed HEAD~1
// 撤销最近一次的commit(撤销commit,撤销git add,工作区的代码改动将丢失。操作完成后回到上一次commit状态)
git reset --hard HEAD~1
// 撤销最近n次的commit,并恢复到暂存区
git reset HEAD~n
// 使用 rebase 撤销代码
git rebase -i [hash]
git rebase -i HEAD~1
```
3. 远程代码的修改(git push)
```js
// 方案1 reset
// reset(前): 版本1(aa1) -> 版本2(aa2) -> 版本3(aa3) -> master
// reset(后): 版本1(aa1) -> 版本2 -> master
// 回到版本1
git reset --hard aa1 // aa1 哈希值
git push -f // 需要强推, 因为本地代码的版本比远程低
// -----------------
// 方案2 revert
// reset(前): 版本1(aa1) -> 版本2(aa2) -> 版本3(aa3) -> master
// reset(后): 版本1(aa1) -> 版本2(aa2) -> 版本3(aa3) -> 版本4(aa4) -> master
// 版本2功能存在问题, 使用 revert 只撤销版本2的代码,生成版本4
git revert -n aa2
git commit
git push
```
* 代码合并
1. merge
* 代码示例
```js
// featureA 分支代码合并到 master
git checkout master
git merge featureA
```
* git merge 命令支持一些选项
1. --no-ff: 禁止fast-forward合并策略,强制Git创建一个新的合并提交
> `git merge --no-ff featureA`
2. --squash: 将合并结果压缩为一个提交,并且不会保留源分支的提交记录
3. -m<message>: 指定新的合并提交的提交信息
```js
git merge --squash featureA
git commit -m 'merge featureA'
```
2. rebase
```js
// featureA 分支代码合并到 master
git checkout master
git rebase featureA
```
3. cherry-pick
```js
// 切换到模板分支,单个提交
git checkout feature
git cherry-pick <commitHash>
// 多个提交
git cherry-pick A..B // 从A到B不包含A
git cherry-pick A^..B // 从A到B包含A
// 使用cherry-pick 遇到冲突,解决冲突,文件添加在暂存区(git add.) 让 cherry-pick 继续执行
git cherry-pick --continue
```
* git merge 与 git rebase 的区别
* merge
* 优点:
1. 保留分叉结构: 清晰显示分支的合并关系,有助于理解整个项目的开发流程
2. 不改变历史: 合并分支时不会改变提交历史,不会对其他开发人员造成困扰,保持代码库的稳定性
3. 较少的冲突: 相比rebase合并分支时可能遇到较少的冲突
* 缺点:
1. 提交历史比较混乱: 可能会导致提交历史变得混乱,不够线性清晰
2. 增加额外的合并提交: 创建额外的合并提交,可能会增加一些无关的提交信息
* rebase
* 优点:
1. 历史整洁: 创建更整洁、更线性的提交历史,避免额外的合并提交
2. 易于理解: 直观的提交历史线性结构更容易理解和回顾
3. 更好的回退和调整: 可以更容易进行提交、回退或修改
* 缺点
1. 潜在的冲突: 可能会遇到分支冲突,需要手动解决冲突并继续rebase过程
2. 改变历史: 可能改变提交历史,导致其他开发困惑,并可能导致代码库不稳定
* merge 与 rebase 如何选择
1. 注重提交历史的整洁性和线性结构选择rebase
2. 注重保留分支接口和稳定性选择 merge