一、Git 简介
Git 是目前世界上最先进的分布式版本控制系统。
二、集中式和分布式的区别
集中式版本控制系统
提到集中式版本控制,大家首先想到的就是SVN,集中式版本控制系统中版本库是集中存放在中央服务器上的,而干活的时候,用的是自己的电脑,所以要先从中央服务器拿到最新的版本,然后开始干活,干完活再把自己的活推送到中央服务器,最大的缺点就是必须联网才能工作。
分布式版本控制系统
每个人的电脑都是一个完整的版本库,这样,你工作的时候就不需要联网了,因为版本库就在自己的电脑上,多人协作时,只需要把各自的修改推送给对方就可以看到对方的修改了。
三、Git 指令
Git 中有四个不同的工作区域,不同的状态的文件处于不同的区域:
- 工作区(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 <远程分支名>:<本地分支名>将最新的提交拉取下来,直接合并,可能会产生冲突,需要手动处理 -
报错:
- 解决办法:执行
git pull origin main --allow-unrelated-histories,git 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: 参数传递命令,用于将标准输入作为命令的参数传给下一个命令
修改分支名称
- 修改本地分支名:
git branch -m oldName newName - 删除远程分支:
git push --delete origin oldName - 上传新命名的本地分支:
git push origin newName - 把修改后的本次分支和远程分支关联:
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 remote或git remote -v查看远程仓库的信息用
不小心把远程地址配错了,提示
fatal: 远程 origin 已经存在。时,只需要将远程配置文件删除,配置最新的即可
git remote rm origingit remote add origin 新的远程地址
3.8 查看历史记录
git log
git log --pretty=onelinegit 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 [第101次commit] [第1次commit]
执行上述命令完之后,代码库会切换到上述范围正中间的那一次提交(也就是第51次提交)
3)此时运行代码,如果代码运行正常,则使用git bisect good标记本次提交是没有问题的,此时代码会自动切换到后半段中点的版本(也就是第76次提交)
4) 继续运行代码,如果代码运行不正常了,则使用git bisect bad标记本次提交是有问题的,此时代码会自动切换到本次提交到上一次提交的中点(也就是第63次提交)
5) 不断重复上述第3、4步骤,就能找到出问题的那次提交
6) 退出查错,回到最近一次提交git bisect reset
3.14 git 中 submodule 子模块的使用
- 添加子模块
git submoudle add <url> <path>
温馨提示:如果提示“索引已经存在”,则执行
git rm --cached 子模块路径
- 删除子模块
// 第一步,删除子模块目录及源码
rm -rf 子模块目录
// 第二步,删除项目目录下.gitmoudles 文件中子模块相关内容
vim .gitmodules
// 第三步,删除配置项中子模块相关内容
vim .git/config
// 第四步,删除模块下的子模块目录
rm -rf .git/modules/子模块目录名称
参照文献: