Git的使用

一、认识 Git

1. Git 和替他版本控制系统的差异

a. 直接记录快照,非差异比较

  • git 和其他版本控制系统主要差别在于对 Git 对待数据的方法。其他版本控制系统(CVS、Subversion等等)大部分都是一文件变更列表的方式存储信息,将保存信息看做一组基本文件和每个文件跟随时间逐步积累的差异。
image-20201019193124074
  • Git 对待数据更像是快照流: 将数据看做是对小型文件的一组快照。每次提交之后/保存项目状态时,对当时的全部文件制作一个快照,并保存这个快照的索引。如果文件没有修改,Git 就不再重新存储,只保留一个链接指向之前存的文件(更高效)。
image-20201019193646321

b. 本地执行,更安全,更便捷

  • Git 在克隆代码时,会将项目的完整历史保存在本地磁盘,与服务器形成分布式系统,增加项目的安全性。
  • Git 在本地磁盘有完整的历史,则Git绝大多数操作都只需要访问本地文件和资源,不会需要网络上的项目信息,使用起来更加便捷(如在离线环境可以进行除了向远程提交修改的操作外的其他操作,等有网络后,在推送到远程服务器)。

c. 保证完整性

Git 中所有数据在存储前都计算检验和(SHA-1散列机制,由40个十六进制字符组成的字符串),然后以检验和来引用,这意味着 Git 对更改文件任何内容或目录都可知。保证文件不会在不知情情况下损坏或丢失信息。

d. Git 一般只添加数据

Git 操作几乎只往数据库中增加数据。很难让 Git 执行任何不可逆操作,或者让它以任何方式清除数据(未提交的本地修改可能会丢失或弄乱修改内容)。

2. Git 的工作区

Git有三种状态: 已提交(committed),已修改(modified),和已暂存(staged)。已提交表示数据已安全保存在本地数据库中。已修改表示修改了文件,但还没保存到数据库中。已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。
由此可引入 Git 的三个工作区域:

  1. Git 仓库: Git 用来保存项目的元数据和对象数据库的地方。
  2. 工作目录: 对项目的某个版本独立提起出来的内容。在磁盘上公使用或修改。
  3. 暂存区域: 是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中,也被称作“索引”。

Git 在三个区域的工作流程如下:

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

二、Git的配置

1. Git 的下载安装

Git下载地址:https://git-scm.com/download

选择自己合适的版本进行下载

下载之后选择路径,默认安装就好。

2. 初次运行 Git 前的配置

Git 自带一个 git config 的工具来帮助设置控制 Git 外观和行为的配置变量,这些变量存储在三个不同的位置:

  • /etc/gitconfig文件:包含系统上每一个用户及他们仓库的通用配置。如果使用带有--system选项的 git config 时,它会从此文件读写配置变量。

  • ~/.gitconfig~/.config/git/config 文件:只针对当前用户。可以传递 --global 选项让 Git 读写此文件。

  • 当前使用仓库的 Git 目录中的 config 文件(``.git/config):针对该仓库

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

3. 用户信息配置

安装完 Git 需要设置用户名和右键地址。这些信息会写入到后面的每一次提交中,不可更改:

$ git config --global user.name "Your UserName"
$ git config --global user.email "Your Email Address"

如果使用了 --global 选项,改命令只需要运行一次,之后在改系统上进行任何 Git 操作,都会使用这些信息。如果想针对特定项目使用不同的用户名和邮箱信息,则可以在那个项目目录下运行没有 --global 选项的命令来配置。

4. 检查配置信息

可以使用 git config --list 命令来列出所有 Git 当前能找到的配置。

$ git config --list
color.status=auto
color.branch=auto
color.interactive=auto
color.diff=auto
...
user.name=Your UserName
user.email=Your Email Address

可以通过 git config <key> 来检查 Git 的某一项配置

$ git config user.name
Your UserName

三、Git的使用

1、获取 Git 仓库

1.1 从服务器克隆一个现有的 Git 仓库

​ 如果已经在服务器存在了 Git 仓库,则使用 git clone 命令。这里和其他 VCS 系统不同的时 Git 克隆是将菜 Git 仓库服务器上的几乎所有数据复制到本地磁盘,而不是仅仅复制完成工作所需的文件。可以使用任何一个克隆下来的用户端来重建服务器上的仓库。

Git 支持多种传输协议:https://协议, git:// 协议,SSH 传输协议(如:user@server:path/to/repo.git)。

**克隆仓库的命令格式是git clonr [url] **:

$ git clone https://github.com/libgit2/libgit2
这会在当前目录下创建一个名为"libgit2" 的目录,并在这个目录下初始化一个 ``.git`` 文件夹,从远程仓库拉取的所有数据都会放入 ``.git`` 文件夹,然后从中读取最新版本的文件拷贝。进入这个新建的 “libgit2” 文件夹,会看到所有的项目文件已经在里面了,可以开始后续的开发和使用。

如果想在克隆仓库的时候自定义本地仓库的名字,可以使用如下命令:

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

这个上一个命令执行相同的操作,只是在本地创建的文件夹名字变为“mylibgit”

1.2 在现有目录中初始化仓库

如果打算在新的目录中使用 Git 进行项目管理,可有在改牡蛎下进行初始化仓库

$ git init

该命令将创建一个名为 .git 的文件夹,这个文件夹含有初始化的 Git 仓库中所有的必须文件。

如果在一个已经存在的文件夹中初始化 Git 仓库,则应该跟踪这些文件并提交。

Git 通过 git add 命令来实现对指定文件的跟踪,通过执行 git commit 命令来提交文件。

$ git add test.txt
$ git commit -m "init project"

2. 仓库更新相关

仓库文件在修改后,有两种状态:已跟踪(被纳入版本控制的文件,在上一次快照中有它们的记录,在工作一段时间后,它们的状态可能处于未修改,已修改或已放入暂存区)或未跟踪(除已跟踪文件外的所有文件,既不存在于上次快照记录中,也没放入暂存区)。

