Jos's Blog - Git
type: channel
link: https://blog.bbcking5.com/category/19/
items: Git之旅(15)：远程仓库（二）
items: Git之旅(14)：远程仓库（一）
items: Git之旅(13)：常见场景与技巧（一）
items: Git之旅(12)：解决冲突
items: Git之旅(11)：合并分支详解
items: Git之旅(10)：后悔了，怎么办？
items: Git之旅(9)：比较差异
items: Git之旅(8)：HEAD是啥？
items: Git之旅(7)：分支是啥？
items: Git之旅(6)：从概念到实践

Git之旅(15)：远程仓库（二）
type: item
date: 2021-05-25T16:01:54+08:00
description: 博主会将与Git有关的知识点总结到”通俗易懂Git入门系列“文章中，如果你对Git不是特别了解，请按照顺序阅读”Git系列”，以便站在前文的基础上理解新的知识点。前文中，我们初步的认识了远程仓库，并且了解了一些相关的基本操作，这篇文章我们继续聊。我们已经知道，当我们需要多人协作时，可以利用远程仓库交换代码，如果你创建的远程仓库是私有仓库，则只有仓库的成员才能对仓库中的代码进行操作，那么，我们就从”为项目添加成员”这个话题开始吧。我们先来看看为仓库添加成员的具体操作步骤，仍然使用前文中创建的github私有仓库为例，现在我有两个github账号，两个账号分别是zsythink和zhushuangyin，我用这两个账号模拟仓库的管理员和项目成员，zsythink是仓库的创建者，也就是默认的管理员，zhushuangyin是另一个测试账号，此账号充当项目成员的角色，当然，zsythink也是项目成员之一，只是权限是最高的。登录zsythink账户，打开上次创建的github仓库，如下图位置进入项目后，如下图，第1步：点击Settings菜单第2步：点击Manager access菜单第3步：点击 invite a collaborator 按钮即可邀请成员从下图可以看出，当前仓库还没有任何成员点击上图的邀请成员按钮后，会提示你搜索对应成员的github账号，输入成员的github账号进行搜索，会出现对应的搜索列表，如下图所示，此处输入zhushuangyin，点击对应的账号，会出现一个绿色的按钮，提示添加对应账号到当前的仓库中，点击对应的绿色按钮添加账号即可。完成上述操作后，页面会自动跳转到 Settings菜单–Manager access菜单中，会看到如下图所示的状态可以看到，我们已经邀请了zhushaungyin成为项目的成员，当前的状态是等待zhushuangyin的响应，也就是说，仓库管理员已经向zhushuangyin账户对应的用户发送了邀请，但是zhushuangyin还没有同意邀请。现在，我们将角色转换为zhushuangyin用户，zhushuangyin用户的注册邮箱会收到一封邀请邮件，也就是刚才zsythink用户发送的邀请请求，邮件内容如下：可以看到，邮件的大致内容就是zsythink用户邀请你成为zsythink/test仓库的成员，你可以选择接受或者拒绝，我们点击邮件中的绿色按钮查看邀约，邀约内容如下图点击上图的接受邀约的按钮，即可成为zsythink/test项目中的一员。此时，我们再把视角切换回zsythink，再次回到 Settings菜单–Manager access菜单中，如下图所示，可以看到zhushuangyin用户已经变成了仓库的成员。如果你想要的邀请更多的成员，只要再次点击下图中的”Invite a collaborator”按钮，然后重复上述步骤即可。目前，zsythink用户和zhushuangyin用户均可对项目中的代码进行操作了。当然，zhushuangyin用户也需要将自己的公钥配置到自己的github账户中，具体的操作前文已经描述过了，此处不再赘述。为了方便操作，我启动了一台Linux虚拟机，并将root用户的公钥放在了zhushuangyin账户的github账户中，也就是说，目前我在windows中的操作代表zsythink用户，在linux中的操作zhushuangyin用户，以便模拟出多人进行操作时的场景。我们还是以实际的场景为例，以便更好的将命令融入到实际的应用中。场景一场景描述：zhushuangyin用户需要基于master分支开发一个新模块，zhushaungyin用户在本地开发完成，并且测试没有问题以后，需要将最新的代码上传到远程仓库中，以便zsythink用户能够获取到最新的、包含新模块的代码。我们一起来看一下具体的操作步骤。步骤1由于需要基于master分支开发新模块，所以zhushaungyin用户需要获取到最新的master分支的代码，通常的做法是从远程仓库中拉取远程master分支的代码到本地，以便将本地的master分支的代码更新到最新（这个方法我们稍后再说），由于我们刚刚才将zhushunagyin用户添加为仓库的成员，所以zhushuangyin用户可以直接通过clone命令获取到最新的仓库代码，现在，我们就站在zhushuangyin的视角上进行操作。# git clone git@github.com:zsythink/test.git# cd test# git branch -avv*master 23294a7[origin/master]add testfile2remotes/origin/HEAD ->origin/maste…

