git笔记
Git 基本操作
整理自网上材料
git clone
git clone <版本库的网址>
git clone https://github.com/xxxx/xxx.git
该命令会在本地主机生成一个目录,与远程主机的版本库同名。如果要指定不同的目录名,可以将目录名作为git clone
命令的第二个参数。
git clone <版本库的网址> <本地目录名>
git clone`支持多种协议,除了HTTP(s)以外,还支持SSH、Git、本地文件协议等
$ git clone http[s]://example.com/path/to/repo.git/
$ git clone ssh://example.com/path/to/repo.git/
$ git clone git://example.com/path/to/repo.git/
$ git clone /opt/git/project.git
$ git clone file:///opt/git/project.git
$ git clone ftp[s]://example.com/path/to/repo.git/
$ git clone rsync://example.com/path/to/repo.git/
SSH协议还有另一种写法。
$ git clone [user@]example.com:path/to/repo.git/
通常来说,Git协议下载速度最快,SSH协议用于需要用户认证的场合。各种协议优劣的详细讨论请参考官方文档。
git remote
为了便于管理,Git要求每个远程主机都必须指定一个主机名。git remote
命令就用于管理主机名。
不带选项的时候,git remote
命令列出所有远程主机。
$ git remote
origin
使用-v
选项,可以参看远程主机的网址。
$ git remote -v
origin git@github.com:jquery/jquery.git (fetch)
origin git@github.com:jquery/jquery.git (push)
上面命令表示,当前只有一台远程主机,叫做origin,以及它的网址。
克隆版本库的时候,所使用的远程主机自动被Git命名为origin
。如果想用其他的主机名,需要用git clone
命令的-o
选项指定。
$ git clone -o jQuery https://github.com/jquery/jquery.git
$ git remote
jQuery
上面命令表示,克隆的时候,指定远程主机叫做jQuery。
git remote show
命令加上主机名,可以查看该主机的详细信息。
$ git remote show <主机名>
git remote add
命令用于添加远程主机。
$ git remote add <主机名> <网址>
git remote rm
命令用于删除远程主机。
$ git remote rm <主机名>
git remote rename
命令用于远程主机的改名。
$ git remote rename <原主机名> <新主机名>
git fetch
一旦远程主机的版本库有了更新(Git术语叫做commit),需要将这些更新取回本地,这时就要用到git fetch
命令。
$ git fetch <远程主机名>
上面命令将某个远程主机的更新,全部取回本地。
git fetch
命令通常用来查看其他人的进程,因为它取回的代码对你本地的开发代码没有影响。
默认情况下,git fetch
取回所有分支(branch)的更新。如果只想取回特定分支的更新,可以指定分支名。
$ git fetch <远程主机名> <分支名>
比如,取回origin
主机的master
分支。
$ git fetch origin master
所取回的更新,在本地主机上要用"远程主机名/分支名"的形式读取。比如origin
主机的master
,就要用origin/master
读取。
git branch
命令的-r
选项,可以用来查看远程分支,-a
选项查看所有分支。
$ git branch -r
origin/master
$ git branch -a
* master
remotes/origin/master
上面命令表示,本地主机的当前分支是master
,远程分支是origin/master
。
取回远程主机的更新以后,可以在它的基础上, 使用git checkout
命令创建一个新的分支。
$ git checkout -b newBrach origin/master
上面命令表示,在origin/master
的基础上,创建一个新分支。
此外,也可以使用git merge
命令或者git rebase
命令,在本地分支上合并远程分支。
$ git merge origin/master
# 或者
$ git rebase origin/master
上面命令表示在当前分支上,合并origin/master
。
使用fetch命令取回更新后,会返回一个FETCH_HEAD
,指的是某个branch在服务器上的最新状态,我们可以在本地通过它查看刚取回的更新信息:
$ git log -p FETCH_HEAD
如果觉得fetch取回的更新没有问题,可以合并到本地分支上:
$ git fetch origin master //从远程主机的master分支拉取最新内容
$ git merge FETCH_HEAD //将拉取下来的最新内容合并到当前所在的分支中
一般使用git pull 来代替代替fetch 和 merge
git pull
git pull
命令的作用是,取回远程主机某个分支的更新,再与本地的指定分支合并。它的完整格式稍稍有点复杂。
$ git pull <远程主机名> <远程分支名>:<本地分支名>
比如,取回origin
主机的next
分支,与本地的master
分支合并,需要写成下面这样。
$ git pull origin next:master
如果远程分支是与当前分支合并,则冒号后面的部分可以省略。
$ git pull origin next
上面命令表示,取回origin/next
分支,再与当前分支合并。实质上,这等同于先做git fetch
,再做git merge
。
$ git fetch origin
$ git merge origin/next
在某些场合,Git会自动在本地分支与远程分支之间,建立一种追踪关系(tracking)。比如,在git clone
的时候,所有本地分支默认与远程主机的同名分支,建立追踪关系,也就是说,本地的master
分支自动"追踪"origin/master
分支。
Git也允许手动建立追踪关系。
$ git branch --set-upstream master origin/next
上面命令指定master
分支追踪origin/next
分支。
如果当前分支与远程分支存在追踪关系,git pull
就可以省略远程分支名。
$ git pull origin
上面命令表示,本地的当前分支自动与对应的origin
主机"追踪分支"(remote-tracking branch)进行合并。
如果当前分支只有一个追踪分支,连远程主机名都可以省略。
$ git pull
上面命令表示,当前分支自动与唯一一个追踪分支进行合并。
如果合并需要采用rebase模式,可以使用--rebase
选项。
$ git pull --rebase <远程主机名> <远程分支名>:<本地分支名>
如果远程主机删除了某个分支,默认情况下,git pull
不会在拉取远程分支的时候,删除对应的本地分支。这是为了防止,由于其他人操作了远程主机,导致git pull
不知不觉删除了本地分支。
但是,你可以改变这个行为,加上参数 -p
就会在本地删除远程已经删除的分支。
$ git pull -p
# 等同于下面的命令
$ git fetch --prune origin
$ git fetch -p
git push
git push
命令用于将本地分支的更新,推送到远程主机。它的格式与git pull
命令相仿。
$ git push <远程主机名> <本地分支名>:<远程分支名>
注意,分支推送顺序的写法是<来源地>:<目的地>,所以git pull
是<远程分支>:<本地分支>,而git push
是<本地分支>:<远程分支>。
如果省略远程分支名,则表示将本地分支推送与之存在"追踪关系"的远程分支(通常两者同名),如果该远程分支不存在,则会被新建。
$ git push origin master
上面命令表示,将本地的master
分支推送到origin
主机的master
分支。如果后者不存在,则会被新建。
如果省略本地分支名,则表示删除指定的远程分支,因为这等同于推送一个空的本地分支到远程分支。
$ git push origin :master
# 等同于
$ git push origin --delete master
上面命令表示删除origin
主机的master
分支。
如果当前分支与远程分支之间存在追踪关系,则本地分支和远程分支都可以省略。
$ git push origin
上面命令表示,将当前分支推送到origin
主机的对应分支。
如果当前分支只有一个追踪分支,那么主机名都可以省略。
$ git push
如果当前分支与多个主机存在追踪关系,则可以使用-u
选项指定一个默认主机,这样后面就可以不加任何参数使用git push
。
$ git push -u origin master
上面命令将本地的master
分支推送到origin
主机,同时指定origin
为默认主机,后面就可以不加任何参数使用git push
了。
不带任何参数的git push
,默认只推送当前分支,这叫做simple方式。此外,还有一种matching方式,会推送所有有对应的远程分支的本地分支。Git 2.0版本之前,默认采用matching方法,现在改为默认采用simple方式。如果要修改这个设置,可以采用git config
命令。
$ git config --global push.default matching
# 或者
$ git config --global push.default simple
还有一种情况,就是不管是否存在对应的远程分支,将本地的所有分支都推送到远程主机,这时需要使用--all
选项。
$ git push --all origin
上面命令表示,将所有本地分支都推送到origin
主机。
如果远程主机的版本比本地版本更新,推送时Git会报错,要求先在本地做git pull
合并差异,然后再推送到远程主机。这时,如果你一定要推送,可以使用--force
选项。
$ git push --force origin
上面命令使用--force
选项,结果导致远程主机上更新的版本被覆盖。除非你很确定要这样做,否则应该尽量避免使用--force
选项。
最后,git push
不会推送标签(tag),除非使用--tags
选项。
$ git push origin --tags
git add
添加文件到暂存区
# 添加某个文件到暂存区,后面可以跟多个文件,以空格区分
git add xxx
# 添加当前更改的所有文件到暂存区。
git add .
git commit
# 提交暂存的更改,会新开编辑器进行编辑
git commit
# 提交暂存的更改,并记录下备注
git commit -m "you message"
# 等同于 git add . && git commit -m
git commit -am
# 对最近一次的提交的信息进行修改,此操作会修改commit的hash值
git commit --amend
git branch
# 新建本地分支,但不切换
git branch <branch-name>
# 查看本地分支
git branch
# 查看远程分支
git branch -r
# 查看本地和远程分支
git branch -a
# 删除本地分支
git branch -D <branch-nane>
# 重新命名分支
git branch -m <old-branch-name> <new-branch-name>
通过 git branch -d git branch -d fix/authentication
。
当一个分支被推送并合并到远程分支后, -d 才会本地删除该分支。
如果一个分支还没有被推送或者合并,那么可以使用 -D 强制删除它。 这就是本地删除分支的方法。
已有本地分支,与远程库创建关联
git branch --set-upstream-to origin/远程分支名 本地分支名
git checkout
git checkout命令对三个不同的实体进行操作, 它们分别是文件, 提交和分支。有时, 此命令可能很危险, 因为此命令上没有撤消选项。
切换本地分支,前提是分支存在:
$ git checkout <branchname>
创建并切换分支,注意,它是基于本地库当前所处的分支上创建并切换,与远程库没有关系:
$ git checkout -b <branchname>
git checkout命令使你可以创建并切换到新分支。你不仅可以创建一个新分支, 还可以通过单个命令同时切换它。 git checkout -b选项是一个便利标志, 它在运行git checkout
拉去远程库分支,并在本地创建新分支,然后切换到新的分支上:
git checkout -b 本地分支名 origin/远程分支名
注意:这是针对本地没有改分支。
如果拉去不成功,则可能是本地没有远程库的信息,需要先执行:
git fetch
然后再
git checkout -b 本地分支名 origin/远程分支名
使用git pull命令也可以:
$ git pull <远程主机名> <远程分支名>:<本地分支名>
git merge
合并分支
git merge branchname
git log
查看版本信息
# 查看版本
git reflog
# 查看版本详细信息
git log
git reset
如果想恢复到之前某个提交的版本,且那个版本之后提交的版本我们都不要了,就可以用这种方法。
版本穿梭
git reset --hard 版本号
退回到上一个版本
git reset --hard HEAD^
此时如果用
git push
会报错,因为我们本地库HEAD指向的版本比远程库的要旧:需要使用
git push -f
强推版本。
git revert
git revert
是用于“反转、逆转”某一个版本,以达到撤销该版本的修改的目的。比如,我们commit了三个版本(版本一、版本二、 版本三),突然发现版本二不行(如:有bug),想要撤销版本二,但又不想影响撤销版本三的提交,就可以用 git revert 命令来反做版本二,生成新的版本四,这个版本四里会保留版本三的东西,但撤销了版本二的东西。
最重要的一点:revert 是回滚某个 commit ,不是回滚“到”某个
命令
git revert -n 版本号
git rebase
rebase 是”变基”的意思,这里的”基”,在我理解是指[多次] commit 形成的 git workflow,使用 rebase,我们可以改变这些历史提交,修改 commit 信息,将多个 commit 进行组合。
git tag
列出标签
# 可带上可选的 -l 选项 --list
git tag
# 如果只对 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 支持两种标签:轻量标签(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
-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
,你不会看到额外的标签信息。 命令只会显示出提交信息:
$ 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
。
$ 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
现在,当其他人从仓库中克隆或拉取,他们也能得到你的那些标签。
Note | git push 推送两种标签 使用 git push --tags 推送标签并不会区分轻量标签和附注标签, 没有简单的选项能够让你只选择推送一种标签。 |
---|---|
删除标签
要删除掉你本地仓库上的标签,可以使用命令 git tag -d
。 例如,可以使用以下命令删除一个轻量标签:
$ git tag -d v1.4-lw
Deleted tag 'v1.4-lw' (was e7d5add)
注意上述命令并不会从任何远程仓库中移除这个标签,你必须用 git push :refs/tags/
来更新你的远程仓库:
第一种变体是 git push :refs/tags/
:
$ git push origin :refs/tags/v1.4-lw
To /git@github.com:schacon/simplegit.git
- [deleted] v1.4-lw
上面这种操作的含义是,将冒号前面的空值推送到远程标签名,从而高效地删除它。
第二种更直观的删除远程标签的方式是:
$ git push origin --delete <tagname>
检出标签
如果你想查看某个标签所指向的文件版本,可以使用 git checkout
命令, 虽然这会使你的仓库处于“分离头指针(detached HEAD)”的状态——这个状态有些不好的副作用:
$ 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 -b version2 v2.0.0
Switched to a new branch 'version2'
如果在这之后又进行了一次提交,version2
分支就会因为这个改动向前移动, 此时它就会和 v2.0.0
标签稍微有些不同,这时就要当心了。
将tag同步到远程服务器
同提交代码后,使用git push
来推送到远程服务器一样,tag
也需要进行推送才能到远端服务器。
使用git push origin [tagName]
推送单个分支。
git push origin v1.0
推送本地所有tag,使用git push origin --tags
。