在项目开发过程中,总是免不了使用版本管理工具。否则可能经常出现 HBO 出版的电视剧《硅谷(Silicon Valley)》中出现的 Pied Piper 的底层代码被全部改写后需要作者一行一行测试进行“还原”的尴尬场景。版本管理工具中,比较流行的有git、svn等。本人使用的是git。从刚接触 git 开始,本人就喜欢上了这个工具,原因除了对 Git 作者 Linus Towards 的崇拜以外,更重要的是第一次使用版本管理工具,发现了此类工具对文档管理的重大意义,以及 Git 工具本身的强大。
Git 相关的书中,《Git 权威指南》讲得比较全,除了基本的 git 命令,该书还讲了很多比较高级的 Git 使用场景。本文是本人在学习和工作过程中使用 git 的一些经验记录,并会随着使用 Git 越来越熟练和深入而不定期持续更新。
使用Git进行团队开发的简要流程如【图1】所示。
对于一个使用 Git 进行版本管理的项目,其开发人员可以分为两种:项目发起人和项目参与者。对于项目发起人而言,要开始使用 Git 进行自己项目的管理,需要初始化一个 Git 版本库。该命令为:
git init [-q | --quiet] [--bare] [--template=] [--separate-git-dir] [--shared[=]] [directory]
本人常用情况有:
1.在本地对已有项目进行版本管理。具体的操作为:命令行进入项目的根目录(cd /x/y/z);Git 初始化(git init)。此时,/x/y/z目录下会生成一个.git目录,用于存放 Git 的相关配置和版本管理历史。
2.在云主机上搭建简易的 Git 库。具体的操作为:(省略 添加git用户、git用户的默认bash设置、Git 库根目录的权限设置 等步骤)命令行进入作为 Git 库的目录(cd /x/y/z);Git 初始化(git init --bare xxx.git)。此时,/x/y/z目录下会生成一个xxx.git目录,该目录下为 branches、 config、 description、 HEAD、 hooks、info、objects、refs 等文件和目录。
以上两种使用方法的主要区别在于第2种只保存历史提交信息,而不保存项目文件本身(适合用作远程仓库),而第1种既保存历史提交信息,也保存项目文件(常用于个人文档管理或者之后将其提交到远程仓库中)。
如果是团队项目,其他开发人员要参与进来时,需要先从远程仓库克隆项目到本地。该命令为:
git clone [--template=] [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror] [-o] [-b] [-u] [--reference] [--dissociate] [--separate-git-dir] [--depth] [--[no-]single-branch] [--no-tags] [--recurse-submodules] [--[no-]shallow-submodules] [--jobs ] [--]
参数很多,常用的是克隆整个项目(默认master分支)到本地:git clone
在本地修改了一些文件并且测试通过后(对于程序来说),需要把代码上传到远程库。经常涉及到的操作有:
1.git status
查看本地文件的修改情况,包括已经被git跟踪的文件(被修改、删除、重命名、移动位置)和未被跟踪的文件(新增文件)。
所有可选操作为:
git status [
2.git diff
比较两个版本之间的差异。直接使用【git diff】时,比较的是工作目录(work tree)与暂存区(之前用git add 添加过修改,但未提交时)或者工作目录与上一次提交(暂存区为空,即上一次提交之后未使用git add 添加修改)之间的差异。
根据不同的参数,还可以:
1)直接比较工作目录与上一次提交的差异:【git diff HEAD】。其中HEAD经过^或者~号修饰还可以表示父提交(如HEAD~1和HEAD^1都表示“上上次”提交),每往前一个提交,修饰的数字加1。
2)比较两个分支间的差异:【git diff branch1 branch2】。若比较当前分支与其他分支的差异,则可简化为 【git diff another_branch】
3)比较再次提交之间的差异:【git diff commit_hash_1 commit_hash_2】,其中提交使用各自hash码全码或者开始的前几位(hash码保留部分能与其他提交的hash码区分即可)
所有可选操作为:
git diff [options] [
git diff [options] --cached [
git diff [options]
git diff [options]
git diff [options] [--no-index] [--]
3.git add
常用的搭配为 【git add .(添加当前目录下所有的改动文件到暂存区)】、【git add FILEPATH [...] (添加指定文件到暂存区)】和【git add EXPRESSION(添加匹配正则的文件到暂存区)】。
所有可选操作为:
git add[--verbose | -v] [--dry-run | -n] [--force | -f] [--interactive | -i] [--patch | -p] [--edit | -e] [--[no-]all | --[no-]ignore-removal | [--update | -u]] [--intent-to-add | -N] [--refresh] [--ignore-errors] [--ignore-missing] [--chmod=(+|-)x] [--] [
4.git commit
常用的搭配为【git commit -m
所有可选操作为:
git commit [-a | --interactive | --patch] [-s] [-v] [-u
[--dry-run] [(-c | -C | --fixup | --squash)
[-F
[--allow-empty-message] [--no-verify] [-e] [--author=
[--date=
[-i | -o] [-S[
5. git pull
常用搭配为【git pull remote branch】,用于拉取远程库remote的branch分支到本地,并与当前分支合并。这一步在提交本地修改到远程库之前很重要。因为如果远程分支没有加保护机制,本地提交的内容会覆盖其他开发人员提交的修改(具体为远程分支与本地分支最近的相同提交以后的其他提交会被覆盖)。
所有可选操作为:
git pull [options] [ [...]]
6.git push
常用搭配为【git push remote branch】,用于把本地branch分支上的修改推送到remote远程库的branch分支上。
所有可选操作为:
git push [--all | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=]
[--repo=
[-u | --set-upstream]
[--[no-]signed|--sign=(true|false|if-asked)]
[--force-with-lease[=
[--no-verify] [
7.git branch
创建新分支。如【git branch branchB】,表示从当前分支的最新提交处新建一个分支brachB。
所有可选操作为:
git branch [--color[=
[--column[=
[(--merged | --no-merged | --contains) [
[--points-at
git branch [--set-upstream | --track | --no-track] [-l] [-f]
git branch (--set-upstream-to=
git branch --unset-upstream [
git branch (-m | -M) [
git branch (-d | -D) [-r]
git branch (-d | -D) [-r]
git branch --edit-description [
8.git checkout
切换分支或者重置工作区文件。
git checkout branchName:切换到branchName分支
git checkout -b branchName:等价于git branch branchName ,git checkout branchName,即创建并切换到branchName分支
git checkout file1 file2 ...:重置(丢弃未暂存的)工作区文件
所有可选操作为:
git checkout [-q] [-f] [-m] [
git checkout [-q] [-f] [-m] --detach [
git checkout [-q] [-f] [-m] [--detach]
git checkout [-q] [-f] [-m] [[-b|-B|--orphan]
git checkout [-f|--ours|--theirs|-m|--conflict=