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 file1 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)LICENSEnothing 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:   LICENSEdimon@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 file1 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:   LICENSEno 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:   LICENSEdimon@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 file1 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 +0800change the license filecommit a588543db607cffd7ec6d2a6504175639d8ed61b
Author: dimon <1181302388@qq.com>
Date:   Fri Mar 15 10:13:20 2024 +0800add a license filecommit d7c707d2c4b2dc4c332e252c419f47c4eabc4846
Author: dimon <1181302388@qq.com>
Date:   Thu Mar 14 18:21:33 2024 +0800add 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:   LICENSEno 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 +0800add a license filecommit d7c707d2c4b2dc4c332e252c419f47c4eabc4846
Author: dimon <1181302388@qq.com>
Date:   Thu Mar 14 18:21:33 2024 +0800add 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 READMEcreate 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:   READMEmodified:   game.pyno 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.jpgdimon@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.pyChanges 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.pydimon@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.pydimon@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-forwardfeature2.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自身来指向另外一个分支。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/758676.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二维数组应用案例

大家好&#xff1a; 衷心希望各位点赞。 您的问题请留在评论区&#xff0c;我会及时回答。 考试成绩统计 案例描述&#xff1a;有三名同学&#xff08;张三、李四、王五&#xff09;&#xff0c;在一次考试中成绩分别如下表&#xff0c;请分别输出三名同学的总成绩。 成绩表 语…

全面整理!机器学习常用的回归预测模型(表格数据)

文章目录 一、前言二、线性模型三、非线性模型 &#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 一、前言 回归预测建模的核心是学习输入 X X X 到输出 y y y &#xff08;其中 y y y 是连续值向量&#xff09;的映射关系。条件期望 E ( Y ∣ X x…

直播预约丨《袋鼠云大数据实操指南》No.1:从理论到实践,离线开发全流程解析

近年来&#xff0c;新质生产力、数据要素及数据资产入表等新兴概念犹如一股强劲的浪潮&#xff0c;持续冲击并革新着企业数字化转型的观念视野&#xff0c;昭示着一个以数据为核心驱动力的新时代正稳步启幕。 面对这些引领经济转型的新兴概念&#xff0c;为了更好地服务于客户…

c/c++ 深拷贝和浅拷贝

深拷贝与浅拷贝 深拷贝&#xff08;Deep Copy&#xff09;和浅拷贝&#xff08;Shallow Copy&#xff09;是对象复制的两种不同方式&#xff0c;它们涉及到对象成员数据的复制方式和内存管理。 浅拷贝&#xff08;Shallow Copy&#xff09;&#xff1a; 浅拷贝是指将一个对象的…

C++:继承:面向对象编程的重要特性