Git之旅(14)：远程仓库（一）
type: item
date: 2021-05-25T16:01:03+08:00
description: 博主会将与Git有关的知识点总结到”通俗易懂Git入门系列“文章中，如果你对Git不是特别了解，请按照顺序阅读”Git系列”，以便站在前文的基础上理解新的知识点。我们之前聊的所有话题都是单人怎样使用git进行版本管理，这篇文章我们来聊聊怎样多人协作使用git进行版本管理，其实只要理解了前文，理解多人协作也是非常容易的，我们先来聊聊概念，理解了概念以后，再聊具体操作。当多人需要通过git进行协作时，通常的做法是创建一个远程仓库，每个人把远程仓库克隆到本地，克隆后，每个人就在本地获取到了一个和远程仓库一样的git仓库，这样，每个人就可以在自己的本地库中对代码进行开发和管理，当你需要把自己本地产生的最新代码同步到远程仓库中时，就可以进行一个推送操作，将本地的最新代码推送到远程仓库中，同理，如果你想要从远程仓库中获取到别人推送的最新的代码，也可以进行一个拉取操作，将远程仓库的最新代码拉取到本地仓库中，换句话说就是，将远程仓库克隆到本地以后，大家通过本地仓库进行实际修改和版本管理，通过远程仓库进行代码的更新和交换，这样描述并不具象化，别着急，向下看。看完上述描述，你可能会有如下疑问1、如果之前有一个只有自己使用的本地仓库，现在突然想要多人协作，能否将已经存在于本地个人仓库中的内容同步到远程仓库中供大家使用呢？2、如果多个人同时修改了自己本地仓库中的同一个文件，比如A文件，那么当他们都向远程仓库中推送A文件时，会出现冲突吗？同理，如果从远程仓库中拉取的最新代码与本地的代码存在冲突，该怎样解决呢？3、一些其他的问题咱们一个一个聊首先咱们聊聊第一个问题，能否将现有仓库中的内容同步到新建的远程仓库中呢？答案是肯定的。一开始，你可能是一个光杆司令，所有开发工作都是你一个人完成的，你并不需要与别人协作，所以你只是在你的电脑上创建了一个git仓库，然后通过这个本地的git仓库管理代码，经过一段时间的发展，你找到了一些志同道合的小伙伴，你们准备多人协作，共同开发，于是您们想要通过远程仓库协作工作，所以，你创建了一个远程仓库，但是新创建的远程仓库是一个空的仓库，里面什么也没有，大家想要基于你之前的工作成果继续开发，所以你们的首要目的是将你本地仓库中已有的内容同步到新创建的远程仓库中，以便远程仓库中存放的内容是最新的，然后其他人再通过克隆远程仓库的方式，在本地创建出一个本地仓库，这样所有人就都能够获取到一份相同的代码了，之后，所有人就能够通过自己的本地仓库进行工作了，如果需要更新或者交换代码，再依靠远程仓库进行。如果是一个新的项目，完全可以直接先创建一个新的空的远程仓库，然后大家将远程仓库克隆下来，在本地仓库中丰富内容，然后将新内容推送到远程仓库中。所以，是否存在已有的工作成果和git仓库，都不会影响你创建远程仓库，也不会影响你何时创建远程仓库，这样空口白话的描述可能还是有点难以理解，不如先来创建一个远程仓库，从头到尾的将整个过程测试一遍，结合实际去理解吧。本文中会在github上创建远程仓库，github是一个代码托管平台，我们可以在github上免费的创建仓库，以便多人协作使用，除了GitHub，国际上比较著名的代码托管平台还有Bitbucket、GitLab，国内比较著名的代码托管平台有码云、coding等，你可以选择自己喜欢的代码托管平台创建远程仓库，本文中使用GitHub，早期的时候，在GitHub中创建的远程仓库分为公有仓库和私有仓库两种，公有仓库是所有人都能访问的远程仓库，通常开源项目代码的存放会选择使用公有仓库，私有仓库是只有指定的仓库成员才能够访问的远程仓库，早期的时候在github上创建私有仓库是收费的，后来可以免费的创建私有仓库了，但是之前我记得github上免费创建的私有仓库最多只能3个人进行协作，也就是说免费创建的私有仓库有人数限制，这么长时间过去了，不知道是否还是存在对应的限制，不过此处我们只是用于测试，即使有限制也不影响我们此处的测试，所以，我们会在github上创建一个远程仓库来进行演示。首先，打开github官网，网址如下： https://github.com使用github账号登录，没有账户可以免费注册一个，如果你是新注册的账号，登录后可以看到如下图所示的 “创建仓库” 的按钮，点击此按钮点击创建仓库按钮后，会让你填写远程仓库的基本信息，界面如下图上图1的位置会让你填写仓库的名称，此处设置远程仓库的名称为test上图2的位置可以填写远程仓库的相关注释上图3的位置可以选择创建的远程仓库是公有仓库还是私有仓库，此处选择私有仓库上图4的位置如果勾选，会在创建远程仓库时，自动在仓库中创建一个README文件，此处没有勾选如上图所示，点击绿色的创建仓库按钮点击创建仓库按钮后，可以看到如下图中的仓库地址提示，通常情况下，代码托管平…

