2. Git 基础
写在前面:这一部分内容真的是好多好多好多ε(┬┬﹏┬┬)3,不过也是使用 Git 最有用的啦,所以 => 我爱学习!开始吧,胖友们~
(っ•̀ω•́)っ✎⁾⁾
本部分涵盖了你在使用 Git 完成各种工作中将要使用的各种基本命令。如:
配置并初始化一个仓库;
开始或停止跟踪文件;
暂存或提交更改;
配置 Git 来忽略指定的文件和文件模式;
迅速而简单地撤销错误操作;
浏览项目的历史版本以及不同提交间的差异;
向远程仓库推送;
从远程仓库拉取文件。
2.1 获取 Git 仓库
获取 Git 项目仓库有两种方法:
- 在现有项目或目录下导入所有文件到 Git 中;
- 从一个服务器克隆一个现有的 Git 仓库。
2.1.1 在现有目录中初始化仓库
git init
执行该命令后会在当前文件夹创建一个名为 .git 的子目录,这个子目录含有你初始化的 Git 仓库中所有必须文件,这些文件是 Git 仓库的骨干。但此时,仅仅是初始化,项目内的文件还未被跟踪。
接下来开始跟踪这些文件并提交(下面每条指令后续进行解释)。
git add *. c //跟踪当前所有文件
git add LICENSE
git commit -m 'initial project version' //提交文件到仓库
运行后,你已经得到了一个实际维护着若干个文件的 Git 仓库,且本地内容已上传到了 Git 仓库内。
2.1.2 克隆现有的仓库
如果你想获得一份已经存在了的 Git 仓库的拷贝,需要用到 git clone 命令,默认配置下远程 Git 仓库中的每一个文件的每一个版本都将被拉取下来。也就是说,如果你的磁盘坏了,你可以克隆服务器上的仓库来找回数据。
克隆仓库的命令格式 git clone [url]
。url为要克隆的仓库的库链接。
eg: 若 url 为: https://github.com/libgit2/libgit2,
则命令应为
git clone https://github.com/libgit2/libgit2
执行完成后,会在当前目录下创建一个名为 libgit2 的目录,并在这个目录下初始化一个 .git 文件夹,从远程仓库拉取所有数据放入 .git 文件夹,然后从中读取最新版本的文件的拷贝,放在 libgit2 文件夹内。
如果你想在克隆远程仓库时,自定义仓库的名字,可使用如下命令:
git clone https://github.com/libgit2/libgit2 mylibgit
则本地仓库名会是 mylibgit ,其他相同。
2.2 记录每次更新到仓库
2.2.1 检查当前文件状态——git status
工作目录下的文件无外乎两种状态:已跟踪或未跟踪。
如图,说明本地内容与 Git 仓库内完全一样,未被更改,没有可提交的内容。
在文件夹下添加 README.txt 文件,再执行 git status 命令,将会看到一个新的未跟踪文件:
2.2.2 跟踪新文件——git add
将 README.txt 添加为跟踪文件 :git add README.txt
再次执行: git status
:
可见, README.txt 文件已被跟踪,并处于暂存状态。
2.2.3 暂存已修改文件——git add
下面,我修改了项目内的一个已被跟踪的 README.md 文件,运行 git status
查看文件状态:
文件 README.md 显示在 Changes not staged for commit 下,说明已跟踪的文件被修改但未暂存,使用
git add
暂存此次更新git add README.md
再次执行
git status
查看文件状态:则两个文件都已暂存,下次提交时会一并记录到仓库。
此时再次修改 README.md 文件,运行
git status
查看文件状态:可见 README.md 文件 同时出现在已暂存和未暂存区域,是因为此时暂存的是你上次运行
git add
时的版本,如果现在提交,提交的也是上次运行 git add
时的版本,因此,在 git add
后又修改了文件的,要重新运行 git add
暂存最新的文件版本,再提交,才能保证提交的是你修改的最新的文件。
2.2.4 状态简览
git status
命令的输出十分详细,你可以通过git status --short
或git status -s
命令来得到更简洁紧凑的输出。首先新建一个 newfile.html 文件,运行git status -s
命令:
- ?? :未跟踪文件
- M:已修改文件,若出现两个 M,则表示文件修改后被暂存过,但暂存过后又有新的修改,未被暂存
- A:新添加到暂存区的文件
2.2.5 忽略文件
一般我们会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表,如日志文件或编译过程中创建的临时文件等。这种情况下,可以创建一个 .gitignore 文件,列出要忽略的文件模式。如下:
*.[oa]
*~
第一行告诉 Git 忽略所有以 .o 或.a 结尾的文件。一般这类对象文件和文档文件都是编译过程中出现的。
第二行告诉 Git 忽略所有以 ~ 结尾的文件,许多文本编辑软件都用这样的文件名保存副本。
.gitignore 文件的格式规范如下:
- 所有空行或者以 # 开头的行都会被 Git 忽略。
- 可以使用标准的 glob 模式匹配。
- 匹配模式可以以(/)开头防止递归。
- 匹配模式可以以(/)结尾指定目录。
- 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反
glob模式:
glob 模式是指 shell 所使用的简化了的正则表达式。
- 星号(*)匹配零个或多个任意字符;
- [abc] 匹配任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);
- 问号(? )只匹配一个任意字符
- 如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配 (比如 [0-9] 表示匹配所有 0 到 9 的数字);
- 使用两个星号(*) 表示匹配任意中间目录,比如
a/**/z
可以匹配 a/z, a/b/z 或a/b/c/z
等。
注:GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表,你可以在 https://github.com/github/gitignore 找到它.
2.2.6 查看已暂存和未暂存的修改——git diff
git diff:
显示尚未暂存的改动;
git diff --cached
(Git 1.6.1及更高版本也支持git diff --staged
):显示已暂存的将要添加到下次提交里的内容。
接之前的文件状态,README.md 文件修改后未暂存,README.txt 文件已暂存:
接下来,执行
git add README.md
将 README.md 文件暂存,再执行这两条命令:此时,已无未暂存文件,则
git diff
下无内容。
2.2.7 提交更新——git commit
提交前,要 git status
确认当前修改过的文件都已暂存,否则提交时不会记录没有被暂存的文件。确认当前文件都已暂存后,运行提交命令git commit
。
此时,会启动文本编辑器以便输入本次提交的说明。
另外,你也可以在
commit
命令后 添加 -m
选项,将提交信息与命令放在同一行,如下:![执行 git commit -m 提交信息
注:调教时记录的是放在暂存区域的快照。每一次提交,都是对你项目做一次快照,以后可以回到这个状态,或者进行比较。
2.2.8 跳过使用暂存区域
Git 提供了一个跳过使用暂存区域的方式,只要在提交的时候,给 git commit
后面加上 -a
选项,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add
步骤:
2.2.9 移除文件——git rm
情况一:将 Git 仓库 和本地目录的此文件均删除
- 删除某个文件:
rm README.txt
- 运行
git rm
记录此次移除文件的操作:
这样,一下次提交时,改文件就不再纳入版本管理了。
如果删除之前修改过且已经放在暂存区域的话,则必须要用强制删除选项-f
(force)。这是一种安全特性,用于防止误删还没有添加到快照的数据,这样的数据不能被 Git 恢复。
情况二:只想把文件从 Git 仓库删除,但仍保留在当前工作目录中,且不再让 Git 继续跟踪
- 执行
git rm --cached newfile.html
- 执行
git status
查看文件状态
2.2.10 重命名文件
文件重命名——git mv file_from file_to
例如我工作目录中有一个文件名为 'index.html', 我要对其进行重命名操作:
git mv index.html indexnew.html
其实,
git mv
相当于运行了下面三条命令:
mv index.html indexnew.html
git rm index.html
git ad indexnew.html
2.3 查看提交历史——git log
此处使用 Git 官网提供的项目实例,运行下面的命令获取项目源代码
git clone https://github.com/schacon/simplegit-progit
2.3.1 查看提交历史
在项目中运行 git log
可按提交时间列出说有的心梗,最近的更新排在最上面。
这个命令会列出每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明。
git log
有许多选项可以帮助你搜寻你所要找的提交
-
-p
用来显示每次提交的内容差异,加上-2
可以仅显示最近两次提交:
该选项除了显示基本信息外,还附带了每次提交的变化。当进行代码审查或快速浏览其他人提交所带来的变化时,可以使用这条命令。 -
--stat
你可以看到每次提交的简略的统计信息。
该选项在每次提交的下面列出所有被修改过的文件、有多少文件被修改了以及被修改过得文件的哪些行被移除或是添加了。在每次提交的最后还有一个总结。 -
--pretty
可以指定使用不同于默认格式的方式展示提交历史
其有一些内建的子选项供你使用:
例如--pretty=oneline
将每个提交放在一行显示,在提交数很大时非常有用,还有short
、full
、fuller
、format
可以使用,可动手实践看下效果。
下面介绍一下format
,此选项可以定制要显示的记录格式。
git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 6 years ago : changed the version number
085bb3b - Scott Chacon, 6 years ago : removed unnecessary test
a11bef0 - Scott Chacon, 6 years ago : first commit
git log --pretty=format
常用选项
git log
常用选项2.3.2 限制输出长度
-
git log --since=2.weeks
显示近两周内的提交 -
author
显示指定作者的提交 -
grep
搜索提交说明中的关键字 (注:如果要得到同时满足这两个选项搜索条件的提交,就必须用--all-match
选项。否则,满足任意一个条件的提交都会被匹配出来) -
-S
选项可以列出哪些添加或是移除了某些字符串的提交。
比如你想找出添加或移除了某一个特定函数的引用的提交,你可以这样使用:
git log -Sfunction_name
-
git log --path
只显示指定目录的历史提交,将--path
放在命令最后即可。
**限制 git log
输出的选项
实例:
要查看 Git 仓库中,2008 年 10 月期间,Junio Hamano 提交的但未合并的测试文件,可以用下面的查询命令:
git log --pretty="%h - %s" --author=gitster --since="2008-10-01" \
--before="2008-11-01" --no-merges -- t/
5610e3b - Fix testcase failure when extended attributes are in use
acd3b9e - Enhance hold_lock_file_for_{update,append}() API
f563754 - demonstrate breakage of detached checkout with symbolic link HEAD
d1a43f2 - reset --hard/read-tree --reset -u: remove unmerged new paths
51a94af - Fix "checkout --track -b newbranch" on detached HEAD
b0ad11e - pull: allow "git pull origin $something:$current_branch" into an unborn branch
2.4 撤销操作
2.4.1 重新提交—— --amend
例如,你提交后发现忘记了暂存某些需要的修改,可以像下面这样操作:
git commit -m 'initial commit'
git add forgotten_file
git commit --amend
这个命令会将暂存区中的文件提交,如果上次提交后你还未做任何修改,那么快照会保持不变,只修改提交信息,最终你只会有一个提交——第二次提交将代替第一次提交的结果。
2.4.2 取消暂存的文件 —— git reset HEAD [file]
各种状态的文件,在执行 git status
后会有对应的提示。
例如当你把所有修改的文件都暂存后,想取消 READEME.md 的暂存状态,可运行:
git reset HEAD README.md
再执行 git status
查看状态,会发现 READEME.md 文件现在处于未暂存状态。
2.2.3 撤销对文件的修改 —— git checkout -- [file]
(谨慎使用)
当你想撤销 READEME.md 的修改,使其回到上次提交时的状态,可运行:
git checkout -- READEME.md
再执行 git status
查看状态,会发现 READEME.md 文件的修改都已撤销。
- 如果你仍然想保留对那个文件做出的修改,但是现在仍然需要撤消,可以使用 Git 分支,这同事更好的做法,Git 分支会在后面介绍。
- Git 中任何 已提交的 东西几乎总是可以恢复的;未提交的东西丢失后很可能再也找不到了。
2.5 远程仓库的使用
远程仓库是指托管在因特网或其他网络中的你的项目的版本库。 你可以有好几个远程仓库,通常有些仓库对你只读,有些则可以读写。 与他人协作涉及管理远程仓库以及根据需要推送或拉取数据。
2.5.1 查看远程仓库
-
git remote
此命令会列出你指定每一个远程服务器的简写,若你已克隆自己的仓库,至少能看到origin
—— Git 给你克隆的仓库服务器的默认名字
-
git remote -v
指定选项-v
会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL。
2.5.2 添加远程仓库
首先,我再本地新建一个空文件夹,运行 git init
,使其初始化为一个本地的 Git 仓库。
执行 git remote
查看其远程仓库,可见为空
运行
git remote add <shortname> <url>
可以添加一个新的远程 Git 仓库,同时指定一个你可以轻松引用的简写:执行
git remote -v
查看其远程仓库,已添加成功,且后面你可直接用 st 来代替远程地址链接2.5.3 从远程仓库中抓取与拉取
git fetch [remote-name]
访问远程仓库,从中拉去你还没有的数据,执行完成后,你会拥有那个远程仓库中所有分支的引用,可以随时合并或查看。
2.5.4 推送到远程仓库
当你想分享你的项目时,必须将其推送到上游。
git push [remote-name] [branch-name]
—— 将 master
分支推送到 origin
服务器。
只有当你有所克隆服务器的写入权限,且在你克隆后没有人推送,这条命令才生效,若在你克隆后已有人推送过,你必须先将他们推送的内容拉取下来进行合并,才能推送你的呢荣。
2.5.5 查看远程仓库
git remote show [remote-name]
这条命令会列出远程仓库的 URL
、跟踪分支、执行 git push
会自动推送到哪一个远程分支、哪些远程分支不在你的本地,哪些远程分支已经从服务器上移除、当你执行 git pull
时哪些分支会自动合并等信息。
2.5.6 远程仓库的移除
例如想修改上述简写名 st
为 ca
,可执行:
git remote rename st ca
2.5.7 远程仓库的移除
例如,想移除上述 ca
仓库的引用,可执行:
git remote rm ca
2.6 打标签
Git 可以给历史中的某一个提交打上标签,以示重要。
比较有代表性的是人们会使用这个功能来标记发布结点(v1.0 等等)。
2.6.1 列出标签——git tag
如图,本项目暂无标签 (〃'▽'〃)
- 查找特定标签:`git tag -l 'v1.0.0' ,会找出 v1.0.0 相关的标签
后续可以验证
2.6.2 创建标签
Git 使用两种主要类型的标签:轻量标签、附注标签。
轻量标签:很像一个不会改变的分支——只是一个特定提交的引用
轻量标签:存储在 Git 数据库中的一个完整对象。可被校验,包含很多标签信息。
1. 附注标签:
-
git tag -a v1.0.0 -m 'my version 1.0.0'
可见,已成功创建 v1.0.0 标签。
-m
制定了一条将会存储在标签中的信息,若没有为附注标签指定一条信息,Git 会运行编辑器要求你输入信息。 -
git show
可以看到标签信息及对应的提交信息
-
此时可验证列出特定标签的方法:
2. 轻量标签:
轻量标签本质上是将提交校验和存储到一个文件中,没有保存其他任何信息。
创建轻量标签,不需要使用 -a
、-s
、-m
选项,只需要提供标签名字:
git tag v1.0.1
git show v1.0.1
时只会显示提交信息,没有额外的标签信息。
2.6.3 后期打标签
执行 git log --pretty=oneline
,显示提交历史
在创建标签命令的末尾加上对应某次提交的校验和
2.6.4 共享标签
默认情况下,git push 命令并不会传送标签到远程仓库服务器上。 在创建完标签后你必须显式地推送标签到共享服务器上。 这个过程就像共享远程分支一样 - 你可以运行 git push origin [tagname]
。
如果想要一次性推送很多标签,也可以使用 git push origin --tags
。
现在,当其他人从仓库中克隆或拉取,他们也能得到你的那些标签。
2.6.5 检出标签
在 Git 中你并不能真的检出一个标签,因为它们并不能像分支一样来回移动。 如果你想要工作目录与仓库中特定的标签版本完全一样,可以使用 git checkout -b [branchname] [tagname]
在特定的标签上创建一个新分支:
git checkout -b version2 v1.0.0
Switched to a new branch 'version2'
当然,如果在这之后又进行了一次提交,version2 分支会因为改动向前移动了,那么 version2 分支就会和 v1.0.0 标签稍微有些不同,这时就应该当心了。
2.7 Git 别名
不想每次都输入
commit
,想将其简化为ci
:
git config --global alias.ci commit
执行后,想要输入git commit
时,只需输入git ci
即可。创建
unstage
为取消暂存的别名时,可执行:
git config --global alias.unstage 'reset HEAD --'
创建
last
为查看最后一次提交的别名时,可执行:
git config --global alias.last 'log -1 HEAD'
然而,你可能想要执行外部命令,而不是一个 Git 子命令。 如果是那样的话,可以在命令前面加入 ! 符号。 如果你自己要写一些与 Git 仓库协作的工具的话,那会很有用。 我们现在演示将 git visual 定义为 gitk 的别名:
git config --global alias.visual '!gitk'
2.8 总结
现在,你可以完成所有基本的 Git 本地操作——创建或者克隆一个仓库、更改文件、暂存并提交这些更改、浏览你的仓库从创建到现在的所有更改的历史。
有木有觉得超级有成就感,那么请继续~ヾ(◍°∇°◍)ノ゙