1 创建 git仓库
1.1 从现有工作目录中初始化新仓库
需要到你需要用git管理的项目中输入以下命令:
1 | git init |
便会创建一个空的git项目,并且当前目录下会出现一个名为 .git 的目录, Git 需要的数据和资源都存放在这个目录中,不过我们目前只是初始化所有的文件与目录
- 告诉 git在这个目录中有几个文件需要版本控制。我使用了几个cpp的文件
1 | git add *.cpp |
还可以:
1 | git add README |
1 | git commit -m 'initial project version' |
你已经得到了一个实际维护着若干文件的 Git 仓库。
1.2 从现有仓库克隆
克隆某个开源项目的git仓库,可以使用 git clone 命令
例如克隆一份Ruby语言的 Git 代码仓库 ticgit可以使用下面的命令
1 | git clone git@github.com:schacon/ticgit.git |
这表示在当前文件夹下新建一个ticgit,其中包含一个 .git 的文件夹,用于保存下载下来的所有版本记录,然后从中取出最新版本的文件拷贝。
修改克隆的名字
1 | git clone git@github.com:schacon/ticgit.git myticgit |
结果如下:

在克隆的时候,我们可以选择不同的数据传输协议,在我们的例子中选择的是 ssh传输协议,你还可以有https://开头或者user@server:/path.git传输协议

2. 记录仓库更新
当我们创建了git存储库后,我们便可以在工作目录对这写文件进行更新。
在工作目录中的文件无非有两种状态:
- 已跟踪:已跟踪的文件是指本来就被纳入版本控制管理的文件,在上次快照中有它们的记录,工作一段时间后,它们的状态可能是未更新,已修改或者已放入暂存区。在克隆获取库后,工作目录的所有文件都是已跟踪的。
- 未跟踪:其他所有的文件都是未跟踪的,即他们既没有快照,也没有放入暂存区。在修改后 git才会把他们表示为已修改的,然后放到暂存区准备提交更新。
2.1 查看跟踪状态
输入下面的命令来查看当前工作目录的文件处于什么状态
1 | git status |
出现的情况:
- 当前工作目录很干净,所有已跟踪文件在上次提交后都未被更改过。
1 | git status |
- 现在让我们修改一下,比如添加一个文件(注意:需要在git克隆的仓库内执行)
1 | vim README |
然后随便输入一些内容保存退出。
1 | git status |
会出现:Untracked files ,即未跟踪状态
1 | Untracked files: |
表示我们的README 处于Untracked files即未跟踪状态
未跟踪的文件意味着Git在之前的快照(提交)中没有这些文件;Git 不会自动将之纳入跟踪范围,除非你明明白白地告诉它“我需要跟踪该文件”,因而不用担心把临时文件什么的也归入版本管理。
2.2 跟踪新文件
跟踪我们上面新建的 README文件:
1 | git add README |
当我们再次 git status,会发现它处于:
Changes to be committed,即未提交状态,它这时已经被跟踪了,但是没有提交。即处于暂存状态
1 | Changes to be committed: |
其实 git add 的作用就是将一个文件放入暂存区域中,并且把所有未跟踪的文件或者目录变为已跟踪状态。
这是个多功能命令,根据目标文件的状态不同,此命令的效果也不同:可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等这是个多功能命令,根据目标文件的状态不同,此命令的效果也不同:可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等
2.3 暂存已修改的文件
我们修改一个已经存在于历史版本的文件:README.mkd
忽略上面的内容,我们会看到这样的状态:Changes not staged for commit
1 | Changes not staged for commit: |
表示已经跟踪的文件发生了修改,但是还没有放在暂存区里。
要暂存这次更新,则需要执行git add(看上节关于git add的讲解)命令。
现在我们运行此命令把 README.mkd放到暂存区中:
1 | git add README.mkd |
再次status其状态得到:
1 | Changes to be committed: |
两个文件都被放在暂存区了,提交后便会被更新到仓库中
注意:如果此时你又想修改一个已经被放在暂存区的文件,则修改后会发现,出现了两个相同的文件,一个已跟踪并且放在暂存区,而另一个已跟踪未在暂存区。
1 | Changes to be committed: |
这是因为 git只会暂存 执行git add后的文件,因此此时需要重新 输入此命令
1 | git add README.mkd |
1 | Changes to be committed: |
2.4 忽略某些文件
我们不想让某些文件被纳入git的管理,即他们根本不用出现在未跟踪状态下
我们创建或者修改一下 .gitignore 文件即可
1 | vim .gitignore |
修改后,查看文件如下:
1 | $ cat .gitignore |
*.gem*.swp*.[oa]表示我们要忽略以 gem swp o a 等后缀的文件~表示 一些文件的副本,或者其他文件rdoc/表示的是一个 文件夹,因为它的末尾是 /
要养成一开始就设置好 .gitignore 文件的习惯,以免将来误提交这类无用的文件。(可以对一些模式取反,表示的就是忽略他们之外的文件或者目录)
2.5 查看已暂存或者未暂存的更新
查看具体修改了什么地方,可以使用下面的命令:
1 | git diff |
运行如下:
1 | diff --git a/README b/README |
前面的 + 号表示我们添改了这一行的内容,- 号则表示我们删改了一行信息
此命令比较的是工作目录中当前文件和暂存区域快照之间的差异,也就是修改了之后还没有暂存起来的变化
查看已经暂存的文件与上次提交的文件的差异:
首先把README先 放入暂存区
1 | git add README |
运行如下命令:即可查看
1 | git diff --cached |
简单总结:
git diff:查看某个文件还没有被暂存起来的改动,其实就是显示你当前修改了什么内容,与在暂存区的内容做比较。暂存前后的变化git diff --cached:查看某个文件已经被暂存和上一次提交时的文件的内容差异。已经暂存的变化
2.6 提交更新
首先检查有没有修改了但是没有被暂存的,因为提交只会提交暂存区的
检查:
1 | git status |
1 | git add xxx # 如果还存在未暂存的目标 |
检查完成后,输入提交命令:
1 | git commit |
这时就会出现一个文本编辑器,并且输入本次提交的说明
我的出现了 vscode,可以按照下列的命令进行修改默认哪个编辑器:
1 | git config --global core.editor xxxxx |
默认的提交信息包括最后一次git status显示的信息
如果觉得这还不够,可以用
-v选项将修改差异的每一行都包含到注释中来。
退出编辑器时,Git 会丢掉注释行,将说明内容和本次更新提交到仓库。
在空行输入提交信息:保存后退出
1 | learning git use |
接着就会提示你提交成功!并且显示当前是在哪个分支(master)提交的,本次提交的完整 SHA-1 校验和是什么(582f005),以及在本次提交中,有多少文件修订过,多少行添改和删改过。
1 | [master 582f005] learning git use |
提交时记录的是放在暂存区域的快照,任何还未暂存的仍然保持已修改状态,可以在下次提交时纳入版本管理。每一次运行提交操作,都是对你项目作一次快照,以后可以回到这个状态,或者进行比较。
使用 -m 快速添加提交信息
1 | git commit -m 我要学习 |
2.7 跳过暂存
使用下面的命令可以将修改的文件无需放入暂存区,即无需使用git add的命令,可以直接 提交。
修改了一个文件之后,执行下面的语句:
1 | git commit -a |
即在commit的时候添加一个 -a 2.
实现快速修改提交:
1 | git commit -a -m 跳过暂存 |
1 | [master 042500c] 跳过暂存 |
2.8 移除文件
从 Git 中移除某个不想要的文件,即从已经暂存的区域移除某个文件。
输入以下命令,来删除暂存区的文件,并且直接把它从工作目录中删除,连未跟踪区域都别留下。
1 | git rm xxx |
相当于直接删除这个文件
1 | Changes to be committed: |
如果要删除一个已经放在暂存区的文件,则必须强制删除,输入以下命令:
1 | git rm -f xxx |
只从暂存区删除,即删除跟踪,但是不删除其本身
1 | git rm --cached xxx |
此命令删除所有 log/ 目录下扩展名为 .log 的文件
1 | git rm log/\*.log |
删除当前目录及其子目录中所有 ~ 结尾的文件。
1 | git rm \*~ |
2.9 移动文件
我们想要把一个文件README.txt 改为 README ,可以使用下面的命令:
1 | git mv README.txt README |
mv 表示 把文件从README.txt 改为 README
实际上执行了三条语句是等价的:注意README.txt一定是在暂存区域内
1 | mv README.txt README |
- mv命令把README.txt 改为 README,但是此时README.txt仍在暂存区,并且README在未暂存区
- 删除暂存区的README.txt
- 把README放入暂存区
实际上 git mv file_from file_to 便可以表示这一过程,无需写三条
3. 查看提交历史
演示: 首先运行命令获取项目库
1 | git clone git://github.com/schacon/simplegit-progit.git |
在此项目中运行:
1 | git log |
会出现以下内容:
1 | commit ca82a6dff817ec66f44342007202690a93763949 (HEAD -> master, origin/master, origin/HEAD) |
git log 会按提交时间列出所有的更新,最近的更新排在最上面
每次更新都有一个 SHA-1 校验和,作者姓名电子邮箱,提交时间与提交说明
使用 -p 显示每次提交的内容差异 -2只显示最近两次:
1 | git log -p -2 |
使用--word-diff获取单词层面的变化
1 | git log -p --word-diff |
使用-stat 显示简要的增改行数统计
1 | git log --stat |
每个提交都列出了修改过的文件,以及其中添加和移除的行数,并在最后列出所有增减行数小计。
--pretty 可以指定使用完全不同于默认格式的方式展示提交历史
1 | git log --pretty=xxx |
xxx可以为:oneline,short,full,fuller
format 定制显示的格式,相当于debug
1 | git log --pretty=format:"%h - %an, %ar : %s" |
说明:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 选项 说明
%H 提交对象(commit)的完整哈希字串
%h 提交对象的简短哈希字串
%T 树对象(tree)的完整哈希字串
%t 树对象的简短哈希字串
%P 父对象(parent)的完整哈希字串
%p 父对象的简短哈希字串
%an 作者(author)的名字
%ae 作者的电子邮件地址
%ad 作者修订日期(可以用 -date= 选项定制格式)
%ar 作者修订日期,按多久以前的方式显示
%cn 提交者(committer)的名字
%ce 提交者的电子邮件地址
%cd 提交日期
%cr 提交日期,按多久以前的方式显示
%s 提交说明
log 的后面参数的其他选择
1
2
3
4
5
6
7
8
9
10
11
12 选项 说明
-p 按补丁格式显示每个更新之间的差异。
--word-diff 按 word diff 格式显示差异。
--stat 显示每次更新的文件修改统计信息。
--shortstat 只显示 --stat 中最后的行数修改添加移除统计。
--name-only 仅在提交信息后显示已修改的文件清单。
--name-status 显示新增、修改、删除的文件清单。
--abbrev-commit 仅显示 SHA-1 的前几个字符,而非所有的 40 个字符。
--relative-date 使用较短的相对时间显示(比如,“2 weeks ago”)。
--graph 显示 ASCII 图形表示的分支合并历史。
--pretty 使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和 format(后跟指定格式)。
--oneline `--pretty=oneline --abbrev-commit` 的简化用法
--since 和 --until 对时间作出限制
显示最近两周的提交:
1 | git log --since=2.weeks |
其他选择:
1
2
3
4
5
6 选项 说明
-(n) 仅显示最近的 n 条提交
--since, --after 仅显示指定时间之后的提交。
--until, --before 仅显示指定时间之前的提交。
--author 仅显示指定作者相关的提交。
--committer 仅显示指定提交者相关的提交。
4. 撤销操作
4.1 修改最后一次操作
如果在提交后,发现提交信息写错了,或者漏掉几个文件没有加,则可以这样修改:
1 | git commit --amend |
如果还没有暂存文件就提交了,则可以这样操作:
1 | git commit # 提交了 |
上面的三条命令最终只是产生一个提交,第二个提交命令修正了第一个的提交内容。
4.2 取消暂存中的文件
我们有多个文件还未暂存,但是我们不小心一次性全部放入暂存了:
1 | git add . |
但是我们想一个一个放,不能一次性放入,因此我们使用这两条命令(git status显示的内容有说明):
1 | git reset HEAD file |
HEAD表示上一个版本 HEAD^ HEAD^^ ….
1 | git store --staged file |
4.3 取消对文件的修改
我们不想对这个文件进行修改了,让他回到一开始的状态:
1 | git checkout -- benchmarks.rb |
你可能已经意识到了,这条命令有些危险,所有对文件的修改都没有了,因为我们刚刚把之前版本的文件复制过来重写了此文件。所以在用这条命令前,请务必确定真的不再需要保留刚才的修改。如果只是想回退版本,同时保留刚才的修改以便将来继续工作,可以用下章介绍的 stashing 和分支来处理,应该会更好些。
5. 远程管理仓库
管理远程仓库的工作,包括添加远程库,移除废弃的远程库,管理各式远程库分支,定义是否跟踪这些分支
5.1 查看当前远程库
查看当前配置有哪些远程库
1 | git remote |
注意:默认存在一个 origin的远程库,Git 默认使用这个名字来标识你所克隆的原始仓库。
显示原始仓库的克隆地址
1 | git remote --v |
如果有多个远程仓库,此命令将全部列出。
5.2 添加远程仓库
要添加一个新的远程仓库,可以指定一个简单的名字,以便将来引用:
1 | git remote add pb git://github.com/paulboone/ticgit.git |
添加了一个 远程仓库 名称为 pb
pb代表的就是远程仓库的地址
抓取仓库地址:
1 | git fetch pb |
Paul 的主干分支(master)已经完全可以在本地访问了,对应的名字是 pb/master,你可以将它合并到自己的某个分支,或者切换到这个分支,看看有些什么有趣的更新。
5.3 从远程仓库抓取数据
使用下面的命令从远程仓库抓取数据到本地:
1 | git fetch <remote-name> |
此命令从远程仓库中拉取所有你本地仓库中还没有的数据。
抓取从你上次克隆这个仓库以来,别人上传到此仓库中的所有更新:
1 | git fetch origin |
有一点很重要,需要记住,fetch 命令只是将远端的数据拉到本地仓库,并不自动合并到当前工作分支,只有当你确实准备好了,才能手工合并。
5.4 推送数据到远程仓库
项目进行到一个阶段,要同别人分享目前的成果,可以将本地仓库中的数据推送到远程仓库。
1 | git push [remote-name] [branch-name] |
把本地的branch分支推送到远程 remote 服务器上
5.5 查看远程仓库信息
命令:
1 | git remote show [remote-name] |
查看某个远程仓库的信息
它友善地告诉你如果是在 master 分支,就可以用 git pull 命令抓取数据合并到本地。
另外还列出了所有处于跟踪状态中的远端分支。
5.6 远程仓库的删除与重命名
修改某个远程仓库在本地的名称
1 | git remote rename pb pbnewname |
对远程仓库的重命名,也会使对应的分支名称发生变化。
删除对应的远程仓库:
1 | git remote rm pbname |
6. 打标签
在某一时间点上打上标签
git的标签类型:
- 轻量型标签:是个不会变化的标签,只指向某个特定对象的引用
- 含附注的标签:存储在仓库中的一个独立对象,它有自身的校验和信息,包含着标签的名字,电子邮件地址和日期,以及标签说明。
6.1 显示所有标签
1 | git tag |
标签按字母顺序排列,所以标签的先后不表示重要程度的轻重.
筛选标签
1 | git tag -l 'v1.4.2.*' |
6.2 创建标签
创建含附注的标签:-a 后附带标签的名字
1 | git tag -a v1.4 -m 'my version 1.4' |
-m表示指定对应的标签说明,如果没有 -m后面的内容,则会跳转到vscode让你手动编写 标签说明
使用下面的命令来显示标签对应的信息:
1 | git show v1.4 |
列出了此标签的提交者和提交时间,以及相应的标签说明。
创建个人的私钥:
1 | git tag -s v1.5 -m 'my signed 1.5 tag' |
创建轻量级标签,直接给出标签的名字即可
1 | git tag v1.8 |
6.3 加注标签
已经提交的版本中补上标签信息:
首先显示所有的版本
1 | git log --pretty=oneline |
可以看到 没有标签,我们输入命令,让其中一个版本加上标签:
1 | git tag -a v1.9 085bb3b |
注意:直需要加上校验和的前几位即可,git就会识别这是哪一个版本。
显示我们刚加的标签:
1 | git show v1.9 |
6.4 分享标签
通过显式命令才能分享标签到远端仓库。其命令格式如同推送分支,运行 git push origin [tagname] 即可:
1 | git push origin v1.5 |
一次性推送所有的本地标签上去:
1 | git push origin --tags |
7. Git使用技巧
7.1 自动补全
首先可以查看自己的 Git 有没有自动补全的功能,如下操作所示:
1 | git con<tab> |
输入git co 然后 按两次tab键,会出现提示的命令: config 和commit

