Git版本控制系统结构和命令手册

概述

Git 作为一个强大的开源的分布式版本控制系统,在设计开发时为自己提出了一些目标:效率、简单设计、支持非线性开发、完全的分布式和高效地处理大型项目(如Linux内核),Git的最终实现完成了大部分目标。

分布式版本控制

什么是版本控制?

传统的基于文件/补丁的版本控制的问题:

  • 难于维护。
  • 集中式,不能并发操作。
  • 难于回溯和历史记录查询。

传统的集中式版本控制的问题:

  • 单点故障

分布式版本控制的问题:

  • 高性能。
  • 高效的工作方式。支持分支开发(非线性开发)。
  • 离线功能。
  • 备份与恢复,数据安全性。
  • 极强的可维护性。


Git 是什么

核心模型

Git 是什么?
Git 是完全的分布式版本控制,即每一个客户端都保存项目的全部文件以及历史,即使服务器崩溃,它也可以从任何一个客户端那里获得镜像进行恢复。
Git 将所有数据都抽象为 快照流Streams of Snapshots)。和其他版本控制系统基于增量的模型不同。

Git 保证 文件完整性,它对每个文件/目录/提交等数据对象会生成签名校验。这意味着在 Git 不知情的情况下,文件和目录的更改是不可能的(包括重命名文件)。
Git 通常只添加数据。
Git 将文件的状态分为三种:Modified -> Staged -> Commited

版本库

  • 文件 - blob
  • 目录 - Tree
  • 版本 - Commit:每次 commit 代表生成了当前工程库的一个快照,且使用唯一的散列值引用。对库中数据的任何修改都会产生不同的快照,也即不同的散列值。
    所有数据,都会生成一个散列值(SHA-1),该值可以用作相关对象的引用以及日后恢复数据时所需的键值。采用这种散列值和这种既定的版本库结构的优势:
  • 高性能。通过散列值访问数据。
  • 冗余度。相同的文件内容只需存储一次。
  • 分布式版本号。Commit 的散列输入中包括了作者、日期信息。完全相同的文件和目录下,不同的开发者产生的commit会不同,也就不用担心未来会发生版本冲突。
  • 版本库之间的高效同步。用户执行 Push 操作时,只需要传送远程版本库中不存在的对象即可。
  • 数据完整性。

分支功能

Git 的杀手级特性是它的分支功能。
参考手册:Git-分支

常用命令

git 手册

重写历史

手册-重写历史
使用交互式 rebase 命令修改历史:

1
$ git rebase -i
  • 配置工具

    git config --global user.name "[name]"
    git config --global user.email "[email address]"
    git config --global color.ui auto
    git config --global core.editor "[vim|emacs]"

  • 分支

    git branch [branch-name] 创建新分支
    git switch -c [branch-name] 切换到指定分支并更新工作目录
    git merge [branch-name] 将指定分支的历史合并到当前分支,git会处理过程中可能会出现的冲突问题。
    git branch -d [branch-name] 删除指定分支
    git stash 储藏当前脏工作目录下的修改;该命令经常用于下面的场景:当想切换到另一个分支修复Bug,但又不想提交当前分支下的修改,这时候可以使用 git stash 来储存当前修改,后面可以使用git stash pop 恢复;另外其储存内容不会 git push 到服务器。

  • 进行更改

    git log 当前分支的历史
    git log --follow [file] 列出文件的版本历史,包括重命名
    git diff [first-branch]...[second-branch] 两个分支的内容差异
    git show [commit] 显示指定commit的元数据和内容变化
    git add [file] 将文件进行快照处理,即进入staged域
    git commit -m "[descriptive message]"将文件快照永久地记录在版本历史中

  • 重做提交

    git reset [commit] 撤销所有commit后的提交,在本地保存更改
    git reset --soft [commit] 保留历史,改回指定提交
    git reset --hard [commit] 放弃所有历史,改回指定提交
    git commit --amend 对commit的反悔
    git reset HEAD <file>... 对add命令的撤回
    git checkout -- <file> 对一个Modified的文件撤回修改

  • 创建仓库

    git init 创建新的仓库
    git remote add origin [url] 将本地仓库与远程仓库连接起来
    git remote show [remote-name]
    git remote rename 改变远程仓库的名字
    git clone [url] 镜像远程仓库到本地

  • 标签tag

    git tag 列出标签
    git tag -a [tag-name] 创建annotated类型的标签,该类型标签比较正式,它指向所有信息
    git tag [tag-name] 创建lightweight类型的标签,不正式,临时指向小部分信息
    git show [tag-name] 显示标签信息
    git tag -a [tag-name] [commit-checksum] 给某次提交添加tag

  • 同步更改
    git fetch 下载远程跟踪分支的全部历史,它只获取本地没有的那部分数据,clone命令封装了fetch命令
    git push 将所有本地分支上传到远程服务器
    git merge 将远端跟踪分支合并到当前本地分支
    git pull 使用来自对应远端分支的所有新提交更新你当前的本地工作分支。git pull是 git fetch 和 git merge 的结合。

  • 子模块

    子模块允许用户将一个git仓库作为另一个git仓库的子目录。它能让你将另一个仓库克隆到自己的项目中,同时还保持提交的独立。

    git submodule add [url]
    git submodule init 初始化本地配置文件
    git submodule update 该项目中抓取所有数据并检出父项目中列出的合适的提交
    git clone --recurse-submodules [url] 自动初始化并更新仓库中的每一个子模块, 包括可能存在的嵌套子模块。
    git submodule update --remote --init

  • Patching:
    git apply --stat xxxx.patch 检查 patch 文件
    git apply --check xxxx.patch 检查能否应用成功
    git am --signoff < xxxx.patch 应用补丁

  • 调试:
    git blame: 追溯一个文件的历史修改记录。

.gitignore文件

参考gitignore文件指导

Github

使用 wget 下载 github 上的单个文件:

1
$ wget -L https://raw.github.com/[user name]/[repositorty name]/[branch]/[file].

如果遇到类似下面的错误报告:

1
2
3
4
5
$ wget -L https://raw.github.com/[user name]/[repositorty name]/[branch]/[file].
...
正在解析主机 raw.githubusercontent.com (raw.githubusercontent.com)... 0.0.0.0, ::
正在连接 raw.githubusercontent.com (raw.githubusercontent.com)|0.0.0.0|:443... 失败:拒绝连接。
正在连接 raw.githubusercontent.com (raw.githubusercontent.com)|::|:443... 失败:拒绝连接。

则可以修改 /etc/hosts 文件,使得对 raw.github.com 域名的解析指向国内可以访问的 IP 地址:

1
2
3
4
5
6
# /etc/hosts

# Hong Kong
151.101.76.133 raw.githubusercontent.com
151.101.76.133 raw.github.com

术语表

  • commit 提交: 一个 Git 对象,是你整个仓库的快照的哈希值
  • branch 分支: 一个轻型可移动的 commit 指针
  • clone: 一个仓库的本地版本,包含所有提交和分支
  • remote 远端: 一个 GitHub 上的公共仓库,所有小组成员通过它来交换修改
  • fork: 一个属于另一用户的 GitHub 上的仓库的副本
  • pull request 拉取请求: 一处用于比较和讨论分支上引入的差异,且具有评审、评论、集成测试等功能的地方
  • HEAD: 代表你当前的工作目录。使用git checkout 可移动 HEAD 指针到不同的分支、标记(tags)或提交。

参考链接

Git 参考手册
Everyday Git