一文带你掌握Visual Studio中集成的git功能
前言
Visual Studio中深度集成了git功能,可以很方便的进行源代码版本控制功能。
大部分日常的操作我们可以通过界面来完成,这样就省去了输入git命令的时间,也可以不用记很多参数。
但这毕竟是辅助工具,掌握常用的git命令行还是很有必要的。
言归正传,接下来开始介绍Visual Studio 中集成的git功能。
本文以Visual Studio 2022为例进行演示
安装
Visual Studio的UI中已经集成了git相关功能,但是也需要安装git后才能使用。

如果没有安装git,在使用相关功能时,可能会看到如下的提示

安装方式可以通过以下两种
1、在Visual Studio的安装程序中,钩选<适用于Windows的Git>
推荐使用这种方式,因为免去了单独下载和安装的环节

2、访问git官方网站,下载安装包手动安装
下载地址:Git - Install for Windows

导入/克隆(clone)代码
方法1、在Visual Studio的启动界面上选择克隆存储库

输入项目地址

方法2、通过git命令行/git gui
输入
1 git clone https://github.com/zhaotianff/ImageViewer.git
分支(branch)功能
Git中的分支(branch)是一个轻量级的、可移动的指针,指向我们所做的提交。
默认分支的名称是master(github现已更新为main)。
每当做出任何commit时,它都会自动前进。
在Git中,可以创建任意子分支,从主存储库创建另一条开发线,开发新功能或修复错误。
一旦功能或错误修复完成,可以将它合并回主分支,然后删除子分支(也可以保留)。
如下图所示:

创建分支
Git分支只是一个小引用,用于保存准确的提交历史记录;
创建分支时不会创建源代码的多个副本。
在工具栏上点击当前分支,在弹出的面板中,选择创建分支。
在弹出的窗口中输入新分支的名称,并选择基于的分支,再点击创建,即可创建分支

对应的git命令行
# 方法1:使用 checkout(兼容所有 Git 版本) git checkout -b 新分支名称 基础分支名称 # 方法2:使用 switch(Git 2.23+ 推荐,更直观) git switch -c 新分支名称 基础分支名称
推送本地分支
创建本地分支后,需要将分支推送到服务器后,才能在服务器上看到新创建的分支。
选择Gti->管理分支菜单

找到对应的分支,在右键菜单中选择推送

推送成功后,可以看到提示信息

此时我们打开git服务器上的页面,可以看到刚推送的分支

对应的git命令
1 git push origin 分支名称
切换分支
在工具栏上选择当前分支,在弹出的面板中选择要切换的分支。
本地分支是指存在本地电脑上的分支。
远程是指存储在git服务器上的分支。

对应的git命令
1 git checkout 分支名称
删除分支
删除本地分支
当我们只想删除本地分支,而不删除远程服务器上的分支时。
可以通过右键菜单里的删除菜单进行删除

对应 的git命令
1 git branch -d 分支名称
通过这种情况删除的分支,还可以通过下面的方式恢复回来。
在remotes/origin文件夹下,选择服务器上本地已经删除的分支,右键选择签出,即可恢复分支。

对应的git命令行
1 git checkout -b 删除的分支 origin/删除的分支
删除服务器上的分支
当我们想彻底删除分支时,可以通过在remotes/origin文件夹下面的分支上打开右键菜单,选择删除菜单。即可永久删除分支

注意,此操作不可逆,在删除前会有确认对话框

对应的git命令
1 git push origin --delete 远程分支名称
更改、暂存和提交功能
文件状态
当我们从git服务器clone一个项目时,所有的文件都是处于未修改的状态(Unmodified)。
当我们对文件进行了修改,修改的文件就变成了修改状态(Modified),可以在右下角看到修改的文件数量

单击修改数量图标,可以看到已经修改的文件

如果我们要把文件提交到git服务器上,就需要先进行暂存(Staging)。
我们看一下这几种状态的含义
未跟踪(Untracked):指的是工作区中存在,但未被 Git 纳入版本控制的文件。正常使用场景下,我们可以不考虑这种状态。
未修改(Unmodified):当我们从服务器导入代码,或进行提交后的文件状态
已修改:对文件进行了编辑,就变成了已修改状态
暂存 (Staging):把文件放到暂存列表中,用于下次提交(Commit)。

