分布式版本控制工具Git

版本控制的概述

版本控制可以完成不同版本的存储管理、重大版本的备份维护、恢复之前的项目版本、记录项目的每处修改、多人开发的代码合并。

分布式版本控制

早期的CVN与SVN采用的都是集中式版本控制,使用单台服务器管理整个项目的开发进程,开发人员通过服务器提交或下载最新版本的文件。这样的作法会造成开发过程容错率低,服务器一旦出错则无法正常开发。

Git采用分布式版本控制,客户端在下载项目时不只是下载最新的文件,同时也将整个项目的代码仓库完整下载,包括历史记录。此时如果服务器发生故障仍可通过客户端进行项目的恢复。

Git的安装

git-scm.com/download/wi...

安装过程中会安装Git Bash、Git CMD、Git GUI。bash是windows下的命令行工具,支持linux命令,比CMD更强大。Git CMD的功能与Windows的CMD无异。Git GUI则是图形化操作界面。

配置邮箱和用户名

git安装完毕后需进行邮箱和用户名的配置才可以使用,如下。

shell 复制代码
git config --global user.name="lin" //--global代表所有项目均使用该配置
git config --global user.email="1419@qq.com"

获取Git仓库

获取Git仓库有两种方式,如下。

  1. 本地新建仓库

    bash 复制代码
    git init
  2. 从Git远程仓库获取

    bash 复制代码
    git clone http://123.1.1/a.git
    //注意,该命令只会clone远程仓库中的master/main分支,其他分支无法clone

Git文件状态

文件状态分为未跟踪和已跟踪两个状态。未跟踪的文件需要使用git add .进行文件的跟踪。已跟踪的文件分为staged暂存区状态(使用add命令后的状态)、unmodified未修改状态(使用commit命令后的状态)、modified修改状态(修改文件但未add的状态)。

每次新建文件或者修改文件后想要记录时,都需要使用如下命令。

bash 复制代码
git add . //将所有文件添加至暂存区
git commit -m "新增修改" //提交文件

add与commit命令可以简写,如下。

shell 复制代码
git commit -a -m "新增修改"

可以使用git status命令查看当前文件的状态,工作区为空状态,即所有文件都已被提交至Git,属于一种安全状态。如下图。

未跟踪untracked状态文件如下图。

将文件add至暂存区后,文件变为staged暂存区状态,如下图(本图中的unstaged改为staged)。

修改a.js并add后,文件变为staged暂存区状态,如下图。

修改a.js后,文件变为modified被修改状态,如下图。

.gitignore配置文件

使用git add .命令可以将文件均添加至git仓库,但是总有那么些文件不需要被添加,比如node_modules文件夹中的内容,此时便可使用.gitignore配置文件来忽略指定文件的添加。实际开发中脚手架会配好。

日志

使用git log可以查看每次提交的历史,效果如下图。

由上图知无用信息过多,且记录之间空行太多,因此可以使用git log --pretty=oneline查看更加简洁的信息并且每条记录都在一行显示。如下图。

另外,可以使用图结构进行展示,即使用git log --pretty=oneline --graph,在使用分支时才有效果(后面学习)。

版本回退

git使用HEAD指针指向当前分支,可以通过移动HEAD指针实现回退至某个版本,命令如下。

shell 复制代码
git reset --hard HEAD^ //回退到上个版本
git reset --hard HEAD^^ //回退到前个版本
git reset --hard HEAD~8 //回退到前8个版本
git reset --hard 8efabd //回退到commit id为8efabd对应的状态,一般使用commit id的前七八位即可(前七八位不和其他id前七八位重复的情况下)

使用git reset命令回退后再使用git log命令查看会发现该版本之后的所有版本都消失不见,如下图。

此时可以使用git reflog命令展示所有操作记录,回退到c版本之后的版本。效果如下。

常见的远程仓库

常见的远程仓库有Github、Gitee、自己搭建Gitlab。

