[关闭]
@lemonguge 2017-09-13T14:49:14.000000Z 字数 9325 阅读 375

Git仓库和操作

Git


在提交了若干更新,又或者克隆了某个项目之后,你也许想回顾下提交历史

接下来的例子会用我专门用于演示的 simplegit 项目, 运行下面的命令获取该项目源代码:

  1. $ git clone https://github.com/schacon/simplegit-progit progit

查看提交历史

git log 命令可以用来查看提交历史,运行该命令后,可以看到下面的输出:

  1. $ git log
  2. commit ca82a6dff817ec66f44342007202690a93763949
  3. Author: Scott Chacon <schacon@gee-mail.com>
  4. Date: Mon Mar 17 21:52:11 2008 -0700
  5. changed the version number
  6. commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
  7. Author: Scott Chacon <schacon@gee-mail.com>
  8. Date: Sat Mar 15 16:40:33 2008 -0700
  9. removed unnecessary test
  10. commit a11bef06a3f659402fe7563abf99ad00de2209e6
  11. Author: Scott Chacon <schacon@gee-mail.com>
  12. Date: Sat Mar 15 10:31:28 2008 -0700
  13. first commit

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

git log 有许多选项可以帮助你搜寻你所要找的提交,接下来我们介绍些最常用的:


撤销操作

撤销提交

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

  1. $ git commit --amend

这个命令会将暂存区中的文件提交。如果自上次提交以来你还未做任何修改(例如,在上次提交后马上执行了此命令),那么快照会保持不变,而你所修改的只是提交信息。

文本编辑器启动后,可以看到之前的提交信息,编辑后保存会覆盖原来的提交信息。

例如,你提交后发现忘记了暂存某些需要的修改,可以像下面这样操作:

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

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

撤销暂存

例如,你已经修改了两个文件并且想要将它们作为两次独立的修改提交,但是却意外地输入了 git add * 暂存了它们两个。如何只取消暂存两个中的一个呢? git status 命令提示了你:

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

在 “Changes to be committed” 文字正下方,提示使用 git reset HEAD <file>... 来取消暂存。所以,我们可以这样来取消暂存 CONTRIBUTING.md 文件:

  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

撤销修改

如果你并不想保留对 CONTRIBUTING.md 文件的修改怎么办? 你该如何方便地撤消修改 - 将它还原成上次提交时的样子(或者刚克隆完的样子,或者刚把它放入工作目录时的样子)? 幸运的是,git status 也告诉了你应该如何做。 在最后一个例子中,未暂存区域是这样:

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

你需要知道 git checkout -- [file] 是一个危险的命令,这很重要。你对那个文件做的任何修改都会消失 - 你只是拷贝了另一个文件来覆盖它。


远程仓库的使用

远程仓库是指托管在因特网或其他网络中的你的项目的版本库

为了能在任意 Git 项目上协作,你需要知道如何管理自己的远程仓库。你可以有好几个远程仓库,通常有些仓库对你只读,有些则可以读写,与他人协作涉及管理远程仓库以及根据需要推送或拉取数据。

这里使用 Github 的远程仓库:

  1. $ git clone https://github.com/lemonguge/git.git

查看远程仓库

如果想查看你已经配置的远程仓库服务器,可以运行 git remote 命令。它会列出你指定的每一个远程服务器的简写。如果你已经克隆了自己的仓库,那么至少应该能看到 origin - 这是 Git 给你克隆的仓库服务器的默认名字:

  1. $ git remote
  2. origin

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

  1. $ git remote -v
  2. origin https://github.com/lemonguge/git.git (fetch)
  3. origin https://github.com/lemonguge/git.git (push)

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

  1. $ git remote show origin
  2. * remote origin
  3. Fetch URL: https://github.com/lemonguge/git.git
  4. Push URL: https://github.com/lemonguge/git.git
  5. HEAD branch: master
  6. Remote branch:
  7. master tracked
  8. Local branch configured for 'git pull':
  9. master merges with remote master
  10. Local ref configured for 'git push':
  11. master pushes to master (up to date)