例如我修改了3个文件,但是下次提交时,只想提交两个文件。就可以对这两个文件进行暂存

对应的git命令
1 git add App.xaml 2 git add MainWindow.xaml
如果我们想把文件从暂存列表中移出,在文件上单击右键,在打开的菜单里选择取消暂存即可。

对应的git命令
1 git restore --staged 文件名
提交更改
当把文件放到暂存列表后,就可以对文件进行提交(Commit)。
在提交前,我们需要编辑此次提交的日志

对应的git命令
1 git commit -m "提交日志xxxxx"
当进行提交后,本地的git仓库已经有了这条提交记录,但是还未同步到服务器。
可以在状态栏上看到具体的数量

此时我们单击传出数量,在弹出的菜单中,选择推送,即可将本地的提交记录推送到服务器。

也可以在提交时直接推送,我一般习惯了使用这种方式进行操作。可以一键完成提交并推送

撤消更改
当我们对一个代码文件进行修改后,可以在修改列表中双击这个文件,与未修改的文件进行对比

如果我们需要撤销某一行的修改,可以在对比页面的修改行上点撤消行按钮

如果需要撤销整个文件的修改,在文件右键菜单中选择撤销更改即可

对应的git命令行
1 git restore <file-name>
修改提交日志信息
当提交未推送到服务器上时,可以修改提交日志信息。
在工具栏点击传入/传出按钮,然后选择查看所有提交

双击本地提交

然后在右侧的面板中编辑提交日志消息即可

提取、推送、拉取和同步功能
当我们点击这个查看传入/传出按钮时,可以在这里看到提取、拉取、推送和同步这几个菜单项。下面依次介绍一下这些功能的区别。

推送(Push)
推送功能在前面我们已经使用过了,它的作用是把本地的修改同步到服务器,包括修改文件、创建分支等操作。
在前面我们还介绍过分支功能,
如果我们创建了一个空的分支,可以在分支的菜单里直接将这个分支推送到远程存储库。
如果我们在本地创建了分支,并在这个分支里修改了文件,那么在推送时,它会通过首先创建与本地存储库同名的分支,然后向其推送本地提交,将更改发布到远程存储库。
如果在推送操作期间,Visual Studio发现远程提交和本地提交之间存在任何冲突,它将立即中断操作。
必须先解决这些冲突,然后才能推送。在后面我们会介绍如何解决冲突。
提取(Fetch)
当我们在服务器进行了修改,或者同仓库的其它协同者更新了仓库代码,而本地又并未同步这些修改。
我们可以通过提取(Fetch)功能,把这些修改导入到本地,但是不自动合并这些修改。
如果服务器上有修改,可以在这里看到修改列表

拉取(Pull)
拉取的功能和提取类似,但是它会自动合并修改。
如果在合并过程中,发现有冲突,系统会提示你。
必须在处理这些冲突之后,才能进行下次推送。
接下来我们演示一下如何处理拉取过程中的文件冲突。
假设我们在本地增加一行代码,如下所示

然后项目的其它协作者也修改了这行并将他的修改推送到了服务器

此时我们进行Pull或Sync(先Pull再Push)的操作时,就会产生冲突,如下所示

我们在冲突的文件上双击,可以看到如下的界面

在这里我们可以钩选采用服务器上的版本(左上),也可以钩选采用本地的版本(右上),也可以两边都要。
在编辑完成后,选择接受合并按钮即可。

合并完成后,需要我们再提交一次

