type
slug
status
summary
icon
category
date
tags
password

0 Git与VSCode

杂七杂八
 

1 Git版本控制

notion image
我们手里的论文可能会经过多次版本迭代,最终我们会选取一个最好的版本作为最终提交的论文。使用版本控制不仅仅是为了去记录版本迭代历史,更是为了能够随时回退到之前的版本实现时间回溯。同时,可能我们的论文是多个人一同完成,那么多个人如何去实现同步,如何保证每个人提交的更改都能够正常汇总,如何解决冲突,这些问题都需要一个优秀的版本控制系统来解决。

1.1 走进Git

我们开发的项目,也需要一个合适的版本控制系统来协助我们更好地管理版本迭代,而Git正是因此而诞生的(有关Git的历史,这里就不多做阐述了,是一位顶级大佬在一怒之下只花了2周时间用C语言开发的,之后的章节还会遇到他)
首先我们来了解一下Git是如何工作的:
notion image
可以看到,它大致分为4个板块:
  • 工作目录(Working Directory)
    • 正在写代码和改文件的地方。
    • 这里的文件处于“未被 Git管理”或“已修改但未保存”的状态。
  • 暂存区(Stage)
    • 暂时保存待提交的内容。
    • 临时快照区,用git add把修改放进来之后,表示这些改动(新版本)准备好提交了,新版本提交后会存放到本地仓库
  • 本地仓库(Local Repository)
    • 位于我们电脑上的一个版本控制仓库(.git目录),存放的就是当前项目各个版本代码的增删信息。
    • 当使用git commit时,暂存区的内容会永久记录成一个新的提交,然后上传到本地仓库。
  • 远程仓库(Remote Repository)
    • 位于服务器上的版本控制仓库Github
    • 可以用git push将本地的提交上传,也可以用git pull从服务器抓取到本地仓库(把别人的提交下载)
它是一个分布式的控制系统,因此一般情况下我们每个人的电脑上都有一个本地仓库,由大家共同向远程仓库去推送版本迭代信息。
通过这一系列操作,我们就可以实现每开发完一个版本或是一个功能,就提交一次新版本,这样,我们就可以很好地控制项目的版本迭代,想回退到之前的版本随时都可以回退,想查看新版本添加或是删除了什么代码,随时都可以查看。

1.2 安装Git

首先请前往Git官网去下载最新的安装包:https://git-scm.com/download/win
安装完成后,需要设定用户名和邮箱来区分不同的用户:
notion image
 

2 基本命令介绍

2.1 创建本地仓库

我们可以将任意一个文件夹作为一个本地仓库,输入:git init来生成一个git的管理仓库
输入后,会自动生成一个.git目录,注意这个目录是一个隐藏目录,当前文件夹就是我们的工作目录。
再次回顾一下四个分区:工作区(能够看到和编辑文件),暂存区(.git/index,二进制文件存放哪些改动被git add了),本地仓库(.git/objects,存放实际的提交,加上.git/refs(分支信息),.git/HEAD等),远程仓库(使用git remote add origin…配置远程地址后Git才知道要和谁交互)
所以这个.git文件夹准确的来说是Git内部的数据库(本地仓库+暂存区+版本控制信息)
创建成功后,我们可以查看一下当前的一个状态,输入:
如果已经成功配置为Git本地仓库,那么输入后可以看到:
这表示我们还没有向仓库中提交任何内容,也就是一个空的状态。
notion image
注意我们的默认分支是main分支。

2.2 添加和提交

