0
点赞
收藏
分享

微信扫一扫

【Flutter 面试题】什么是Widget,Stateful Widget和Stateless Widget之间的区别?

彩虹_bd07 03-16 11:31 阅读 1
git

前言:

本文记录学习使用 Git 版本管理工具的学习笔记,通过阅读参考链接中的博文和实际操作,快速的上手使用 Git 工具。

本文参考了引用链接博文里的内容。

引用:

Git使用教程-配置管理

git reset详解-CSDN博客

3、Git使用不完全指南:git/github/gitlab/gitee的区别,原理和常用命令总结_gitlab github gitee-CSDN博客

正文

1. Git的3棵树

在本地仓库中Git维护三棵树,这是Git的核心构架。这三棵树分别是:工作区域,暂存区域,和Git仓库。

  • 工作区域(Working Directory),就是你平时存放项目代码的地方
  • 暂存区域(Stage),用于临时存放你的改动,事实上它只是一个文件,保存即将提交的文件列表信息。
  • Git仓库(Repository),就是安全村行数据的位置,这里有你提交的所有版本的数据。其中,HEAD指向最新放入仓库的版本(这第3棵树,确切的说,应该是Git仓库中的HEAD指向的版本)。

Git的一般工作流程是:

  1. 在工作目录中添加,修改文件
  2. 将需要进行版本管理的文件放入暂存区
  3. 将暂存区的文件提交到Git仓库

因此,Git管理的文件有三种状态:已修改(modified),已暂存(staged),和已提交(commited),依次对应上面的每一个流程。

2. Git初始化一个仓库

###创建一个目录,这个目录将会作为git repository 仓库
dimon@dimon-VirtualBox:~$ mkdir gittest
###进入这个目录
dimon@dimon-VirtualBox:~$ cd gittest/

###执行'git init'命令初始化git项目,初始化成功之后会有一个隐藏的'.git'文件
dimon@dimon-VirtualBox:~/gittest$ git init
已初始化空的 Git 仓库于 /home/dimon/gittest/.git/

###
dimon@dimon-VirtualBox:~/gittest$ git add README.md
fatal: 路径规格 'README.md' 未匹配任何文件

###在当前目录里创建一个文件'README.md',md表示Markdown文件
dimon@dimon-VirtualBox:~/gittest$ touch README.md
###'git add'命令把文件加入暂存区
dimon@dimon-VirtualBox:~/gittest$ git add README.md

###'git commit'命令把文件提交到git仓库repository,'-m'后面是提交日志
dimon@dimon-VirtualBox:~/gittest$ git commit -m "add a readme file"
[master (根提交) d7c707d] add a readme file
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README.md
dimon@dimon-VirtualBox:~/gittest$ 

3. Git使用教程--状态

怎么知道哪些文件是新添加的,哪些文件已经加入到暂存区?总不能自己用文本记录下来吧?

当然不,作为通用的版本管理系统,我们遇到的问题,Git都已经有了解决方案,可以用 'gti status‘ 命令查看当前状态。

dimon@dimon-VirtualBox:~/gittest$ git status
On branch master
nothing to commit, working tree clean
dimon@dimon-VirtualBox:~/gittest$  

on branch master:我们位于一个叫做'master’的分支里,这个是默认的分支。

nothing to commit, working directory clean:说明你的工作目录当前是“干净的”,没有需要提交的文件(意思就是自上次提交之后工作目录中的内容压根就没有改动过)。

在工作目录里添加 LICNESE 文件,并用Notepad++修改文件'LICENSE'的内容。输入 'git status'命令,提示如下:

###在工作目录下创建了新文件'LICENSE'
dimon@dimon-VirtualBox:~/gittest$ touch LICENSE
dimon@dimon-VirtualBox:~/gittest$ ls
LICENSE  README.md

###编辑文件的内容
dimon@dimon-VirtualBox:~/gittest$ vi LICENSE
dimon@dimon-VirtualBox:~/gittest$ 

###'git status'命令查看文件的状态
dimon@dimon-VirtualBox:~/gittest$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)

	LICENSE

nothing added to commit but untracked files present (use "git add" to track)
dimon@dimon-VirtualBox:~/gittest$

Untracked files 说明存在未追踪文件(下面红色的那个)

所谓的“未追踪”文件,是指那些新添加的并且未被加入到暂存区域或者提交的文件。它们处于一个逍遥法外的状态,但你一旦将它们假如暂存区或提交到Git仓库,他们就开始受到Git的“跟踪”。

