Git必知必会

《Git Pro》真是一本好书,回老家的来回车程阅读了一番,厘清了很多之前模糊不清的概念。

Git 的基础

git使用命令行可以使用其所有的功能,gui工具一般都是利用了某一些功能来实现某一种工作流的方式,gui工具会把几个命令组合起来完成某一项功能,对我们深入了解Git的实现流程是不利的,建议从命令行入手理解Git这个内容寻址文件系统
在Mac系统上安装Xcode后会自动安装git。
我们第一步要做的是对git做一些全局配置(git的配置有三级,第一级是在/etc/gitconfig,对应git
config –system,第二级在 ~/.gitconfig,对应git config –global,第三级在自己的工作区.git/config下面,后面的配置会覆盖前面的配置)
~/.ssh目录下 ssh-keygen -t rsa -C "sqin.lin@foxmail.com" ,将公钥的内容复制到GitHub的配置里面去.

1
2
git config --global user.name "your_name"
git config --global user.email "your_email"

设置命令别名,加快键入速度

1
2
3
4
5
git config --global alias.co checkout
git config --global alias.st status
git config --global alias.ci commit
git config --global alias.br branch
git config --global alias.last "log -1 HEAD"

git init: 创建一个空的git目录
git clone URL: 将远程仓库所有的东西都克隆一份到目录下的.git目录下,并将当前HEAD指向的快照展示出来,可以直接用于开发.
git add: 将未跟踪的文件加入暂存区 将解决冲突后的文件加入暂存区以便提交.注意git add .git add *的区别,add .将除了.gitignore指定的文件外所有的未跟踪和修改的放进暂存区,add * -f 则会忽略.gitignore的作用.
git ci -m: 提交文件到本地仓库,git ci --amend可用于修改最后一次提交的内容
git st: 查看当前三个区域的状态.(工作区,缓存区,仓库)
git diff:查看工作区与暂存区的变化.加入 --staged(--cached) 参数,就是查看暂存区与仓库的变化.
git log:查看提交历史,可以-p,--preety=oneline,-1,--graph等优化输出 ,-Svar 可以查看var是是什么时候引入的。
git co检出dev分支git co dev,git co -- a丢弃a文件的修改:这是个危险的命令,不要随便使用,如果误用了只能依靠编辑器找回修改.用git co -b test快速创建一个test分支并切过去
git br: 查看当前分支, git br test创建一个新分支,git br -a查看所有本地和远程的分支,git br --merge查看已经合并的分支,git br --no-merge查看未合并 的分支,git br -f br_name some-sha1强制修改当前br_name指向的节点
git reset HEAD: git reset HEAD -- file回退暂存区的文件修改 , 回退本地历史,可以使用HEAD^HEAD~1等操作回退指定次数,
git revert: 回退到上一次的修改,产生一个新的节点,与上上个节点的内容一致。之后可push到远端同步回退。与reset的区别在于reset用于local的回退,而revert用于远端的回退。
git push的标准语法是:git push <origin> <place>,例如git push origin master的意思是切到本地仓库中的“master”分支,获取所有的提交,再到远程仓库“origin”中找到“master”分支,将远程仓库中没有的提交记录都添加上去
git fetch: 把远端仓库有,而本地仓库没有的内容拉下来,更新本地仓库的远程指针(如origin/master)但是不做合并
git pull: 把远端仓库有,而本地仓库没有的内容拉下来,并尝试做一次三方合并,相当于先git fetch后再做一次git merge origin/mastergit pull --rebase拉下远端仓库内容后做一次变基合并
git rm [FILE]: 不再跟踪某个文件并从当前目录完全删除. 如果只是想不跟踪,继续存留在目录里,可以使用git rm --cached [FILE]
git mv [FILE] [FILE_NEW]: git mv 是一个命令的组合,等价于以下操作:

1
2
3
mv [FILE] [FILE_NEW]
git rm [FILE]
git add [FILE_NEW]

git stash暂存这个分支的修改,可快速成功切到其它分支

git merge: 如果没有冲突,那么就是将当前的HEAD和分支快速前进(fast-forward) 到 被合并分支的最新位置.如果有冲突,会做一个三方合并,然后生成一个节点.这个合并后的节点将会有两个父节点。
git cherry-pick: 将一些提交复制到当前所在的位置(HEAD)下面。
git rebase: git rebase master test等价于

