Git是一个分布式版本控制系统(DVCS),在过去的二六年中linux 版本控制软件,已成为世界上使用最广泛的版本控制系统。虽然你很可能早已晓得怎样使用Git的基础知识,但你可能不熟悉常见的命令行模式,或则一些使用较少(但强悍!)的功能。我们将在这儿介绍这种内容。本章还将给你一些背景知识,便于常用的Git术语更有意义,常见的参考概念也更清晰。

你将了解到以下内容:

Git和分布式版本控制的基础知识首次设置Git基本的Git命令常见的Git术语两个强悍且稍稍中级一些的Git概念:二分查找和变基Git最佳实践,非常是有效使用递交消息有用的Gitshell别称,可以节约你大量的输入你可以用GUI工具与Git交互最后,“穷人的GitHub”部分介绍了一个小但真正有用的项目,你可以进行实践并整合到目前为止你学到的Linux技能。我们希望你尝试一下:假如你这样做了,你在命令行上的舒适度和技能将大大获益。

关于Git的一些背景Git是由Linux内核的创建者LinusTorvalds开发的分布式版本控制系统。Git的起源可以溯源到2005年,当时Linux内核社区与一个名为BitKeeper的专有分布式版本控制系统的关系断裂。

为了应对这些情况,Torvalds寻求创建一个免费的开源DVCS,以满足Linux内核开发过程的需求。仅仅几天之内,他就概念化并奠定了Git的基础。

Git优先考虑性能、安全性、灵活性和非线性开发(支持数千个并行分支),迅速在软件开发社区中获得了关注。它的设计指出速率、数据完整性,并支持分布式工作流程,使其成为开发者的最爱,并已成为软件行业版本控制的事实标准。

哪些是分布式版本控制系统?传统的版本控制系统(如并发版本系统(CVS)等)使用一个中央服务器,仍然保持单一、连贯的储存库状态。这种系统容许开发者推送和获取代码,并准许使用分支、标签和其他熟悉的机制。重要的是,这种版本控制系统是围绕中央权威设计的。

Git和其他DVCS,如Mercurial和Fossil,采用不同的技巧。每位开发者都有自己的完整储存库。其他开发者不是通过中央服务器,而是通过彼此的储存库拉取修改。在Linux项目的情况下,有数百个独立的储存库由开发者使用。一旦开发者觉得其中一个储存库的状态早已打算好,她们将恳求将修改拉入主内核。这就是“拉取恳求”一词的来源。

尽管GitHub、GitLab、sourcehut等提供了Git的集中式托管,处理用户授权等事务,并提供许多围绕软件开发项目的其他功能,但Git在没有这种功能的情况下也能挺好地工作,并提供了许多机制来实现这一点。甚至可以仅使用电子短信发送和接收补丁和递交组,而无需离开命令行和Git。这容许虽然只有一个电子电邮地址用于发送补丁的参与者也能轻松协作。

Git基础知识以下是最重要的Git命令行基础知识的快速回顾。那些提供作为参考,而不是逐渐说明-虽然我们早已这样编撰,便于你若果想要练习可以跟着。

首次设置首先:假如你是在一台机器上首次运行Git,你可能想要设置几个全局配置选项。

将默认分支名称设置为main:

git config --global init.defaultBranch main

如今配置你的默认名称和电子电邮(附加到你所有的递交):

git config --global user.email "you@example.com"
git config --global user.name "Your Name"

如今你可以初始化一个新的Git储存库。

初始化一个新的Git储存库创建一个目录并步入它:

mkdir my-repo
cd my-repo

如今告诉Git你想要初始化这个目录作为一个新的Git储存库:

git init

制做和查看修改创建一个包含一些简单内容的文件,并显示Git检查到的相应修改:

echo "Hello World" >> README
git status

暂存和递交修改暂存你所做的修改以供递交,并观察gitstatus的输出怎样变化:

git add README
git status

