1.获取Git仓库

Git仓库通常分为2类:1.本地代码未在Git云端上。2.克隆一个已经存在的git仓库。

两种方式都会在你的本地机器上得到一个工作就绪的 Git 仓库。
在已存在目录中初始化仓库 如果你有一个尚未进行版本控制的项目目录,想要用 Git 来控制它,那么首先需要进入该项目目录中。 如果你还没这样做过,那么不同系统上的做法有些不同:

  1. Linux 上:
  2. $ cd /home/user/my_project
  3. macOS 上:
  4. $ cd /Users/user/my_project
  5. Windows 上:
  6. $ cd /c/user/my_project
  7. 之后执行:
  8. $ git init # Git初始化

初始化后,就会在本地生成一个.git的文件夹,这个文件夹里面是Git仓库中的所有文件,但是这个时候文件夹里面并没有将本地的文件和远程关联起来。

  1. $ git add *.c # 将所有文件添加到暂存区
  2. $ git add LICENSE # 将单个文件 “LICENSE” 添加到暂存区
  3. $ git commit -m 'initial project version' # 将暂存区的文件提交到仓库,并添加注释
  4. $ git clone https://github.com/libgit2/libgit2 # 将url的仓库克隆在本地

如果你想在克隆远程仓库的时候,自定义本地仓库的名字,你可以通过额外的参数指定新的目录名:

  1. $ git clone https://github.com/libgit2/libgit2 mylibgit

这会执行与上一条命令相同的操作,但目标目录名变为了 mylibgit。

2.记录每次更新到仓库

请记住,你工作目录下的每一个文件都不外乎这两种状态:**已跟踪****未跟踪**。 已跟踪的文件是指那些被纳入了版本控制的文件,在上一次快照中有它们的记录,在工作一段时间后, 它们的状态可能是未修改,已修改或已放入暂存区。简而言之,已跟踪的文件就是 Git 已经知道的文件。

工作目录中除已跟踪文件外的其它所有文件都属于未跟踪文件,它们既不存在于上次快照的记录中,也没有被放入暂存区。 初次克隆某个仓库的时候,工作目录中的所有文件都属于已跟踪文件,并处于未修改状态,因为 Git 刚刚检出了它们, 而你尚未编辑过它们。

编辑过某些文件之后,由于自上次提交后你对它们做了修改,Git 将它们标记为已修改文件。 在工作时,你可以选择性地将这些修改过的文件放入暂存区,然后提交所有已暂存的修改,如此反复。
image.png
Figure 8. 文件的状态变化周期

2.1检查当前文件状态

可以用 git status 命令查看哪些文件处于什么状态。 如果在克隆仓库后立即使用此命令,会看到类似这样的输出:

  1. $ git status
  2. On branch master
  3. Your branch is up-to-date with 'origin/master'.
  4. nothing to commit, working directory clean

2.2跟踪新文件

  1. $ git add README

此时再运行 git status 命令,会看到 README 文件已被跟踪,并处于暂存状态:

  1. $ git status
  2. On branch master
  3. Your branch is up-to-date with 'origin/master'.
  4. Changes to be committed:
  5. (use "git restore --staged <file>..." to unstage)
  6. new file: README

2.3暂存已修改的文件

要暂存这次更新,需要运行 git add 命令。 这是个多功能命令:可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等。 将这个命令理解为“精确地将内容添加到下一次提交中”而不是“将一个文件添加到项目中”要更加合适。
新添加的未跟踪文件前面有 ?? 标记,新添加到暂存区中的文件前面有 A 标记,修改过的文件前面有 M 标记。 输出中有两栏,左栏指明了暂存区的状态,右栏指明了工作区的状态。例如,上面的状态报告显示:README 文件在工作区已修改但尚未暂存,而 lib/simplegit.rb文件已修改且已暂存。Rakefile 文件已修改,暂存后又作了修改,因此该文件的修改中既有已暂存的部分,又有未暂存的部分。

2.4忽略文件

一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。 通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。 在这种情况下,我们可以创建一个名为.gitignore 的文件,列出要忽略的文件的模式。 来看一个实际的.gitignore 例子:

  1. $ cat .gitignore
  2. *.[oa]
  3. *~

第一行告诉 Git 忽略所有以 .o 或 .a 结尾的文件。一般这类对象文件和存档文件都是编译过程中出现的。 第二行告诉 Git 忽略所有名字以波浪符(~)结尾的文件,许多文本编辑软件(比如 Emacs)都用这样的文件名保存副本。 此外,你可能还需要忽略 log,tmp 或者 pid 目录,以及自动生成的文档等等。 要养成一开始就为你的新仓库设置好 .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 等。

  1. # 忽略所有的 .a 文件
  2. *.a
  3. # 但跟踪所有的 lib.a,即便你在前面忽略了 .a 文件
  4. !lib.a
  5. # 只忽略当前目录下的 TODO 文件,而不忽略 subdir/TODO
  6. /TODO
  7. # 忽略任何目录下名为 build 的文件夹
  8. build/
  9. # 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt
  10. doc/*.txt
  11. # 忽略 doc/ 目录及其所有子目录下的 .pdf 文件
  12. doc/**/*.pdf

2.5 查看已暂存和未暂存的修改