1
2
git checkout test
git rebase master

,可以使用交互式变基来实现多个历史记录的修改git rebase -i
HEAD:^~移动指针操作符, HEAD^ 当前指针的上一个位置,HEAD^^是上两个位置.可以使用HEAD~2来简化.HEAD^2对于合并后有多个父节点,这个表示第二个父节点,即不在同一条线上的父节点。
git blame:文件标注,展示文件中每一行最后一次修改的提交。
git bisect:二分查找,当不知道是什么时候有问题的时候,可能经过上百个提交,这个可以让你快速找到这个问题在哪个提交被引入的,操作流程如下:

1
2
3
4
5
git bisect start
git bisect bad
git bisect good v1.5.0
循环使用 git bisect bad/good 来标识,最后找到特定的提交记录
git bisect reset 避免HEAD分离。

也可以使用git bisect start HEAD v1.5.0第一个参数是项目不正常的提交,第二个参数是项目正常的提交.
git grep

Git的底层命令

理解三个对象:

  1. blob object 数据对象
  2. tree object 树对象
  3. commit object 提交对象
    树对象可以理解成目录,数据对象可以理解成文件。
    一个树对象包含一个或多条树对象记录,每条记录指向一个数据对象或者子树对象。
    数据对象记录了内容
    树对象记录文件名、类型、sha1指针,查看smt项目最新的树对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
➜  smt-ios git:(Dev) git cat-file -p Dev^{tree}    
100644 blob f58336d7c372fd07b1f994960fb6738ccb7d5a37 .clang-format
100644 blob da7f0b456decacc6b4afffe8382888b84615af2d .formatting-directory-ignore
100644 blob 2b2fd6d74ecd60c6c8c1d8c123098bd414edc190 .gitignore
100644 blob a04e47c2e26365457525bb92bbd8543496475d08 .gitmodules
040000 tree 3c9b9232d56ec9b76913e0068bfda9af6f161615 Build-Phases
040000 tree e78ba62d8d5a26f789f297bac2c3668ea0bc78a9 Docs
040000 tree a421a14d00e0f31c95b7d50d196c98c17fcad150 FreeCitizen.xcodeproj
040000 tree cf7a49e6d373d65586577d3e9e571f405aa2bc8b FreeCitizen.xcworkspace
040000 tree d3b2576371ee10ddf47d5a56d8a811de9204a810 FreeCitizen
040000 tree 3bf3f004ad7d2a4399422fef70c1ba4869f4b240 LocalPods
040000 tree 43c506e57a807ddcc02a6ebfb68fe8b5b545d6e1 Modules
040000 tree 058214ea03b2abdb6df747c1c5ddc5ed85fc0449 NotificationServiceExtension
100644 blob 803b5e0c4f5531a3a647270dd937e47b738008b4 Podfile
100644 blob 8311c39b98e92724960c62444d84c3f1fd0c2d92 Podfile.lock
040000 tree 96f0257a3d27f291e3846ccd4e8cc64a439023f2 Pods
040000 tree 45d41f0ff419518ecf5ab073544859243d46f96b ReadMe.rtfd
100644 blob 366bb7f40803e159e0b3ff6be340fde4d0846e98 addRouter.py
100644 blob 8ffb6dd72159103da05e35ea3af41874385d9801 code-format.sh
040000 tree 2772c124a6c49e4967eb609411a7a1b6803087c8 "\350\257\201\344\271\246\346\217\217\350\277\260\346\226\207\344\273\266"

提交对象记录了提交注释、顶层的树对象、作者、时间戳

生成数据对象:

1
2
3
4
echo "hello git world" | git hash-object -w --stdin => sha1
find .git/objects -type f
git cat-file -p sha1 => content
git cat-file -t sha1 => (blob,tree,commit)

生成树对象:
先把对象写进暂存区,再通过write-tree即可生成

1
2
3
git update-index --add --cahcheinfo 100644 sha1 file_name 
git read-tree --prefix=bak tree_sha1
git write-tree

生成提交对象:
ehco "commit message" | git commit-tree tree_sha1

对象的关系图如下:
git底层三个对象的理解

0%