随着软件工程的发展,开发者之间的合作开发变得越来越重要,为了解决不同开发者之间的协同开发问题,集中化的版本控制系统(CVCS,Centralized Version Control System)应运而生。
CVCS 固然提高了软件开发的效率,但是其也有一些缺陷。如果网络发生异常,或者中央服务器宕机,那么,开发人员就不能提交或更新数据了。并且,严重情况下,可能造成数据的丢失。所以,分布式的版本控制系统(DVCS,Distributed Version Control System)问世。
Git 简介
Git 就是分布式版本管理系统的一种,但不同于其他版本管理系统,其不是保存每个变更文件的差异,而是对所有的文件保存一次快照。这些保存在数据库中的快照数据都是以文件内容生成的哈希值,该值由 SHA-1
函数计算得到,能够保证数据的完整性,同时可知,对于未发生变化的文件,其哈希索引值是不变的,所以每个版本做一次快照保存并不意味着将所有的文件数据重复保存,它们的文件索引值都指向一份文件数据。
在 Git 中有三种状态,已修改,已暂存,已提交。
- 已修改,表示工作目录中的文件发生了变更,但是并没有保存到暂存区或数据库中。
- 已暂存,表示已修改的文件保存到了暂存区,并且其会在下一次提交时,保存到数据库中。
- 已提交,表示暂存区中的数据已经保存到了数据库中。
Git 基本命令
git config
在 Git 中,可以自定义一些配置,这些配置可以是针对所有用户的,也可以只针对当前用户,同样,可以只作用于当前版本库。
–system 作用于所有用户的配置,配置一般保存在 /etc/.gitconfig 文件中
–global 作用于当前用户的配置,配置一般保存在 ~/.gitconfig 文件中
–local 作用于当前仓库的配置,配置一般保存在仓库的 .git/config 文件中,该选项为默认选项
如设置一些别名来简化命令:
1
2
3$git config --global alias.st status
$git config --global alias.unstage 'reset HEAD --'
$git config --global alias.list '!ls -la'
> 作用范围小的配置会覆盖作用范围大的配置
git init
将当前目录初始化为一个版本管理库
git clone
克隆远程仓库到本地
git status
查看当前仓库的状态
git diff
查看工作目录中的文件同暂存区中文件的区别,使用
--staged
或--cached
选项则可以查看暂存区同最后一次提交的文件区别。git add
将修改的文件加入到暂存区,该命令除了可以添加新文件和被改动的文件,还可以表示冲突文件已经修改完毕。
git commit
提交已暂存的数据,执行该命令时,会打开编辑器要求输入提交注释,如果不添加注释,则无法提交成功。
使用
-m
选项可以直接添加注释,另外,使用-am
选项可以将添加和提交合为一个操作。另外,
--amend
选项可以用来修改最后一次提交,表面上看,似乎似将当前暂存区中的修改追加到了最后一次提交上。git reset
撤销提交,或者取消暂存区中的修改。
git checkout
取消工作目录下的修改,其实质是拷贝了暂存区中的文件来覆盖工作目录下修改的文件,所以该命令会造成数据的不可追溯,应慎用。
git rm
将指定文件从 git 的工作目录中删除,并且 git 仓库也不会再对该文件进行跟踪,如果暂存区中存在该文件,那么说明该文件被修改了且未提交,此时删除文件会造成修改的永远丢失,所以应先进行提交,当然,也可以使用
-f
选项强制删除。使用
--cached
选项可以将指定文件从仓库即暂存区中删除,但是该文件仍然保留在工作目录下,例如,当想要移除某些跟踪的文件,但想将其保留在工作目录下,便可以使用该命令,而后将文件加入的忽略配置文件中。git mv
移动文件,使用该命令可以对文件进行重命名。
git log
查看提交历史,使用一些选项,可以帮助日志的查看。
1
2
3
4
5
6
7
8//显示出每次提交的差异
$git log -p
//显示出最近指定条数的提交
$git log -3
//显示分支图形
$git log --pretty=format:"%an" --graph
在使用这些命令时,需要查看命令帮助,查看方式有很多种,以 git log 为例,可使用下面的方式查看帮助:
$man git-log
$git log –help
$git help log
$git help git-log
还可以用下面的命令将帮助手册转为 PDF 文档进行查看:
$man -t git-log | open -a Preview -f
变基
除了 git merge
命令外,使用 git rebase
也可以合并分支,这种合并方式实际是将一个分支上的提交移动到另外一个分支上。
如要将 dev 分支上的新增提交移动到 master 分支上,可执行下面的命令:
1 | $git checkout dev |
在进行变基前,要先处于待移动分支上,但是也可以直接指定两个分支,从而不必进行分支的切换。
1 | $git rebase master dev |
在变基的过程中,若发生冲突,则先解决冲突并将其添加到暂存区,但是不能进行提交,而是应执行继续变基命令,再进行快速合并。
1 | $git rebase --continue |
另外,其有一个 --onto
选项可以用来变基分支的分支,如,A 分支有一个 B 分支,而 B 分支有一个 C 分支,现在只是想将 C 分支变基到 A 分支,那么可以执行下面的命令:
1 | $git rebase --onto A B C |
该命令会寻找 B 分支和 C 分支的最近的共同祖先,而后将其在 C 分支上的所有修改变基到 A 分支上。
使用这个命令可以选择性的删除中间提交,假设在 dev 分支上有连续 3 个提交,现在想移除中间的 commit-B 提交:
1 | [base-commit] <- [commit-A] <- [commit-B] <- [commit-C] <- dev |
第一步,基于 commit-B 提交和 commit-C 提交创建两个分支 branch-B 和 branch-C :
1 | $git checkout branch-B commit-B |
$git reset commit-A
[base-commit] <- [commit-A] <- [commit-B] <- [commit-C]
^ ^ ^
| | |
dev branch_B branch_C
1 |
|
$git rebase –onto dev branch-B branch-C
[commit-C] <- branch_C
|
∨
[base-commit] <- [commit-A] <- [commit-B]
^ ^
| |
dev branch_B
1 |
|
$git merge branch-C
$git branch -d branch-B
$git branch -d branch-C
[base-commit] <- [commit-A] <- [commit-C] <- dev