2.1 检测当前文件状态

使用 git status 命令来查看文件处于什么状态

$ echo 'My Project' > README
$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
    README
nothing added to commit but untracked files present (use "git add" to
track)

可以看到当前分支处于 master 分支,在当前仓库中发现一个未跟踪文件 “README”

2.2 跟踪新文件

使用git add 命令跟踪一个文件

$ git add README 

此时在运行 git status 命令,可以看到 README 文件一杯跟踪,并处于暂存状态

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

只要在 Changes to be committed 这行下面的,就说明是已暂存状态。

git add 命令使用文件或目录的路径作为参数,如果参数是目录路径,则改命令将递归跟踪改目录下所有文件。

2.3 暂存已修改文件

修改一个已经被跟踪的文件,如 test.txt ,然后运行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:   test.txt

文件 test.txt 出现在 Changes not staged for commit 下面,说明已跟踪文件发生变化,但还没有放到暂存区,要暂存这次更新,需要运行git add命令。

git add是个多功能命令,可以用它开始跟踪文件;或者把已跟踪的文件放到暂存区;还能用于合并时将有冲突的文件标记位已解决状态等。

接下来运行 git add 命令将 test.txt 文件放到暂存区,然后在看看 git status 的输出

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

	new file:   README
	modified:   test.txt

再次修改 test.txt 文件,然后运行 git status 命令查看文件状态:

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

	new file:   README
	modified:   test.txt

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:   test.txt

可以看到 test.txt 文件同时出现在了暂存区和非暂存区。如果此时进行提交,test.txt 文件的版本是最后一次运行git add 命令时的那个版本,而不是运行git commit时,工作目录中的版本。所以在运行了git add 之后有做了修订的文件,需要重新运行git add把最新版本重新 暂存起来。

2.4 文件状态预览

git status 命令输出非常详细,如果使用git status -s命令或git status --short 命令,将得到一种更为紧凑的格式输出。

$ git status -s           
A  README
MM test.txt
A  version
?? LICENSE.txt
  • 新添加的未跟踪文件前有 ??标记
  • 新添加到暂存区中的问价前有 A标记
  • 修改或的文件前面有 M标记
  • 出现在右边的 M 表示该问家被修改了但还没有放入暂存区
  • 出现在左边的 M 表示改文件被修改了并放入了暂存区。

2.4 忽略文件

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

$ cat .gitignore 
*.iml
*.log
*.tmp
/build/
  • 第一,二,三行告诉 Git 忽略所有以 .iml,以.log,以.tmp结尾的文件
  • 第四行告诉Git 忽略build文件夹中的所有文件

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

  1. 所有空行或者以#开头的行都会被 Git 忽略
  2. 可以使用标准的 glob 模式匹配
  3. 匹配模式可以以 / 开头房子递归
  4. 匹配模式可以以 / 结尾指定目录
  5. 要忽略指定模式以外的文件或目录,可以在模式前加上 ! 取反。

所谓 glob 模式是指 shell 所使用的简化了的正则表达式。

  • * 匹配零个或多个任意字符
  • [abc] 匹配任何一个列在方括号中的字符(要么匹配一个a,要么匹配一个 b,要么匹配一个 c)
  • [0-9] 在方括号中使用短划线分隔两个字符,表示在这两个字符范围内的都可以匹配。
  • ? 只匹配一个任意字符
  • a/**/z 使用两个 型号表示匹配任意中间目录

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

如果git status命令输出过于模糊,想知道具体修改了深地方,可以用git diff 命令。

$ git diff
diff --git a/test.txt b/test.txt
index 9c9852f..bb08ffe 100644
--- a/test.txt
+++ b/test.txt
@@ -1,3 +1,6 @@
 This is test file
 
 modified
+
+
+modefied  two

此命令比较的是工作目录中当前暂存文件和暂存区域快照之间的差异,也就是修改之后还没有暂存起来的变化内容。

若要查看已暂存的将要添加到下移提交的内容里,可以用git diff --cached命令。(Git 1.6.1及更高版本允许使用git diff --staged,效果相同。)

$ git diff --staged
diff --git a/README b/README
new file mode 100644
index 0000000..cd19876
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+My Project-
diff --git a/test.txt b/test.txt
index 9915fa7..9c9852f 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1,3 @@
-This is test file-
+This is test file
+
+modified
diff --git a/version b/version
new file mode 100644
index 0000000..6029d7f
--- /dev/null
+++ b/version
@@ -0,0 +1,2 @@
+version: 1.0.0
+code: 100

2.6 提交更新

在提交更新之前,需要确认一下是否还有什么修改过的文件或者新建的文件没有git add 过,否则提交的时候不会记录这些没暂存起来的变化。这些修改过的文件只保留在本地磁盘。

$ git commit

这种方式会启动文本编辑器以便输入本次提交的说明。


# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
# Changes to be committed:
#       new file:   README
#       modified:   test.txt
#       new file:   version
#
# Changes not staged for commit:
#       modified:   test.txt
#
# Untracked files:
#       .gitignore
#       LICENSE.txt
#
~".git/COMMIT_EDITMSG" 17L, 358C

可以看到,默认的提交消息包含最后一次运行git status 的输出,放在注释行里。另外开头还有一空行,用于输入提交说明。退出编辑器时,Git 会丢掉注释行,用输入的提交福袋信息生成一次提交。

也可以在 commit 命令后添加 -m选项,将提交信息语命令放在同一行。

$ git commit -m"update text.txt; add README,version File"
[master ba93592] update text.txt; add README,version File
 3 files changed, 6 insertions(+), 1 deletion(-)
 create mode 100644 README
 create mode 100644 version

可以看到,在提交的信息中会告诉当前是在哪个分支(master)提交的,本次提交的完整 SHA-1校验和(ba93592),以及本次提交中,有多少文件修订过,多少行添加和删改过。

