vscode中的git插件将git操作从git指令简化到简单的图形界面操作,不用再去记忆git指令,操作简单直观了很多。第一次使用时,为了加深理解,我将一些基本操作和该操作底层使用的命令结合起来,并包含实例,方便学习,也希望能帮助到初学者。
0.配置
在完成git的下载和安装后,一定要设置用户名称和email地址。这是非常重要的,因为每次Git提交都会使用该用户信息。如果没有配置信息,在使用vscode调动git进行commit时会出现这样的弹窗:
基本配置: 任意文件夹下打开Git Bash,或者打开任意终端,使用以下指令设置用户信息:
git config --global user.name "name"git config --global user.email "xxx@xxx.cn"
查看配置信息:
git config --global user.namegit config --global user.email
1.获取本地仓库、查看状态
1.1 获取本地仓库
【vscode中的操作】
打开需要进行版本管理的项目文件夹(即将创建本地git仓库的地方),找到git插件(源代码管理),点击open repository,如果该文件夹下还没有本地仓库,则会初始化一个仓库;如果之前已经创建过仓库了,那么vscode会引导用户打开已有的仓库。
【对应的git指令】
以上的操作相当于:在该文件夹下,进入终端(可以是git bash、也可以是终端),输入以下git初始化指令。该命令用于在当前目录初始化一个新的 Git 仓库。如果当前目录已经是一个 Git 仓库,执行此命令不会有任何效果。
git init
【结果】该文件夹下有.git隐藏目录,且git插件部分显示了该目录下各文件的状态,说明本地仓库已经存在。
【示例】
作为示例,在该文件夹里创建test1、test2两个文件:
1.2 查看状态
文件状态表明了各文件是否被 Git 识别和纳入版本控制。在vscode中的Git插件,文件可以处于以下几种状态:
- 未跟踪(U):文件不存在于最近的提交中,Git 尚未开始跟踪这个文件。当在仓库中创建新文件时,它们最初都是未跟踪的。
- 已修改(M):文件自上次提交以来已经被修改,但还没有被暂存。
- 已删除(D):文件在本地仓库中存在,但是在工作区中被删除,该删除操作还没被暂存。
- 已暂存(索引):文件的当前版本已经被标记为将在下次提交时被包含,vscode中包含以下暂存的三种状态:
- 已添加索引(A):文件已经被添加到暂存区
- 已修改索引(M):文件自上次提交以来已经被修改,且已经被暂存。虽然显示的也是M,但是需要和“已修改”分别开。
- 已删除索引(D):文件在本地仓库中存在,且删除操作被暂存。虽然显示的也是D,但是需要和“已删除”分别开。
【vscode中的操作(其实不用操作)】
Git插件的图形化界面本身可以轻松观察到当前全部文件状态,十分方便。此时Git 插件会显示以上test1、test2文件的状态为“未跟踪”(后面的大U),因为它们尚未被纳入版本控制。
【对应git指令】
git status
如果使用该指令,可以查看所有文件的状态:
2.工作区与暂存区之间的转换
2.1 工作区->暂存区
【vscode中的操作】
在git插件中,“更改”部分列出了所有未暂存(包括“未跟踪”、“已修改”、“已删除”状态)的文件。
点击“更改”后面的按钮可以对全部文件进行操作;也可以鼠标悬停到某一个文件,对单一文件进行操作:曲线剪头是撤销所有修改(这个在后面提及)," + " 号是暂存所有修改
【对应的git指令】
添加全部未暂存文件到暂存区:将当前目录下所有新的或修改过的文件添加到暂存区。
git add .
添加单一未暂存文件到暂存区:将 <file>
替换为要暂存的文件名(例如,test1.txt)。
git add <file>
【结果】文件从“更改”栏进入“暂存的更改” ,文件状态变成“已暂存”(后面的大A)
2.2 暂存区->工作区
从暂存区中移除特定的文件,回到工作区状态,且不修改该文件工作区的内容
【vscode中的操作】
在Git插件中,“暂存的更改”部分列出了所有已经暂存的文件。
同理,点击“暂存的更改”后面的按钮可以对全部文件进行操作;也可以鼠标悬停到某一个文件,对单一文件进行操作:上图所框选出的“-”号是移除暂存文件
【对应的git指令】
将暂存区中的所有文件取消暂存
git reset HEAD -- .
取消暂存某个特定的文件:将 <file>
替换为要暂存的文件名(例如,test1.txt)。
git reset HEAD -- <file>
【结果】文件从“暂存的更改”栏移除。出现在“更改”栏,文件状态变回未暂存状态。
2.3 暂存区与工作区同一文件版本不同的情况(冲突问题)
在 VSCode 的 Git 插件中,“暂存的更改”部分显示的不仅仅是 Git 暂存区中的文件,它还可能包括那些已经被暂存但之后又被修改的文件。即“暂存的更改” ≠ “暂存区”,在 Git 命令行中,只有真正被暂存且未被进一步修改的文件才被视为暂存区的一部分。
-
只在“暂存的更改”部分出现的文件:文件状态为“已暂存”(包含“已修改索引”、“已添加索引、“已修改索引”),这些文件的当前版本已经被添加到 Git 的暂存区,准备在下一次提交中被包含。
-
同时在“暂存的更改”和“更改”两个部分出现的文件:状态不是“已xx索引”,这些文件之前可能已经被暂存,但在工作区中又有了新的修改。这些修改尚未被添加到暂存区。
【示例】
①暂存test1.txt:此时该文件状态为“已添加索引”(A),表示文件的当前版本已经存在于 Git 的暂存区中。
②修改test1.txt:将所有的“广东”改成“东莞”。同时观察文件状态——此时test1文件状态为“已修改”,同时也在“更改”区域出现。
此时,由于对文件做了新的修改,它的状态变为“已修改”(M),并且也出现在 VSCode 的“更改”区域。尽管这个修改后的状态为“M”的test1.txt仍然显示在“暂存的更改”部分,它实际上表示工作区中的文件版本与暂存区的版本不同。这些更改尚未被添加到 Git 的暂存区。③此时可进行的操作:
(1)重新暂存修改:按照上述 工作区->暂存区 的方法,将工作区中的新修改添加到暂存区,即再次执行add。这样,test1.txt文件状态由M变为A,vscode中“暂存的更改”被覆盖,即全部“广东”变为“东莞”,保留了“更改”中的新内容:
(2)撤销旧版本文件的暂存状态:即不提交这些新的修改,而是想要撤销对旧版本test1.txt的暂存状态,即可按照上述 暂存区->工作区 的方法,将旧版本的该文件从暂存区中移除,同时工作区中的新修改仍然保留(即“东莞”版本)。【有可能出现的问题】
在使用“-”操作时,如果跳出以下弹窗,这是因为“暂存的更改”和“更改”中的test1.txt内容存在冲突,它不知道你需要保留哪个版本的文件放入工作区
(好像在没有提交的时候会出现这个情况,如果已有提交,似乎就不会再有这个弹窗,而是直接移除暂存版本)(3)手动融合两个版本,并暂存融合版本:点击更改区的该文件,vscode会显示出暂存版本(左侧)和当前工作区版本(右侧)的内容,并高亮差异部分。暂存版本不可更改,只能对照,可以直接在工作区版本手动更改融合,也可以使用中间的按钮来对各行的差异部分做取舍:箭头是保留暂存版本方案,+号是采用工作区版本方案
完成融合后,按照上述 工作区->暂存区 的方法,将工作区中的新修改添加到暂存区。
3.提交、修改与回退
3.1 提交、查看提交历史
再次提示:已暂存状态为“已修改索引”、“已添加索引”、“已删除索引”(“索引”就是暂存),未暂存状态为“已修改”“未追踪”“已删除”
【vscode中的操作】
在输入框中输入本次提交的注释,描述代码的版本或者内容修改的情况,方便之后进行浏览差异。输入之后点击提交,会将所有暂存区的文件进行提交。
提交后,在“源代码管理图”中,可以看到提交历史,鼠标悬浮在上面可以获取更多信息,点进去也可以看该版本的具体代码与前一版本的差异。
【对应的git指令】
将暂存区的文件提交到本地仓库的当前分支,将“Your commit message”替换为提交注释。
git commit -m "Your commit message"
查看提交历史(通过日志):
git log
3.2 修改已提交的文件
一旦文件被提交,并且之后没有发生更改,它不会在 Git 插件的“更改”或“暂存的更改”部分显示。这是因为该文件的状态与仓库中的最新提交相匹配,没有新的更改需要跟踪。
如果在提交后又对文件进行了修改,那么这个文件将出现在 Git 插件的“更改”部分,并标记为“已修改”,因为现在它的状态与仓库的最新提交不再一致。
对于进行了修改的文件,可以再次进行上文所述 暂存区<—>工作区 的转换,放在暂存区的全部文件用于等待下一次提交。
【示例】
test1.txt文件在提交“初版0.1”后没有被修改,此时的文件状态如下:它不会在 Git 插件的“更改”部分显示,因为它的状态与最后一次提交的版本一致。
此时,Git插件只显示了未追踪的test2.txt文件,test1.txt文件虽然没有显示,但仍然存在于仓库中,只是没有新的更改需要版本控制。①对test1.txt文件进行修改,删掉其中几行,并将版本改成0.2
②查看Git插件,修改后的test1.txt文件(工作区版本)出现在了“更新”部分,文件状态为“已修改”,点击后可以看到工作区版本的文件内容(右)与最新提交版本的文件内容(左)的差异
③ 使用add暂存test1.txt,该文件进入“暂存的更改”栏,文件状态为“已修改索引”【暂存状态】,点击后可以看到暂存版本的文件内容(右)与最新提交版本的文件内容(左)的差异④再次修改test1.txt:将所有的“厦门”改成“福州”。此时test1文件状态为“已修改”,同时也在“更改”区域出现。点击后可以看到工作区版本的文件内容(右)与暂存版本的文件内容(左)的差异。
⑤再次使用add暂存test1.txt,该文件进入“暂存的更改”栏,文件状态为“已修改索引”【暂存状态】,点击后可以看到暂存版本的文件内容(右)与最新提交版本的文件内容(左)的差异。
3.3 撤销全部修改
撤销全部修改针对当前的未暂存文件,即“更改”中的文件,分为两种操作,都需要舍弃当前的工作区版本,一是回退到暂存版本;一是回退到最新提交版本。
【vscode中的操作】
在vscode中,这两种操作没有显式的区分,实现的方法就是点击“更改”栏的文件后面的“曲线箭头”。具体回退的版本为点击该文件时,编辑区左边显示的内容。即,如果暂存区有该文件的历史版本,就会显示暂存版本;如果暂存区没有该文件的历史版本,就会显示最新提交版本。
(一个题外话:“暂存的更改”栏下的文件,永远都会显示 最新提交版本 和 暂存版本)
结合以上示例,在第②步时,暂存区为空,因此显示工作区版本和最新提交版本;第④步时,暂存区已经有一个该文件的历史版本,因此显示工作区版本和暂存版本。
如果在第④步后,点击了test1.txt后面的“曲线箭头”,该工作区版本就会回退到暂存版本(缺行 + “厦门”),同时,因为暂存版本和回退后的工作区版本内容一致,该文件将只挂载在“暂存的更新”栏,且状态将为“已修改索引”。
假如:暂存区有历史版本,工作区在暂存版本的基础上做了修改,此时需要回退到最新提交版本,可以这么操作:根据上述2.2移除暂存区文件,使暂存区为空,点击撤销箭头,回退到最新提交版本。
【对应的git指令】
将工作区中的文件替换为暂存区或最新提交的版本。将 <file>
替换为要暂存的文件名(例如,test1.txt),或者. (全部文件)
git checkout -- <file>
3.4 版本回退与撤销
版本回退分为两类:一是直接回退到某版本并撤销该版本之后全部历史(reset);一是撤销某些版本的更改且保留历史(revert)。暂时没有在我的vscode中找到回退的图形化操作,只能copy到版本号,因此得结合git指令操作。
【操作】
在源代码管理图中选中要回退的版本,右键,选择复制commit ID。
打开终端,根据需求输入恰当的回退命令(reset/revert),将<commitID>替换为复制的版本号
3.4.1 回退 git reset:
git reset将 HEAD(当前分支的指向)回退到项目历史的某个特定点。有三种模式,分别是硬回退、软回退、混合回退。使用git reset命令会彻底撤销指定版本之后的所有提交,如果在和他人协作,或是正在操作主分支,要慎重使用。
①硬回退:将 HEAD、暂存区和工作区都回退到指定的提交版本(<commitID>
)。所有在该提交版本之后的更改都会被永久丢弃。
适用场景:需要彻底回退到某个版本,并且不需要保留之后的更改。
git reset --hard <commitID>
②软回退:将 HEAD回退到指定的提交版本,但保留暂存区和工作区的状态不变。其他更改的内容会保留在暂存区,可以再次提交。
适用场景:想要撤销提交,但仍然需要对这些更改进行评估或重新组织后再提交。
git reset --soft <commitID>
③混合回退:将 HEAD 回退到指定的提交版本,清空暂存区,但不会改变工作区。更改的内容全部保留在工作区中,可以对工作区中的文件进行审查和修改,然后重新提交。
效果和软回退差不多,但是无法保留暂存版本。
git reset --mixed <commitID>
因为 --mixed
是默认选项,所以可以省略,简写成以下
git reset <commitID>
【示例】
再次提交0.2版本,提交的文件为:缺行+“厦门”改“福州” 的test1-0.2 ,和提交0.1版本时没有提交的test2-0.1。
从源代码管理图中也可以查看不同提交版本之间的差异。①修改test2.txt文件,将其中一行改成首字母缩写,改成0.2版本,暂存。
再删除缩写下面的全部数字,这时文件在“暂存的更改”和“更改”中同时出现,文件状态为“已修改”
②在源代码管理图中复制“初版0.1”的版本号,进入终端,查看不同回退方式的效果:
(1)混合回退:git reset <commitID>
观察仓库状态:暂存区无文件,test1和test2的工作区版本没变,所有更改都保留在了工作区,最新提交版本回到初版0.1状态。test1状态为“已修改”,test2状态为“未追踪”(因为初版0.1没有提交teset2文件)(2)硬回退:git reset --hard <commitID>
观察仓库状态:Git 插件的“更改”或“暂存的更改”部分无文件,因为文件状态与仓库中的最新提交相匹配,没有新的更改需要跟踪。即,所有在提交该版本之后的更改,全部被丢弃。
接着查看文件目录:很糟糕,因为初始版本没有提交test2文件,test2被完全丢弃了,只剩下了初始提交版本内容的test1文件。【所以要谨慎】
(3)软回退:git reset --soft <commitID>
观察仓库状态:test2文件的暂存区版本、工作区版本没变,同时暂存区多了一个test1文件的历史提交版本,最新提交版本回到初版0.1状态。test1状态为“已修改索引”,test2状态仍为“已修改”。
3.4.3 撤销 revert:
revert用来撤销某个具体提交的更改。<commitID>理应为要撤销的版本,而不是要回退到的版本。它通过创建一个新的提交来实现,这个新提交的更改会抵消<commitID>的更改。它不会改变提交的历史,而是在历史的基础上添加一个新的提交。因此更加具有安全性。
适用场景:需要撤销历史中某次提交的情况,该提交可以穿插在历史中任意地方
这项操作通常在已经提交了当前版本的更改之后执行,要确保工作区是干净的,即当文件状态与仓库中的最新提交相匹配时。
git revert <commitID>
【示例】
在使用revent时,要保证工作区是干净的,因此将对test2的修改进行提交,注释为 初版0.2(test2-0.2版本)。如果要撤销掉 初版0.2(test2-0.2版本) ,对应的要撤销的操作就是 修改test2文件(0.1->0.2)。即test2变回0.1版本。
复制 初版0.2(test2-0.2版本) 的版本号,输入revert命令进行版本撤销:
此时,如果没有冲突,会自动定义revert注释,并将当前版本(左)和git进行反操作之后的版本(右)显示出来,此时test2在上一次提交进行的更改已经被抵消,并被放入暂存区,等待下一次提交。
【可以理解为:git试图根据撤销版本的操作进行反操作,来抵消撤销版本的更改,更改后进行暂存,然后展现在我们面前,如果我们认为它操作的正确,那么可以直接提交,如果代码比较复杂,我们认为它没有处理好,那么可以将其转换到工作区,在工作区继续修改,而后暂存提交】
提交revert进行的撤销操作,test2文件又回到了0.1状态