这才是真正的Git

Git原理及实用技巧

李泽帆(靓仔) · 腾讯CDC · Web开发和数据科学 · @LZANE
而又经常有人说,Git复杂难懂
命令很容易混淆
同一个指令,如git checkout,后面带不同参数实现完全不同的功能
git checkout master
git checkout -f
git checkout -- .
git checkout -b new_branch
git checkout master -- file.txt
git文档晦涩难懂
$ man git-push
Update remote refs along with associated objects
人话:将本地的变更记录推送到远端
如果你不懂一个东西的内部原理,
它有时会变得十分混乱。

小调查

了解Git object,如blob、tree、commit等?

知道git reset --soft、git reset、git reset --hard的区别

听说过git reflog?

PPT or DEMO?

Git是怎么储存信息的


                    $ git init
                    $ echo '111' > a.txt
                    $ echo '222' > b.txt
                    $ git add *.txt
                

                    $ tree .git/objects
                    .git/objects
                    ├── 58
                    │   └── c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c
                    ├── c2
                    │   └── 00906efd24ec5e783bee7f23b5d7c941b0c12c
                    ├── info
                    └── pack

                

                    $ cat .git/objects/58/c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c
                    xKOR0a044K%
                
git cat-file [-t] [-p]

                    $ git cat-file -t 58c9
                    blob
                    $ git cat-file -p 58c9
                    111
                
Git Object
111
blob
SHA1
键值对

                    $ git commit -m '[+] init'
                    $ tree .git/objects
                    .git/objects
                    ├── 0c
                    │   └── 96bfc59d0f02317d002ebbf8318f46c7e47ab2
                    ├── 4c
                    │   └── aaa1a9ae0b274fba9e3675f9ef071616e5b209
                    ...
                

                    $ git cat-file -t 4caaa1
                    tree
                    $ git cat-file -p 4caaa1
                    100644 blob 58c9bdf9d017fcd178dc8c0...	a.txt
                    100644 blob c200906efd24ec5e783bee7...	b.txt
                

                $ git cat-file -t 0c96bf
                commit
                $ git cat-file -p 0c96bf
                tree 4caaa1a9ae0b274fba9e3675f9ef071616e5b209
                author lzane 李泽帆  1573302343 +0800
                committer lzane 李泽帆  1573302343 +0800
                [+] init
                
那分支和tag在哪里?

                $ cat .git/HEAD
                ref: refs/heads/master

                $ cat .git/refs/heads/master
                0c96bfc59d0f02317d002ebbf8318f46c7e47ab2
                
HEAD、分支、普通的Tag可以简单的理解成是一个指针,指向对应commit的SHA1值。
Q1: 为什么要把文件的权限和文件名储存在Tree object里面而不是Blob object呢?

Git的三个分区及变更历史的形成

  • 工作目录 ( working directory ):操作系统上的文件,所有代码开发编辑都在这上面完成。
  • 索引( index or staging area ):一个暂存区域,会在下一次commit被提交到Git仓库。
  • Git仓库( git repository ):由Git object记录着每一次提交的快照,以及链式结构记录的提交变更历史。
Git的大部分指令就是在操作这三个分区以及这条链。
思考一下git的各种命令,尝试在上图将它们“可视化”出来
Q2:每次commit,Git储存的是全新的文件快照还是储存文件的变更部分?
全新的文件快照
Q3:Git怎么保证历史记录不可篡改?
Git和区块链的数据结构非常相似,两者都基于哈希树和分布式

Git实用技巧

误操作导致分支不见了,如何恢复?
不小心删了分支
git reset --hard
git rebase
...
git reflog 时光机

                     $ git reflog
                     e171c5f (HEAD -> article/git, origin/article/git) HEAD@{0}: commit: [+] writing
                     7788bcd HEAD@{1}: commit: [+] writing
                     adbb712 HEAD@{2}: commit: [*] 修改构建脚本
                     7341618 HEAD@{3}: commit: [+] writing
                     925c148 HEAD@{4}: pull: Fast-forward
                     6952e07 HEAD@{5}: commit: [+] writing
                     c92a024 HEAD@{6}: commit: [+] 添加文章内容
                     cfb234e (origin/master, origin/HEAD, master) HEAD@{7}: reset: moving to HEAD~2
                
如何获得一个干净的工作空间?
现在的工作空间太乱了
工作到一半,临时插需求
...
git reset --hard HEAD 或 git checkout -f
git clean -df
git stash push [-u | --include-untracked]
从Git历史中删除一个文件
敏感信息(私钥,内网ip等)
不需要版本控制的超大文件
...
$ git filter-branch --tree-filter 'rm -f passwords.txt' HEAD
$ git commit --amend
$ git rebase -i origin/master
$ git show-branch
$ git blame
$ git bisect

recap

好的,你变强了。

Q&A

@LZANE