圆括号是的提示是 git 给用户的提示:使用 git add <file> 命令将待提交的文件添加到暂存区域。

dimon@dimon-VirtualBox:~/gittest$ git add LICENSE 
dimon@dimon-VirtualBox:~/gittest$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   LICENSE

dimon@dimon-VirtualBox:~/gittest$ 

‘use git reset HEAD <file>  to unstage’ 的意思是,如果你反悔了,你可以使用  git reset HEAD 命令恢复暂存区域。如果后面接文件名,表示恢复该文件;如果不接文件名,则表示上一次添加的文件。

再次添加到“暂存区域”,然后执行 'git commit -m "add a license file"'命令:

###把文件'LICENSE'加到暂存区
dimon@dimon-VirtualBox:~/gittest$ git add LICENSE

###查看当前文件状态,暂存区有文件未提交
dimon@dimon-VirtualBox:~/gittest$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   LICENSE


###把暂存区提交到Git 仓库
dimon@dimon-VirtualBox:~/gittest$ git commit -m "add a license file"
[master a588543] add a license file
 1 file changed, 6 insertions(+)
 create mode 100644 LICENSE

###查看当前文件状态
dimon@dimon-VirtualBox:~/gittest$ git status
On branch master
nothing to commit, working tree clean
dimon@dimon-VirtualBox:~/gittest$

  

关于修改

突然发现版权那块忘记写上自己名字了...

打卡LINCESE文件,修改"Copyrith (c) 2024 dimon",保存。

执行 git status 命令:

dimon@dimon-VirtualBox:~/gittest$ vi LICENSE 
dimon@dimon-VirtualBox:~/gittest$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   LICENSE

no changes added to commit (use "git add" and/or "git commit -a")
dimon@dimon-VirtualBox:~/gittest$ 

由于对工作目录中的文件进行了修改,导致这个文件和“暂存区域”的文件不匹配了,所以Git提了两条建议

  1. 使用 git add 将工作目录的新版本覆盖暂存区域的几版本,然后提交
  2. 使用 git checkout将暂存区域的旧版本覆盖工作目录的新版本(危险操作:相当于丢弃工作目录的修改)

还有一种情况没有分析,大家先把新版本文件覆盖掉暂存区域的旧版本:

dimon@dimon-VirtualBox:~/gittest$ git add LICENSE 
dimon@dimon-VirtualBox:~/gittest$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   LICENSE

dimon@dimon-VirtualBox:~/gittest$

然后我们打开LINCENSE文件,将 Dimon 修改为 Dimon.chen 

dimon@dimon-VirtualBox:~/gittest$ vi LICENSE 
dimon@dimon-VirtualBox:~/gittest$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   LICENSE (绿色)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   LICENSE (红色)

dimon@dimon-VirtualBox:~/gittest$ 

 这次的情况:被绿的LINCENSE文件存放在暂存区(待提交),同时红色的LICENSE说明文件还在工作目录等待添加到暂存区域。

这种情况你应该意识到这里存在两个不同版本的 LICENSE 文件,如果此时你直接执行了 commit 命令,那么提交的是暂存区域的版本,如果你希望提交工作目录的新版本,那么你先执行 add 米宁覆盖暂存区域,然后在提交。

一步到位

从工作目录一步添加到Git仓库: git commit -am "说明"

dimon@dimon-VirtualBox:~/gittest$ git commit -am "change the license file"
[master 1657372] change the license file
 1 file changed, 1 insertion(+), 1 deletion(-)
dimon@dimon-VirtualBox:~/gittest$ 

-a的已是是add。

git log 查看历史操作记录

3. Git使用教程5

 有关回退的命令有两个: reset 和 checkout

先执行Git log命令,将此事的Git仓库可视化

三棵树的情况

回滚快照

注:快照即提交的版本,每一个版本我们称之为一个快照。

现在我们利用 reset 命令回滚快照,帮看看Git仓库和三棵树分别发生了什么。

执行: git reset HEAD ~ 命令:

主: HEAD 表示最新提交的快照,而 HEAD ~表示HEAD的上一个快照,HEAD~~表示上上个快照。如果表示10个快照可以使用 HEAD~10 

###现在'git log'能看到3个版本,HEAD指向第3次提交
dimon@dimon-VirtualBox:~/gittest$ git log
commit 1657372baaca2c3c797d3e2f1676b087810e655b (HEAD -> master)
Author: dimon <1181302388@qq.com>
Date:   Fri Mar 15 10:48:34 2024 +0800

    change the license file

