Git的几个重要概念

来源:互联网 发布:打字软件赚钱平台 编辑:程序博客网 时间:2024/04/30 03:00
弄懂以下几个概念, 对理解Git如何工作有很大帮助: (可能需要来回的揣摩几遍)

<> repository & workspace

repository, 仓库, 包含了所有的代码, 分支, 代码历史等信息.
workspace, 工作区, 从repository check out出来的代码.

git和CVS,SVN最大的不同就在于仓库的位置, CVS,SVN的仓库都是在服务器上, 代码提交, branch, tag等操作都是在服务器上完成; 相反, git的每个用户都有一份完整的repository, 也就是说, clone下来的repository和服务器上的repository是一样的. 每个人都可以是一个服务器. 这就是所谓的分布式版本控制系统.

正因为repository在本地, 所以几乎所有操作都可以本地进行, (e.g. branch, Commit, log, status ...), 只有你想和别人交换信息的时候才需要联网. 另外一个好处是速度, 所有的操作都在本地, 所以git的速度堪称飞快.
repository放置在顶层目录的.git目录下.

<> hash.

  进入.git/objects/中就能看到一大堆的16进制字符组成的文件名. 所有的代码, 所有的目录, 所有的分支, 所有的变更历史... 所有的和代码相关的信息都在这些文件里. 这些Objects有3类: Blob, Tree, Commit. 所有存储到objects下的文件都会被计算SHA1值, 然后以该SHA1值作为文件名, 而它原来的文件名则存放在下面要说到"Tree"里面.

<> Blob

  BLOB用来存储常规文件. 这个概念很简单, 把一个文件拷贝到object目录下, 重命名, 新的名字就是它的SHA1值.   需要注意是: 当一个文件的内容修改了, 它会以一个新的SHA1名字, 整个的重新存储到git库中, 而不单单是修改了部分. 这是git一个重要的特征, 虽然会带来一些存储上的浪费, 但是换来的很多其他方面的好处.

<> Tree

  Tree用来表示目录, 存储的是一个 "文件名<-->SHA1文件名" 的列表. 根据上面的规则可以推出以下的重要结论:
    * 只要某个文件/目录发生了变化, 所有的上级目录的Tree都要变化.
    * 一个顶级目录的Tree, 代表了一个代码库的版本.

<> Commit

  一个Commit包含一次代码的变更信息, 每git commit一次代码, 生成一个Commit. 除了log, Commiter等信息, Commit包含的最重要的信息就是两个top Tree的SHA1名称. 一个是perant Tree, 一个是current Tree. 比较这两个Tree之间的不同就能知道这个Commit包含的变更内容.

<> refs

    在.git/refs目录下有很多reference, 查看这些reference的内容, 你会发现都是SHA1值. 很简单, refs就是指向某个Commit的指针.  branch是refs, tag是refs, HEAD也是ref.
    随着你的pull, push, Commit, branch等操作, git会自动修改这些refs.

<> stage

在git库和workspace之间还有一个index(stage), 可以把它看做是临时的中转仓库, 在代码真正放入仓库前, 先集中放在这里. 在用git status 和 git diff的时候对这个概念最有体会.


<> remote

打开.git/config, 就明白remote是什么了.
   [remote "origin"]
       fetch = +refs/heads/*:refs/remotes/origin/*
       url = git://git.xxx.org/xxx.git
fetch 字段用来说明远端git库中refs和本地refs的对应关系.
url 字段是远端git库的地址.
remote通常只有一个, origin, 指向你clone的来源, 但也可以有很多个, 比如你和甲乙丙丁都做同一个项目, 那么你可以把他们都加到remote里面, 这样能fetch他们的任何一个人的改动.

<> pack

   其实就是把objects压缩打包, 在git fetch/pull/push/clone中就要用到. git gc也用来减少磁盘空间的占用量.


把上面的概念精简一下:


    file ==hash==> Blob
    目录信息(文件列表) ==hash==> Tree
    牵一发动全身, new Tree of top dir === Commit
    指向Commit的指针  === refs
    在这中转, 再搬到仓库区 === stage
    其他仓库的位置 ==> remotes
    打包 ==> pack

示例


用以上的概念可以解释所有的git操作, 先用git diff作为例子吧.
git diff master dev
这个命令用来比较master分支(主分支) 和dev分支的不同.
git内部的流程如下:

    通过.git/refs/heads/master得到该分支最新的Commit:
        比如:602088ec1f420f19e0c8f76715d7c035f8383f9f
    可以用git show 来查看Commit的详细信息.
    也可以用git ls-Tree来查看该Commit包含的目录信息.

    同理得到dev分支的Commit,
    对比Commit中包含的Tree, 由于SHA1相同的objects内容一定相同. 所以只需要对比SHA1不同的objects.
    如果objects是Tree, 递归比较.
    如果是Blob, diff 之.
    输出结果
原创粉丝点击