Git 相关 - Git 常用命令(自用)

345 阅读11分钟

一、Git 简介

Git 是目前世界上最先进的分布式版本控制系统。

二、集中式和分布式的区别

集中式版本控制系统

提到集中式版本控制,大家首先想到的就是SVN,集中式版本控制系统中版本库是集中存放在中央服务器上的,而干活的时候,用的是自己的电脑,所以要先从中央服务器拿到最新的版本,然后开始干活,干完活再把自己的活推送到中央服务器,最大的缺点就是必须联网才能工作。

分布式版本控制系统

每个人的电脑都是一个完整的版本库,这样,你工作的时候就不需要联网了,因为版本库就在自己的电脑上,多人协作时,只需要把各自的修改推送给对方就可以看到对方的修改了。

三、Git 指令

Git 中有四个不同的工作区域,不同的状态的文件处于不同的区域: image.png

  • 工作区(Workspace):本地写代码的区域
  • 暂存区(Index):暂存区是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中
  • 本地仓库(Repository):在自己电脑上的仓库,提交更新,找到暂存区域的文件,将快照永久性存储在 Git 本地仓库
  • 远程仓库(Remote):在远程用于存放代码的服务器

3.1 配置

Git自带一个 git config 的工具来帮助设置控制 Git 外观和行为的配置变量。

git config [--global] user.name "[name]"
git config [--global] user.email "[email address]"

3.2 启动

  • git clone git@server-name:path/reponame.git 从远程克隆

  • git init [project-name] 初始化一个新的git仓库,或者重新初始化已存在的仓库,默认为 master 分支

3.3 添加文件

添加文件到暂存区

git add

git add <file> 添加多个文件(放到暂存区),可以反复多次使用

添加文件到本地仓库

git commit

  • git commit --amend 修改 commit 说明

  • git commit -v 提交时,显示所有 diff 信息

  • git commit -m <message> 提交到本地仓库

commit message格式:

⚠️ 注意:<message>存在规范,不能随便写,例如修改了哪个文件或者新增了哪个文件

<type>(scope): <subject>
  • type(必须):用于识别 git commit 的类别

    • feat: 新功能
    • fix/to: 修复bug
      • fix: 适合于一次提交直接修复问题
      • to: 适合于多次提交。最终修复问题提交时使用fix
    • docs: 文档
    • style: 格式(不影响代码运行的变动)
    • refactor: 重构(既不是新增功能,也不是修复bug)
    • perf: 优化相关,比如提升性能、体验
    • test: 增加测试
    • chore: 构建过程或辅助工具的变动
    • revert: 回滚到上一个版本
    • merge: 代码合并
    • sync: 同步主线或分支的bug
  • scope(可选):用于说明commit影响的范围

  • subject(必须):commit目的的简短描述

提交代码到远程仓库

git push

  • git push -u origin <name> 推送到远程 master 分支
  • 如果远程仓库没有对应的分支,则使用git push --set-upstream origin <name>创建远程分支

3.4 拉取代码

拉取代码到工作区

git pull

  • git pull origin <远程分支名>:<本地分支名> 将最新的提交拉取下来,直接合并,可能会产生冲突,需要手动处理

  • 报错:image.png

    • 解决办法:执行 git pull origin main --allow-unrelated-historiesgit pull命令后加一个--allow-unrelated-history合并两个独立启动仓库的历史。

拉取代码到本地仓库

git fetch

  • git fetch origin <分支名> 用于从远程仓库获取最新的代码和提交历史,但不会合并或修改你的工作目录
  • git fetch --all 获取远程仓库所有分支的更新

git fetch 🆚 git pull

  • git pull = git fetch + git merge

3.4 分支操作

在每次提交时,Git都将他们串成一条时间线,这条时间线只有一条叫做主分支(master),HEAD 指向当前分支

查看分支

git branch

  • git branch 查看当前分支
  • git branch -r 查看远程所有分支
  • git branch -a 查看远程和本地所有分支
  • git branch <新分支名> 基于当前分支,新建一个分支
  • git branch <新分支名称> <提交 ID> 从提交历史恢复某个删掉的某个分支

合并分支

