所在位置:

Pro Git 读书笔记

这是记录Pro Git的读书笔记,有些内容会根据自己的理解加以注释,温故而知新,当中还是可以学到不少知识的

版本控制

版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。

版本控制分为:

  • 集中化的版本控制系统 (CVS、Subversion 以及Perforce等)

  • 分布式版本控制系统(Git、Mercurial、Bazaar 以及 Darcs等)

Git基础

Git有三种状态:

  • 已提交(committed):已提交表示数据已经安全的保存在本地数据库中
  • 已修改(modified):已修改表示修改了文件,但还没保存到数据库中
  • 已暂存(staged):已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中

Git的三个工作区域:

  • 工作目录:对项目的某个版本独立提取出来的内容
  • 暂存区域:是一个文件,保存了下次将提交的文件列表信息
  • Git仓库:Git用来保存项目的元数据和对象数据库的地方

基本的 Git 工作流程如下:

  • 在工作目录中修改文件
  • 暂存文件,将文件的快照放入暂存区域
  • 提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库目录

初次运行 Git 前的配置,有三个地方:

  • /etc/gitconfig文件: 包含系统上每一个用户及他们仓库的通用配置
  • ~/.gitconfig或 ~/.config/git/config文件:只针对当前用户,可以传递 --global选项让 Git读写此文件
  • 当前使用仓库的 Git 目录中的 config文件(就是 .git/config):针对该仓库

注意:每一个级别覆盖上一级别的配置,所以 .git/config的配置变量会覆盖 /etc/gitconfig中的配置变量

获取 Git 仓库

  • 在现有目录中初始化仓库
git init
  • 克隆现有的仓库
git clone url

记录每次更新到仓库

  • 检查当前文件状态
git status
  • 跟踪新文件
git add file
  • 暂存已修改文件

现在我们来修改一个已被跟踪的文件。 如果你修改了一个名为 CONTRIBUTING.md的已被跟踪的文件,然后运行 git status命令,会看到下面内容:

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

    new file: README

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:  CONTRIBUTING.md

文件 CONTRIBUTING.md出现在 Changes not staged for commit这行下面,说明已跟踪文件的内容发生了变化,但还没有放到暂存区。 要暂存这次更新,需要运行 git add命令。 这是个多功能命令:可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等。 将这个命令理解为“添加内容到下一次提交中”而不是“将一个文件添加到项目中”要更加合适。

状态简览

git status -s

示例

$ git status -s
M README
MM Rakefile
A  lib/git.rb
M  lib/simplegit.rb
?? LICENSE.txt

说明:新添加的未跟踪文件前面有 ??标记,新添加到暂存区中的文件前面有 A标记,修改过的文件前面有 M标记。 你可能注意到了 M有两个可以出现的位置,出现在右边的 M(红色)表示该文件被修改了但是还没放入暂存区,出现在靠左边的 M(绿色)表示该文件被修改了并放入了暂存区。

忽略文件

在根目录创建 .gitignore 文件

文件 .gitignore的格式规范如下:

  • 所有空行或者以 #开头的行都会被 Git 忽略。
  • 可以使用标准的 glob 模式匹配。
  • 匹配模式可以以(/)开头防止递归。
  • 匹配模式可以以(/)结尾指定目录。
  • 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。

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

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

# 比较的是工作目录中当前文件和暂存区域快照之间的差异
git diff

# 比较暂存区域快照和仓库之间的差异
git diff --cached

提交更新

# 只会提交在暂存里的文件,没有 git add 不会提交的
git commit -m "提交信息"

# 把所有已跟踪的文件进行提交,新的文件如果没有 git add 则不会提交,直接跳过暂存区域
git commit -a -m "提交信息"

移除文件

# 先手工删除文件,再运行这个命令
git rm file

# 把工作区和暂存区的文件删除
git rm -f file

# 把暂存区的文件删除,保留文件在工作区
git rm --cached file

移动文件

# 重命名文件
git mv src_file des_file

git mv 命令相当于:

mv README.md README
git rm README.md
git add README

查看提交历史

git log

# 一个常用的选项是 -p,用来显示每次提交的内容差异。 你也可以加上 -2 来仅显示最近两次提交:
git log -p -2

# 查看提交的简略的统计信息
git log --stat

# 一行显示
git log --pretty=oneline

取消暂存的文件

# 取消暂存的文件
git reset HEAD file

撤消对文件的修改

# 撤消对文件的修改,还原成上次提交时的样子
git checkout -- file

