Git正解 脱水版 【2. Git基础】

2.1 获取Git仓库

获取Git仓库有两种方法,

  1. 将项目文件下载到本地目录,创建一个Git仓库
  2. 克隆一个Git仓库

初始化新仓库

如果需要使用Git,对项目文件进行管理,首先进入项目目录,如下,

linux: $ cd /home/user/my_project
macOS: $ cd /Users/user/my_project
windows: $ cd /user/my_project

再输入git init,它将创建一个子目录.git,其中包含了Git仓库所需的文件(即Git仓库的模板),此时开发项目并未纳入Git的监控范围,因此用户需要将项目文件,添加到Git的监控清单中,并进行首次提交,git add可添加项目文件,git commit可实现提交,之后Git仓库则完成创建,

$ git add *.c
$ git add LICENSE
$ git commit -m 'initial project version'

克隆仓库

如果需要获取Git仓库的副本,可使用git clone,Git将获取服务器上,开发项目的所有数据,默认情况下,将得到开发项目的所有版本,如果服务器的磁盘损坏,也可使用客户端的仓库镜像,恢复服务器的数据,因此即使服务器的数据全部丢失,对于开发项目,并不会造成太大的影响。

假设用户需要克隆一个开发项目,即Git的链接库libgit2,

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

这时将创建一个目录libgit2,其中包含了一个子目录.git,原始仓库的所有数据,以及最新版本的工作目录,如果需要将克隆仓库,放入指定目录,需给出路径,比如,

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

仓库克隆将放入mylibgit目录中。

Git包含了不同的传输协议,上述例子使用了http协议,还可以使用git://或user@server:path/to/repo.git,同时还支持SSH协议。

2.2 记录修改

假定存在一个本地Git仓库,以及一个工作区环境,当用户完成修改,并提交到本地仓库,这时本地仓库将得到,开发项目的一个新状态或快照。注意,工作区的文件只有两种状态,已跟踪或未跟踪,已跟踪是指,已被Git跟踪,保存在仓库的快照内,可以处于未修改,已修改,已暂存等模式,未跟踪文件则不言自明,当完成仓库克隆后,所有文件处于已跟踪而未修改的状态,一个完整的工作流程,如下图,
在这里插入图片描述

检查文件的状态

使用git status,可查看文件的状态,完成仓库克隆后,使用该命令,将得到以下输出,

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

上述输出将告知用户,你有一个干净的工作区,所有跟踪文件未被修改,以及开发项目包含的所有分支,此时只有一个主分支master,这也是默认名称。

如果在项目目录(工作区)中,创建一个文件(README文件),再运行git status,

$ echo 'My Project' > README
$ git status
On branch master
Your branch is up-to-date with 'origin/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)

输出将报告,在工作区中,存在一个未跟踪文件README,未跟踪是指,Git在仓库记录中,未找到该文件,同时Git不会进行未跟踪文件的自动跟踪,需要用户手动配置,因为用户有可能误操作,加入了二进制文件,Git只能跟踪文本文件,无法跟踪二进制文件,但一些Git扩展可实现跟踪。

跟踪新文件

使用git add,可跟踪新文件

$ git add README

运行git status,README文件已被跟踪,并处于暂存态:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
    (use "git reset HEAD <file>..." to unstage)
    new file: README

Changes to be committed之下,将列出已暂存的文件,已暂存的文件,可以直接提交,add之后,可包含文件或目录的路径,如果是目录路径,等同于添加,该目录下的一切文件,包括子目录的文件。

暂存已修改文件

假设跟踪文件CONTRIBUTING.md被修改,运行git status,将看到,

$ git status
On branch master
Your branch is up-to-date with 'origin/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

Changes not staged for commit之下,将列出未暂存的文件,这表示在工作区中,跟踪文件已被修改,运行git add,可实现文件暂存,而git add是一个多用途命令,既可以添加新文件,暂存文件,还可以处理合并冲突,等等功能,将CONTRIBUTING.md暂存,并查看当前状态,

$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
    (use "git reset HEAD <file>..." to unstage)
    new file:   README
    modified:   CONTRIBUTING.md

两个文件都已暂存,如果此时又对CONTRIBUTING.md进行一次小改动,再次运行git status,

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
    (use "git reset HEAD <file>..." to unstage)
    new file:   README
    modified:   CONTRIBUTING.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:   CONTRIBUTING.md

what,CONTRIBUTING.md同时出现在暂存和未暂存的列表中,可将其视为CONTRIBUTING.md的不同版本,如果使用git add CONTRIBUTING.md,后一版本将覆盖之前的版本,如下,

$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
    (use "git reset HEAD <file>..." to unstage)
    new file:   README
    modified:   CONTRIBUTING.md

简单的状态信息

虽然git status的输出信息很完整,但也过于详细,因此Git提供了一种更简明的方式,添加-s或–short选项,

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

??表示未跟踪文件,A表示已暂存,M表示已修改,在每行输出开头,存在两列标识,第一列表示暂存区状态,第二列表示工作区状态,如下,

README           未暂存,已修改
Rakefile         修改已暂存,修改未暂存,存在两个版本
lib/git.rb       已暂存
lib/simplegit.rb 已暂存,已修改
LICENSE.txt      未跟踪

忽略文件

有时候用户不希望Git自动添加或跟踪某一类文件,比如log文件,编译生成的文件,在这种情况下,可创建一个.gitignore文件,其中将包含文件过滤的模板,比如,

$ cat .gitignore
*.[oa]
*~

第一行可过滤.o和.a结尾的文件,这是编译生成的文件,第二行可过滤~结尾的文件,这是大多数文本编辑器生成的临时文件,为新仓库配置.gitignore文件,可避免无用文件的意外提交。

以下是.gitignore文件的模板规则,

  • 空行,以#开头的行,将被忽略
  • 使用glob的标准规则,可实现整个工作区的递归遍历
  • 模板起始处,放入反斜杠/,可避免递归操作
  • 模板末尾处,放入反斜杠/,可指定一个目录
  • 添加惊叹号!, 可实现取反

Glob规则类似于简单的正则表达式,*可匹配零个或多个字符,[abc]可匹配任意的备选字符,?可匹配单个字符,[0-9]可匹配0到9的任意数字,使用两个星号,可匹配多层目录,比如a/**/z,可匹配a/z,a/b/z,a/b/c/z等,以下是一些示例,

*.a             过滤所有.a文件
!lib.a          保留lib.a文件
/TODO           过滤当前目录的TODO文件,但不过滤TODO子目录
build/          过滤掉,名为build的所有目录
doc/*.txt       过滤doc的所有txt文件,不包含子目录
doc/**/*.pdf    过滤doc的所有pdf文件,包含子目录

GitHub维护了一个相当完整的.gitignore文件,可用于不同项目和编程语言,参见https://github.com/github/gitignore,为了简化应用,每个仓库会在根目录下,创建一个.gitignore文件,当然也可在子目录中,创建.gitignore文件,实现整个仓库的递归操作,因此子目录的.gitignore文件,只在子目录树中有效,比如Linux内存仓库中,存在206个.gitignore文件。

查看变更

git status的输出信息相对简单,如果需要查看具体的修改内容,可使用git diff,继续之前的状态, README文件被修改并暂存,CONTRIBUTING.md被修改并暂存,之后再次修改CONTRIBUTING.md,这时工作区和暂存区中,将存在CONTRIBUTING.md的两个版本,运行git diff,

$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
Please include a nice description of your changes when you submit your PR;
if we have to read the whole diff to figure out why you're contributing
in the first place, you're less likely to get feedback and have your change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your patch is
+longer than a dozen lines.

If you are starting to work on a particular area, feel free to submit a PR
that highlights your work in progress (and note in the PR title that it's

diff可比较工作区和暂存区之间,同名文件的差异,并列出工作区版本的差异,-表示删除行,+表示添加行,如果附带–staged选项,可比较暂存区版本和最新提交版本之间的差异,

$ git diff --staged
diff --git a/README b/README
new file mode 100644
index 0000000..03902a1
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+My Project

–cached选项,可查看哪些修改已被暂存,所以–staged和–cached类似,只是侧重点不同,一个针对工作区版本,另一个针对暂存区版本。同时用户也可以调用外部的比较工具,比如emerge, vimdiff等,即使用git difftool,附带–tool-help选项,可获知系统支持的外部比较工具。

提交变更

未添加到暂存区的变更,无法被提交,因此运行git status,可查看已暂存的变更,再运行git commit,会将暂存区保存的所有变更,一次性提交,同时可附带-m选项,设定提交的简单描述,如下,

$ git commit -m "Story 182: Fix benchmarks for speed"
[master 463dc4f] Story 182: Fix benchmarks for speed
2 files changed, 2 insertions(+)
create mode 100644 README

首次提交已完成,输出信息可告知用户,本次提交的分支为master,即主分支,SHA-1校验码为463dc4f,产生变更的文件数,增加或删除的文本行数,注意,提交的快照,即暂存区的所有数据,而开发项目的快照记录,可用于恢复或比较。

跳过暂存区

git commit附加-a选项,Git可实现已修改文件直接提交,无需使用git add,跳过暂存区,使用之前CONTRIBUTING.md文件,

$ git status
On branch master
Your branch is up-to-date with 'origin/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:   CONTRIBUTING.md
     
no changes added to commit (use "git add" and/or "git commit -a")

$ git commit -a -m 'added new benchmarks'
[master 83e38c7] added new benchmarks
1 file changed, 5 insertions(+), 0 deletions(-)

删除文件

值得注意,所有上传的Git远程共享仓库的数据,无法被删除,因为强制删除,可能造成开发协作者之间,出现数据不同步,当然也存在变相删除的方法,即清除某个文件在开发项目的所有引用,等同于废弃某个文件,已达到删除的效果,这里的删除,是指工作区,暂存区以及本地仓库的文件删除,使用git rm可删除工作区的文件,如果直接使用外部命令rm,将导致本地仓库的记录无法被删除,如下,

$ rm PROJECTS.md
$ git status
On branch master
Your branch is up-to-date with 'origin/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: PROJECTS.md
no changes added to commit (use "git add" and/or "git commit -a")

PROJECTS.md已被删除,但并未通知本地仓库,删除该文件的记录,正确的方法,应如下,

$ git rm PROJECTS.md
rm 'PROJECTS.md'
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
    (use "git reset HEAD <file>..." to unstage)
    deleted: PROJECTS.md

文件删除已通知本地仓库,而删除暂存区的文件,则必须附带-f选项,避免删除的误操作,方便数据的恢复。另一个实用建议,将需删除的文件保存在磁盘中,同时告知Git,放弃这些文件的跟踪,之前已提过.gitignore文件,如果用户忘记在.gitignore文件中,添加过滤规则,同时又暂存了这些无用文件,比如超大的log文件,一大堆编译文件,这时可使用–cached选项,

$ git rm --cached README

git rm支持文件,目录以及glob模板,

$ git rm log/\*.log     将删除log目录下,扩展名为log的所有文件,
$ git rm \*~    将删除当前目录树中,以~结尾的所有文件

文件更名

不同于其他VCS系统,Git不会跟踪文件的更名,只要不出现同名文件,Git将接受用户的重命名操作,同时会自动处理,文件更名带来的影响,

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

mv等同于,以下命令集合

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

2.3 查看提交历史

当用户完成几次提交后,或是克隆仓库中已包含提交,使用git log,可查看提交的历史记录,这里用一个简单项目simplegit为例,

$ git clone https://github.com/schacon/simplegit-progit
$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <[email protected]>
Date:
 Mon Mar 17 21:52:11 2008 -0700
    changed the version number

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <[email protected]>
Date:
 Sat Mar 15 16:40:33 2008 -0700
    removed unnecessary test

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <[email protected]>
Date:
 Sat Mar 15 10:31:28 2008 -0700
    first commit

git log给出的提交报告,采用生成时间的逆向排序,首位是最新提交,每个提交都包含了SHA-1校验码,作者名和邮箱地址,提交时间以及简要描述,git log包含大量的选项,以方便用户实现精确查看,如果使用-p或–patch选项,将显示每次提交,引入的变更(基于patch格式),有些选项还能限制提交的显示个数,比如-2,将显示最新的两次提交,

$ git log -p -2

-p选项可方便开发者,快速浏览一组提交的所有变更,如果需要了解每次提交的简单统计,可附加–stat选项,它将列出已修改文件的名称和个数,文件中加减的行数,

$ git log --stat
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <[email protected]>
Date:
 Mon Mar 17 21:52:11 2008 -0700
    changed the version number
    Rakefile | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)
    
commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <[email protected]>
Date:
 Sat Mar 15 16:40:33 2008 -0700
    removed unnecessary test
    lib/simplegit.rb | 5 -----
    1 file changed, 5 deletions(-)

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <[email protected]>
Date:
 Sat Mar 15 10:31:28 2008 -0700
    first commit
    README           |  6 ++++++
    Rakefile         | 23 +++++++++++++++++++++++
    lib/simplegit.rb | 25 +++++++++++++++++++++++++
    3 files changed, 54 insertions(+)

另一个选项是–pretty,它可改变默认的输出格式,并为用户预定义了一些输出格式,比如oneline格式,一行只显示一个提交,而其他格式,比如short,full和fuller,基本相似,只是输出的信息量有所不同,

$ git log --pretty=oneline
ca82a6dff817ec66f44342007202690a93763949 changed the version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test
a11bef06a3f659402fe7563abf99ad00de2209e6 first commit

除去上述格式,还提供了一种自定义格式format,这将极大方便自动化的分析处理,而无需对Git进行任何修改,

$ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 11 months ago : changed the version number
085bb3b - Scott Chacon, 11 months ago : removed unnecessary test code
a11bef0 - Scott Chacon, 11 months ago : first commit

表2-1 format占位符的意义

选项        说明
%H      提交的哈希校验码
%h      提交的简明哈希校验码
%T      目录树的哈希校验码
%t      目录树的简明哈希校验码
%P      上层目录树的哈希校验码
%p      上层目录树的简明哈希校验码
%an     作者名
%ae     作者的邮件地址
%ad     修改日期(也可用--date=选项)
%ar     修改日期,一个相对时间
%cn     提交者的名字
%ce     提交者的邮件地址
%cd     提交日期
%cr     提交日期,一个相对时间
%s      提交说明

作者和提交者之间的区别在于,前者是完成修改的人,而后者是将修改,提交到仓库的人,当然也可能是同一个人。除了上述选项,还提供一个小巧的图形选型–graph,它可使用ASCII符号,显示分支与合并的历史记录,

$ git log --pretty=format:"%h %s" --graph
* 2d3acf9 ignore errors from SIGCHLD on trap
*  5e3ee11 Merge branch 'master' of git://github.com/dustin/grit
|\
| * 420eac9 Added a method for getting the current branch.
* | 30e367c timeout code and tests
* | 5a09431 add timeout protection to grit
* | e1193f8 support for heads with slashes in them
|/
* d6016bc require time for xmlschema
*  11d191e Merge branch 'defunkt' into local

其中的含义,可参考后续的分支与合并,以下将列出git long的常用选项,

表2-2 git log常用选项

选项                 说明
-p              每次提交引入的补丁
--stat          每次提交中,文件修改的统计信息
--shortstat     --stat输出中,包含的文件修改行数
--name-only     每次提交中,修改文件的列表
--name-status   每次提交中,修改文件的列表,以及每个文件的修改行数
--abbrev-commit 每次提交的简明SHA-1校验码
--relative-date 显示相对时间,而非完整的时间格式
--graph         使用ASCII字符,显示分支与合并的历史记录
--pretty        提交的显示格式,包含了oneline,short,full,fuller,format等格式
--oneline       --pretty=oneline --abbrev-commit的缩写

受限的输出

git log附带-选项,n为整数,可显示最新的n次提交,在实际应用中,用户可能不太喜欢这个选项,因为Git采用了管道输出的方式,并存在一个分页器,因此每次只能查看单页日志,需要手动翻页,才能查看所有日志。

使用–since和–until可以设定一个时间范围,即查看这一范围内的所有提交,比如查看最近两周内的所有提交,

$ git log --since=2.weeks

同时该命令支持不同的时间格式,比如特定的日期,2008-01-15,或者是一个相对时间,2 years 1 day 3 minutes ago,除此之外,还可基于不同的查询条件,对所有提交进行过滤,–author选项,可基于特定作者名进行过滤,–grep选项,可基于提交信息的特定字符进行过滤,当然用户可同时给出多个查询条件,如果希望得到多个查询条件的交集,必须后跟–all-match选项。