显示暂存的内容:

linux 版本控制软件_版本控制软件是什么_版本控制软件svn

git diff --staged

递交暂存的修改:

git commit -m 'Add README file'

这是递交命令的缩写方式,它直接指定消息(-m)。通过运行仅gitcommit,你将获得递交命令的交互式版本。

交互式版本的这个命令(没有-m选项)将打开你shell的EDITOR环境变量手指定的文本编辑器,一旦文件被保存但是编辑器退出-也就是说,当$EDITOR命令返回时-递交将被写入。

可选:添加远程Git储存库以下命令将添加一个名为origin的远程储存库,Git可以推送和拉取。这可能看上去类似于我们在第13章“使用SSH安全远程访问”中介绍的SSH登入命令,由于Git在这些情况下将使用它。Git还支持其他合同,如HTTPS。

git remote add origin git@example.org:repo-path

这只是一个反例,但当你在处理一个真实的储存库时-比如,一个存在于GitHub上的储存库-你将修改主机名和repo-path以匹配你想要添加的储存库。GitHub和其他源托管工具都有清晰的文档说明怎样为托管在哪里的储存库执行此操作。

推送和拉取从你当前的分支推送修改到远程Git储存库:

git push -u origin HEAD

从远程分支拉取修改:

git pull

克隆储存库让我们克隆一个远程储存库-我创建的一个基于项目的Linux课程的所有代码:

git clone https://github.com/groovemonkey/hands_on_linux-self_hosted_wordpress_for_linux_beginners

这将拉取储存库的Git历史记录,并将远程储存库的origin设置为指定的URL。之后你可以使用本章早已学过的所有Git命令来处理代码库。

像先前一样,你可以检测储存库的状态:

git status

其实这个命令一般用于检测什么内容被更改了,它就会在合并期间提供有关受影响文件的信息,在合并冲突期间显示受影响的文件,并在二分查找代码以及各类其他情况下帮助你。当你不确定发生了哪些时,查看gitstatus是值得的;很可能你处于一个特殊的Git状态,你可能想要退出,或则在继续之前完成。

如今我们早已介绍了你将最常使用的命令,让我们让你熟悉一些常常让新使用Git的人倍感疑惑的术语。

你可能会碰到的术语对Git的词汇有一个基本的了解十分有帮助。虽然当其他软件混和使用这种术语时可能会引起混淆,但晓得它们在Git世界中的含意可以让你更自信地工作,比如,在故障排除和阅读错误消息时。

以下是最常见的术语及其涵义的概述。

储存库这本质上是一个“项目”,由版本控制管理并跟踪的代码的根目录-包含.git目录的那种。一个储存库包含你的源代码及其历史记录和修改。

裸储存库这有类似的含意,只是代码没有被检出。它匹配.git目录包含的内容。在像GitHub、GitLab、sourcehut或你公司的Gogs或Gitea实例这样的服务器上托管储存库时,那些一般是坐落名为project-name.git的目录中,只包含你在检出(克隆)的储存库中见到的project-name/.git的内容。

分支假如你想像第一个递交是新储存库的种子,一个项目由各类分支组成。有一个主分支(下边描述),一般还有一个或多个侧分支,包含项目正在采取的其他方向。

这种可能是主要版本分支,其中应用了错误修补,但永远不会合并回主分支。它们可能是实验,可能会也可能不会合并回主分支。或则,它们可能是仍在开发中的新功能或错误修补分支,但一旦打算好才会合并-可能性是无限的。

主/master分支这是默认分支,将在初始化或克隆储存库时使用。按照项目的不同,它一般包含最新的(开发中的)或最新的稳定代码。

HEAD这是分支上的最新递交。有时也被称为分支的“尖端”。在命令行上,HEAD也一般与相对递交一起使用。

比如,HEAD~2引用了两个递交之前;为此,以下命令将显示你直至两个递交前的日志:

git log HEAD~2

