漫谈Git和Github 客官°小女子只卖身不卖艺 2022-05-26 07:14 159阅读 0赞 ![image.png][] 上期[漫谈版本控制系统][Link 1]中我们谈到了版本控制系统的四个演进过程,即悲观锁版本 -> 乐观锁版本 -> 多分支版本 -> 分布式版本,目前我们使用最多的是分布式版本,本期我们就来介绍下分布式版本控制系统的具体实现**Git**和**GitHub**。 ## Git基础 ## Git不用于其他版本控制系统主要体现在以下几点:1. Git对待数据的方法,直接记录快照,而非差异比较;2. 暂存区;3.高效的分支模型。 \- **直接记录快照,而非差异比较** CVS、Subversion等版本控制系统会以文件变更列表的方式存储信息,即以增量形式存储信息,如下图所示。而Git全量方式存储信息,同时为了减少空间使用,当文件没有修改时,最新版本中并不会存储该文件的全量信息,而是保留一个链接指向之前存储的文件。譬如`File A`在version2发生了修改,因此全量存储文件信息,而在version3并没有修改,因此保留一个链接指向A1。 ![CVS、Subversion等版本控制系统存储文件方式][CVS_Subversion] ![Git文件存储方式][Git] * **工作目录、暂存区、本地仓库** Git引入三个工作区域的概念:工作目录(Working Directory)、暂存区(Staging Area)、本地仓库,尤其是暂存区具有独创性。工作目录是对项目的某个版本提取出来的内容存放到磁盘中;**暂存区只是一个文件,保存下次提交的文件列表信息**;本地仓库是Git用来保存项目的元数据和对象数据库的地方,当进行克隆仓库时,拷贝的就是这里的数据。**数据在三者之间的基本交互流程**:1.在工作目录中修改文件;2.暂存文件,将**文件的快照**存放到暂存区域;3.提交更新,找到暂存区域的文件,将快照永久性存储到Git仓库中。 ![image.png][image.png 1] \- **高效的分支模型** 在很多版本控制系统中,创建一个分支意味着需要完全创建一个源代码目录的副本,对于大型项目来说,这样的过程会耗费大量时间,而这对于Git来说是非常轻便的。上文我们已经提到Git对待数据的方法,即直接记录快照,同时,Git在进行提交操作时,它会保存一个**提交对象**(commit object),该对象会包含一个指向暂存内容快照的指针,提交者的姓名、邮箱、输入信息和指向它的父对象的指针。注意:首次提交的提交对象没有父对象。 为了帮助大家更好地理解,假设有一个工作目录,包含三个将要被暂存和提交的文件。**暂存操作**为每个文件计算校验和,然后把当前版本的文件快照保存到Git仓库中(Git使用blob对象保存它们)。当使用`git commit` 进行提交操作时,会计算每一个子目录的校验和,然后在Git仓库中将这些校验和保存为**树对象**,随后,Git便会创建一个提交对象,它除了包含上面提到的那些信息外,还包含指向这个树对象的指针。如下图所示,现在Git仓库包含五个对象:三个blob对象(保存着文件快照)、一个树对象(记录着目录结构和blob对象索引)以及一个提交对象。 ![image.png][image.png 2] ## 安装 ## * Windows系统 可以通过cmder中的`choco install git`,也可以通过普通安装完成 * Mac系统 `brew install git` * Linux系统 `yum install git` * 检查安装是否成功 `git --version` ## 初次运行Git前的配置 ## **用户信息** 当安装完Git之后应该做的第一件事就是设置你的用户名称和邮件地址,这样做很重要,因为每一次Git提交都会使用这些信息。 git config --global user.name "mukedada" git config --global user.email mukedada@126.com 注意`--global`选项表示全局设置。 **检查配置信息** 通过`git config --list`命令列出所有Git当前能找到的配置,还可以通过`git config <key>`来检查某一项配置,例如:`git config user.name`,结果: $ git config user.name mukedada ## 获取Git仓库 ## 目前有两种方式获取Git项目仓库的方法。第一种方法是把现有目录下的所有文件导入到Git中;第二种方法是一个服务器克隆一个现有的Git仓库。 **在现有目录中初始化仓库** $ cd test $ git init 在test目录下创建一个名为`.git`的子目录。 **克隆现有的仓库** 克隆仓库的命令格式是`git clone [url]`。比如,要克隆木可大大的code仓库,可以用下面的命令: $ git clone git@github.com:mukedada/code.git 这回在当前目录下创建一个名为”code”的目录,并在这个目录下初始化一个`.git`文件夹。 ## 记录每次更新到仓库 ## test目录下的每个文件都不外乎两个状态:**已跟踪或未跟踪**。已跟踪的文件是指那些被纳入了版本控制的文件,在上一次快照中有它们的记录,在工作一段时间后,它们的状态可能处于未修改或已修改或一放入暂存区。test目录下除了已跟踪的文件以外,剩下的文件都属于未跟踪的文件,它们既不存在于上次快照的记录中,也没有放入暂存区。初次克隆的test仓库,此时该工作目录中的所有文件都属于已跟踪文件,并处于未修改状态。编辑过某些文件之后,由于自上次提交后我们对它们做了修改,Git将它们标记为已修改文件。我们逐步将这些修改过的文件放入暂存区,然后提交所有暂存区中的修改,如此反复。 ![image.png][image.png 3] ## 检查当前文件状态 ## 使用`git status`名称查看当前文件处于什么状态。 $ git status On branch master Your branch is up to date with 'origin/master'. nothing to commit, working tree clean `nothing to commit,working tree clean`说明当前工作目录中所有已跟踪的文件在上次提交之后没有修改过;`On branch master`说明当前处于`master`分支。 现在,我们在test项目下创建text.txt文件,再使用`git status`命令。 $ echo 'my project' > test.txt $ git status On branch master Your branch is up to date with 'origin/master'. Untracked files: (use "git add <file>..." to include in what will be committed) test.txt nothing added to commit but untracked files present (use "git add" to track) 从中我们可以发现,test.txt在`Untracked files`下面,这就意味着该文件并未在之前的快照中,如果我们想让该文件纳入到Git的跟踪范围内,需要使用`git add`命令。 ## 跟踪新文件 ## `git add + 文件或目录`,如果是目录,则将递归跟踪该目录下所有的文件。 $ git add test.txt $ git status On branch master Your branch is up to date with 'origin/master'. Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: test.txt 只要出现`Changes to be committed`说明test.txt已经进入暂存区。 ## 暂存已修改文件 ## 现在我们修改test.txt,发现该文件既出现在`Changes to be committed`下面,又出现在`Changes not staged for commit`下面,前一句说明该文件在暂存区,而后一句说明该文件在非暂存区,这怎么可能呢?其实,文件在暂存区是因为暂存区保存的是我们上一次运行`git add`命令时的版本,接着我们没有运行`git commit`命令,而是对文件进行修改,所以出现了`Changes not staged for commit`,因此,我们需要对修改后的文件重新运行`git add`命令把最新版本重新暂存起来。 $ vim test.txt $ git status On branch master Your branch is up to date with 'origin/master'. Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: test.txt Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: test.txt ## 查看已暂存和未暂存的区别 ## 通过上面代码我们知道我们对已暂存的test.txt进行了修改,还没有执行`git add`命令,但是我们不知道具体修改了什么内容,此时,我们就可以用`git diff`命令来查看修改的内容。 $ git diff diff --git a/test.txt b/test.txt index a159320..b3b1c1b 100644 --- a/test.txt +++ b/test.txt @@ -1 +1,2 @@ hello 'my project' +haha~ ## 提交更新 ## 使用 `git commit -m "备注"`命令提交存放在暂存区的快照,`-m`选项表示提交时备注信息。 ## 跳过使用暂存区域 ## `git commit`加上`-a`选项表示跳过`git add`步骤直接将文件保存到暂存区。 ## 打标签 ## * 列出标签 输入`git tag`命令: $ git tag v0.1 * 创建标签 $ git tag -a v1.0 -m 'my version 1.0' $ git tag v0.1 v1.0 ## 分支 ## **Git分支,本质上就是指向提交对象的可变指针**。每当提交一次,都会生成一个新的提交对象,它包含一个指向上次提交对象的指针,如下图所示。 ![image.png][image.png 4] **分支创建** 通过使用`git branch`命令创建分支,譬如: $ git branch testing ![image.png][image.png 5] 当有两个指向相同提交历史的分支,Git怎么知道当前在哪一个分支上呢?Git有一个特殊指针`HEAD`,它指向当前所在的本地分支。 ![image.png][image.png 6] **分支切换** 通过使用`git checkout`命令进行分支切换,譬如:我们切换到新创建的testing分支上: $ git checkout testing 此时,HEAD就指向`testing`分支。 ![image.png][image.png 7] **分支合并** 目前Git分支合并主要有两种方法:`merge`和 `rebase`。 \- **merge**:把两个分支的最新快照和以及两者最近的共同祖先进行三方合并,合并的结果是生成一个新的快照,并提交,如果没有冲突的话。举个栗子,首先将`hotfix branch`合并到`master`分支上,由于当前`master`分支所指向的提交是`hotfix`分支的之间上游,因此Git知识简单的将指针向前移动,这就是**快进(fast-forward)**。 $ git checkout master $ git merge hotfix Updating f42c576..3a0874c Fast-forward index.html | 2 ++ 1 file changed, 2 insertions(+) ![image.png][image.png 8] ![image.png][image.png 9] 由于`master`分支和`hotfix`分支指向同一个位置,我们可以使用`git branch -d`指令**删除分支**: $ git branch -d hotfix 接下来,我们继续在`iss53`工作,最后一个提交对象是`C5`,此时,如何合并`iss53`分支和`C5`分支? ![image.png][image.png 10] 我们需要将`HEAD`指向`master`,然后执行`git merge`命令: $ git checkout master Switched to branch 'master' $ git merge iss53 Merge made by the 'recursive' strategy. index.html | 1 + 1 file changed, 1 insertion(+) 这和之前合并`hotfix`分支看起来有些不同,Git会使用两个分支的末端所指的快照(`C4`和`C5`)以及这两个分支的工作祖先(`C2`),做一个简单的三方合并。 ![image.png][image.png 11] * **rebase** ,中文名”变基”,即将某一分支上的所有修改都移植到另一分支上,就好像”重新播放”一样。为了加深大家的印象,对`C4`分支和`C3`分支进行合并,首先提取`C4`的修改,然后在`C3`上重新播放一遍。 ![1240][] $ git checkout experiment $ git rebase master First, rewinding head to replay your work on top of it... Applying: added staged command 执行完上述代码之后,形成如下结构。 ![1240 1][] 对于上述结构,我们还需要进行一次合并。 $ git checkout master $ git merge experiment ![image.png][image.png 12] * 注意:当两个不同的分支中,对同一个文件的同一个部分进行不同的修改,Git就没法干净的合并它们,此时需要我们手动解决冲突。 ## GitHub ## 目前,GitHub是最大的Git版本库托管商,大部分开源项目都托管在Github,因此学习Github就比不可少了。 \- 账户的创建和配置 访问[GitHub官网][GitHub],填写相关信息完成注册。 ![image.png][image.png 13] \- 配置SSH 首先需要生成本机公钥,如果是Window,使用指令`ssh-keygen -t rsa -C "mukedada@126.com"`生成主机的公私密钥对,如果是Mac,则使用`ssh-keygen`命令上。注意:运行上述指令时,不要输入任何信息,只需按enter就可以,成功之后,公私钥文件会存放于当前用户目录的.ssh目录下,例如`C:\Users\kwy\.ssh`。接着,将生成出的公钥放到github中。 ![image.png][image.png 14] \- 创建仓库 ![image.png][image.png 15] \- 克隆远程仓库到本地:`git clone git@github.com:mukedada/artical.git` -------------------- ![image][] 欢迎关注微信公众号:木可大大,所有文章都将同步在公众号上。 [image.png]: /images/20220526/8a5f961543d849d2a52ec3347e139f97.png [Link 1]: https://www.jianshu.com/p/a46f1cdada53 [CVS_Subversion]: /images/20220526/b7096e8ae7e74cdfaeb8b91c08e5db7a.png [Git]: /images/20220526/82a0890dc50940f6aaa866349fe54ec6.png [image.png 1]: /images/20220526/5f97cac55b8d482c93bbe505829de880.png [image.png 2]: /images/20220526/0628e80ebbd64ccaa69a26b62a4b8b27.png [image.png 3]: /images/20220526/5bce8791172249c0a1c2eafb50872147.png [image.png 4]: /images/20220526/b56da7b9b8794917bd9357583309fb5c.png [image.png 5]: /images/20220526/0b26f2e262f14d2ebcd4c2768aca4ddb.png [image.png 6]: /images/20220526/2fd07fe42bdd47ddba3b4b8f8603d118.png [image.png 7]: /images/20220526/a04398c6df4343db86f86679c7cabce6.png [image.png 8]: /images/20220526/d7e42b4bbcca4b6dae15364505a26d99.png [image.png 9]: /images/20220526/abefd2e4743b43a782a10bb4fdb3c864.png [image.png 10]: /images/20220526/1e95dc2cbba347459170ce6dadda6860.png [image.png 11]: /images/20220526/7e7e3dbf0f6b4e73a3c2ea5c7dfcc9f7.png [1240]: /images/20220526/4b6e26baa88142a2a0536a7f49845735.png [1240 1]: /images/20220526/6c061b3457484cfb971e63334d092b51.png [image.png 12]: /images/20220526/24af2f86b3734aca8c3cf35d4ea24275.png [GitHub]: https://github.com/join [image.png 13]: /images/20220526/c43f5a4a20204ccdaff951c031920e2d.png [image.png 14]: /images/20220526/33bfe257543a4d1bae664241002003ef.png [image.png 15]: /images/20220526/017b958c74de48d381d04a9017d966d9.png [image]: /images/20220526/93a5ca3b6c444e149f1640f3fdcff916.png
还没有评论,来说两句吧...