如果想要对远程仓库进行访问或操作,需要有相应的权限。git验证手段有http连接和SSH连接。

  1. http连接:输入远程仓库中自己的账号密码,但是由于http默认短连接,因此用户名和密码需要通过其他方式存储起来(缓存、凭证等)以便操作远程仓库时自动携带验证信息。使用http进行关联的步骤如下。

  2. ssh连接:ssh连接采用非对称加密的形式,客户端保存私钥,服务端保存公钥,客户端使用私钥加密数据,服务端采用公钥解密;服务端使用公钥加密数据,客户端采用私钥解密;

    首先使用如下命令生成一对公钥和私钥:

    shell 复制代码
    ssh-keygen -t ed25519 -C "your email"
    //ed25519是一种加密方式
    //-C代表注释,一般用email作注释

    输入命令后会有对应的选项,包括保存的路径以及访问密码,一般使用默认即可。

    之后即可生成对应的公钥和私钥,git会显示其保存的路径,如下图。

    然后在服务端中保存这个公钥,gitee中点击设置->SSH公钥,如下图。

在连接后,可以使用git remote -v|--verbose进行远程仓库的连接情况查询。

与远程仓库的同步

与远程仓库的同步分为pull和push操作。

从远程仓库同步至本地

git pull命令用于项目从远程仓库同步至本地当前分支,该命令实际上是git fetch加上git merge的简写,即先下载至仓库再进行合并。

bash 复制代码
git pull origin master //origin为远程仓库名,master为远程分支名

每次都需要指定远程仓库名和远程分支名比较麻烦,因此,可以为本地分支设置上游分支,来进行pull命令的简写。

bash 复制代码
git branch --set-upstream-to=origin/master //设置当前分支的上游分支为远程仓库origin下的master分支
git pull //设置完后再使用pull命令时即可不用传递参数

注意,使用clone创建的本地仓库是不用指定上游分支的,会自动将本地进行远程关联。因此,在clone后执行git pullgit push是不用带参数的。

另外,在git2.9版本之后使用merge操作时是无法合并没有相同祖先分支(base)的两个分支的。如下图。

如果想要在没有共同base的情况下强行合并,可以使用如下命令。

bash 复制代码
git merge origin/master --allow-unrelated-histories
//--allow-unrelated-histories选项只需全局执行一次
//一般origin/master代表已经fetch至本地仓库的origin仓库中的master分支
//origin master代表远程仓库中的master分支

从本地同步至远程仓库

git push命令用于项目从本地同步至远程仓库,命令如下。

bash 复制代码
git push origin master //push至origin远程仓库的同名分支master分支
//若指定了上游分支则不需要带参

git push命令有自己的默认配置,push的默认配置为simple,详解如下(以下情况均假设本地有master分支,远程有main分支)。

  1. 如果单用不带参的git push命令,默认将本地当前分支推送至远程服务器的同名分支,会报错。
  2. 如果写git push origin master默认将本地master分支推送至远程服务器的master分支,会报错。
  3. 如果写全称git push origin master:main则是将本地master分支推送至到远程服务器的main分支,将成功推送。

默认配置可以更改,为master分支设置了上游分支为origin/main后,可将默认配置更改为upstream,配置以后则可以直接写不带参的git push命令将本地master分支直接推送至远程仓库下的main分支。更改push默认行为为upstream的命令如下。

bash 复制代码
git config push.default upstream

使用git进行管理的三种情况总结

项目已搭建好

当项目已搭建好并存在于远程仓库时,命令如下。

bash 复制代码
git clone [location]
---编写代码中,这个期间别人可能上传了最新代码---
git commit -a -m "c1" //提交自己代码
git pull //获取别人在这期间上传的最新代码并进行合并
git push //上传至远程仓库

项目须由自己搭建