Git之旅(13)：常见场景与技巧（一）
type: item
date: 2021-05-25T15:00:13+08:00
description: 博主会将与Git有关的知识点总结到”通俗易懂Git入门系列“文章中，如果你对Git不是特别了解，请按照顺序阅读”Git系列”，以便站在前文的基础上理解新的知识点。之前，为了文章之间的逻辑连贯性，好多零散的知识点没有总结，不过这并不代表着这些零散的知识点没有用，相反，这些点在某些场景下非常好用，这篇文章就先来总结一些吧。为了方便演示，我们先来创建一个测试仓库，命令如下：/d/workspace/git$git init test_repoInitialized empty Git repositoryinD:/workspace/git/test_repo/.git//d/workspace/git$cd test_repo//d/workspace/git/test_repo (master)$echo11 >testfile1/d/workspace/git/test_repo (master)$cat testfile111/d/workspace/git/test_repo (master)$git add testfile1/d/workspace/git/test_repo (master)$git commit -m"init commit, testfile1"[master (root-commit)2feec01]init commit, testfile11file changed,1 insertion(+)create mode100644testfile1/d/workspace/git/test_repo (master)$git log --oneline2feec01 (HEAD ->master)init commit, testfile1如上例所示，我们在测试仓库中创建了一个测试文件testfile1，然后创建了一个初始化的提交。现在，我继续修改testfile1文件，命令如下：/d/workspace/git/test_repo (master)$echo12 >>testfile1/d/workspace/git/test_repo (master)$cat testfile11112如上所示，我在testfile1中追加了一行新内容，如果我想要将新的修改创建为提交，那么应该先将这次的修改添加到暂存区，然后再创建提交，此时，如果你使用”git status”命令查看状态，会看到我们还没有将testfile1的最新修改添加到暂存区，如下所示/d/workspace/git/test_repo (master)$git statusOn branch masterChanges not stagedforcommit:(use"git add <file>..."to update what will be committed)(use"git checkout -- <file>..."to discard changesinworking directory)modified: testfile1no changes added tocommit (use"git add"and/or"git commit -a")正常来说，我们应该先执行”git add”命令，然后再执行”git commit”命令创建提交，其实，我们还有更加方便的方法，就是直接执行如下命令：git commit -am"second commit"上述命令的作用就是将暂存操作和提交操作一次性完成，其效果相当于我们先执行了”git add testfile1″命令，然后又执行了git commit -m “second commit”命令，我们来执行一下，看一下效果，如下：/d/workspace/git/test_repo (master)$git commit -am"second commit"[master ac238f9]second commit1file changed,1 insertion(+)/d/workspace/git/test_repo (master)$git log --onelineac238f9 (HEAD ->master)second commit2feec01 init commit, testfile1如上例所示，执行git commit -am “second commit”命令后，第二个提交就被创建了，省去了手动执行git add命令的步骤。需要注意的是，如果你的工作区中存在完全新创建的文件（从未被git跟踪过，刚刚从工作区中新建出来），那么”git commit -am”命令并不会将新建的文件添加到暂存区。当你觉得，目前工作区中的所有变更（被跟踪过的文件的变更）适合创建…

Git之旅(12)：解决冲突
type: item
date: 2021-05-25T14:57:24+08:00
description: 博主会将与Git有关的知识点总结到”通俗易懂Git入门系列“文章中，如果你对Git不是特别了解，请按照顺序阅读”Git系列”，以便站在前文的基础上理解新的知识点。前文中介绍了合并分支的方法以及常见场景，但是并没有模拟合并分支时遇到冲突的场景，这篇文章就站在前文的基础上，来总结一下怎样解决冲突。如果两个分支中的同一个文件中的同一行的内容不一样，当我们合并这两个分支时，就会出现冲突，因为git无法判断我们想要以哪个内容为准，所以需要我们人为介入去确认，人为介入确认内容的过程，就是解决冲突的过程。为了方便演示，我们先来创建一个测试仓库，并且创建两个分支出来，然后分别修改这两个分支中的同一个文件中的同一行，以便之后合并时能够出现冲突，过程如下：$ git init testgitInitialized empty Git repositoryinD:/workspace/git/testgit/.git//d/workspace/git$cd testgit//d/workspace/git/testgit (master)$echo1 >testfile/d/workspace/git/testgit (master)$git add testfile/d/workspace/git/testgit (master)$git commit -m"add test file"[master (root-commit)d808b6e]add test file1file changed,1 insertion(+)create mode100644testfile/d/workspace/git/testgit (master)$echo2 >>testfile/d/workspace/git/testgit (master)$git add testfile/d/workspace/git/testgit (master)$git commit -m"add 2"[master 6b5149f]add21file changed,1 insertion(+)/d/workspace/git/testgit (master)$cat testfile12/d/workspace/git/testgit (master)$git checkout -bnewSwitched to anewbranch'new'/d/workspace/git/testgit (new)$cat testfile12通过上述步骤，我们创建了一个测试文件testfile，在testfile里面写了两行内容，并且创建了两个初始提交，然后，我们基于master分支创建了new分支，现在，new分支和master分支是完全相同的，我准备在两个分支中分别修改testfile的第二行，让new分支和master分支中的testfile的第二行的内容变的不同。先来操作new分支，操作如下：/d/workspace/git/testgit (new)$cat testfile12/d/workspace/git/testgit (new)$vim testfile/d/workspace/git/testgit (new)$cat testfile12new/d/workspace/git/testgit (new)$git add testfile/d/workspace/git/testgit (new)$git commit -m"2 new"[new7d188a4] 2 new1file changed,1 insertion(+),1 deletion(-)如上所示，我将new分支中的testfile文件中的第二行从”2″改成了”2new”，并且基于这个修改，在new分支中创建了新提交。new分支操作完了，现在来操作master分支。/d/workspace/git/testgit (new)$git checkout masterSwitched to branch'master'/d/workspace/git/testgit (master)$cat testfile12/d/workspace/git/testgit (master)$vim testfile/d/workspace/git/testgit (master)$cat testfile12master/d/workspace/git/testgit (master)$git add testfile/d/workspace/git/testgit (master)$git commit -m"2 master"[master 3c5ea03] 2master1file changed,1 …

