Git的学习笔记
背景
Linux之父Linus是坚定的CVS反对者,他也两样地反对SVN。这就是为什么在1991- 2002这十余年间,Linus宁可以手工修补文件的方式维护代码,也迟迟不愿意使用CVS的原因。 我想在当时要想对说Linus使用CVS只有一个办法:把CVS服务器请进Linus的卧室, 并对外配以千兆带宽。
2002年到2005年,Linus顶着开源社区精英们口诛笔伐的压力,选择了一个商业版本控制系统BitKeeper 作为Linux内核的代码管理工具。BitKeper不同于CVS和SVN等集中式版本控制工具, 而是一款分布式版本控制系统工具。
分布式版本控制系统最大的反传统之处在于,可以不需要集中式的版本库, 每个人都工作在通过克隆建立在本地版本库中。也就是说每个人都拥有一个完整的版本库, 查看日志、提交、创建里程碑和分支、合并分支、回退等所有操作都直接在本地完成而不需要网络连接。 每个人都是本地版本库的主人,不再有谁能提交谁不能提交的限制, 加上多样的协同工作模型(版本库间推送、拉回、以及补丁文件的传送等)让开源项目的参与度有爆发式增长。
2005年发生的一件事最终导致了Git的诞生。在2005年4月,Andrew Tridgell(即大名鼎鼎的Samba的作者) 试图对BitKeeper进行反向工程,以开发一个能与BigKeeper交互的开源工具。 这激怒了BitKeeper软件的所有者BitMover公司,要求收回对Linux社区免费使用BitKeeper的授权。迫不得已, Linus选择了自己开发一个分布式版本控制工具以替代BitKeeper。以是Git诞生过程中的大事记:
- 2005年4月3日,开始开发Git。
- 2005年4月6日,项目发布。
- 2005年4月7日,Git就可以作为自身的版本控制工具了。
- 2005年4月18日,发生第一个多分合并。
- 2005年6月16日,Linux内核2.6.12发布,那时Git已经在维护Linux内核源代码了。
Linus以一个文件系统专家和内核设计者的视角对Git进行了设计, 其独特的设计让Git拥有非凡的性能和最为优化的存储能力。完成原型设计后,在2005年7月26日, Linus功成身退,将Git的维护交给另外一个Git的主要贡献者Junio C Hamano,直到现在。
最初的Git除了一些核心的命令以外,其他的都用脚本语言开发,而且每个功能作为一个独立的命令, 例如克隆操作用git-clone,提交操作用git-commit。这导致Git拥有庞大的命令集, 使用习惯也和其他版本控制系统格格不入。随着Git的开发者和使用者的增加,Git也在逐渐演变, 例如到1.5.4版本时,将一百多个独立的命令封装为一个git命令,使它看起来更像一个独立的工具, 也使Git更贴近于普通用户的使用习惯。
经过短短几年的发展,众多的开源项目都纷纷从SVN或其他版本控制系统迁移到Git。 虽然版本控制系统的迁移过程是痛苦的,但是因为迁移到Git会带来开发效率的极大提升, 以及巨大的效益,所以很快就会忘记迁移的痛苦过程,而且很快就会适应新的工作模式。 在Git的官方网站上列出了几个使用Git的重量级项目,每一个都是人们耳熟能详的, 除了Git和Linux内核外,还有Perl,Eclipse、Gnome、KDE、Qt、Ruby on Rails、Android、 PostgreSQL、Debian、Z.org,当然还有GigHub的上百万个项目。
Git虽然是在Linux下开发的,但现在已经可以跨平台运行在所有主流的操作系统上, 包括Linux、Mac OS X和Windows等。可以说每一个使用计算机的用户都可以分享Git带来的便利和快乐。
git配置
- $ git config –global user.name “your name”
配置你的用户名 - $ git config –global user.email you@example.com
配置你的邮箱 - $ git config –global alias.ci “commit -s” 当使用git ci时,会自动带上-s参数,这样会在提交说明中自动添加上包含提交者的姓名和邮箱地址的签名标识。
- $ git config –system xxx
配置系统级别的信息
克隆
- $ git clone url
theurl
sometimes likehttps://github.com/username/repository.git
保存工作进度
- $ git stash
git stash会保存工作区和暂存区的内容,然后会重置工作区和暂存区的内容,相当于执行了git reset –hard HEAD - $ git stash [ save [–patch] [-k]–[no-]keep-index] [ -p | –quiet] [<message>]
git stash的完整版本,如果需要在保存进度时指定版本,必须使用如下格式:
git stash save “message …”
– 使用参数–patch会显示工作区和HEAD的差异,通过编辑差异文件可以最终确定要保存的文件。
– 使用-k 或者–keep-index参数,在保存进度时,不会将暂存区重置。 默认会将暂存区和工作区强制重置。 - $ git stash apply [–index] [<stash>] 除了不删除恢复的进度之外,其余和git stash pop一样。
- $ git stash drop [<stash>]
删除一个存储的进度。默认删除最新的进度。 - $ git stash clear
删除所有存储的进度 -
$ git stash brance <branchname> <stash> 基于进度创建分支。
- $ git checkout <new_branch> 新的工作分支修改完毕后,再切换回当前分支,调用git stash pop命令则可恢复之前保存的工作进度
- $ git stash
- $ git checkout <new_branch>
保存当前分支的工作进度,然后切换到新的分支, - $ git checkout <orignal_branch>
- $ git stash pop
当新的工作分支修改完毕后,再切换回当前分支,调用git stash pop命令则可恢复之前保存的工作进度
更新
- $ git fetch
如果本地已经克隆过一个Git项目的版本库,直接在工作区中更新,以获得最新版的Git。
清理
- $ git clean -fdx
- $ git reset –hard
执行清理工作,避免前一次的编译的遗留文件对编译造成影响。注意,该操作会丢弃本地对Git代码的改动。
里程碑
- $ git tag
- $ v1.7.4.1
查看Git的里程碑,选择最新的版本进行安装,例如v1.7.4.1
检出
- $ git checkout v1.7.4.1
检出该版本的代码
检出代码默认是针对暂存区的,即checkout [–] <file>会用暂存区覆盖工作区, checkout HEAD会检查当前HEAD与远程仓库间在差异,但是checkout HEAD .会用版本库的文件覆盖暂存区和工作区的文件。 checkout <branch>会切换分支,并更新暂存区和工作区。 checkout <commit>会使当前处于头分离模式,即当前不属于任何版本。
重置
- $ git reset
重置是相对于当前分支的,即git reset 与git reset HEAD相同,与git reset HEAD –mixed git reset有两种方式: - git reset [<commit>] <file>
第一种方式不会重置引用,也不会改变工作区,而是用指定提交状态(<commit>)下的文件(<file>)替换掉暂存区的文件。 例如命令:git reset HEAD <file>相当于取消git add <file>命令改变的暂存区。 - git reset –soft | –mixed | –merge | –hard <commit>
第二种命令有好几种方式,git reset HEAD 等于 git reset HEAD –mixed因为 –mixed是默认的, 它会重置引用以及重置暂存区,–soft只会重置引用,–hard会重置引用、重置暂存区以及重置工作区。 - merge会进入合并界面
修改上一次提交
- $ git commit -amend
查看差异
- $ git diff
详细地列出工作区代码和暂存区代码的区别 - $ git diff HEAD
详细地列出工作区代码和版本库代码的区别 - $ git diff –cached 或者 $ git diff –state
可以查看暂存区与版本库代码的区别 -
$ git status
列出本地与暂存区的,暂存区与远程仓库代码的区别 -
$ git add .
将所有本地的改动(包括新增和修改)都同步到暂存区 -
$ git reset
取消所有暂存区的改动 - $ git reset file
取消暂存区中file的改动
原理探索
.git/index文件是用来跟踪工作区文件的,文件.git/index实际上就是一个包含文件索引的目录树,像是一个虚拟的工作区。 在这个虚拟工作区的目录树中,记录了文件名和文件状态信息(时间戳和文件长度等)。 文件内容并没有存储在其中,而是保存在Git的对象库.git/Object目录中, 文件索引建立了文件和对象库中对象实体之间的对应。