Git 是一个分布式的文件管理和版本控制工具,本文主要从 Git 的快照记录方式和分布式工作方式上介绍一些基础。私以为对 Git 的这些工作方式的认知,会对理解和优化 Git 的日常使用的一些命令比较有帮助。
推荐阅读
GitBook : https://git-scm.com/book/zh/v2
廖雪峰:https://www.liaoxuefeng.com/
一、基础概念
分布式、文件管理、版本控制
什么是分布式?如下图:

如图,每一个 version 其实就是一个版本的数据存储。SVN 等集中式的版本控制工具,是将所有的版本信息存储在远程版本仓库中,如果断网,则无法工作。而Git则不同,Git的每一台 clone 过某个仓库的电脑或者服务器,都是一个完整的仓库,他的版本信息都存储在本地。换句话说,Git 的 commit 操作其实是提交信息到本地仓库,所以 Git 在断网的情况下也可以进行版本管理工作,只有在从远程仓库获取更新以及推送信息到远程仓库时,才需要联网。
二、本地仓库的文件存储和版本管理
1.本地仓库的文件存储
在工作目录下,进入 .git
目录,查看 tree
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| . ├── HEAD ├── branches ├── config ├── description ├── hooks │ ├── applypatch-msg.sample │ ├── commit-msg.sample │ ├── post-update.sample │ ├── pre-applypatch.sample │ ├── pre-commit.sample │ ├── pre-push.sample │ ├── pre-rebase.sample │ ├── pre-receive.sample │ ├── prepare-commit-msg.sample │ └── update.sample ├── info │ └── exclude ├── objects │ ├── info │ └── pack └── refs ├── heads └── tags
|
本地工作目录下面的 .git 目录就是本地的版本仓库,其中各个目录和文件的内容如下:
hooks
: 这个目录存放一些shell脚本,可以设置特定的git命令后触发相应的脚本;在搭建 gitweb 系统或其他 git 托管系统会经常用到 hook script
info
: 包含仓库的一些信息
logs
: 保存所有更新的引用记录
objects
: 所有的Git对象都会存放在这个目录中,对象的SHA1哈希值的前两位是文件夹名称,后38位作为对象文件名
refs
: 这个目录一般包括三个子文件夹,heads
、remotes
和tags
,heads
中的文件标识了项目中的各个分支指向的当前 commit
COMMIT_EDITMSG
: 保存最新的 commit message
,Git 系统不会用到这个文件,只是给用户一个参考
config
: 这个是GIt仓库的配置文件
description
: 仓库的描述信息,主要给gitweb等git托管系统使用
index
: 暂存区(stage),是一个二进制文件
HEAD
: 这个文件包含了一个档期分支(branch)的引用,通过这个文件Git可以得到下一次commit的parent
ORIG_HEAD
: HEAD
指针的前一个状态
本地仓库文件的四中状态:

对应的各种git操作:
1 2 3 4
| {untracked/modified => staged} git add {staged => unmodified} git commit
|
注意:
(1)git checkout
: 优先恢复到staged
(2)git diff
: modified vs staged | unmodified
git diff —cached
: staged vs unmodified
(3)途中的 remove
文件指的是执行 rm
操作物理删除文件,如果是执行的 git rm
操作,被删除的文件会直接变成 staged
状态
2.所谓版本:commit 的时候发生了什么

结合前面提到的本地版本库,其实本地版本库就是一堆指针和一堆文件快照。
如图,每次 commit
的时候,有变化的文件会生成一个文件快照,然后本次 commit
生成一个 commit 指针,commit 指针指向一个 tree
文件,tree文件记录的是本次 commit 时候的所有文件的快照。
而每个分支的指针其实就是指向当前分支最新一次commit。而本地仓库的 head 指针,就是指向当前分支。
由此,git checkout
切换分支,实际就是改变当前 HEAD 指针的指向,git reset
操作实际就是将当前分支的指针指向某次 commit 记录。
另外:
git add
操作(文件转为 staged
状态)也会生成 blob
快照文件,且 git add
生成的 blob
文件容易变成“悬空对象”
commit
记录的是完整的文件状态,所以 git reset
操作其实可以恢复到任何一次 commit
的完整状态,也能找回所有存在过git中的文件,无论你是否进行过分支的merge操作
三、分享一些命令,值得逐条研究
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| # 全局配置开发者信息,建议开发目录中在 .git/config 中配置当前仓库开发者信息覆盖全局信息 git config --global user.name "username" #配置本地git账户的姓名 git config --global user.email "username@email.com" #配置本地git账户的邮件 git remote [-v] #显示所有的远程仓库 git remote add <name> <url> #添加远程仓库 git remote rm <name> #删除相应的远程仓库 git branch [-v] #显示所有的本地分支 git branch [-r] #显示所有的远程分支 git branch <branchname> #创建相应的本地分支 git branch [-d|D] <branchname> #删除相应的本地分支 git checkout <branchname> #切换到相应分支 git chechout [-b] <branchname> <repository>/<branchname> #创建对应的本地分支,并获取对应远程分支的代码 git add [filename | .] #添加相应文件到暂存区 git commit [-m] <comment> #将暂存区的更改添加到本地仓库 git log #列出当前分支的提交记录 git push <repository> <local branchname>:<branchname> #将本地分支的内容推送到对应的远程分支,如果远程分支不存在则创建对应的远程分支 git push <repository> :<branchname> # 删除远程仓库分支 git merge <branchname> #合并对应分支到当前分支 git rebase <branchname> #将对应分支的变更衍生到当前分支
git commit --amend 重新编辑commit信息 git branch -r -a -l 查看所有远程分支 git reset --hard {commit-hash} 回退到某次提交,并撤销之后的所有修改 git reset --soft {commit-hash} 回退到某次提交,并保留之后的修改(modified) git revert {commit-hash} 撤销某次操作 git rebase --continue rebase 冲突解决后,先git add 后执行此命令 git log --oneline commit-short-hash & commit-message 一行显示 git log --pretty=oneline commit-hash & commit-message 一行显示 # 一条神奇的查看git log 的命令,建议尝试 git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
# 恢复到上次commit的状态,完整恢复,包括gitignore的文件 git reset --hard;git clean -df # 从某次commit中提取文件 git checkout <commit-hash> --filename # 将某次commit(可以是其他分支的)修改的所有内容提取到当前分支 git cherry-pick # 查看fileName文件第160最近10次的修改记录 git blame -L 160,+10 <filename> git reflog # 查看提交版本历史记录 git fsck # 运行一些仓库的一致性检查, 如果有任何问题就会报告. 这项操作也有点耗时, 通常报的警告就是“悬空对象"(dangling objects).git add 产生的
|