Git之旅(11)：合并分支详解
type: item
date: 2021-05-25T14:56:24+08:00
description: 博主会将与Git有关的知识点总结到”通俗易懂Git入门系列“文章中，如果你对Git不是特别了解，请按照顺序阅读”Git系列”，以便站在前文的基础上理解新的知识点。前文中已经介绍过什么是分支，我们知道，不同分支中的提交是互不影响的，在实际的工作中，不同的分支通常对应了不同的功能和场景，或者对应着不同的开发人员，又或者对应着不同的代码模块，总之，我们可以利用分支，将”提交”从某个逻辑角度隔离开，让它们之间互不影响，以便在不影响他人或者其他逻辑的情况下完成工作，不过，当某个分支中的工作完成后，我们通常需要将这条分支与其他分支进行合并，以便多个分支的代码能够汇聚到一起，从而获取到一份更加全面、更加完整的可用代码，所以，合并分支也是我们必须掌握的技能，这篇文章我们就来总结一下怎样合并分支。合并分支的操作其实不难，只是想要说明白，需要费一些口舌，因为在执行”合并”操作时，我们可以根据具体情况，选择不同的合并模式去合并，不同的合并模式对应了不同的命令参数，而且在合并的过程中，还可能遇到”冲突”，听到这里是不是觉得有些麻烦，不用害怕，其实理解了原理以后是非常简单的，为了说明白原理，我们先来看一些示意图，理解了示意图以后，再去结合实际命令，搞定合并分支的操作简直不要太简单，也请阅读这篇文章的朋友一口气将此文读完，阅读中如果遇到问题，先记下来，等读完了这篇文章，再去回顾这些问题。为了更好的理解，我们从头开始聊，先聊聊合并分支之前会发生的事情，示意图如下此示意图并没有涉及到任何合并操作，而是描述了合并分支之前，两个分支的创建过程。上图中的第1步表示已经存在的一条分支，这条分支的名字是base。第2步表示基于base分支，创建了new分支，此时，base分支的指针和new分支的指针都指向了最新的提交。第3步表示我们在new分支中创建了新的提交。第4步表示base分支也产生了新的提交，new分支也产生了新的提交，两个分支的指针分别指向了自己分支的最新提交，换句话说就是，从分叉点开始以后，两个分支各自产生了属于自己的提交。有了前文作为基础，看明白上图肯定不在话下，我们接着聊。上图中有两个分支，base分支和new分支，如果，我们想要将两个分支合并，该怎么做呢？没错，我们只需要将一条分支合并到另外一条分支上就行了（听上去似乎是句废话），但是，仔细想想，此处有一个小问题，我是把new分支合并到base分支上呢？还是将base分支合并到new分支上呢？有的朋友可能会问，有什么区别吗？听上去似乎是没有任何区别的呀。其实，还是有一些区别的，这里牵扯到一个合并方向的问题，让我们带着这个疑问，看看如下示意图：上图左侧的第4步我们已经解释过，第4步表示两个分支合并之前的状态，上图右侧有上下两个图示，分别表示两种合并方向，图示一表示将new分支合并到base分支上以后的状态，图示二表示将base分支合并到new分支上以后的状态。现在，我们分别解释一下上图中的两个图示。我们先聊聊图示一（对比着第4步去看图示一更容易理解，第4步表示合并前，图示一表示合并后），图示一表示将new分支合并到base分支上，合并操作完成后（后文会细说具体操作，此处不用纠结），会产生一个新的提交（蓝色提交），这个新提交就是合并后的提交，它包含了两个分支中的最新代码，并且将它们合并到了一起，这个提交就是我们想要的合并后的状态，base分支的指针会指向这个新的蓝色提交，而new分支的指针则没有移动位置，仍然指向了new分支的最新提交（绿色提交）。为什么base分支的指针会指向最新的蓝色提交，而new分支的指针却保持原位呢？我们可以这样理解，在合并之前，base分支和new分支都有属于自己独有的提交（最新的黄色提交只属于base分支，绿色提交只属于new分支），如果我们是把new分支合并到base分支上，就表示要把只属于new分支上的变更合并到base分支上，对于base分支来说，会有新的变更进入（原来只属于new分支的变更对于base分支来说就是新变更），新变更进入后，base分支的内容会产生变化，所以，base分支需要一个新的提交（蓝色提交）来对应变化后的状态，于是，base分支的指针会指向最新产生的合并提交（蓝色提交），而对于new分支来说，并没有任何内容发生变动，所以new分支的指针仍然保持原位。理解了图示一，再去理解图示二就非常简单了，道理其实是一样的，我们仍然对比着第4步去看图示二，图示二表示将base分支合并到new分支上，合并后会产生一个新的合并提交（蓝色提交），这个蓝色提交对应了合并后的状态，这个新的蓝色提交属于new分支，而不属于base分支，因为我们是把base分支合并到new分支上，这表示只属于base分支的变更会加入到new分支中，对于new分支来说，内容会发生变化，new分支需…

