VCS(版本控制系统)

Git基础

关于git的详细介绍,可以参考官网的Git Book

Git安装

不同系统上git的安装流程 ,参照官方文档

Git配置

Git 自带一个 git config 的工具来帮助设置控制 Git 外观和行为的配置变量

config作用域

1
2
3
4
5
6
7
8
git config --local #只对某个仓库有效,该命令只能在某个git repository内部使用,在仓库内部--local的配置优先级会大于--global的配置
git config --global #对当前用户的所有仓库都有效
git config --system #对系统所有登录的用户都有效

#显示指定作用域的config配置,只需加 --list
git config --list --local #只该命令只能在某个git repository内部使用,查看某个具体的仓库的配置
git config --list --global
git config --list --system

配置用户信息

安装完 Git 之后,要做的第一件事就是设置你的用户名和邮件地址。 这一点很重要,因为每一个 Git 提交都会使用这些信息,它们会写入到你的每一次提交中,不可更改

1
2
git config --global user.name "your_name"
git config --global user.email "your_email"

查看配置信息

1
git config --list

image-20240506152643834

新建Git仓库

新建git仓库的两者场景

方法一:将已有的代码文件纳入git管理

1
2
进入已有的项目文件夹,执行:
git init

方法二:新建一个直接用git管理的新文件夹

1
git init 文件夹名 #其会在当前目录下新建一个新的文件夹,并加此文件夹纳入git管理

git工作区域的理解

img

Git本地有四个工作目录,这四个工作目录之间的状态转换关系如上图所示

  • Workspace:工作区,本地存放项目的文件夹
  • Index/Stage:暂存区,用于存放临时改动的记录
  • Repository:仓库区/版本库,里面会存放所有提交的版本数据
  • Remote:远程仓库,比如Github上的仓库,我们可以通过相关命令把本地文件推送到远程仓库

我们通常直接操作的目录就是工作目录,然后将需要用git进行管理的文件或者文件夹,通过git add 文件名..放入暂存区,通过git commit -m 标记将暂存区文件提交至本地仓库,通过git push将本地仓库推送到关联的远程仓库

git文件状态理解

版本控制是对文件进行版本控制,所以要明确当前操作文件所处的状态,在git中文件有四种状态

  • untrack
    • 未跟踪, 此文件在文件夹中, 但并没有加入到git库, 不参与版本控制. 通过git add 状态变为Staged
  • modified
    • 修改过,针对的就是已经登记在案的文件最近又发生了改动的情况,也就是说我们最近改过了某一个之前已经登记在案的文件
  • committed
    • 执行完commit之后,会在仓库中生成一个版本号(hash值),标志这次提交。之后任何时候,都可以借助这个hash值回退到这次提交。
  • stage
    • 这个时候已经执行过git add,但未执行git commit,但是用git diff已经看不到任何修改。

Git常见实操

场景一:从头创建一个新的仓库

在项目中新建文件以及文件内容修改

在C盘下创建目录git_learning,进入该目录执行git init,可以看到生成了一个隐藏文件夹.git,此时git_learning文件夹就成为了一个版本库,里面的文件都可以被git管理,即每个文件的修改、删除都能被git跟

image-20240506195103057

在版本库(本地仓库)中添加新的文件

我们在git_learning文件夹下新建一个hello.txt文件,里面内容为v000000

image-20240506200840972

执行git add hello.txt将该文件提交到暂存区

image-20240506200930083

执行git commit -m xxx将文件提交到仓库

image-20240506201100485

每次执行git status可以查看文件的状态

hello.txt文件进行修改,将v000000改为v111111

image-20240506201330714

我们可以通过执行git diff 文件名的方式查看文件中到底改动了什么内容

image-20240506201453188

知道文件修改内容之后,如果无误,可以重新对文件提交到暂存区和仓库

image-20240506201707786

场景二:文件版本回退

前面我们对hello.txt文件进行了修改,前后一共提交了两次

现在我们对文件再次修改,将文件内容改为v222222,并提交,我们前后对该文件修改了两次,该文件存在三个不同的版本

我们可以通过git log查看历史提交记录

image-20240506202044597