提交时记录的是放在暂存区域的快照。任何还未暂存的文件仍然保持已修改状态,可以在下次提交时纳入版本管理。每一次运行提交操作,都是对项目做一次快照,以后可以回到这个状态,或者进行比较。

2.7 跳过使用暂存区域

尽管使用暂存区域的方式可以精心准备要提交的细节,但有时候这么做略显繁琐。Git提供了一个跳过使用暂存区域的方式,只要在提交的时候,给git commit 加上 -a 选项,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过git add 步骤:

$  git commit -a -m 'added .gitignore'    
[master 57e60ca] added .gitignore
 1 file changed, 3 insertions(+)

2.8 移除文件

要从 Git 中移除某个文件,就必须要从已跟踪的文件清单中移除(从暂存区域移除),然后提交。可以用git rm命令完成此项工作,并连带从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清单中了。

如果只是简单的从工作目录中手工删除文件,运行git status时就会在“Changes not staged for

commit” (未暂存清单)部分看到

$ rm test.txt 
$ git status
On branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	deleted:    test.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	.gitignore
	LICENSE.txt

no changes added to commit (use "git add" and/or "git commit -a")

然后在运行git rm 记录此次移除文件的操作:

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

	deleted:    test.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	.gitignore
	LICENSE.txt

下一次提交时,改文件就不再纳入版本管理了。如果删除之前修改过并切已经放到暂存区域的话,则必须要用强制删除选项 -f(force 首字母)。用于防止巫山还没有添加到快照的数据,这样的数据不能被 Git 恢复。

另外一种情况是:我们想把文件从 Git 仓库中删除(亦从暂存区玉移除),但仍然希望保留在当前工作目录中。换句话说,你想让文件保留在磁盘,但是不想让 Git 继续跟踪。当你忘记添加 .gitignore 文件,不小心把一个很大的日志文件或一堆编译生成的文件添加到暂存区时,可以使用这一做法。使用--cached 选项。

$ git rm --cached test.txt

git rm 命令后面可以列出文件或者目录的名字,也可以使用 glob 模式。比方说:

$ git rm log/\*.log

注意到星号 * 之前的反斜杠 \,因为 Git 有它自己的文件模式扩展匹配方式,所以我们不用 shell 来帮忙展开。

此命令删除 log/ 目录下扩展名为 .log 的所有文件。

2.9 移动文件

Git 并不显示跟踪文件移动操作。如果在 Git 中重名了了某个文件,仓库中存储的元数据并不会体现出这是一次改名操作。

要在 Git 中对文件改名,可以这么做:

$ git mv file_from file_to

此时查看状态信息,也可以看到重命名操作的说明

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

	renamed:    README -> README.md
	deleted:    test.txt

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

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

3. 查看提交历史

git log命令可以在提交了若干更新或者克隆了某个项目之后,回顾提交历史。

$ git log
commit f974236b7551a860b5c31c184cff66a66970603d (HEAD -> master)
Author: TestUserName <test@example.com>
Date:   Thu Oct 22 19:50:29 2020 +0800

    add .gitignore LICENSE.txt

commit 29fb9b4a159899da5675c132b64f1bcf0170c7a5
Author: TestUserName <test@example.com>
Date:   Thu Oct 22 19:17:14 2020 +0800

    added .gitignore

commit ba935920d4afc2121b674f933bada9d1c9791fa0
Author: TestUserName <test@example.com>
Date:   Thu Oct 22 17:56:01 2020 +0800

    update text.txt; add README,version File

commit 4ee1d4d20421d9276bc80808276207940695bbff
Author: TestUserName <test@example.com>
Date:   Thu Oct 22 10:51:17 2020 +0800

    init

默认不用任何参数的话,git log 会按照提交时间列出所有的更新,最近的更新排在最上面。这个命令会列出每个提交的 SHA-1校验和、作者的名字和电子邮件地址、提交时间以及提交说明。

git log 有许多选项可以用来搜寻索要找的提交,下面列出一下最常用的:

-p 用来显示每次提交的内容差异,也可以加上 -2来仅显示最近两次提交

$ git log -p -2
commit f974236b7551a860b5c31c184cff66a66970603d (HEAD -> master)
Author: TestUserName <test@example.com>
Date:   Thu Oct 22 19:50:29 2020 +0800

    add .gitignore LICENSE.txt

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..40c74dc
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*.iml
+*.log
+*~
+*.tmp
+
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..6b1d0bf
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1 @@
+LICENSE
diff --git a/README b/README.md
similarity index 100%
rename from README
rename to README.md
diff --git a/test.txt b/test.txt
deleted file mode 100644
index bb08ffe..0000000
--- a/test.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is test file
-
-modified
-
-
-modefied  two
commit 29fb9b4a159899da5675c132b64f1bcf0170c7a5
Author: TestUserName <test@example.com>
Date:   Thu Oct 22 19:17:14 2020 +0800

    added .gitignore

diff --git a/test.txt b/test.txt
index 9c9852f..bb08ffe 100644
--- a/test.txt
+++ b/test.txt
@@ -1,3 +1,6 @@
 This is test file
 
 modified
+
+
+modefied  two

如果想看到每次提交的简略的统计信息,可以使用--stat选项

--stat 选项在每次提交的下面列出额所有被修改过的文件、有多少文件被修改了以及被修改过的文件的哪些行被移除或是添加了。

$ git log --stat
commit f974236b7551a860b5c31c184cff66a66970603d (HEAD -> master)
Author: TestUserName <test@example.com>
Date:   Thu Oct 22 19:50:29 2020 +0800

    add .gitignore LICENSE.txt

 .gitignore          | 5 +++++
 LICENSE.txt         | 1 +
 README => README.md | 0
 test.txt            | 6 ------
 4 files changed, 6 insertions(+), 6 deletions(-)

commit 29fb9b4a159899da5675c132b64f1bcf0170c7a5
Author: TestUserName <test@example.com>
Date:   Thu Oct 22 19:17:14 2020 +0800

    added .gitignore

 test.txt | 3 +++
 1 file changed, 3 insertions(+)