另一个实用的过滤器选项-S,它可基于某一字串,并从提交信息中,匹配该字串,如果想查找,添加或删除某个特定函数的最新提交,可使用,

$ git log -S function_name

如果git log附带一个文件名或目录名,只会显示与这些文件相关的提交,通常这也是最后的命令参数,因此可包含–前缀,以区分选项和路径,以下将给出git log的输出限制选项,

表2-3 git log的限制选项

选项                      说明
-<n>                只显示最新的n次提交
--since, --after    仅显示指定时间之后的提交
--until, --before   仅显示指定时间之前的提交
--author            仅显示与特定作者相关的提交
--committer         仅显示与特定提交者相关的提交
--grep              只显示与特定字串相关的提交
-S                  只显示添加或删除信息中,包含特定字串的提交

如果想从Git源码中,查询2008年10月以来,Junio Hamano基于测试文件的所有提交中,未被合并的提交,t/表示t目录,可使用,

$ git log --pretty="%h - %s" --author='Junio C Hamano' --since="2008-10-01" \
    --before="2008-11-01" --no-merges -- t/
5610e3b - Fix testcase failure when extended attributes are in use
acd3b9e - Enhance hold_lock_file_for_{update,append}() API
f563754 - demonstrate breakage of detached checkout with symbolic link HEAD
d1a43f2 - reset --hard/read-tree --reset -u: remove unmerged new paths
51a94af - Fix "checkout --track -b newbranch" on detached HEAD
b0ad11e - pull: allow "git pull origin $something:$current_branch" into an unborn branch

Git源码中,存在近40000条提交,而只有6条,满足查询条件,–no-merges可以阻止已合并的提交,因为一个大型的Git仓库中,通常会存在大量的已合并提交。

2.4 撤消操作

应当注意,有些操作无法撤销,这也是Git中,为数不多的无法让人满意的地方,因此一旦误操作,存在丢失数据的可能性。

一种常见的撤销场景,提交过程中,忘记添加某些文件,或者提交描述出错,如果需要重新提交,需使用–amend选项,

$ git commit --amend

该命令同样会将已暂存数据,提交到仓库,如果当前提交相比于上一次提交,未做任何修改,这时Git将自动开启编辑器,等待用户修改,本次提交的提交说明,因为相同的提交说明,已出现在上一次提交中,用户必须输入一个不同的提交说明,以便当前提交可覆盖上一次提交。

如果上一次提交中,忘记添加某些文件,可使用以下命令,

$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend

应当正确理解提交的修正,用户无需使用一个全新的提交,去覆盖之前的提交,而应当使用一个新提交,修补之前的失误,这才是一个高效的方法,同时又带来另一个问题,新的提交也应当拥有一些小改进(相对于之前的提交),而不是为了弥补之前提交的失误,才产生的一次提交。

暂存文件的撤销

假设用户完成了两个文件的修改,并希望两个文件能够分成两次提交,由于误操作,将两个文件同时添加到暂存区,该如何撤销?

$ git add *
$ git status
On branch master
Changes to be committed:
    (use "git reset HEAD <file>..." to unstage)
    renamed:  README.md -> README
    modified: CONTRIBUTING.md

撤销CONTRIBUTING.md文件的暂存,

$ git reset HEAD CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
    (use "git reset HEAD <file>..." to unstage)
    renamed: README.md -> 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

注意,git reset是一个危险命令,尤其是附带–hard选项后,因为上述场景中,git reset无法处理工作区的文件,所以该命令相对安全。

修改状态的撤销

参看上例的Changes not staged for commit条目的第二行,已告知用户,如何撤销文件的已修改状态,

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

注意,git checkout – 同样是一个危险命令,因为使用这个命令,用户当前所做的任何修改,都能被最新的提交版本所覆盖,除非用户能够确定文件的当前修改,无需保存时,才可使用该命令进行恢复,否则慎用。

如果用户希望保存当前的工作成果,并在需要时,能随意调取,这时可选择储藏或分支操作,它们都是常见的优选方案,应当注意,Git的任何提交,基本都能恢复,无论是被删除的分支,或者被–amend选项所覆盖的提交。