当项目项目须由自己从零开始搭建时,有两个方案。

  1. 在服务器先创建远程仓库,然后本地clone,命令如下。

    bash 复制代码
    ---创建远程仓库中---
    git clone [location]
    ---编写代码中,这个期间别人可能上传了最新代码---
    git commit -a -m "c1"
    git pull //获取别人在这期间上传的最新代码并进行合并
    git push
  2. 本地仓库进行初始化,同时服务器有创建一个远程仓库,即此时本地和远程各有一个仓库,没有相同的base。(假设此时本地为master分支,远程仓库为main分支,所有推送均需推送至远程main分支)

    bash 复制代码
    git init //创建本地仓库
    git remote add [location] //关联至远程仓库
    git fetch origin master //获取别人在这期间上传的最新代码
    git branch --set-upstream-to=origin/main //设置当前分支的上游
    git merge --allow-unrelated-histories //无相同base情况下强行合并代码
    //注意,直接执行git pull命令代替fetch+merge会出错,因为无相同的base
    //  疑惑:为啥不是origin master ??
    ---编写代码中,这个期间别人可能上传了最新代码---
    git commit -a -m "c1" 
    git pull //下载远程仓库最新代码并合并
    git config push.default upstream //配置push的默认行为
    git push

    以上命令总是将本地master分支与远程main分支联系显得较别扭,因此常常在本地新建main分支并指定该main分支关联至远程main分支即可避免繁琐的操作。命令如下。

    bash 复制代码
    git remote add [location]
    git fetch
    git checkout --track origin/main //该命令先检查远程仓库中是否有对应main分支,有则创建对应本地分支并跟踪,且会自动切换至该分支
    ---编写代码中,这个期间别人可能上传了最新代码---
    git commit -a -m "c1"
    git pull
    git push

开源协议

常见的开源协议及其内容如下图。

tag标签

如果有比较大的更新提交,往往会给该版本打上标签,即tag。否则过多的commit操作中往往难以区分重大版本的更新。本地操作生成的tag是无法直接推送至远程仓库的,需要写上对应参数。

本地tag操作

本地打上标签的命令如下。

bash 复制代码
git tag v1.0.0
git tag -a v1.0.0 -m "重大版本更新1"

删除标签的命令如下。

bash 复制代码
git tag -d v1.0.0

将本地tag与远程仓库tag同步

tag想要推送至远程仓库时,需要在push操作时显式指定,命令如下。

bash 复制代码
git push origin v1.0.0
git push origin --tags //所有tag均推送至远程仓库

但是从远程仓库拉取至本地时,使用不带参的git pull命令是可以直接下载远程仓库中的tag的。

删除远程仓库的tag的命令如下。

bash 复制代码
git push origin -d v1.0.0 //-d是--delete简写

基于某个tag进行开发

想要查看对应某个标签指向的文件版本,可以使用git checkout命令,命令如下。

bash 复制代码
git checkout v1.0.0
---新建分支并开发中---

git分支

使用git分支的流程

假设有如下场景:

项目经过依一定次数的commit后开发出了v1.0.0版本并上线。如下图。

然后,基于当前的master分支继续进行开发新功能,如下图。

此时,v1.0.0版本的项目经过用户反馈后存在bug,那么由于master分支正在开发新功能,去改动不符计划内的代码是不合适的,因此会在v1.0.0标签对应的提交下,新建一个用于改bug的分支(重点),并进行bug的修复。新建分支如下图。

然后基于该分支进行bug的修复,生成了v1.0.1版本,如下图。

修复BUG的相关命令如下。

js 复制代码
git checkout v1.0.0 //切换至tag v1.0.0所指向版本
git branch branch1 //新建分支1
git checkout branch1
---修复BUG中---
git commit -a -m "修复BUG" //提交修复
git tag v1.0.1 //修复后上线1.0.1版本,master分支继续完成新功能的开发

最后,再将该分支对应的修复结果合并至主分支master上即可。合并命令如下。

bash 复制代码
git merge branch1

合并后,可能会产生冲突,对于产生冲突的文件,如下图。

有如下几种解决方案。

  1. 手动删除无效字段。将文件中<<<<head和=====等。
  2. ide的自动合并。

合并后再一次提交commit(合并branch1)的图示如下。

使用git log --pretty=oneline --graph以图结构展示提交记录的结果如下图(本质上同上图)。

与分支相关常用命令

bash 复制代码
git branch //查看分支
git branch -v //同时查看最后一次提交
git brach --merged //查看所有合并到当前分支的分支
git brach -d brach1 //删除branch1分支