(❁◡❁)(●◡●)╰(*▽*)╯(*/ω&#xff3c;*)(^///^)(❁◡❁)(❁◡❁)(●◡●)╰(*▽*)╯(*/ω&#xff3c;*)(❁◡❁)(●’◡’●)╰(▽)╯(/ω&#xff3c;)(///) C&#xff1a;继承&#xff1a;面向对象编程的重要特性 前言**继承**1.继承的概念及定义1.1继承的概念1.2继…

算法笔记p251队列循环队列

目录 队列循环队列循环队列的定义初始化判空判满入队出队获取队列内元素的个数取队首元素取队尾元素 队列 队列是一种先进先出的数据结构&#xff0c;总是从队尾加入元素&#xff0c;从队首移除元素&#xff0c;满足先进先出的原则。队列的常用操作包括获取队列内元素的个数&a…

【Godot4.2】颜色完全使用手册

概述 本篇简单汇总Godot中的颜色的构造和使用&#xff0c;内容包括了&#xff1a; RGB、RGBA&#xff0c;HSV以及HTML16进制颜色值、颜色常量等形式构造颜色颜色的运算以及取反、插值用类型化数组、紧缩数组或PNG图片形式存储多个颜色 构造颜色 因为颜色是一种视觉元素&…

Jmeter接口测试步骤

一、使用工具测试 1、使用Jmeter对接口测试 首先我们说一下为什么用Posman测试后我们还要用Jmeter做接口测试&#xff0c;在用posman测试时候会发现的是一个接口一个接口的测试&#xff0c;我们每次测试成功后的数据&#xff0c;在工具中是无法保存的&#xff0c;再次测试的时…

【蓝桥杯入门记录】继电器、蜂鸣器及原理图分析

一、继电器、继电器概述 &#xff08;1&#xff09;蜂鸣器原理 蜂鸣器的发声原理由振动装置和谐振装置组成&#xff0c;而蜂鸣器又分为无源他激型与有源自激型&#xff0c;蜂鸣器的发声原理为: 1、无源他激型蜂鸣器的工作发声原理是&#xff1a;方波信号输入谐振装置转换为声…

Vue.js开发基础

单文件组件 使用Vite创建Vue项目后&#xff0c;目录结构中包含一些扩展名为.vue的文件&#xff0c;每个.vue文件都可用来定义一个单文件组件。Vue中的单文件组件是Vue组件的文件格式。每个单文件组件由模板、样式和逻辑3个部分构成。 运行结果&#xff1a; 1.模板 模板用于搭建…

PyTorch 深度学习(GPT 重译)(一)

第一部分&#xff1a;PyTorch 核心 欢迎来到本书的第一部分。在这里&#xff0c;我们将与 PyTorch 迈出第一步&#xff0c;获得理解其结构和解决 PyTorch 项目机制所需的基本技能。 在第一章中&#xff0c;我们将首次接触 PyTorch&#xff0c;了解它是什么&#xff0c;解决了…

爬虫基础:HTTP基本原理

爬虫基础&#xff1a;HTTP基本原理 前言HTTP基本原理URI 和 URLHTTP 和 HTTPSHTTP 请求过程请求与响应HTTP请求HTTP响应请求与响应的交互过程 HTTP 2.0二进制传输多路复用Header压缩服务器端提前响应内容安全 前言 了解 HTTP的基本原理&#xff0c;了解从往测览器中输人 URL到获…

算法沉淀——贪心算法四(leetcode真题剖析)

算法沉淀——贪心算法四 01.最长回文串02.增减字符串匹配03.分发饼干04.最优除法 01.最长回文串 题目链接&#xff1a;https://leetcode.cn/problems/longest-palindrome/ 给定一个包含大写字母和小写字母的字符串 s &#xff0c;返回 通过这些字母构造成的 最长的回文串 。 …

YOLOV5 改进:修改网络结构--C2f 模块

1、前言 YOLOV5 采用C3模块,类似于残差结构的思想 class C3(nn.Module):# CSP Bottleneck with 3 convolutionsdef __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansionsuper().__init__()c_ = int(c2 * e) #…

Linux中,运行程序,顺便将打印信息存储在Log文件中查看

前言 如题&#xff0c;原本打算在代码中自己写一个类去管理将打印信息收集到log日志中&#xff0c;忽然想到&#xff0c;其实也可以写sh脚本 简单demo1 #!/bin/bash# 启动应用程序 test&#xff0c;并将标准输出和标准错误输出都追加到 log 文件中 ./test >> output.log…

7-7 12-24小时制

题目链接&#xff1a;7-7 12-24小时制 一. 题目 1. 题目 2. 输入输出格式 3. 输入输出样例 4. 限制 二、代码 1. 代码实现 #include <stdio.h>int main(void) {int hour, minute;char *str;if (scanf("%d:%d", &hour, &minute) ! 2) {return -1;}i…

操作系统系列学习——死锁处理

文章目录 前言死锁处理 前言 一个本硕双非的小菜鸡&#xff0c;备战24年秋招&#xff0c;计划学习操作系统并完成6.0S81&#xff0c;加油&#xff01; 本文总结自B站【哈工大】操作系统 李治军&#xff08;全32讲&#xff09; 老师课程讲的非常好&#xff0c;感谢 【哈工大】操…

如何优惠申请DigiCert证书

DigiCert作为全球知名的数字证书颁发机构&#xff0c;其SSL证书以高度的安全性和信任度广受认可。而JoySSL作为国内优秀的SSL证书服务平台&#xff0c;提供了便捷、高效的证书申请服务&#xff0c;让您能够轻松获取并安装DigiCert SSL证书。接下来&#xff0c;本文将详细介绍如…

什么情况用@RequestBody、@RequestParm、@PathVariable

1.requestParam(请求参数&#xff09;&#xff1a;使用RequestParam注释将请求参数绑定到控制器中的方法参数。用于从请求访问查询参数值的RequestParam注释。 如下请求URL&#xff1a;http://localhost:8080/springmvc/hello/101?param110&param220 以下是RequestParam注…

腾讯云服务器怎么买省钱?先领券,再下单!

腾讯云代金券领取渠道有哪些&#xff1f;腾讯云官网可以领取、官方媒体账号可以领取代金券、完成任务可以领取代金券&#xff0c;大家也可以在腾讯云百科蹲守代金券&#xff0c;因为腾讯云代金券领取渠道比较分散&#xff0c;腾讯云百科txybk.com专注汇总优惠代金券领取页面&am…