Git之旅(10)：后悔了，怎么办？
type: item
date: 2021-05-25T14:55:17+08:00
description: 博主会将与Git有关的知识点总结到”通俗易懂Git入门系列“文章中，如果你对Git不是特别了解，请按照顺序阅读”Git系列”，以便站在前文的基础上理解新的知识点。人都是会后悔的，你我都不能例外。在使用Git进行版本管理的过程中，我们也会经常后悔的，比如，我写了一些代码，做了一些修改，为了能将这些修改创建为提交，我先进行了暂存操作，但是没有立即创建提交，也就是说，这些修改从工作区同步到了暂存区，以便将来能够创建提交，但是过了一会儿，我后悔了，我觉得这些修改并不适合用来创建下次的提交，我该怎么办呢？这些修改已经存在于工作区和暂存区了，我现在想要保留工作区的修改，但是不想让这些修改同时存在于暂存区，也就是说，我想要撤销暂存区中的变更，我该怎么办呢？此时，我们只需要借助一条git命令就能达到我们的目的，这条命令就是”git reset HEAD”，看到这条命令，是不是觉得特别熟悉，没错，前文中我们粗略的使用过”git reset”命令，但是并没有详细的介绍它，这篇文章我们就来仔细的聊聊”git reset”命令。刚才说过，”git reset HEAD”命令可以帮助我们把暂存区恢复到未暂存任何工作区修改的状态（即与最新的commit的状态保持一致），那么现在我们就来通过实际的操作来演示一遍。首先，创建一个用于演示的测试仓库，然后创建两个用来测试的文件，最后初始化第一个提交，命令如下：$ git init test_repoInitialized empty Git repositoryinD:/workspace/git/test_repo/.git/$cd test_repo/$echo'test file1' >f1$echo'test file2' >f2$git add -A$git commit -m'init, add f1 and f2'[master (root-commit)1a09207]init, add f1 and f22files changed,2 insertions(+)create mode100644f1create mode100644f2$git log --oneline1a09207 (HEAD ->master)init, add f1 and f2如上述命令所示，我们创建了两个测试文件，f1和f2，并且创建了第一个提交，第一个提交的哈希码为”1a09207″。准备工作完毕，现在我们来模拟一遍文章开头描述的场景，命令如下：首先，在两个测试文件中各自添加一行新行，模拟修改操作，如下：$ echo'The second line in the f1 file' >>f1$echo'The second line in the f2 file' >>f2然后查看git仓库状态，发现有两个文件变更没有暂存，如下：$ git statusOn branch masterChanges not stagedforcommit:(use"git add <file>..."to update what will be committed)(use"git checkout -- <file>..."to discard changesinworking directory)modified: f1modified: f2no changes added tocommit (use"git add"and/or"git commit -a")看工作区和暂存区的差异，可以看到新增的两行$ git diffdiff --git a/f1 b/f1index d9e310a..2041f47100644--- a/f1+++ b/f1@@-1+1,2@@test file1+The second lineinthe f1 filediff --git a/f2 b/f2index d15d3b2..4d9f2f1100644--- a/f2+++ b/f2@@-1+1,2@@test file2+The second lineinthe f2 file将所有变更添加到暂存区$ git add -A再次查看仓库状态，发现两个测试文件的变更状态已经同步到暂存区，我们随时可以根据这些变更创建新的提交。$ git statusOn branch masterChanges to be committed:(use"git reset HEAD <file>..."to unstage)modified: f1modified: f2再次对比差异，可以看出工作区和暂存区已经没有任何差异。$ git diff刚才我将变更添加到暂存区是因为我觉的这些变更适合成为下一次的提交，但是我现在后悔了，我想要让这些变更从暂存区消失，…