接着我们来看看,如何使用git来管理我们文档的版本,我们创建一个文本文档,随便写入一点内容,接着输入:
我们会得到如下提示:
notion image
其中Untracked files是未追踪文件的意思,也就是说,如果一个文件处于未追踪状态,那么git不会记录它的变化,始终将其当做一个新创建的文件,这里我们将其添加到暂存区,那么它会自动变为被追踪状态:
再次查看当前状态:
notion image
现在文件名称的颜色变成了绿色,并且是处于Changes to be committed下面,因此,我们的hello.txt现在已经被添加到暂存区了。(因为已经检测到了change。那么一定在暂存区里面,如果文件还在工作目录里面的话,这个change不会被检测到)(还有啊注意这个Changes to be committed,是此时这些changes在暂存区里面,根据英语可以知道to be committed是还没有被提交,将要被提交的状态。也译为这些changes准备好被提交。be committed之后,changes在本地仓库,那么现在就在暂存区)
notion image
接着我们来尝试将其提交到Git本地仓库中,注意需要输入提交的描述以便后续查看,比如你这次提交修改了或是新增了哪些内容:从暂存区到本地仓库使用的是git commit命令。然后空格+-m+空格‘’,描述信息。
git commit -a -m ’’;这里的-a,意思是-all,在执行 commit 之前,自动把所有已经被Git跟踪的文件的修改(新增内容/修改内容/删除文件)放进暂存区。换句话说就是省去了手动git add <文件名>的步骤。不完全等价git add.,区别是git add.会把当前目录下的所有改动都放进暂存区(包括新文件),但是git commit -a,只会把已经被跟踪的文件的改动自动放进暂存区,新建的文件(Git还没有add自动追踪的)不会被包括进来。同时这个-a也不是将暂存区的所有内容上传到本地仓库,因为上传本地仓库的职责是git commit。
所以-a/—all,并不是控制提交什么,而是决定在commit前要不要顺便帮你做一次add。
notion image
所以使用的时候,对已经被追踪过即被add过的文件再进行修改的时候,可以将add和commit合并。
notion image
接着我们可以查看我们的提交记录:
notion image
notion image
我们还可以查看最近一次变更的详细内容git status:修改hello.txt之后,查看状态显示出现修改。因为我们的hello.txt已经在暂存区里面了,所以是自动追踪状态,会检测出change。
notion image
但是需要再次git add才可以将最新的改动放入下一次的提交中。
notion image
这里就悟道了:-a一般用在已经被add过的文件的修改上,就可以省略一次add更改到暂存区叻。这里再梳理清楚一些:这个文件第一次被git add就是到了追踪状态,也到了已暂存状态。但如果再被修改了,change会被追踪到(git status),但是这个change并没有在暂存区,也就是这个change并没有被git add。所以需要再次git add才可以将change放入暂存区,才能将最新的改动放入下一次的提交中。
notion image
HEAD所在就是当前版本。每个commit都会生成一个唯一ID标识。即每个版本在本地版本仓库都有唯一ID。
git log可以看完整ID,git log —oneline就会只有缩写生成的ID
notion image
git show的详细信息会输出:commit哈希值(版本ID的完整表示);Author(提交人和邮箱),Date(提交时间),commit message(提交的时候写的说明文字)
变更摘要(diffstat):显示本次提交中哪些文件被修改/新增/删除,每个文件按后面+/-符号代表改了多少行
具体改动内容(diff):会显示修改的前后对比,前面带-表示删除的内容,带+表示新增的内容。
git show 详解
查看第一次
notion image
现在的东西都提交完了,再次查看当前状态,已经是清空状态了:
接着我们可以尝试修改一下我们的文本文档,由于当前文件已经是被追踪状态,那么git会去跟踪它的变化,如果说文件发生了修改,那么我们再次查看状态会得到下面的结果:
也就是说现在此文件是处于已修改状态,我们如果修改好了,就可以提交我们的新版本到本地仓库中:
接着我们来查询一下提交记录,可以看到一共有两次提交记录。
 
