上一篇文章,我们学习了 使用git如何创建一个仓库。而且还详细的介绍了git各个工作目录的作用。
git: global information tracker
git其实是内容寻址文件系统。本质是一个key-value的数据库。在上一篇文章了解了git的四种对象:提交对象,数据对象,树对象和标签对象。还学习了git的引用(HEAD,Index,refs目录),以及最后学习了git的压缩,(git gc).
今天我们从 简单的git使用流程说起。
上一篇中,我们创建了一个仓库.
➜ gitlearn git init .
Initialized empty Git repository in /private/tmp/gitlearn/.git/
➜ gitlearn git:(master)
新建完仓库之后,我们一般会对仓库进行配置。
git config
git 自带了一个 git config 工具来帮助设置控制Git外观和行为的配置变量。这些变量存储在三个不同的位置。
A:/etc/gitconfig文件: 包含系统上每一个用户以及他们仓库的通用配置。 如果执行git config时,带上 —system 选项,就会读写该配置文件中的配置属性。B:~/.gitconfig或~/.config/git/config文件: 只针对当前用户。使用--global选项会让git读写此文件,这会对你系统的上的所有仓库生效。C:当前使用仓库的git目录的config文件(.git/config): 只针对当前仓库。 可以使用--local选项让git强制读写此文件, 默认情况下也会使用它。
读取顺序为: A->B->C, C会覆盖B中相同的配置,B会覆盖A中相同的配置。
可以通过 git config —list —show origin 命令查查文件位置以及命令所在的文件。
一般我们新建了仓库,或者 clone 一个远程仓库到本地之后,第一件事就是配置自己的用户名和邮件地址。
刚才说过,三种配置方式的作用范围,这里一般情况下会使用 --global。 当前登录的用户都会使用一样的配置。
$ git config --global user.name "fangjiaxiaobai"
$ git config --global user.email "fangjiaxiaobai@163.com"
这一点非常重要!
我们来查看一下配置的结果。
$ git config --global --list
user.name=fangjiaxiaobai
user.email=fangjiaxiaobai@163.com
修改 git 的默认文本编辑器
git的文本编辑器有什么作用呢?
当我们的文件 在 提交代码,拉取远程代码或者切换分支出现冲突的时候,git命令行窗口就会有一个处理冲突之后填写commit信息的命令行窗口,这里使用的编辑器就是 我们要说的“文本编辑器了”。
git中默认的文本编辑器是 nano 编辑器,我们使用进行配置,使用 vim 编辑器。
➜ gitlearn git:(master) ✗ git config --global core.editor "vim"
➜ gitlearn git:(master) ✗ git config --global -l
user.name=fangjiaxiaobai
user.email=fangjiaxiaobai@163.com
core.editor=vim
配置完仓库,之后,我们就正式开始使用 git 了。
使用 git 进行工作
简单来讲,我们只需三步,两个命令就可以完成文件的版本控制。
- 修改文件(创建文件,修改文件内容,删除文件)
- 使用
git add .将文件纳入版本管理 - 使用
git commit -m "xxx"将文件提交到版本仓库。
在我们的工作目录中(比如 gitlearn/), 所有的文件只有两种状态: 已跟踪和未跟踪。
已跟踪的文件是指被纳入版本控制的文件。在上一次快照中有他们的记录,在工作一段时间后,他们的状态可能是未修改,已修改,或者已经放入了暂存区 。
未跟踪的文件:就是 即不存在上次快照中,也没有被放入暂存区中。
这里我们再次的介绍一下git的工作区域:
工作区,暂存区,版本库。
工作区,就是我们修改的文件。包括:新建文件,修改文件内容,删除文件。
暂存区,就是git将我们修改的文件记录起来起来。
版本库,就是git的记录的版本变更历史。就是 .git目录下的objects/等目录下的所有文件。即我们 进行了commit操作之后就会进入了版本库。
让 git 跟踪我们的文件
使用 git add 命令,可以让git开始跟踪一个文件。
使git跟踪文件 README.md
➜ gitlearn git:(master) echo 'test git跟踪文件' > README.md
# 查看工作区中文件的状态
➜ gitlearn git:(master) ✗ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md
nothing added to commit but untracked files present (use "git add" to track)
这里我们看到了,未跟踪的该文件: README.md。我们可以使用git add命令,将未跟踪的文件纳入跟踪范围。
➜ gitlearn git:(master) ✗ git add README.md
# 查看文件的状态
➜ gitlearn git:(master) ✗ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md
Changes to be committed: 将要提交的变更。说明下面的文件已经是暂存状态了。使用 git rm --cached <file>... 命令可以取消暂存。此时README.md 文件已经是git跟踪的了。我们再次修改一下 README.md 文件。查看一下工作区中文件的状态.
➜ gitlearn git:(master) ✗ echo 'test 再次修改已经被跟踪的文件' >> README.md
➜ gitlearn git:(master) ✗ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md
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: README.md
又看到了Changes not staged for commit: 还没有被暂存的提交去提交。说明第二次的变更还没有被git跟踪起来。这就需要我们在运行一次git add README.md命令了。
➜ gitlearn git:(master) ✗ git add README.md
➜ gitlearn git:(master) ✗ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md
我们可以看到,第二次更改也被git跟踪了起来。
git status 命令的输出十分详细,可以使用git status -s(--short)命令,输出非常简洁的结果.
➜ gitlearn git:(master) ✗ git status -s
A README.md
输出结果的格式是这样的:
XX file1
XX file2
左列XX: 第一个X表示,暂存区的状态,第二个X表示工作区的状态。
XX的规则如下:
- 新添加的未跟踪文件前面有 ?? 标记
- 新添加到暂存区中的文件前面有 A 标记
- 修改过的文件前面有 M 标记。
提交到版本库
现在我们就可以提交文件了。最好在每次提交之前都用 git status 看下,我们需要的文件是否都放入 暂存区了。然后再用 git commit 进行提交。
➜ gitlearn git:(master) ✗ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md
# 提交代码
➜ gitlearn git:(master) ✗ git commit -m "first commit"
[master (root-commit) fb554b5] first commit
1 file changed, 2 insertions(+)
create mode 100644 README.md
可以看到,提交后它会告诉你,当前是在哪个分支(master)提交的,本次提交的完整 SHA-1 校验和是什么(463dc4f),以及在本次提交中,有多少文件修订过,多少行添加和删改过。
以上就是我们最简单的开发流程了。
这时,如果我不想某个文件纳入版本管理,但是这个文件还必须要在工作区中呢?
忽略文件
在这种情况下,我们可以创建一个名为: .gitignore的文件,列出要忽略的文件的模式。
.gitignore文件的格式规范如下:
- 所有空行或者以 # 开头的行都会被 Git 忽略。
- 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中。
- 匹配模式可以以(/)开头防止递归。
- 匹配模式可以以(/)结尾指定目录。
- 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(!)取反。
所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。 星号(*)匹配零个或多个任意字符;[abc] 匹配任何一个列在方括号中的字符 (这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c); 问号(?)只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符, 表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。 使用两个星号(**)表示匹配任意中间目录,比如 a/**/z 可以匹配 a/z 、 a/b/z 或 a/b/c/z 等。
来看一个 .gitignore文件的例子:
# 忽略所有的 .a 文件
*.a
# 但跟踪所有的 lib.a,即便你在前面忽略了 .a 文件
!lib.a
# 只忽略当前目录下的 TODO 文件,而不忽略 subdir/TODO
/TODO
# 忽略任何目录下名为 build 的文件夹
build/
# 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目录及其所有子目录下的 .pdf 文件
doc/**/*.pdf
假设:我们还有一个名叫: git.log的文件。在更早的一个快照中,已经把它纳入了版本库中。现在我们要把它移除掉。应该怎么办呢
### 准备工作
➜ gitlearn git:(master) echo 'test remove logs files' > git.log
➜ gitlearn git:(master) ✗ git add .
➜ gitlearn git:(master) ✗ git commit -m "test remove logs files"
[master b83b8f1] test remove logs files
1 file changed, 1 insertion(+)
create mode 100644 git.log
### 移除 git.log
➜ gitlearn git:(master) git rm git.log
rm 'git.log'
➜ gitlearn git:(master) ✗ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: git.log
# 新建 .gitignore 文件
➜ gitlearn git:(master) ✗ echo '*.log' > .gitignore
➜ gitlearn git:(master) ✗ git add .
# 查看文件的状态
➜ gitlearn git:(master) ✗ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: .gitignore
deleted: git.log
➜ gitlearn git:(master) ✗ echo '*.log' > .gitignore
➜ gitlearn git:(master) ✗ git add .
➜ gitlearn git:(master) ✗ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: .gitignore
deleted: git.log
# 提交文件
➜ gitlearn git:(master) ✗ git commit -m "test remove logs files - remove git.log"
[master 9118876] test remove logs files - remove git.log
2 files changed, 1 insertion(+), 1 deletion(-)
create mode 100644 .gitignore
delete mode 100644 git.log
➜ gitlearn git:(master) git status
On branch master
nothing to commit, working tree clean
# 验证一下git.log文件会不会被git跟踪
# 修改了git.log文件之后,git不会跟踪其变更。
➜ gitlearn git:(master) echo 'test track git.log??' > git.log
➜ gitlearn git:(master) git status
On branch master
nothing to commit, working tree clean
注意:
运行 git rm命令并不能删除文件!是从git中删除,使git不在跟踪其变化。
有时候,使用 git rm 命令并不能使文件不被git跟踪,因为在缓存中还跟踪了文件。 这使,可以使用 git rm -rf --cached 命令使git不跟踪文件。
git rm 命令也可以使用 glob 模式。
查看文件的修改内容
git 提供了一个命令git diff可以查看文件修改了那些地方.
假设:我们修改了一个文件,我要看一下修改的内容(此时还没有提交。)
➜ gitlearn git:(master) echo 'test diff' > README.md
## 查看不同
### 比较的是: 工作目录中当前文件和暂存区域快照之间的差异。
➜ gitlearn git:(master) ✗ git diff
diff --git a/README.md b/README.md
index 2afbeed..b69a2df 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1 @@
-test git跟踪文件
-test 再次修改已经被跟踪的文件
+test diff
使用 --staged 选项可以比较 已暂存文件与最后一次提交的文件差异。
请注意,git diff 本身只显示尚未暂存的改动,而不是自上次提交以来所做的所有改动。 所以有时候你一下子暂存了所有更新过的文件,运行 git diff 后却什么也没有,就是这个原因。
移动文件
可以使用 git mv 命令来移动文件。
➜ gitlearn git:(master) ✗ git mv README.md README.md.md
➜ gitlearn git:(master) ✗ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: README.md -> README.md.md
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: README.md.md
这个命令就相当于:
$ mv README.md README.md.md
$ git rm README.md
$ git add README.md.md
本篇文章就到这里啦,下一篇~ git的时光机
最后
期望与你一起遇见更好的自己