Git之旅(9)：比较差异
type: item
date: 2021-05-25T14:54:03+08:00
description: 博主会将与Git有关的知识点总结到”通俗易懂Git入门系列“文章中，如果你对Git不是特别了解，请按照顺序阅读”Git系列”，以便站在前文的基础上理解新的知识点。前文中，我们一直在总结git中的各种概念，现在，我们可以换一个方向，从一些简单的使用场景出发，了解一些新的Git命令，不过我们前面的努力并没有白费，因为站在前文概念的基础上，能够很快的理解这些命令。这篇文章主要来聊聊怎样比较差异，比较差异是我们在使用git的过程中经常会遇到的场景，我们边做边聊，为了方便演示，重新创建一个git仓库，并且创建两个测试文件，命令如下：$ git init test_repo$cd test_repo$echo1 >>test1$echo2 >>test1$echo3 >>test1$echo a>>test2$echo b>>test2$echo c>>test2$git add test1 test2$git commit -m"init test file"我创建了两个测试文件，test1和test2，然后将这两个文件添加到了暂存区，最后创建了一个提交，也就是说，最新的提交中保存了test1文件和test2文件的当前的状态。目前test1和test2的文件内容如下：$ cat test1123$cat test2abc现在，我想要修改一下这两个文件，我想把test1文件的第2行删除，然后再添加一行，我想把test2文件的最后一行的’c’改成’cc’，修改后的结果如下：$ cat test113new$cat test2abcc上述修改的操作其实是在我的工作目录中进行的，上述操作完成后，我们并没有使用git add命令将修改添加到暂存区，更没有创建提交，所以说，当前工作区的test1文件和test2文件的内容与暂存区和提交中的内容是不同的，那么我们怎样对比这种不同呢？很简单，我们只要使用git diff命令就能够进行差异比较了，比如，我想比较一下，当前的工作目录和暂存区中都有哪些差异呢？则可以直接使用git diff命令进行对比，示例如下：注：最好在你的命令窗口中键入同样的命令，有语法着色的情况下更加直观$ git diffdiff --git a/test1 b/test1index01e79c3..397b006100644--- a/test1+++ b/test1@@-1,3+1,3@@1-23+newdiff --git a/test2 b/test2index de98044..278314e100644--- a/test2+++ b/test2@@-1,3+1,3@@ab-c+cc执行git diff命令后，返回信息如上，可以看到，test1文件中的第二行被删除了，因为”2″前面有一个减号，并且，添加了新的一行，新行的内容为”new”，因为”new”前面有一个加号，test2文件中的差异也被显示了出来，我们把test2文件中的第三行的’c’改成了’cc’，对于git来说，git认为我们把’c’这一行删除了，然后又在原位置添加了新的一行’cc’，可以看出，当我们使用git diff命令时，git会将工作区与暂存区中的所有文件差异一次性的全部显示出来，如果我们只想查看某个特定文件在这两个区域的差异，也可以指定要查看的文件，比如，我们只想看看test1文件在工作区和暂存区是否存在差异，只需要执行如下命令即可：$ git diff -- test1diff --git a/test1 b/test1index01e79c3..397b006100644--- a/test1+++ b/test1@@-1,3+1,3@@1-23+new上例中的’–‘后面可以跟随多个文件路径，每个文件路径用空格隔开，上述命令中我们只指定了test1文件的文件路径。由于我们修改文件以后并没有暂存这些修改，更没有创建提交，所以，目前来说，暂存区和提交中的文件内容是相同的，也就是说，”暂存区和提交中指向的文件” 与 “工作区中的文件” 之间的差异是相同的，那么，怎样查看工作区和提交中的文件差异呢？如果想要查看工作区和最新提交之间的差异，则可以使用如下命令查看：$ git diff HEADdiff --git a/test1 b/test1index01e79c3..397b006100644--- a/test1+++ b/test1@@-1,3+1,3@@1-23+newdiff --git a/test2 b/test2index de98044..278314e100644--- a/test2+++ b/test2@@-1,3+1,3@@ab-c+cc没错，使用”git diff HEAD”命令即可查看工作区与当前分支最新的提交之间的差异，还记…

Git之旅(8)：HEAD是啥？
type: item
date: 2021-05-25T14:46:47+08:00
description: 博主会将与Git有关的知识点总结到”通俗易懂Git入门系列“文章中，如果你对Git不是特别了解，请按照顺序阅读”Git系列”，以便站在前文的基础上理解新的知识点。上一篇文章中，我们提到了一个概念，那就是HEAD，但是我们并没有详细的去解释HEAD是个什么东西？这篇文章我们就来聊聊什么是HEAD为了方便，我仍然使用之前的测试仓库进行测试，你也可以随意的创建一个用于测试的git仓库，然后创建几条分支，以便测试时使用。我们先来回顾一下前文中测试仓库的状态，如下：注：下图中使用了前文中创建的allbranch视图如上图所示，我们现在有两个分支，master分支和test分支，从上图可以看出，目前我们处于黄色的提交，也就是test分支的”add D to m2″，如果我们想要切换回master分支，则可以使用前文中总结的如下命令/d/workspace/git/test_repo1 (test)$git checkout masterSwitched to branch'master'/d/workspace/git/test_repo1 (master)$如上述信息所示，我们已经从test分支切换到了master分支。假设，我们现在关闭git bash和工作目录，当我们下次再次进入工作目录并且打开git bash时，仍然会显示为当前处于master分支，因为我们上次关闭工作目录之前，已经切换到了master分支，当然，如果你之前处于test分支，那么当你再次打开工作空间，仍然会显示你处于test分支。那么问题来了，git是怎么知道我们当前该处于哪个分支呢？git其实就是靠HEAD知道我们该处于哪个分支的，你可以把HEAD理解成一个指针，HEAD指针通常会指向一个分支（或者说指向一个分支指针），分支和分支指针的概念我们在前文中已经说明过，此处不再赘述，你可以把HEAD也理解成一个指针，这个指针通常指向一个分支指针，这样说不太直观，不如看下图（仍然在前文的图片的基础上进行修改）：如上图所示，由于我们当前处于master分支，所以，HEAD这个指针指向了master分支指针，如果我们现在检出test分支，那么HEAD指针就会指向test指针，也就是说，当我们从master分支检出到test分支时，HEAD指针会由上图中的状态变成下图中的状态：所以说，git只要找到HEAD，就能找到我们当前所处的分支（因为我们在切换分支时，会将HEAD指向所在的分支）。我们可以直观的查看当前仓库的.git目录中的HEAD文件的内容，你会发现，其实.git/HEAD文件的内容就是HEAD指针所指向的分支，如下所示：/d/workspace/git/test_repo1 (master)$cat .git/HEADref: refs/heads/master从上述返回信息可以看出，当前HEAD指针指向了另一个文件，这个文件就是.git/refs/heads/master，那么我们顺藤摸瓜，看看.git/refs/heads/master这个文件的文件内容/d/workspace/git/test_repo1 (master)$cat .git/refs/heads/master7406a10efcc169bbab17827aeda189aa20376f7f可以看到，这个文件的内容是一串哈希码，而这个哈希码正是master分支上最新的提交所对应的哈希码。聪明如你，肯定已经看出来了，.git/HEAD文件和.git/refs/heads/master文件不正是上图中的HEAD指针和master分支指针么，没错，就是这样的，只不过，在Git中，这些代表了上图中”指针”的文件还有另外一个名字，它们被称之为”引用” （references 或者 refs），其实都是一样的东西，不用纠结于它们的名字。为了证明我们的想法，我们切换几次分支， 看看.git/HEAD文件内容的变化/d/workspace/git/test_repo1 (master)$git checkout testSwitched to branch'test'/d/workspace/git/test_repo1 (test)$cat .git/HEADref: refs/heads/test/d/workspace/git/test_repo1 (test)$git checkout masterSwitched to branch'master'/d/workspace/git/test_repo1 (master)$cat .git/HEADref: refs/heads/master嗯嗯，看来是没错了，跟我们想的一样，HEAD指针通常指向我们所在的分支（的分支指针）。前文中说过，当我们在某个分支上…

