Githug 闯关式学习 git(二)

谈谈 .gitignore 文件

在 Level 7 与 Level 8 中我们看到,通过配置 .gitignore 文件实现了对仓库内特定文件的忽略与追踪。git 通过丰富的机制用你的文件名模式列表来指定哪些文件要忽略。.gitignore 的模式如下:

  • 所有空行都会被忽略,# 开头的行可用于注释。

  • 同名的文件名匹配同名文件。

  • 匹配模式以 / 开头防止递归,以 / 结尾指定目录。

  • 忽略指定模式以外的文件或目录,可以在模式前加 ! 取反。

  • 可以使用标准的 glob 模式匹配。
    所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。 星号(*)匹配零个或多个任意字符;[abc] 匹配任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);问号(?)只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。 使用两个星号(*) 表示匹配任意中间目录,比如 a/**/z 可以匹配 a/z, a/b/za/b/c/z 等。

除了在仓库根目录下使用 .gitignore 文件外,也可以在子目录下建立 .gitignore 文件,文件的忽略规则总是使用最靠近文件本身目录的规则,上级目录规则被本级目录规则覆盖,类似 CSS(Cascading Style Sheets)。
假设你在本机所有的仓库中都使用同样的编辑器,如 vim,需要在所有的仓库忽略规则中添加 *.swp 来排除 vim 的编辑缓存。更为简便的方式是建立一个全局配置:

1
$ git config --global core.excludesfile ~/.gitignore_global

它将应用于所有本地仓库。

另一个场景:

假设你把仓库推送到远程仓库,别人 clone 仓库来进行协作。这时仓库中你所定义的忽略规则对他人而言也许不再适用,比如编辑器自动生成的一些文件。这时应把特定的规则写在 .git/info/exclude 文件中。clone 仓库的其它人将不会应用此规则。

储藏

在 Level 13 中,我们使用 git stash 命令来储存工作进度。下面来详细看一下这个命令的用法。

任何工具或命令都有它特定的应用场景,储藏命令也不例外。当在日常的开发周期中,工作经常会发生中断,或紧急修复 BUG,或处理来自他人的请求。此时的工作目录处于工作中,有已经暂存的,有已修改还没有暂存的。换句话说,工作目录处于“脏”的状态。储藏命令可以捕获工作进度,将修改的跟踪文件与暂存状态保存。当紧急事务处理完毕,你可以恢复到这个保存的状态点继续进行开发。

1
2
3
4
5
6
7
8
9
10
11
12
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

new file: about.html

Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

modified: index.html

此时可以看到有一个已暂存但还未提交的 about.html,已修改但还未暂存的 index.html。接下来使用储藏命令保存这个工作状态。

1
2
3
4
5
6
7
$ git stash save
Saved working directory and index state WIP on master: 8e97a93 Initial commit.
HEAD is now at 8e97a93 Initial commit.

$ git status
On branch master
nothing to commit, working directory clean

已经变为一个干净的工作目录。现在进行一些修改,引入一个 CSS 文件。回到之前保存的工作状态。
查看储藏的工作状态,可以使用 git stash list 命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ git stash list
stash@{0}: WIP on master: 8e97a93 Initial commit.

$ git stash pop
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html

$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

new file: about.html

Unmerged paths:
(use "git reset HEAD <file>..." to unstage)
(use "git add <file>..." to mark resolution)

both modified: index.html

已经返回了之前的工作状态,但看到产生了一个合并冲突。pop 操作会取出储藏的内容并合并这些变更到当前状态,像合并分支一样,你需要手动处理可能产生的合并冲突。
处理合并冲突后的整个提交图如下:

1
2
$ git stash list
stash@{0}: WIP on master: 8e97a93 Initial commit.

此时,我们增加一个 fix.js 文件,但并不追踪它。并对 about.html 也引入 CSS 文件,随后进行另一个储藏操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ echo "console.log(\"git\")" >> fix.js

$ git status -s
M about.html
?? fix.js

$ git stash save
Saved working directory and index state WIP on master: 63b9816 Fix merge
HEAD is now at 63b9816 Fix merge

$ git stash list
stash@{0}: WIP on master: 63b9816 Fix merge
stash@{1}: WIP on master: 8e97a93 Initial commit.

储藏条目增加了一条,最新的储藏条目编号为 0。随着条目增加编号也会递增。形成储藏状态的变更是相对于某个特定的提交,所以在上面储藏条目中显示为父提交的提交信息。可以使用自己的储藏信息。

1
$ git stash save "Your message"

使用 git stash show -p 命令显示储藏相对于它父提交的索引和文件变更记录。

1
2
3
4
5
6
7
8
9
10
11
12
$ git stash show -p stash@{0}
diff --git a/about.html b/about.html
index cabef06..9aa68a9 100644
--- a/about.html
+++ b/about.html
@@ -3,6 +3,7 @@
<head>
<meta charset="UTF-8">
<title> 关于 </title>
+ <link rel="stylesheet" href="./style.css">
</head>
<body>

现在我们在 fix.js 修改内容 githug 为 git。
执行 pop 操作后可以看到,fix.js 文件内容没有变回之前的状态,也没有冲突的处理。因为默认情况下储藏操作不会储藏未追踪文件。

git 不会储藏未追踪文件

若要储藏为追踪文件,需要在储藏命令后添加 -u 参数。

此时我们再看一下储藏列表。

1
2
$ git stash list
stash@{0}: WIP on master: 8e97a93 Initial commit.

在一个 pop 操作成功后,git 会将储藏状态栈中储藏的状态删除,之所以还剩余一个储藏状态是因为在 pop 操作时有合并冲突,解决冲突后必须使用 git stash drop 命令来将状态从储藏栈中删除。这时,提交图也能看到提交记录的变化。

如果只是想重新创建一个储藏状态上下文,又不想把它从栈中删除,那么应该使用 git stash apply 命令。事实上,pop 操作就是在 apply 操作后紧跟一个 drop 操作。在使用 git stash apply 命令时,只能恢复工作目录,若要同时恢复暂存区,需要添加 --index 参数,并且在恢复暂存区时发生冲突,恢复会失败。

本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明出处! © 雨落
  1. 1. 谈谈 .gitignore 文件
  2. 2. 储藏