Skip to content

Git

Always use source code control. ---Andrew Hunt 程序员修炼之道

版本控制

什么是版本控制?我们为什么要关心它呢? 版本控制系统(Version Control System)是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。 在本书所展示的例子中,我们仅对保存着软件源代码的文本文件作版本控制管理,但实际上,你可以对任何类型的文件进行版本控制。

如果你是位设计师,可能会需要保存某一幅图片或页面布局文件的所有修订版本(这或许是你非常渴望拥有的功能)。采用版本控制系统(VCS)是个明智的选择。有了它你就可以将某个文件回溯到之前的状态,甚至将整个项目都回退到过去某个时间点的状态。你可以比较文件的变化细节,查出最后是谁修改了哪个地方,从而找出导致怪异问题出现的原因,又是谁在何时报告了某个功能缺陷等等。

使用版本控制系统通常还意味着,就算你乱来一气把整个项目中的文件改的改删的删,你也照样可以轻松恢复到原先的样子。但额外增加的工作量却微乎其微。

本地版本控制系统

为了解决上面提到的问题,人们很久以前就开发了许多种本地版本控制系统,大多都是采用某种简单的数据库来记录文件的历次更新差异。

其中最流行的一种叫做 rcs,现今许多计算机系统上都还看得到它的踪影。甚至在流行的 Mac OS X 系统上安装了开发者工具包之后,也可以使用 rcs 命令。它的工作原理基本上就是保存并管理文件补丁(patch)。文件补丁是一种特定格式的文本文件,记录着对应文件修订前后的内容变化。所以,根据每次修订后的补丁,rcs 可以通过不断打补丁,计算出各个版本的文件内容。

集中化的版本控制系统

接下来人们又遇到一个问题,如何让在不同系统上的开发者协同工作?于是,集中化的版本控制系统( Centralized Version Control Systems,简称 CVCS )应运而生。这类系统,诸如 CVS,Subversion 以及 Perforce 等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。多年以来,这已成为版本控制系统的标准做法。

事分两面,有好有坏。这么做最显而易见的缺点是中央服务器的单点故障。如果宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。要是中央服务器的磁盘发生故障,碰巧没做备份,或者备份不够及时,就会有丢失数据的风险。最坏的情况是彻底丢失整个项目的所有历史更改记录,而被客户端偶然提取出来的保存在本地的某些快照数据就成了恢复数据的希望。但这样的话依然是个问题,你不能保证所有的数据都已经有人事先完整提取出来过。本地版本控制系统也存在类似问题,只要整个项目的历史记录被保存在单一位置,就有丢失所有历史更新记录的风险。

分布式版本控制系统

于是分布式版本控制系统( Distributed Version Control System,简称 DVCS )面世了。在这类系统中,像 Git,Mercurial,Bazaar 以及 Darcs 等,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。因为每一次的提取操作,实际上都是一次对代码仓库的完整备份。

安装 Git

MacOs

Mac OS 最近版本中,已经内置了 git 工具,无需安装。但也可以通过 HomeBrew 安装最新的版本。

Bash
brew install git

Windows

Windows 上安装 Git 非常简单,可以到 Git - Downloading Package (git-scm.com) 下载安装文件。完成安装之后,就可以使用命令行的 Git 工具,而且还集成了 SSH 客户端和图形界面的 Git 管理工具。

建议在安装Git时,选择勾选整合到终端的选项。

还可以使用包管理工具 WinGet 进行安装:

bash
winget install Git.Git

Git基本概念和常用命令

关键概念

有几个关键概念,理解之后,对于使用 Git 有很大帮助。

git

git是目前广受欢迎的分布式版本管理工具。

仓库

所谓仓库,就是带有Git工具所需信息的文件夹(删除其中的.Git隐藏目录后,该目录也就变成了普通目录)。所有的 Git 操作,使用命令行工具时,需要进入到仓库(也就是目录中)才可以正确执行。

本地电脑中的三个区域

Git 是分布式版本控制系统,本地电脑就是一个完整的版本控制系统,由工作区、暂存区、本地仓库三个区域组成,所谓区域都是逻辑上的划分,并不会文件系统中可见。

工作区

工作区就和正常的目录是一致的,我们可以在里面创建文件和文件夹,进行存放、删除、修改等操作。

暂存区

