Git第二章
Git常见命令
##1.常用的命令和分支 变基
重置文件
git restore+ 文件名
专门用来撤销文件的修改
git restore 有两个核心使用场景,对应git工作区、暂存区两个核心区域
1.撤销工作区的修改
也就是本地改了文件,但是没有 git add 到暂存区,想把文件恢复到上次提交状态
git restore + 文件名 ----撤销单个文件的工作区修改
git restore . + 文件名 ----撤销该目录下所有文件的工作区修改
把文件恢复到最近一次提交的状态,也就是说你在工作区所有未暂存修改都会被清空。注意:无法恢复
2.撤销暂存区的修改
也就是已经 git add 把文件放入暂存区,想重新拿出来,但保留工作区的修改
git restore --staged + 文件名----取消单个文件暂存
git restore --staged . + 文件名----取消该目录下所有文件的暂存
文件回到未暂存状态,但是文件里的修改会被保留
删除文件
git rm + 文件名
专门用来删除义跟踪文件的命令
rm核心使用
1.删除磁盘上的真实文件
2.删除后自动暂存
3.直接git commit 就能提交这次删除
如果只是想取消跟踪,不删除文件
git rm --cached + 文件名
效果
1.磁盘文件完全保留,不会删除
2.git不再跟踪文件,并自动暂存
强制删除
如果一个文件已被跟踪,但是被改了内容,如果我没有进行 git add 直接执行 git rm ,此时Git会拒绝删除
并提示(use --cached to keep the file, or -f to force removal)
此时要么commit然后再进行rm,或者进行强制删除
git rm -f + 文件名
为什么要进行rm删除,为什么不直接右键删除
不用手动写 git add
git rm --cached 它只会把文件从git仓库移除,不会删除本地磁盘文件,比较安全
误区
staged作为撤销,rm作为删除,那如果我们先使用rm删除然后再撤销,是不是文件就会回来了呢
答案是:并不会
Why
git restore --staged本质:只操作暂存,不操作磁盘,也就是staged能把文件从暂存撤回至未暂存
此时你肯定会想,删了又不能给我撤回删除,给我个撤回暂存有什么用啊
答案也确实是没什么用。因为这个不归staged管
真正恢复文件的是
1.仅用于撤销工作区的修改,文件本地还在
git restore + 文件名
2.从git仓库的HEAD里,把文件恢复到本地
git checkout HEAD -- + 文件名
移动文件
本质上是先删除旧文件,再创建新文件
git mv <原路径> <新路径>
注意
不要试图右键手动移动文件
git会以为旧文件被删除了,并且创建了一个一样的新文件,那么会导致新文件处于未跟踪状态,并且要执行两次暂存,第一个是旧文件暂存删除,第二次是新文件暂存。并且Git会丢失这个文件的提交记录!而mv就完全不会出现这种情况
mv总结
1.移动文件
2.自动暂存
3.记录重命名信息,会告诉Git这两个文件是同一个文件,只是改了路径,从而保留提交历史
分支
git在存储文件时,每一次代码提交都会创建一个与之对应的节点,git就是通过一个个节点来记录代码的状态
也就是我们每一次做提交,git都会给我们生成一个节点,这个节点存储着你的 name、email、-m "xxx"里面的备注等一系列信息。
并且它会和你的上一个节点产生关系,指向你上一个节点 例如: 节点1 <= 节点2 <= 节点3 <= 节点4(最新)
怎么查看Git历史节点
git log
会出现一堆信息,其中每一次commit xxx 就是一个节点。如果你不想看这么多的信息
可以使用 git log --oneline 结果是一行一行的节点,大概长这样:
a7c474f 第二次提交 878b203 第一次提交
当你使用log查看历史时,它最后会出现 :的情况,这说明你当前还处于查看模式,可以使用上下键流量提交历史。
按q键可以回到正常的终端命令行
commit 1317409a14a7f04e2a63fea042264dcf30bc027b这个id它是git节点的唯一标识,也就是哈希ID
通过上述解释不难发现,节点会构成一个树状结构,树状结构就意味着这个数会存在分支,默认情况下仓库只有一个
分支,命名为main,但是也存在老项目仍使用master
怎么查看分支
git branch
分支的作用
在不影响main的情况下,能开出一个独立线路去写代码,做到并行开发,功能隔离
创建新的分支
在我们使用git时,可以创建多个分支,分支与分支之间相互独立,在分支上修改代码不会影响其他的分支
git branch + 分支名字
删除分支
git branch -d + 分支名
作用:仅删除已经合并到最后合并到主分支的分支,防止误删
git branch -D+ 分支名
作用:无论是否合并,直接强制删除分支
当你处于当前分支时,git不会让你删除当前使用的分支,你必须切换到其他分支才能删
切换分支
git switch + 分支名
如果我们想创建分支,并且自动切换到这个新分支上
git switch -c + 分支名
合并分支
当你创建一个新分支时,你在新分支里的写的了很多代码,然后你回到主分支,你会发现你写的代码都不见了。
其实你的代码处于新分支,而不在主分支里面,这样做的好处是不会污染主分支,影响主分支功能。那么当你处理完你新分支
的代码时,你需要让他在主分支显现,就需要合并分支。
git merge + 分支名
合并分支的规则只有一句,谁是目标分支,就在谁身上合并别人
例如: 想把 bug1合并至main,就需要先switch到main,再merge
此时又有个疑问,合并后的分支要留着吗
合并完成后,可以安全删除分支
fast-forword(快速合并)
分支本质上是指向commit的指针
快速合并就是把main分支的指针,挪到被合并分支的最新commit,并且它不会生成新的合并提交
快速合并只有一条,其他的都是普通合并
此时又会有个问题
都是分支,哪一个才是快速合并的分支呢
一句话,这条路是自己选的。
假设有两个新分支,一个是bug分支,一个是test分支
当你处于main分支时,如果你先对bug分支进行merge,此时bug分支就是快速合并路线,并且此时的指针已经进入bug分支
test分支就只能走普通合并
普通合并,会生成一个新的commit,可以保留完整的分支记录,这样反而对项目开发有利,它可以清楚的看到分支历史
那我们怎么不让它快速合并呢
git merge --no-ff + 分支名
代码冲突
还是上面两个分支,如果恰好两个分支都修改了一个文件,就会触发代码冲突。
Auto-merging src/hello.js
CONFLICT (content): Merge conflict in src/hello.js
Automatic merge failed; fix conflicts and then commit the result.
怎么发生的
因为bug分支属于快速合并,先合并bug分支到main,此时无冲突。当再合并test时,就会发现,修改的同一个文件版本不一致,无法自动合并,其中必须
注意
1.冲突只在合并时发现,不合并不发生
2.修改同一个文件并不会直接触发代码冲突,当你修改两个文件同一行代码,git无法判断保留哪一个,才会发生代码冲突
如何解决冲突
有些编辑器会提示你,点解决冲突,然后选一侧保留就好了。或者自己删除一侧代码
注意
永远不要在未提交代码的情况下切换分支,会导致代码归属混乱,污染主分支
变基(rebase)
在开发中,我们除了可以用merge来合并分支外,还可以通过变基来完成分支的合并
此时有个疑问,我们不是已经有了merge,为什么还要出现变基呢?变基到底是什么呢?
我们在通过merge合并时,在提交记录中会将所有的分支创建和分支合并的过程全部都显示出来,这样当我们项目复杂,开发
过程比较长,我们必须要反复创建合并删除分支,这样一来将会使得我们代码的提交记录变得十分混乱
变基是什么
比如我们有个结构
A -- B -- C(main)
\
D -- E (bug)
bug分支原来是从B节点搭出去的,通过变基
A -- B -- C -- D -- E
把两条分支变成一条分支,没有分叉,没有合并节点,历史干净
变基时发生了什么
1.当我们发起变基时,git会首先找到两条分支的最近的共同祖先(相交节点)
2.对比当前分支相对于祖先的历史提交(找到D对于B发生的所有变化),并且将他们的不同提取出来存储到一个临时文件中
3.调整E指针的位置,把它存到C当中,也可以理解为base
4.以当base开始,重新执行历史操作
通俗来说变基不是合并而是把bug分支的起点由B改向了C
本质
Git提交完成后,它是不能被修改的。它本质不是把D、E移动到C节点后面,而时在C节点的基础上重新做一遍,生成全新的D、E
然后把bug分支的指针指向C,再把全新的D、E在C上重新生成提交,使其看起来像把分支起点由B改向了C
我们从新生成的D、E节点的唯一标识,也就是哈希值的改变可以验证这一点
注意:变基会改变历史,不能对main分支进行变基,只能对自己的节点进行变基
补充
Git里,每一个分支,本质就是一个永远指向该分支最后一个提交节点的指针
其实,变基,rebase,base是理解的关键,就是指针的移动,新提交的生成。就是改变base的位置,把原来节点的
分支后面发生变化的部分重新生成,存储,等到base位置改变好了后,就把我们前面存储的节点放入新的base节点里面
讲了这么多,没说命令!
变基命令
变基永远在自己分支变,也就是这个代码例如在bug分支写
git rebase + 目标分支名
这个目标分支名就是,还是上面的例子,bug分支base要变,main就是目标分支名
变基同样也有冲突问题
解决方式跟上面一样
解决完冲突后继续变基
git rebase --continue
放弃变基命令
git rebase --abort
变基完,合并分支还没有完成
此时只需要回答哦main然后进行merge
最后branch -d 删除bug分支。