那么如果我们现在想把文件内容恢复到前面的某个版本,该怎么做?

git中回滚到历史版本的命令:

  • git reset --hard HEAD^:回退到当前的上一个版本
  • git reset --hard HEAD^^:回退到当前的上上一个版本
  • git reset --hard HEAD~n:回退到当前的前n个版本
  • git reset --hard 版本号:可以精准回退到某个具体的版本记录

image-20240506202650087

可以看到回滚之后,git log看不到第三次提交的记录,那么如果我们想恢复到第三版记录(即内容为v222222),该怎么做?

我们可以先通过git reflog查看版本号,然后回滚到指定版本

1
Git 的 reflog 是指引用日志(reference logs)的简称,它记录了 Git 仓库中 HEAD 引用的变化历史。换句话说,reflog 记录了本地仓库的操作历史,包括分支切换、合并、重置等操作,即使在一些操作后出现了提交丢失或者分支丢失的情况下,通过 reflog 也可以找回之前的状态。

image-20240506203046924

场景三:撤销文件修改与恢复被删除文件

我们修改hello.txt文件,将其内容改为了v333333,此时未执行其他命令,文件处于工作区,我们发现内容修改错了,想恢复到原始内容v222222,该怎么做?

此时有三种解决办法:

  • 直接修改hello.txt,将内容修改为原始内容
    • 此方法缺陷在于,如果原始内容较多,不记得了该怎么办?无法手动恢复
  • 将错就错,执行git addgit commit将文件提交仓库,再执行git reset --hard HEAD^回滚到上一版本
  • 执行git checkout -- 文件名,可以把文件在工作区的修改全部丢弃

image-20240506203932209

我们在git_learning目录下新建一个文件test.txt,然后将其提交到仓库,然后将该文件删除,那么我们如果想将该文件恢复应该怎么做?

  • 方法1:git commit然后git reset
  • 方法2:git checkout -- test.txt,可以直接在版本库中恢复此文件

image-20240506204655377

场景四:本地仓库与远程仓库的关联

git配置连接github

我们在GitHub上新建一个仓库git_learning,可以通过如下操作,将本地仓库与远程仓库关联起来,并将本地仓库推送到远程仓库

1
2
git remote add origin xxxxx.git #本地仓库与远程仓库
git push -u origin master #将本地仓库master分支推送到远程仓库

场景五:创建和管理分支

在我们实际代码开发过程中,一个项目可能会衍生出多个版本或者类型,但不同版本可能依赖的主体核心代码一致,只是不同版本的部分功能可能不一样,这个时候我们就需要将核心代码的部分生成多个分支用于支持不同版本程序的开发

或者同一项目多人协作,一般是不会直接允许在master(主分支)上进行开发,而是先在主分支上克隆一份,等个人开发完毕后再合并到主分支,这样可以避免代码污染等对主分支造成破坏

git branch -a列出所有本地分支和远程分支

git branch列出所有本地分支

git branch -r列出所有远程分支

image-20240506213127779

git branch 分支名创建分支

image-20240506213656875

git branch -d 分支名删除分支

git checkout 分支名将当前项目切换为指定分支

image-20240506213823140

将当前新的分支推送到远程仓库(当前本地分支first推送到远程仓库的分支名也应该叫first)

git push --set-upstream origin first

image-20240506214230927

在本地first分支上的修改不会影响本地和远程master分支上的内容

观察下面两张图,我们本地将分支切换回master,可以发现本地的tt.txt文件就会自动消失

image-20240506214738664

image-20240506214808174

如何合并多个分支?

在实际项目开发过程中,我们在自己分支上进行开发,最后要部署测试时,需要将自己分支代码合并到主分支应该怎么做?

我们首先执行git checkout master切换回主分支

执行git merge first将当前分支(主分支)与first分支代码合并

执行git push将本地主分支代码推送到远程仓库主分支

image-20240506215256645

场景六:团队协作与代码冲突解决

团队仓库如何进行git协作

团队仓库可以添加多名成员同时协作,注意此时各个成员在本地操作之前最好使用

git pull将仓库最新代码拉取到本地,保证线上仓库与本地仓库的一致性

