Git是一个常用的软件,用来记录对文件和目录的修改。它最擅长的是跟踪文本的变化,而这正是源代码的全部内容。你可能已经遵循了一个与Git类似的工作流程。如果你有一个文本文件,然后你对它进行了一些修改。可以说,第一稿是版本1。第二稿是第二版,以此类推。Git会记录这些修改的时间。它还为你提供了一种重做和撤销的方式。有了Git,你可以移动到时间轴上的任何一点。Git是一个版本控制系统,也是最常用的一个。它的出现是由于程序员需要一种方法来跟踪他们对计算机代码所做的修改,当他们增加功能和修复错误时。这种类型的软件也被称为源代码管理。
Git的历史
早在1972年,AT&T发布了一个名为源代码控制系统(SCCS)的工具。它被用在Unix操作系统上,并在大学和各种研究项目中开始流行。SCCS是直到80年代初才被使用的版本控制工具。这时RCS,即修订控制系统,被发布了。RCS开始流行,因为它是跨平台的,而SCCS只是Unix的。它的语法更容易学习,功能更多,速度也比SCCS快。SCCS和RCS有一个缺点,就是它们只允许你一次处理一个文件。这使得你可以跟踪单个文件的变化,但不能跟踪一组文件或整个项目的变化。随之而来的是并发版本系统,它使处理多个文件和代码库的想法成为可能。这就开始了将代码放在远程服务器上的概念,在那里,一个以上的用户可以同时在同一个文件上工作。下一个创新是Apache Subversion或简称为SVN。SVN增加了保存非文本文件的能力,并改进了跟踪和提交过程。Bitkeeper是另一个版本控制系统,运行良好,但成为一个付费软件。2005年,Linux的创造者Linus Torvalds创建了Git。Git后来成为第一大版本控制工具,并一直保持到今天。2008年,GitHub推出了它的服务,允许任何人托管Git源代码库。
安装Git
Git可以安装在Windows、Mac和Linux上。如果你还没有Git,可以在这里下载。在本教程中,我们将在 Windows 上运行 Git。运行安装程序时,只需接受所有的默认值,因为有很多选项。
开始使用Git
为了开始使用 Git,我们可以创建一个示例项目文件夹,其中存放一些我们要用 Git 跟踪的文件。在这里,我们导航到该目录,并运行git -version命令来验证Git是否已经安装和运行。
如果你不在配置中添加用户名和电子邮件,Git就会向你吠叫,所以我们可以直接使用**git config -global user.name "gituser "和git config -global user.email "gituser@example.com "**添加一些示例数据来开始。
自动完成和帮助
Git 的自动完成是一个很好的功能,它可以帮助你输入命令、文件名、分支名和其他东西,使工作流程更容易。所以你可以开始输入一个词,然后使用Tab键,让Git尝试完成你可能想到的其余命令。这有助于节省一点打字的时间。在有几个选项的情况下,Git会通知你它需要更多信息或提供你的选项。例如,如果我们输入git a,然后按tab键,可能完成的选项是add、am、apply、archive和askyesorno。
通过输入git help,你可以查看Git中常用的命令列表,这些命令分为5类。
这些是在不同情况下常用的 Git 命令。
1. 启动工作区
- clone将一个仓库克隆到一个新的目录中
- init创建一个空的 Git 仓库或重新初始化一个现有的仓库
2. 在当前的修改上工作
- add将文件内容添加到索引中
- mv移动或重命名一个文件、一个目录或一个符号链接
- restore恢复工作树上的文件
- rm从工作树和索引中删除文件
- sparse-checkout初始化和修改sparse-checkout
3. 检查历史和状态
- bisect使用二进制搜索来查找引入错误的提交文件
- diff显示提交、提交和工作树等之间的变化
- grep打印与某个模式相匹配的行
- log显示提交日志
- show显示各种类型的对象
- status显示工作树的状态
4.增长、标记和调整你的共同历史
- 分支列出、创建或删除分支
- 提交将修改记录到版本库中
- merge将两个或多个开发历史合并在一起
- rebase在另一个基础提示的基础上重新应用提交内容
- reset将当前 HEAD 重置到指定的状态
- switch切换分支
- tag创建、列出、删除或验证一个用GPG签名的标签对象
5.协作
- fetch从另一个资源库下载对象和参考文献
- pull从另一个版本库或本地分支获取并与之集成
- push将远程 refs 与相关对象一起更新
要获得个别命令的详细帮助,只需键入诸如githelp init、githelp clone、githelp add等。
使用Git
现在我们可以开始测试如何在本地环境下使用 Git 了。
初始化一个仓库
要启动一个仓库,你需要一个目录来存放你的项目。我们已经有了一个名为exampleproject的文件夹,我们的项目就在这里。你可以在没有文件、一些文件或许多文件的情况下初始化一个仓库。Git会知道如何进行相应的操作。你可以简单地输入git init来开始工作,Git会让你知道它已经初始化了一个Git仓库。
.git 文件夹
初始化仓库后,你会在项目根目录下发现一个新的文件夹**.git**。这是一个隐藏的文件夹,所以为了看到它,你需要使用ls -la。这个不可见的Git目录是Git要对项目进行所有跟踪的地方。一旦这个目录出现,我们就知道Git仓库已经被初始化并准备好了。关键的启示是,这个Git目录是Git的所有跟踪。如果你要删除这个Git目录,Git就会从项目中被删除。所以要给项目添加 Git 跟踪,请使用git init。要从项目中移除 Git 跟踪,请删除 .git 文件夹。
Git 的三棵树
Git 采用了三棵树的结构。它们是仓库、暂存索引和工作副本。在使用Git的过程中,了解这些不同的树是有帮助的。工作目录包含了可能还没有被Git追踪到的改动。Staging Index 包含了我们即将提交到仓库的改动,而实际的仓库是被 Git 完全跟踪的。
进行提交
Git现在正在跟踪我们的项目。这不算是一个项目,因为我们没有文件在里面。让我们通过添加一个index.html文件来改变这一状况。
让我们在 Visual Studio Code 中打开 exampleproject 文件夹。VS Code具有Git意识,所以我们现在会看到一些很好的东西。我们看到index.html文件是绿色的,一个字母U和一个数字1在左边。Git看到了项目中的这个新文件。
一个Git提交遵循三个步骤。
- 1.做一个改动
- 2.添加修改内容
- 3.提交更改
我们已经采取了第1步。我们在项目中添加了一个文件。这就是一个变化。它也可以是一个文件编辑或其他动作。现在让我们用git add和git commit来完成提交。首先,我们做添加。
在Visual Studio Code中,这个变化被发现了。它看到该文件已经被添加。
现在我们用git commit进行提交,并使用-m标志来添加提交信息。你总是希望在提交时添加一个描述性的摘要信息。
在Visual Studio Code中,我们在左边的Git图标上不再看到任何特殊的颜色或数字指示。原来在暂存索引中的内容现在已经提交了,VS Code很高兴。这相当于在使用git status时,我们得到的信息是 "没有什么可提交的,工作树干净"。
提交信息的一些最佳实践如下。
- 使用少于50个字符的简短单行摘要。
- 你可以选择在后面加一个空行和一个较长的描述。
- 每行应少于72个字符。
- 用现在时态来写消息。"修复错别字",而不是 "修复错别字"。
- 要清晰、简洁。
- 为了使要点突出,你可以使用连字符或星号。
- 可以选择添加跟踪号码,如bug id或支持票id。
查看Git日志
每一个改动都在Git中被跟踪,我们可以通过日志来查看这些改动。在项目根目录下,输入git log来查看提交日志。我们只做了一个提交,但如果有几个提交,最新的条目会在最上面。
在上图中,我们可以看到提交的旁边有*(HEAD -> Master)*的文字。这是什么?这就是 Git 中的头部指针。它是 Git 系统中的一个参考变量,指向仓库中的一个特定提交。它的关键点如下。
- 指向仓库中当前分支的顶端。
- 仓库的最后状态,最后签出的内容。
- 指向下一次提交的父分支,在那里进行编写。
添加文件到我们的版本库
我们的项目只有一个index.html文件,算不上什么项目。让我们再添加两个文件:page_two.html和page_three.html。然后我们试试一个新的git命令:git status。
我们可以看到这两个新文件。git status 命令告诉我们:"没有添加到提交中,但存在未跟踪的文件(使用'git add'来跟踪)"。Visual Studio Code也看到了这两个新文件,它们是绿色的,有一个字母U表示它们是未被追踪的。
未追踪与已追踪
未追踪和已追踪是什么意思?好吧,我们刚刚添加的这两个文件没有被追踪。Git 知道它们的存在,但并不关心它们是否被修改或更新。而我们创建的第一个文件是被跟踪的,它已经被提交到了仓库中。三个文件都是空的。让我们做个测试,在这三个文件中填入一些HTML标记,然后运行git status命令,看看有什么变化。index.html文件的信息是修改过的,其中的改动还没有提交。换句话说,工作目录中的文件在上次提交后有变化。其他两个文件没有被列为修改。它们仍然是未跟踪文件的状态。
VS Code也以同样的方式列出了这些文件。Index.html的M代表修改,其他两个文件的U代表未跟踪。
原子提交
这给我们带来了原子式提交的概念。我们想把这些修改添加到版本库中,但它们并不完全相关。我们可以一次性添加并提交它们,但把它们分成相关的小块可能更好。这和把代码分解成特定功能的想法一样。在修改 index.html 文件的同时,增加一个提交,然后再增加一个提交,把另外两个页面加入到版本库中,这样可能更合理。我们可以先用git add index.html和git status。index.html 文件变成了绿色的文字,上面写着 "待提交的修改"。其他两个文件仍然是未跟踪的状态。
在VS Code中,你可以通过点击Git图标和查看阶段性变化区域来看到阶段性变化。这与我们上面的git status命令的输出是一致的。
现在我们可以提交当前已缓存的修改。
git commit -m "Add html markup to index file"
让我们一次性添加并提交两个未跟踪的文件。这里我们将使用git add ., 一次性添加所有文件到暂存区,然后用git status查看要提交的修改,最后我们可以用git commit提交两个文件。我想你现在已经开始看到git的工作流程了
我们可以再次运行git log来查看到目前为止的所有提交内容。这应该说明,Git 就像你的代码的活动追踪器。它告诉你在生命周期的每一步发生了什么。我们可以看到,初始提交在日志输出的底部。那是我们的第一次提交,我们只是添加了一个空白的index.html文件。每个提交都有一个唯一的ID,是一个40个字符的校验哈希值。这是通过SHA-1算法创建的。所以在我们的例子中,e703e01c587d141308359c8fff53ec8af71773c0是第一次提交,f77c5907fb319c2b9a70c3e2fa73a860f0676bcb是第二次提交,3eb9816d034f2338ca193e14bb80628ac8d4b1e3是最近提交。正如我们所了解的,HEAD 指针指向的是我们正在工作的分支的最新提交。很完美!
用 diff 查看更改
到目前为止,我们已经用git status来查看文件的状态。我们能够看到一个文件目前属于三个树中的哪一个,它是否被修改过,等等。如果我们想看看到底有什么变化呢?这可以做到吗?是的,可以。你可以用git diff来查看一个文件的变化。到目前为止,我们的项目中已有三个页面。让我们对index.html做一个修改,然后在提交之前用git diff来看看发生了什么。
当我们调用diff程序时,它会显示文件的不同版本,并对它们进行比较。上面看到的格式是常用的格式。它在比较文件A和文件B,文件A是版本库中的版本。它是我们已经提交的文件的最新版本。文件B是在工作目录中的那个。所以从输出中,我们可以很容易地通过+号和彩色的绿色文本看到有什么变化。工作副本有一个文本链接,而版本库中的文件则没有。
我们可以对该文件再做一次修改,然后再运行git diff看看结果。有趣的是!现在我们既有红色文字的-号,也有绿色文字的+号。如果有什么东西从文件中被删除了,就会用红色文字和"-"号显示。所以现在,H1标签的文本不是 "这是索引页",而是改为 "这是主页"。通过使用git diff,你可以看到任何被删除、添加或修改的内容。
要进一步深入了解这些变化,你可以使用git diff -word-diff。这显示我们删除了 "index "这个词,用 "home "代替。
现在我们知道了到底有什么变化,如果愿意的话,我们可以进行提交了。正如我们所看到的,要提交文件,我们需要把文件添加到缓存中,然后提交。这是一个很常见的工作流程,Git 提供了一个快捷方式,让你可以一次性添加到暂存区并提交到仓库。要做到这一点,使用git -am "The commit message"。我们在下面使用这个技术,并使用gitstatus检查工作树是否干净。
在 Git 中删除一个文件
在Git中处理删除可能会感觉有点奇怪,因为它还需要提交到仓库中。最好先看个示范。首先,我们要给项目添加两个新的页面。这些将被添加到工作树上,一开始会被git取消追踪。
现在如果我马上删除其中一个文件,它就会消失。Git还没有跟踪这些文件,因为它们还没有在我们的仓库或暂存树中,它们现在只在工作目录中。如果我们把它们添加到暂存目录中会怎样?那我们现在就去做吧。
让我们也提交这些文件。
现在我们在仓库的主分支里有两个新文件。在使用 Git 时,要删除一个文件,你可以手动操作,也可以用 Git 来完成删除。
手动删除
对于page_four.html,我们直接在VS Code中删除该文件。
git status 命令告诉我们,Git 知道工作目录中的这个文件的删除。
现在有一个小插曲。这个删除的文件需要被 "添加 "到staging中,这样我们才能提交它。好吧,文件已经消失了,那么我们怎么把它添加到暂存区呢。我们可以像这样用git rm把这个删除文件移到暂存区。
所以现在这个改动已经在暂存区了。我们现在可以把这个改动提交到仓库。
文件被删除了,Git知道了它,仓库被更新了,工作树也干净了。大家都很高兴。在 Git 中删除文件的另一个选择是跳过手动删除,直接告诉 Git 来删除。这样可以从工作目录中删除文件,并一次性完成修改。
在VS Code中,这个文件已经消失了。我们的工作目录中只剩下index.html、page_two.html和page_three.html。
最后,我们可以把这个删除提交到版本库中。
最后,我们可以用git log查看我们git演示的整个生命周期。光看每条提交信息,输出结果几乎就能说明一个问题。第一个是在底部,我们有一个初始提交。接下来,我们在第二次提交中给索引文件添加了HTML标记。在第三次提交中,我们在第二页和第三页加入了HTML标记。在第四次提交中,我们修改了一些文字并添加了一个超链接。在第五次提交中,我们增加了两个页面。在第六次提交中,我们手动删除了第四页。在第七次提交中,我们用 Git 直接删除了第五页。继续这个过程,几十次,几百次,甚至几千次,你就拥有了一个真实的软件项目! 🙂
查看一个特定的提交
每个提交都有唯一的标识,就是我们学过的40个字符的校验和SHA-1哈希值。我们可以使用任何特定提交的哈希值来查看该提交的细节变化。如果你需要在以后的时间里回来,而你完全忘记了项目中什么时候或为什么会有改动,这就很有帮助。我们用git show和提交ID结合起来查看该提交。下面是一个例子。
制作多行提交信息
你可能想做一个多行的提交信息,我们还没有看到,所以现在让我们试试。我们将对项目中的三个文件做一些修改,然后查看git状态,看看是否确实有变化。
要进行多行提交,我们可以发出git commit -a的命令,同时关闭-m选项。Git 还是想要一个提交信息,但我们没有在命令行中指定。让我们看看会发生什么。
VS Code 现在会给你输入多行的提交信息。
一旦你在编辑器中保存并关闭这个文件,提交将被处理,你的命令行git会话将自动更新。爽啊!
撤销修改
Git 提供了撤销修改的方法,甚至在你关闭编辑器之后。这是一个很好的功能,因为我相信你有过这样的经历:你需要恢复一些代码或文本,但不知怎么就失去了所有的修改。撤销能力适用于工作目录、暂存索引,在某些情况下也适用于实际提交。比如说,我们在做index.html页面的时候,不小心删除了页脚,同时也关闭了文件。这些改动现在已经消失了......或者说,它们是吗?让我们做一个git状态。
注意上面的文字,"(使用 "git restore... "来放弃工作目录中的修改)"。好吧,让我们来试试。
这就成功了。index.html已经改变了,我们删除了HTML中的整个页脚,保存并关闭了文件。这意味着在编辑器中没有撤销的能力。在这种情况下,Git救了我们。通过输入git restore index.html,这些改动被回滚了,当我们打开该文件时,页脚又回到了原位。
git restore是一个相当新的方法。用git checkout也可以得到同样的结果,见这里。
如果你已经把一个文件添加到暂存区了呢?在这种情况下,你可以使用同样的git restore命令,但你可以指定-staged标志。在下面的例子中,我们对page_two.html做了一些文字编辑,然后将该文件添加到暂存索引。然后我们简单地把它从暂存索引中移回工作目录。
改变提交的内容
每个提交都有一个校验和,也就是我们学过的标识符。它的工作原理是,当你提交时,Git 会查看文件中的所有变化以及所有元数据,通过一种算法来运行所有内容,并分配唯一的 ID。如果提交过程中有任何变化,校验和就会被破坏,提交链的完整性就会失效。所以一般来说,你不会真的编辑旧的提交。你可以改变的提交是当前的提交。编辑最近的提交不会有什么不好的副作用,因为它是提交链中的最后一个。其他提交的校验值都不依赖于当前的提交。举个例子,我们打开page_three.html,添加一个副标题。
运行git status和git diff,可以看到有什么变化。
这看起来不错,所以我们提交了这些改动。
如果你改变了对该提交的看法,你可以修改它。这可能是在文件本身,也可能是你不喜欢提交信息。你可以用git commit -amend命令来更新这些内容。首先,让我们运行git log来看看最近的那个提交。
我们想把副标题改成一个很棒的副标题,同时也想更新一下提交的消息。下面是我们如何做到这一点的。
那个最近的提交现在已经被修正或改变了。由于我们修改了HTML代码和提交消息本身,现在的校验和已经不同了。此外,我们可以看到在这个最新的提交之前的提交也是一样的。所以我们把最近的提交给覆盖了。
使用 .gitignore 文件
一旦你有了一个git项目,所有文件都会被追踪。在某些情况下,你可能不希望这样。可能有一个不断变化的日志文件,而你不想跟踪它。另一个例子是像一个.ENV文件,它保存了一个应用程序的密码。追踪本地的密码没什么大不了的,但如果你决定把你的项目推送到GitHub或其他远程仓库,这些秘密密码就不再那么秘密了。要告诉Git忽略某些文件或目录,你可以使用.gitignore文件。我们可以像这样在项目根部添加一个.gitignore文件。
一些关键的.gitignore点。
-
驻留在project/.gitignore中
-
有一个要忽略的规则列表
-
对被忽略的文件的修改会被 Git 忽略
-
使用RegEx模式匹配
-
*?[aeiou][0-9] 。
-
logs/*.txt
-
可以使用负数表达式
-
*.txt
-
!"readme.txt
-
可以忽略带有尾部斜线的整个目录
-
assets/private/
-
可以使用注释
-
# 这是一个注释
推送代码到GitHub
我们要做的最后一件事是把我们的代码推送到GitHub。如果你的电脑从现在开始到下一次写代码时发生自燃,你的项目将在GitHub上安全无恙。要推送代码到GitHub,你首先需要有一个GitHub账户。一旦你有了账户,你就可以选择建立一个新的仓库。它可以是公开的,也可以是私有的。
在创建仓库时,你需要给它起个名字,并给它一个描述。为了我们的目的,我们把这个仓库命名为gitforbeginners,并附上Git 初学者教程的描述。基于这些信息,GitHub 会为你提供推送代码到该仓库所需的信息。
- git remote add originhttps://github.com/username/gitforbeginners.git
- git push -u origin master
要推送你的代码,从命令行导航到项目的根目录,并输入上述命令。代码推送完成后,你就可以在 GitHub 的用户界面上看到你在本地所做的所有提交、修改和编辑。
我们通过命令行处理的所有提交,现在都可以在 GitHub 的网页界面上看到。这与我们在命令日志中使用git log时的情况类似。相当酷啊!
你现在还可以点击任何特定的提交,非常容易地查看差异信息。这就相当于在命令行上使用git diff。
初学者的Git总结
在本教程中,我们对如何使用 Git 有了一个很好的速成课程。习惯于使用Git是一个在自己的项目中踢轮胎和使用它的问题。这是一种管理源代码的好方法。Git可以帮助我们跟踪文件在一段时间内的变化,并随心所欲地查看或比较这些变化。学习Git的基础知识也是向更好的合作迈出的一大步,因为你可以通过GitHub分享项目,或者可能为一个开源项目做出贡献。