如果上述办法不可以,则需要进行如下操作:
如果你用的是 Bash shell,可以试试看 Git 提供的自动补全脚本。下载 Git 的源代码,进入
contrib/completion目录,会看到一个git-completion.bash文件。将此文件复制到你自己的用户主目录中(译注:按照下面的示例,还应改名加上点:cp git-completion.bash ~/.git-completion.bash),并把下面一行内容添加到你的.bashrc文件中:
1 source ~/.git-completion.bash也可以为系统上所有用户都设置默认使用此脚本。Mac 上将此脚本复制到
/opt/local/etc/bash_completion.d目录中,Linux 上则复制到/etc/bash_completion.d/目录中。这两处目录中的脚本,都会在 Bash 启动时自动加载。
7.2 使用别名
为命令起一个别名: git config
1 | git config --global alias.st status |
接下来输入
1 | git st |
其实就是
1 | git status |
取消在暂存区的文件:完整命令如下:
1 | git reset HEAD file |
可以使用别名:
1 | git config --global alias.unstage 'reset HEAD --' |
1 | git unstage file |
显示最后一次提交的文件,完整命令如下:
1 | git log -1 HEAD |
可以使用别名,看起来会更清晰
1 | git config --global alias.last 'log -1 HEAD' |
1 | git last |
Git 只是简单地在命令中替换了你设置的别名
输入Git外部命令
1 | git config --global alias.visual '!gitk' |
1 | git visual |