前言
Git是一款免费、开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。
分布式相比于集中式的最大区别在于开发者可以提交到本地,每个开发者机器上都是一个完整的数据库,所以公共服务器压力和数据量都不会太大。并且它速度快、灵活,任意两个开发者之间可以很容易的解决冲突。并且可以快速新建及切换分支,重置任意文件或文件夹到某个历史版本,把以对于突发需求能更做到更快更好的响应,对敏捷开发尤其方便。
本文将对git的使用进行流程化的介绍,如果你只是想查看相关命令,可以移步Git 参考手册,本文部分内容摘自该手册。
Git的配置
配置用户名:git config --global user.name "YOUR NAME"
配置邮箱:git config --global user.email "YOUR EMAIL ADDRESS"
当你在本机配置好用户名和邮箱后,以后你在本机的所有git提交,都会以你设置的用户名和邮箱进行签名。
获取与创建项目
拥有一个 Git 仓库的途径有两种:
- 在已有的目录中,初始化一个新的.比如一个新的项目,或者一个已存在的项目,但该项目尚未有版本控制。
- 仓库克隆.如果你想要复制一份别人的项目, 或者与别人合作某个项目,也可以从一个公开的 Git 仓库克隆。
git clone 复制一个 Git 仓库
如果你需要与他人合作一个项目,或者想要复制一个项目,看看代码,你就可以克隆那个项目。 执行:git clone [GIT_REPOSITORY_URL]
进行克隆,如https://github.com/defei/codelogger-utils.git
如果该项目需要进行身份授权验证,你可能需要输入用户名及密码。推荐的方式是使用ssh key进行身份授权验证。
上述操作将复制该项目的全部记录,让你本地拥有这些。并且该操作将拷贝该项目的主分支, 使你能够查看代码,或编辑、修改。进到该目录中,你会看到 .git 子目录。 所有的项目数据都存在那里。
git init 将一个目录初始化为 Git 仓库
如果你还没有git项目,可以进行git init
来新建及初始化项目:
Git的版本管理
Git 的工作就是创建和保存你的项目的快照及与之后的快照进行对比,在此我们将这个快照称作版本。
Summary:使用
git add
添加需要追踪的新文件和待提交的更改, 然后使用git status
和git diff
查看有何改动, 最后用git commit
将你的快照记录。这就是你要用的基本流程,绝大部分时候都是这样的。
#####git add 添加文件到缓存
在 Git 中,在提交你修改的文件之前,你需要把它们添加到缓存,只有在缓存中的文件才会在commit的时候添加到版本管理中去。
命令说明:git add [target]
target可以是单个文件,或该git仓库中的任意目录中的所有文件。
假设当前git仓库中有如下文件结构:
.
|-- hello.md
`-- resources
|-- hello.app
`-- hello.jpg
1 directory, 3 files
则有如下几种操作方法:
git add .
:表示将当前目录下的所有文件及文件夹加入到git缓存中去。git add hello.md
:表示只将hello.md这个文件添加到git缓存中去。git add resources
:表示只将resources文件夹添加到git缓存中去。git add resources/hello.app
:表示只将resources目录下的hello.app添加到git缓存中去。
如果要一次添加多个文件或文件夹,可以用空格分开,如:git add hello.md resources
,这个命令会把hello.md和resources都添加到git缓存中去。
git status 查看你的文件在工作目录与缓存的状态
执行 git status
命令可查看从你上次提交之后当前git仓库中文件的状态,查看文件的增删改情况,以决定是否需要进行版本提交。
git status
会列出完整的变更信息及git操作提示。如果你已经非常熟练的知道git操作,可以用git status -s
来简化输出信息。
git diff 显示已缓存与已修改但未缓存的改动的区别
git diff
命命用于检查版本之间的数据变动,常用命令如下:
git diff [FILE | DIRECTORY]
:显示当前工程中,指定的file或directory与已经缓存版本的区别,如果已提交的文件没有使用git add添加到缓存中,则该文件会与前一个版本做比较。git diff --cached [FILE | DIRECTORY]
:显示已添加到缓存中的文件与前一个版本的区别。git diff [HEAD | COMMIT-HASH]
:显示当前git仓库中所有文件与指定版本之间的所有更改,HEAD表示上一次提交的版本,不区分大小写。git diff --stat
:如果我们不想要看整个 diff 输出,但是又想比 git status 详细点, 就可以用 –stat 选项。该选项使它显示摘要而非全文。git diff [COMMIT-HASH] [COMMIT-HASH]
显示两个版本之前的所有差异。
git commit 提交一个版本
当我们已经用git add
添加了要提交的文件,并且通过git diff
确认你的提交无误后,就可以用git commit
来进行版本提交了。
如果只使用
git commit
来提交,会打开本机的默认文本编辑器,让你输入本次提交的说明信息,如果你不想使用文本编辑器来输入,可以使用git commit -m 'commit informations'
来快速设置本次提交的说明信息。
如果你觉得提交流程太过繁锁,可以使用git commit -a
来提交已受版本管理的所有提交,包括对文件的删除及重命名,不过该操作不适用于新加文件。对于新建的文件,因为没有受版本管理,所以还是需要用到git add
来添加到缓存中来提交。
git reset 重置版本信息
如果你想放弃本次更改或快速清除提交到缓存中的信息,就可以用到git reset
命令了,常用命令如下:
git reset [HEAD | COMMIT-HASH]
:清除当前缓存中的所有信息,相当于你从上次提交(HEAD)或指定版本(COMMIT-HASH)后,没有执行过git add
或git rm
操作。git reset [HEAD | COMMIT-HASH] --hard
:强制恢复到指定版本,并清除所有更改。注意,该操作不可恢复,所以除非你非常确定不保留任何更改信息,不然尽量少用–hard参数。
git rm 将文件从版本控制中移除
git rm [FILE | DIRECTORY]
会将条目从版本控制中移除。这与 git reset HEAD
将条目取消缓存是有区别的。 “取消缓存”的意思就是将缓存区恢复为我们做出修改之前的样子。 在另一方面,git rm
则将该文件彻底从版本控制中踢出。
如果你只想删除该文件的版本控制,但保留该文件,可用git rm --cached [FILE | DIRECTORY]
进行移除版本控制操作。
git mv 移动被版本控制的文件
不像绝大多数其他版本控制系统,Git 并不记录记录文件重命名。它反而只记录版本提交,并对比版本提交以找到有啥文件可能被重命名了。 如果一个文件从更新中删除了,而在下次版本提交中新添加的另一个文件的内容与它很相似,Git 就知道这极有可能是个重命名。 因此,虽然有 git mv
命令,但它做得所有事情就是 git rm --cached
, 重命名磁盘上的文件,然后再执行 git add
把新文件添加到缓存区。
分支与合并
分支Git的精华所在,你可以用git branch [branch name]
在不同的分支之间来回切换,然你在一条主线上做开发,但有bug需要马上处理的时候,它就能发挥用处了。
大致流程就是:你可以执行 git branch (branch-name) 来创建分支, 使用 git checkout (branch-name) 命令切换到该分支,在该分支的上下文环境中, 提交版本等,之后可以很容易地来回切换。当你切换分支的时候,Git 会用该分支的最后提交的版本替换你的工作目录的内容, 所以多个分支不需要多个目录。使用 git merge 来合并分支。你可以多次合并到统一分支, 也可以选择在合并之后直接删除被并入的分支。
git branch 列出、创建与管理分支
git branch
可以查看及管理当前git仓库中的分支,常用命令如下:
git branch [-a]
:列出本地仓库的所有分支,如果加上-a则会列出本地及远程的所有分支情况。你所在的分支前会以’*’号进行标记。git branch [branch-name]
: 创建新分支。新创建的分支停留在你最后一次提交的版本,并拥有你当前分支的所有版本信息。在创建分支成功以后,你在当前分支做的所有更改,并不会影响已创建的分支。git branch -d [branch-name]
:删除本地分支。
使用
git checkout -b [branch-name]
可以快速创建并切换到分支。
git checkout 检出文件/切换分支
git checkout [branch-name]
:切换分支到给定的分支。git checkout [FILE | DIRECTORY]
:重置指定的文件或文件夹到最后一次提交的版本。
如果你有一个文件和分支名相同的时候,checkout只能用于重置文件,并且只能使用命名
git checkout -- [FILE | DIRECTORY]
。
git stash临时缓存所有更改
git stash
可以将当前git仓库下新的更改放入git的临时工作目录下,以方便快速切换到其它工作上去。git stash pop
可以取出前一次stash的所有更改.
git stash是以栈(stack)模式工作的,也就是遵循后进先出的原则,你可以进行多次stash及stash pop。
git merge 合并分支
一旦某分支完成了新的功能开发并且测试充分,你可以使用 git merge [branch-name]
命令将任何分支合并到当前分支中去。
只要没有多个人员同时更改同一个文件中的同一块代码区域,一般就不会出现版本冲突,包括并不限于内容的理发,重命名,位置移动,删除等操作。
在自动合并完成后,git会自动提交一个版本信息,标明该合并信息。
如果合并中出现冲突,git会给出下的提示信息:
$ git merge test
Auto-merging test
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
$ cat README.md
<<<<<<< HEAD
version 1.0.0
=======
version 1.0.1
>>>>>>> test
提示README.md有冲突,需要你手动解决冲突。”<<<<<<< HEAD” 到 “=======” 之间的代码是你当前分支的内容,”=======” 到 “>>>>>>> test” 之间的内容是合并的分支的内容,你可以根据你的情况删除不需要的内容(包括”<<<<<<< HEAD” , “=======” 和 “>>>>>>> test”),使用git add
添加到缓存,并git commit
提交这次合并。
到此,你已经将要全并的分支合并到当前分支了,如果被合并的分支已经没有用了,可以用`git branch -d [branch-name]’删除。
git log显示一个分支中提交的版本更改记录
git log
可以查看当前分支中以提交时间倒序排列的所有版本信息,常用命令如下:
git log
:显示完整的版本提交信息,包括版本hash值,提交者及邮件,提交日期,提交说明。git log --oneline
:提示版本提交的简要信息,包括版本hash的前7位及提交说明。一般情况下,版本hash的前7位已经足以定位一个版本,所以我们可以只用这7位值进行版本操作,比如git reset dd574cc
。git log --graph
:开启了拓扑图显示。
使用
git log --oneline --graph
可以更清楚明了地看到何时工作分叉、又何时归并。 这对查看发生了什么、应用了什么改变很有帮助,并且极大地帮助你管理你的分支。
在git log视图中,可以按’h’键打开帮助界面,获取更多信息。其实操作的vim几乎一样,如 ‘b’:上一页, ‘f’:下一页, ‘/RegExp’:按正则表达示查找.
git tag 给一个里程碑打上标签
如果你的项目已经达到一个里程碑阶段,并希望永远记住这个版本,你可以使用 git tag
给它打上标签。 通常,你会在切取一个发布版本或者交付一些东西的时候打个标签,如:
git tag -a "v1.0.0" [COMMIT-HASH]
- “v1.0.0”:是当前标签的值
- -a:“创建一个带注解的标签”,从而使你为标签添加注解。不用 -a 选项也可以执行的,但它不会记录这标签是什么时候打的,谁打的,也不会让你添加个标签的注解,我并不推荐这样操作。
- [COMMIT-HASH]:指定提交版本的hash值,如果不全,默认为最后一次提交。
如果你想要查看tag信息,可以使用git log --decorate
来进行查看。
分享与更新
Git 并不像 Subversion 那样有个中心服务器。你自己本身就是一个git服务器,并且你可以添加多个远程服务器,进行代码的提交及合并。
简要流程就是,使用 git fetch
更新你的项目,使用 git push
分享你的改动。 你可以用 git remote
管理你的远程仓库。
git remote 显示和管理远端仓库
不像中心化的版本控制系统(客户端与服务端很不一样),Git 仓库基本上都是一致的,并且并可以同步他们,这使得当前仓库可以拥有多个远端仓库。
常用命令列表:
git remote [-a]
:列出所有远端仓库,加上-a则会显示出具体的仓库地址,否则只显示仓库别名。git remote add [alias] [url]
:如果你想要以任何方式与一个新仓库沟通,最简单的方式通常就是把它添加为一个远端仓库。比如,我们在在本地新建一个codelogger-utils的文件夹mkdir codelogger-utils && cd codelogger-utils
,执行git init
以初史化仓库,并执行git remote add origin https://github.com/defei/codelogger-utils.git
以添加一个origin远程仓库,再执行’git pull origin master’就可以把远程仓库的master分支pull下来了。git remote rm [alias]
:删除远程仓库别名。注意,该操作只会删除本地远程仓库的信息,但远程仓库还是存在的,并不会被删除。
git fetch从远端仓库下载新分支与数据
git fetch [remote-alias]
会使你与另一仓库同步,提取你本地所没有的数据,为你在同步时的该远端的每一分支提供书签。 这些分支被叫做“远端分支”,你可以将它们合并到当前分支,与其他分支作比较差异,查看那些分支的历史日志,等等。
git pull从远端仓库提取数据并尝试合并到当前分支
git pull [remote-alias] [branch]
,该命令就是在 git fetch 之后紧接着 git merge 远端分支到你所在的任意分支。
git push 推送你的分支数据到远端仓库
git push [remote-alias] [branch]
,就会将你的 [branch] 分支推送到 [alias] 远端上的 [branch] 分支。
当你试图推送到某个以被更新的远端分支时,会出现下面这种情况:
$ git push origin master
To https://github.com/defei/codelogger-utils.git
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to 'https://github.com/defei/codelogger-utils.git'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again. See the 'Note about
fast-forwards' section of 'git push --help' for details.
你可以执行git pull origin master
以获取并合并无端的数据,当合并成功后,你就可以执行git push origin master
把你本地数据提交到远程仓库了。
后记
到此,git的基本操作已经全部介绍完了,git与Subversion等仓库还是有很大的不同的,其去中心化与branch是其精华所在,能够快速的做到版本切换,离线提交等快,大大提高工作效率。
希望本文对你有所帮助。