commit a588543db607cffd7ec6d2a6504175639d8ed61b
Author: dimon <1181302388@qq.com>
Date:   Fri Mar 15 10:13:20 2024 +0800

    add a license file

commit d7c707d2c4b2dc4c332e252c419f47c4eabc4846
Author: dimon <1181302388@qq.com>
Date:   Thu Mar 14 18:21:33 2024 +0800

    add a readme file
dimon@dimon-VirtualBox:~/gittest$ git reset HEAD~
Unstaged changes after reset:
M	LICENSE
dimon@dimon-VirtualBox:~/gittest$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   LICENSE

no changes added to commit (use "git add" and/or "git commit -a")


###现在'git log'能看到2个版本,HEAD指向第2次提交
dimon@dimon-VirtualBox:~/gittest$ git log
commit a588543db607cffd7ec6d2a6504175639d8ed61b (HEAD -> master)
Author: dimon <1181302388@qq.com>
Date:   Fri Mar 15 10:13:20 2024 +0800

    add a license file

commit d7c707d2c4b2dc4c332e252c419f47c4eabc4846
Author: dimon <1181302388@qq.com>
Date:   Thu Mar 14 18:21:33 2024 +0800

    add a readme file
dimon@dimon-VirtualBox:~/gittest$

此时我们回滚到第二课树(暂存区域)

 

第一次执行reset后的Git仓库

git reset HEAD~ 命令其实是 git rest --mixed HEAD~ 的缩写,--mixed选型是默认的。

git reset HEAD~ 命令其实影响了两棵树:首先是移动 HEAD 的指向,将其指向上一个快照(HEAD~);然后再讲该位置的快照回滚到暂存区域。

--soft 选项

git reset --soft HEAD~ 命令就相当于只移动 HEAD 的指向,但并不会将快照回滚到暂存区。相当于撤销了上一次的提交(commit)。以不小心提交了,后悔了,那么你就执行 git reset --soft HEAD~ 命令(此时执行命令 git log 命令,也不会再看到已经撤销的那个提交)。

--hard选项

reset不仅移动HEAD的指向,将快照回滚到暂存区,它还将暂存区的文件还原到工作目录。

回滚指定快照

reset 不仅可以回滚指定快照,可以可以回滚个别文件

命令格式: git reset 快照 文件名/路径

这样,它就会忽略移动HEAD指向这一步(因为你知识回滚快照的部分内容,并不是整个快照,所以HEAD的指向不应发生改变),直接将指定快照的指定文件回滚到暂存区域。

不仅可以往回滚,还可以往前滚。

这里需要强调的是: reset 不仅是一个“复古”的命令,它不仅可以回到过去,还可以到“未来”。

唯一的前提条件是:你需要指导指定快照的ID号。

哪如果不小心把命令窗口关了不记得ID号怎么办?

命令: git reflog

Git揭露的每一次操作的版本号ID。

4. Git使用教程6--版本对比

目的:对比版本之间有哪些不同。

准备工作

创建一个叫做MyProject2的新文件作为此次演示的目录,初始化Git。

创建一个game.py的文件,将下面代码拷贝进去。

再新建一个README文件,写清楚这是第一个课后作业。

执行 git add README game.py 命令将文件添加到暂存区,紧着执行 git commit -m '猜数字游戏' 提交一个项目快照。

dimon@dimon-VirtualBox:~/MyProject2$ git init
Initialized empty Git repository in /home/dimon/MyProject2/.git/
dimon@dimon-VirtualBox:~/MyProject2$ touch game.py
dimon@dimon-VirtualBox:~/MyProject2$ vi game.py
dimon@dimon-VirtualBox:~/MyProject2$ touch README
dimon@dimon-VirtualBox:~/MyProject2$ vi README
dimon@dimon-VirtualBox:~/MyProject2$ git add README game.py 
dimon@dimon-VirtualBox:~/MyProject2$ git commit -m "猜数字游戏"
[master (root-commit) c1df484] 猜数字游戏
 2 files changed, 22 insertions(+)
 create mode 100644 README
 create mode 100644 game.py
dimon@dimon-VirtualBox:~/MyProject2$ vi game.py 
dimon@dimon-VirtualBox:~/MyProject2$ vi README 
dimon@dimon-VirtualBox:~/MyProject2$ git diff

然后修改 game.py 文件内容化和 README文件内容。

比较暂存区域域工作目录的差异:

直接执行 git diff 命令是比较暂存区域与工作目录的文件内容。

现在来解释一下上面每一行的含义:

第一行: diff --git a/README b/README

表示对比的存放在暂存区域的README和工作目录的README

第二行: index 2146df9..7d37b6e 100644

表示对应的文件ID分别是2146df9 和7d37b6e,左边暂存区域与,右边当前目录。最后的100644是指定文件的类型和权限。

第三行:--- a/README

---表示的是就文件(存放在暂存区域)
第四行:+++ b/README

+++表示该文件是新文件(存放在工作区域)

第五行:@@ -1 +1,2 @@

以@@开头和结束,总监的-表示旧文件,+表示新文件,后面的数字表示开始行号,显示行数。

第6,7行: 

home work 2024-03-15 11:37
+《零基础入门学习Git》

这是将两个文件合并显示的结果,前面有+的绿色一行说明是新文件所独有的,浅灰色的说明是两个文件共享的。所有,+1,2 表示线文件合并显示中从第一行开始,显示2行内容。那为啥-1后面没有显示行数?因为在合并显示结果中,旧文件已经完全包含在新文件中了(也就是旧文件没有自己的“独有”内容)。

最后的(:)是什么?

意思是窗口太小,没有办法完全显示,正在等待命令(Vim编程知识)

移动命令:

  • j,k:向下/向上一行
  • f,b:向下翻页/向上翻页
  • d,u:向下翻半页/向上翻半页

跳转命令

g, G:跳转到第一行/跳转到最后一行

搜索命令

输入反斜杠(/)或问号(?),后面搜索关键字

区别:斜杠(/)表示从当前位置向下搜索,问号(?)表示从当前位置向上搜索

接着输入n表示顺着当前的搜索方向快速调到下一个匹配位置,大写的N则是与当前搜索方向相反。

退出和帮助

在点点(:)后面输入q,表示退出diff;输入h表示进入帮助页面,你会看看到很多命令和功能,输入q可以退出帮助页面。

比较两个历史快照

我们执行命令 git commit -am "添加功能:玩家只有三次机会”命令,添加并提交目录中的所有文件。执行git log命令,可以看到Git仓库中已经有连个快照了。

###查看当前'git status'状态
dimon@dimon-VirtualBox:~/MyProject2$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   README
	modified:   game.py

no changes added to commit (use "git add" and/or "git commit -a")


###‘git commit -am’ 一次性提交工作目录到暂存目录和Git仓库
dimon@dimon-VirtualBox:~/MyProject2$ git commit -am "添加功能:玩家只有三次机会"
[master 7e3a972] 添加功能:玩家只有三次机会
 2 files changed, 9 insertions(+), 4 deletions(-)
dimon@dimon-VirtualBox:~/MyProject2$

###‘git log’查看当前Git仓库快照,当前有两个快照
dimon@dimon-VirtualBox:~/MyProject2$ git log
commit 7e3a9725b0e348a938153d37b6450eb74eb5febb (HEAD -> master)
Author: dimon <1181302388@qq.com>
Date:   Fri Mar 15 14:37:26 2024 +0800

    添加功能:玩家只有三次机会

commit c1df484caeee134d604a08e6957b28fb836c1ea3
Author: dimon <1181302388@qq.com>
Date:   Fri Mar 15 11:38:14 2024 +0800

    猜数字游戏
dimon@dimon-VirtualBox:~/MyProject2$ 

执行命令 git diff 7e3a972 c1df484 命令,既可以比较Git仓库中两个快照的差异

 git diff 7e3a9725b0e348a938153d37b6450eb74eb5febb   c1df484caeee134d604a08e6957b28fb836c1ea3

比较当前工作目录和Git仓库中的快照

我们稍微改动一下README的内容

目前我们的Git仓库应该是

三棵树应该是

比较之前版本和快照与当前工作目录的内容

输入: git diff ed3708c 命令即可

比较当前版本库快照与当前工作目录的内容,

输入: git diff HEAD 命令即可

比较Git仓库与暂存区域

执行 git add README.md命令,将第三版的README文件添加到暂存区域。

然后三棵树就是这样的了:

如果希望比较最新提交的快照和暂存区域的文件,只需要执行命令 diff --cached 命令;当前艳也可以指定其他快照,就是需要多协商一个ID值,即 git diff --cached ID号。

哈哈,感觉有点乱,实际上就是这三棵树之间相互比较,最后附上一个总结图片。

 

