typora-copy-images-to: ......\md_pics
2 基本操作
Git 的基本操作都要由命令行完成,当然也有 GUI 方式的 Git 工具,是对某些命令的封。
[TOC]
2.1 获取 Git 仓库
在现有目录中初始化仓库
1 | # 进入该项目,并执行一下命令 |
该命令将创建一个名为 .git
的子目录,包含了初始化的 Git 仓库中所有的必须文件,是 Git 仓库的骨干。
接着通过 git add
命令来对指定文件进行跟踪,并将其放入暂存区域,执行 git commit
进行提交。
1 | git add *.md |
克隆已有的仓库
Git 克隆的是该 Git ==仓库服务器上的几乎所有数据==,而不是仅仅复制完成你的工作所需要文件。 当你执行 git clone
命令的时候,默认配置下远程 Git 仓库中的每一个文件的每一个版本都将被拉取下来。 事实上,如果你的服务器的磁盘坏掉了,你通常可以使用任何一个克隆下来的用户端来重建服务器上的仓库。
1 | # git clone [url] [local repository name] |
支持多种数据传输协议。https://、git:// 或者 SSH 协议。
2.2 记录每次更新到仓库
仓库中每个文件的状态
工作目录下的文件不外乎两种状态:已跟踪或未跟踪。已跟踪的文件是指那些被纳入了版本控制的文件,在上一次快照中有它们的记录。工作一段时间后,状态可能处于 未修改 已修改 已暂存。 新建的文件属于未跟踪文件。初次克隆某个仓库有的时候,工作目录中所有文件都属于以跟踪文件,并处于未修改状态。
状态简览
1 | # 查看当前文件的状态,显示当前所属的分支,反应每个文件是处于 已修改未暂存 还是 已暂存 或者 未追踪状态 |
新添加的未跟踪文件前面有 ??
标记
新添加到暂存区中的文件前面有 A
标记
修改过的文件前面有 M
标记
M
有两个可以出现的位置,出现在右边的 M
表示该文件被修改了但是还没放入暂存区,出现在靠左边的 M
表示该文件被修改了并放入了暂存区。
例如,上面的状态报告显示: README
文件在工作区被修改了但是还没有将修改后的文件放入暂存区, lib/simplegit.rb
文件被修改了并将修改后的文件放入了暂存区。 而 Rakefile
在工作区被修改并提交到暂存区后又在工作区中被修改了,所以在暂存区和工作区都有该文件被修改了的记录。
追踪文件或将已修改文件放入暂存区
1 | # git add 不仅可以用于追踪文件,还用于暂存文件 |
查看已暂存和未暂存的修改
1 | # 查看已修改文件和暂存区域文件的差异 |
提交更新
1 | # 将暂存区域的更新提交只版本库 |
移除文件
- 先将文件从工作目录中删除,然后运行
git rm
记录此次移除文件的操作,也就是不在追踪此文件。之后再提交后,版本库里的文件也被移除掉了。 - 如果要保留工作目录中的文件,即需要移除暂存区的文件,需要通过
git rm --cached READEME.md
, 提交后,Git 就不再跟踪此文件,但工作目录中依然保留。
git rm
命令后面可以列出文件或者目录的名字,也可以使用 glob 模式。
1 | git rm --cached log/\*.log |
移动文件
移动文件和文件的重命名是一样的。
1 | git mv fileFrom fileTo |
相当于运行了下面的三条命令
1 | mv README.md README |
忽略文件
有些文件不需要被 Git 管理,比如编译后生成的文件、日志文件、临时生成的文件。这时就可以创建一个名为 .gitignore
的文件。列出要忽略的文件模式。
1 | # 创建一个 .gitignore 文件 |
.gitignore 文件的格式规范如下:
所有空行或者以
#
开头的行都会被 Git 忽略。可以使用标准的 glob 模式匹配。
匹配模式可以以(
/
)开头防止递归。匹配模式可以以(
/
)结尾指定目录。要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(
!
)取反。
glob 模式是指使用简化了的正则表达式
* 表示匹配零个或多个任意字符
[abc ] 匹配方括号中的任意一个字符
[0-9] 范围
?匹配一个任意字符
使用两个星号 ** 匹配任意中间目录,比如 a/**/z 可以匹配 a/z a/b/z 或 a/b/c/z
1 | # no .a files |
2.3 查看提交历史
在提交了若干更新,又或者克隆了某个项目之后,你也许想回顾下提交历史。 完成这个任务最简单而又有效的工具是 git log
命令。
默认不用任何参数的话,git log
会按提交时间列出所有的更新,最近的更新排在最上面。这个命令会列出每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明。
1 | # 只显示提交的作者、时间信息和提交的注释说明 |
默认内置格式显示
另外一个常用的选项是 --pretty
。 这个选项可以指定使用不同于默认格式的方式展示提交历史。 这个选项有一些内建的子选项供你使用。 比如用 oneline
将每个提交放在一行显示,查看的提交数很大时非常有用。 另外还有 short
,full
和 fuller
可以用,展示的信息或多或少有些不同,请自己动手实践一下看看效果如何。
1 | $ git log --pretty=oneline |
格式化显示
可以定制显示的记录格式。
1 | $ git log --pretty=format:"%h - %an, %ar : %s" |
下表列出了常用的格式占位符写法及其代表的意义。
选项 | 说明 |
---|---|
%H |
提交对象(commit)的完整哈希字串 |
%h |
提交对象的简短哈希字串 |
%T |
树对象(tree)的完整哈希字串 |
%t |
树对象的简短哈希字串 |
%P |
父对象(parent)的完整哈希字串 |
%p |
父对象的简短哈希字串 |
%an |
作者(author)的名字 |
%ae |
作者的电子邮件地址 |
%ad |
作者修订日期(可以用 –date= 选项定制格式) |
%ar |
作者修订日期,按多久以前的方式显示 |
%cn |
提交者(committer)的名字 |
%ce |
提交者的电子邮件地址 |
%cd |
提交日期 |
%cr |
提交日期,按多久以前的方式显示 |
%s |
提交说明 |
作者指的是实际作出修改的人,提交者指的是最后将此工作成果提交到仓库的人。 所以,当你为某个项目发布补丁,然后某个核心成员将你的补丁并入项目时,你就是作者,而那个核心成员就是提交者。
当 oneline 或 format 与另一个 log
选项 --graph
结合使用时尤其有用。 这个选项添加了一些ASCII字符串来形象地展示你的分支、合并历史:
1 | $ git log --pretty=format:"%h %s" --graph |
以上只是简单介绍了一些 git log
命令支持的选项。
1 | $ git log --pretty=format:"%ad ar - %s" --date=format:%Y-%m-%d |
1 | %a Abbreviated weekday name |
下面列出了我们目前涉及到的和没涉及到的选项,以及它们是如何影响 log 命令的输出的:
选项 | 说明 |
---|---|
-p |
按补丁格式显示每个更新之间的差异。 |
--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(后跟指定格式)。 |
限制输出长度
Git 在输出所有提交时会自动调用分页程序,所以你一次只会看到一页的内容。
按照时间作限制的选项,比如 --since
和 --until
也很有用。
1 | # 下面的命令列出所有最近两周内的提交: |
用 --author
选项显示指定作者的提交,用 --grep
选项搜索提交说明中的关键字。 (请注意,如果要得到同时满足这两个选项搜索条件的提交,就必须用 --all-match
选项。否则,满足任意一个条件的提交都会被匹配出来)
另一个非常有用的筛选选项是 -S
,可以列出那些添加或移除了某些字符串的提交。 比如说,你想找出添加或移除了某一个特定函数的引用的提交,你可以这样使用:
1 | $ git log -Sfunction_name |
最后一个很实用的 git log
选项是路径(path), 如果只关心某些文件或者目录的历史提交,可以在 git log 选项的最后指定它们的路径。 因为是放在最后位置上的选项,所以用两个短划线(–)隔开之前的选项和后面限定的路径名。
常用的选项
选项 | 说明 |
---|---|
-(n) |
仅显示最近的 n 条提交 |
--since , --after |
仅显示指定时间之后的提交。 |
--until , --before |
仅显示指定时间之前的提交。 |
--author |
仅显示指定作者相关的提交。 |
--committer |
仅显示指定提交者相关的提交。 |
--grep |
仅显示含指定关键字的提交 |
-S |
仅显示添加或移除了某个关键字的提交 |
来看一个实际的例子,如果要查看 Git 仓库中,2008 年 10 月期间,Junio Hamano 提交的但未合并的测试文件,可以用下面的查询命令:
1 | $ git log --pretty="%h - %s" --author=gitster --since="2008-10-01" \ |
在近 40000 条提交中,上面的输出仅列出了符合条件的 6 条记录。
2.4 撤销操作
补充提交
如果在一次提交完成之后发现有些文件还没有被添加,或者提交信息写错了。此时可以通过以下命令尝试重新提交:
1 | git commit --amend |
这个命令会将添加进暂存区的文件再次提交。如果上次提交后立马执行了此命令,那么修改的只是提交信息。
1 | git commit -m "Add files." |
1 | git commit -m 'Add files' |
取消暂存的文件
如过不想同时暂存两个文件,但又通过命令 git add *
暂存了所有的文件,如何撤销已经暂存的另一个文件。 git 在 git status 中一般有相应的提示。
1 | git reset HEAD second.md |
撤销对文件的修改
如果对该文件的修改要退回到上次提交后的状态。 git status 中同样有所提示。
1 | git checkout -- file |
2.5 远程仓库
远程仓库的几个命令
进行远程仓库的克隆
1 | git clone repository_url |
从远程仓库中进行抓取,本地库被更新为最新的版本
1 | git fetch [remote-name] |
从远程仓库中进行来进行拉取,并尝试合并到当前所在的分支
1 | git pull [remote-name] |
推送到远程仓库中相应的分支中
1 | git push [remote-name] [branch-name] |
添加远程仓库
1 | git remote add [remote-name] [remote-url] |
查看远程仓库的别名
1 | git remote |
查看远程仓库的别名与远程库链接
1 | git remote -v |
查看远程仓库的具体信息
1 | git remote show [remote-name] |
一般的流程是
1 | git fetch ---> git add ---> git commit ---> git push |
2.6 打标签
给历史提交打上标签,来标记重要的提交节点或重大的功能完成节点。
列出已有的标签
1 | git tag |
创建标签
Git 中有两种标签:lightweight - 轻量标签; annotated - 附注标签
一个轻量标签只是一个特定提交的引用。
一个附注标签是存储在 Git 数据库中的一个完整对象,包括打标签作者的名字、电子邮件地址、日期时间、标签信息,可以使用 GNU Privacy Guard (GPG) 签名与验证。
通常建议创建附注标签,这样可以拥有很多信息。
- 附注标签
1 | git tag -a v1.0 -m 'version 1.0' |
轻量标签
轻量标签本质上是提交校验和存储到一个文件中 - 没有保存任何其他信息。只需要提供标签名字就可以创建轻量标签。
1 | git tag v1.0-lightweight |
如果前面的某一次提交忘记打标签了,可以在之后补上标签。需要在命令的末尾指定提交的校验和(部分校验和)。
1 | git log --pretty=oneline |
共享标签至远程库
创建完标签,必须显示地推送标签到共享服务器上。
1 | # git push origin [tagname] |
检出标签
在 Git 中你并不能真的检出一个标签,因为它们并不能像分支一样来回移动。 如果你想要工作目录与仓库中特定的标签版本完全一样,可以使用
git checkout -b [branchname] [tagname]
在特定的标签上创建一个新分支:1
2$ git checkout -b version2 v2.0.0
Switched to a new branch 'version2'当然,如果在这之后又进行了一次提交,
version2
分支会因为改动向前移动了,那么version2
分支就会和v2.0.0
标签稍微有些不同,这时就应该当心了。
2.7 别名
Git 可以通过别名的方式简化命令,为命令设置一个别名,通过别名就可完成相应的命令。别名一般从字面上就可以看出该命令的执行作用。
1 | git config --global alias.co checkout |
可以看出,Git 只是简单地将别名替换为对应的命令。 然而,你可能想要执行外部命令,而不是一个 Git 子命令。 如果是那样的话,可以在命令前面加入 !
符号。 如果你自己要写一些与 Git 仓库协作的工具的话,那会很有用。 我们现在演示将 git visual
定义为 gitk
的别名:
1 | git config --global alias.visual '!gitk' |