2.5 远程操作

为了实现开发项目的协作,用户必须了解远程仓库的管理,通常远程仓库必须使用网络连接,可设定不同的网络权限,当完成远程仓库的共享设置后,项目协作者可向远程仓库,获取或推送数据,远程仓库的管理包括,添加远程仓库,移除远程仓库,管理不同的远程分支,设定远程分支的跟踪状态,当然远程仓库也可保存在本地,远程并不意味着,仓库必须放置在网络上。

查看远程仓库

运行git remote,可列出所有远程仓库的简称,当完成远程仓库的克隆,用户至少会看到origin目录,这是默认名称,Git会将克隆仓库放入其中,

$ git clone https://github.com/schacon/ticgit
Cloning into 'ticgit'...
remote: Reusing existing pack: 1857, done.
remote: Total 1857 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (1857/1857), 374.35 KiB | 268.00 KiB/s, done.
Resolving deltas: 100% (772/772), done.
Checking connectivity... done.
$ cd ticgit
$ git remote
origin

如果git remote附带-v选项,将显示读写远程仓库所使用的简称,以及对应的URL,

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

当然用户可配置多个远程仓库,同时一个仓库也可包含多个远程地址,方便开发项目的分类管理,同时也可实现协作者的权限管理,

$ cd grit
$ git remote -v
bakkdoor    https://github.com/bakkdoor/grit (fetch)
bakkdoor    https://github.com/bakkdoor/grit (push)
cho45       https://github.com/cho45/grit (fetch)
cho45       https://github.com/cho45/grit (push)
defunkt     https://github.com/defunkt/grit (fetch)
defunkt     https://github.com/defunkt/grit (push)
koke        git://github.com/koke/grit.git (fetch)
koke        git://github.com/koke/grit.git (push)
origin      [email protected]:mojombo/grit.git (fetch)
origin      [email protected]:mojombo/grit.git (push)

添加远程仓库

在添加远程仓库时,应设定一个简称,可方便后续的引用,

$ git remote add pb https://github.com/paulboone/ticgit
$ git remote -v
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)
pb https://github.com/paulboone/ticgit (fetch)
pb https://github.com/paulboone/ticgit (push)

之后使用pb,则可替代对应的URL,如果用户需要获取Paul的共享数据,可运行

$ git fetch pb
remote: Counting objects: 43, done.
remote: Compressing objects: 100% (36/36), done.
remote: Total 43 (delta 10), reused 31 (delta 5)
Unpacking objects: 100% (43/43), done.
From https://github.com/paulboone/ticgit
* [new branch] master -> pb/master
* [new branch] ticgit -> pb/ticgit

Paul主分支的本地路径为pb/master,用户可将其,合并到自己的分支,或者直接浏览此本地目录。

远程仓库的获取

从远程仓库获取数据,可运行

$ git fetch <remote>

上述可进入远程仓库,从远程仓库中下载所有数据,已保持远程仓库和本地仓库的同步,之后用户可浏览或合并,本地仓库的所有分支。如果用户需要克隆一个远程仓库,git fetch将自动使用origin(默认名),添加该远程仓库,之后可使用git fetch origin获取克隆仓库的最新数据,注意,git fetch只能下载数据,无法实现分支的自动合并,或是修改用户的当前开发版本,而分支合并必须由用户手动完成。

如果用户设定了,本地分支与远程分支的跟踪关系,可使用git pull,自动获取远程分支,并将其合并到本地分支,默认情况下,git clone会自动设定,本地主分支与远程主分支的跟踪关系,当用户切换到本地主分支,运行git pull,可实现本地主分支与远程主分支之间的数据同步。

远程仓库的推送

如果用户需要分享自己的工作成果,可使用git push <远程仓库名> <本地分支名>,向远程仓库推送数据,如果用户需要将本地主分支,推送到克隆过的远程仓库,可运行,

$ git push origin master

上述命令需要用户具有远程仓库的写入权限,并在同一时刻下,只允许单个用户的推送,如果其他协作者的推送已经开始,你的推送将被驳回,只能等待其他人的推送结束,从远程仓库获取(fetch)最新的数据,完成自动合并,再推送自己的更新。