暂存区存放修改过的、打算存放到本地仓库的、让版本控制系统记录的各种文件,为什么不直接将修改后的文件存放到本地仓库呢?因为有些修改、有些文件可能不值得、或者不应该存放到本地仓库。暂存区给了用户更多的灵活性。

本地仓库

存放经过确认之后的文件详细信息。本地仓库保留有完整的修改历史,在内容上和远程仓库是一致的。

远程服务器

远程服务器的作用,主要是在网络中存放数据,以便和他人共享。远程服务器中通常只有远程仓库。

Git 命令

常用 Git 命令

命令功能
git init初始化 Git 仓库
git clone下载远程仓库到本地(包含所有历史信息)
git pull取回远程仓库的变化,并与本地分支合并(相当于 fetch + merge )
git add添加本地文件到暂存区
git commit确认变化信息,提交到本地仓库
git push推送代码到远程库
git diff显示暂存区和工作区的差异
git checkout切换到指定分支
git fetch下载远程仓库所有变动到本地
git merge合并指定分支到当前分支

Git核心语句

命令功能
git clone下载远程仓库到本地(包含所有历史信息)
git pull取回远程仓库的变化,并与本地分支合并(相当于 fetch + merge )
git add添加本地文件到暂存区
git commit确认变化信息,提交到本地仓库
git push推送本地仓库到远程仓库

Git 常用工作流程

常用流程

简化流程

对于简单的个人项目,只需四个常用操作即可:

仓库连接协议

Git 支持多种仓库的连接协议,其各自的优缺点如下:

本地协议:相关于硬盘内的另一个目录

优点:基于文件系统的版本库的优点是简单,并且直接使用了现有的文件权限和网络访问权限。

缺点:通常共享文件系统比较难配置,并且比起基本的网络连接访问,这不方便从多个位置访问。

HTTP协议:通过 HTTP 通信

优点:不同的访问方式只需要一个 URL 以及服务器只在需要授权时提示输入授权信息,这两个简便性让终端用户使用 Git 变得非常简单。

缺点:在一些服务器上,架设 HTTP/S 协议的服务端会比 SSH 协议的棘手一些。不做设置时,每次都需要输入用户名和密码信息才能完成推送操作。

SSH协议:使用SSH 协议作为传输协议

优点:SSH 架设相对简单 —— SSH 守护进程很常见,多数管理员都有使用经验,并且多数操作系统都包含了它及相关的管理工具。 其次,通过 SSH 访问是安全的 —— 所有传输数据都要经过授权和加密。 最后,与 HTTP/S 协议、Git 协议及本地协议一样,SSH 协议很高效,在传输前也会尽量压缩数据。

缺点:不能匿名访问。

Git协议

Git 协议包含在 Git 里的一个特殊的守护进程;它监听在一个特定的端口(9418),类似于 SSH 服务,但是访问无需任何授权。

优点:Git 协议是 Git 使用的网络传输协议里最快的。

缺点:Git 协议缺点是缺乏授权机制。

Git使用FAQ

如何将符号链接目录视为正常目录

在安装Git时,选择处理符号链接,则可将符号链接目录视为正常目录。

如何使用Git子模块

什么要使用子模块

在仓库中单独发布某个目录,如电子书编译之后的HTML、PDF等,或在仓库中使用别人的仓库作为项目的组成部分,如在博客中使用某个第三方主题时,需要使用子模块。

子模块使用要点

  1. 在主仓库中添加子仓库。使用git submodule add repo subdir命令在当前主仓库目录中添加位于repo的远程仓库,将该仓库克隆到主仓库的subdir目录中。例如:git submodule add --force https://gitee.com/yangjh/html.git 02-job/0201-教学/统计与数据分析/_build/html
  2. 主仓库的操作照旧,在主仓库目录下,操作的是主仓库内容;
  3. 进入子仓库cd third_party/subdir 后操作的便是子仓库内容。添加更新操作与正常仓库一致。

更新子仓库

bash
git submodule update --remote

如何忽略项目中的特定文件

在项目中,总会有一些特定的文件不想采用 Git 工具进行版本的控制,如临时文件、编译时产生的过渡文件或包含帐号信息的文件,对于这类文件,Git 提供了一个非常高效灵活的方式进行屏蔽,即创建一个.gitignore文件。