文件忽略
我们可以创建一个叫做.gitignore文本文件(因为Git只认这个特殊的名字)来确定一个文件忽略列表,如果忽略列表中的文件存在且不是被追踪状态,那么git不会对其进行任何检查:(也就是我希望ignore文件是不去作为版本管理的文件不论怎么修改都不追踪,请Git忽略根目录下的ignore.txt文件)
Q:忽略规则什么时候生效?
A1:.gitignore 只对“未被追踪”的文件生效。如果ignore.txt还没被git add过(未被追踪),那写进.gitignore之后,Git就完全不管它了。如果ignore.txt已经被追踪了(之前git add ignore.txt 过),那即使写进.gitignore,Git还是会继续跟踪它的变化。
A2”如果一个文件已经被追踪过,所以你想让它“彻底不追踪”,要先把它移出版本控制:
注意:--cached只从暂存区/版本库移除,文件本身还留在工作目录中不会被删掉),之后再在.gitignore文件里写入ignore.txt,Git 就会彻底无视它了。
notion image
这里我们根据git status信息,解读出来是.gitignore还没被追踪ignore.txt也未被追踪(即新建了这两个文件都没有git add追踪过)。我现在编辑.gitignore文件写入ignore.txt。保存后再次运行git status。只会剩下.gitignore未追踪(因为ignore.txt已经被规则忽略了。)
notion image
这里需要区分一下Git检测规则生效和提交到仓库的两件事:
当我们在.gitignore文件里面把规则(ignore.txt写入后),保存后忽略规则就已经生效。Git会在下一次git statues时读取.gitignore的文件,判断哪些未被追踪的文件应该被忽略。此时没有提交.gitignore,那么它只在本地生效。
提交.gitignore文件:目的:把忽略规则记录到版本库,让其他人 clone 项目时也能自动忽略这些文件。如果不提交,规则只在你本地有效,别人拿到仓库不会知道。这一步是可选操作,如果我想让仓库里面的其他人也忽略该文件,那么就得提交。
💡
.gitignore是一个普通的配置文件,用于告诉Git哪些未被追踪的文件不需要管理。
  • 本地未追踪文件,写入.gitignore后Git就会忽略它们。
  • 已追踪文件,需要先git rm --cached 才能被忽略。
  • 提交.gitignore 的作用是共享规则,让别人 clone 仓库也能忽略相同的文件。
 
notion image
一些gitignore的写法例子
 

2.3 回滚

当我们想要回退到过去的版本时,就可以执行回滚操作,执行后,可以将工作空间的内容恢复到指定提交的状态:
hard:直接不保留所有文件
执行后,会直接重置为那个时候的状态。再次查看提交日志,我们发现之后的日志全部消失了。
notion image
那么要是现在我又想回去呢?但是这之前我的ID都找不到了。我们可以通过查看所有分支的所有操作记录:
这样就能找到之前的commitID,再次重置即可。
notion image
git reset —hard +ID去到想去的版本

3 分支

分支就像我们树上的一个树枝一样,它们可能一开始的时候是同一根树枝,但是长着长着就开始分道扬镳了,这就是分支。我们的代码也是这样,可能一开始写基础功能的时候使用的是单个分支,但是某一天我们希望基于这些基础的功能,把我们的项目做成两个不同方向的项目,比如一个方向做Web网站,另一个方向做游戏服务端。
因此,我们可以在一个主干上分出N个分支,分别对多个分支的代码进行维护。分支之间互不影响。

3.1 创建分支

一些Linux命令
记忆一下这些命令:ls就是list列出目录的内容。-a:all即所有文件,包括隐藏的.文件。-l:long,长格式,显示读写属性权限,用户和时间。-al:all+long,显示所有文件的详细信息
notion image
notion image
pwd:print working directory 打印当前目录
mkdir Hello:make directory 新建目录Hello,即新建一个文件夹Hello
cd:change directory 换目录的命令
ls:list列出目录内容,..列出父目录的内容,ls ../.. 父目录的父目录
notion image
notion image
 
Q1:我有点疑惑的是上一级文件夹和上一次所在的目录有什么区别 cd ..和cd -?以及这个文件夹和目录的关系我一直没有弄清楚?
A1:
  • 文件夹 vs 目录
    • 文件夹(folder)是图形界面里小黄文件夹)的叫法。
    • 目录(directory)是命令行/操作系统底层的叫法。
    • 两个是同一个东西,只是叫法出发角度不同。所以在 Linux 命令行里,我们习惯说“目录”,但脑子里完全可以想成“文件夹”。
  • cd ..
    • 来到上一级目录,即父目录。也就是所在目录的外层目录
    • 举例:/home/user/docs,如果我在docs目录里,那么我敲命令cd ..就会回到/home/user。..永远是往上爬一层。
  • cd -
    • 上一次cd进入的目录,历史位置,作用ctrl+z
notion image
Q2:Linux目录格式我也一直有一点晕?
Linux 的目录格式
 