在脚本和日常使用中常用linux系统,它也可以作为当前分支的代替品,由于它是当前分支的尖端。

标签与分支不同,标签是标记特定递交的一种形式,比如,创建(并稍后引用)代码库的特定版本。

浅层一般,“浅层”用于描述不包含或只包含特别少历史的检出。当Git仅被用作获取代码的手段,而不是完整的储存库及其历史记录时,都会使用浅层检出。但是,这可能会制止个别依赖更多历史的命令和工具的工作。

合并合并是将一个分支的代码集成到另一个分支的过程。这可能发生在各类情况下,比如将特点分支合并到主分支,从远程分支拉取修改,从Gitstash检索代码等。这种合并可以以完全手动化的形式发生。有时,如在合并冲突的情况下,合并可能须要自动干预。

合并递交这是合并代码时形成的递交。当合并代码时,合并本身会弄成一个递交。当出现合并冲突时,这个合并递交将包含解决该冲突的修改。即使技术上是可能的,但将任何其他修改(比如额外的错误修补)添加到这样的递交中并不是一个好主意。合并递交应当只包含使特定合并工作所需的修改。

在Git手动处理的无冲突合并的情况下,一般只需递交它们,而不须要自动修改代码或消息。

合并冲突当Git不确定怎样合并传入的代码时,将造成合并冲突,你须要自动解决,一般使用合并工具。当代码被拉取、从暂存区应用代码、合并分支或在任何其他操作当前检出的代码时,都可能发生此类冲突。合并冲突须要解毅然后递交。gitstatus一般会告诉你怎么进行。

暂存有时须要将修改暂时搁置以供之后检索。Git因此提供了一种机制,称为暂存。暂存的结构像一个栈,通过gitstashpop,可以轻松地按次序应用修改。

拉取恳求Git是一个分布式版本控制系统,这意味着每位开发者都有自己的完整储存库,因而可以独立于其他开发者在同一个项目上工作。

想像一个开发者Steve,他在自己储存库中的代码做了一些修改。他希望另一个开发者Sarah在正式到来的软件发布之前将这种修改集成到代码库中。Steve恳求Sarah将这种修改拉入她的储存库-如我们在本章后面听到的,这就是“拉取恳求”一词的来源。

因为许多公司和项目不使用Git作为DVCS,更喜欢一个所有开发者都从中拉取和推送的中央权威代码储存库,所以“拉取恳求”这个术语如今一般拿来描述将代码添加到哪个权威储存库(或则有时只是储存库的主分支)的恳求。

注意由于这一概念偏离了Git的去中心化特点,所以没有Git原生的词汇来描述它。不同的产品实现这个工作流(更新权威的中央代码库)有不同的名称:GitHub称之为“拉取恳求”,而Launchpad称之为“合并建议”,GitLab称之为“合并恳求”。

选购有时只从不同分支获取单个修改(递交)是有意义的。一个典型的事例是在开发分支中的错误修补,例如应当添加到稳定分支便于发布的功能分支。这可以通过选购来完成。与合并不同,合并是合并整个分支,选购容许你指定要添加的单个递交。

二分查找gitbisect是快速找到造成变化的递交的一种形式,一般用于确定那个递交引入了某个错误。因此,须要指定一个已知的“坏”提交和一个已知的“好”提交。坏递交包含错误,而好递交一直正常。Git如今将向你展示你可以用于测试错误的递交。以下是一个示例:

git bisect start
git bisect bad
git bisect good a0634a0

二分查找:在此以后还剩下675次修订须要测试(大概10个步骤)

第一行开始二分查找。在第二行中,我们告诉Git当前版本是坏的,因而包含错误。因为我们晓得递交a0634a0依然良好,我们在第三行指定它。其实,这不一定是一个递交,也可以是一个标签或一个分支。之后Git将告诉我们还须要检测多少个版本。

linux 版本控制软件_版本控制软件svn_版本控制软件是什么

