一文带你掌握Visual Studio中集成的git功能

一文带你掌握Visual Studio中集成的git功能

前言

Visual Studio中深度集成了git功能,可以很方便的进行源代码版本控制功能。

大部分日常的操作我们可以通过界面来完成,这样就省去了输入git命令的时间,也可以不用记很多参数。

但这毕竟是辅助工具,掌握常用的git命令行还是很有必要的。

言归正传,接下来开始介绍Visual Studio 中集成的git功能。

本文以Visual Studio 2022为例进行演示

安装

Visual Studio的UI中已经集成了git相关功能,但是也需要安装git后才能使用。

image

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

image

安装方式可以通过以下两种

1、在Visual Studio的安装程序中,钩选<适用于Windows的Git>

推荐使用这种方式,因为免去了单独下载和安装的环节

image

2、访问git官方网站,下载安装包手动安装

下载地址:Git - Install for Windows

image

导入/克隆(clone)代码

方法1、在Visual Studio的启动界面上选择克隆存储库

输入项目地址

image

方法2、通过git命令行/git gui

输入

1 git clone https://github.com/zhaotianff/ImageViewer.git

分支(branch)功能

Git中的分支(branch)是一个轻量级的、可移动的指针,指向我们所做的提交。

默认分支的名称是master(github现已更新为main)。

每当做出任何commit时,它都会自动前进。

在Git中,可以创建任意子分支,从主存储库创建另一条开发线,开发新功能或修复错误。

一旦功能或错误修复完成,可以将它合并回主分支,然后删除子分支(也可以保留)。

如下图所示:

image

创建分支

Git分支只是一个小引用,用于保存准确的提交历史记录;

创建分支时不会创建源代码的多个副本。

在工具栏上点击当前分支,在弹出的面板中,选择创建分支。

在弹出的窗口中输入新分支的名称,并选择基于的分支,再点击创建,即可创建分支

image

对应的git命令行

# 方法1:使用 checkout(兼容所有 Git 版本) git checkout -b 新分支名称 基础分支名称 # 方法2:使用 switch(Git 2.23+ 推荐,更直观) git switch -c 新分支名称 基础分支名称

推送本地分支

创建本地分支后,需要将分支推送到服务器后,才能在服务器上看到新创建的分支。

选择Gti->管理分支菜单

image

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

image

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

image

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

image

 对应的git命令

1 git push origin 分支名称

切换分支

在工具栏上选择当前分支,在弹出的面板中选择要切换的分支。

本地分支是指存在本地电脑上的分支。

远程是指存储在git服务器上的分支。

image

对应的git命令

1 git checkout 分支名称

删除分支

删除本地分支

当我们只想删除本地分支,而不删除远程服务器上的分支时。

可以通过右键菜单里的删除菜单进行删除

image

对应 的git命令

1 git branch -d 分支名称

通过这种情况删除的分支,还可以通过下面的方式恢复回来。

在remotes/origin文件夹下,选择服务器上本地已经删除的分支,右键选择签出,即可恢复分支。

image

对应的git命令行

1 git checkout -b 删除的分支 origin/删除的分支

删除服务器上的分支

当我们想彻底删除分支时,可以通过在remotes/origin文件夹下面的分支上打开右键菜单,选择删除菜单。即可永久删除分支

image

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

image

 对应的git命令

1 git push origin --delete 远程分支名称

更改、暂存和提交功能

文件状态

当我们从git服务器clone一个项目时,所有的文件都是处于未修改的状态(Unmodified)。

当我们对文件进行了修改,修改的文件就变成了修改状态(Modified),可以在右下角看到修改的文件数量

image

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

image

如果我们要把文件提交到git服务器上,就需要先进行暂存(Staging)。

我们看一下这几种状态的含义

未跟踪(Untracked):指的是工作区中存在,但未被 Git 纳入版本控制的文件。正常使用场景下,我们可以不考虑这种状态。

未修改(Unmodified):当我们从服务器导入代码,或进行提交后的文件状态