我们可以通过以下命令来查看当前仓库中存在的分支:
我们发现,默认情况下是有一个master分支的,并且我们使用的也是master分支,一般情况下master分支都是正式版本的更新,而其他分支一般是开发中才频繁更新的。(我们在git初始化的时候设置的是main分支为主分支)
我们接着来基于当前分支创建一个新的分支:同样使用git branch命令+分支名字来创建,*所在的就是当前分支,这个-d的意思是delete
notion image
现在我们修改一下文件,提交,再查看一下提交日志:
通过添加-a来自动将原来已经追踪过的文件的修改提交到暂存区然后和commit一起执行查看日志,我们发现现在我们的提交只生效于main分支,而新创建的test分支并没有发生修改。
notion image
Head所在即为当前分支。
我们将分支切换到另一个分支:使用git checkout命令
我们会发现,文件变成了此分支创建时的状态,也就是说,在不同分支下我们的文件内容是相互隔离的。test分支里面的hello的内容没有改变。
notion image
我们现在再来提交一次变更,会发现它只生效在test分支上。我们可以看看当前的分支状态:
notion image
这里我们再复习一下git log的相关命令
git show 默认显示最近一次提交的详情,也可以指定某个commit ID,git show +ID。它比git log更详细,但一次只显示一条提交记录。

3.2 合并分支

我们也可以,我们先切换回主分支:换分支就是使用git checkout的命令。
接着使用分支合并命令:git merge 分支名,就是将分支名所对应的分支合并到当前分支上。
会得到如下提示:
在合并过程中产生了冲突,当两个分支在同一个文件的同一行都做了修改,Git就没办法自动判断该保留哪一个修改,于是就会提示冲突 (conflict)
当执行git merge后出现冲突,文件里面会出现特殊的标记:
  • <<<<<<< HEAD:表示 你当前分支的版本
  • =======:中间的分隔符。
  • >>>>>>> feature-branch:表示 要合并进来的分支的版本
notion image
我们可以查看一下是哪里发生了冲突:
notion image
需要保留哪些就留下哪些,不需要的就删除。将冲突标记(<<<<<<<, =======, >>>>>>>)都删掉,然后正常的git commit -a -m ‘’
notion image
 
notion image
这里可以看到从add ignore 分出分支,再到merge on conflict合并。但是可以看见test分支还是留在那里。
 
重新测试,如果两个分支修改的内容不在同一个文件里面。回顾最初的创建仓库,提交等等。第一次提交必须手动输入add
notion image
查看当前状态。我们是在main分支上修改了hello.text,在test分支上修改了text。
notion image
notion image
在文本里面输入merge commit.保存后关闭.
notion image
在main分支上可以看到
notion image
test分支仍然存在。并不是分支合并成一个分支,而是另外一个分支上的更改到了这个分支上。
所以这里有一个思考:Git里面的合并并不是把分支消灭。分支就是指针/标签,指向某个提交。git merge的效果是把另一个分支上的提交整合到当前分支的提交历史中。所以当前分支会前进吸收了另一个分支的内容,但是被合并的分支仍然存在不会被删除。
如果两个分支修改的是不同的文件/同一个文件的不同部分,Git就会自动合并,不会出现冲突。结果就是当前分支包含了两边的修改,另一个分支仍然存在而且可以继续使用。
如果合并完后不需要这个分支了,需要手动删除分支(这个分支上的提交更改已经被main吸收)
使用键盘上的上下键可以寻找使用过的命令
 

3.3 变基分支

除了直接合并分支以外,我们还可以进行变基操作,它跟合并不同,合并是分支回到主干的过程,而变基是直接修改分支开始的位置,比如我们希望将test变基到main上,那么test会将分支起点移动到main的最新提交:git rebase main
notion image
变基后,变成一条线了。原来的test分支的起点是first commit,现在test分支的起点是modify on main。本质上还是将两个分支合并。test分支相当于同步了此前main分支的全部提交。但注意test中的改变并没有合并到main分支中。这张图是main分支下的test内容
notion image
 

3.4 优选

cherry-pick:可以从test分支中选择一个或者多个提交,应用到另main分支上。并不会把原来的整个test分支合并到main分支上。
notion image
在main分支中修改后,又变成了两个分支。因为虽然test是基于686b这个分支,但是新的main上的修改也基于686b,所以为了区别,继续分开。
notion image
我们新建一个test2.txt,注意这里是第一次建立,则需要add和commit分开显式提交。同样的我们可以看见是在main上有这次提交44658cc。
我现在想要把add on main这次提交也生效到我的test分支上。
我们还可以选择其他分支上的提交作用于当前分支上,这种操作称为cherrypick:(ctrl c在linux里面是终止当前进程的)
这里我们在main分支上创建一个新的文件,提交此次更新,接着通过cherry-pick的方式将此次更新作用于test分支上。我们需要先git checkout test到test分支,再使用git cherry-pick id,test分支上也有这次更新(add on main)
notion image
区别于前面的变基和合并可以看出:变基和合并是将所有的更改都拿过来。优选可以选择指定更改,可以选择一个或者多个。
 
 

