Git笔记(5) 状态记录
1. 文件的状态变化周期
现在手上有了一个真实项目的 Git 仓库,并从这个仓库中取出了所有文件的工作拷贝
接下来,对这些文件做些修改,在完成了一个阶段的目标之后,提交本次更新到仓库
请记住,工作目录下的每一个文件都不外乎这两种状态:已跟踪 或 未跟踪
-
已跟踪文件:
那些 被纳入了版本控制的文件,在上一次快照中有它们的记录
在工作一段时间后,它们的状态可能是未修改,已修改或已放入暂存区 -
未跟踪文件:
工作目录中除已跟踪文件以外的所有其它文件都属于
它们既不存在于上次快照的记录中,也没有被放入暂存区
初次克隆某个仓库的时候
工作目录中的所有文件都属于已跟踪文件,并处于未修改状态
编辑过某些文件之后
由于自上次提交后你对它们做了修改,Git 将它们标记为已修改文件
逐步将这些修改过的文件放入暂存区
然后提交所有暂存了的修改,如此反复
2. 检查当前文件状态
可以用 git status
命令查看哪些文件处于什么状态
如果在克隆仓库后立即使用此命令
$ git status
会看到类似这样的输出:
On branch master
显示了当前所在分支,分支名 是 “master
”,这是默认的分支名
并告诉这个分支同远程服务器上对应的分支没有偏离
nothing to commit, working tree clean
还说明现在的工作目录相当干净
也就是所有已跟踪文件在上次提交后都未被更改过
并且当前目录下没有出现处于未跟踪状态的新文件
现在,在项目下创建一个新的 README 文件,内容为 “ My Project
”
$ echo 'My Project' > README
现在使用 git status
命令,将看到一个新的未跟踪文件:
在状态报告中可以看到新建的 README 文件出现在 Untracked files
下面
未跟踪的文件意味着 Git 在之前的快照(提交)中没有这些文件
Git 不会自动将之纳入跟踪范围
除非你明明白白地告诉它“我需要跟踪该文件”
这样的处理让你不必担心将生成的二进制文件或其它不想被跟踪的文件包含进来
不过现在的例子中,确实想要跟踪管理 README 这个文件
3. 跟踪新文件
使用命令 git add
开始跟踪一个文件
所以,要跟踪 README 文件,运行:
$ git add README
只要在 Changes to be committed
这行下面的,就说明是 已暂存状态
如果此时提交,那么该文件在运行 git add 时的版本将被留存在历史记录中
4. 暂存已修改文件
这里新增加一个CONTRIBUTING.md
文件,并设置跟踪,即为已暂存状态
如果现在 修改了这个已被跟踪的文件
然后运行 git status
命令,会看到下面内容:
文件 CONTRIBUTING.md
出现在 Changes not staged for commit
这行下面
说明 已跟踪文件的内容发生了变化,但还没有放到暂存区
要暂存这次更新,需要重新运行 git add
命令
这是个多功能命令:
- 开始跟踪新文件
- 把已跟踪的文件放到暂存区
- 合并时把有冲突的文件标记为已解决状态等
将这个命令理解为:添加内容到下一次提交中
现在运行git add
将 CONTRIBUTING.md
文件放到暂存区,然后再看git status
的输出:
5. 状态简览
git status
命令的输出十分详细,但其用语有些繁琐
Git 有一个选项可以缩短状态命令的输出,这样可以以简洁的方式查看更改
如果使用 git status -s
命令或 git status --short
命令,将得到一种格式更为紧凑的输出
前面有 A 标记表示 新添加到暂存区中的文件
还有一些常见的情况:
应该注意到了 M 有两个可以出现的位置,M表示:修改过的文件
出现在左边的 M 表示该文件被修改了并被放入了暂存区
出现在右边的 M 表示该文件被修改了但未被放入暂存区
例如,上面的状态报告显示:
- README 文件被修改了并已将修改后的文件放入了暂存区
- hello_world.c 文件在工作区被修改了但是还没有将修改后的文件放入暂存区
- CONTRIBUTING.md 文件在工作区被修改并提交到暂存区后又在工作区中被修改了
所以在暂存区和工作区都有该文件被修改了的记录
?? 标记:新添加的未跟踪文件
6. 忽略文件
一般总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表
通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等
在这种情况下,可以创建一个名为 .gitignore
的文件,列出要忽略的文件的模式
来看一个实际的 .gitignore
例子:
$ cat .gitignore
第一行,忽略所有以 .o 或 .a 结尾的文件
一般这类对象文件和存档文件都是编译过程中出现的
第二行,忽略所有以波浪符(~)结尾的文件
许多文本编辑软件都用这样的文件名保存副本
此外,可能还需要忽略 log,tmp 或者 pid 目录,以及自动生成的文档等等
要养成一开始就设置好 .gitignore 文件的习惯,以免将来误提交这类无用的文件
文件 .gitignore 的格式规范如下:
- 所有空行或者以 # 开头的行都会被 Git 忽略
- 可以使用标准的 glob 模式匹配
- 匹配模式可以以(/)开头防止递归
- 匹配模式可以以(/)结尾指定目录
- 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反
所谓的 glob 模式是指 shell 所使用的简化了的 正则表达式:
- 星号(*)匹配零个或多个任意字符
- 两个星号(*)表示匹配任意中间目录
比如 a/**/z 可以匹配 a/z , a/b/z 或 a/b/c/z 等 - 问号(?)只匹配一个任意字符
- 方括号[ ]中 匹配任何一个列在方括号中的字符
比如[abc] ,要么匹配一个 a,要么匹配一个 b,要么匹配一个 c - 方括号[ ]中 使用短划线 - 分隔两个字符,表示所有在这两个字符范围内的都可以匹配
比如 [0-9] 表示匹配所有 0 到 9 的数字
再看一个 .gitignore 文件的例子:
# no .a files
*.a
# but do track lib.a, even though you're ignoring .a files above
!lib.a
# only ignore the TODO file in the current directory, not subdir/TODO
/TODO
# ignore all files in the build/ directory
build/
# ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt
# ignore all .pdf files in the doc/ directory
doc/**/*.pdf
- 忽略了上面的
.a
文件 - 即使您忽略了上面的
.a
文件,但是要跟踪lib.a
文件 - 只忽略当前目录中的
TODO
文件,而不是subdir/TODO
- 忽略
build/
目录中的所有文件 - 忽略
doc/notes.txt
文件,但不包括doc/server/arch.txt
文件 - 忽略
doc/
目录中的所有.pdf
文件
Tip:GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表
7. 查看已暂存和未暂存的修改
如果 git status
命令的输出对于你来说过于模糊,想知道具体修改了什么地方
可以用 git diff
命令
通常会用它来回答这两个问题:
- 当前做的哪些更新还没有暂存?
- 有哪些更新已经暂存起来准备好下次提交?
虽然 git status
已经通过在相应栏下列出文件名的方式回答了这个问题
但 git diff
将通过文件补丁的格式更加具体地显示哪些行发生了改变
假如再次修改 README 文件后暂存,然后编辑 CONTRIBUTING.md 文件后先不暂存, 运行 status
命令将会看到:
7.1. 查看未暂存的修改
查看尚未暂存的文件更新了哪些部分
$ git diff
增加了一行Contributing Authors
此命令比较的是工作目录中当前文件 和 暂存区域快照 之间的差异
也就是 修改之后还没有暂存起来的变化内容
7.2. 查看已暂存的修改
若要查看已暂存的将要添加到下次提交里的内容
$ git diff --staged
这条命令将比对已暂存文件与最后一次提交的文件差异:
–staged 和 --cached 是同义词,所以也可以这样
$ git diff --cached
所以有时候一下子暂存了所有更新过的文件后
运行 git diff
后却什么也没有,就是这个原因
8. 提交更新
在此之前提交更新,请一定要确认暂存区域是否已经准备妥当
所以,每次准备提交前,先用 git status
看下,所需要的文件是不是都已暂存起来了
8.1. 命令启动文本编辑器
然后再运行提交命令 git commit
:
$ git commit
这种方式会 启动文本编辑器 以便输入本次提交的说明
默认会启用 shell 的环境变量 $EDITOR
所指定的软件
编辑器会显示类似下面的文本信息(本例选用 Vim 的屏显方式展示):
可以看到:
开头还有一空行,供你输入提交说明
默认的提交消息包含最后一次运行 git status
的输出,放在注释行里
完全可以去掉这些注释行,不过留着也没关系,多少能帮助回想起这次更新的内容有哪些
如果想要更详细的对修改了哪些内容的提示,可以用 -v 选项
这会将所做的改变的 diff 输出放到编辑器中从而使你知道本次提交具体做了哪些修改
退出编辑器时,Git 会丢掉注释行,用输入提交附带信息生成一次提交
8.2. 命令附加提交信息
另外,也可以在 commit
命令后添加 -m
选项,将提交信息与命令放在同一行
如下所示:
$ git commit -m "Story 182: Fix benchmarks for speed"
现在你已经创建了第一个提交
可以看到,提交后它会告诉当前是在哪个分支(master)提交的
本次提交的完整 SHA-1 校验和是什么(28d15bd)
以及在本次提交中,有多少文件修订过,多少行添加和删改过
请记住,提交时记录的是 放在暂存区域的快照
9. 跳过使用暂存区域
完成提交后,现在重新修改CONTRIBUTING.md文件
查看状态,可以看到最后一行有提示:
为了极致简约,Git 提供了一个跳过使用暂存区域的方式
只要在提交的时候,给 git commit
加上 -a
选项
Git 就会 自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add
步骤:
$ git commit -a -m 'delete the Contributing Authors'
但是要小心,有时这个选项会将不需要的文件添加到提交中
10. 移除文件
如果只是简单地从工作目录中手工删除文件
运行 git status
时就会在 “Changes not staged for commit” 部分看到:
10.1. 从 Git 仓库中删除
要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除
确切地说,是从暂存区域移除,然后提交
可以用 git rm
命令完成此项工作,并连带从工作目录中删除指定的文件
$ git rm README
下一次提交时,该文件就不再纳入版本管理了
10.2. 强制删除
如果删除之前 修改过 并且已经 放到暂存区域 的话
则必须要用强制删除选项 -f(即 force 的首字母)
这是一种安全特性,用于防止误删还没有添加到快照的数据
这样的数据不能被 Git 恢复
如 README文件修改后并放在暂存区域,如下:
10.3. 保留当前文件
另外一种情况是,我们想把文件从 Git 仓库中删除(亦即从暂存区域移除)
但仍然希望 保留在当前工作目录中
换句话说,想让文件保留在磁盘,但是并不想让 Git 继续跟踪
当忘记添加 .gitignore 文件
不小心把一个很大的日志文件或一堆 .a 这样的编译生成文件添加到暂存区时
这一做法尤其有用
为达到这一目的,使用 --cached
缓存选项:
$ git rm --cached README
README文件还是在的
git rm
命令后面可以列出文件或者目录的名字
也可以使用 glob 模式
比方说:
$ git rm log/\*.log
注意到星号 * 之前的反斜杠
因为 Git 有它自己的文件模式扩展匹配方式
所以不用 shell 来帮忙展开
此命令删除 log/
目录下扩展名为 .log
的所有文件
类似的比如:
$ git rm \*~
该命令为删除以 ~ 结尾的所有文件
11. 移动文件
如果在 Git 中重命名了某个文件
仓库中存储的元数据并不会体现出这是一次改名操作
不过 Git 会推断出究竟发生了什么
当看到 Git 的 mv 命令时一定会困惑不已
要在 Git 中对 文件重命名,可以这么做:
$ git mv file_from file_to
实际上,即便此时查看状态信息,也会明白无误地看到关于重命名操作的说明:
其实,运行 git mv
就相当于运行了下面三条命令:
$ mv README README.md
$ git rm README
$ git add README.md
如此分开操作,Git 也会意识到这是一次改名
所以不管何种方式结果都一样
而 git mv
相对简约
不过有时候用其他工具批处理改名的话
要记得在提交前删除老的文件名,再添加新的文件名
参考: git
以上内容,均根据git官网介绍删减、添加和修改组成
相关推荐:
Git笔记(4) 获取仓库
Git笔记(3) 安装配置
Git笔记(2) 入门认知
Git笔记(1) 版本控制
谢谢