已修改:对文件进行了编辑,就变成了已修改状态

暂存 (Staging):把文件放到暂存列表中,用于下次提交(Commit)。

ec73f4e59822b4fc6347295cc6cd9ef9_lifecycle

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

demo

对应的git命令

1 git add App.xaml 2 git add MainWindow.xaml

如果我们想把文件从暂存列表中移出,在文件上单击右键,在打开的菜单里选择取消暂存即可。

image

对应的git命令

1 git restore --staged 文件名

  

提交更改

当把文件放到暂存列表后,就可以对文件进行提交(Commit)。

在提交前,我们需要编辑此次提交的日志

image

对应的git命令

1 git commit -m "提交日志xxxxx"

当进行提交后,本地的git仓库已经有了这条提交记录,但是还未同步到服务器。

可以在状态栏上看到具体的数量 

image

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

image

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

image

撤消更改

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

image

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

image

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

image

对应的git命令行

1 git restore <file-name>

修改提交日志信息

当提交未推送到服务器上时,可以修改提交日志信息。

在工具栏点击传入/传出按钮,然后选择查看所有提交

image

双击本地提交

image

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

提取、推送、拉取和同步功能

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

image

推送(Push)

推送功能在前面我们已经使用过了,它的作用是把本地的修改同步到服务器,包括修改文件、创建分支等操作。 

在前面我们还介绍过分支功能,

如果我们创建了一个空的分支,可以在分支的菜单里直接将这个分支推送到远程存储库。

如果我们在本地创建了分支,并在这个分支里修改了文件,那么在推送时,它会通过首先创建与本地存储库同名的分支,然后向其推送本地提交,将更改发布到远程存储库。

如果在推送操作期间,Visual Studio发现远程提交和本地提交之间存在任何冲突,它将立即中断操作。

必须先解决这些冲突,然后才能推送。在后面我们会介绍如何解决冲突。

提取(Fetch)

当我们在服务器进行了修改,或者同仓库的其它协同者更新了仓库代码,而本地又并未同步这些修改。

我们可以通过提取(Fetch)功能,把这些修改导入到本地,但是不自动合并这些修改。

如果服务器上有修改,可以在这里看到修改列表

image

拉取(Pull)

拉取的功能和提取类似,但是它会自动合并修改。

如果在合并过程中,发现有冲突,系统会提示你。

必须在处理这些冲突之后,才能进行下次推送。
 

接下来我们演示一下如何处理拉取过程中的文件冲突。

假设我们在本地增加一行代码,如下所示

image

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

image

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

image

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

image

在这里我们可以钩选采用服务器上的版本(左上),也可以钩选采用本地的版本(右上),也可以两边都要。

在编辑完成后,选择接受合并按钮即可。

demo

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

image

由于冲突会导致一次多余的提交记录 ,所以在多人协同开发时,在每次修改前,都执行一下拉取或同步命令,保证本地的文件是最新的。

虽然 在后面我们会介绍如何避免产生这条多余的提交记录,但是我们还是要养成良好的开发习惯。