由于冲突会导致一次多余的提交记录 ,所以在多人协同开发时,在每次修改前,都执行一下拉取或同步命令,保证本地的文件是最新的。
虽然 在后面我们会介绍如何避免产生这条多余的提交记录,但是我们还是要养成良好的开发习惯。
同步(Sync)
这个我们在前面已经介绍过它的作用了,这的作用就是先拉取(Pull)再推送(Push)。
Pull Requests,拉取请求(PR)功能
Pull Requests是一种协作过程,用于讨论分支中实施的更改,获取更改的早期反馈,并在每个人都批准后将其与主分支合并。
即使我们还没有准备好合并更改,也可以创建工作输入模块的拉取请求。
说明:因为这个功能的翻译可能会存在差异,所以尽量直接称呼为PR或Pull Requests。
假设我们有一个计算器的项目,然后项目框架搭建好以后,将加、减、乘、除四个功能分别创建了四个分支,并分给四个不同的人开发。
当这些功能代码完成后,需要再合并到主分支,这个时候就需要使用到PR功能。
例如,作者A要合并他的“加”功能模块到主分支,他就可以创建一个PR,当仓库(Repo)管理员接收到这个PR以后,他可以选择合并,也可以选择忽略。
可能有小伙伴会问了,为什么不直接在主分支上进行协同开发。
这里主要是出于以下原因考虑
1、保护主分支的稳定性
主分支会贯穿整个项目开发,所以需要保证它的代码的稳定性。分支则相当于 “隔离的开发环境”,开发者在分支中完成功能后,通过 PR 审核确认无误后再合并,能确保主分支始终可运行、可发布。
2、减少代码冲突
由于分支是在自己的“隔离的开发环境”下进行开发,所以不会存在冲突问题。最后在进行PR时,再统一处理冲突问题,且冲突范围可控(通常是与主分支的差异)。
3、支持代码评审
如果直接在主分支进行开发,每个人都可以直接提交代码,可能会导致低质量代码进入主分支。
PR 的核心作用之一是触发代码评审:其他开发者可以在 PR 中检查代码质量、逻辑漏洞、风格规范等,提出修改建议。
4、支持并行开发
大家可以同时开发自己的功能模块,在完成后,再创建PR进行合并。
5、功能管理与回溯
每个分支可对应一个具体任务(如 “用户登录功能”“修复支付 bug”),分支名(如feature/login fix/payment)能清晰标识用途,方便团队跟踪进度。
如何创建PR
1、在git服务页面上创建
我一般习惯了使用这种方式创建,代码对比或比较清晰,方便。
这里以github为例
首先找到仓库的Pull Requests Tab页

然后新建一个PR

然后选择要合并的分支

选择分支后,可以看到与对应基础的差异。
确认无误后,点击Create pull request按钮就可以创建PR

2、在Visual Studio中创建
在对应的分支上打开右键菜单,选择“创建拉取请求”

在弹出的界面中填写相应信息后,单击Create按钮即可创建PR

注意:
项目的参与者一般在创建PR时,需要选择Reviewers(审核者),类似下面的界面,根据实际情况选择即可

评审及合并PR
当创建一个PR后,创建PR时选择的审核者会收到一个通知。他们可以提供反馈或通过这个PR并合并代码到主分支。
这里还是以github为例
我们打开项目的Pull Requests Tab页,可以在列表里看当当前未合并的PR。
说明:因为我这里是项目的管理者,而且没有其他协作者,所以无法展示系统通知的效果。但是操作步骤是一样的。

我们点开这个PR,如果合并有冲突,我们需要先解决这个冲突,点击Resolve conflicts按钮,开始解决冲突

跟Visual Studio中界面类似,这里也有接受当前、接受传入、接受全部三个选项,也可以自行编辑。

编辑完成后,选择右上角的Mark as resolved按钮,然后再选择Commit merge按钮。

此时再回到前面的合并页面,可以看到已经没有冲突了。点击 Merge pull request按钮即可合并分支。

在前面的操作中,因为我是管理员,所以有部分界面会不太一样。
在在多人协同开发时,我们在进行合并前,审核者需要对代码进行评审(Review)。
当鼠标划过代码行时, 左侧会有一个加号按钮,点击这个加号,可以在对应的代码行写下相应的评论。