git merge

  • git merge <分支名> 合并分支到指定分支
  • git merge --abort 合并分支出现冲突时,取消合并,一切回到合并前的状态

git rebase

  • git rebase -i <commit> 将当前分支移植到指定分支或指定 commit 上
  • git rebase --continue 用于解决冲突之后,继续执行 rebase

merge和rebase有什么区别❓

dev                 ✅ -- ✅ 
                  /                
                 /                
                /               
matser  ⭕️ -- ⭕️ -- ⭕ --️️ ⭕
  • merge

    • 特点:会自动创建一个新的commit
    • 优点:真实记录commit
    • 缺点:commit繁杂
    dev                 ✅ -- ✅ -- ✅(多了一次合并的commit)
                      /           /
                     /           /
                    /           /
    matser  ⭕️ -- ⭕️ -- ⭕ --️️ ⭕ 
    
  • rebase

    • 特点:合并之前的commit地址
    • 优点:得到更简洁的commit历史
    • 缺点:如果合并代码时出现了问题,不容易定位,因为重写了commit history
    dev                ⭕ -- ⭕️️ -- ✅ -- ✅ 
                     /                
                    /                
                   /               
    matser  ⭕️ -- ⭕️
    

切分支

git checkout

  • git checkout -- file 丢弃工作区的修改
    • 文件自修改后还没有放到暂存区,现在撤销修改就回到和版本库一模一样的状态;
    • 文件已经添加到暂存区后,又做了修改,现在撤销修改就回到添加到暂存区后的状态。
  • git checkout -b dev 或者git switch -c dev 创建 dev 分支,并切换到 dev 分支
// 等同于
git branch dev
git checkout dev 或者 git switch dev

删除分支

  • git push origin -d <name> 删除远程分支
  • git branch -D <name> 删除本地分支
  • git branch | grep 'fix*' | xargs git branch -d 删除包含fix的所有分支
  • git branch | xargs git branch -d 删除当前分支以外的其他所有分支

删除分支时需要切换到除被删除分支之外的分支

解释一下👇

  • |: 管道命令,用于将一串命令串联起来。前面命令的输出可以作为后面命令的输入
  • grep: 搜索过滤命令,使用正则表达式
  • xargs: 参数传递命令,用于将标准输入作为命令的参数传给下一个命令

修改分支名称

  1. 修改本地分支名: git branch -m oldName newName
  2. 删除远程分支:git push --delete origin oldName
  3. 上传新命名的本地分支:git push origin newName
  4. 把修改后的本次分支和远程分支关联:git branch --set-upstream-to origin/newName

3.5 git diff

  • git diff <file> 查看当前代码 add 后,具体修改了什么内容
  • git diff 可以查看所有具体修改,也可以指定查看具体的文件修改
  • git diff --staged 查看现在 commit 提交后,会提交哪些内容

3.6 git status

git status 查看工作区的状态,可以查看本地未提交的代码中,修改了哪些文件。

3.7 远程仓库

  • git remote add origin git@server-name:path/reponame.git 关联一个远程仓库

  • git remotegit remote -v 查看远程仓库的信息用

不小心把远程地址配错了,提示fatal: 远程 origin 已经存在。 时,只需要将远程配置文件删除,配置最新的即可

  • git remote rm origin
  • git remote add origin 新的远程地址

3.8 查看历史记录

git log

  • git log --pretty=oneline
  • git log --graph 查看分支合并图

3.9 版本回退

git reset

场景: 如果想恢复到之前某个提交的版本,并且那个版本之后的提交都不要了。

作用: git reset 主要用于移动分支引用和 HEAD 指针,以便重新设置当前分支的状态。

影响:

  • --mixed 模式(默认):移动分支引用和 HEAD 指针,并取消暂存区的修改。工作目录的状态变为指定提交,但保留工作目录的更改。
  • --soft 模式:只移动分支引用和 HEAD 指针,保留工作目录和暂存区的更改。工作目录和暂存区的状态变为指定提交。
  • --hard 模式:彻底放弃之前的提交和更改,移动分支引用和 HEAD 指针,工作目录变为指定提交的状态。