同步(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页

image

然后新建一个PR

image

然后选择要合并的分支

image

选择分支后,可以看到与对应基础的差异。

确认无误后,点击Create pull request按钮就可以创建PR

image

2、在Visual Studio中创建

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

image

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

image

注意:

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

image

评审及合并PR

当创建一个PR后,创建PR时选择的审核者会收到一个通知。他们可以提供反馈或通过这个PR并合并代码到主分支。

这里还是以github为例

我们打开项目的Pull Requests Tab页,可以在列表里看当当前未合并的PR。

说明:因为我这里是项目的管理者,而且没有其他协作者,所以无法展示系统通知的效果。但是操作步骤是一样的。

image

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

image

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

image

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

image

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

image

在前面的操作中,因为我是管理员,所以有部分界面会不太一样。

在在多人协同开发时,我们在进行合并前,审核者需要对代码进行评审(Review)。

当鼠标划过代码行时, 左侧会有一个加号按钮,点击这个加号,可以在对应的代码行写下相应的评论。

image

所有注释添加完后,点击 “Finish review”,选择审查结论并提交,整个审查流程就结束了。

管理提交历史(Commit History)

Git用于在将代码作为提交保存到本地存储库时管理更改历史,然后在pull请求获得批准后将这些更改与main分支合并。

当团队成员使用分支进行开发,它失去了提交历史的线性,使其难以遵循。

这也使得当单个功能分支中存在多个提交时,很难跟踪最终的功能更改。在这种情况下,如果我们想在以后恢复(revert)一个功能,就会变得比较复杂

为了解决这个问题,Git提供了一个名为rebase的命令,可以解决所有这些问题。

它接收在当前分支上进行的提交,并在另一个分支上还原它们。

当前分支上的提交历史将被重写,以保留历史的粒度。

例如,将下图视为提交历史记录,我们从old base开始功能分支,并通过两次提交保存了更改。

与此同时,团队的其他一些成员在main中提交了两项更改。因此,old base现在将有两个分支:

一个指向main,另一个指向feature

image

现在,当我们将功能分支重新设置为主分支时,它将重写您的本地提交历史,将我们的功能更改重放到主分支。

然后,在本地存储库上能看到线性提交历史记录以及其他人所做的更改。

如何使用rebase重写提交历史

我们按照上面示意图创建对应的分支

1、创建一个master分支,master分支commit一次

2、在master的基础上创建branch_one

3、在master分支上进行两次提交

4、在branch_one上进行两次提交

现在我们来看一下提交记录情况

image

image

 操作步骤如下

1、在master上右键菜单选择"将branch_one"变基为"master"

image

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

image

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

image

这个时候我们可以看到提交记录是线性的,branch_one的提交在master的提交后面。

有时候我们会遇到在rebase时发生冲突的情况

image

处理方法跟前面处理冲突方法一致,我们在修复冲突后,选择接受合并。解决完冲突以后,就可以继续执行后面的操作。

对应的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分支

image

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

image

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

image

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

image

为提交创建Tag(标签)

在github中我们创建release时,需要把release对应一个Tag。如下所示:

image

 Tag的作用是用来标识某些关键的提交。

如何创建Tag

打开提交记录,在需要创建Tag的提交上,打开右键菜单,选择新建标记

image

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

image

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

image

对应的git命令

其中v1.0是tag名称,a1b2c3d为提交id

1 git tag -a v1.0 a1b2c3d -m "提交信息xxxxx"

撤销修改

有时候我们本地修改的代码,或者已经提交的代码,想进行撤销 ,应该如何处理呢?

这里可以分为多种情况

1、将本地分支重置为以前的状态

这里的话,可以继续使用前面的方式。只不是右键的位置换成了项目根节点,而不是单独的某一个文件。

我平常习惯使用这种方式,比较方便快捷。

image

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

image

2、将分支重置到某一次提交

这里可以参考我前面写的一篇文章

https://www.cnblogs.com/zhaotianff/p/18727126

3、从远程分支还原更改

有时候我们已经将修改推送到服务器, 例如我进行了3次提交,但是我现面不想要后面的2次提交了,这个时候我们就可以用到revert功能

image

git revert 的作用是创建一个新的提交,抵消目标提交之后的所有变更,而不是直接删除历史。

所以我们在执行还原后,可以看到这样一条提交记录

image

对应的git命令

xxxx为提交id 2 git revert xxxx

Read more

C++ 多线程同步之互斥锁(mutex)实战

C++ 多线程同步之互斥锁(mutex)实战

C++ 多线程同步之互斥锁(mutex)实战 💡 学习目标:掌握 C++ 标准库中互斥锁的基本用法,理解多线程同步的核心原理,能够解决多线程环境下的资源竞争问题。 💡 学习重点:std::mutex 与 std::lock_guard 的使用、死锁的产生原因及规避方法、实际场景中的同步案例实现。 48.1 多线程同步的必要性 在多线程编程中,当多个线程同时访问共享资源时,会出现资源竞争问题。 例如两个线程同时对同一个变量进行读写操作,会导致最终结果与预期不符。 这种问题被称为线程安全问题,而解决该问题的核心就是线程同步。 ⚠️ 注意事项:线程不同步会引发数据竞争,造成程序运行结果不可预测,甚至导致程序崩溃。 举个简单的反例,两个线程同时对全局变量 count 进行自增操作: #include<iostream>#include<thread>usingnamespace std;int count

By Ne0inhk
基于SpringBoot+Vue的汽车资讯网站管理系统设计与实现【Java+MySQL+MyBatis完整源码】

基于SpringBoot+Vue的汽车资讯网站管理系统设计与实现【Java+MySQL+MyBatis完整源码】

系统架构设计### 摘要 随着互联网技术的快速发展和汽车行业的持续繁荣,汽车资讯平台成为消费者获取车辆信息、比较车型性能以及了解行业动态的重要渠道。传统的汽车资讯平台在信息整合、用户体验和后台管理方面存在诸多不足,如信息更新不及时、交互体验差、管理效率低下等问题。为解决这些问题,设计并实现一个高效、稳定且用户友好的汽车资讯网站管理系统具有重要意义。该系统能够满足用户对汽车资讯的多样化需求,同时为管理员提供便捷的内容管理工具,提升整体运营效率。关键词包括:汽车资讯、管理系统、SpringBoot、Vue、MySQL、MyBatis。 本系统采用前后端分离架构,后端基于SpringBoot框架实现,结合MyBatis作为持久层框架,MySQL作为数据库存储数据,确保系统的高效性和可扩展性。前端使用Vue.js框架构建用户界面,提供响应式设计和良好的交互体验。系统功能模块包括用户管理、新闻资讯管理、车型数据管理、评论互动等,支持多角色权限控制,确保数据安全。管理员可通过后台管理系统快速发布、编辑和删除资讯内容,用户则能通过前端页面浏览最新汽车资讯、参与评论互动。关键词包括:前后端分离、权

By Ne0inhk
Python vs Java:做AI项目到底选哪个?我的真实体验

Python vs Java:做AI项目到底选哪个?我的真实体验

Python vs Java:做AI项目到底选哪个?我的真实体验 最近在做AI项目,在Python和Java之间纠结了很久。两个都用过,各有优缺点。今天就来聊聊我的真实体验,给要选型的同学参考。 先说结论 我的建议: * 快速原型、实验性项目:选Python * 企业级应用、已有Java技术栈:选Java * 混合使用:Python做模型训练和服务,Java做业务系统 但这不是绝对的,具体还得看项目情况。 Python的优势 1. AI生态成熟 Python在AI领域确实有优势,库太丰富了: # 模型训练import tensorflow as tf from transformers import AutoModel # 数据处理import pandas as pd import numpy as np # 可视化import matplotlib.pyplot as plt

By Ne0inhk

2026年值得关注的十大 JavaScript 框架

引言 JavaScript生态系统正在以极快的速度不断演进。五年前使用的技术在今天可能已经显得沉重或过时。随着2026年的临近,某些框架继续占据主导地位,而其他一些新兴框架则迅速崛起,响应着不断变化的性能需求、开发者体验优先级以及现代网页架构趋势(如边缘渲染、SSR、岛屿架构)。本文将探讨10个值得在2026年关注的前端、全栈/元框架或边缘准备框架,分析它们的特点、权衡和适用场景。 什么是"2026-ready"的JavaScript框架 在选择值得关注的框架时,我们主要考虑以下标准: 1. 性能与捆绑包大小:更小的捆绑包,更快的加载时间,最小的运行时开销。 2. 渲染/部署模型的灵活性:能够支持SSR、SSG、边缘渲染、增量静态生成或混合渲染。 3. 开发者体验与可维护性:语法干净,支持TypeScript,良好默认,最小的样板程序,以及流畅的开发者体验。 4. 生态系统与社区支持:库、工具、插件、主动维护、日益增长的采用率。 5.

By Ne0inhk