使用 git diff 命令
若要查看已暂存的将要添加到下次提交里的内容,可以用git diff --staged命令。 这条命令将比对已暂存文件与最后一次提交的文件差异

  1. $ git diff --staged
  2. diff --git a/README b/README
  3. new file mode 100644
  4. index 0000000..03902a1
  5. --- /dev/null
  6. +++ b/README
  7. @@ -0,0 +1 @@
  8. +My Project

2.6 提交更新

运行提交命令 git commit -m "Story 182 "

2.7 跳过使用暂存区域

git commit加上 -a 选项,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过git add步骤

2.8 移除文件

git rm [文件名称]
git rm -f [文件名称]注意!运行此命令,会从删除整个文件,无法恢复。
如果只是简单地从工作目录中手工删除文件,运行 git status 时就会在 “Changes not staged for commit” 部分(也就是 未暂存清单)看到:

  1. $ rm PROJECTS.md
  2. $ git status
  3. On branch master
  4. Your branch is up-to-date with 'origin/master'.
  5. Changes not staged for commit:
  6. (use "git add/rm <file>..." to update what will be committed)
  7. (use "git checkout -- <file>..." to discard changes in working directory)
  8. deleted: PROJECTS.md
  9. no changes added to commit (use "git add" and/or "git commit -a")
  10. 然后再运行 git rm 记录此次移除文件的操作:
  11. $ git rm PROJECTS.md
  12. rm 'PROJECTS.md'
  13. $ git status
  14. On branch master
  15. Your branch is up-to-date with 'origin/master'.
  16. Changes to be committed:
  17. (use "git reset HEAD <file>..." to unstage)
  18. deleted: PROJECTS.md

下一次提交时,该文件就不再纳入版本管理了。

2.9 移动文件

不像其它的 VCS 系统,Git 并不显式跟踪文件移动操作。 如果在 Git 中重命名了某个文件,仓库中存储的元数据并不会体现出这是一次改名操作。 不过 Git 非常聪明,它会推断出究竟发生了什么,至于具体是如何做到的,我们稍后再谈。
既然如此,当你看到 Git 的 mv 命令时一定会困惑不已。 要在 Git 中对文件改名,可以这么做:
$ git mv file_from file_to
它会恰如预期般正常工作。 实际上,即便此时查看状态信息,也会明白无误地看到关于重命名操作的说明:

  1. $ git mv README.md README
  2. $ git status
  3. On branch master
  4. Your branch is up-to-date with 'origin/master'.
  5. Changes to be committed:
  6. (use "git reset HEAD <file>..." to unstage)
  7. renamed: README.md -> README

其实,运行 git mv 就相当于运行了下面三条命令:

  1. $ mv README.md README
  2. $ git rm README.md
  3. $ git add README

如此分开操作,Git 也会意识到这是一次重命名,所以不管何种方式结果都一样。 两者唯一的区别在于,git mv 是一条命令而非三条命 令,直接使用 git mv 方便得多。 不过在使用其他工具重命名文件时,记得在提交前 git rm 删除旧文件名,再 git add 添加新文件名。

3.查看提交历史

git log
git log -p -2 显示每次提交所引入的差异,也可以限制2条显示的日志条数。
git log --stat 显示每次提交的简略统计信息。

  1. --since, --after仅显示指定时间之后的提交。
  2. --until, --before仅显示指定时间之前的提交。
  3. --author仅显示作者匹配指定字符串的提交。
  4. --committer仅显示提交者匹配指定字符串的提交。
  5. --grep仅显示提交说明中包含指定字符串的提交。
  6. -S仅显示添加或删除内容匹配指定字符串的提交。

tips

隐藏合并提交 按照你代码仓库的工作流程,记录中可能有为数不少的合并提交,它们所包含的信息通常并不多。 为了避免显示的合并提交弄乱历史记录,可以为 log 加上--no-merges选项。

4.撤销操作

有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。 此时,可以运行带有 --amend 选项的提交命令来重新提交:

  1. $ git commit -m 'initial commit'
  2. $ git add forgotten_file
  3. $ git commit --amend

最终你只会有一个提交——第二次提交将代替第一次提交的结果。

4.1 取消暂存文件

git reset HEAD

  1. $ git reset HEAD CONTRIBUTING.md
  2. Unstaged changes after reset:
  3. M CONTRIBUTING.md
  4. $ git status
  5. On branch master
  6. Changes to be committed:
  7. (use "git reset HEAD <file>..." to unstage)
  8. renamed: README.md -> README
  9. Changes not staged for commit:
  10. (use "git add <file>..." to update what will be committed)
  11. (use "git checkout -- <file>..." to discard changes in working directory)
  12. modified: CONTRIBUTING.md

4.2 撤销对文件的修改

git checkout -- [filename]

git checkout — 是一个危险的命令。 你对那个文件在本地的任何修改都会消失——Git 会用最近提交的版本覆盖掉它。 除非你确实清楚不想要对那个文件的本地修改了,否则请不要使用这个命令。

如果你仍然想保留对那个文件做出的修改,但是现在仍然需要撤消,我们将会在 Git 分支 介绍保存进度与分支,这通常是更好的做法。 记住,在 Git 中任何 已提交 的东西几乎总是可以恢复的。 甚至那些被删除的分支中的提交或使用 —amend 选项覆盖的提交也可以恢复 (阅读 数据恢复 了解数据恢复)。 然而,任何你未提交的东西丢失后很可能再也找不到了。

5.远程仓库的使用