commit ba935920d4afc2121b674f933bada9d1c9791fa0
Author: TestUserName <test@example.com>
Date:   Thu Oct 22 17:56:01 2020 +0800

    update text.txt; add README,version File

 README   | 1 +
 test.txt | 4 +++-
 version  | 2 ++
 3 files changed, 6 insertions(+), 1 deletion(-)

commit 4ee1d4d20421d9276bc80808276207940695bbff
Author: TestUserName <test@example.com>
Date:   Thu Oct 22 10:51:17 2020 +0800

    init

 test.txt | 1 +
 1 file changed, 1 insertion(+)

--pretty 选项可以指定使用不同语默认格式的方式展示提交历史。

这个选项还有一些内建子选项可以使用,比如 oneline 将每个提交放在一行显示,查看的提交数很大时非常有用,另外还有 shortfullfuller ,展示的信息或多或少有些不同。

$ git log --pretty=oneline
f974236b7551a860b5c31c184cff66a66970603d (HEAD -> master) add .gitignore LICENSE.txt
29fb9b4a159899da5675c132b64f1bcf0170c7a5 added .gitignore
ba935920d4afc2121b674f933bada9d1c9791fa0 update text.txt; add README,version File
4ee1d4d20421d9276bc80808276207940695bbff init

format 可以定制要显示的记录格式。这样的输出对后期提取分析格外有用。

$ git log --pretty=formate:"%h - %an, %ar : %s"
formate:f974236 - TestUserName, 19 hours ago : add .gitignore LICENSE.txt
formate:29fb9b4 - TestUserName, 20 hours ago : added .gitignore
formate:ba93592 - TestUserName, 21 hours ago : update text.txt; add README,version File
formate:4ee1d4d - TestUserName, 28 hours ago : init

git log --pretty=format 常用的选项 列出了常用的格式占位符写法及其代表的意义。