4 使用IDEA版本控制

虽然前面我们基本讲解了git的命令行使用方法,但是没有一个图形化界面,始终会感觉到很抽象,所以这里我们使用IDEA来演示,IDEA内部集成了git模块,它可以让我们的git版本管理图形化显示,当然除了IDEA也有一些独立的软件比如:SourceTree(挺好用)
打开IDEA后,找到版本控模块,我们直接点击创建本地仓库,它会自动将当前项目的根目录作为我们的本地仓库,而我们编写的所有代码和项目目录下其他的文件都可以进行版本控制。屏蔽target这类动态生成的
notion image
我们发现所有项目中正在编写的类文件全部变了,也就是处于未追踪状态,接着我们进行第一次初始化提交,提交之后我们可以在下方看到所有的本地仓库提交记录。
接着我们来整合一下Web环境,创建新的类之后,IDEA会提示我们是否将文件添加到Git,也就是是否放入暂存区并开启追踪,我们可以直接对比两次代码的相同和不同之处。
接着我们来演示一下分支创建和分支管理。
绿色代表新增文件,蓝色代表修改
notion image
文件白色代表没有修改
notion image
回滚
notion image
notion image
底层实现
notion image
分支,勾选了checkout,那么就会自动git checkout test//到达test分支上,书签的标记表示当前位于的分支
notion image
notion image
notion image
合并
notion image
变基
将main分支的base基于test分支的最新版本
notion image
优选(cherry-pick)
也想要将test分支上的更改放入master分支上,在master分支上也会有这个test的版本变化
notion image
notion image
 

4.1 远程仓库

远程仓库实际上就是位于服务器上的仓库,它能在远端保存我们的版本历史,并且可以实现多人同时合作编写项目每个人都能够同步他人的版本,能够看到他人的版本提交,相当于将我们的代码放在服务器上进行托管
远程仓库有公有和私有的公有的远程仓库有GitHub、码云、Coding等,他们都是对外开放的,我们注册账号之后就可以使用远程仓库进行版本控制,其中最大的就是GitHub,但是它服务器在国外,我们国内连接可能会有一点卡。私有的一般是GitLab这种自主搭建的远程仓库私服,在公司中比较常用,它只对公司内部开放,不对外开放。

4.2 远程账户认证和推送

接着我们就可以创建一个自定义的远程仓库了。
创建仓库后,我们可以通过推送来将本地仓库中的内容推送到远程仓库
  • 用于添加远程仓库,给远程仓库取一个本地的别名,方便后续操作。本质上是在告诉Git:这个远程仓库叫做name,地址是repository-url。
  • <name>:远程仓库别名,一般叫origin
  • <repository-url>:远程仓库地址,可以是HTTPS或SSH。
下面这个命令就是验证远程仓库:git remote -v(-v的意思是version)
notion image
  • <remote>:远程仓库别名,比如 origin
  • <local-branch>:你要推送的本地分支名,比如main
  • [:<remote-branch>]:可选,指定远程分支名。如果省略,默认和本地分支同名。如果我们希望推送的分支在远端没有同名的,那么需要额外指定。
示例1:推送本地main分支到远程同名分支。git push origin main
示例2:推送本地feature分支到远程dev分支。git push origin feather:dev
推送前需要登陆账户,GitHub现在不允许使用用户名密码验证,只允许使用个人AccessToken来验证身份,所以我们需要先去生成一个Token才可以。
推送后,我们发现远程仓库中的内容已经与我们本地仓库中的内容保持一致了,注意,远程仓库也可以有很多个分支。
notion image
修改一次之后,可以看到本地已经add和commit了但是远程还没有同步
notion image
需要再次提交
notion image
但是这样比较麻烦,我们每次都需要去输入用户名和密码,有没有一劳永逸的方法呢?当然,我们也可以使用SSH来实现一次性校验,我们可以在本地生成一个rsa公钥:
接着我们需要在GitHub上上传我们的公钥,当我们再次去访问GitHub时,会自动验证,就无需进行登录了,之后在Linux部分我们会详细讲解SSH的原理。
接着我们修改一下工作区的内容,提交到本地仓库后,再推送到远程仓库,提交的过程中我们注意观察提交记录:
notion image
我们可以将远端和本地的分支进行绑定,绑定后就不需要指定分支名称了:
在一个本地仓库对应一个远程仓库的情况下,远程仓库基本上就是纯粹的代码托管了(云盘那种感觉,就纯粹是存你代码的)
notion image
对应的三次提交
notion image
本地的仓库和远程仓库同步,都在modify second这个版本上
notion image
 