它同样会列出远程仓库的 URL 与跟踪分支的信息。 这些信息非常有用,它告诉你正处于 master 分支,并且如果运行 git pull,就会抓取所有的远程引用,然后将远程 master 分支合并到本地 master 分支,运行 git push,将本地 master 分支推送到远程 master 分支。

这是一个经常遇到的简单例子。 如果你是 Git 的重度使用者,那么还可以通过 git remote show 看到更多的信息。

  1. $ git remote show origin
  2. * remote origin
  3. URL: https://github.com/my-org/complex-project
  4. Fetch URL: https://github.com/my-org/complex-project
  5. Push URL: https://github.com/my-org/complex-project
  6. HEAD branch: master
  7. Remote branches:
  8. master tracked
  9. dev-branch tracked
  10. markdown-strip tracked
  11. issue-43 new (next fetch will store in remotes/origin)
  12. issue-45 new (next fetch will store in remotes/origin)
  13. refs/remotes/origin/issue-11 stale (use 'git remote prune' to remove)
  14. Local branches configured for 'git pull':
  15. dev-branch merges with remote dev-branch
  16. master merges with remote master
  17. Local refs configured for 'git push':
  18. dev-branch pushes to dev-branch (up to date)
  19. markdown-strip pushes to markdown-strip (up to date)
  20. master pushes to master (up to date)

这个命令列出了当你在特定的分支上执行 git push 会自动地推送到哪一个远程分支。它也同样地列出了哪些远程分支不在你的本地,哪些远程分支已经从服务器上移除了,还有当你执行 git pull 时哪些分支会自动合并。

添加远程仓库

运行 git remote add <shortname> <url> 添加一个新的远程 Git 仓库,同时指定一个你可以轻松引用的简写:

  1. $ git remote add pb https://github.com/paulboone/ticgit
  2. $ git remote -v
  3. origin https://github.com/lemonguge/git.git (fetch)
  4. origin https://github.com/lemonguge/git.git (push)
  5. pb https://github.com/paulboone/ticgit (fetch)
  6. pb https://github.com/paulboone/ticgit (push)

现在你可以在命令行中使用字符串 pb 来代替整个 URL。 例如,如果你想拉取 Paul 的仓库中有但你没有的信息,可以运行 git fetch pb

  1. $ git fetch pb
  2. remote: Counting objects: 634, done.
  3. remote: Total 634 (delta 0), reused 0 (delta 0), pack-reused 634
  4. Receiving objects: 100% (634/634), 109.68 KiB | 79.00 KiB/s, done.
  5. Resolving deltas: 100% (232/232), done.
  6. From https://github.com/paulboone/ticgit
  7. * [new branch] master -> pb/master
  8. * [new branch] ticgit -> pb/ticgit

现在 Paul 的 master 分支可以在本地通过 pb/master 访问到 - 你可以将它合并到自己的某个分支中,或者如果你想要查看它的话,可以检出一个指向该点的本地分支。

从远程仓库中抓取与拉取

就如刚才所见,从远程仓库中获得数据,可以执行:

  1. $ git fetch [remote-name]

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

如果你使用 git clone 命令克隆了一个仓库,命令会自动将其添加为远程仓库并默认以 “origin” 为简写,自动设置本地 master 分支跟踪克隆的远程仓库的 master 分支(或不管是什么名字的默认分支)。所以,git fetch origin 会抓取克隆(或上一次抓取)后新推送的所有工作。必须注意 git fetch 命令会将数据拉取到你的本地仓库 - 它并不会自动合并或修改你当前的工作。当准备好时你必须手动将其合并入你的工作。

如果你有一个分支设置为跟踪一个远程分支,可以使用 git pull 命令来自动的抓取然后合并远程分支到当前分支。

推送到远程仓库

