所有的版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件、程序代码等等,Git也不例外。
版本控制系统可以告诉你每次的改动,比如在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了啥,版本控制系统不知道,也没法知道。
注意:Microsoft的Word格式是二进制格式,因此版本控制系统是没法跟踪Word文件的改动的。 如果要真正使用版本控制系统,就要以纯文本方式编写文件。
btw:
千万不要使用Windows自带的记事本编辑任何文本文件。原因是Microsoft开发记事本的团队使用了一个非常弱智的行为来保存UTF-8编码的文件,他们自作聪明地在每个文件开头添加了0xefbbbf(十六进制)的字符,你会遇到很多不可思议的问题,比如,网页第一行可能会显示一个“?”,明明正确的程序一编译就报语法错误,等等,都是由记事本的弱智行为带来的。
Git是一个由C语言开发而成的分布式版本控制系统。

集中式版本控制系统中(比如CVS、SVN),版本库是集中存放在中央服务器的,而由于工作时用的都是自己的电脑,所以要先从中央服务器取得最新的版本,工作结束后,再把新的版本推送给中央服务器。
中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。
集中式版本控制系统最大的毛病就是必须联网才能工作。
而分布式版本控制系统根本没有“中央服务器”,每个人的电脑都是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本库就在自己的电脑上。
分布式版本控制系统的安全性更高,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。而集中式版本控制系统的中央服务器要是损坏,所有人都没法干活了。
此时如何进行多人协作?比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
在实际使用中,其实很少在两人之间的电脑间推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机…。
因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。
假如你还有10个同事,你每一次更改都要提交10次,其他同事有更改也要像这样分别向我们提交,是不是觉得非常麻烦,所以我们说干脆找一台固定电脑(服务器)用来统一规定把修改推给这台电脑,这样只需要提交1次就行了,其他人去这台机器上同步就好了。
发现没有,Git的中央服务器可以没有,我们只是为了方便才这么做的。
此时,如果这个服务器坏了,你只需要重新弄个电脑,把自己电脑上的同步一份过去,大家约定好都提交到这个新电脑上就行了。【所有的版本和历史都依然在自己的电脑上】
集中式和分布式的区别是:本地是否有完整的版本库历史。
假设SVN服务器没了,那你丢掉了所有历史信息,因为你的本地只有当前版本以及部分历史信息。
假设GitHub服务器没了,你不会丢掉任何git历史信息,因为你的本地有完整的版本库信息。你可以把本地的git库重新上传到另外的git服务商。
MacOS系统,苹果开发者网站中下载的命令行工具中包含了Git。
设置当前机器的git信息(自报家门):
git config --global user.name "Your Name"
git config --global user.email "email@example.com"
一个文件夹就是一个工作区(Working Directory)。终端进入该文件夹(工作区),输入命令git init即可用Git管理该工作区(包括其中所有子文件夹和子文件)。此时当前文件夹中多了一个隐藏文件夹.git,该隐藏文件夹就是版本库(Repository)。
对于MacOS的终端,当你指定某个文件夹为Git管理的版本库时,进入该文件夹时,命令提示符会发生改变:
只是个提示信息,不影响命令行的操作。
此时Git自动为我们创建了一个根结点(称为master),并将HEAD指针指向它。
.git中跟踪并记录了工作区的每次修改、删除等信息,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
.git中有一个很重要的文件stage(或index),称为“暂存区”。git add命令其实就是将文件的修改之处添加到暂存区,git commit就是将暂存区中的所有内容存为一个结点,存到当前HEAD指针所指的结点后面,并将HEAD指针指向当前结点。
可见:Git版本库中每次存储的只是当前版本与前一个版本的不同之处。
将需要Git管理的文件(以hhh.txt为例)先存入该文件夹中。将其放入Git版本库需要2步:
git add hhh.txt (类似于“多选”选中)此时使用git status命令(该命令可以让我们时刻掌握仓库当前的状态),会显示“untracked files”,表明存在新创建的文件。

git commit -m "备注信息"-m后面是本次提交的说明,所输入的内容最好是有意义的,这样就能从历史记录里方便地找到改动记录。X file changed:X个文件被改动(我们新添加的文件);Y insertions:插入了Y行内容。为什么Git添加文件需要add,commit一共两步呢?
因为commit可以一次提交很多文件,所以你可以多次add好几个文件,最后一起commit。
git add file1.txt
git add file2.txt file3.txt
git commit -m "add 3 files."
注意:
- Git命令必须在Git仓库目录内执行(git init除外),在仓库目录外执行是没有意义的。
- 添加某个文件时,该文件必须在当前目录下存在。
再次修改hhh.txt文件,使用git status命令:

返回的信息告诉了我们hhh.txt文件被修改了,且"not staged",即还没被“选中”。要想查看具体的变化之处,可以使用命令:
git diff hhh.txt

显示的格式正式Unix通用的diff格式。
若运行git add hhh.txt后再git status,此时会显示:

表示被提交的文件中包含该文件。
Git存储各版本类似于“保存存档”,每个存档称为“commit”,可以通过读取存档从而快速地从某个阶段进行继续。
git log命令可以查看该项目所有commit的记录:

如果嫌输出太多,可以添加命令参数:
git log --pretty=oneline

其中长串的编码是commit id,一一对应着某次提交。每个编号都是一个十六进制的非常大的数字,有效避免了多人协作时发生编号冲突。
用HEAD表示当前版本,上一个版本就是HEAD^,再上一个版本就是HEAD^^,前
n
n
n个版本写为:HEAD~n。
使用reset命令进行版本的回退(相当于读取存档):

此时再查看log,会发现看不到后面的版本了。

要想再修改回去,可以利用commit id进行reset。

命令git reflog中记录了每次HEAD指针的移动,因此在这里可以很方便地找到所有commit id。