对于团队协作,我们的提交顺序:

  1. 刚开始进行项目开发时,使用git pull拉取更新
  2. 项目代码开发完毕之后,先git addgit comiit到本地仓库
  3. push之前再使用git pull确保当前远程仓库所有更新都已经获取
    • 这样做是为了避免冲突,因为如果两个人同时操作了一个文件的变更,这时就会出现协作冲突,git此时不知道到底要使用哪一个人的变更,所以它会将两个人提交的不同部分标记出来
  4. 最后再git push将本地仓库推送到远程仓库

Git开源项目或者团队项目协作场景

如何进行Github团队项目的协作?

背景

我们准备两台不同的电脑,每台电脑登陆不同的github账号,模拟团队中的不同项目成员,由其中一个成员在github上创建一个公共仓库,然后邀请另一个账号(成员)协作。github创建团队项目team-work、并且邀请团队成员如下图所示

image-20240604234532722

image-20240604234406883

团队协作整个流程

一般团队协作各个成员是不允许直接在main(master)分支上直接操作,都是各自简历一个新的分支来进行

下面来模拟两个成员A和成员B如何协作团队项目

仓库最初的状态如下图所示,三个文件,以及test.txt中的内容如下图所示:

image-20240605100946687

image-20240605101127141

下面模拟团队协作,成员A的任务:创建新的文件testA.txt、在原始的test.txt最后一行添加I am member A

成员B的任务:创建新的文件testB.txt、在原始test.txt最后一行添加I am member B

然后两个成员各自提交到远程仓库对应的分支,然后由管理员B来进行分支合并和冲突问题解决

成员A

  • 拉取项目到本地
    • git clone 远程仓库地址
  • 在本地创建自己的分支
    • git checkout -b 自己的分支名
  • 进行文件修改或者相关文件添加
  • 提交到远程仓库
    • git push origin 自己的分支名

image-20240605102708908

image-20240605102814850

成员B

  • 拉取项目到本地
    • git clone 远程仓库地址
  • 在本地创建自己的分支
    • git checkout -b 自己的分支名
  • 进行文件修改或者相关文件添加
  • 提交到远程仓库
    • git push origin 自己的分支名

image-20240605103558966

image-20240605103623151

仓库合并

当前仓库状态:

image-20240605103656896

成员可以在Github上创建pull request请求,让原作者(管理员人)看到你的修改,然后管理员会review代码文件,解决合并冲突,然后会执行Squash merge将对应分支代码合并到main(master)分支

对于分支memberA的处理

image-20240605103729459

image-20240605103758042

image-20240605103848407

image-20240605103949299

对于分支memberB的处理

image-20240605104109678

由于分支A与分支B都在同一文件test.txt中做了修改,所以会发生合并冲突,需要解决冲突才能合并

image-20240605104152827

image-20240605104330474

解决冲突,同时保留A和B的修改(删除文件中所有的分隔符即可)

image-20240605104508244

image-20240605104547186

image-20240605104614032

此时main分支中包含了A和B两者提交和更改的所有记录

image-20240605104708323

image-20240605104839138

各个成员如何同步远程最新的代码

远程main(master)仓库更新后,各个成员本地git与远程仓库不一致,需要拉取远程main仓库最新状态,然后与本地自己的分支合并,同步最新状态

仓库主分支main中内容发生了变更,此时成员A需要同步远程仓库最新状态,并在最新状态上做修改,那么他应该怎么做?

  • 本地切换到main分支git checkout main
  • 拉取远程仓库main分支最新内容到本地git pull origin main
  • 切换到自己的分支git checkout memberA
  • 将main分支与自己的分支进行合并git rebase main
  • 后续在最新状态上重复前面正常操作即可

image-20240605105913293

image-20240605110117907

参考资料

如何作为Collaborator在Github更新仓库(上传代码)

十分钟学会正确的github工作流,和开源作者们使用同一套流程

详解Git合并冲突——问题重现、原因及解决 “Automatic merge failed; fix conflicts and then commit the result.“

参考资料

Pro Git

Git使用教程,最详细,最傻瓜,最浅显,真正手把手教