选项 说明
%H 提交对象(commit)的完整哈哈希字符串
%h 提交对象的剪短哈希字符串
%T 树对象(tree)的完整哈希字符串
%t 树对象的简短哈希字符串
%P 父对象(parent)的完整哈希字符串
%p 父对象的简短哈希字符串
%an 作者(author)的名字
%ae 作者的电子邮件
%ad 作者修订日期,可以用–date=选项定制格式,``–date=(relative
%ar 作者修订日期,按多久以前的方式显示
%cn 提交者(committer)的名字
%ce 提交者的电子邮件地址
%cd 提交日期
%cr 提交日期,按多久以前的方式显示
%s 提交说明

作者指的是实际做出修改的人

提交者指的是最后将次工作成功提交到仓库的人

当某个项目发布不定,然后某个人核心成员将你的补丁并入项目时,你就是作者,而那个核心成员就是提交者。

onelineformat 与另一个log 选项 --graph 结合使用时尤其有用。这个选项添加了一些ASCII字符串来形象地展示你的分支、合并历史:

$ git log --pretty=format:"%h %s" --graph

git log常用选项

选项 说明
-p 按补丁格式显示每个更新之间的差异
–stat 显示每次更新的文件系统修改统计信息
–shortstat 只显示–stat中最后的行数修改添加移除统计
–name-only 仅在提交信息后显示已修改的文件清单
–name-status 显示新增、修改、删除的文件清单
–abbrev-commit 仅显示 SHA-1 的前几个字符,而非所有的40个字符
–relative-date 使用较短的相对时间显示(比如:“2 weeks ago”)
–graph 显示 ASCII 图形表示的分支合并历史
–pretty 使用其他格式显示历史提交信息。可以的选项包括 online,short,full,fuller和 format

限制输出长度

除了定制输出格式的选项之外,git log 还有许多非常使用的限制输出长度的选项,也就是只输出部分提交信息。前面提到的 -2(-<n>) ,初次之外还有按照时间做闲职的选项,比如--since--until

$ git log --since=2.weeks

这个命令可以在多种格式下工作,比如具体某一天"2008-08-08",或者相对多久以前"1 years 2day 3 minutes ago"

另一个非常有用的筛选选项是 -S,可以列出那些添加或者移除了某些字符的提交。

$ git log -S function_name

git log [文件路径] 可以查看选择文件或目录的历史提交

git log 常用输出限制选项

选项 说明
-(n) 仅显示最近的n 条提交 ,如 -2.
–since,–after 仅显示指定时间之后的提交
–until,–before 仅显示指定时间之前的提交
–author 仅显示指定作者相关的提交
–committer 仅显示指定提交者相关的提交
-grep 仅显示包含知道关键字的提交
-S 仅显示添加或移除了某个关键字的提交

4. 撤销操作

4.1 重新提交

在某些情况下,发现漏了几个文件没有提交,或者是提交信息写错了,此时 ,可以运行带有 --amend 选项的命令尝试重新提交

$ git commit --amend

该命令会将暂存区中的文件提交。如果自上次提交依赖还未做任何改变,快照会保持不变,所修改的只是提交信息。最终只会有一个提交(第二次提交会代替第一次提交的结果)。

4.2修改倒数第n次commit

git rebase -i HEAD~[倒数第n次commit]

$ git rebase -i HEAD~2//修改倒数第二次 commit

执行该命令,会出现编辑窗口,在命令界面编辑倒数第n次提交的commit 前的 pick 为 e 表示编辑

pick eae306bcae change:commit msg

# Rebase 60e669d341..eae306bcae onto 60e669d341 (1 command)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.

改为

e eae306bcae change:commit msg

# Rebase 60e669d341..eae306bcae onto 60e669d341 (1 command)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.

然后点击 Esc 键,退出编辑模式,使用:wq 命令保存本次编辑。

然后可以对此次提交的文件进行修改 ,该操作会使本地git创建一个临时修改分支,再修改完成后,使用命令回到刚才的分支,并合并修改到刚才分支

修改完成后,使用 git add 命令,添加修改文件索引

$ git add A.java

使用一下命令将本次修改追加到此次修改的commit 中,也可以再该命令后修改 commit msg ,然后使用 :wq 命令保存修改的 commit msg

$ git commit --amend

使用以下命令回到刚才的分支,并合并修改到刚才分支

$ git rebase --continue

使用git push 命令将修改推送到远程

$ git push origin develop

4.3 取消暂存的文件

如果需要将已经添加到暂存区的文件取消暂存,可以使用git reset 命令。

$ git reset HEAD test.txt
Unstaged changes after reset:
M	test.txt

在调用时加上--hard 选项可以令git reset 成为一个危险的命令,会将该项目中的修改丢失。

4.4 撤销对文件的修改

如果在修改了一段代码后,没有解决问题,所以不想保留该文件的修改是,可以使用git checkout -- <file> 命令来将文件还原成上次提交时的样子。

$ git status
On branch master
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

no changes added to commit (use "git add" and/or "git commit -a")
$ git checkout -- README.md
$ git status
On branch master
nothing to commit, working tree clean

5、隐藏本地修改

如果当前修改没修改完,紧急修复一个 bug时,需要先将当前修改内容隐藏,修改完 bug 后,回来继续修改,则可以使用git stash 命令来进行隐藏修改操作

$ git stash save "隐藏说明信息" 

改命令会将当前修改的已跟踪文件进行隐藏,保存到隐藏栈中。将项目恢复到上次提交时的状态。

查看本地隐藏栈

$ git stash list

根据隐藏栈中的对象id将隐藏栈中的一项恢复,继续上次的修改。

$ git stash pop stash@{0}

6. 仓库的使用

6.1 查看远程仓库

可以运行git remote 命令来查看已经配置的远程仓库服务器。它会列出知道的每一个远程服务器的简写。如果已经克隆了自己的仓库,至少能看到 origin - 这是克隆的仓库服务器的默认名字。

$ git clone https://github.com/onestravel/test.git 
Cloning into 'test'...
remote: Enumerating objects: 21, done.
remote: Counting objects: 100% (21/21), done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 21 (delta 2), reused 21 (delta 2), pack-reused 0
Unpacking objects: 100% (21/21), done.
$ cd test 
$ git remote
origin

也可以指定选项 -v,会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL。

$ git remote -v
origin	https://github.com/onestravel/test.git (fetch)
origin	https://github.com/onestravel/test.git (push)

如果想要查看某一个远程仓库的更多信息,可以使用 git remote show [remote-name]命令。

$ git remote show origin
* remote origin
  Fetch URL: https://github.com/onestravel/test.git
  Push  URL: https://github.com/onestravel/test.git
  HEAD branch: master
  Remote branch:
    master tracked
  Local branch configured for 'git pull':
    master merges with remote master
  Local ref configured for 'git push':
    master pushes to master (up to date)

这个命令会列出在特定分支上 pull 或 push 对自动的操作远程仓库中的哪一个分支。也列出了那些远程分支不再本地,那些远程分支已经从服务器上移除了。

6.2 添加远程仓库

可以使用git remote add <shortname> <url> 来添加一个新的远程 Git 仓库,同时知道一个可以轻松引用的简写:

$ git remote add pb https://github.com/onestravel/test.git
$ git remote -v
origin	https://github.com/onestravel/test.git (fetch)
origin	https://github.com/onestravel/test.git (push)
pb	https://github.com/onestravel/test.git (fetch)
pb	https://github.com/onestravel/test.git (push)

此时如果想拉取 pb 对应的仓库服务器上的信息,可以运行:

$ git fetch pb
From https://github.com/onestravel/test
 * [new branch]      master     -> pb/master

6.3 从远程仓库中抓取与拉取

从远程仓库中获得数据,可以执行:

$ git fetch [remote_name]

这个命令会访问远程仓库,从中拉取所有你还没有的数据。执行完成后,你将会用于那个远程仓库中所有分支的引用,可以随时合并或查看。

git fetch 命令会将数据拉取到本地仓库,但是他不会自动合并或修改当前的工作。当准备好时必须手动将其合并。

git pull 命令会自动的抓取并合并远程分支到当前分支,默认情况下,git clone 会自动设置本地 master 分支跟踪克隆的远程仓库的 master 分支。运行 git pull 通常会从最初克隆的服务器上抓取 bong 自动尝试合并到当前所在分支

6.4 推送到远程仓库

git push [remote-name] [branch-name] 命令可以将本地仓库中 当前分支(master)上的为推送到远程仓库的提交,全部推送到远程仓库服务器。

$ git push origin master
Enumerating objects: 21, done.
Counting objects: 100% (21/21), done.
Delta compression using up to 4 threads
Compressing objects: 100% (11/11), done.
Writing objects: 100% (21/21), 1.76 KiB | 1.76 MiB/s, done.
Total 21 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), done.
To https://github.com/onestravel/test.git
 * [new branch]      master -> master

只有当有远程服务器的写入权限时,改命令才会生效。

如果在此次推送之前有其他人推送过时,需要先进行 pull ,将他们的推送拉取到本地并将其合并如本地仓库后才能推送。

6.5 远程仓库的移除与重命名

想要重命名引用名称,可以使用git remote rename [old name] [new name]

$ git remote rename pb pt
$ git remote
origin 
pt

这种操作会修改远程分支的名字,比如过去引用pb/master 会变成 pt/master

如果想要移除一个远程仓库,可以使用git remote rm 命令:

$ git remote rm pt
$ git remote
origin

7. 标签的使用

Git 和其他版本控制系统一样,可以给历史中的某一个提交打算标签,以示重要。比如发布结点。

7.1 列出标签

在 Git 中可以使用git tag 很直观的列出已有的标签

$ git tag
v1.0
v1.1
v2.0
v2.3

可以使用特定模式查找标签

$ git tag -l 'v2.*'
v2.0
v2.3

7.2 创建标签