常见分支解释

  1. master分支

    master分支作为主分支,通常接收来自development分支的合并,使得master分支下的日志记录清晰明了。

  2. develop分支

    develop分支用于开发分支,常常伴随着许多次提交,在有稳定的版本时会合并至master分支。

  3. topic分支

    topic分支作为某个主题分支,开发需求中的不定性等都会使用该分支,完成开发后会合并至develop分支,但是否完成也具有不定性。

git工作流

由于git分支的便捷性产生了许多git工作流。

小公司常用工作流
大公司常用工作流

使用git clone操作克隆的只是远程仓库中的main/master分支,无法clone其他分支如develop,因此想要在develop分支进行开发,可以使用git checkout --track origin/develop,该命令先检查远程仓库中是否有对应develop分支,有则创建对应本地分支并跟踪,且会自动切换至该分支。使用该命令进行正式开发有如下两种情况。(假设本地无对应仓库,远程仓库中已有develop和main分支)

  1. 加入项目开发时远程仓库中已有对应代码,本地仓库无代码,命令如下。

    bash 复制代码
    git clone [location]
    git checkout --track origin/develop //创建+跟踪+切换至develop进行开发
    ---开发中,别人可能上传了最新代码---
    git commit -a -m "c1"
    git pull
    git push //默认模式simple,此时由develop push至远程仓库下的develop
  2. 加入项目开发时远程仓库和本地仓库中均已有代码,命令如下。

    bash 复制代码
    git init
    git remote add [locaiton]
    git fetch
    git checkout --track origin/develop
    ---开发中,别人可能上传了最新代码---
    git commit -a -m "c1"
    git pull
    git push //默认模式simple,此时由develop push至远程仓库下的develop

git rebase变基(了解)

常用的合并分支方法有git mergegit rebase,下面论述下两者的区别。

假设现有feature和develop分支,各自提交情况如下。

提交记录如下图。

此时想要合并feature分支至develop分支上,可以在develop分支下使用git merge feature 合并feature分支。

合并后的图示如下。

提交记录如下图,可见,在记录中呈现树形结构。

这里有个问题,有些开发场景中并不想要如上的树形结构,而是更喜欢线性结构,因此可以在feature分支中使用git rebase命令代替git merge命令。变基后的图示如下。

在feature中查看提交记录如下图,可见,在记录中呈现线性结构。

此时的develop分支仍然指向dev3,为使develop分支指向f2版本,可以在develop分支中使用git merge。merge后的图示如下。

HEAD指针同时指向feature和master,如下图。

总的变基命令如下。

bash 复制代码
git checkout develop
git commit -a -m "dev1"
git commit -a -m "dev2"
git branch feature //新建feature分支
git checkout feature //切换至feature分支
git commit -a -m "f1"
git commit -a -m "f2"
git checkout develop
git commit -a -m "dev3"
git checkout feature
git rebase develop //变基
git checkout develop 
git merge feature //合并feature分支

实际可以看出来rebase不太好用的,实际开发较少使用。

注意,永远不要在master分支里面使用rebase命令,会造成混乱。

相关推荐
Good_Starry12 小时前
Git介绍--github/gitee/gitlab使用
git·gitee·gitlab·github
云端奇趣17 小时前
探索 3 个有趣的 GitHub 学习资源库
经验分享·git·学习·github
F_D_Z21 小时前
【解决办法】git clone报错unable to access ‘xxx‘: SSL certificate problem:
网络·git·网络协议·ssl
等风来不如迎风去1 天前
【git】main|REBASE 2/6
git
艾伦~耶格尔1 天前
IDEA 配置 Git 详解
java·ide·git·后端·intellij-idea
云兮杜康1 天前
IDEA中用过git之后文件名颜色全变红
java·git·intellij-idea
睡不醒的小泽1 天前
git merge 和 git rebase
git
艾伦~耶格尔1 天前
Git 下载及安装超详教程(2024)
git·gitee·码仓
weixin_438197381 天前
linux部署redis,整合ansible和redis
linux·redis·git
安全在心中1 天前
gitee公钥设置、创建库及使用
git·gitee