如今轮到测试我们正在尝试找到的代码中的错误。假如存在错误,我们输入gitbisectbad,否则输入gitbisectgood。重复这个过程。最终,你将找到引入错误的准确递交。

假如你想退出这些模式并回到之前的状态,输入gitbisectreset即可。

按照你正在尝试找到的内容,“好”和“坏”可能不是最好的词汇,但是在企图找到任何其他类型的行为变化时可能会令人困扰。所以可以使用“旧”和“新”来取代,以找到引入新行为的递交。请记住,你不能混和使用这种术语。它要么是好和坏,要么是旧和新。

还有一些方式可以推动这个过程,比如,假如你晓得行为变化的位置,可以指定文件或目录。假如你晓得一个变化必须与some/directory或some/other/directory中的个别内容有关,你可以像这样缩小搜索范围:

git bisect start -- some/directory some/other/directory

Git将确保只考虑对这种路径进行修改的递交。

甚至还有更多方式可以推动这个过程,比如指定多个好的递交,甚至传递一个测试脚本,按照退出代码,将手动找到递交。假如你须要浏览大量递交,查看mangit-bisect也很有帮助。

变基gitrebase是一种常见的方法,通过“重放”(实际上是重新创建)一组给定的修改(如功能分支)到一个新的基础递交上,而不是它们真正分叉的基础递交,进而保持递交历史的便于理解。

由于开发一般是分布式的,你可能有一个像这样的“真实”提交历史:

版本控制软件svn_linux 版本控制软件_版本控制软件是什么

图14.1:“真实”提交历史

在历史记录中混杂着多个特点分支历史一般比其有用性更令人疑惑,因而Git的变基功能被拿来在合并时简化这种特点递交。

特点1首先被合并,所以它使用的是原始的基础递交。现今的历史看上去像这样:

linux 版本控制软件_版本控制软件是什么_版本控制软件svn

图14.2:特点1变基/合并于1月13日

特点3接出来被变基并合并,所以现今的历史看上去像这样:

版本控制软件svn_版本控制软件是什么_linux 版本控制软件

图14.3:特点3变基/合并于1月14日

最后,特点2被变基,致使其基础递交变为1月14日特点3的递交。如今我们拥有了如下所示的漂亮、简化的历史:

linux 版本控制软件_版本控制软件svn_版本控制软件是什么

图14.4:特点2变基/合并于1月15日

GitHub和其他集中式Git储存库托管商在合并时手动化了这个过程,所以你极少须要在命令行自动变基。但是,以下是执行变基的过程:

创建一个新的分支并添加一个递交:

版本控制软件是什么_版本控制软件svn_linux 版本控制软件

复制

gitcheckout-bdave/myfeaturegitcommit-m”madesomechanges”

假定基础分支名为main,但是自从你开始开发你的分支以来早已添加了一些递交,如今你可以“在main上变基”:

git rebase main

这将更改Git历史,将你的分支递交变基到最新的main递交,如同你在前面的图表中见到的那样。由于你正在改变现有的历史,这可能须要向权威储存库(如GitHub储存库)强制推送,这可能会造成其他用户出现冲突。请在变基时注意这一点。

如今我们早已确定了一些使用Git时会碰到的关键术语和概念,我们可以概述一些编撰有效递交消息的最佳实践。

递交消息的最佳实践作为通常规则,“一次递交,一次修改”是保持你的Git递交-以及历史-有用的形式。

有许多情况下,你可能只处理一个重大修改,但还添加了一些次要的(无关的)代码更正和改进。那些不相关的修改一般应当单独递交。最好保持某些递交专注于你尝试完成的一个具体事项:一个小修补,修正一个错别字,修改款式,添加一个(单一的)功能,等等。虽然你最终同时进行多个相关的修改,将它们分成多个递交可能依然有意义。更频繁地递交可以使这个过程显得更容易。