4.3 克隆项目

如果我们已经存在一个远程仓库的情况下,我们需要在远程仓库的代码上继续编写代码,这个时候怎么办呢?
我们可以使用克隆操作来将远端仓库的内容全部复制到本地:
notion image
这样本地就能够直接与远程保持同步。
notion image
 
注意要在这个含有git的文件夹里面打开才可使用git bash
notion image
notion image
notion image
 

4.4 抓取、拉取和冲突解决

我们接着来看,如果这个时候,出现多个本地仓库对应一个远程仓库的情况下,比如一个团队里面,N个人都在使用同一个远程仓库,每个人在本地都有一个仓库(clone下来的)。但是他们各自只负责编写和推送自己业务部分的代码,也就是我们常说的协同工作,那么这个时候,我们就需要协调。
比如程序员B完成了他的模块,那么他就可以提交代码并推送到远程仓库.这时程序员A也要开始写代码了,由于远程仓库有其他程序员的提交记录,因此程序员A的本地仓库和远程仓库不一致无法push报错:! [rejected] master -> master (fetch first),意思是:远程仓库有新的提交,你本地没有,先把它拉下来。
 
解决方案:同步远程到本地
  • 作用:从远程仓库抓取最新的提交,但不会修改你当前分支。需要手动合并
  • Git会把远程origin上所有的分支更新到本地的一个特殊空间:origin/<branch-name>,如果远程有一个master分支,那么本地就会看到origin/master。如果远程有一个main分支,那么本地就会看到一个origin/main分支。这个特殊空间(远程分支名=远程仓库别名+/+远程分支名)。
  • 查看远程分支git branch -r(这个-r的意思是remote)输出示例如下:其中origin/main就是远程main分支在本地的映射
    • 手动合并:git merge origin/main
      • 如果没有冲突的话,即远程和本地的改动不在同一个文件的同一行,Git就能自动合并。
      • 如果有冲突的话,即远程和本地同时修改了同一个文件的同一行,Git就无法判断应该保留哪一个。也就是前面<<<<HEAD 本地内容 ===== 远程内容 >>>>> origin/main
    • 优点:安全可控(可以先看到差异再决定怎么合并)
    • 本质上是git fetch和git merge的结合,先抓取再合并。
     
     
    实战演练:
    首先我们进行了A程序员的版本更改后,使用命令git commit -a -m ‘modify by A’,然后由于我们前面绑定了本地仓库和远程仓库,所以直接使用git push origin。这里出现冲突。意思是远程仓库里面有本地没有拥有内容。
    notion image
    然后我们将远程仓库的内容抓取下来 git fetch origin
    notion image
    远程仓库现在只有Modify by B这个版本,而Modify by A这个版本还在本地仓库里面。所以要讲远程的版本合并到我的本地上。git merge origin/master。写下合并的日志。wq退出。
    notion image
    然后现在才能push到远端。git push origin。此时我们的远端分支既包含B的修改又包含A的修改。
    notion image
    此时我也可以在B程序员的电脑上,git fetch origin,此时刚刚fetch的时候还处Modify by B这个版本.也就是我们前面所说的抓取到一个本地的特殊空间叫做origin/master。
    notion image
    然后git merge origin/master来同步A的更改。此时程序员B的本地仓库的版本也是远端仓库的最全版本Merge commit by A了。
    notion image
     
    比如说A改变了Hello.txt的其中一行,B改变了Hello.txt的另外一行。然后程序员A先进行了push(左侧的git)。此时B如果push就会出现reject push,就说明有人在B之前就已经推送了新的版本,和我们前面所了解的一样,是因为本地仓库的内容和远程仓库不一致导致。
    notion image
    所以解决方案有俩,一个是git fetch origin+git merge origin/master。另一个是git pull origin master。使用后者git pull origin master(拉取加合并)也是在合并的时候出现冲突confict。
    notion image
    又有一点疑惑了:为什么这里在写git pull origin啊。严格的git pull的语法是:git pull <remote> <remote-branch>,<remote>→远程仓库名,比如origin<remote-branch>→你要拉取的远程分支,比如mastermain
    这里只写了git pull origin的原因是:当有的第一次git push/clone的时候,本地分支通常会被设置为跟踪某个远程分支。例如本地的master跟踪远程的origin/master。如果当前分支已经有了默认的追踪分支,那么Git会自动推断你要pull哪个远程分支。所以git pull origin等价于git pull origin mater。
    怎么查看追踪关系:执行git branch -vv示例输出如下:
    • 表示本地master正在跟踪origin/master,即pull到远端的master分支。
    • 表示本地dev正在跟踪origin/dev,即pull到远端的dev分支。
    notion image
    notion image
     
    回到这个conflict,发生冲突是因为改变的同一个文件里面得到同一行。A删除的是i’m 3 years old,B删除的是My name is Xiao Ming.
    这里对冲突又有疑惑了:前面所说的改同一个文件的同一行就会发生冲突,不知道究竟保留哪个版本。那这里很明显啊是删除的同一个文件的不同行,为什么还是发生了冲突?
    Git冲突机制
     
    解决冲突后(比如说都删),然后再提交一次git commit -a -m ‘Modify by B finally’,然后再git push origin。
    notion image
    notion image
    notion image
    B解决冲突之后再提交到远程仓库一次。然后A再git fetch origin+git merge origin/master一次。A也可以得到最新版本了。最高版本和A的版本都是删除同一句,那么就不会发生冲突。然后高版本和A不修改第二句也不发生冲突。所以直接merge成功。【这里不要纠结merge会不会冲突,出现冲突修改就好了】
    notion image
     

    4.5 使用IDEA同步远程仓库

    notion image
    在github上修改后,远程仓库有三次修改,但是本地还是只有两次
    notion image
    notion image
    notion image
    添加权限之后,可以协同
    notion image
    如果需要获取项目,从VCS获取,输入URL后Clone
    notion image
    • IDEA中git的使用
     

    5 常用的Linux命令与补充

     
    • Git项目创建与克隆
    notion image
    notion image
     
    • Git的基本操作命令
      • notion image
        notion image
    notion image
    • /在前面代表往上忽略
    • /在后面代表往下忽略
     
    • 分支
      • notion image
    • 多个分支如果并行执行,就会导致我们代码不冲突,也就是同时存在多个版本!
      • web-api -A(Restful.xx())
      • web-admin-B 会调用A(修改了A的代码!)
      • web-app -c会调用B和A的代码
    • 如果同一个文件在合并分支时都被修改了则会引起冲突:解决的办法是我们可以修改冲突文件后重新提交.选择保留他的代码还是你的代码。
    • master主分支应该非常稳定,用来发布新版本,一般情况下不允许在上面工作。工作一般情况下在新建的dev分支上工作,工作完后,比如上要发布,或者说dev分支代码稳定后可以合并到主分支master上来。
     

    6 Git在工作场景下的常用

    6.1 SSH

    Git里和远程仓库认证相关的SSH key
    • SSH(Secure Shell)是一种加密通信协议,常用于登录远程服务器、传输文件。
    • 在Git场景下,SSH的作用是:
      • 通过密钥对(公钥 + 私钥)来完成身份认证,让你和远程仓库(如 GitHub、GitLab、Gitee)安全通信,而不用每次输入用户名和密码。
    • Git和SSH的关系
      • 当我们clone和push代码的时候,远程仓库地址有两种形式:HTTPS形式如https://github.com/username/repo.git,推送时可能要输入账号和token(令牌),简单但每次需要认证。SSH形式:git@github.com:username/repo.git。通过SSH key来认证,配置一次后即可免密登录,适合长期开发。
      • 本质就是一个令牌,让github账户认得你的设备就拥有了对代码仓库的读写。
    • 配置SSH key
      • 本地生成SSH key,在终端输入
        • 一路回车会生成
        • 私钥:~/.ssh/id_rsa(不要泄露)
        • 公钥:~/.ssh/id_rsa.pub(上传到 GitHub)
        • notion image
      • 添加SSH Key到GitHub
        • cat ~/.ssh/id_rsa.pub
        • notion image
          notion image
      • 测试SSH连接
        • notion image
      • 修改远程仓库地址为SSH
        • 如果你之前是用 HTTPS 克隆的,可以改成 SSH 地址:
          • 以后推送直接到git push origin main
       

      6.2 常用工作流

      又是叽里呱啦一大堆的Git命令

      6.2.1 仓库基础操作

      • 初始化本地仓库:git init
        • 克隆远程仓库到本地仓库:git clone

          6.2.2 提交与修改

          • 查看当前状态:git status
            • 输出结果
            • 添加文件:git add
              • 提交到本地仓库:git commit

                6.2.3 分支管理

                • 查看分支:git branch
                  • 创建新分支:git branch <分支名>
                    • 切换分支:git checkout
                      • 合并分支
                         

                        6.2.4 远程协作

                        • 拉取远程分支:git pull
                          • 这俩主要区别在于如何把远程分支的提交整合到本地分支
                          • 默认git pull的行为等价于git fetch origin main + git merge origin/main,这样会在你本地分支上产生一次merge commit(合并提交)。
                          • 而使用——rebase的行为,等价于git fetch origin + git rebase origin/main的逻辑是:把你的本地提交摘下来之后接入到最新的远程提交之后。历史会保持一条直线,不会产生额外的merge commit。
                        • 推送到本地分支或远程分支:git push
                          • 远程仓库:git remote
                             

                            6.2.5 撤销(丢弃)与急救

                            • 撤销:git checkout —— <文件>
                              • git checkout ——丢弃指定文件(这里是 src/components/Button.js)的未暂存修改,把它恢复到最近一次HEAD(最新提交)或暂存区的状态。如果这个文件修改了但是没有git add修改会直接丢掉恢复到上一次提交的版本。如果这个文件修改过后但是还没有git add,运行这个命令就会恢复成暂存区版本(而不是工作区修改),暂存区的改动会保留
                              • git checkout -- .作用:丢弃当前目录下 所有未暂存的修改,恢复到暂存区或HEAD的状态。效果就是“把工作区的改动全抹掉”。慎用,因为没有提示确认,一下子就全没了。
                              • 危险的原因是:因为它不会把改动放进回收站或者stash,而是直接丢掉,无法用git找回。
                            • 回退:git reset
                              • 提交: git commit --amend
                                 

                                6.2.6 查询与调试

                                • 日志:git log
                                  • 第二条命令详解:——graph:以ASCII字符画树状分支图,直观显示分支和合并关系。——abbrev-commit:显示简短的提交ID(通常是7位)。——decorate:在提交旁边显示分支名、tag、HEAD等引用。
                                  • 输出示例
                                 
                                 
                                 
                                • 比较:git diff
                                  • 查看:git show
                                     

                                    6.27 临时存储

                                    • 临时保存:git stash
                                      • 恢复最近一次的暂存内容:git stash pop
                                         

                                        6.2.8 实战场景示例

                                        • 场景1:误删文件
                                          • 这里只在工作区删除。git checkout HEAD表示转到当前分支的最新提交。-- important.js表示恢复这个文件。效果就是从HEAD提交里面把important.js拷贝出来,覆盖到工作区。于是这个文件就回来了,就像从来都没有删除过一样。
                                        • 场景2:提交到错误分支
                                          • 场景3:合并后想取消
                                             

                                            6.3 学习建议

                                            1. 优先掌握这些命令的常规用法,遇到特殊需求再查文档。
                                            1. -h参数快速查看帮助git push -h
                                            1. 常用别名配置(在~/.gitconfig中添加):
                                            记住:不要试图背诵所有命令,就像你不会记住所有手机App的功能一样。实际开发中遇到问题时,只需要:
                                            1. 明确你要达到什么目的(例如"撤销上次提交")。
                                            1. 搜索"git 如何撤销上次提交" 。
                                            1. 找到对应命令(比如git reset HEAD~1) 。
                                            1. 查看文档确认用法。
                                            附一张常用命令的思维导图供参考:
                                            C2驾驶证考试1-1-1 用Keil点亮一盏小灯
                                            Loading...