Git 理解和使用

 

git

git

1 Git

 

1.1 内部原理1

 

1.1.1 底层命令(plumbing)和高层命令(porcelain)

git 根本上就是: a content_addressable filesystem(内容寻址文件系统) + VCS user interface

依次介绍如下3个内容:

  1. 内容文件寻址系统
  2. 传输机制(transport mechanisms)
  3. 版本库管理任务(the repository maintance tasks)

底层命令和高层命令 git 最初是 提供VCS 的 工具集, 只包含底层命令(plumbing). 而现在常用的~check, branch, remote~等都是建立在底层命令上的高层命令(porclain). 通过学习底层命令, 能够了解git的工作原理, 知道git怎么运行和为什么这么运行.

.git 目录几乎包含了 everything that Git 存储和操作. 该目录中最重要的4个条目如下:

  1. HEAD文件: 指向当前check out的分支
  2. index文件: 存储的 staging area 信息. 暂存区信息
  3. object目录: 数据库的所有内容
  4. refs目录: 存储 pointers which 指向提交对象. ??这个描述后面改下.

后续内容, 介绍着4个条目.

1.1.2 Git 对象

Git is a content-addressable filesystem, 意思是: 其核心 就是一个简单的键值对数据库(key-value datastore). 插入内容会获得一个key, 用key可以找回对应数据.

在Git中插入, 就是:

  1. 得到key key 是个 SHA-1值(40位), 该值由 数据内容+header 计算得到.
  2. 在objects目录下, 生产key相关的文件 以key(key共40位)的头2位为目录, 后38位为文件名

例如:

$ echo 'test content' | git hash-object -w --stdin
d670460b4b4aece5915caf5c68d12f560a9fe3e4

$ echo 'version 2' > test.txt
$ git hash-object -w test.txt
1f7a7a472abf3dd9643fd615f6da379c4acb3e3a

在Git中获取, 就是:

  1. 利用key获取内容
$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4
test content

目前剩下的问题是:

  1. 不可能人工管理key, 记版本的key.
  2. 存数据时, 没有存文件名.
  1. 数据对象

    数据对象(blob object) 对应实际的数据. 前面实例中的都是数据对象.

  2. 树对象

    树对象(tree object), 可以:

    1. 解决文件名保存问题
    2. 将多个文件组织到一起

    所有内容 均以 树对象和数据对象的形式存储, 类似UNIX文件系统:

    1. 树对象 对应 UNIX中的目录项 一个树对象 包含: 多条 树记录(tree entry) 每条树记录 包含: SHA-1指针(指向其他数据对象或树对象), 文件名 等.
    2. 数据对象 对应 inodes或文件内容

    树对象从 暂存区(staging area) 生成. 因此, 生成新的树对象, 首先要添加到 暂存区.

    $ git update-index --add --cacheinfo 100644 83baae61804e65cc73a7201a7252750c76066a30 test.txt
    $ echo 'new file' > new.txt
    $ git update-index --add new.txt
    
  3. 提交对象

    目前问题: 能创建快照, 但是没有其他信息保存, 且只能记住SHA-1值. 提交对象(commit object)用于保存这些信息. commit 对象指向了顶层 tree 对象以及先前的 commit 对象.

1.1.3 Git References

问题: 需要记住提交的SHA-1

references(引用): 通过简单的名字记录SHA-1值. 在refs目录下的文件, 文件记录了提交的SHA-1.

git branch 创建分支, 就是 用当前分支的 最后一次SHA-1, 创建引用.

  1. Head

    指向当前分支的最后一次提交. refs下的文件夹heads文件夹, 包含另一个引用文件. 例如: refs/heads/master 这个不同于HEAD

  2. Tags

    类似commit对象, 记录提示信息, 但是不指向 tree. 类似引用, 但是不会变化, 总是指向同一个commit.

  3. Remotes

    remote reference(远程引用), 指向最后一次与服务器通信的commit的SHA-1 例如: refs/remotes/origin/master 存的是本地最后一次与 远程分支master 通信的SHA-1

1.2 Git 分支

 

1.2.1 何谓分支

Git分支: 本质上仅仅是指向 提交对象 的指针.*

git branch <new_branch_name> 基于当前 HEAD 新建一个分支指针. HEAD是正在工作的分支的别名

1.2.2 分支的新建与合并

git checkout -b <new_branch_name> 新建并切换到分支

git merge hotfix 将hotfix代码, 合入当前分支.

分支合并, 三方合并. 找出共同祖先. 合并为一个新的 commit, 该commit有2个祖先.

git add 将把冲突文件标记为已解决.

1.2.3 分支管理

git branch -v 所有分支的最后一次提交.

git branch -a 本地和远程的所有分支.

git branch –merged git branch –no-merged

1.2.4 远程分支

远程分支(remote branch): 对远程仓库的分支的引用, 与远程仓库交互时自动移动.

git push origin <local_branch_name>:<remote_branch_name> git push origin <branch_name> 如果本地与远程分支名相同, 可以使用第二个push git push origin :<remote_branch_name> 删除远程分支

git fetch orgin 会将所有远程分支下载到本地, 但是本地不能编辑. git checkout -b <new_branch_name> origin/<remote_branch_name> 将创建可编辑的本地分支. 并且该分支是 跟踪分支.

跟踪分支(tracking branch) pull, push时, 知道关联的远程分支

1.2.5 变基

rebase(变基): 将一个分支上的改动 在另一个分支上 重做一遍. 变基的内部步骤:

  1. 找到基线分支, 即共同祖先;
  2. 提取出当前分支,即变基分支的改动
  3. 然后将改动应用到目标分支的最后一个提交上,
  4. 最后在目标分支上生成一系列新的commit, 且变基分支指向该提交.

此时, merge 目标分支 与 变基分支 就只需要快速合并了.

例如: 将 experiment rebase master上

  1. git checkout experiment 切到变基分支
  2. git rebase master rebase到目标分支
  3. git checkout master 切换到目标分支
  4. git merge experiment 快速合并
  1. 好处
    1. 产生线性的修改历史.
    2. rebase时, 解决冲突, 在merge时, 只需要 fast foward.
  2. 变基的风险
    1. 变基必须遵守的戒律: 不要对已经提交的分支做变基. 只要遵守, 就不会出错.
    2. 戒律的解释: 变基就是 删除一些 commits, 生成一些 新的, 相似的, 但是不同的 commits.
    3. 不遵守的后果: 如果 别人 已经基于rebase前的分支进行了修改, 那么老分支和rebase后的分支做merge时, 会有很多冲突, 并且有message相同的不同提交.

1.3 Git 基础

 

1.3.1 查看分支提交历史

-p 以补丁格式显示差异
–stat 统计信息
–graph 分支合并历史
–name-only 仅显示文件名

1.4 常用命令与常见问题

Footnotes:

 

posted @ 2018-08-26 23:04  董庆然  阅读(362)  评论(0编辑  收藏  举报