当你想分享你的项目时,必须将其推送到上游。这个命令很简单:git push [remote-name] [branch-name]。当你想要将 master 分支推送到 origin 服务器时(再次说明,克隆时通常会自动帮你设置好那两个名字),那么运行这个命令就可以将你所做的备份到服务器:

  1. $ git push origin master

只有当你有所克隆服务器的写入权限,并且之前没有人推送过时,这条命令才能生效。当你和其他人在同一时间克隆,他们先推送到上游然后你再推送到上游,你的推送就会毫无疑问地被拒绝。你必须先将他们的工作拉取下来并将其合并进你的工作后才能推送。

远程仓库的移除与重命名

如果想要重命名引用的名字可以运行 git remote rename 去修改一个远程仓库的简写名。 例如,想要将 pb 重命名为 paul,可以用 git remote rename 这样做:

  1. $ git remote rename pb paul
  2. $ git remote
  3. origin
  4. paul

值得注意的是这同样也会修改你的远程分支名字。那些过去引用 pb/master 的现在会引用 paul/master

如果因为一些原因想要移除一个远程仓库 - 你已经从服务器上搬走了或不再想使用某一个特定的镜像了,又或者某一个贡献者不再贡献了 - 可以使用 git remote rm

  1. $ git remote rm paul
  2. $ git remote
  3. origin

打标签

列出标签

在 Git 中列出已有的标签是非常简单直观的,只需要输入 git tag

  1. $ git clone https://github.com/mrniko/redisson.git
  2. $ git tag
  3. redisson-1.0.0
  4. redisson-1.0.1
  5. redisson-1.0.2
  6. ...

也可以使用特定的模式查找标签,如下:

  1. $ git tag -l 'redisson-2.2.2*'
  2. redisson-2.2.2
  3. redisson-2.2.20
  4. redisson-2.2.21

创建标签

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

建议创建附注标签,这样你可以拥有打标签者的名字、电子邮件地址、日期时间,以及标签信息。如果你只是想用一个临时的标签,或者因为某些原因不想要保存那些信息,轻量标签也是可用的。

附注标签

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

  1. $ git tag -a -m "first annotation tag" v1.0
  2. $ git tag -a v1.1 -m "second annotation tag"
  3. $ git tag
  4. v1.0
  5. v1.1

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

轻量标签

轻量标签本质上是将提交校验和存储到一个文件中 - 没有保存任何其他信息。创建轻量标签,不需要使用 -a-s-m 选项,只需要提供标签名字:

  1. $ git tag v1.1-lw
  2. $ git tag
  3. v1.0
  4. v1.1
  5. v1.1-lw

后期标签

也可以对过去的提交打标签,使用之前介绍过的 git log --all --oneline --graph --decorate 命令:

  1. $ git log --all --oneline --graph --decorate
  2. * fc7a94b (HEAD, tag: v1.2, master) case
  3. * f5c0680 add update
  4. * 314cba6 (tag: v1.1-lw, tag: v1.1, tag: v1.0, origin/master, origin/HEAD) first commit

如果想对 f5c0680 进行打标签,需要在命令的末尾指定提交的校验和:

  1. $ git tag -a v1.1.2 -m "future tag" f5c0680
  2. $ git log --all --oneline --graph --decorate
  3. * fc7a94b (HEAD, tag: v1.2, master) case
  4. * f5c0680 (tag: v1.1.2) add update
  5. * 314cba6 (tag: v1.1-lw, tag: v1.1, tag: v1.0, origin/master, origin/HEAD) first commit

查看标签

通过使用 git show 命令,如果是附注标签,可以看到标签信息与对应的提交信息,如果是轻量标签,不会看到额外的标签信息,命令只会显示出提交信息:

  1. $ git show v1.1
  2. tag v1.1
  3. Tagger: homjie <1248823086@qq.com>
  4. Date: Mon Jul 25 10:48:47 2016 +0800
  5. second annotation tag
  6. commit 314cba6f692fc862267809d934ddccb2643cdcb2
  7. Author: lemonguge <1248823086@qq.com>
  8. Date: Sun Jul 24 21:48:14 2016 +0800
  9. first commit
  10. diff --git a/RD b/RD
  11. new file mode 100644
  12. index 0000000..aa7eb1c
  13. --- /dev/null
  14. +++ b/RD
  15. @@ -0,0 +1 @@
  16. $ git show v1.1-lw
  17. commit 314cba6f692fc862267809d934ddccb2643cdcb2
  18. Author: lemonguge <1248823086@qq.com>
  19. Date: Sun Jul 24 21:48:14 2016 +0800
  20. first commit
  21. diff --git a/RD b/RD
  22. new file mode 100644
  23. index 0000000..aa7eb1c
  24. --- /dev/null
  25. +++ b/RD
  26. @@ -0,0 +1 @@
  27. +Hello Github

共享标签

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

  1. $ git push origin v1.1.2
  2. Counting objects: 6, done.
  3. Delta compression using up to 4 threads.
  4. Compressing objects: 100% (2/2), done.
  5. Writing objects: 100% (4/4), 373 bytes | 0 bytes/s, done.
  6. Total 4 (delta 0), reused 0 (delta 0)
  7. To https://github.com/lemonguge/git.git
  8. * [new tag] v1.1.2 -> v1.1.2

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

  1. $ git push origin --tags
  2. Counting objects: 9, done.
  3. Delta compression using up to 4 threads.
  4. Compressing objects: 100% (3/3), done.
  5. Writing objects: 100% (5/5), 430 bytes | 0 bytes/s, done.
  6. Total 5 (delta 1), reused 0 (delta 0)
  7. To https://github.com/lemonguge/git.git
  8. * [new tag] v1.0 -> v1.0
  9. * [new tag] v1.1 -> v1.1
  10. * [new tag] v1.1-lw -> v1.1-lw
  11. * [new tag] v1.2 -> v1.2

现在,当其他人从仓库中克隆或拉取,他们也能得到你的那些标签。

检出标签

在 Git 中你并不能真的检出一个标签,因为它们并不能像分支一样来回移动。如果你想要工作目录与仓库中特定的标签版本完全一样,可以使用 git checkout -b [branchname] [tagname] 在特定的标签上创建一个新分支

  1. $ git checkout -b dev-v1.1 v1.1
  2. Switched to a new branch 'dev-v1.1'
  3. $ git log --all --oneline --decorate --graph
  4. * fc7a94b (tag: v1.2, master) case
  5. * f5c0680 (tag: v1.1.2) add update
  6. * 314cba6 (HEAD, tag: v1.1-lw, tag: v1.1, tag: v1.0, origin/master, origin/HEAD, dev-v1.1) first commit

删除标签

删除本地标签,可以使用 -d 选项:

  1. $ git tag -d v1.1-lw
  2. Deleted tag 'v1.1-lw' (was 314cba6)
  3. $ git status
  4. On branch dev-v1.1
  5. nothing to commit, working directory clean
  6. $ git log --all --oneline --decorate --graph
  7. * fc7a94b (tag: v1.2, master) case
  8. * f5c0680 (tag: v1.1.2) add update
  9. * 314cba6 (HEAD, tag: v1.1, tag: v1.0, origin/master, origin/HEAD, dev-v1.1) first commit

如果想删除远程标签,可以使用 --delete 选项:

  1. $ git tag
  2. v1.0
  3. v1.1
  4. v1.1.2
  5. v1.2
  6. $ git push origin --delete tag v1.1-lw
  7. To https://github.com/lemonguge/git.git
  8. - [deleted] v1.1-lw

Git别名

如果不想每次都输入完整的 Git 命令,可以通过 git config 文件来轻松地为每一个命令设置一个别名。

  1. $ git config --global alias.co checkout
  2. $ git config --global alias.br branch
  3. $ git config --global alias.ci commit
  4. $ git config --global alias.st status
  5. $ git config --global alias.unstage 'reset HEAD --'

当我们想要取消暂存是,可以使用 git unstage fileA,这将等价于 git reset HEAD -- fileA

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注