所有注释添加完后,点击 “Finish review”,选择审查结论并提交,整个审查流程就结束了。
管理提交历史(Commit History)
Git用于在将代码作为提交保存到本地存储库时管理更改历史,然后在pull请求获得批准后将这些更改与main分支合并。
当团队成员使用分支进行开发,它失去了提交历史的线性,使其难以遵循。
这也使得当单个功能分支中存在多个提交时,很难跟踪最终的功能更改。在这种情况下,如果我们想在以后恢复(revert)一个功能,就会变得比较复杂
为了解决这个问题,Git提供了一个名为rebase的命令,可以解决所有这些问题。
它接收在当前分支上进行的提交,并在另一个分支上还原它们。
当前分支上的提交历史将被重写,以保留历史的粒度。
例如,将下图视为提交历史记录,我们从old base开始功能分支,并通过两次提交保存了更改。
与此同时,团队的其他一些成员在main中提交了两项更改。因此,old base现在将有两个分支:
一个指向main,另一个指向feature

现在,当我们将功能分支重新设置为主分支时,它将重写您的本地提交历史,将我们的功能更改重放到主分支。
然后,在本地存储库上能看到线性提交历史记录以及其他人所做的更改。
如何使用rebase重写提交历史
我们按照上面示意图创建对应的分支
1、创建一个master分支,master分支commit一次
2、在master的基础上创建branch_one
3、在master分支上进行两次提交
4、在branch_one上进行两次提交
现在我们来看一下提交记录情况


操作步骤如下
1、在master上右键菜单选择"将branch_one"变基为"master"

2、变基以后可以看到提交记录变成如下

3、选择同步(先拉取后推送)功能,可以看到提交记录如下:

这个时候我们可以看到提交记录是线性的,branch_one的提交在master的提交后面。
有时候我们会遇到在rebase时发生冲突的情况

处理方法跟前面处理冲突方法一致,我们在修复冲突后,选择接受合并。解决完冲突以后,就可以继续执行后面的操作。
对应的git命令行
1 # 切换到你的开发分支 2 git checkout branch_one 3 4 # 基于 master分支的最新提交,重新调整 branch_one分支的提交 5 git rebase master
使用cherry-pick(挑拣)来复制commit
Cherry pick是一个将提交从一个分支复制到另一个分支的过程。
它只复制提交中的更改,而不是复制分支中的所有更改,它与合并和重基执行的功能完全不同。
当我们不小心提交到错误的分支或想在某个分支中提取一组提交到主/功能分支时,我们就可以使用Cherry-pick功能。
在Visual Studio中,这个功能的翻译是“挑拣”
假设我们有一个master分支和branch_one分支,我们想把branch_one分支中的某一次提交复制到master中
操作步骤如下:
1、切换到master分支

2、保持当前分支在master,然后在branch_one上右键 选择查看历史

3、在需要复制的commit上,右键选择挑拣

4、此时我们可以看到master分支已经有这条commit了,然后再推送即可

为提交创建Tag(标签)
在github中我们创建release时,需要把release对应一个Tag。如下所示:

Tag的作用是用来标识某些关键的提交。
如何创建Tag
打开提交记录,在需要创建Tag的提交上,打开右键菜单,选择新建标记

然后在弹出的窗口中填写Tag信息

创建完成后,我们可以在提交历史上看到创建好的Tag信息。

对应的git命令
其中v1.0是tag名称,a1b2c3d为提交id
1 git tag -a v1.0 a1b2c3d -m "提交信息xxxxx"
撤销修改
有时候我们本地修改的代码,或者已经提交的代码,想进行撤销 ,应该如何处理呢?
这里可以分为多种情况
1、将本地分支重置为以前的状态
这里的话,可以继续使用前面的方式。只不是右键的位置换成了项目根节点,而不是单独的某一个文件。
我平常习惯使用这种方式,比较方便快捷。

也可以在分支上右键,选择重置->删除更改(--hard)

2、将分支重置到某一次提交
这里可以参考我前面写的一篇文章
https://www.cnblogs.com/zhaotianff/p/18727126
3、从远程分支还原更改
有时候我们已经将修改推送到服务器, 例如我进行了3次提交,但是我现面不想要后面的2次提交了,这个时候我们就可以用到revert功能

git revert 的作用是创建一个新的提交,抵消目标提交之后的所有变更,而不是直接删除历史。
所以我们在执行还原后,可以看到这样一条提交记录

对应的git命令
xxxx为提交id
2 git revert xxxx

浙公网安备 33010602011771号