这个规则有许多实际缘由。最实际的诱因之一是,当你的递交很小,假如有必要(虽然你在修改代码时未曾意料到),可以轻松地选购或撤消某些修改。拥有小而专注的递交在某人使用gitblame来理解修改时也很有帮助。

好的递交消息有时,模糊的建议,比如,“在使用gitcommit时保持递交消息简略”,可能会令人困扰且无法遵守。为了提供上下文,解释Git的预期用途是有意义的。Git作为一个分布式版本控制系统(DVCS),容许以电子短信的方式发送补丁。为此,递交消息本身-在某种程度上-采取了电子短信的方式。第一行被视为主题行,提供了所做工作的简略概述,之后是一个空行和修改的更详尽的摘要。

因为这是一个十分开放式的模式,有一些普遍接受的规则。像所有这样的规则一样,它们可能按照项目或组织的须要被覆盖,但以下是许多成熟的开源项目所做的概述:

保持第一行简练。它应当是一个使用72个字符或更少的摘要。使第一行成为一个祈使代词(比如Add…,Fix…)。小写主题行。假如须要更多内容,添加一个空行和完整的摘要。使用正文解释你为何要进行此修改。这对于任何将来使用gitblame的未来读者都十分有用。确保描述你是怎么得出推论/实现的,以及它为何相关。这对于复杂的递交和可能对于只看代码的人来说可能不会立刻有意义的递交尤其重要。这在追踪错误、稍后删掉过时的代码、重写系统或只是理解代码时可以提供巨大的帮助。考虑你递交消息中写的一些东西是否可以更好地添加到代码注释中。想像一个审查者或未来的读者完全没有上下文。确保代码修改可以很容易地理解。有了这种建议,你应当才能制做清晰有序的递交消息。接出来,我们将瞧瞧一些进一步的建议,便于轻松有效地使用Git。

GUI其实这本书强烈偏重于提升你的命令行技能,但值得一提的是,有一些图形工具可以使Git交互显得更容易。

tig和gitk是两个图形化储存库浏览器的事例,它们为你提供了一个类似于许多IDE提供的Git界面。要尝试它们,只需使用cd导航到储存库并运行gitk或tig。你可能须要通过你的包管理器安装这种工具;许多Unix版本(包括流行的Linux发行版和macOS)默认没有安装它们。

有用的shell别称以下是一些常用Git命令的有用shell别称。随便将它们添加到你的~/.bash_aliases文件中(假定你使用的是Bash):

alias gpo='git push origin $(git branch | grep "*" | cut -d " " -f2)'
alias gp='git pull'
alias gs='git status'
alias gd='git diff'
alias gds='git diff --staged'

假如你每晚输入gitstatus数十次,添加一某些名让你可以输入gs取代可能会有很大的改进。随便将这种修改为更便利的东西-这就是订制的目的!

如今让我们稍为放大视野linux运维最佳实践,瞧瞧我们怎样在建立一个大型Linux服务器项目时实际应用所有这种知识:你自己的私有Git服务器。

穷人的GitHub在这一部份,我们将向你展示怎样为自己设置一个远程Git储存库。你只须要在远程机器上有一个SSH帐户,以及在你的本地机器上有一个Git二补码文件(如同Git命令本身)。假如Git早已安装在远程机器上,你甚至不须要root权限。

这是一个有趣的项目,它将使你熟悉与Git相关的基本面向操作系统的概念。这些设置不建议用于生产用途;相反,它将向你展示,当涉及到Git时,绝对没有魔法。像Linux中的所有其他事物一样,它只是文件(在这些情况下,是远程文件和一个SSH隧洞)。

考虑事项按照你是否拥有root权限以及你是否想与别人共享储存库,你可能须要考虑为你的共享Git服务创建一个特定的用户。这是完全可选的。