开发者还可通过 https://www.gitignore.io/ 工具生成合适的.gitignore文件。

在这个文件中,项目拥有者只需将不想进入版本仓库的文件列举出来即可,支持通配符。例如:

Bash
*.sublime-project
*.sublime-workspace
*.bak
*.dump
.gz(busy)
test/*

需要提醒的是,当.gitignore文件更改后,并不能立即起效,需要进行如下操作:

  1. 清除缓存。命令为:

    Bash
    git rm -r --cached .
  2. 添加文件到仓库:

    Bash
    git add .
  3. 之后就可添加说明、推送。

如何清除 git 授权缓存

当我们修改了仓库密码时,由于 Git 会缓存之前的密码,可能会出现授权错误,这是可以运行

Bash
git credential-cache exit

来清除缓存。

如何自动推送仓库

有时候,难免会忘记将本地内容推送到远程仓库,遗憾地漏掉一次Github中的小绿块。下面介绍一个windows系统开机自动运行推行脚本的方案。其原理是利用自运行批处理,自动生成注释,自动推动到远程仓库。

使用win+r,键入shell:startup,打开启动文件夹。

在此文件夹新建批处理文件:如push.bat

编辑该批处理文件,内容可参考如下代码:

Bash
H:
cd H:\Users\hdcb\Desktop\repos\front-end-source
git add .
git commit -m %time:~0,2%:%time:~3,2%-%DATE:~0,10%
git push

其中%time:~0,2%:%time:~3,2%-%DATE:~0,10%是生成当前的时间。

读者可根据自己仓库实际所在的驱动器和目录,进行修改。

需要注意的是,如果安装了安全卫士之类的软件,可能会对在startup文件夹中的内容进行隔离,允许允许即可。

这样,每次计算机开机后,都会自动运行Git推送脚本,将脚本指定的本地仓库,推送到远程仓库。

如何在同一台电脑上使用多个 git 账号

通常情况下,我们使用全局性配置,使用 Git 工具进行版本管理:

Bash
git config --global [user.name](http://user.name) "xxx"
git config --global user.email "xxxx"

但是,上述设置在同一台电脑上需要使用多个账户进行git仓库管理的时候,会出现账号冲突的问题。因此,我们需要使用如下措施:

在仓库中使用本地配置,这样就可以在不同的仓库中,使用不同于全局设置的用户进行操作:

Bash
git config [user.name](http://user.name) "xxx"
git config user.email "xxxx"

除此之外,在 Windows 10 中,我们可能还需要进行对仓库的配置进行修改,打开仓库中.git目录中的config文件,在其中远程仓库的信息中直接写入用户名:

Bash
url = https://[email protected]/username/repos.git

如果在远程仓库信息中不写入具体用户名称,在 Windows 10 中进行推送操作是就会使用已有用户的凭据信息进行操作,出现仓库操作权限问题。例如:

remote: You do not have permission push to this repository

如何回退到指定版本

首先使用 git log 查看提交历史及提交的 commit_id

再使用回退命令:

bash
git reset --hard HEAD^         回退到上个版本
git reset --hard HEAD~3        回退到前3次提交之前,以此类推,回退到n次提交之前
git reset --hard commit_id     退到/进到 指定commit的sha码

强推到远程,更新回退后的远程仓库:

bash
git push origin HEAD --force

为Git配置代理

查看代理

sh
git config --global --get http.proxy
git config --global --get https.proxy

临时设置(仅当前会话有效)

sh
export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890

全局配置代理

sh
git config --global http.proxy http://127.0.0.1:10809
git config --global https.proxy https://127.0.0.1:10809

取消代理

sh
git config --global --unset http.proxy
git config --global --unset https.proxy

如果出现错误信息:

txt
fatal: unable to access 'https://github.com/yangjh-xbmu/vitepress-blog.git/': schannel: failed to receive handshake, SSL/TLS connection failed

执行以下命令,禁用 HTTPS 连接时的 SSL/TLS 证书验证,允许 Git 接受任何 SSL 证书,包括自签名证书或不受信任的证书。

sh
git config --global http.sslVerify false

参考资料

  1. 一个成功的 Git 分支模型
  2. 在线练习沙盒
  3. Git权威指南
  4. Git命令速记表
  5. Pro Git