查看远程仓库的信息

需要查看特定远程仓库的信息,可运行git remote show <远程仓库名>,

$ git remote show origin
* remote origin
Fetch URL: https://github.com/schacon/ticgit
Push URL: https://github.com/schacon/ticgit
HEAD branch: master
Remote branches:
    master          tracked
    dev-branch      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)

上述信息给出了远程仓库的URL,以及远程分支的信息,如果用户已切换到本地主分支,可运行git pull,Git将下载远程分支的最新数据,并自动合并到本地主分支,直接运行git remote show,将显示所有远程仓库的详细信息。

删除和重命名远程仓库

使用git remote rename,可修改远程仓库的简称,如果将pb改为paul,可使用

$ git remote rename pb paul
$ git remote
origin
paul

如果需要删除一个远程仓库,可运行git remote remove或git remote rm,

$ git remote remove paul
$ git remote
origin

一旦远程仓库被删除,与之相关的所有远程分支,配置设定,都将被删除。

2.6 仓库标签

和其他VCS系统一样,Git可为仓库的某个历史记录,设定标签,通常情况下,可基于标签,设定不同的版本号,

标签列表

运行git tag,并能附带可选选项-l或–list,可列出仓库中包含的所有标签,

$ git tag 
v1.0
v2.0 

命令输出的标签列表,将按字母顺序排列,所以标签的次序,并无特殊含义,同时还能附带一个模板,对标签进行过滤,比如Git源码仓库中,标签已超过500个,如果只想查看1.8.5的系列版本,可使用,

$ git tag -l "v1.8.5*"
v1.8.5
v1.8.5-rc0
v1.8.5-rc1
v1.8.5-rc2
v1.8.5-rc3
v1.8.5.1
v1.8.5.2
v1.8.5.3
v1.8.5.4
v1.8.5.5

如果查看所有标签,git tag无需附带-l或–list选项,如果需要附带一个过滤模板,则必须使用-l或–list选项

创建标签

Git支持两种标签类型,简单标签和附注标签,简单标签,类似于一个固定分支,用于标记一个特定提交,附注标签,可标记仓库的所有对象,同时附注标签也拥有自身的校验码,可包含名称,邮件地址,日期,描述,以及GPG的签名验证,一般情况下,推荐使用附注标签,如果只需一个临时标签,则可使用简单标签。

附注标签

git tag附带一个-a选项,就可创建一个附注标签

$ git tag -a v1.4 -m 'my version 1.4'
$ git tag
v0.1
v1.3
v1.4

-m选项可设定附注标签的描述,如果用户未设定附注标签的描述,Git将自动调用文本编辑器,提醒用户输入,使用git show,可查看标签对应的提交,

$ git show v1.4
tag v1.4
Tagger: Ben Straub <[email protected]>
Date: Sat May 3 20:19:12 2014 -0700
my version 1.4

commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <[email protected]>
Date: Mon Mar 17 21:52:11 2008 -0700
    changed the version number

以上输出给出了标签名,标签日期,标签描述。

简单标签

简单标签可视为一个保存了提交校验码的文件,创建简单标签,无需-a,-s,-m选项,只需附带标签名,

$ git tag v1.4-lw
$ git tag
v0.1
v1.3
v1.4
v1.4-lw

使用git show查看简单标签时,不会显示详细的信息,

$ git show v1.4-lw
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <[email protected]>
Date: Mon Mar 17 21:52:11 2008 -0700
    changed the version number

追加标签

假定用户的提交历史如下,

$ git log --pretty=oneline
15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment'
a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support
0d52aaab4479697da7686c15f77a3d64d9165190 one more thing
6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment'
0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function
4682c3261057305bdd616e23b64b0857d832627b added a todo file
166ae0c4d3f420721acbb115cc33848dfcc2121a started write support
9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile
964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo
8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme

如果用户忘记为v1.2版本,设定标签,即updated rakefile提交,可为特定提交,追加一个标签,在git tag命令后,附带提交校验码的首7位,

