本地的git
git除了最经典的add commit push用来做版本管理,其实他的分支管理也非常强大
可以说你学好了分支管理,就可以完成团队的配合协作了
git仓库
我们可以使用git init
来初始化一个git仓库,只要能看见.git
文件夹,就代表这是一个git仓库了
git分区
git一共有三个分区,工作区、暂存区、版本库
工作区
和.git
文件夹在相同目录即为工作区,也就是我们写代码的地方
暂存区与版本库
这两个分区实际上是存在.git
文件夹里的
当我们使用add之后,代码就会被存储在暂存区,只有commit之后,也就是提交代码,整个代码才会被放入版本库,也就是上图的master文件夹中
我们也可以偷看一下.git
文件夹,需要注意的是,我们绝不能更改.git
文件夹的任何内容
在整个git目录中,我们不需要全部搞明白,只需要抓住几个核心文件即可
- objects:这是一个对象目录,存储的是git对象,Git进行版本管理的核心不是将文件全部备份,而是只记录修改的部分,当工作区代码修改后,会将修改的内容写入obj库中的一个新git对象中,因此暂存区和版本库存的不是数据本身,而是git对象的索引,以便快速定位与修改
- index:暂存区,add之后就会更新这里的内容,我还没有add所以并没有这个文件夹
- /refs/heads/master:这是当前master分支(版本库)的最新一次提交的id索引,在每一次提交的内容中都会保存上一次提交的索引id,因此整个版本库就像一个链表一样
- HEAD:这是一个指针,用于指向当前我们处于版本库的哪一个位置,也就是在链表的哪一个节点
git 本地常用命令
add commit这里就不说了,分别就是将文件保存到暂存区和提交到版本库
- 查看工作区与暂存区代码差异:
git diff [file]
- 查看版本库与工作区代码差异:
git diff head -- [file]
- 查看提交记录:
git log
commit后面那一串代码是提交的ID,每一次的提交ID都是独一无二的,确保我们可以进行版本回退
版本回退
版本回退是比较复杂的,核心是使用git reset [--soft | --mixed | --hard] [HEAD]
实现的
我们核心理解的是,版本回退指的是将版本库中的内容进行回退,工作区和暂存区是否回退则由参数决定
- --mixed 是默认选项,会将暂存区的内容回退,工作区不变
- --soft 是工作区和暂存区都不回退
- --hard 是暂存区和工作区都回退,当工作区有未保存备份提交的代码时不要使用这个选项!否则工作区代码无法找回!
- HEAD选项是标识当前版本 HEAD^ 标识上一个版本 HEAD^^ 标识上两个版本,可以依次类推,也可以直接写上面的提交ID,回退到指定版本
如果不小心全部回退到目标版本之前的某个版本了,这时git log
是无法找到目标版本的提交ID了,需要使用git reflog
,查看所有提交的命令,再利用ID回退到目标版本即可
删除文件
git rm
删除工作区和暂存区的文件
撤销修改
- 撤销工作区的修改:
git checkout -- [file]
将工作区文件恢复到最近一次add或commit的状态 - 撤销工作区和暂存区的代码:使用
git reset --mixed [HEAD]
,会将暂存区和版本库的代码进行回退,工作区不变,变为第一种情况 - 全部回退:
git reset --hard [HEAD]
,前提是不能push,因为推送到远端仓库后再回退其实就意义不大了,本身就是为了避免不影响远端仓库的
分支管理
master分支或者main分支为主分支,一般大型项目都不在主分支上,分支就像是分身一样,写不同部分的代码,最后合并就是完整的项目,因此我们也可以进行分支的创建、切换、合并
比如我们现在创建一个dev分支,我们可以把这个时间线画出来
创建分支git branch [name]
,查看分支git branch
星号就标识我们当前所处的分支
使用git checkout [name]
可以切换分支
我们可以在dev分支中创建文件,编写代码
写好后我们切换到master分支,会发现工作区的文件和代码并没有改变
在dev分支合并之前,master主分支都不会收到影响
这是因为dev分支的新提交对于master分支来说是完全不可见的
那要进行部署上线,就需要合并分支,可以利用git merge [name]
进行分支合并
需要注意的是,这个name指的是需要将name分支合并到当前所在分支
例如当前是master分支,使用git merge dev
是将dev分支合并到master分支
合并分支之后分支并没有删除,仍然可以继续开发,因此合并也可以用来同步各个分支的代码
如果某个分支没有用了,就可以使用git branch -d [name]
删除指定分支
如果两个分支是两个团队在维护,并且他们都对同一个文件进行修改了,合并会发现有冲突,就像下面这样
这种情况下git会提示我们哪些文件有冲突,我们需要手动修改保留代码,然后再进行一次add和commit,就可以解决冲突了
Fast forword模式
这是一种分支合并的模式,在这种模式下,删除分支后查看分支历史时,就无法查看到以前的分支信息了,我们无法直到这个最新提交是merge来的还是commit来的
但是我们在解决冲突之后再commit一次,这样就不是fast forword模式了,就能看出分支信息了
git也可以强制禁用 fast forword git merge -no-ff -m "合并" [name]
这样就会自动生成新的commit,就能看到分支信息了
这里需要边操作边理解画图,才能更好理解
分支管理策略
一般来说master分支是最稳定的,也就是服务部署的分支,然后是dev开发分支,开发分支可以再继续细分到具体的某个人,如果开发只有你一个人来包揽也是可以的,类似的还有feature分支
如何管理和实践还是因人而异了
master分支遇见BUG怎么办
master分支突然遇到bug,有两种解决的思路
第一种是直接在master上开一个新的bug分支,然后再改bug,改好之后直接合并,最后删除bug分支
第二种是需要在dev分支上修,但是dev分支上还有未完成的工作,我们就可以使用git stash
将当前工作区文件信息进行存储,然后修bug,修好之后给push回去,之后再使用git stash list
可以查看内容,用git stash pop
恢复即可
远端的git
其实远端的git是用于合作用到的更多,例如github,gitee都是代码托管平台,相当于免费给了一个远程的代码存储服务器
我们在push和pull的时候其实就是和远端的git仓库进行互动,将本地的所有git信息发到远端去了
但是在多人协作时,还是要优先使用pull,将其他人的代码拉下来,再进行push,要提前在本地解决好冲突才行
git标签
试想一下这样的场景, 公司在团队协作开发项目时, commit提交了上万次, 但是此时你想要回滚到某个特定的commit版本, 你怎么应对? 难道一个一个的去找吗? 难受, 实在是难受
理解标签
标签tag可以理解为对某次commit的一个标识, 相当于为此次commit取别名, 例如在项目发布某个版本时, 可以给最近一次commit打上v1.0的标签,这样下次需要回滚到1.0版本的提交时, 就不需要查看log了, 只需要查看tag标签即可定位
常用指令如下
- 创建标签:
git tag [name],如: git tag v1.0
- 此标签默认打在最新一次提交的commit id上
- 查看所有标签:
git tag
- 给标签标注信息:
git tag -a [name] -m "信息"
- 查看标签信息:
git show [标签名]
- 删除标签:
git tag -d [标签名]
- 推送标签至远端服务器:
git push origin v1.0
- 推送所有标签:
git push origin --tags