开局一张图
大家好,我是沐华,可能大家或多或少的有遇到过类似图片这种情况,这是不是很烦,一个文件还能这么凑合,如果是多文件,比如一个项目成千上万个文件,还可能多人修改,要是都这么维护,就算不考虑占用存储空间那也绝对是地狱级难度,所以 Git
出现了
本文将从 Git 入门到进阶、由浅入深,从常用命令、分支管理、提交规范、vim 基本操作、进阶命令、冲突预防、冲突处理等多方面展开,足以轻松应对工作中遇到的各种疑难杂症,如果觉得有所帮助,还望看官高抬贵手给个赞呗,感谢
虽说现在工作中使用 Git 都会用一些图形化管理工具来提高开发效率。可事实上使用图形管理化工具的前提,也是基于对命令都基本了解。还有比如我平时用的工具 GithubDesktop
因为不带第三方合并工具,只能手动解决冲突,而且有的功能没有,只能配合自己手动敲命令。
即使是工具也没有那么完美的工具,掌握命令才是渔
,工具只是鱼
。其他的 Git 可视化管理工具比如:小乌龟、SourceTree、还有我们开发用的 IDE 集成的,本期就不过多介绍了
基本概念
Git 是一个开源的,也是目前最主流的分布式版本控制系统。
Git 的作用与好处是:
可以帮我们保存文件的所有修改记录,并且使用版本号进行区分,让我们随时可以浏览历史版本、对比不同版本的差异、还原到指定版本,起到恢复和保护作用的同时,还能和其他人同时修改,然后通过 Git 来合并修改的部分文件,超级方便
不熟的同学别和 Github 搞混了,Git 是工具,Github 是平台,没有什么必然的联系,就像 Java 和 JavaScript 也没有什么必然联系一样
Github 是一个主流的代码托管平台。可以理解为存放和管理代码的网盘,可以把自己的代码传上去进行共享和维护
安装配置
安装地址:Git - Downloads (git-scm.com)
安装好后,命令行黑窗口是使用 Git Bash
、CMD
、Powershell
、终端
、或者编译器内置的,这个就看个人喜欢了
接着可以再配置下默认用户名和邮箱,比如配置全局的就用如下两条命令,替换成自己的用户名和邮箱,以后所有的项目都会默认这里配置的用户信息
如果只需要在某个特定的项目中用其他的名字和邮箱,不用全局的,就把上面命令中的 --global
去掉在项目下执行即可,或者不执行命令,直接在项目下的 .git/config
文件里添加如下,也可以
基本操作
先了解一下几个基本概念:
- 工作区:开发的地方,开发过程就是对工作区的操作
- 暂存区:执行
git add xxx
命令后,会把当前修改过的文件添加到暂存区 - 本地仓库:执行
git commit
命令完成后,会把当前暂存区的文件放入本地仓库 - 远程仓库:就是用来托管代码的服务器(如:Github、Gitee、GitLab、工蜂、Bitbucket..),执行
git push
命令后,会把本地仓库的文件提交到远程仓库
常见选项
再认识一下几个后面会用到多次的命令,之后就不一一解释了
命令 | 缩写 | 意思 |
--all | -a | 全部 |
--force | -f | 强制 |
--delete | -d | 删除 |
--delete --force | -D | 强制删除 |
--move | -m | 移动或重命名 |
--move --force | -M | 强制移动或重命名 |
-u | 设置默认远程分支 |
拉取远程项目
拉取远程项目到本地,先复制远程项目链接,再在本地执行如下命令
上传本地项目
本地新建的项目,还没有提交到远程仓库,就需要先关联远程仓库。先在远程创建一个空项目,并复制该项目的链接,然后在本地项目根目录依次执行下面命令即可
其中 git remote add origin https://xxxx
,就是往 .git/config
文件里添加下面这一段,手动添加也可以,意思就是与远程仓库建立关联。其他的几条命令后面有介绍,我们先认识下 origin
为后面做铺垫;
命令里的 origin
类似变量命名,这是默认的而已,没什么特别的意思,可以随便写,假如改成 abc
,后面的 git push origin xxx
改成 git push abc xxx
即可,方便区分远程仓库的
由此可得出一个结论,就是一个项目可以关联多个远程仓库,命不同的名就行了
没错
git remote -v
可以快速查看当前已经关联的远程仓库列表
关联多个远程仓库
可以使用 git remote add xxx
添加多个,或者直接动在 .git/config
文件里添加。
比如一个项目同时关联一个 Github
仓库和一个 Gitee
仓库,添加一个 remote
就是了,比如如下:
这样当我们提交代码的时候,想提交到 Github
就用 git push github master
,想同时提交到 Github
和 Gitee
的仓库,只需要 git push all master
即可
以命令的方法在某个 remote
下添加 url
如下,比如在上面 remote github
下再添加一个 url
:
常用命令 add/commit/fetch/merge/pull/push
git add
git commit
git fetch
git merge
git pull
pull
和 fetch
都是下载远程分支,区别是 pull
会和当前分支合并,fetch
不会
git push
vim 基本操作
一点点小插曲
比如 git commit
就会打开一个 vim
的终端编辑器,让我们写提交说明,新手很容易在这个编辑器上面踩坑,不知道怎么输入,不知道怎么退出,最后只能关闭终端窗口,这也没办法,vim
的操作确实有些反人类。
vim
打开默认是不能输入的,要按 a
或者 i
进入编辑模式,输入完成后,再按 Esc
退出编辑模式,这时左下角会有输入框,输入如下英文字符,注意冒号别打成中文字符,回车即可退出 vim
回到终端:
-
:w
:保存 -
:q
:退出 -
:wq
:保存并退出 -
!
:强制的意思,不能保存时 :w!
强制保存,不能退出时 :q!
或 :wq!
强制退出
我们继续 git
分支管理 branch/switch/checkout
一个人玩,可能分支的作用没那么大,但是团队协作,离不开分支管理。
比如本文开头图片那样一个版本一个分支多方便,是吧
或者现有一个新需求一个页面分为多个模块,分配给多个人负责,每人做一个模块,最后合并成一个完整的页面,如果都在同一个分支上开发,各种逻辑相互穿插,那冲突真的是人都要搞麻了,如果每个人都新建一个分支,开发自己负责的那个功能,最后再合并到同一个分支上去就非常方便了
然后因为多人协作肯定不是在一台电脑上,所以就需要一个服务器,来搭建一个 Git 仓库服务,或者用公共的云服务器仓库存储,常见的代码托管平台有比如:Github
、码云(Gitee)
、腾讯工蜂
、GitLab
、Bitbucket
...,关于这个本篇文章不过多展开
创建分支
查看分支
切换分支
checkout
和 switch
的共同点是都能切换分支,不同点是:
-
switch
语义上好点 -
switch
仅仅用于切换和创建并切换,checkout
还能用来还原工作区,后面进阶那有介绍
删除分支
重命名分支
合并分支
其实就是上面的 git merge
。比如要把 test
分支合并到 master
分支,就:
git commit 提交规范
git commit
提交规范指的就是 git commit -am 'xxxx'
里的 xxxx
的书写规范,比如我在工作中开发了一个新功能提交的时候一般这么写:
-
git commit -am 'feat: 添加扫码登录
-
git commit -am 'feat(mobile):添加扫码登录
,或者加个范围说明是添加哪方面的功能
feat
就是添加新功能的时候用,更多说明如下:
-
feat
:添加新功能 -
fix
:修复问题/BUG -
style
:注意不是指CSS,而是修改了如空格、缩进、逗号等代码风格相关,且不影响运行结果的 -
perf
:优化相关的,比如功能优化、性能提升、提升体验等 -
refactor
:代码重构,没有加新功能或者修复 bug -
revert
:撤消编辑,回滚到上一个版本、撤销上一次的 commit 之类的 -
test
:测试相关,比如单元测试、集成测试等 -
docs
:修改文档/注释,比如 README、CHANGELOG、CONTRIBUTE 等 -
chore
:依赖更新/脚手架配置修改等,比如有改变构建流程、或者增加依赖库、工具之类的 -
workflow
:工作流程改进 -
ci
:持续集成 -
types
:类型定义文件更改
到这里,基础部分内容就结束了
问个问题:git branch -M ac
是啥意思?不许翻上面
进阶操作
常用命令
装*神器 alias
命令难记?没有关系
咱们除了会写一些别人看不懂的代码,也可以敲一些别人看不懂的命令
alias
这个单词想必大家就熟悉了,和项目中创建路径别名类似,在 Git
里是用来创建命令别名的,比如执行如下这命令后
然后比如想创建一个名为 test
的本地分支,如下即可
好像有点邪教了,了解一下吧~
继续工作中用到的
检出 git checkout/git restore
重置 git reset
git reset
通常用来把代码重置到过去的某个版本,有五种模式(--mixed
、--soft
、--hard
、--merge
),注意看注释有说明区别。
另外 git reset
比较暴力,要慎用,比如现在提交五次了,然后使用这个命令重置到第一次,那么第二三四五次提交记录会全部没了的,找不回来的,这种情况记得新建个分支来执行这种操作就没事了,或者使用 git revert
commitID
可以通过三种方法查看
- 执行
git log
命令能看到当前分支本地所有提交记录,上面每一条记录都有对应一个 commitID
- 去远程代码仓库查看历史提交记录,那里每一条提交记录都有一个对应的
commitID
-
git tag
查看标签列表,如果有的话,再 git show 标签名
查看标签详情,里面也会有 commitID
另外关于叫法本地仓库一般说重置、还原、撤销都行,远程仓库一般叫回滚
还原 git revert
git revert
和 git reset
有点类似,只是比 reset
稍微温柔一点,没那么暴力。
上面介绍了假如现在是第五版,用 reset
在重置回第一版本的时候,二三四五版全都会没了,而 revert
重置回第一版的时候,只是新增一条提交记录“第六版”,代码变成第一版的代码,原本的一二三四五版记录都会有
另外 revert 还要分两种情况,一种是还原正常的 commit,也就是 git commit 提交的 commit,另一种是用 merge 合并的 commit,如下
挑拣 git cherry-pick
比如有两个分支 master 和 test,在 test 上修改了,并且提交了 commit 之后,这时候想把这次的提交也给弄到 master 上,就可以复制 test 的 commitID,再换到 master 分支后执行 git cherry-pick commitID
就可以了
what?这不就是 merge?
和 merge 不同的是:cherry-pick
合并的是某一次 commit
提交的文件,merge
合并的是整个分支。且 merge
会额外多一条 merge commit
的记录,而 cherry-pick
不会。
而且 cherry-pick
更加灵活,在需要把某个/或多个分支中的 commit,合入其他分支的时候都可以用,示例如下
变基 git rebase
git rebase
和 git merge
的区别
git merge 和 git rebase 都是可以合并分支,合并用法也是一样,不同的一个是在 commit 记录的处理上:
-
git merge
会新建一条新的 commit,然后两个分支以前的 commit 记录都指向这个新 commit 记录。这种方法会保留之前每个分支的 commit 历史。 -
git rebase
会先找到两个分支的第一个共同的 commit 祖先记录,然后将提取当前分支这之后的所有 commit 记录,放到目标分的最新提交后面。经过这个合并后,两个分支合并后的 commit 记录就变为了线性的记录了。
这么说可能不太好理解,看如下示例:
- 然后是解决冲突的问题上,merge 是解决一次冲突就行了,rebase 需要一次一次地解决,如上示例的记录顺序也能看出来
- 再就是
rebase
可以合并多次 commit。比如本地分支提交了三个 commit,但没有 push 到远程,最后想提交到远程的时候,为了简洁,我们希望把本地的三个 commit 合并成一个 commit 再提交到远程,远程只产生一条 commit 记录,就可以用 git rebase -i
处理下先,这命令可以删除指定记录,或者合并多个 commit,对 commit 消息编辑等
贮藏 git stash
git stash
常用于把修改储存起来,需要的时候再取出来。常用于:
- 切换分支并且需要保留修改的时候
- 切换分支并且需要把修改带到新的分支的时候
清理 git clean
和 git reset
的区别是:reset 删除的是己跟踪的文件,并且将已 commit 的回退。clean 删除的是未跟踪的文件/目录
差异 git diff
用来找出仓库或者文件之间的差异,可以用来预测或者阻止可能产生冲突的合并
问题预防
- 不要对已经提交到远程仓库的 commit 进行 rebase 变基操作,除非是你一个人玩的分支
- 在切换分支,或者合并分支,或者重置/回滚之前,最好不要有未
commit
的文件,如果有并且不想提交就用 git stash
先存起来,再执行操作,如果用命令操作的话,取出之后记得清理 - 远程仓库回滚前记得做好备份,比如拉一个分支在本地。并且需要通知团队其他成员,不要悄摸摸地就搞了
解决问题
切换分支保留修改
有时候比如我们在 test 分支上开发了一半,由于某些原因需要切换到 master 分支,但现在又不想提交,又想保留修改并且不带到 master 分支上去,就可以这样:
切换分支转移修改
有的时候我们需要在 test 分支上开发,但是忘记了,活快干完了才发现当前原来是 master 分支,可是已经开发了,这时候就需要切换分支到 test,并且把已经开发的部分内容也从 master 分支带到 test 分支来,就可以这样:
合并时发生冲突用 git merge abort
或 git reset --merge
都可以取消合并
比如把不想要的代码 commit 了,但是没有 push 比如刚更新的代码出问题了,需要还原这次提交的代码 比如某次提交了不想提交的东西,需要清除掉它
revert 之后重新上线 diff 丢失
- 比如在 dev 分到开发了个功能,提交后会产生一条 commit 记录,为了方便理解,我们先把这次提交标记为 a
- 然后合并到 master 后,我们把这次合并记录标记为 b
- 结果出现了 bug 需要撤销合并,使用 revert b 撤销了,这会产生了一条新的记录 我们标记为 c
- 然后继续在 dev 分支开发完成提交,提交记录标记为 d
- 这时候再合并到 master 上去,此时合并后的内容不会包含 a 的提交,因为 a 被 revert 丢弃过,不会参与 diff,如果需要包含 a,需要先 revert c 意思是撤销某一次的撤销,再来合并,就 ok 了
合并冲突不想合并了
合并时、或者拉取时等,发现有冲突,可能是其他同事提交的,自己不知道怎么冲突怎么选择,或者其他原因,总之不想合并了,都可以用 --abort
取消,比如合并的时候发现有冲突不想合并了
git merge --abort
取消合并即可
解决冲突
有的时候合并分支冲突是由于本地主分支没有更新导致,或者有时 git pull
的时候冲突,只需要掉本地主分支,再重新拉一下远程分支就好了。
有的时候冲突就只能解决冲突,使用 git status
看由于冲突导致没有合并成功的文件是哪些,然后去编辑器打开冲突的文件即可,也可用 cat <文件路径>
查看指定文件里冲突的部分,直接去编辑器改
或者就是用命令,比如把 test 分支,合入 master 分支时产生冲突。