HEAD 表示当前版本,上一个版本HEAD^ ,上上个版本HEAD^^ ,以此类推,往上 100 个版本是HEAD~100

举例:

git reset --mixed commit_id
git reset --soft commit_id
git reset --hard commit_id

具体操作

1. git log 查看版本号
2. git reset --hard 目标版本
3. git push -f origin 分支名
  • 穿梭前,用git log 查看提交历史,以便确定要回退到哪个版本。
  • 重返未来,用git reflog 查看历史命令,以便确定要回到未来的哪个版本。

git revert(反做)

场景: 如果想撤销之前的某个版本,但是又想保留该目标版本之后的版本,记录下整个版本变动流程。

作用: git revert 用于创建一个新的提交,该提交的变更效果是撤销之前的提交。

影响:

  • 生成一个新的提交,该提交的变更效果是撤销之前的提交
  • 保留了提交历史的完整性,不修改分支引用

具体操作

1. git log 查看版本号
2. git revert -n 版本号
3. git commit -m "版本名"
4. git push

3.10 删除文件

本地文件管理器删除文件rm file 后,使用git status可以 查询哪些文件被删除了:

1)如果确定要删除,使用git rm file ,并且git commit

2)如果误删,则恢复删除的文件git checkout -- file

3.11 bug 分支

例如,你正在 dev 分支上进行工作到一半,突然接到要修复一个代号 101 的 bug 任务

1)把当前工作现场储藏起来git stash

2)创建分支修复 bug,修复完之后 commit。切换到 master 分支完成合并,最后删除新创建的 bug 分支;

3)恢复未做完的 dev 工作现场

​ 使用git stash list 查看工作现场

​ (a)用git stash apply ,然后使用git stash drop 删除 stash 内容。使用git stash apply stash@{0} 恢复指定的 stash;

​ (b)使用git stash pop 恢复的同时能把 stash 内容也删除了。

在 master 分支上修复 bug,想要合并到当前的 dev 分支,可以使用git cherry-pick <commit> ,把 bug 提交的修改复制到当前分支,避免重复劳动。

3.12 git tag <name> 打标签

为什么要打标签?四个字:以示重要,比如说使用tag标记发布节点(v1.0、v2.0等)

  • 切换到需要打标签的分支上
git branch
git checkout <tagname>
  • 打标签git tag <tagname>
  • 查看所有标签git tag
  • 查看指定标签信息git show <tagname>
  • 删除标签 git tag -d <tagname>
  • 推送一个本地标签git push origin <tagname>
  • 推送全部未推送过的本地标签git push origin --tags
  • 删除一个远程标签git push origin :refs/tags/<tagname>

3.13 查找哪一次代码提交引入了错误

git bisect

原理:二分法

举个栗子:一共有101次提交

使用流程

1) 检查代码提交记录 git log --pretty=oneline

2) 启动查错 git bisect start [终点commit] [起点commit]

终点是最近一次的提交,起点是更久之前的提交

git bisect start [第101commit] [第1commit]

执行上述命令完之后,代码库会切换到上述范围正中间的那一次提交(也就是第51次提交)

3)此时运行代码,如果代码运行正常,则使用git bisect good标记本次提交是没有问题的,此时代码会自动切换到后半段中点的版本(也就是第76次提交)

4) 继续运行代码,如果代码运行不正常了,则使用git bisect bad标记本次提交是有问题的,此时代码会自动切换到本次提交到上一次提交的中点(也就是第63次提交)

5) 不断重复上述第3、4步骤,就能找到出问题的那次提交

1661616730056\_.pic.jpg

6) 退出查错,回到最近一次提交git bisect reset

3.14 git 中 submodule 子模块的使用

  1. 添加子模块 git submoudle add <url> <path>

温馨提示:如果提示“索引已经存在”,则执行git rm --cached 子模块路径

  1. 删除子模块
// 第一步,删除子模块目录及源码
rm -rf 子模块目录

// 第二步,删除项目目录下.gitmoudles 文件中子模块相关内容
vim .gitmodules

// 第三步,删除配置项中子模块相关内容
vim .git/config

// 第四步,删除模块下的子模块目录
rm -rf .git/modules/子模块目录名称

参照文献: