git clone
Git 克隆的是该 Git 仓库服务器上的几乎所有数据,而不是仅仅复制完成你的工作所需要文件。
当你执行
git clone
命令的时候,默认配置下远程 Git 仓库中的每一个文件的每一个版本都将被拉取下来。 事实上,如果你的服务器的磁盘坏掉了,你通常可以使用任何一个克隆下来的用户端来重建服务器上的仓库 (虽然可能会丢失某些服务器端的钩子(hook)设置,但是所有版本的数据仍在)。git add
将
git add
理解为“精确地将内容添加到下一次提交中”而不是“将一个文件添加到项目中”要更加合适。git status -s
git status
命令的输出十分详细,但其用语有些繁琐。 Git 有一个选项可以帮你缩短状态命令的输出,这样可以以简洁的方式查看更改。 如果你使用
git status -s
命令或 git status --short
命令,你将得到一种格式更为紧凑的输出。$ git status -s M README MM Rakefile A lib/git.rb M lib/simplegit.rb ?? LICENSE.txt
新添加的未跟踪文件前面有
??
标记;新添加到暂存区中的文件前面有
A
标记(add);修改过的文件前面有
M
标记。 输出中有两栏,左栏指明了暂存区的状态,右栏指明了工作区的状态。例如,上面的状态报告显示:
README
文件在工作区已修改但尚未暂存,而 lib/simplegit.rb
文件已修改且已暂存。 Rakefile
文件已修改,暂存后又作了修改,因此该文件的修改中既有已暂存的部分,又有未暂存的部分。git remote
指定选项
-v
,会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL。$ git remote -v origin https://github.com/schacon/ticgit (fetch) origin https://github.com/schacon/ticgit (push)
我们在之前的章节中已经提到并展示了
git clone
命令是如何自行添加远程仓库的, 不过如何自己来添加它。 运行 git remote add <shortname> <url>
添加一个新的远程 Git 仓库,同时指定一个方便使用的简写:$ git remote origin $ 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)
如果想要查看某一个远程仓库的更多信息,可以使用
git remote show <remote>
命令。 如果想以一个特定的缩写名运行这个命令,例如 origin
,会得到像下面类似的信息:$ 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 与跟踪分支的信息。 这些信息非常有用,它告诉你正处于
master
分支,并且如果运行 git pull
, 就会抓取所有的远程引用,然后将远程 master
分支合并到本地 master
分支。 它也会列出拉取到的所有远程引用。这是一个经常遇到的简单例子。 如果你是 Git 的重度使用者,那么还可以通过
git remote show
看到更多的信息。$ git remote show origin * remote origin URL: https://github.com/my-org/complex-project Fetch URL: https://github.com/my-org/complex-project Push URL: https://github.com/my-org/complex-project HEAD branch: master Remote branches: master tracked dev-branch tracked markdown-strip tracked issue-43 new (next fetch will store in remotes/origin) issue-45 new (next fetch will store in remotes/origin) refs/remotes/origin/issue-11 stale (use 'git remote prune' to remove) Local branches configured for 'git pull': dev-branch merges with remote dev-branch master merges with remote master Local refs configured for 'git push': dev-branch pushes to dev-branch (up to date) markdown-strip pushes to markdown-strip (up to date) master pushes to master (up to date)
这个命令列出了当你在特定的分支上执行
git push
会自动地推送到哪一个远程分支。 它也同样地列出了哪些远程分支不在你的本地,哪些远程分支已经从服务器上移除了, 还有当你执行 git pull
时哪些本地分支可以与它跟踪的远程分支自动合并。git fetch
现在你可以在命令行中使用字符串
pb
来代替整个 URL。 例如,如果你想拉取 Paul 的仓库中有但你没有的信息,可以运行 git fetch pb
:$ 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
就如刚才所见,从远程仓库中获得数据,可以执行
$ git fetch <remote>
这个命令会访问远程仓库,从中拉取所有你还没有的数据。 执行完成后,你将会拥有那个远程仓库中所有分支的引用,可以随时合并或查看。
如果你使用
clone
命令克隆了一个仓库,命令会自动将其添加为远程仓库并默认以 “origin” 为简写。 所以,git fetch origin
会抓取克隆(或上一次抓取)后新推送的所有工作。 必须注意 git fetch
命令只会将数据下载到你的本地仓库——它并不会自动合并或修改你当前的工作。 当准备好时你必须手动将其合并入你的工作。如果你的当前分支设置了跟踪远程分支(阅读下一节和 Git 分支 了解更多信息), 那么可以用
git pull
命令来自动抓取后合并该远程分支到当前分支。 这或许是个更加简单舒服的工作流程。默认情况下,git clone
命令会自动设置本地 master 分支跟踪克隆的远程仓库的 master
分支(或其它名字的默认分支)。 运行 git pull
通常会从最初克隆的服务器上抓取数据并自动尝试合并到当前所在的分支。
关于 fetch 和 pull 的区别👇git push
当你想分享你的项目时,必须将其推送到上游:
git push <remote> <branch>
。当你想要将
master
分支推送到 origin
服务器时(再次说明,克隆时通常会自动帮你设置好那两个名字), 那么运行这个命令就可以将你所做的备份到服务器:$ git push origin master
只有当你有所克隆服务器的写入权限,并且之前没有人推送过时,这条命令才能生效。当你和其他人在同一时间克隆,他们先推送到上游然后你再推送到上游,你的推送就会毫无疑问地被拒绝。 你必须先抓取他们的工作并将其合并进你的工作后才能推送。
.gitignore
一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。 通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。 在这种情况下,我们可以创建一个名为
.gitignore
的文件,列出要忽略的文件的模式。 来看一个实际的 .gitignore
例子:$ cat .gitignore *.[oa] *~
第一行告诉 Git 忽略所有以
.o
或 .a
结尾的文件。一般这类对象文件和存档文件都是编译过程中出现的。 第二行告诉 Git 忽略所有名字以波浪符(~)结尾的文件,许多文本编辑软件(比如 Emacs)都用这样的文件名保存副本。 此外,你可能还需要忽略 log,tmp 或者 pid 目录,以及自动生成的文档等等。 要养成一开始就为你的新仓库设置好 .gitignore 文件的习惯,以免将来误提交这类无用的文件。文件
.gitignore
的格式规范如下:- 所有空行或者以
#
开头的行都会被 Git 忽略。
- 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中。
- 匹配模式可以以(
/
)开头防止递归。
- 匹配模式可以以(
/
)结尾指定目录。
- 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(
!
)取反。
所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。
*
匹配零个或多个任意字符;
[abc]
匹配任何一个列在方括号中的字符(a or b or c);
?
只匹配一个任意字符;
- 如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配(比如
[0-9]
表示匹配所有 0 到 9 的数字)。
**
表示匹配任意中间目录,如a/**/z
匹配a/z
a/b/z
a/b/c/z
等。
# 忽略所有的 .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 tag
像其他版本控制系统(VCS)一样,Git 可以给仓库历史中的某一个提交打上标签,以示重要。 比较有代表性的是人们会使用这个功能来标记发布结点(
v1.0
、 v2.0
等等)。 Git 支持两种标签:轻量标签(lightweight)与附注标签(annotated)。
附注标签是存储在 Git 数据库中的一个完整对象,它们是可以被校验的,其中包含打标签者的名字、电子邮件地址、日期时间,此外还有一个标签信息,并且可以使用 GNU Privacy Guard (GPG)签名并验证。通常会建议创建附注标签,这样你可以拥有以上所有信息。但是如果你只是想用一个临时的标签,或者因为某些原因不想要保存这些信息,那么也可以用轻量标签。
在 Git 中创建附注标签十分简单。 最简单的方式是当你在运行
tag
命令时指定 -a
选项:$ git tag -a v1.4 -m "my version 1.4" $ git tag v0.1 v1.3 v1.4 $ git tag -l "v1.*" v1.3 v1.4
-m
选项指定了一条将会存储在标签中的信息。 如果没有为附注标签指定一条信息,Git 会启动编辑器要求你输入信息。通过使用
git show
命令可以看到标签信息和与之对应的提交信息:$ git show v1.4 tag v1.4 Tagger: Ben Straub <ben@straub.cc> Date: Sat May 3 20:19:12 2014 -0700 my version 1.4 commit ca82a6dff817ec66f44342007202690a93763949 Author: Scott Chacon <schacon@gee-mail.com> 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 v1.5
$ git show v1.4-lw commit ca82a6dff817ec66f44342007202690a93763949 Author: Scott Chacon <schacon@gee-mail.com> 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 -a v1.2 9fceb02 $ git tag v0.1 v1.2 v1.3 v1.4 v1.4-lw v1.5 $ git show v1.2 tag v1.2 Tagger: Scott Chacon <schacon@gee-mail.com> Date: Mon Feb 9 15:32:16 2009 -0800 version 1.2 commit 9fceb02d0ae598e95dc970b74767f19372d61af8 Author: Magnus Chacon <mchacon@gee-mail.com> Date: Sun Apr 27 20:43:35 2008 -0700 updated rakefile ...
默认情况下,
git push
命令并不会传送标签到远程仓库服务器上。在创建完标签后你必须显式地推送标签到共享服务器上。这个过程就像共享远程分支一样: git push origin <tagname>
。$ 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 git@github.com:schacon/simplegit.git * [new tag] v1.5 -> v1.5
如果想要一次性推送很多标签,也可以使用带有
--tags
选项的 git push
命令。 这将会把所有不在远程仓库服务器上的标签全部传送到那里。$ 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 git@github.com:schacon/simplegit.git * [new tag] v1.4 -> v1.4 * [new tag] v1.4-lw -> v1.4-lw
要删除掉你本地仓库上的标签,可以使用命令
git tag -d <tagname>
。例如删除一个轻量标签:$ git tag -d v1.4-lw Deleted tag 'v1.4-lw' (was e7d5add)
注意上述命令并不会从任何远程仓库中移除这个标签
你必须用
git push <remote> :refs/tags/<tagname>
来更新你的远程仓库:第一种变体是
git push <remote> :refs/tags/<tagname>
:$ git push origin :refs/tags/v1.4-lw To /git@github.com:schacon/simplegit.git - [deleted] v1.4-lw
上面这种操作的含义是,将冒号前面的空值推送到远程标签名,从而高效地删除它。
第二种更直观的删除远程标签的方式是:
$ git push origin --delete <tagname>