看了一本《Git学习指南》的书,所以写了这个note,多多学习Git操作,也好装B,以前只会简单几个操作。
基本概念
分布式版本控制、有何过人之处
集中式概念:
是将项目集中存放在中央服务器中,在工作的时候,大家只在自己电脑上操作,从同一个地方下载最新版本,然后开始工作,做完的工作再提交给中央服务器保存。这种方式需要联网,现在云开发就是这样的处理方式。

分布式概念:
只要提供一台电脑作为版本集中存的服务器放就够了,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它也一样干活,只是交换修改不方便而已。而每一台电脑有各自独立的开发环境,不需要联网,本地直接运行,相对集中式安全系数高很多。

以上的简介和图片均来自网上blog
分布式版本控制的特型版本库
- 项目版本库:该版本库主要用于存储有“官方”创建并发行的版本
- 共享版本库:该版本库主要用于开发团队内人员之间的文本交换。
- 工作流版本库:工作流版本库通常只用于填充那些代表工作流中某些特定进展状态的修改,例如审核通过后的状态等
- 派生版本库:该版本库主要用于从开发主线分离出某部分内容(例如,分离出那些开发耗时较长,不适合在一个普通发布周期内完成的内容),或者隔离出永远不会被包含在主线中的、用于实验的那部分开发进展。
分布式系统的优点
- 高性能:几乎所有的操作都不需要进行网络访问,均可直接在本地执行
- 高效的工作方式:开发者可通过多个本地分支在不同任务之间进行快速切换
- 灵活的开发进程:我们可以在团队和公司中为其他部门建立专门的版本库,例如为方便与测试人员交流而建的版本库。这样相关修改就会很容易发布,因为只是特定版本库上的一次推送。
- 备份作用:由于每个开发者都持有一份拥有完整历史版本的版本库副本,所以因服务器故障而导致数据丢失的可能性是微乎其微。
- 可维护性:对于那些难以对付的重构工作,我们可以在将成功传送给其原始版本库之前,先在该版本库的副本尝试一下。
版本库,分布式工作的基础所在
版本库其实就是一个高效的数据存储结构而已,由以下部分组成
- 文件
- 目录
- 版本
对于所有数据,它们会被计算一个十六进制散列值。这个散列值将会被用作相关对象的引用,以及日后恢复数据时所需的键值。
也就是说,一个提交对象的散列值实际上就是它的版本号,如果我们持有某一提交的散列值,就可以用它来检查对应版本是否存在于某一版本库中。如果存在,我们就可以将其恢复到当前工作区相应的目录中。如果该版本不存在,我们也可以从其他版本库中单独导入该提交所引用的全部对象。
散列值和版本库的优点
- 高性能:通过散列来访问数据时非常快的
- 冗余度—释放存储空间:相同的文件内容只需存储一次即可
- 分布式版本号:由于相关散列值是根据文件,作者和日期来计算的,所以版本也可以“离线”产生,不用担心将来会因此而发生版本冲突。
- 版本库间高效同步:当我们将某一提交从一个版本库传递给另一个版本库,只需要传递那些目标版本库中不存在的对象即可。而正是因为有了散列值的帮助,我们才能很快判断相关对象是否已经存在。
- 数据完整性:由于散列值是根据数据的内容来计算的,所以我们可以随时通过Git来查看某一散列值是否与相关数据匹配。以检查该数据上可能的意外变化或恶意操作
- 自动重命名检测:被重命名的文件可以被自动检测到,因为根据该文件内容计算出的散列值并没有发生变化。也正因为如此,Git中并没有专门的重命名命令,只需移动命令即可。
入门
准备Git环境
去官网安装
去Git官网安装
config命令配置用户名和用户邮箱
git config –global user.email “xxxxx@xxx.com”
第一个Git项目
创建版本库
init命令,对于一个带版本库的项目目录,通常称之为工作区
git init
首次提交
第一步,我们先要用add命令来确定哪些文件应被包含下次提交中。第二步,再用commit命令将修改传送到版本库中,并赋予该提交一个散列值以便标识这次新提交。
git add xx.text
git commit –message “xxx”
检查状态
git status
status命令就会显示出该项目自上次提交以来所发生的所有修改。
git diff 命令可以显示其每个被修改的行
提交修改
接下来,所有修改都必须要被先归档成一次新的提交。我们要对修改过的文件和新文件执行add命令,并对要删除的文件使用rm命令。
git add foo.txt bar.html
git rm bar.txt
现在再次调用status命令,我们会看到所有的修改已经被纳入下次提交中。
然后在用commit命令提交这些修改。
显示历史
log 命令可用来显示项的历史,所有提交都会按时间顺序被降序排列出来
git log
Git 的协作功能
克隆版本库
git clone
git pull命令可以从原版本库中取回新的修改,将它们与克隆体中的的本地修改进行对比,并在工作区中合并两边的修改,创建一次新的提交。这个过程就是所谓的合并。
创建共享版本库
除了可以用pull命令从其他版本库取回相关提交外,我们也可以用push命令将提交传送给其他版本库。
Pull命令:取回修改
推送和拉回
push和pull命令可用于在本地和远程版本库之间共享版本提交。
提交究竟是什么
提交的时候不仅提交被修的文件,它包含该项目的所有文件,针对每次提交,Git都会为其计算一个由40个字符组成的唯一编码,我们称之为提交散列值。只要知道这个散列值,我们就可以将项目中的文件从版本库中恢复到该提交被创建的那个时间点上。在Git中,恢复到某一版本通常被称之为检出(checked)操作。
add命令与commit命令
我们可以分add命令和commit命令着两步来创建一次提交
- 注册修改
我们可以用add命令来进行注册,将所有的修改纳入下次提交。在这里,你可以使用-all参数,这表示我们会将所有修改都纳入在内
git add –all
- 创建提交
现在可以创建一次新的提交
git commit
在谈提交散列值
Git选择散列值的理由
- 这样的提交散列值可以在本地生成。我们无需与其他计算机或中央服务器进行通信,就可以随时随地创建新的提交。
- 提交散列值中的信息要比单纯一个软件版本的名称要多得多。
提交历史
版本库中所包含的并不仅仅是一个个独立的提交,它同时也存储了这些提交之间的关系。没当我们修改了软件并确认提交时,Git就会记下这个提交之前的版本,
提交之间的差异的比较
通过diff命令,我们可以比较出两次提交之间的差异。
同一项目的多部不同历史
我们可以通过log命令来显示提交历史
部分输出:-n
该选项通常用于限制输出,例如显示最后三次提交
git log -n 3
格式化输出:–format、–oneline
对于日志的输出格式,我们可以用–format选项来控制。–oneline选项所显示的概述信息
统计修改信息:–stat、–shortstat
统计类选项也是很有用的:–stat可用来显示被修改的那些文件。–dirstat则可以用来显示那些包含被修改文件的目录。而–shortstat则用来显示项目中有多少文件被修改,以及新增或删除了多少文件
日志选项:–graph
我们也可以通过–graph选项来显示各提交之间的关系
多次提交
提交的产生通常分为两个步骤。首先,我们要用add命令将所有相关的修改纳入到一个缓存区中。这个缓存区通常被叫做暂存区或索引。接着我们才能用commit命令将暂存区中的修改传送到版本库中。
status命令
通过status命令,我们可以查看到当前工作区中所发生的修改。以及其中的哪些修改已经被注册到了暂存区中,以作为下次提交的内容。
- changes to be committed:被提交的修改,这部分将列出那些将在下次提交中被纳入版本库中的、被修改的文件。
- changed but not updated:不会被更新的修改,这部分将列出那些已被修改,但尚未被注册到下次提交中的文件
- untracked files:未被跟踪的文件,这部分将列出所有的新增文件
怎样的修改不该被提交
- 为调试而做的实验性修改
- 意外添加的修改
- 尚未准备好的修改
- 自动生成文件中所发生的修改
从暂存区撤回修改
reset命令可用来重置暂存区。其中第一个参数为HEAD,表示的是我们将其重置为当前HEAD版本。第二个参数则用来指定要被重置的文件或目录
用.gitignore忽略非版本控制文件
创建一个名为.gitignore文件,文件内的文件就会被忽略
存储
情况:如果我们在某些事情进行到中间的时候,突然发现自己需要快速修复某个问题。这个时候,我们通常会希望立即去做相关的修改,但同时先不提交之前一直在做的事情。在这个情况下,我们可以用stash命令先将这些修改保存在本地,日后再处理。
我们通过stash命令将工作区和暂存区中的修改保存在一个被我们称之为储藏栈的缓存区中
我们可以用stash pop命令将栈中所储藏的修改恢复到工作区中
版本库
- 对象数据库:所有提交中的文件、目录以及相关的元数据将被存储在该数据库
- SHA1散列值:我们可以通过一个SHA1散列值从对象数据库中捡取相关对象。SHA1散列值是一种针对文件内容的加密校验植
- 相同数据只存储一次:内容相同的对象拥有相同的SHA1散列值,并且只存储一次
- 相同的数据会被压缩:对于内容相似的数据,Git会针对其被修改的部分采取增量存储的方法
- Blob对象:文件的内容将会被存储在相应的blob对象中
- Tree对象:目录会被存储在相应tree对象中。一个tree对象中通常会包含一份文件名列表,包含这些文件名和存储在blob或tree对象中内容的SHA1散列值
- 重命名检测:文件的重命名和移动操作在提交之前无需报备。Git可以自动根据文件内容的相似度来识别操作
2017/9/16
最近有点忙,今天周末抽空把这本书看看完,写完笔记就换回去。
分支
当有多个开发者用git处理同一软件开发项目时,他们就会在版本库的提交图中创建各自的分支,
在一个Git版本库中,总是唯一存在着一个活动分支,我们可以用branch命令来列出当前所有的分支。其中用*凸显的就是当前活跃分支。
一般情况下,活动分支将会被继续用于接受所有新的提交,并将分支指针移动至最近的那次提交。当然,我们也可以用checkout命令来改变当前的活跃分支
创建一个分支
git branch xx
切换到新分支
branch命令只能用于创建新的分支,但并不会自动切换到该新的分支
git checkout a-branch
快捷方式: 创建并切换到新的分支
git checkout -b a-branch
重置分支指针
分支指针主要用于指向活动分支,它每次提交时移动到最新提交上,因此在通常情况下,我们几乎不太需要去直接设置分支指针,但偶尔我们也会因为一些偶发事件而失去该指针的跟踪,想将其恢复到之前的状态,在这种情况下,我们可以用reset命令来重置分支指针
git reset –hard 39ea21
这样一来,该指针就被重置到提交39ea21所在活动分支上了。其中–hard选项用于确保工作区和缓存区也都会被设置都提交39ea21的状态
reset –hard 命令会覆盖当前工作区和暂存区中的所有修改。所以最好在执行重置之前先用git stash 命令来存储一下这些修改
git stash 可以将修改储存起来,然后再进行切换。之后用stash pop 命令来恢复它们
删除分支
git branch -d b-branch
恢复被删除的分支
Git会自行负责分支的管理,所以当我们删除一个分支时,Git只会删除了指向相关提交的指针,但该提交对象依然会留在版本库中。因此,如果我们知道删除分支时的散列信息,就可以将某个已删除的分支恢复过来
合并分支
使用merge命令来进行分支合并是Git的重要操作之一。我们可以通过指定分支名称来选择待合并修改的分支,然后Git会基于合并的内容来创建一次新的提交。
冲突
Git 非常适合于几个开发者对同一软件做多处修改时,被用于合并他们对程序源代码中所做的修改。这些操作甚至常会涉及那些受移动或重命名操作影响的文件
编辑冲突
通常发生在两个开发者对同一行代码做了不同修改的时候,在这种情况下Git往往无法自行确定两种修改中的哪一种才是正确的。
内容冲突
通常发生在两个开发者对某份代码的几个部分作出各自修改的时候。例如这种情况下就容易导致这类冲突:当一个开发者在修改某一函数的时候,另一个开发者也在同一时间修改同一函数
pull 和 push
- 写访问: push 只能用在我们对其他版本库有写访问权限时。
- 只针对快进合并: push操作通常不会带来合并(不像pull命令)push操作只在快进提交模式下被允许,也就是远程版本没有比本地更多更新的提交
- 无远程跟踪分支
- 无参数调用push : 在无参数的情况下,push命令将只发送那些在其他版本库中有相同名字匹配的本地分支。与之不同的是,pull 和 fetch 所选取的都是全部分支。
总结pull = fetch + merge
pull命令是两种操作的组合。它首先执行的是获取操作。
常用技巧
忽略临时性的本地提交
- gitignore 文件中的那些条目在这里可起不了作用,因此它们只针对那些不受Git管理的文件
检查对文本文件的修改
一般情况下,Git的diff算法会去逐行比较两个文件。因为在源代码中,我们往往修改的都是单行内容,其邻近、行通常不会被涉及,所以diff算法很容易就能察觉到其中的不同。但在文本文件中,事情就不一样了。因为其修改往往是整体性的,例如我们可能会将某些单词整体从一行移动另一行。所以从diff的输出中,我们往往很难看出一个文本文件究竟修改那些内容
对于连续性的文本,–word-diff选项会很用,它可以按单词显示我们所做的修改
git diff –word-diff
–word-diff=color 不同颜色显示
别名
git config –global alias.ci commit
上面就将commit命令简写为ci
项目设置
工作流简介
基于项目目录创建一个新的版本库
- 准备空目录
- 忽略不需要的文件和目录
- 创建一个版本库
- 定义行尾终止符
- 导入终止符
- 创建一个裸版本库