5. Git使用教程7--修改最后一次提交,删除文件和重命名文件

问题出现

Situation one: 版本一提交(commit)到仓库,突然想起漏掉了两个文件还没有添加(add)

Situation two: 版本一提交(commit)到仓库,突然兴起版本说明写的不够全面,无法彰显你本次修改的重大意义....

由于使用 reset 命令过于繁琐,需要提交一个新的版本,这里可以使用带 --amend 选项的 commit 命令(即 git commit -amend) Git 会“更正”最近一次的提交。由于这里没有-m说明,会进入一下页面。

这个编辑界面知识让你编辑提交说明而已。如果不需要修改,可以连续按两次大写Z来退出,或者先按下(:),再输入q!退出,Git会保留旧的提交说明。如果需要提交说明又不想出现这么繁琐的方式,输入 git commit --amend -m "新的提交说明"就可以。

删除文件

问题1:不小心删除文件怎么办?

现在从工作目录总手动删除 README 文件,然后执行 git status命令:

提醒使用 checkout 命令可以将暂存区域的文件恢复到工作目录:

dimon@dimon-VirtualBox:~/MyProject2$ git checkout -- README
dimon@dimon-VirtualBox:~/MyProject2$

注意 "--"两端各有一个空格。

问题2:如何彻底删除一个文件哪?

假如不小心把小黄图下载到工作目录,然后又不小心提交到了Git仓库。

dimon@dimon-VirtualBox:~/MyProject2$ touch yellow.jpg
dimon@dimon-VirtualBox:~/MyProject2$ git add yellow.jpg
dimon@dimon-VirtualBox:~/MyProject2$ git commit -m "有一次伟大的改进"
[master eeba2c4] 有一次伟大的改进
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 yellow.jpg
dimon@dimon-VirtualBox:~/MyProject2$ 

执行 git rm yellow.jpg 命令

dimon@dimon-VirtualBox:~/MyProject2$ git rm yellow.jpg 
rm 'yellow.jpg'
dimon@dimon-VirtualBox:~/MyProject2$

此时工作目录中的小黄图(yellow.jpg)已经被删除了...

但是执行 git status 命令,你仍然发现Git还不肯松手

dimon@dimon-VirtualBox:~/MyProject2$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	deleted:    yellow.jpg

dimon@dimon-VirtualBox:~/MyProject2$

意思说它在仓库快照里发现有一个 'yellow.jpg'的文件,但似乎在暂存区域和当前工作目录不见了。

此时可以执行 git reset -- soft HEAD~ 命令将快照回滚到上一个位置,然后重新提交,Git就不会再提小黄图的事了。

dimon@dimon-VirtualBox:~/MyProject2$ git reset --soft HEAD~
dimon@dimon-VirtualBox:~/MyProject2$ git status
On branch master
nothing to commit, working tree clean
dimon@dimon-VirtualBox:~/MyProject2$ 

注意:rm命令删除的只是工作目录和暂存区的文件(即取消跟踪,下一次提交是不纳入版本管理)

问题3:我在工作目录里中增加了一个 test.py 文件,然后执行 git add test.py 命令将其加入到暂存区,此时我修改了test.py文件的内容,那么暂存区和工作目录就是两个不同的test.py文件了,此时如果我执行 git rm test.py 命令,Git会下意识的阻止我,这怎么办?

dimon@dimon-VirtualBox:~/MyProject2$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   test.py

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   test.py

dimon@dimon-VirtualBox:~/MyProject2$ 
dimon@dimon-VirtualBox:~/MyProject2$ git rm test.py
error: the following file has staged content different from both the
file and the HEAD:
    test.py
(use -f to force removal)
dimon@dimon-VirtualBox:~/MyProject2$

因为两个不同内容的同名文件,谁知道你是不是搞清楚了都要删除?还是提醒一下好,别等一下出错又要赖机器。。。

根据提示,执行 git rm -rf test.py 命令就可以把两个都是删除

问题4:我只想删除暂存区域的文件,保留工作目录,应该怎样操作?

执行 git rm --cached “文件名” 命令。

重命名文件

直接在工作目录重命名文件,执行 git status 会出错

正确的姿势应该是:

git mv 旧文件名 新文件名

dimon@dimon-VirtualBox:~/MyProject2$ git mv test.py TEST.py
dimon@dimon-VirtualBox:~/MyProject2$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	renamed:    test.py -> TEST.py

dimon@dimon-VirtualBox:~/MyProject2$ git commit -m 'rename test.py to TEST.py'