Git之旅(7)：分支是啥？
type: item
date: 2021-05-25T13:50:38+08:00
description: 博主会将与Git有关的知识点总结到”通俗易懂Git入门系列“文章中，如果你对Git不是特别了解，请按照顺序阅读”Git系列”，以便站在前文的基础上理解新的知识点。直到现在，我们一直都偏重概念，通常是在介绍清楚相关概念以后，才会结合相关的命令进行练习，所以，如果你同时也在看别的教程，你会发现很多不同之处，你甚至会觉得我们的进度太慢了，如果你看别的教程，在看到第7篇的时候，应该已经介绍了很多命令，但是你可能并不理解为什么要那样做，我们力求在使用命令的同时能够理解相关的原理，所以，不要着急，厚积薄发，搞定命令简直不要太轻松。前文中，我们一直在创建提交，但是一直没有回退到过任何一个版本，主要执行的命令就是，查看状态、暂存修改、创建提交，一直在重复这三件事，这样做是为了更好的理解工作区、暂存区、提交之间的关系，不如现在，我们来尝试一下，回退到某个版本，看一看利用git进行版本回退的效果，同时，通过版本回退的操作引出”分支”的概念。为了我们的思路能够同步，我决定重新创建一个测试仓库，一步一步的创建提交，并且回退到特定的版本，过程如下：创建测试仓库$ git init test_repoInitialized empty Git repositoryinD:/workspace/git/test_repo/.git/进入仓库，创建两个测试文件，f1和f2$ cd test_repo/$echo1 >f1$echo A>f2如上述命令所示，f1的内容为1，f2的内容为A。测试文件已经初始化完成了，我们来创建第一个提交吧。$ git add .使用”git add .”命令将当期目录中的所有变更状态加入到暂存区，然后使用如下命令创建第一个提交，注释信息为1A$ git commit -m"1A"[master (root-commit)510658e]1A2files changed,2 insertions(+)create mode100644f1create mode100644f2多次修改f1和f2的文件内容，并且创建对应的提交，为一会儿的回退测试做准备，过程如下，不再详细描述$ echo2 >>f1$echo B>>f2$git add .$git commit -m"2B"[master 2fc70fe]2B2files changed,2 insertions(+)$echo3 >>f1$echo C>>f2$git add .$git commit -m"3C"[master aa81e63]3C2files changed,2 insertions(+)$echo4 >>f1$echo D>>f2$git add .$git commit -m"4D"[master 866b6de]4D2files changed,2 insertions(+)$echo5 >>f1$echo E>>f2$git add .$git commit -m"5E"[master 526ff66]5E2files changed,2 insertions(+)我又一口气创建了4个提交，每次修改都对两个文件加入一行新文本，到目前为止，我们一共已经有了5个提交，最新的提交是注释信息为”5E”的提交，当前状态下，两个文件的内容如下：$ cat f112345$cat f2ABCDE现在，我后悔了，我想要回到”3C”时的状态，该怎么办呢？如果想要回到”3C”时的状态，首先要找到”3C”提交的哈希码，我们先通过git log命令看看3C状态对应的哈希码吧。$ git log --oneline526ff66 (HEAD ->master)5E866b6de 4Daa81e63 3C2fc70fe 2B510658e 1A从上述信息可以看出，”3C”提交对应的ID是aa81e63 ，好了，状态对应的哈希码已经找到了，我们可以使用如下命令，回到”3C”提交对应的状态$ git reset --hard aa81e63HEAD is now at aa81e63 3C执行完上述命令后，再次查看工作区内两个文件的内容，如下：$ cat f1123$cat f2ABC可以看出来，我们已经回到过去了，轻松的实现了版本回退，我们只是执行了一条”git reset –hard”命令而已，我们先不纠结这条命令的参数都是什么含义，之后我们再去详细的了解它。如果，我回到”3C”状态以后又反悔了，想要再次回到”5E”时的状态，该怎么办呢？聪明如你一定想到了，仍然使用刚才的命令啊，我们只要找到”5E”状态的哈希码，就能够通过”git reset –hard”命令再次回到”5E”的状态了，没错，思路完全正确，于是，我们可能会想要尝试使用”git log –oneline”命令查找”5E…