Git 使用两种主要类型的标签:轻量标签(lightweight)与 附注标签(annotated)。

一个轻量标签很像一个不会改变的分支,他只是一个特定提交的引用。

附注标签是存储在 Git 数据库中的一个完整对象。它们是可以被校验的;其中包含打标签者的名字、电子邮件地址、日期时间,还有一个标签信息。并且可以使用 GNU Privacy Guard(GPG)签名与验证。

附注标签

在 Git 中创建一个附注标签时很简单的,最简单的方法是在运行git tag 命令时指定 -a 选项:

$ git tag -a v2.5 -m 'version 2.5'
$ git tag
v1.0
v1.1
v2.0
v2.3
v2.5

-m 选项指定了一条将会存储在标签中的信息。如果没有为附注标签指定一条信息,Git 会运行编辑器要求你输入信息。

通过使用 git show 命令可以看到标签信息与对应的提交信息:

$ git show v2.5
tag v2.5
Tagger: wanghu <wanghu@do-global.com>
Date:   Mon Oct 26 20:09:19 2020 +0800

version 2.5

commit bf1c84c9273b827f28c06b26a176a44795b38ef0 (HEAD -> master, tag: v2.5, pbhttps/master, origin/master, origin/HEAD)
Author: TestUserName <test@example.com>
Date:   Fri Oct 23 16:09:46 2020 +0800

    create test.txt

diff --git a/test.txt b/test.txt
new file mode 100644
index 0000000..46fdabe
--- /dev/null
+++ b/test.txt
@@ -0,0 +1 @@
+test code

输出显示了打标签者的信息、打标签的日期时间、附注信息,然后显示具体的提交信息。

轻量标签

创建轻量标签,不需要使用 -a、-s 或 -m 选项,只需要提供标签名字:

$ git tag v2.5-1
$ git tag
v1.0
v1.1
v2.0
v2.3
v2.5
v2.5-1

运行 git show,你不会看到额外的标签信息。命令只会显示出提交信息:

$ git show v2.5-1
commit bf1c84c9273b827f28c06b26a176a44795b38ef0 (HEAD -> master, tag: v2.5-1, tag: v2.5, pbhttps/master, origin/master, origin/HEAD)
Author: TestUserName <test@example.com>
Date:   Fri Oct 23 16:09:46 2020 +0800

    create test.txt

diff --git a/test.txt b/test.txt
new file mode 100644
index 0000000..46fdabe
--- /dev/null
+++ b/test.txt
@@ -0,0 +1 @@
+test code

7.3 后期打标签

如果相对过去的提交打标签,需要在命令末尾知道提交的校验和(或部分校验和):

$ git log --pretty=oneline
bf1c84c9273b827f28c06b26a176a44795b38ef0 (HEAD -> master, tag: v2.5-1, tag: v2.5, pbhttps/master, origin/master, origin/HEAD) create test.txt
7236b53506f041de847f43eab3fedaa97d45a789 update README.md
f974236b7551a860b5c31c184cff66a66970603d add .gitignore LICENSE.txt
29fb9b4a159899da5675c132b64f1bcf0170c7a5 added .gitignore
ba935920d4afc2121b674f933bada9d1c9791fa0 update text.txt; add README,version File
4ee1d4d20421d9276bc80808276207940695bbff init
$ git tag -a v1.2 7236b53
$ git show v1.2
tag v1.2
Tagger: wanghu <wanghu@do-global.com>
Date:   Mon Oct 26 20:16:54 2020 +0800

version 1.2
s

commit 7236b53506f041de847f43eab3fedaa97d45a789 (tag: v1.2)
Author: TestUserName <test@example.com>
Date:   Fri Oct 23 16:00:21 2020 +0800

    update README.md

diff --git a/README.md b/README.md
index cd19876..9fafd26 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,6 @@
 My Project-
+
+
+
+update on dev branch

7.4 共享标签

默认情况下,git push 命令并不会传送标签到远程仓库服务器上。在创建完标签后你必须显式地推送标签到共享服务器上。这个过程就像共享远程分支一样 - 你可以运行 git push origin [tagname]。

$ git push origin v2.5
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 158 bytes | 158.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To https://github.com/onestravel/test.git
 * [new tag]         v2.5 -> v2.5

如果想要一次性推送很多标签,也可以使用带有 --tags 选项的 git push 命令。这将会把所有不在远程仓库服务器上的标签全部传送到远程仓库。

$ git push origin --tags
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 160 bytes | 160.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To https://github.com/onestravel/test.git
 * [new tag]         v1.2 -> v1.2
 * [new tag]         v2.5-1 -> v2.5-1

7.5 检出标签

如果想要本地工作目录与仓库中知道的标签版本完全一样,可以使用git checkout -b [branch-name] [tag-name] 在特定标签上创建一个新分支:

$ git checkout -b version2.5 v2.5
Switched to a new branch 'version2.5'

如果在这之后又进行了一次提交,version2.5 分支会因为改动向前移动了,那么 version2.5 分支就会和v2.5 标签稍微有些不同。

四、Git 分支

Git 的分支,本质上紧急时指向提交对象的可变指针。Git 的默认分支名字是 master 。在多次提交操作之后,已经有一个指向最后那个提交对象的master 分支。它会在每次的提交操作中自动向前移动。

Git 的 master 分支,并不是一个特殊的分支,和其他分支没有任何区别。只是在git init 命令的时候默认创建的。

1. 创建分支

Git 使用git branch <branch-name> 命令来新建分支(创建一个可以移动的新的指针)。使用git branch <branch-name> 会在当前所在对象上创建一个指针。

Git 是怎么知道当前是在哪一个分支上呢?其实,Git 有一个名为HEAD 的特殊指针。它和其他版本控制系统里的 HEAD 概念完全不同。在 Git 中,它是一个指针,指向当前所在的本地分支。

git branch 命令仅仅创建一个新分支,并不会自动切换到新分支中。