教程彩蛋6:

如何让Git识别某些格式的文件,然后自动不跟踪他们?

比如工作目录里有三个文件 1.temp, 2.temp, 3.temp ,我们不希望后缀名为 .temp 的文件被跟踪,可是每次 git status 都会出现

6. Git使用教程7--创建和切换分支

分支是什么?

假设你的大项目已经上线了(有上百万人在使用),过了一段时间及突然觉得应该添加一些新功能,但是为了保险起见,你肯定不能再当前项目上直接开发,这时候你就有创建分支的必要了。

对比其他版本控制系统而言,创建分支常常需要创建一个源代码目录的副本,项目越大,耗费的时间就越多;而Git由于每一个节点都已经是一个完整的项目,所以只需要创建多一个“指针”(像master)指向分支开始的位置即可。

创建分支

来到之前创建的项目MyProject2,

当前项目状态如下

执行Git status查看状态

可以看到README文件被修改并添加到暂存区域(还没有提交),所以当前三棵树应该是这样:

创建分支,使用 “git branch 分支名” 命令:

dimon@dimon-VirtualBox:~/MyProject2$ git branch feature
dimon@dimon-VirtualBox:~/MyProject2$ 

没有任何提示说明分支创建成功(一般也不会失败,除非创建了同名的分支会提醒你一下),此时执行 git log --decorate 命令查看:

如果希望以“精简版”的方式显示,可以加上一个 --oneline 选项(即 git log --decorate --oneline),这样就只用一行来显示快照记录。

可以看到最新的快照后面多了一个(HEAD->master,fature)

它的意思是:目前有两个分支,一个是主分支(master),一个是我们刚才创建的新分支(feature),然后HEAD指针仍然指向默认的master分支。

目前仓库中的快照应该是这样的。

切换分支

现在我们需要将工作目录环境切换到新创建的分支(feature)上,使用的是我们之前语言又止的checkout命令。执行 git checkout feature 命令:

dimon@dimon-VirtualBox:~/MyProject2$ git checkout feature
M	README
Switched to branch 'feature'
dimon@dimon-VirtualBox:~/MyProject2$

这样HEAD指针就指向了 feature 分支了:

dimon@dimon-VirtualBox:~/MyProject2$ git log --decorate --oneline
d97db41 (HEAD -> feature, master) rename test.py to TEST.py
4bd1779 add faile test.py
67d158e 添加功能:玩家只有三次机会
c1df484 猜数字游戏
dimon@dimon-VirtualBox:~/MyProject2$ 

现在我们再进行一次提交(暂存缓冲区还有一个更改的文件没有提交呢):

dimon@dimon-VirtualBox:~/MyProject2$ git commit -m "修改了说明文件"
[feature d158dfb] 修改了说明文件
 1 file changed, 1 insertion(+)
dimon@dimon-VirtualBox:~/MyProject2$ 

现在仓库中的快照应该是这个样子(提交的快照由当前HEAD指针指向的分支来管理)

 

 然后我们再讲 HEAD 指针切回 master 分支

dimon@dimon-VirtualBox:~/MyProject2$ git checkout master
Switched to branch 'master'
dimon@dimon-VirtualBox:~/MyProject2$

细心的朋友会发现上一次对 README 文件的修改已经当然无存了,这是因为我们工作目录已经回到了 master 分支的状态。

现在对 README 文件做修改(随意修改),然后执行 git commit -m "再次修改说明文件":

dimon@dimon-VirtualBox:~/MyProject2$ git commit -am "再次修改说明文件"
[master 756c48b] 再次修改说明文件
 1 file changed, 1 insertion(+)
dimon@dimon-VirtualBox:~/MyProject2$ 

目前仓库快照变成了这样

执行 git log --oneline --decorate --graph --all 命令

--graph 选项表示让 Git 绘制分支图,--all 表示显示所有分支

 7. Git使用教程9-合并和删除分支

合并分支

当一个子分支的使命完成后,它就应该回归到主分支中去。

合并分支我们使用 merge 命令,执行 git merge feature 命令,将 feature 分支合并到 HEAD 所在的分支(master)上:

dimon@dimon-VirtualBox:~/MyProject2$ git merge feature
Auto-merging README
CONFLICT (content): Merge conflict in README
Automatic merge failed; fix conflicts and then commit the result.
dimon@dimon-VirtualBox:~/MyProject2$ 

从Git提示的内容来看,我们知道这次合并并没有成功,Git提示:

合并 README 时出现了冲突。

所以自动合并失败;请修改冲突的内容请从新提交快照。

意思是说现在你需要先解决冲突的问题,Git才能进行合并操作。所谓冲突,无非就是像两个分支中存在同名但内容却不相同的问价,Git不知道你要舍弃哪一个或者保留哪一个,所以需要你自己来决定。

此时执行 git status 命令也会显示需要你解决冲突:

然后Git会在有冲突的文件中加一些标记,可以打开 README 文件查看一下:

以 ‘=====’为界,上到"<<< HEAD"表示当前分支,下到">>> fature"表示 待合并的 feature 分支,之间的内容就是冲突的地方。

现在我们将README 同意修改掉(去掉 <<<< HEAD 等内容)

保存文件,然后提交快照

dimon@dimon-VirtualBox:~/MyProject2$ git add README
dimon@dimon-VirtualBox:~/MyProject2$ git commit -m '解决冲突'
[master 90086a5] 解决冲突
dimon@dimon-VirtualBox:~/MyProject2$ 

执行 git log --decorate --all --graph --oneline 命令,可以看到此时分支已经自动合并了

 

当然,如果不存在冲突,就不用搞这么多了... ,举个例子:

执行: git checkout -b feature2 命令,(相当于 git branch feature2 和 git checkout feature2 两个命令的合体)

dimon@dimon-VirtualBox:~/MyProject2$ git branch feature2
dimon@dimon-VirtualBox:~/MyProject2$ git checkout feature2
Switched to branch 'feature2'
dimon@dimon-VirtualBox:~/MyProject2$ 

在工作目录随便创建一个文件 feature2.txt 并提交快照。

dimon@dimon-VirtualBox:~/MyProject2$ git add feature2.txt 
dimon@dimon-VirtualBox:~/MyProject2$ git commit -m "我就是试试"
[feature2 11c5b05] 我就是试试
 1 file changed, 1 insertion(+)
 create mode 100644 feature2.txt
dimon@dimon-VirtualBox:~/MyProject2$

执行 git log --decorate --oneline --graph --all 命令: 

可以看到, feature 分支比master分支快了一步。现在我们切换回 master 分支,并将 feature2 分支合并进来:

###当前工作目录切换到 master 分支
dimon@dimon-VirtualBox:~/MyProject2$ git checkout master
Switched to branch 'master'
dimon@dimon-VirtualBox:~/MyProject2$ 

###'git merge'合并 feature2 分支到 master 分支
dimon@dimon-VirtualBox:~/MyProject2$ git merge fature2
merge: fature2 - not something we can merge
dimon@dimon-VirtualBox:~/MyProject2$ git merge feature2
Updating 90086a5..11c5b05
Fast-forward
 feature2.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 feature2.txt
dimon@dimon-VirtualBox:~/MyProject2$ 

这次 git 只显示了 fast-forward (快进)这个词,这是因为 feature2 这个分支的父节点是 master 分支,所以 git 只需要简单的而移动 master 的指向就可以。

执行 git log --decorate --all --graph --oneline 命令:

删除分支,使用 git branch -d "分支名" 命令:

dimon@dimon-VirtualBox:~/MyProject2$ git branch -d feature
Deleted branch feature (was d158dfb).
dimon@dimon-VirtualBox:~/MyProject2$

执行 git log --decorate --all --graph --oneline 命令:

用于Git的分支原理实际上只是通过一个指针记载,所以创建和删除分支都几乎是瞬间完成。

注意:如果试图删除为合并的分支,Git会提示你“该分支未完全合并,如果你确定要删除,请使用 git branch -D 分支名”命令。

彩蛋:Git的两种合并方式--Fast-forward和Three-way-merge

Fast-forward

所谓的 Fast-forward 就是当待合并的分支位于目标分支的直接上游时,Git只需要把目标分支的指针直接移动既可以实现合并。

如下图 master 分支就是位于 feature2 分支的直接下游:

将 fearture2 分支合并到 master 分支,只需要移动 master 分支即可。

Three way Merge

如果待合并的两个分支不在同一条线上,那么进行合并就需要解决一个根本的问题--冲突!

为何两个分支在同一条线上就不会出现冲突?

因为Git的快照是按时间顺序提交的,所以在同一条时间线上的两个快照,他们是有先后顺序,尽管两者可能出现同名文件不同内容,Git会认贼这是“改变”而不是“冲突”。

举个例子:

合并 C3 和 C4 得到C5,但C5应该如何处理冲突哪?

SVN会把问题抛给用户,让用户自行解决;Git则显得更为高明,它会找到第三个快照,然后综合三者特点自动解决冲突。

那第三个亏按照应该如何决定哪?

没错,应该找两者的共同“祖先”作为参照物,一比较就知道两个分支都干了什么?

图片中C3, C4的共同祖先是C1,可以看到C3和C4分别增加了 test2.py 和 test1.py 两个文件。因对比之后发现三者并没有冲突,所以C5应该是三者的合体,集同事拥有 comm.py test1.py 和 test2.py 三个文件。

另外,值得一提的是,Git的这种合并方式也适用于同名文件的不同更改。

举个例子:

这里C3和C4都只有一个文件 test.txt ,但是内容却不一样。如果这样合并,你猜Git会不会报“冲突”?

答案是不会的!

因为 Git 找到了它们的共同祖先 C1,可以看到C3 和 C4 都是在 C1 的基础上机型添加(C4在第二行添加了"I",C3在第四行添加了"FishC",C1的第三行“Love”是他们共同拥有的),同时在每一行并没有产生冲突的地方,所以Git会自动合并的C5是这样的。

#test.txt
I
Love
FishC

注意:如果Git检测到同一行有不同的内容,还会报冲突并让你自行决定去谁留谁的。

8. Git使用教程10--匿名分支和chekout命令

再论checkout

事实上,checkout 命令有两种功能。

  1. 从历史快照(或暂存区域)中拷贝文件到工作目录
  2. 切换分支
从历史快照(或暂存区)中拷贝文件到工作目录

当给定某个文件名时,Git会从指定的提交中拷贝文件到暂存区域和工作目录。比如执行 git checkout HEAD~ README 命令会将上一个快照中的 README 文件复制到工作目录和暂存区域中。

如果命令中没有指定具体的快照ID,将从暂存区域恢复指定文件到工作目录(git checkout README)

有些朋友会问:“上一次看你在文件前面有加两个横杠 -- ,这次怎么就没有了呢?”

问题的好?Git提醒你写成 git checkout -- README 的形式,那是为了预防你恰好有一个分支叫做 REDME,那么它就搞不懂你要恢复文件还是要切换分支了,所以约定两个横杠(--)后面跟的是文件名。

反过来说,如果你确保你没有一个叫做 README 的分支,你直接写 git checkout README 也是妥妥没有问题的。

切换分支

首先我们知道 Git 的分支其实就是添加一个指向快照的指针,其次我们知道切换分支除了修改 HEAD 指针的的指向,还会改变暂存区域和工作目录的内容。

所以执行 git chekout 373c0 命令,Git 主要做了下面两件事(当然事实上Git还做了更多)

那回过头来 ,如果我们只想恢复指定的文件/路径,那么我们只需要指定具体的文件,Git就会忽略第一步修改HEAD指向的操作,这不正是根之前讲的reset命令一致的么?

checkout 命令和 reset 命令的区别
恢复文件

下面开始划重点:

它们的区别是 reset 命令只将指定文件恢复到暂存区域(--mixed),而 checkout 命令同时覆盖暂存区域和工作目录。

注意:也许你师徒使用 git rest --hard HEAD~ README 命令让 reset 同时覆盖工作目录,但Git会告诉你这是徒劳的(此时 reset 不允许使用 --sort 或 hard 选项)

这样看来,在恢复文件方面, reset 命令要比 chekout 命令更安全一些。

恢复快照

reset 命令是用来“回到过去”的,根据选项的不同,reset命令将移动 HEAD 指针(--soft)-> 覆盖暂存区域(--mixed,默认)->覆盖工作目录(--hard)。

checkout 命令虽说是用于切换分支,但前面你也看到了,它事实上也是通过移动 HEAD 指针和覆盖暂存区域,工作目录来实现的。

哪问题来了:他们有什么区别哪?

下面开始haul重点了:

  • 第一个区别是,对于 reset --hard 命令来说,checkout命令更安全。因为 Chekout命令在切换分支前会先检查一下当前工作状态,如果不是'clean'的话,Git不会允许你这样做;而 'reset --hard'命令则是直接覆盖掉所有数据。
  • 另一区别是如何更新 HEAD 的指向,reset 命令会移动 HEAD 所在的分支指向,而checkout命令只会移动HEAD自身来指向另外一个分支。

看到文字你肯定懵,我们举例说明:

举报

相关推荐

0 条评论