我们将使用SSH帐户进行身分验证,所以假如你共享Git储存库,你与之共享的人将拥有与远程机器上该用户相同的权限。假如你不完全信任你的程序员朋友可以访问这个帐户,这么在这个项目中(命名为git)为远程机器创建一个单独的用户可能是有意义的。

这个项目假定你对设置SSH和联接服务器倍感舒适-假如你对细节有些生疏,请查看前一章:第13章,使用SSH安全远程访问。

版本控制软件svn_版本控制软件是什么_linux 版本控制软件

联接到你的服务器使用你希望储存库所属的帐户联接到服务器(比如git,或则你自己的用户):

ssh myuser@example.com

安装Git首先,通过运行以下命令检测Git是否已安装:

git version

这应当会输出安装在你服务器上的Git版本。假如你收到“命令未找到”的消息,这么Git就没有安装在你的系统上。

要安装Git,只需使用你的系统包管理器安装git包。在Ubuntu上,你会运行:

apt-get install git

初始化储存库如今你可以初始化一个新的裸储存库。在这些情况下,我们将称其为my-project。你可以在任何地方创建它。为了简单起见,我们假定它在你的主目录中:

git init --bare my-project.git

这将创建一个名为my-project.git的目录。它不是一个文件,而是一个Git觉得是储存库的目录结构。我们不会在这儿详尽说明,你可能须要很长时间才会须要修改个别东西。

信不信由你,这实际上是你所须要做的一切!

如今你可以从服务器断掉联接了(假如你是通过SSH联接的,按Ctrl+D)。

克隆储存库虽然它完全是空的linux 版本控制软件,但你如今可以克隆储存库了。从服务器断掉联接后,从你的本地机器运行以下命令:

git clone myuser@example.com:my-project.git

如前所述,这假定你在myuser用户的主目录中创建了储存库。从主机名开始(假如你没有设置DNS,这可能只是你的服务器IP地址),路径是相对于用户的主目录的。假如你想指定一个完整的(绝对)路径,只需以斜杠开头。换句话说,使用命令gitclone:/home/myuser/my-project.git将克隆到相同的目录。

Git会警告你克隆了一个空储存库。但既然这就是我们预期的,就没有必要害怕。

编辑项目并推送修改如今我们可以切换到克隆的目录并开始工作:

cd my-project
echo "My personal project" >> README
git add README
git commit -m 'initial commit'

如今我们有了第一次递交,我们可以推送它。第一次推送有一个小的注意事项:由于储存库一直完全为空,它还不晓得任何分支,甚至是主分支。假如你只运行gitpush,Git会告诉你这一点。所以请确保在第一次推送到新储存库时告诉Git分支:

git push origin master

就是这样!

如今你可以或任何有访问你SSH帐户权限的人可以克隆、推送和自此储存库拉取。你甚至可以设置钩子并做其他有趣的事情。Git是一个功能强悍、功能多样的工具。熟悉它们可能须要一段时间,所以就把这当成你的起点。

可能性是无限的,我总是很高兴看到人们使用Git用于有趣或奇特的用例。玩得开心!

推论在这一章中,你学习了有效使用Git所需的基本概念、命令和工作流程。一些常用的中级特点和术语如今应当对你更清晰了,我们传授了一些“软”Git技能的建议,例如编撰好的递交消息。

我们向你展示的shell别称每晚可以为我们节约数百次按钮;我们希望它们对你也像对我们一样有用,希望你使用命令别称来记住所有无法记忆或无法输入的命令。

我们还希望你跟进了穷人的GitHub项目!运行命令只须要几分钟,但假如你花一个晚上真正尝试它(租用几个小时的LinuxVM,在那儿设置一个远程储存库,并推送一些示例递交),你将感遭到当你将新发觉的Linux技能结合上去解决现实世界问题时,它们是多么强悍和有效。

Tagged:
Author

这篇优质的内容由TA贡献而来

刘遄

《Linux就该这么学》书籍作者,RHCA认证架构师,教育学(计算机专业硕士)。

发表回复