远程仓库的使用

  • 查看远程仓库
# 查看远程仓库
git remote

# 查看远程仓库,显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL
git remote -v
  • 添加远程仓库
# 添加一个新的远程 Git 仓库,shortname是别名
git remote add <shortname> <url>

示例:

git remote add pb https://github.com/paulboone/ticgit

现在你可以在命令行中使用字符串 pb 来代替整个 URL

git fetch pb
  • 从远程仓库中抓取与拉取
# 将数据拉取到你的本地仓库,它并不会自动合并或修改你当前的工作
git fetch [remote-name]

# 自动抓取然后合并远程分支到当前分支
git pull [remote-name]

说明:git fetch 运行之后,可以使用 git diff origin/master 用本地分支跟远程分支做对比,用 git merge origin/master 进行合并,git pull 相当于执行了 git fetch 和 git merge 这两个命令

  • 推送到远程仓库
# 推送到远程服务器
git push [remote-name] [branch-name]

# 当你想要将 master 分支推送到 origin 服务器时,远程服务器可以使用 git remote 查看
git push origin master
  • 查看远程仓库
# 查看某一个远程仓库的更多信息,这些信息非常有用
git remote show [remote-name]
  • 远程仓库的移除与重命名
# 重命名远程仓库名字
git remote rename 已经存在的名字 要修改的名字

# 移除远程仓库名字
git remote rm 名字

打标签

  • 列出标签
# 查看标签
git tag
  • 创建标签
# 创建附注标签
git tag -a v1.4 -m 'my version 1.4'

# 创建轻量标签
git tag v1.4-lw

Git 分支

Pro Git 分支这块写得挺好的,可以认真去看看

# 分支创建
git branch new_branch

# 分支切换
git checkout branch_name

# 输出你的提交历史、各个分支的指向以及项目的分支分叉情况
git log --oneline --decorate --graph --all

# 建立分支并立即切换到新分支
git checkout -b new_branch

# 删除分支
git branch -d branch_name

# 强制删除分支
git branch -D branch_name

# 把branch_name合并到当前分支
git merge branch_name

# 查看每一个分支的最后一次提交
git branch -v

# 查看哪些分支已经合并到当前分支
git branch --merged

# 查看哪些分支没有合并到当前分支
git branch --no-merged

# 把远程的origin/serverfix分支建立为本地名为serverfix的分支
git checkout -b serverfix origin/serverfix

# 查看设置的所有跟踪分支,如每一个分支正在跟踪哪个远程分支与本地分支是否是领先、落后或是都有
git branch -vv

变基

  • 变基的基本操作

之前介绍过,整合分支最容易的方法是 merge 命令。 它会把两个分支的最新快照(C3 和 C4)以及二者最近的共同祖先(C2)进行三方合并,合并的结果是生成一个新的快照(并提交)。

其实,还有一种方法:你可以提取在 C4 中引入的补丁和修改,然后在 C3 的基础上应用一次。 在 Git 中,这种操作就叫做 变基。 你可以使用 rebase 命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样。

在上面这个例子中,运行:

$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command

它的原理是首先找到这两个分支(即当前分支 experiment、变基操作的目标基底分支 master)的最近共同祖先 C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件,然后将当前分支指向目标基底 C3, 最后以此将之前另存为临时文件的修改依序应用。(译注:写明了 commit id,以便理解,下同)

现在回到 master 分支,进行一次快进合并。

$ git checkout master
$ git merge experiment

此时,C4' 指向的快照就和上面使用 merge 命令的例子中 C5 指向的快照一模一样了。 这两种整合方法的最终结果没有任何区别,但是变基使得提交历史更加整洁。 你在查看一个经过变基的分支的历史记录时会发现,尽管实际的开发工作是并行的,但它们看上去就像是串行的一样,提交历史是一条直线没有分叉。

请注意,无论是通过变基,还是通过三方合并,整合的最终结果所指向的快照始终是一样的,只不过提交历史不同罢了。 变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起。

总结

  • 了解git的三种状态:已提交、已修改、已暂存

  • 了解git的三个工作区域:工作目录、暂存区域、Git仓库

  • 我们的任何操作都离不开git的三个工作区域和三种状态

  • 会git的基本操作,比如查看提交记录、当前的状态、删除、撤消、添加等等

  • 会写简单的忽略文件

  • 会使用分支、标签、远程操作

  • 了解变基的使用场景

【上一篇】git常用命令

【下一篇】Flutter的安装和配置