《Git权威指南》学习笔记
前些日子买了蒋鑫老师的Git权威指南,为了更好地学习Git,将学习过程中感觉应该记下来的东西记录下来,遂成此文。此文在学习过程当中,不断更新。
这个博客是在GitHub上搭建的,搭建的过程中,我对git产生了浓厚的兴趣,遂买了蒋鑫老师的这本《Git权威指南》。写此文的目的,一是督促自己学习,二是作为以后的参考笔记,三希望对别人也能够有所帮助。
配置用户名和邮箱
$git config --global user.name "xiaoji121"
$git config --global user.email "dong.fly.ming@gmail.com"
删除Git全局配置文件中关于user.name和user.email的设置
$git config --unset --global user.name
$git config --unset --global user.email
设置命令别名
$git config --global alias.st status
$git config --global alias.ci commit
$git config --global alias.co checkout
$git config --global alias.br branch
开启控制台颜色显示
$git config --global color.ui true
初始化版本库
$git init demo
在工作区中建立目录 a/b/c,进入到该目录中:
$cd /path/to/my/workspace/demo/
$mkdir -p a/b/c
$cd /path/to/my/workspace/demo/a/b/c
显示版本库.git目录所在位置
$git rev-parse --git-dir
显示工作区根目录
$git rev-parse --show-toplevel
/path/to/my/workspace/demo
相对于工作区根目录的相对目录
$git rev-parse --show-prefix
a/b/c
显示从当前目录(cd)后退(up)到工作区的根的深度
$git rev-parse --show-cdup
../../../
提交
$git commit --allow-empty -m 'who does commit?'
$git commit --amend --allow-empty --reset-author
--allow-empty参数后充许执行空白提交
--amend是对刚刚提交进行修补
打印日志
$git log --pretty=fuller
$git log --stat
$git log --pretty=online
工作区、版本库、暂存区原理图
图中左侧为工作区,右侧为版本库。在版本库中标记为 "index" 的区域是暂存区(stage, index),标记为 "master" 的是 master 分支所代表的目录树。
图中我们可以看出此时 "HEAD" 实际是指向 master 分支的一个“游标”。所以图示的命令中出现 HEAD 的地方可以用 master 来替换。
图中的 objects 标识的区域为 Git 的对象库,实际位于 ".git/objects" 目录下。
当对工作区修改(或新增)的文件执行 "git add" 命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID 被记录在暂存区的文件索引中。
当执行提交操作(git commit)时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。
当执行 "git reset HEAD" 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。
当执行 "git rm --cached
当执行 "git checkout ." 或者 "git checkout --
当执行 "git checkout HEAD ." 或者 "git checkout HEAD
Git diff 魔法
工作区和暂存区比较
$git diff
暂存区和HEAD比较
$git diff --cached
工作区和HEAD比较
$git diff HEAD
保存当前工作进度
$git stash
打印日志,并可以提供短小的提交ID
$git log --graph --oneline
git reset
可以将“游标”指向任意一个存在的提交ID。
$git reset --hard HEAD^
HEAD^ 代表了HEAD的父提交,这条命令就相当于将master重置到上一个老的提交上。
重置到任意一个版本
$git reset --hard 版本号
使用重置命令很危险,会彻底地丢弃历史。那么,还能够通过浏览提交历史的办法找到丢弃的提交ID,再使用重置命令恢复历史吗?不可能!因为重置让提交历史也改变了。
用reflog挽救错误的重置
虽然不能通过浏览提交历史的办法找到丢弃的提交ID,但我们有reflog。
$git reflog show master | head -5
输出类似如下:
93dd33d master@{0}: 93dd33d : updating HEAD
343eed3 master@{1}: HEAD^: updating HEAD
33hff22 master@{2}: commit: does master commit ?
……
……
\<refname>@{\<n>},这个表达式的含义是引用\<refname>之前第\<n>次改变时的SHA1哈希值。
重置master为两次改变之前的值
$git reset --hard master@{2}
深入git reset
用法一:git reset [-q] [\<commit>] [--] \<paths>
用法二:git rest [--soft | --mixed | --hard | --merge | --keep] [-q] [\<commit>]
用法一不会重置引用,更不会改变工作区,而是用指定提交状态(\<commit>)下的文件(\<paths>)替换掉暂存区中的文件。例如命令git reset HEAD \<path>相当于取消执行之前执行的git add \<paths>命令时改变的暂存区。
用法二则会重置引用。根据不同的选项,可以对暂存区或工作区进行重置。
使用参数 --hard,如:git reset --hard \<commit>.会执行
替换引用的指向。引用指向新的提交ID。
替换暂存区。替换后,暂存区的内容和引用指向的目录树一致。
替换工作区。替换后,工作区的内容变得和暂存区一致,也和HEAD所指向的目录树内容相同。
使用参数 --soft,如:git reset --soft \<commit>.会执行1。即只更改引用的指向,不改变暂存区和工作区。
使用参数 --mixed或不使用参数(默认为--mixed),如:git reset \<commit>.会执行1和2。即更改引用的指向及重置暂存区,但是不改变工作区。
命令 git reset
仅用HEAD所指向的目录树重置暂存区,工作区不会受到影响,相当于将之前的git add命令更新到暂存区的内容撤出暂存区。引用也未改变,因为引用重置到HEAD相当于没有重置。
命令 git reset HEAD
同上
命令 git reset -- filename
仅将文件filename的改动撤出暂存区,暂存区中的其他文件不改变。相当于对命令 git add filename的反向操作。
命令 git reset HEAD filename
同上
命令 git reset --soft HEAD^
工作区和暂存区不改变,但是引用向前回退一次。当对最新的提交说明或提交的更改不满意时,撤销最新的提交以便重新提交。
命令 git reset HEAD^
工作区不改变,但是暂存区会回退到上一次提交之前,引用也会回退一次。
命令 git reset --mixed HEAD^
同上
命令 git reset --hard HEAD^
彻底撤销最近的提交。引用回退到前一次,而且工作区和暂存区都会回退到上一次提交的状态。自上一次以来的提交全部丢失。
git checkout命令
命令:git checkout branch
检出branch分支。更新HEAD以指向branch分支,以及用branch指向的树更新暂存区和工作区。
命令:git checkout
汇总显示工作区、暂存区与HEAD的差异。
命令:git checkout HEAD
同上
命令:git checkout -- filename
用暂存区中filename文件来覆盖工作区中的filename文件。相当于取消自上次执行git add filename以来(如果执行过)的本地修改。这个命令很危险,因为对于本地的修改会悄无声息地覆盖,毫不留情。
命令:git checkout branch -- filename
维持HEAD的指向不变。用branch所指向的提交中的filename替换暂存区和工作区中相应文件。注意会将暂存区和工作区中的filename文件直接覆盖。
命令:git checkout -- . 或写作git checkout .
注意 git checkout 命令后的参数为一个点。这条命令最危险!会取消所有本地的修改(相对于暂存区)。相当于用暂存区的所有文件直接覆盖本地文件,不给用户任何确认的机会!
恢复进度
查看保存的进度
$git stash list
从最近保存的进度进行恢复
$git stash pop
删除本地多余的目录和文件
可以使用git clean命令。先来测试运行以便看看哪些文件和目录会被删除,以免造成误删。
$git clean -nd
真正开始强制删除多余的目录和文件
$git clean -fd
整个世界都清净了。
使用git stash
命令:git stash
保存当前的工作进度。会分别对暂存区和工作区的状态进行保存。
命令:git stash list
显示进度列表。此命令显然暗示了git stash可以多次保存工作进度,并且在恢复的时候进行选择。
命令:git stash pop [--index] [\<stash>]
如果不使用任何参数,会恢复最新保存的工作进度,并将恢复的工作进度从存储的工作列表中清除。如果提供\<stash>参数(来自git stash list显示的列表),则从该\<stash>中恢复。恢复完毕也将从进度列表中删除\<stash>。
选项--index除了恢复工作区的文件外,还尝试恢复暂存区。
本地删除
$ rm *.txt
执行这个命令,文件只是在本地进行了删除,尚未添加到暂存区。也就是说直接在工作区删除,对暂存区和版本库没有任何影响。
执行git rm 命令删除文件
$ git rm *.txt
$ git commit -m 'delete files'
命令git add -u 快速标记删除
当执行了rm *.txt后可以直接执行git add -u 命令将本地文件的变更(修改、删除)全部记录到暂存区中。
恢复删除的文件
执行下面的命令可以从历史(前一次提交)中恢复welcome.txt文件
$ git cat-file -p HEAD~1:welcome.txt > welcome.txt
也可以使用git show命令取代git cat-file -p命令,效果相同
$ git show HEAD~1:welcome.txt > welcome.txt
使用git checkout命令则最为简洁实用
$ git checkout HEAD~1 -- welcome.txt
移动文件
$ git mv welcome.txt README
使用git add -i 选择性添加
$ git add -i
当执行这个命令时会出现一个交互性界面,如图:
文件忽略
执行下面的命令可以在目录下创建一个名为.gitignore的文件,把要忽略的文件写在其中,文件名可以使用通配符。注意:第二行开头的右尖括号是cat命令的提示符,不是用户的输入。
$ cat > .gitignore << EOF
> hello
> *.o
> *.h
> EOF
文档归档
基于最新提交建立归档文件latest.zip
$ git archive -o latest.zip HEAD
只将某个目录建立到归档partial.tar中
$git archive -o partial.tar HEAD src
基于里程碑v1.0建立归档,并且为归档中的文件添加目录前缀1.0
$git archive --format=tar --prefix=1.0/ v1.0 | gzip > foo-1.0.tar.gz