Git之旅(6)：从概念到实践
type: item
date: 2021-05-25T13:49:42+08:00
description: 博主会将与Git有关的知识点总结到”通俗易懂Git入门系列“文章中，如果你对Git不是特别了解，请按照顺序阅读”Git系列”，以便站在前文的基础上理解新的知识点。在git中，有一些”区域”的概念，我们在使用git时，其实一直都在使用这些”区域”，所以，了解git”区域”的概念是必须的，这有助于我们使用git和理解git的工作原理。从物理上来说，我们能直观的看到两个”区域”，一个是”工作区”，一个是”版本库”。就拿我们之前的测试仓库举例，进入git_test仓库，你会发现一个名为”.git”的隐藏目录，以及除了”.git”目录的其他文件和目录，如下图所示其实，上图中的”.git”目录就是所谓的”版本库”，而上图中除了”.git”目录以外的其他文件和目录组成了”工作区”，换句话说就是，进入git_test目录，排除”.git”目录以后的区域就是工作区，工作区的概念非常容易理解，因为我们的实际工作就发生在这个区域，我们在这个区域创建文件和目录、编辑文件、删除文件和目录，这些操作都是在工作区完成的，而当我们需要把工作区的状态保存到版本库时，则需要借助到”版本库”区域了，也就是说，两个区域的关系如下图当工作区的状态保存到版本库以后，工作区的文件就会转换成blob对象，工作区的目录结构会转换成对应数量的tree对象（前文中已经总结了git对象的概念，此处不再赘述），这些git对象存储在”版本库区域”的对象库中。不知道你还记不记得，在前文中，当我们想要将一个状态保存下来时，通常会通过类似如下两条命令创建一个提交$ git add -A$git commit -m"some comment"如你所见，上述两条命令协力将工作区的状态保存到了版本库中，也就是说，仅仅靠上述一条命令是无法完成整个操作的，前文说过，我们可以利用”git add”命令选择将哪些变更加入到下一次的提交中，其实，当我们执行”git add”命令以后，工作目录中文件的状态就已经转换成blob对象了，当我们使用”git commit”命令以后，才会创建出commit对象。其实，在工作区和最终存储的对象之间还有一个”重要区域”，这个区域被称之为”索引”或者”暂存区”，而刚刚提到的”git add”命令其实就是用来操作索引区域的，如果跟前文中的对象的概念结合在一起，那么索引区域应该在下图中的如下位置上图描述了第一次提交产生以后，各个区域的状态，从上图可以看出，工作区有两个文件，file1和file2，文件内容分别为f1和f2，在对象库区域中，第一次提交对应的commit对象(圆形)已经指向了对应的tree对象（三角形），tree对象又指向了直接子目录的blob对象，而此时，索引的结构与对象库其实是一样的，索引也指向了file1和file2对应的blob，或者说，索引中记录的file1和file2的哈希就是上图中那两个blob的哈希，目前来说，我们不用纠结索引到底是什么样的，在后文中我们会通过更加直观的方式去了解它，但是在这之前，我们先借助上图去搞明白它的概念和作用就好，只依靠上面一幅图就想完全搞明白索引的作用有些不太现实，最好坚持看完后文，再回过头来理解，就容易多了， 就目前的状态而言，索引和对象库中的状态是一致的，都指向了同样的blob。如果此时，我们修改了工作目录中的file2文件，我们将其内容从f2改为了f22，那么此时，各个区域的状态如下图所示。当file2的内容变化以后，工作区file2文件的状态已经发生了改变，工作区中file2的新状态已经与索引区和对象库中的状态不一致了，索引和对象库中指向的仍然是file2的内容为f2时的状态（即上图中哈希为9de77c1的blob），这时，file2的新状态对应的blob对象还没有生成，file2的新状态只存在于工作目录中，那么file2的新状态对应的blob对象是在什么时候生成的呢？刚才其实我们已经剧透了，当我们执行”git add”命令以后，对应的blob就会产生，”git add file2″命令执行后，对象库和索引区的状态如下图：如上图所示，当”git add file2″命令执行以后，”git add”命令会做两件事，第一件要做的事就是为file2的新状态创建blob对象，也就是上图中浅灰色曲线所表示的步骤，当新的blob对象（即上图中哈希为a8319的blob对象）创建完成后，”git add”命令就会做第二件事，即更新索引，将索引中的file2指向新创建的blob对象，即上图中橘黄色曲线所表示的步骤，橘黄色的区线表示索引中的file2原来指向9de77c1，当”git add”命令执行后，索引中的file2指向了a8319f8。此时，虽然在对象库中已经生成了file2文件的新状态对应的blob，但是仍然没有任何一个提交…