git 0基础入门—git入门与实践(3)—详细图解git分支操作及超详细的解决分支冲突及reset和checkout原理深究和详细操作

    技术2022-07-10  117

    文章目录

    git入门与实践(3)1. 分支入门操作1. 1 查看分支: git branch1. 2 创建分支:git branch 分支名称1. 3 切换分支:git checkout 分支名1. 3. 1 分支流程详解1. 3. 1. 1 流程动态演示 2. 分支合并2. 1 HEAD查看命令2. 1. 1 git log --decorate2. 1. 2 git log --oneline --decorate2. 1. 3 git log --oneline --decorate --all --graph 2. 2 git merge 分支合并2. 2. 1 模拟合并小结 2. 3 快速前移2. 3. 1 --no-ff2. 3. 2 模拟快速前移 3. 分支冲突3. 1 分叉冲突3. 2 快速前移3. 3 如何判断是否会引起冲突3. 3. 1 快速前移不会引起冲突3. 3. 2 分叉冲突可能会引起冲突 4. 解决分支冲突5. 删除分支5. 1 无法删除的分支 6. 取消合并7. 撤销合集7. 1 撤销上一次添加暂存区的内容7. 1. 1 git rm --cached7. 1. 2 将文件内容手动修改回之前的状态 7. 3 git checkout -- 撤销对文件的修改7. 4 取消暂存7. 4. 1 git reset HEAD 7. 5 撤销上一次提交信息7. 5. 1 git commit --amend7. 5. 1. 1 修改提交信息7. 5. 1. 2 修正紧挨着的一次的提交与本次提交合并 8. reset使用8. 1 git reset HEAD8. 1. 1 多条回退8. 1. 2 git reset --hard (尽量避免使用)8. 1. 3 git reset --soft(建议使用)8. 1. 4 git reset --mixed(默认) 8. 2 通过哈希找回历史记录8. 3 查看历史提交记录 9. reset与checkout本质9. 1 reset过程分析9. 2 checkout过程对比

    git入门与实践(3)

    1. 分支入门操作

      某天完成了项目的一次开发后,准备开始第二次开发,但是如果直接在一次开发的基础上更改,我们的文件就是1+2,管理起来相当不方便。

    1. 1 查看分支: git branch

      前面*代表当前所处的分支

    1. 2 创建分支:git branch 分支名称

      创建出来的分支,并不会改变我们当前所在的位置。

    git branch branch1

    git branch

      git是如何判断我们所处当前哪个分支上呢?

      (HEAD -> master, branch1) git是通过HEAD指向获取当前分支的。

    1. 3 切换分支:git checkout 分支名

      将HEAD指向切换的分支

      将工作目录恢复成当前分支的快照

      简写命令:git checkout -b 分支名

      之后提交一个文件,之后看日志,发现HEAD已经指向branch1了。再往后仔细看标注,就是master分支的日志了。

      除此之外,如果是branch1分支,切换过去,只会显示该分支所有的文件。

      切换master分支,则是它所有的文件。

      在branch1分支下删除所有文件

      git rm * -r

      再切回去:

      文件都在!因此各个分支是互不影响的!

    1. 3. 1 分支流程详解

      首先有一次c1的提交,在c1的基础上还有c2的提交,这些操作都是在默认的master分支上进行的,在c2的提交上又创建新分支branch1。git如何判断在当前在哪个分支上,就是通过HEAD指针。当前HEAD指向master。

      我们切换分支后,HEAD就指向branch1了。

      我们再提交c3,此时branch1向前移动,并带着HEAD一块移动了。此时branch1的路线就是c1->c2->c3。

      此时我们想操作master分支,就需要切换过去了。

      之后再进行c4提交。此时master的路线就是c1->c2->c4。

    1. 3. 1. 1 流程动态演示

    2. 分支合并

      假如我们开始开发,基础功能是c1提交和c2提交之间的内容,处理的是第一个版本的内容。

      为了便于后面的开发,我们将其分成两个分支,一个master,一个branch1。

      紧接着我们在分支branch1上开始开发,然后进行功能提升,进行第二个版本开发,提交c3、c5。

      现在又出现了问题,第一个版本开发的时候,有一些小的bug。这个时候需要提交一些补丁,这可怎么呢?首先需要回退到c2上,这上面有第一个版本开发的时候所有的记录,这个时候我们实际不用回退。直接切换到master的分支,在这个分支修改bug并提交c4。这个时候就可以将c1->c2->c4的代码进行打包,替换线上的代码了。

      第二个版本开发完成至c5提交。唯独缺少了c4的补丁,你可能会想到再创建一个提交修改bug。明显是不科学的,这样重复处理,是非常耽误时间和工作效率的。因此git就提供了一个很好用的功能,即合并分支。

      模拟一下以上操作,新建一个文件夹。

    c1提交

    c2提交

    git checkout -b branch1 创建分支并使HEAD指向新分支,-b就代表 branch

    完成c3提交

    切换回master打补丁,c4提交

    2. 1 HEAD查看命令

    2. 1. 1 git log --decorate

    --decorate 参数用来显示一些相关的信息(带有分支信息),如HEAD、分支名、tag名等

    2. 1. 2 git log --oneline --decorate

    --oneline 校验和(哈希)

      查看分支指向+哈希

      以上显示不太明显,我们可以该命令

    切换回branch1看看

    我们继续提交c5

    2. 1. 3 git log --oneline --decorate --all --graph

      查看命令的完美组合 —> 包含了所有分支的提交,以树形图形形式展现。

    --all 所有分支信息

    --graph 打印出树形图

    2. 2 git merge 分支合并

    注意:在我们日常开发中最好必须有一个主分支,有一个主分支就利用我们对分支进行管理。比如平时打游戏,就会有一个主线任务和一个支线任务。然后支线任务也不会影响主线,实际上项目中主线就是项目的版本。默认情形下,大家都把默认分支master作为主分支。

    git merge 目标分支

      将目标分支的内容合并到当前分支

    git merge branch1 将branch1分支合并到主分支master上来。

      此时完成了合并,解决了第二个版本中第一个版本的bug,我们想让第二个版本上线,就打包c6代码即可。

    2. 2. 1 模拟合并小结

      其实最终合并关注3个点,一个是必须有共同父节点c2,其次是master末尾节点c4和brach末尾节点c5,将c4、c5实际整合成了c6,c6就完美解决了,第二个开发版本c2->c3->c5中需要修复第一个开发版本bug的问题了。

    2. 3 快速前移

      当master和branch没有形成分叉,依旧是处于一条路径线,当HEAD落后于所要合并的分支,将会形成快速前移

      先初始化目录

      进行两次提交

      创建分支branch1,并切换过去,做第三次提交

      git checkout -b branch1

    git log --oneline --decorate --all --graph

    切换到master,并与branch1合并

    git log --oneline --decorate --all --graph

      我们发现了奇怪的问题,master和branch1都跑到c3了。为啥成这样了, 因为快速前移,我们仔细观察上图,就有提示:Fast-forward

      仔细观察上图发现合并前并没形成分叉,branch1只是在master的上开了一个分支。

    master:c1->c2

    branch1:c1->c2->c3

      master上的提交都包括在branch1里了,这时执行的合并就和之前不一样了,不会出现新的提交,而是将master的指针往前移动了,同样HEAD会跟随master往前移。我们把这个过程称为“快速前移”。

      实际快速前移在合并操作里是不友好的,我们打印log,它这没有任何信息(有关合并的信息)可以表示出来。

      那如何解决呢?

    2. 3. 1 --no-ff

      禁止快速前移(可以commit记录描述为合并操作)

      我们回退回去!

    git merge --no-ff -m '这是一次合并操作' branch1 (要加描述)

    2. 3. 2 模拟快速前移

    3. 分支冲突

    3. 1 分叉冲突

      初始化git仓库

      创建并切换一个分支

      修改a文件,并提交

      切换成master主线,a.txt内容为空,因为提交也分先后,在master中只是新建了a.txt,在branch1里才修改了内容。然后切换回master,会重置工作目录。我们添加1.txt的内容。

    提交它!

    我们把branch1合并过来,发现冲突报错了。

    我们打开a.txt

    <<<<<<< HEAD master添加的内容,截止到分隔符

    ======= 分隔符

    >>>>>>> branch1 从分隔符到当前,是branch1添加的内容

    <<<<<<< HEAD 1 2 3 4 5 第二次修改 ======= a b c 第1次修改 >>>>>>> branch1

      想要解决冲突,打开文本,可将内容合并或删除后不需要的内容,再提交即可,这里我们只保留master添加的内容。

    3. 2 快速前移

      有的时候修改,不会产生冲突。

      我们新建并提交一个b文件

      添加内容,并提交

      再开一个分支branch2,对b进行修改!再提交。

      切换到master再合并

      提示Fast-forward(快速前移),并没有产生冲突!

    3. 3 如何判断是否会引起冲突

    3. 3. 1 快速前移不会引起冲突

      如上master第1次提交:新建文件并添加内容

      再创建分支,修改文件中的内容

      最后切换到master合并分支,合并之前,git会判断两个分支是什么关系?如果是祖先级关系,master和branch2处于同一条commit路径上(直接级祖先关系),就进行了快速前移。

    ✔️ master和branch2直接进行合并,不会引起冲突

    3. 3. 2 分叉冲突可能会引起冲突

      如上上面的操作是,master第1次提交:新建文件并创建并切换分支,添加文件中的内容

      再切换回master,修改文件中的内容,提交之后最后进行合并。这时候出现了分叉,则不会进行快速平移了,git进行如下的分支判断:

    分析master和branch1中的修改是否一致,如果一致合并将会成为一次空合并(因为内容完全一致,没有合并的需要)如果不一致,是否修改的同一个文件内容,如果是,产生冲突

    4. 解决分支冲突

    解决分支冲突:

    ​ ① 手动解决冲突部分

    ​ ② 解决完成后再次提交,会以这次提交内容为准

    5. 删除分支

      合并完成后,分支就没有任何的后期用途了,这时候我们需要手动删除分支,以防止自己词穷的时候出现重复命名分支的情况。

    git branch -d 分支名称 -d -> delete

    5. 1 无法删除的分支

    注意:HEAD所指向的分支,无法删除

    还有一种情形也无法删除:

    如果你的分支,从未合并:git branch -D 分支名称

      切换回master,再删除分支,都失败了。提示从来没合并过的分支,git会提示你是否真的要删除一个分支。它防止我们删错分支,导致分支上的内容丢失。

      这个时候就需要强制删除分支命令了。

    git branch -D branch3

    6. 取消合并

    git merge --abort

    修改文件内容

    切换回master,再修改内容,提交合并

    合并必然失败

    可以取消合并!

    git merge --abort

      日志也不会提示进行过合并操作。

    7. 撤销合集

    7. 1 撤销上一次添加暂存区的内容

    7. 1. 1 git rm --cached

      我们参考上面提示说明:git rm --cached <file> 将暂存区文件变为未追踪状态(删除暂存区或分支上的文件, 但本地又需要使用),这其实就是一种撤销

    7. 1. 2 将文件内容手动修改回之前的状态

    修改a.txt的内容

    我们再把文件中的内容清空

    7. 3 git checkout – 撤销对文件的修改

      从先从缓存区中拉取版本还原,如果没有再到版本库中拉取还原。参考廖雪峰老师的官网如下:

    修改文件内容。

    7. 4 取消暂存

    7. 4. 1 git reset HEAD

    git reset HEAD <file>

    修改a.txt

      本想分开提交,但是一不小心全部放到了暂存区

      如果提交的话,两个文件都得提交

      那我们尝试 git rm --cached a.txt 删除暂存区或分支上的文件, 但将本地文件留存

      我们发现,也无法提交,这里git会帮我们重命名了,完全不符合我们的需求。我们需求是仅仅提交b.txt。

      我们还是回到原来的状态,把a.txt添加回暂存区

    git reset HEAD a.txt

    注意:当一个文件第一次进入暂存区实际上无需用reset命令的,直接remove就行,因为暂存区没有其之前的信息。

      假设我们当前提交的记录写错了怎么整?请看下面的内容。

    7. 5 撤销上一次提交信息

    7. 5. 1 git commit --amend

    7. 5. 1. 1 修改提交信息

    git commit -m '新建一个文件b,a文件待提交' --amend

    注意:上次commit提交错后,不能再执行任何操作,必须紧接着它执行我们上面的修改提交信息命令才行。

    7. 5. 1. 2 修正紧挨着的一次的提交与本次提交合并

    我们再修改b文件

    我们本想将a、b文件一起提交,结果只提交了a文件

    我们把b文件也加入暂存区,再修正合并上次提交

    我们可以补充记录!

    8. reset使用

    8. 1 git reset HEAD

      撤销我们提交最新的一次提交

    git reset HEAD^

    如果撤销最新的两次提交

    git reset HEAD^^

    如果撤销最新的三次提交

    git reset HEAD^^^

    git reset HEAD^

    可能有的编译器,会提示More ,是因为windows将其认为是换行符了,所有加上"…"即可

    解决:

    回归正题,看下日志

    提交内容

    撤销两次提交

    注意:该提交并未丢失,可以通过哈希找回。

    8. 1. 1 多条回退

    git reset HEAD~n n代表最近删除的条数

    8. 1. 2 git reset --hard (尽量避免使用)

    重置工作目录,丢失暂存: git reset --hard (尽量避免使用)

    修改了a.txt

    git reset HEAD^ --hard

    并且发现一个问题,对a.txt的修改没有了。

    因此尽量避免使用--hard,丢失的暂存,是不能找回的。

    8. 1. 3 git reset --soft(建议使用)

    git reset --soft

      保留工作目录,与原分支差异将放到暂存区

      撤销回去

      我们打开a.txt,也很容易发现,之前里写的内容,是不存在的,因为丢失的内容,是找不回的,因此建议尽量避免使用--hard。

    git reset HEAD^ --soft

    并且发现暂存区文件内容还在!因此它不会造成文件的丢失。

    8. 1. 4 git reset --mixed(默认)

    git reset --mixed(默认) 这是默认的,平时直接reset就是这种命令了。

    保留工作目录,并且清空暂存区

    8. 2 通过哈希找回历史记录

    git reset cc12a6c13af1f5b135f531617b0ce346bb8d46ca

    但是如果没有打印日志,不知道哈希,如何回退呢?

    8. 3 查看历史提交记录

    git reflog

    我们回到三次提交的日志。

    git reset 4180e8e

    9. reset与checkout本质

      可以用来撤销commit,但实质行为上并不是撤销操作,而是移动HEAD并且带上所指向的分支,重置HEAD及分支

      即在HEAD之后的提交,因为当前不在任何分支上,就不会出现在工作目录中,起到撤销效果。

    9. 1 reset过程分析

      假设进行c1、c2、c3次提交,从c3回退到c2,实际上就是HEAD带上master一块移动到c2,此时c3就不在任何分支上了。因此打印log,就看不到c3了。如果想找回的话,即可通过reset重置回c3,即HEAD带上master一块移动到c3。

    9. 2 checkout过程对比

      撤销除了reset,checkout也与它类似,但是两者也是不一样的,之前我们学习发现。checkout一般撤销的是对文件的修改,它前提是没有加入暂存区或者没有提交的内容。

      如果我们用checkout完成上述分析,从c3回退到c2,实际HEAD指向了c2,而master没有变化,打印log的时候,一切照旧。因此我们才用checkout切换分支,因为checkout不会偏移master(分支)指针。

      所以,签出指定commit,只会改变HEAD指向,并不会影响分支指向。

    (后续待补充)
    Processed: 0.012, SQL: 10