$ git branch testing
$ git branch
* master
  testing
  version2.5
$ git log --oneline --decorate
bf1c84c (HEAD -> master, tag: v2.5-1, tag: v2.5, pbhttps/master, origin/master, origin/HEAD, version2.5, testing) create test.txt
7236b53 (tag: v1.2) update README.md
f974236 add .gitignore LICENSE.txt
29fb9b4 added .gitignore
ba93592 update text.txt; add README,version File
4ee1d4d init

可以看到 mastertesting 分支均指向校验和以 bf1c84c 开头的提交对象。

2. 分支切换

要切换到另一个已经存在的命令,可以使用git checkout 命令。

$ git checkout testing

执行完改命令后, HEAD 就会指向 testing 分支了。

切换分支时,这么命令做了两件事。一是使HEAD 指向指定的分支。二是将工作目录恢复成指定分支所执行的快照内容。

分支切换会改变工作目录中的文件。

如果不能保证在切换分支时可以干净利落的完成这个任务,那么则切换分支失败。

3. 分支代码合并

假设,现在在master 分支上进行新的开发工作,但是现在线上版本(version 2.5)出现了一个 bug,需要紧急修复,则需要将当前分支修改的代码暂存,切换到 version2.5 版本,新建 version2.5.1 分支,用于修复 bug。修复之后,进行发版,并将修复bug 的修改合并到 master 分支。

$ git checkout version2.5                       
Switched to branch 'version2.5'
$ git checkout -b version2.5.1
Switched to a new branch 'version2.5.1'
$ vim test.txt 
$ vim version
$ git add test.txt
$ git add version
$ git commit -m"fix bug on version2.5"
[version2.5.1 2b1d2e0] fix bug on version2.5
 2 files changed, 5 insertions(+), 2 deletions(-)
 git push origin version2.5.1
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 4 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (4/4), 367 bytes | 367.00 KiB/s, done.
Total 4 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
remote: 
remote: Create a pull request for 'version2.5.1' on GitHub by visiting:
remote:      https://github.com/onestravel/test/pull/new/version2.5.1
remote: 
To https://github.com/onestravel/test.git
 * [new branch]      version2.5.1 -> version2.5.1

现在已经修复完 bug,并生成了新的分支 version 2.5.1,接下来需要将 version2.5.1 分支上的修改合并到 master 分支。

$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
$ git merge version2.5.1
Auto-merging version
CONFLICT (content): Merge conflict in version
Automatic merge failed; fix conflicts and then commit the result.
$ git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Changes to be committed:

	modified:   test.txt

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

	both modified:   version

可以看到在合并 version 2.5.1 的时候有了冲突(在 master 分支和 version2.5.1 分支都对 version 文件的相同部分做了不同的修改),则需要解决冲突,名进行提交(commit)。

如果在合并的两个版本之间没有修改同一个文件的同一个部分,则不会产生冲突,就可以干净的合并他们。

$ vim version

编辑冲突文件

<<<<<<< HEAD
version: 3.0.0
code: 300
=======
version: 2.5.1
code: 251
>>>>>>> version2.5.1
~                    

因为这个是版本改变,在 master 分支应该是新的版本 3.0.0 ,所以,删掉冲突中的 version2.5.1 中的代码,进行解决。并且将<<<<<<< , ======= , >>>>>>>这些行完全删除。

version: 3.0.0
code: 300

也可以尝试使用git mergetool命令来解决冲突。改命令会启动一个合适的可视化合并工具。

保存对改文件的修改,然后进行文件的提交

$ git add version 
$ git commit 
[master 0639659] Merge branch 'version2.5.1'

此处使用git commit 命令继续提交,会出现编辑提交日志的窗口,会显示以下内容:

Merge branch 'version2.5.1'

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Wed Oct 28 16:38:53 2020 +0800
#
# On branch master
# Your branch is ahead of 'origin/master' by 3 commits.
#   (use "git push" to publish your local commits)
#
# Changes to be committed:
#       modified:   test.txt
#       modified:   version
#

直接保存改日志的编辑,则提交成功。接下来可以选择推送至远程仓库服务器,或者继续进行新功能的开发,后续推送至远程仓库服务器。

4. 分支管理

git branch 命令不只是可以创建或删除分支。如果不加参数运行这个命令,会得到当前所有分支的一个列表

$ git branch
* master
  testing
  version2.5
  version2.5.1

master 分支前的 * 字符代表现在检出的哪一个分支,也就是说,当前 HEAD 指针所指向的分支。

如果需要查看每一个分支的最后一次提交,可以运行git branch -v命令:

$ git branch -v

* master       02c3021 [ahead 3] Merge branch 'version2.5.1'
  testing      bf1c84c create test.txt
  version2.5   bf1c84c create test.txt
  version2.5.1 4b30818 change version

--merged--no-merged 者两个选项可以过滤这个俩表中已经合并或者尚未合并到当前分支的分支。

$ git checkout testing
$ vim test.txt
$ git add test.txt
$ git commit -m"update test"
[testing b00d0ae] update test
 1 file changed, 3 insertions(+)
$ git checkout master
Switched to branch 'master'
$ git branch --merged
* master
  version2.5
	version2.5.1
$ git branch --no-merged
  testing

5. 远程分支

5.1 远程分支

远程引用是对远程仓库的引用(指针),包括分支,标签等等。可以通过git ls-remote 来显示的获得远程引用的完整列表,或者通过git remote show (remote) 获得远程分支的更多信息。

$ git ls-remote   
From https://github.com/onestravel/test.git
bf1c84c9273b827f28c06b26a176a44795b38ef0	HEAD
bf1c84c9273b827f28c06b26a176a44795b38ef0	refs/heads/master
e5b97a2fb0ad902b2a6069d07964bc09ab102f0f	refs/heads/version2.5.1
853cf5e3d043663e823565c6f8b7b4eb713e8d2c	refs/tags/v1.2
7236b53506f041de847f43eab3fedaa97d45a789	refs/tags/v1.2^{}
e5fb21c6d785132c26100f6f951feebce8aa2a40	refs/tags/v2.5
bf1c84c9273b827f28c06b26a176a44795b38ef0	refs/tags/v2.5^{}
bf1c84c9273b827f28c06b26a176a44795b38ef0	refs/tags/v2.5-1

