Git是一个分布式的版本控制系统,最初由Linus Torvalds编写,用作Linux内核代码的管理。在推出后,Git在其它项目中也取得了很大成功,尤其是在Ruby社区中。目前,包括Rubinius、Merb和Bitcoin在内的很多知名项目都使用了Git。GitHub 使用 Git 作为版本控制系统(version control system)提供在线源码托管的服务。同时是一个有社交功能的开发者社区。
1.Introduction
介绍Git,一个版本控制系统。它带来的分布式特性,能让你在本地或者web上的存储资源上工作,它沿袭了CVS和Subversion。
我爱Git的原因之一是,我做的一切工作都是在我的笔记本上的本地修改,直到我显式地告诉它(提交修改)。因此,如果我没有任何互联网连接,没关系,我还是能做一些工作。当我终于连接上了互联网,我可以将该数据发送回远程服务器和做更多的工作。
所以,我可以从本地机器的存储器开始,最终,当我需要进行协作时,将它放到网上,或某些其他托管的解决方案里,这给了我两者的灵活性。
我做的一切工作,都可以在版本控制下。但是我开始的时候总是遇到这样的问题,“我将需要什么工具?”使用命令行并不是唯一的选择,当我们使用Git时,有不同的图形化用户界面,支持所有主流操作系统。
都有自己的图形化用户界面,但是也都与可用的命令行工具绑定。
如果我想想“我需要学习多少东西,才能使用这个高效工作呢?”
大约十个命令,而且大约单击十个按钮就将足以使你使用这个来满足你每日的软件开发需求。
GitHub Social Coding社交编码
git init 新项目
我们刚刚谈了工具、命令行、图形化用户界面,它是怎样从本地数据库启动,然后被推送到web,但是我感兴趣的是,当我启动一个软件项目,为什么我要从本地创建资源库,而Git怎么将那称作分布式的版本控制?
答:这个本地控制的想法,允许我们只从新项目启动,就在我们的命令行上或者用一个图形用户界面,我们仅需要输入"git init 新项目" ,就会创建一个文件夹,就在我们的文件系统中,这个即被称为新的项目。
如果继续前进转到文件夹目录结构,我们将会看到它只包含一个简单的.git文件。
.git文件:
这真的是我们所需要的一切,做任意量我们需要做的工作。我们可以再深入一点,去.git文件夹里去看一些内部情况。真正了解Git是如何持久化这些对象的。
所以.git文件夹是这样的,一个具有一些简单的文件的文件夹,这些主要是纯文本格式,就是在这里,所有的东西得以保存,当我们对我们的源代码和项目做历史演变时。好处就是.git文件夹就是每一个Git和GitHub的工具的写入目标。无论它是GUI或命令行,它只需写入.git文件夹中。关闭笔记本电脑,让它睡觉,所有东西都保存了下来。
git remote add origin https://github.com/……
2、现在当我开始想要添加远程目标时该怎么做呢? 当我想要与别人合作时该怎么做呢?我们一直在谈论本地保存,在本地持久化,但怎样分享给其他人,和他们一起在源代码上工作呢?如何远程与他人交互?
答:所以,当你想要与一个不同的远程端进行交互时,不管是 GitHub.com或甚至是朋友的笔记本电脑,你可以通过创建一个不用的地址来设置它,就在配置文件里面。
$ git remote add origin https://git.com/……
cat.git/config
$ cat.git/config
这只是Git用于开始读取的另一个地方,不仅要了解它将数据发送到那里,还要了解它可以从那里提取数据。
所以这种想法很简单,再次,仅需要从文本文件中读取,让Git知道有这么个地址,我想从那里得到资料,也有可能要将信息发送到那里,但同样,仅当你指定了位置。
所以我们设置了这个地址,它可以是在您的网络中的,如果您有一个自托管的解决方案,它也可以在web上,如果您正在使用GitHub.com,工具知道如何与他对话。而你的主要工作仍然发生在笔记本上,本地的,不具有网络访问权限,但后来偶尔如果你需要与其他人协作,并与它们共享该代码,你使用这两个命令,正如你所说,push和pull。
2.Setup
我们将来帮助你学会如何安装设置Git。要来设置Git,你需要有Git命令行工具,Git图形用户界面以及github.com账号。
设置清单(Setup Checklist)
首先,你需要确认你已经安装了Git命令行工具,我们提供一个相应的安装包,同时,我们也有Git图形用户界面的安装包,此外,你还需要确认你有github.com的账号。在确认这三个要素都符合要求之后,我们还希望能够保持它们有最新的版本,这些工具都是自动更新的。
设置:Git版本
要想安装Git命令行工具,我们最好先去git-scm.com来查看一下。
在这里你能找到一份清单,包括了Git所有不同的版本。你能找到基于不同的操作系统应该如何安装Git命令行工具。
如果今后你对何时需要更新有任何问题,你都可以常常来这个网站查看最新的版本是什么。
GitHub安装包
好了,之前我们看到的是种比较费时的安装办法,我们还提供了一种更简便的方法——用户图形界面安装。在mac.github.com和windows.github.com这两个网站上。
你能找到把Git用户图形界面和命令行工具合二为一。同时,它也有自动更新的功能,这样就可以一直保持最新版本。
所以,如果你在使用这些操作平台,并且你不知道你是否会一直使用命令行工具,或者仅仅是偶尔用一些。那么你最好选择这个安装包,因为它可以一直保持最新的版本。
一旦你安装好了这些工具,你就可以在本地创建repository了。不过,和他人合作也是Git的一个重要任务。
我需要怎么做才能把代码和你共享呢?
设置GitHub账号
当你决定要和他人进行合作之后,那么你马上需要做的就是——注册一个免费的GitHub账号,接下来就可以开始与他人合作了。你可以用相同的密码来登入任何一个桌面客户端。
之后就会显示出你已经建立的所有的Repository。还有那些你可以commit的repository。
接下来你就可以把这些和你的同事共享了。
3.Config
如果你已经安装了Git,让我们配置一下你的设置。
首先,你需要确保你配置了你的user.name和 user.email。然后你可以调整行的结尾和颜色,做一点个性化。最后,我们需要确保我们理解不同的设置级别:做你想跨越所有的资料库还是只设置你现在工作的那个地方?
配置用户信息(Config User Info)
user.name和 user.email配置正确,对你的工作产权很重要。你想要识别一些你的工作吗?你需要确保用户名和电子邮箱设置正确。这些值会延续到你为你的工作得到的信用,并会在github.com等网站的用户界面中显示,当你发布和导入内容时。
git config --global user.name bihailantian21
git config --global user.email 864620611@qq.com
配置行尾&颜色(Config Line Endings & Color)
行尾是特别重要的,因为在不同平台中的仍然有区别:Mac,linux,Windows,CR与CRLF,LF,所有这些选择,Git将帮助标准化那些正在被check的文件到存储库,通过设置比如 core.autocrlf。
git config --global core.autocrlf true
git config --global core.autocrlf input
git config --global color.ui auto
颜色是更多的用户界面调整,颜色是非常容易识别的东西。无需读取整个句子,因此,如果我们的某个东西时红色的,我们可能知道那仍在进行处理。相反,如果某个东西是绿色的,意味着它运行正常。
git diff
分支以颜色列出,状态以颜色列出,历史记录日志以颜色列出。几乎每个Git命令,以红色、绿色、黄色和其他颜色为补充,来知识该代码的状态。那条线,该分支或那次提交。
Config有用的设置
这三种设置我们刚刚一直在讨论,我们想要设置的几个级别。一个像是全系统的,一个可能更窄点。
git config --local user.name bihailantian21
git config --local user.email 864620611@qq.com
更窄的是local设置,这是离我们最近的那个,具有最高的优先级,大于global。
global稍弱,将被local覆盖。
System最弱,通常是最模糊的或者不常用的设置,将被global或者local覆盖。
所以我告诉我的学生它就像面向对象继承那样工作。最近的设置级别就是那个有效的。–local,在这种情况下。
local > global >system
4.Init
要怎样开始使用GitHub呢?我们将告诉你如何初始化一个Git仓库。
你可以在本地做这件事,比如在你的电脑上,或者在github.com云端完成这件事,我们将分别演示这两种方式。
本地仓库
假设在你的电脑上,已经有一个项目,你已经完成了一些工作,然后你觉得你应该把这个项目做个版本控制,这其实很简单,来到你这个项目的目录下,在命令行中输入"git init ",这个目录就被变成有git仓库的了。并且它完全不会影响到你现在的项目。
ls -l
git init
git init 目录名称
如果你想变得更谨慎些,也许你希望在开始一个项目之前,就像把它纳入版本控制中,这也很简单。
在你开始一个新项目之前,先输入:“git init 目录名称”。就把这个目录初始化成了有git仓库的目录。
在本地端git是十分有用的,不过更厉害的是,当你开始和别人一起在github.com上面合作。让我们来看看怎样在这里创建一个新的git仓库。
在GitHub.com上的仓库
如果你在你的电脑上还没有一个本地的项目,那么让GitHub来为你创建"Read Me"和.gitignore文件将会是件很方便的事。
当你已经在你的电脑上完成创建本地仓库,也在github.com上面建立好之后,你接下来要做的就是把这两者连接起来。
GitHub会给你一些帮助以供参考。不过在这之前,我们还有一些东西想先来讨论一下。
登陆github.com,接着找到"new repository"新建仓库的按钮。
然后输入你想要创建项目的名称。请注意,这个名字并不一定要独一无二,它只需要不和你现有的仓库名称重名就可以。你的用户名将作为你所有项目的命名空间,这就使得识别任意一个项目简单多了。现在你要来决定这个仓库是公开的还是私人的。还有你是否想要GitHub来创建一个"README"或者一个.gitignore文件。
"README"就是告诉人们你这个项目是关于什么的。.gitignore文件会告诉git哪些文件你不希望纳入版本控制系统。
如果在你的电脑上已经有了一个想要上传到GitHub上的项目,那么可以略去这些步骤。如果你在你的电脑上还没有一个本地的项目,那么让GitHub来为你创建一个"README"或者一个.gitignore文件,将会是件很方便的事。
当你已经在你的电脑上完成创建本地仓库,也在github.com上面建好之后,你接下来要做的就是把这两者连接起来。
GitHub会给你一些帮助以供参考。不过在这之前,我们还有些其他的内容想先来讨论一下。
5.commit
在commit时遇到麻烦了吗?在这一集的GitHub基础中,我们将展示三种不同的方式在Git中完成commit。
使用GitHub完成源代码管理系统的关键是跟踪更改。在Git中,这些被称为提交(commit)。在这里,我们将着眼于三种不同的方式来进行提交。
命令行
git status
git add 文件名.后缀
git status
我们将从本地计算机开始,使用命令行。假设你已经有一个已经开始的项目。什么语言或平台都没关系,只要它的文本文件以目录组织,现在你将要使用文本编辑器来对某一个文件进行更改。或者你将会一次改变几个。
"git status"命令将告诉你什么文件有可能需要被提交。它将告诉你已经更改的文件,或者是自上次提交之后,你添加的新文件。
为了接受这些更改,并让他们准备被提交,你需要使用"git add 文件名.后缀"命令。将他们放在一个特殊的被称为暂存区的持久化容器中。
你可以看到他们被移动到了暂存区,通过再次使用"status"命令,注意看输出看起来不同了。
每次你提交一个更改,它都必须通过暂存区。
这是Git的架构的一个关键部分。起初它看起来挺奇怪的,但你用Git用的越多,它就越有道理。
git commit -m 描述信息
git status
完成此过程,要使用"git commit"命令。保存仓库的历史记录。可以将当前暂存区中的文件实际保存到仓库的历史记录中,通过这些记录,我们就可以在工作树中复原文件。
-m 参数后的 “First commit” 称作提交信息,是对这个提交的概述。
一定要写个好点的描述以便其他人可以理解此次提交是关于什么的。如果你不包括一条消息,Git实际上将打开一个文本编辑器,并让你输入一个。它不会通过你的提交,如果你不去描述它。
git add
git commit
你应该注意到这点:如果你是第二次编辑该文件,在提交之前你实际上会再次使用"git add"命令,接着,当文件暂存后,你将再次使用"git commit"命令来说明你的更改。
在实际项目中,很多时候,你会一次更改多个文件,暂存区域让你灵活的决定什么改动将成为哪次提交的一部分。
当你能更舒适的使用Git时,你将开始重视有技巧地提交的方法。每次提交应是一个连贯的故事,它对看你的历史记录的人而言是有意义的。它不仅仅是你碰巧作出的一堆杂乱的更改,在你最后一次提交之后。不要担心,如果它目前毫无意义。它会开始有更多的意义,当你更多地使用Git,并且与其他人一起使用Git时。
例:
新建文件夹,在里面先初始化一下git,然后创建文件,例如创建a1.cpp
touch a1.cpp //生成a1.cpp文件
vi a1.cpp //编辑进入 :wq保存退出
cat a1.cpp //可以查看该文件内容
git status
git add a1.cpp //将文件提交到缓存区
git commit -m ‘提交描述’ //提交到git仓库
git status
GitHub.com
如果你已经有了一个在GitHub.com上的项目会怎样呢?你也可以在那里提交。在该文件上单击,你要编辑,然后单击"编辑"按钮,在浏览器中。你会得到一个简单的文本编辑器,你可以对你的文件进行更改。
当你提交这些更改,GitHub将创建一个新的提交,仅包含对该文件的更改。这样做,你没有很多控制权限关于每次提交什么,但是它很容易,对于那些对不太习惯使用命令行的人,并且对文本文件的更改中真的很简单。
GitHub for Mac/Windows
最后,回到你的计算机上, 你可以使用桌面版的GitHub提交代码。这仍然使得本地提交在您的电脑上,但不强制您使用命令行。
你用文本编辑器编辑您的文件,就像平常一样,但现在,桌面版的GitHub ,我在这儿展示的是Ma版本,会让你选择你想暂存哪些文件然后提交,你可以方便地选择你想要提交的文件,并输入描述消息,桌面版的GitHub 将为你处理add和commit。
这是另一个好方法。如果你想要避开将命令行作为日常操作。即属是与Git和GitHub 合作的基石。在将来的情节,我们将着眼于怎样检查你的本地的提交,以及,最好的部分,如何与其他人共享它们。
6.Diff
你走开了一小会儿,注意力被分散了,你回到电脑前,忘记了你刚才写到哪儿了。你需要的是Diff。
我们将着眼于它的三种不同用法。
总结:观察你所做的成果和Git是怎样看待这些变化的窗口。
git diff
如果你做了一个简单的改动,然后马上提交了它,你并不需要Git来告诉你你做了什么,你可能在你的脑子里记录了它。但是有很多时候,你会需要检验内容发生了怎样的变化。有三种主要的方法来做到这个,都是使用同一个命令:Diff。
看看Diff最主要的功能,是他帮助巩固我们学到的暂存区域,当我们学习怎样提交的时候。现在,假设你改动了一个文件然后被从电脑前叫出去了一小会儿然后回来,你是怎样记起你做了什么的?用不同的方式,你想要知道你对你没存档的文件做了哪些改动。这对你用的开发工具而言同样困难,这些工具自动为你改动了代码,然而你想要找出哪些被改动了。只需要输入git diff你就会得到你的工作树的精确描述,也就是,仅仅是你的文件,而不同于你的暂存区域。
git diff
总结:找出项目中哪些地方被改动了,通过这个命令,对你的工作树的精确描述,也就是,仅仅是你的文件,而不同于你的暂存区域。查看工作区的文件 和 暂存区的文件以及已提交的文件的差别。
diff --staged,HEAD
git diff --staged
现在,假设你已经存档了那些文件而且你想要知道你的暂存区域文件和最近提交的历史文件有什么区别。只需要输入git diff–staged,然后你就能看到这些改动。作为一个小小的意外收获,通过这段练习,能帮助你巩固对暂存区域的理解。
总结:暂存区域文件和最近提交的历史文件的区别。查看暂存区的文件 和 已提交的文件的差别。
git diff HEAD
仅仅因为你暂存了一个文件并不意味着你不能再次修改它,如果你继续对同一文件进行修改,状态命令将会告诉你文件已暂存,并且已经未缓存修改。
同时,如果你已经做了这个,你可能需要diff命令来跳过正在暂存的区域,并告诉你在最后一次提交之后你所做的所有修改。
输入git diff HEAD将你的工作树和头一次提交相比较,这只是在提交历史中最近一次提交的另一个别名。一旦你开始学会怎样使用,分支、推、拉,这最后一个模式将来得挺困难。你能使用它将两个分支彼此比较,或者将历史中两个之前的提交彼此比较,来得知过去发生了什么更改。
总结:查看当前文件(包括暂存的和未暂存的)和上一次提交后的文件的区别。
diff --color-words,diff --word-diff
git diff --color-words
git diff --word-diff
现在你可能注意到最后一个Diff,用一种有点冗余的方式表述了。我只更改了一个单词,但是Git现在告诉我,我更改了整行。这就是Git怎样处理文本文件差异的,但是它看起来并不十分有用。
你可以加上diff --color-words或者diff --word-diff来转换,到任何Diff命令来得到一种对长行小改动而言更易读的报告。有时,这可以是一个真正的救星。
总结:一种对长行小改动而言更易读的报告。这两个命令显示单修改中单词的不同,而不是显示单词那一整行的修改。
git diff --stat
另一个简单方便的技巧是让Diff不要输出所有的代码块,而是仅输出更改了的文件。使用diff --stat转换到这种模式。这太棒了,当你拿到一个复杂的diff,但你可能只是需要锁定一个被修改过的特定文件时。
追踪更改是Git的活儿。Diff命令是你观察你所做的成果和Git是怎样看待这些变化的窗口。这是一个伟大的命令。
总结:让Diff阻止输出所有的代码块,而是仅仅输出更改了的文件。显示修改的文件,不会显示修改的内容(比如修改的代码不会显示出来)。
7.Log
想知道在这些提交之后你的历史数据是什么样子吗?使用Log去找吧。
我们将详细阐述Git是如何管理我们的文件,用日志看看我们的提交真实是什么样子的。
Getting started
git log
最简单的开始方式是进入我们的终端,在我们的一个仓库中键入git log。
最上面的记录是我们最新的提交,最早的提交则位于最底部,他们是按照时间先后顺序排列的。
你首先要注意的事情是这里有一串40个字符的十六进制码,你不必太担心这个,那不过是唯一标识符,或者是git生成的提交引用。
当你每次提交到你仓库的时候,你可能也会注意到,在提交引用下面,有三行语句,第一行有你或者提交者的用户名和邮件地址,紧接着是可以显示那次提交发生的时间,第三行则是提交的内容本身。
最上面记录的是我们最新的提交,最早提交的位于底部,他们是按照时间先后顺序排列的。
第一行:40个字符的十六进制码,作为唯一标识符,或者是git生成的提交引用。
第二行:提交者的用户名和邮箱地址
第三行:显示那次提交发生的时间
第四行:提交本身的内容
如果你的仓库中有许多次提交,在你的屏幕的左下角部分,你将会看到一个冒号,你可以使用上下方向键,来滚动这些提交内容,按照时间顺序来浏览这些内容。但是我们一般不需要看这些全部提交和全部信息,我们可以使用一个选项过滤得到更加具体的内容。
git log–oneline,git log–stat
git log --oneline
尽管git的日志给我们提供了很多可以查看的信息,但是我们使用git log–oneline可以更加方便的,去快速查看一个概要,关于我们提交的是什么,提交的信息和一个简短的版本关于标识符或者提交,这让我们能够快速了解到仓库历史是什么样子的,以及代码是怎么前进的。
git log --stat
查看每次提交中包含了哪些文件是更加经常用到的,通过使用git log
–stat,我们不仅可以看到提交信息,提交引用,并且可以看到列出的每次提交包含的文件,我们可以看到它们的路径,甚至可以看到他们的相对改变,使用加减符号列出,表示每次提交中,内容的增加或者减少,
git log --patch
git log --patch
除了以上简单看看那些文件被包含了,你可能想了解,在每次提交之间哪些内容改变了,为了看这些改变,只需要运行git log --patch就可以了。它会展示不同的地方,和后续的提交做对比。如果在两次提交之间,内容改变以及增加了,你将会看到使用绿色列出来并且会看到一些加法符号。如果一些东西被移除了,你将会看到一些减法符号,那可能会用红色展示。
记住,这些选项并不相互排斥,你可以把它们组合起来得到一个日志输出,那对于你的需求来说是最有用的。你可能想看看提交信息的概述,所以oneline听上去像是正确的选择。但是,接着你也想要输出不同的地方,只需要运行git log --patch,git log --online,这样你将得到,在一次日志输出中,多个选项带来的好处。
git log --patch --oneline
git log --graph
git log --graph --all --decorate --oneline
关于日志命令,最有用之一的命令是去graph它,或者得到一个ascii码,来提交我们的提交结构的样子,我们可以使用git log --graph,但是我建议增加几个其他的选项,可以简洁输出并且得到一些其它的信息。
让我们运行git log --graph --all --decorate --oneline,马上会给我们展示每次提交的一行概括,将会使用ASCII码描绘全部提交,同时它会提供我们每个分支的标签,和我们提交的其它的标志,例如tags,这些就是你可以使用log来做得一些例子。
log功能非常强大,它是一个很好的方式去了解你的仓库的进展、仓库的提交内容以及提交修改的文件。
8.Remove
有时候有一些冗余数据在你的工程里积累,你必须清理它们,让我们看看Git怎么做到这个,我们将看看怎么删除文件,我们将会看到几种不同的方式去删除文件,一种是使用git rm命令,另外一种是使用add命令。这样可以让文件消失。
git rm
git rm file1.txt
如果你只有一个文件想要删除,那么git rm命令就是你想要的,它真正的从文件系统中删除了文件,并且它会暂存这个文件已经被删除的事实。如果你提交了,这个文件不会从之前的历史中消失。但会从未来的提交中消失。
如果你像我一样,是一个命令行爱好者,你可能会忘了git这个环节,只是简单的输入"rm 文件名"。然后,你会注意到git发现文件已经消失。告诉你改变还没有被暂存,你可以同样适用"git rm 文件名"命令来暂存它,就像之前一样。它并不在意文件已经不再存在了,但是它暂存了删除已经发生的事实。
git add -u
git add -u .
在一个实际的清楚场景中,你可能会有许多文件要删除,你不太可能从命令行中来做这些事情,你可能会用一些其它的工具。比如:Finder或者Windows Explorer或者一些其它的工具。状态告诉你,这些被删除的文件已经消失了。
但是你不想单独删除它们。如果你在做这样的清除工作,你可以使用add命令,git add -u。
它会遍历你的工作树,寻找Git之前已经识别到的文件,现在要消失的文件,它会把它们作为新的删除来暂存。
你会注意到我这里输入了一个点,作为文件名字,那只是一个意味着当前工作目录的简写,当add命令看到它的时候,它会从你当前所在的目录递归到最深处,寻找它能够添加的所有文件,或者说,在这个场景下,所有能够被删除的文件。
git rm --cached
git rm --cached
最后,你可能想删除一个文件,不想从文件系统中真正的删除它,换个说法,你想告诉Git,不再跟踪这个文件,但是把它保留在工作树中。这可能是一种情况,你意外地提交了一个文件,你并不想让它成为历史的一部分,你可以使用git rm --cached去实现它。
它暂存了删除,但是,如你所看,它在那里保存了文件。现在,在你的工作树中,作为一个不被追踪的文件。
现在这个技巧带来了其他的问题。
比如:如果你不想这个文件成为历史的一部分,你需要返回到之前的提交中去清除它?这是另外一个视频的主题。
或者,如果你想文件不被追踪,但是你想确定在将来某个时候你不会偶然的添加它,也有方法,比如:使用git ignore file去保证。这将是另外一堂课的主题。
Desktop Clients
现在,桌面的客户端去处理这些怎么样?答案是真的很简单。
如果你在Finder中删除一个文件,然后切换到mac到GitHub客户端。你可以看到,它会马上识别到那些被删除的文件,准备好为你暂存那些删除。你知道,这些表面后面,有很多东西在运行。Git让删除文件的操作变得非常简单。祝你在清除之旅中好运。
9.Move
版本控制系统总是要和如何处理移动文件做斗争,让我们看看git是如何处理它的。
我们将看看git move。我们将看到几种移动文件的不同方式,使用mv命令以及add命令。
git mv
记住在git中,重命名和移动文件是同一件事情。
git mv源路径 目标路径
最基本的想法是,你有一段内容,比如说一些代码,你把它从一个地方移动到另外一个地方,所以,假设我们有一些想要移动的文件,从一个目录下面。这很简单,只要输入"git mv 原来的路径 新的路径",回车就可以了。通过查看状态,你可以看到,git已经暂存了move发生的事实。
git rm //删除原来的文件
git add production.log //添加新文件
但是,如果你只是简单的使用mv命令来移动文件,然后你忘了告诉git,Git注意到,某个地方出现了一个本不应该出现的新文件,它同时注意到原来的文件思域已经被删除掉了。
我们可以一次一个步骤来解决它。使用git rm命令删除原来的文件。然后添加新文件,如你所见,当我们做这些的时候,状态把这些拼在一起了,告诉我们一个移动已经发生了。
git add -A .
git add -A .
但是,一个真实的场景,比如:你正在重构代码,你可能不会用命令行,你可能使用一些其它的编辑器或者IDE,或者例如Finder、Windows Exploer之类的其它东西。你不想为你移动的每个文件都输入git mv。
幸好,add命令有一个开关,-A,可以解决这个问题。它发现所有的移动过去的新文件,删除所有原来的旧文件。然后解释为移动已经发生了。
记住,这个.只是告诉git从当前工作目录开始,无限向下递归,你可以比这个更加具体。比如说:如果你已经在一个目录下作了移动,称作源目录或者类似其它的。
git add -A 目录
这一切都很好,但是注意到我们并没有改变,这里的文件,当我们移动它们的时候。
在一个真实的场景中,你可能会改变一点文件,当你将它们从一个目录移动到另外一个目录的时候。
让我我们看看git是如何处理这种场景的,我们将会模拟这种情况,通过编辑一个长文件,然后使用Finder移动它,然后再次使用git add -A来记住这次移动。注意,git仍然把它看做一次移动。
git log -M --follow
git log -M --follow
让我们进一步考虑,移动文件之后,我们在新的路径下面编辑这个文件,做另外一次提交。
git log --stat – 文件名称
所以,现在我们有了3次提交,文件创建的提交、文件移动的提交、在新的地方,我们编辑它的提交。我们可以使用日志命令来展示这个文件在移动过程中的历史。看看是否是我们想看到的。
“git log --stat – 文件名称"可以给我们清晰地展示那个文件的全部提交。
但是请注意,历史在移动的时候停止了,这特别让人泄气,当我们想追踪一个文件的历史,在一个大的重构过程中,添加开关”-M"和"–follow"。
git log --stat -M --follow
"git log --stat -M --follow – 文件名称"告诉日志在文件移动过程中跟踪文件,现在,我们来得到我们想要的结果。
imilarity Index
回想一下,我们什么时候提交的?在我们移动这些文件之后,commit给我们一些数字。
这些数字是一个类似度,可以表现文件在移动前后内容的相似度,git默认提供一个50%的相似度阈值。
如果文件在移动前后,50%相似,它会在移动的过程中追踪他,认为它是一个移动而不仅仅是一个删除和添加。
我们可以调整这个阈值,通过在开关-M之后提供一个数字,如果你比较挑剔,可以使用大于50%的数值。你可以自由地添加参数,尽管如此,注意不要把阈值设置的太小,因为你不认为是相同的文件最后可能会被判定为相同的,在一个比较低的相似度的情况下。
我们来考虑这种情况,在移动的过程中,如果一个人在将来的某个分支移动了文件,在他们做一些重构的时候,并且,你在这个文件之前的位置上编辑了这个文件,比如说在主分支上。
之后,当你移动的时候,你可能会疑问,会发生什么事情?好,答案是相似度的逻辑会起作用,这就像魔术一样,只要文件是大于50%的相似度,将要被移动的文件以及你的编辑将会在合并中在那个文件中生效。只要在这个过程中,没有冲突发生。
这个工作地很连续,如果你的改变相对有序并且相对少,就像典型的软件开发工作流一样,移动文件对于一个git用户来说,是一件非常普遍的日常事情。Git在表面之下做着所有有趣的事情。最终,给我们一个正常工作的系统,
10.Ship of Theseus
Git Move比简单看上去更加复杂,它和哲学必须处理的问题有些关切。如果某些东西随着时间而改变,后来的它还是和之前一样的东西么?如果一个东西由几个部分组成,如果其中一部分改变了,那么还是原来相同的东西么?或者说整个全部改变了?Move解决相同的问题。
哲学很难,所以,哲学家喜欢用讲故事的方式来阐述他们的问题,这里,他们讲了一个特修斯之船的故事。
Philosophy
特修斯计划一个一年之久的航行,他召集了全体船员,踏上船,开始航行。海上第一天,船上的一块木板坏了,所以,他们必须停在港口,砍断一棵树。得到一块新的木板,替换掉坏的木板,然后重新航行。第二天,相同的事情发生了;另外一块木板坏掉了,他们必须用一块新的木板替换他。在整个航行过程中,这件事情每天都会发生,经过大概一年的冒险,船上的所有木板都已经被调换掉了。所以问题是:它还是特修斯之船吗?
关于这个问题,有三个答案。实在主义者会说:不,它不是的,一旦整体的一部分,一旦一块木板改变了,它就不再是原来那艘船了。另外一种可能会说,船上有一个标语牌,标语牌上有一串数字,并且首部里有这艘船的注册信息,有这串数字的任何东西,都是特修斯之船,所以,我们有一些社会上的人说,那是特修斯之船。另外一部分人可能会说,让我们讲点道理,如果少于50%的木板改变了,它仍然是那条船,但是,如果大于一半的木板已经被替换掉了,它就是一条不同的船了。
现在,我不知道,哪个答案你认为在现实生活中是正确的答案。事实证明,任何一个都代表一个不同的方向,不同的版本控制系统,用来移动和改变文件。
Version Control
第一种是CVS系统,当你移动文件的时候,历史就会被破坏,它认为这是一个完全不同的东西。你不能在移动过程中追踪文件的历史。
第二种,船上有一串数字,首部有注册信息,就像企业的版本控制系统,每个文件都有标识。文件可以分支,追踪文件的移动是很简单的事情。因为有一些数据库记录这个东西。目前的位置和它以前的位置。
第三种答案就是Git处理相似度的方式,默认,只要有0%相似,它就被判定为同一个东西,我可以上下调整0%这个参数。
git log --stat -1 -M
git log -M99 -1 --stat
使用-M开关在log命令中,当我们的相似度观点改变的时候,Git不存储Move,内部的持久化数据结构。
Moves是事后的说明,关于日志命令或者合并命令,在仓库中发生。在持久化数据结构这个level,它只是存储一个删除和一个添加的操作,代码在之后能够读到那个数据,然后能够确定它是什么意思。
这是Git开发者所说,继续研究相似度索引算法,当他们有新的想法关于算法该如何运行,这是一个好的软件设计思路。
当你遇到一个设计问题,它有点像哲学分析上不能解决的问题,谨慎地对待它,**别在你的持久化数据结构中弄太多的提交。尽量把决定留给代码,你可以事后很方便的修改。**高兴的事,Git很好的解决了它。
所以,下次你重构代码以及把它从一个目录移到另外一个目录的时候,记得特修斯之船。
11.Ignore
想要避免提交那些不应该改在你的仓库中出现的文件,新的一节:git ignore。
git ignore会让你主观上避免暂存或者提交文件到我们的目标仓库中,例子可能是这样的。来自sass工程中./directory目录,甚至一个来自于Ruby的开发工程中.bundle目录。
The .gitignore File
为了避免这些文件或者目录,只需要在你工程的根目录下面创建一个.gitignore文件,在这里,每一行的样式应该和你想要忽略的文件相匹配,而且不再去关注它们。
touch .gitignore
git add .gitignore
git commit -m ” Preparing to ignore temporary files ”
vim .gitignore
ignore的格式可以是简单的字符串,或者更好的方式使用星号,典型的忽略样式就是这样:*.log。
如果你想忽视一个目录,那么在目录名字之后加上"/",记住,ignore匹配规则应用到目录中的所有文件,以及该目录下的所有次级目录。
ignore样式也可以放置在子目录中,我们需要在路径方面给它排一个优先级。
它也可以让我们用叹号来应用于.git样式,如果你有一个.gitignore文件,而且需要评论一行,直接在描述或者评论前面加上#号,这样这一行就成为了你ignore样式的描述了。
如果你忘记在本地创建Git的ignore文件,只需要在GitHub仓库页面,点击+号创建文件,命名为.gitignore,如果你要选择语言的话,右边有一个下拉列表供你选择。创建好需要的文件之后,拉到页面的底部,然后提交。
选择忽略模式Checking Ignore Patterns
git ls-files --others --ignored --exclude-standard
如果你想知道仓库中哪些文件被忽略了,而且你不想看.gitignore文件样式了,只需要到命令行下,运行"git ls-file --others --ignored --exclude-standard",显示出来的文件就是被忽略的文件,而且不再被关注了。
12.Brach
**添加一个新特性?修复一个bug?**这些工作都应该在一个新分支中做,为什么我们要用新分支来开始,创建和删除分支以及,如何在新的和已经存在的分支中转换。
为什么要使用分支?
当开始一个新项目或者打开一个已经存在的项目的时候,我们一开始就要新建一个分支,这是非常重要的。
很多人认为master分支是许多工作代码所在的地方,但是我们在提交的时候要十分小心,因为它就是对产品特性的一种呈现。
通过在这个分支上自由工作,允许我们安全地工作并且远离master分支,比如后面我们需要在Github.com上打开一个pull request。为了添加一些关于新特性的协调与沟通。
创建和删除分支
创建一个新分支:
git branch 新分支名字
要开始一个新分支,我们直接输入"git branc 新分支的名字",这就可以创建一个我们后面可以切换的分支。
删除一个分支:
git branch -d分支名字
我们想删除一个分支,只需要输入"git branch -d 分支的名字"。
现在,如果它没有完全被合并,将会给你一个warning。告诉你把-d替换为-D,如果你对合并不熟悉的话,不必担心,将会在其他章节中覆盖到。
转换分支
git checkout 分支名字
删除分支的另一方面是,我们显然不能删除我们现在正在使用的分支,所以下面要做的就是要切换到一个新分支上面。
使用"git checkout 分支名字",当我们切换分支的时候,任何出现在面板区的工作或者工作目录,都会跟着我们转过来。
我们需要注意的是,如果我们处于这个活动目录或者面板区的文件被覆盖的话,是无法切换到新分支上面去的。
最后一点,你可能看到文件消失又重现,在进行切换分支的时候,不用担心这些文件和它们的改变,它们会待在各自的分支里,直到你合并它们为止。
分支是Git中的一个关键元素,请一定要观看本节的合并视频以完整观看这一讲解。
13.Checkout
如果你学习了git branch,下一步就是学习git checkout。checkout被用来切换分支,接下来,我们将看看它还能干些什么。
Checking out to a branch
git checkout 分支名字
通过运行"git checkout 分支名字",我么就可以重写那个分支的工作树和视图。我们用它来干什么?它可以让我们看到我们的文件,就是我们版本控制中从分支视图中看到的文档。
git branch
我们可以检查我们正处于哪个分支,通过运行"git branch ",得到所有分支,看到星号旁边那个星,我们所在的分支。
git status
或者通过运行"git status",也可以查看正在运行的分支。
git chexkout 你想要转换的分支或者环境
checkout 的目的在于改变分支,之后就在该分支或者环境下进行commit,一旦你commit到你已经切换的分支,你可以很容易切换到另外一个不同的分支,通过简单的使用相同的命令。“git chexkout 你想要转换的分支或者环境”,然后,你就切换成功了。
Detached head
git checkout 提交引用
另一个checkout的目的是就是把你的项目下的工作树、目录和文件等东西,做一个更加详细的commit。
为了做到这个,我们需要运行"git checkout 提交引用"。这样我们的工作树就会在commit提交的那个时间点被覆盖了。当我们看到这个状态时,注意,我们正处在detached head状态。这不是一个我们想commit的地方。这只是一种显示我们的工作树、目录和文件看起来是什么样子的方式。
一旦你已经了解了detached head状态之后,一定要回去检查你的分支,在那个分支上,你打算进行commit,使用这种方式,你将不会丢失掉任何东西。
丢弃编辑Discarding edits
git checkout – 文件名
git checkout的另外一个目的是撤销或者丢弃编辑的内容。可能我们有许多文件,但是只有一个是正确的,如果我们想丢掉这些改变,我们可以运行:“git checkout – 文件名”,这个可以为我们做到的是,它会清理掉最后一次commit的内容。
联合移动Combo moves
git checkout -b 新分支的名字
checkout的最后一个小技巧是,缩短一些其它的步骤,如果你想要创建一个分支,然后切换到它,只使用一步的话,只需要运行:“git checkout -b 新分支的名字”。这样就可以创建一个新分支,并且切换到它上面,只使用一步。
14.Merge
分支是每一个git工作流的关键部分,把这些改变汇聚起来也是非常重要的,这个工作可以通过Merge来完成。它把分支和多条线的历史操作汇聚起来。
git merge指令
git merge分支名字
通过merge,我们可以把两个或者更多分支的历史汇聚起来。然后在工作树中展示,所有这些分支中全部commit的累积结果。
对于一个典型的工作流,我们会切换到master分支,然后确认该分支有我们想要合并的commit,我们运行"git merge 我们想要的commit的分支名字".
。
master分支现在有了累积的结果。包括文件、修改和历史。这些东西之前只是在那个主题分支上。
解决冲突
合并过程中,你可能会遇到一些冲突情况。
合并过程中遇到冲突意味着两个文件的变化非常的相似,Git自己不知道如何去解决这些冲突,或者把他们合并在一个文件里。
为了解决这个,从冲突信息中很容易确认冲突文件,或者通过运行git status,然后可以看到哪些文件没有在commit中显现出来。
用你最喜欢的编辑器打开这个文件,
你首先想查看的是那个重复的<符号和HEAD标记, HEAD标记给你展示了文件内容是什么样子的。站在你当前所在分支的角度上,在这里,是master分支
在你确认了master分支上的文件内容之后,你会看到一行=号,这个是master分支的文件内容的分割,这个下面,就是你想要合并的分支的内容,这个分支造成了冲突,
在代码段或者文本内容之后,你会看到一些>号,接着是你的分支的名字,这表明了冲突结束的位置。
文件的这两部分内容,你需要手动解决冲突。接下来你需要做的一步是编辑你的文件,移除你看到的这些冲突的标签,确定你想要保留的或者应该继续下去的内容,保存文件即可。
回到终端,运行"git status",暂存文件,如果有其他的冲突的文件,使用同样的方式解决这些冲突,暂存这些,然后运行"git commit"去结束这个过程。即再次提交即可。
–abort指令
git merge --abort
在git merge过程中,有一种情况是你遇到了分支冲突,但是你不想马上解决它或者你目前只想抛弃它,如果你这么做,简单地运行:
$ git merge --abort
这将会从你当前分支的最后一次提交中清除你的工作目录,它同样会清除你的暂存区。
–squash指令
git merge --squash 目标分支名字
如果你不想把历史汇聚起来,但是你想要一个具体分支中的全部commit简单的运行:
$ git merge --squash 目标分支名字
在你目前切换到的分支上创建一个新的提交,这代表了发生在目标分支上的所有改变。
git branch -d 指令
git branch -d 分支名字
一旦你成功地完成了一次合并,没必要保存分支标签或者名字,因为你可以从你的最终分支或者当前分支看到所有的历史,所有的提交,
你需要做的事情实在合并之后清除分支名字:
$ git branch -d 分支名字
这样就会清理标签,你不必再关注这个分支了。因为这些提交现在已经是主分支或者历史分支的一部分了,他们都可以查看得到。
15.Network
我们将要讲讲关于创建和移除远端,远端的分支和它们到底能干什么,然后是fetch push pull操作。
远端(Remotes)
git remote add 目的地的名字 目的地url地址
一开始,我们有一个git仓库,这个仓库只存活在我们的笔记本上,我们需要告诉它,我们将要把我们的信息发送到哪里,我们输入:
$ git remote add 目的地的名字 目的地url地址
现在,目的地的名字应该是你很容易记住的东西。
git remote set-url 目的地名字 修改url地址
如果你输错了URL或者你想要修改URL,你可以输入:
$ git remote set-url 目的地名字 修改url地址
git remote rm 远端名字
最后,如果你想删除其中一个远端:
$ git remote rm 远端名字
git remote -v
如果你好奇URL是什么,因为你忘掉,或者你想知道你想要移除掉的远端:
$ git remote -v
得到全部的输出
现在,GitHub上当然有了分支,就像我们在笔记本上的操作一样,并且这些远端追踪的分支,则是分支间的中间人,这些分支有一些不同的唯一原因是在所有分支名字前面有一个前缀就是用来响应远程控制的,大部分情况加,这个将是origin/。
Fetch,Pull,Push
现在,在处理远端控制中,最有用的三个命令是:fetch pill push。
git fetch origin
Fetch命令本身是去github.com抓取任何信息下载下来,把它放在远程追踪分支里。
$ git fetch origin
现在,pull命令和fetch非常像,首先做fetch操作,它将要拉取东西到"origin/分支名字"里,然后做合并操作,合并到那个分支名字的本地版本里。
现在,pull命令和fetch非常像,如果我们有一个分支叫做"feature1"
git pull orgin
然后我们做了一个操作:
$ git pull orgin
它将要更新github.com知道关于"feature1"的任何信息到orgin/featurs1,然后做合并操作到feature1。
git push origin
最后,我们剩下的是push操作,当我们在电脑上有已经完成的工作时,并且我们准备把它发送到gitHub,com,我们输入:
$ git push origin
它会把全部信息发送到gitHub.com,现在,在做这个的过程中,它同时也会更新远端追踪的分支。
了解网络、远端追踪的分支以及他们是什么。以及fetch pull push操作。这些都是在GitHub上合作所必须的。
16.GUI
在你日常工作任务中,去和Git和GitHub交互,图形化用户界面是一种很方便的方式。
图形化用户界面可以分为两类:
第一类是提供关于所有命令行的抽象,这样你就可以点击按钮开替代输命令了;
第二类的目的不在于去抽象Git命令行中的一切,而是使用视觉化和图表来作为补充,这些只有在臃肿的客户端中才有可能,同时,仍然提供到命令行的入口作为大部分的选择切换。
Cross Platform Clients
GitHub为Windows/mac提供了图形用户接口,如果你工作在这两个操作系统之外,其余的可以从git-scm网站上得到跨平台界面。这里有一个下载GUI的页面,列出了其中一些值得关注的下载链接。
Windows/mac
GitHub for Windows和GitHub for mac拥有很多共同点,但是GitHub for Windows有一个东西不同,就是它提供shell,Git for cmd.com,Git Bash,和Git for PowerShell,更被熟知为Posh-Git。
再说一次,它就是一个图形用户界面和一个自动更新拷贝,关于Git命令行的混合体。
它之所以非常有用,在一个发行版中同时包括命令行和GUI,是因为在像Windows/mac这样的平台上,有很多细节和细微的差别,在安装Git命令行上。那么,你必须每次重复那个过程,当你想搞一个新的点发布的时候,GitHub for Windows将图形客户端和命令行捆绑在一起,补充了一种我们的自动更新的功能。这样你就总是在一个最新的测试好的版本上,这样就可以完美兼容GitHub.com和GitHub。
GitHub for mac类似地包含了命令行和一个图形用户界面,但是不需要那三个相同的Windows所需要的东西,它简单地载入Git,在路径上,你可以选择使用任何shell,无论是T shell,Cshell,Zshell还是Bash。
Web integration
我们的两个图形用户界面,和GitHub.com和GitHub深深的融合在了一起。这是两个web应用,也是我们的合作平台。有按钮,比如克隆到桌面,在任何仓库中都可以看得到,这个也会触发桌面客户端,去吧一个仓库的完整备份拿到你的本地机器上。
当你工作在一个合作的code-review过程中,使用pull请求,有一个等价的按钮,会去获取那个指定的分支到你本地的位置上,并且切换分支,这样,你就可以运行本地测试。也可以对pull请求或者可能的merge的进行细微补充,来查看这个分支如何和其他分支融合。
Git和GitHub的图形用户界面,会以多种大小以及许多不同的特性,但是我们偏好提供的是命令行,和提供自动更新的功能。以便于你可以关注你最关心的内容,比如:修改代码和搞定工作。
17.Intro to GitHub
Git是一个优秀的、业界认可的版本控制系统,GitHub.com这个网站让Git更加广为人知。
很容易就会想到,你可以在任何地方掌管你的Git仓库,有很多服务、许多工具供你去掌管它们,即使你处于你自己的企业防火墙里。但是,不仅仅是掌管代码,我们将要讨论改变软件,它包括所有合作的所有类型和所有方面。
文件问题,组织仓库以便于让人容易查找,可以通过用户名字来提醒代码贡献者,以及能够控制输入流的改变,可以通过我们叫做pull request的概念来做到。这些都被github.com优化了,GitHub.com同时也是一个能够掌管Git仓库的合作平台。
The Platform
你和GitHub.com的第一次互动可能是通过这个浏览页面,查找一些开源代码,用来解决你目前应用的一些需求。很快,你会发现,你想要提交一个issue,甚至可能给工程提交一个修改,去改进它,或者修改一些bug,这些全部东西,在GitHub.com平台上都是可以的。
你会发现我们有解决方案,比如一个集成的问题追踪器。和pull request的进程。这样代码改动的地方就可以得到复查。评论、改良、最终被接受。即使对于不是这个工程的核心代码贡献者来说。
GitHub添加了更多的创新东西,允许Git能够到达一些它一般不会被欢迎的地方。比如:我们有一个SVnbridge,可以允许任何Git仓库能够被对待为一个subversion仓库,这经常会优化一个连续整合基础架构的缓慢迁移,构建脚本或者其他自动化事情。你可以把这些整合进你的发布进程中。
The Web Flow
GitHub同时有web流的概念,这个把大部分Git操作带进web浏览器,不用把仓库克隆到硬盘上,不用把Git软件下载到本地机器上。
特别,如果它是一个共用的终端,只需要一个编辑器,带有语法高亮,直接在浏览器中,对于仓库中的任何文件,重命名、移动、删除、添加新的文件,改变工程的各种东西,直接通过浏览器来操作。
这意味着Git更加容易接触到你的组织成员,打开开源工程,或者公司相对于如果它们需要桌面工具才能和仓库交互来说。
Documents
由于文档被意识到是所有软件工程的一个关键部分。已经表明,不管在资源库中还是周边注释,都是非常重要的,GitHub提供了GitHub风格的markdown,这个是核心markdown语言上做了一些改进,应用在issues,pull request甚至在那些被提交到核心仓库本身的文档里。只需要给它们一个.md的扩展后缀,把它们放进仓库里,像你处理其它文件的方式一样。
你可以看到它们进行着变动,就像你在文档编辑器中期待的一样。有删除线的行被删除,行会展示在被校正的合适的位置上,额外添加的行则显示为绿色。
Tools for Collaboration
仅仅改变代码和文档并不是GitHub的终点,我们添加对3D模型、STL格式文件和地图的GeoJson格式的支持,这些东西可以在浏览器中显示,这意味着你平常必须购买和下载到你本地机器的软件,复杂地建立、配置和安装,现在只需要在浏览器中就可以直接显示。让这些文件更加容易接触到对于访问这个仓库的人来说。GitHub是一个统一的平台把东西整合进web流里面。这些东西平常需要桌面工具,既可以使用Git工作,同时在线上显示这些复杂的markdown STL GeoJson文件,这些使用起来非常简单。这意味着合作发生更加频繁,冲突发生更少,也会有更多人贡献到开源或者闭源项目中去。
18.Forking
forking是一个安全基石,对于贡献代码到任何开源工程中来说,forking可以用来获取你的仓库并拷贝它到自己的账户下。现在,拷贝这个行为让你安全地在沙盒里进行修改。这个可以工作在开源模型中以及开放公司模型中,极大地扩展了员工的数量去向工程贡献代码。
当我们看到一个我们想要贡献代码的项目,我们点击Fork按钮,从而在自己的账户下面建立一份拷贝,然后就可以开始我们自己的修改。
合适的步骤是创建一个分支在那个拷贝库上,这样就会有一个名字、标签和容器服务于一个潜在的变更版本,我们之后会把这个版本加入到原来的仓库中。
一旦这个在你的账户下面,那里就会有一些元数据可以展示哪些用户拥有这个项目的原始拷贝,你也可以看到谁复制了这个项目。网络图提供了一些元数据到提交level上,可以看到人们在这个仓库干了些什么工作。
这些是一个准备步骤,会把你的变动返回个最初项目开发者,通过Pull Request的机制。
19.Pull request
Pull requestds是一个核心部分,可以把一些修改弄到其他GitHub仓库中,让我们看看怎么高效地使用他们。
Pull requestd意味着提交一个修改到另一个代码库中,你可以这样做,无论是一个核心代码贡献者亦或者是使用fork的帮手。如果你不是一个核心开发人员,你可以fork这个项目在你自己的仓库中工作、修改代码然后把这个修改发送回去,作为一个提议。使用pull request,返回给原来的作者。这也意味着,做出一个修改比抱怨一下更加舒服,这也就是为什么GitHub一直促进了开源的成长和发展。这也应用到闭源项目、公司项目和私人项目。
Promoting Collaboration
如果你有权利push到仓库,你仍然应该工作在一个分支上,然后发送那个pull request去获得代码的一些review。这意味着你将要创建一个分支,开始一些提交,并且当你准备好接受review的时候,使用pull request把它发送给团队里的其他每个人。
**这意味着pull request是一个会话,不仅仅是一个分支的一次提交而已。**相反的,一些对白和讨论,对于代码的一些复审,以时间先后顺序出现,最终同意或者一种糟糕的情况,一些反对者会说,这些看上去对于基础代码并不是一个好的修改。但是,这两种情况,URL和pull request都是他们的依赖所在。
further Conversation
你不必停止会话,仅仅因为某些东西关闭或者不被接受,你可以继续找出他们为什么不被接受,找出在你以后可以做出哪些修改,确保你的所有的pull request都会被接受,它可以当做一个教育类工具用来教后面加入团队的人们,这些pull request是哪种变化,可能在文化上被接受的对话,有哪些期待、要求、格式是人们希望添加进去的。你可以保存这些URLs并且把他们当成教育工具送给新人。
这意味着,你不必弄一些邮件会话去讨论接下来的新特性,你只需要把URL给他们,然后他们随时都可以查看了。
Intergrations and Testing
我们同时对技术输入很感兴趣,而不仅仅是人类的输入。一个CI系统,也就是持续集成系统,比如:Travis,Hudson,Jenkins,Circle CI,Team City都可以使用GitHub的pul request来集成并且报告这个分支的编译状态。Pull request的基础单位和会话一起发送。
所以,这意味着,随着会话和代码的改动,有一些编译的状态会弹出来,“是,所有测试通过”“不,有些测试失败”这同时会影响合并按钮的状态。
给你一个警告,说“你不愿意让所有的测试通过,以及让分支清楚无误,在你按下合并pull request按钮之前?”。所以现在我们有CI状态和人类反馈的想法集成在一起,我们有整体、人类的review外加一些技术测试,不仅在分支内容上,并且预测分支和目的地的合并之后的情况。所以,你将看到未来,如果合并之后会怎么样。这并不意味着合并是持久的,这实际上是作了一次预计的合并,看看事情如何发展,然后告诉你,如果你这样做了一次合并,你是会成功还是会失败。
Merging
如果CI报告了一个号状态,你会获得社交认可,得到一些赞,是时候按下merge pull request按钮了。一旦这个发生了,你也被提供选项去删除这个分支。这听起来有点令人担心,但是这并不知道一件坏事情。
我们不必担心关闭和删除分支,因为所有的提交已经在目标分支了,它们已经被保存了。所以你可以删除分支,让人们知道将来的发展不会再在这个分支上发生了。Pull request仍然待在旁边,万一你想要讨论的记录以及你的身份认证和你已经做的贡献的声望出现在目标分支,随着这些提交合并。
20.Reset
Git reset是一个允许你塑造仓库历史的命令,无论你是想撤销一些修改,还是把你的commit弄得不一样,这就是一个为你准备的命令。
这个命令功能很多,也有很多模式,是的,这里我们即将演示的有三种模式:soft、mixed(或者是默认)、hard。
Overview:soft、mixed、hard
这些形容词非常的形象,让我们用默认的mixed模式来开始,它修改了历史和工作目录,所以叫做混合模式,修改了多个东西。
soft模式是选取一条或者多条commit,把它们的全部改变放回到暂存区,让你在这此基础上继续创建新的提交。
hard,另一方面,是一个具有破坏性的操作,这意味着擦除掉你不再想保存的东西。
所以这里有三种模式,首先我们来看看混合模式,
in-depth:Mixed,soft,hard
mixed模式是推荐模式,大部分Git新手用的都是它,因为它们会显示在status命令中,当你在编辑器有一些改动时。
你输入"git status",我们可以看到git reset HEAD
这允许我们把这些改变移除暂存区。把它们放回到工作目录中,使用mixed模式。
soft是这样一种方式,我把一些改动。这些改动可能太过于分散,五条commit。
然后我意识到这些commit都属于同一个事项,把它们全部弄到一起,通过"git reset --soft HEAD~5"这个命令。这最新的5条提交
所以,使用soft这条命令,你可以把这5条commit当做一次提交,压缩进暂存区。
对于重新塑造历史非常有用。
但重塑历史操作有时候走的太远了。它把commit丢弃掉,并不添加任何值。如果你不想发送、传送或者和其他人分享它们,这就是hard模式发挥作用的地方。
如果你想完全丢掉一些你的工作,可能想丢掉一些不再发挥作用的变动。你可以使用"git reset --hard"来完全丢掉这些提交。
人们可能会问,那么为什么你要做一个提交?但是Git会提供一个非常良好安全的网络,通过reflog命令,我们接下来的视频中会看到。这个可以让你通过commit去做检查点,让你知道你在使用hard模式,你可以在你喜欢的任何时候,清除这个历史操作。
Checkout
有另外一个相像的命令,会经常拿来与reset讨论,这个命令是checkout命令。checkout命令和reset有一些不同,reset经常操作的是仓库的整个历史,而checkout更加关注在一个目录或者文件级别的精度上。
不是撤销或者改变一条提交,我们可以回到一个特定文件的某次提交的历史上,然后把这个文件和版本拉回到我们目前的工作目录。
清晰的沟通是所有Git仓库历史的目标,所以不管你是使用git reset hard,reset soft,reset mixed或者是更加精确的checkout命令,使用这些命令把你的变动清晰意图传达给你的同事。
git reset是一个有点让人害怕的工具,对于Git新用户来说。但是他是一个非常有用的工具,当你去处理创建你更好的仓库历史的时候。
21.Reflog
Git追踪你对你的软件做的所有的修改。但是你了解reflog么?它会追踪你对修改内容的修改。
git reflog
它会追踪你对修改内容的修改。
Git用户首先会发现他们在仓库的每次提交是一个实时的记录快照,会展示代码库是怎么发展的。
但是更高级的git用户会发现reflog会追踪制造的commit以及丢弃的commit。这提供了一个30天的缓冲时间,在这期间,你可以从任何错误中恢复,包括git reset命令带来的不好的部分,分支的删除或者可能rebase消失了。
Git reset对每个分支都很特别,你会注意到,如果你选择去观察,在.git目录下有一个子目录叫做logs,在那下面,每个分支都有具体的文件,你本地仓库里有的分支。
每个这些日志都追踪你做的变动,包括前进和后退方向的。Git reflog命令是做到这个的用户接口,它打印出大部分最近的历史,分页机制让你可以通过已经发生的旧的入口去到你目前已经切换到的分支上。
一旦你已经第一次运行git reflog,看到屏幕上展现的历史事件,你会好奇你可以用这些干些什么。
简单地选取展现的7个字符的哈希串中间的一个,使用它作为一个可能的候选去恢复你的代码库。“git reset --hard 那个hash串”
目前的分支现在被强制切换到那个历史点。
Using a GUI
Reflog提供的线性历史是很难查看的,哪一个是孤单的分支?哪一个是不在代码库里一部分的提交,一些有技巧和创造性的命令行可以把reflog的结果通过管道到一个图形用户界面:
$ gitk --all ‘ git reflog | cut -c1-7 ’ &
这样很容易看出来哪些分支是独立的,哪些提交不再是这个分支的一部分,哪些东西你想要恢复,通过捕获他们的哈希值和使用reset --hard命令。
频繁提交(Frequent commits)
Git reflog是你做频繁提交的动力,频繁提交意味着,在reflog里有历史存储着,不管你reset了它们,抛弃了提交,修改它们还是犯了一个错误。
没有提交的所有东西,在工作区或者暂存区都是有风险的。但是,如果它被提交了,你可以恢复它们,这最近的30天有一个保证措施允许你采取大的,勇敢的步骤使用Git的其他特性。
22.Rebase
git rebase可以把已经存在的提交放到今天开始的一个分支上。
创建一个分支是一个艰难的决定,今天开始,还是晚点再开始?然而,一些重要的修复可能要马上开始。那么最好等到明天再说把。这个困难的决定对于Git来说已经不存在了,在你喜欢的任何时候开始一个分支,让它包含你想要提供的变更。
专注于一个特别的特性:修复一个bug或者某个任务。
标准使用方式(standard usage)
那么,想让这个从历史中的稍后的地方开始怎么样?为了整合,这些要进入主分支的修复?没问题,rebase就是这个的解决方案。
Rebase,在它的标准使用方式中允许一个分支在历史操作追踪中重新定位。
意味着,把所有仅在你分支的所有变更,表现为,他们仿佛发生在主分支下的当前工作之后。
这完成了同一件事情,和一个反合并的将是相比,有着更加干净的历史。反合并从主分支挪到特色分支,相同的内容将会在特色分支中呈现。但是,不用复杂的合并进入到特色分支,然后在它的历史中记录。
git checkout, git rebase
切记,rebase命令会修改所有提交在分支中的呈现,它保存你做的所有工作,但是他们的位置和跟其它提交的关系也改变了。这主要应用在一个只有你拥有的分支上,并且别人将不会在上面工作。Commit之前的关系和这些每次提交的标识符的改变让它很难与其它人工协调时保持一致。
我们首先来讨论你关注的分支,尽管有这么多的约束,使用却是非常简单的。
$ git checkout 特色分支
$ git rebase 原来的分支(一般是master分支)
这个将会依次检查发生在特色分支上的所有提交,然后在主分支上重播他们,似乎他们被重写,从最近的一个时间点开始,当这个过程完成的时候,看着所有单条提交都导入之后,它会让你知道,rebase已经完成了,你也会回到一个命令行提示界面,这似乎是一个类似的状态和你运行哪个指令之前相比。然而,所有这些历史提交现在有了新的标识。
记住这个,你会发现,使用这种模式的请求, 在一个开源项目中是最普遍的,这是因为他们想要优化代码库的将来阅读体验。
仓库历史呈现一条单独的直线,这提供了最轻松的阅读体验。
对于这个项目的未来开发者来说,这是为什么它们把责任放在开发者身上。让历史更加简洁,这需要一些努力,但是做了一次之后,这个项目的将来所有贡献者都将会获益。
History vs features
持续发布的应用,比如:web服务、web app,一般用merge优化而不是rebase,他们想要一个最快可能的,发表机制去发送一个变更,小而专注,到master分支上。如果它没有做它应该做的所有事情,另外一个分支就会开始工作,然后再回来把它合并掉。
rebase是一个非常有用的特色工具,让你优化仓库历史的清晰度。只需要记住你的项目和你的团队的需求,如果它需要快速发表特色分支,那么合并它们,如果它需要历史的清晰度,那么使用rebase.