$ git tag -a v1.2 9fceb02
$ git show v1.2
tag v1.2
Tagger: Scott Chacon <[email protected]>
Date: Mon Feb 9 15:32:16 2009 -0800
version 1.2
commit 9fceb02d0ae598e95dc970b74767f19372d61af8
Author: Magnus Chacon <[email protected]>
Date: Sun Apr 27 20:43:35 2008 -0700
    updated rakefile

共享标签

默认情况下,git push不会将标签,推送到远程仓库,必须由用户手动推送,并类似于生成一个远程分支,可使用git push origin <标签名>,

$ git push origin v1.5
Counting objects: 14, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (14/14), 2.05 KiB | 0 bytes/s, done.
Total 14 (delta 3), reused 0 (delta 0)
To [email protected]:schacon/simplegit.git
* [new tag]     v1.5 -> v1.5

如果希望一次性推送所有标签,可为git push附加–tags选项,那么所有标签将推送到远程仓库,

$ git push origin --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 160 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To [email protected]:schacon/simplegit.git
* [new tag] v1.4 -> v1.4
* [new tag] v1.4-lw -> v1.4-lw

此时克隆或同步远程仓库的其他用户,则可共享所有的标签,注意,git push <远程仓库名> --tags并不区分简单标签和附注标签,同时git push命令也没有提供一个选项,用于不同标签类型的推送。

删除标签

删除本地仓库的标签,可使用git tag -d <标签名>,

$ git tag -d v1.4-lw
Deleted tag 'v1.4-lw' (was e7d5add)

注意,远程仓库的标签是不可删除的,但存在两种变相删除的方法,第一种,git push <远程仓库名> :refs/tags/<标签名>

$ git push origin :refs/tags/v1.4-lw
To /[email protected]:schacon/simplegit.git
- [deleted]     v1.4-lw

上述命令,等同于将冒号:之前的空值,推送并覆盖标签名,以达到删除的目的,第二种方法更直观,

$ git push origin --delete <标签名>

原文并未解释远程仓库的标签为什么不可删除,以及两种变相的删除方法,其背后的机理?

切换标签

如果需查看标签对应的快照记录,可使用git checkout,

$ git checkout 2.0.0
Note: checking out '2.0.0'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
    git checkout -b <new-branch>
HEAD is now at 99ada87... Merge pull request #89 from schacon/appendix-final

$ git checkout 2.0-beta-0.1
Previous HEAD position was 99ada87... Merge pull request #89 from schacon/appendix-final
HEAD is now at df3f601... add atlas.json and cover image

如上所示,git checkout将导致本地仓库,进入detached HEAD状态,将带来一些副作用,在detached HEAD状态下,如果用户生成一个新提交,标签会保持不变,但新提交将不从属于任何分支,甚至无法检索,除非使用新提交的校验码进行检索,此时,如果用户需要修正老版本的bug,只能新建一个分支,

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

上述命令可创建一个新分支version2,而新分支将以v2.0.0标签为起点,如果用户在新分支上,完成一次提交,那么新分支与v2.0.0标签,则存在差异,除非v2.0.0标签能指向新提交,但相关操作必须十分小心。

2.7 命令别名

如果用户输入的命令并不完整,Git不会推测用户的意图,去补全命令,如果用户觉得Git命令的输入,过于繁琐,可使用git config,为命令配置一个别名,如下,

$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status

上述方法可自定义命令,比如恢复文件的未暂存状态,

$ git config --global alias.unstage 'reset HEAD --'

以下两个命令是等价的,

$ git unstage fileA
$ git reset HEAD -- fileA

自定义命令看上去更简明,再自定义一个last命令,用于查看最后一次的提交,

$ git config --global alias.last 'log -1 HEAD'
$ git last
commit 66938dae3329c7aebe598c2246a8e6af90d04646
Author: Josh Goebel 
Date:   Tue Aug 26 19:48:51 2008 +0800
    test for current head
    Signed-off-by: Scott Chacon

除了简单的文本替换,别名还可以调用外部命令,不仅仅是Git命令,在这类定义中,需在外部命令前,添加感叹号!,比如自定义git visual命令,用于调用外部工具gitk,

$ git config --global alias.visual '!gitk'

在这里插入图片描述

发布了80 篇原创文章 · 获赞 10 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/osoon/article/details/103803168