远程跟踪分支是远程分支状态的引用。它们是不能移动的本地引用,当做任何网络通信操作时,它们会自动移动。

远程分支以(remote)/(branch)形式命名,如果响应查看最后一次与远程仓库 origin 通信时 master 分支的状态,可以查看origin/master 分支。

可以运行git fetch teamone 来抓取远程仓库 teamone 有而本地没有的数据。因为那台服务器上现有的数据是 origin 服务器上的一个子集,所以 Git 并不会抓取数据而是会设置远程跟踪分支 teamone/master 指向 teamone 的 master 分支。

5.2 推送

当想要公开分享一个分支时,需要将其推送到有写入权限的远程仓库上。本地分支并不会自动与远程仓库同步,必须显示的推送想要分享的分支。

将本地分支 testing 推送到远程仓库上:

$ git push origin testing
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 4 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 291 bytes | 291.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
remote: 
remote: Create a pull request for 'testing' on GitHub by visiting:
remote:      https://github.com/onestravel/test/pull/new/testing
remote: 
To https://github.com/onestravel/test.git
 * [new branch]      testing -> testing

如果不想让远程仓库上的分支叫做 testing 可以运行git push origin testing:otherbranch 来将本地的 testing 分支推送到远程仓库上的 otherbranch 分支。

$ git push origin testing:otherbranch
Total 0 (delta 0), reused 0 (delta 0)
remote: 
remote: Create a pull request for 'otherbranch' on GitHub by visiting:
remote:      https://github.com/onestravel/test/pull/new/otherbranch
remote: 
To https://github.com/onestravel/test.git
 * [new branch]      testing -> otherbranch

如果使用 HTTPS URL 来推送,Git 服务器会询问用户名和密码,默认情况下它会在中断中提示服务器是否允许你进行推送。

git merge origin/otherbranch 会将这些工作合并到当前所在的分支。

如果想要在远程分支origin/otherbranch 上创建 dev 分支进行一些工作时,可以如下操作:

$ git checkout -b dev origin/otherbranch
Branch 'dev' set up to track remote branch 'otherbranch' from 'origin'.
Switched to a new branch 'dev'

这会在本地创建一个 用于工作的 dev 分支,并且起点位于 origin/otherbranch

5.3 跟踪分支

从一个远程分支检出一个本地分支会自动创建一个叫做“跟踪分支”(也叫“上游分支”)。跟踪分支是与远程分支有直接关系的本地分支。如果在一个跟踪分支上输入 git pull ,Git 能自动滴识别去那个服务器上抓取、合并到哪个分支。

如果想要设置本地分支跟踪其他远程仓库上的跟踪分支,可以运行git checkout -b [branch] [remote-name]/[branch] 命令,这个命令 Git 提供了快捷方式 git checkout --track [remote-name]/[branch]

设置已有的本地分支跟踪一个刚刚拉取下来的远程分支,或者想要修改正在跟踪的上游分支,你可以在任意时间使用 -u 或 --set-upstream-to 选项运行 git branch 来显式地设置。

$ git branch -u origin/testing
Branch 'dev' set up to track remote branch 'testing' from 'origin'.

如果想要查看设置的所有跟踪分支,可以使用 git branch 的 -vv 选项。这会将所有的本地分支列出来并且包含更多的信息,如每一个分支正在跟踪哪个远程分支与本地分支是否是领先、落后或是都有。

$ git branch -vv
* dev          b00d0ae [origin/testing] update test
  master       65682fc [origin/master: ahead 5] Merge branch 'version2.5.1'
  testing      b00d0ae update test
  version2.5   bf1c84c create test.txt
  version2.5.1 4b30818 change version

可以看到本地分支 dev 正在跟踪 origin/testingmaster 分支正在跟踪origin/master ,并且“ahead” 是5,表示本地 master 分支还有 5 个提交没有推送到服务器。

想要统计最新的领先与落后数字,需要在运行此命令前抓取所有的远程仓库。

$ git fetch --all; git branch -vv

5.4 拉取

git fetch 命令从服务器上抓取本地没有的数据时,它并不会修改工作目录中的内容。它只会获取数据然后让你自己合并。

git pull 会查找当前分支所跟踪的服务器与分支,从服务器上抓取数据然后尝试合并如那个远程分支。大多数情况下,它可以看着是一个git fetch 紧接着一个git merge 命令。

5.5 删除远程分支

如果临时创建了一个分支,并且这个分支的职责已经完成了,不需要了,想将这个分支从远程服务器删除。可以运行带有--delete 选项的git push 命令来删除一个远程分支。比如需要从远程服务器上删除testing 分支,运行下面的命令:

$ git push origin --delete testing
To https://github.com/onestravel/test.git
 - [deleted]         testing
$ git branch -vv
* dev          b00d0ae [origin/testing: gone] update test
  master       65682fc [origin/master: ahead 5] Merge branch 'version2.5.1'
  testing      b00d0ae update test
  version2.5   bf1c84c create test.txt
  version2.5.1 4b30818 change version

这个命令做的只是从服务器上移除这个指针,Git 服务器通常会保留数据一段时间直到垃圾回收运行,所以是不小心删除了,通常比较容易恢复。使用git branch -vv查看分支跟踪状态,可以看到 dev 分支跟踪的远程分支origin/testing 后面是一个 gone 的状态。

6. 变基

在 Git 中整合来自不同分支的修改主要有两种方法:mergerebase

使用 rebase 命令将提交到某一分支上的所有修改都移动至另外一个分支上。必然在 C4 提交中引入的补丁和修改,然后在 C3 提交的基础上再应用一次。就叫变基。