Git 的常用命令
查看 Git 配置
$ git config
用来配置或读取相应的工作环境变量。
配置用户信息
$ git config --global user.name "XXX"
$ git config --blobal user.email XXX@XXX.com
配置个人的用户名陈和电子邮箱地址,每次 Git 提交都会引用这两条信息,说明是谁提交了更新,会随着更近内容被永久纳入历史记录。
配置文本编辑器
$ git config --global core.editor XXX
差异分析工具
$ git config --global merge.tool XXX
查看配置信息
$ git config --list
Git 获取帮助
$ git help <verb
$ git <verb> --help
$ man git-<verb>
创建 Git 仓库
- 创建空目录
- 使用
$ git init
创建仓库
当前状态查看
$ git status
跟踪新文件
$ git add <file>
忽略某些文件
一般我们总会有些文件无需纳入 Git 的管理,也不希望他们总出现在未跟踪文件列表。通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。我们可以创建一个名为 .gitignore 的文件,列出要忽略的文件模式。
文件.gitignore 的格式规范如下:
- 所有空行或者以注释符号 # 开头的行都会被 Git 忽略。
- 可以使用标准的 glob 模式匹配。
- 匹配模式最后跟反斜杠(/)说明要忽略的是目录。
- 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。
所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。星号(*)匹配零个或多个任意字符;[abc] 匹配任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);问号(?)只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。
我们看一些 .gitignore 文件的示例:
# 此为注释 – 将被 Git 忽略
# 忽略所有 .a 结尾的文件
*.a
# 但 lib.a 除外
!lib.a
# 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
/TODO
# 忽略 build/ 目录下的所有文件
build/
# 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目录下的所有 .txt 文件
doc/**/*.txt
查看具体修改内容
$ git diff
此命令比较的是工作目录中当前文件和暂存区域快照之间的差异,也就是修改之后还没有暂存起来的变化内容。
$ git diff --staged
可以通过加上 --cached 或 --staged 命令来查看已经暂存起来的文件和上次提交时的快照之间的差异。
git diff <file>
查看具体文件的更新情况
提交更新
$ git commit
会将所有进入暂存状态的文件进行提交。
$ git commit -m
使用参数 -m
来对提交进行说明。
$ git commit -a
加上选项 -a
Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add 步骤。
移除文件
$ git rm <file>
要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除,然后进行提交,该文件就不再纳入版本管理了。
$ git rm --cached <file>
这个指令可以把文件从 Git 仓库中删除,但仍会保留在当前工作目录中,话句话说,仅是从跟踪清单中删除。比如一些大型日志文件或临时文件,不小心纳入仓库之后,要移除跟踪但不删除文件,以便之后添加到忽略文件列表中。
后面可以列出文件或者目录的名字,也可以使用 glob 模式。
$ git rm log/\*.log
该指令会删除 log/ 目录下扩展名为 .log 的文件。
文件改名/移动文件
$ git mv <file_from> <file_to>
无论是文件改名或者是文件的移动都可以使用上面的指令。其实,运行 git mv 就相当于运行了下面三条命令。
$ mv README.txt README
$ git rm README.txt
$ git add README
提交历史查询
$ git log
默认不使用任何参数的话,git log 会按提交时间列出所有更新,最新的更新排在上面。每次更新都以一个 SHA-1 校验和,作者的名字和电子邮件地址,提交时间,最后缩进一个段落显示提交说明。
可以增添选项来帮助你搜寻感兴趣的提交。
-
-p 选项展开显示每次提交内容的差异。
-
--word-diff 进行单词层面的对比,比行层面的对比,更加容易观察。我们可以将其添加到 git log -p 命令的后面,从而获取单词层面上的对比。
-
-g 输出包含 reflog 格式的日志信息。
-
-U1 选项进行单词层面的对比时,你可能希望上下文 (context) 行数从默认的 3 行减为 1 行,那么可以使用此选项。
-
-- stat 选项可以仅显示摘要的增改行数统计。每个提交都列出了修改过的文件,以及其中添加和移除的行数,并在最后列出所有增减行数小计。
-
-- pretty 选项,可以指定使用完全不同于默认格式的方式展示提交历史。
- --pretty=oneline 将每个提交放在一行显示,这在提交数很大时非常有用。
- --pretty=short 提供一种简短模式,省略了提交时间。
- --pretty=full 列出了提交的SHA-1校验和,作者和提交者与提交说明。
- --pretty=fuller 列出了校验和,作者,作者日期,提交者,提交日期与提交说明。
- 最强大的是 --pretty=format ,可以定制要显示的记录格式,便于后期编程提取分析。点击这里查看常用的格式占位符及代表的意义。
- 使用 --pretty=online 或者 --pretty=format 时结合 -- graph选项,可以形象的展示每个提交所在的分支以及分支衍合情况。
-
--abbrev-commit
Git 很聪明,它能够通过你提供的前几个字符来识别你想要的那次提交,只要你提供的那部分 SHA-1 不短于 4 个字符,并且没有歧义。 -
这里还有一些 git log 命令支持的选项
-
限制输出长度
- -<n>,其中,n 可以是任何自然数,表示仅显示最近的 n 条提交。
- -- since, --after 仅显示指定时间之后的提交
- -- until, --before 仅显示指定时间之前的提交
- -- author 仅显示指定作者相关的提交
- -- committer 仅显示指定提交者相关的提交
- -- grep 搜索提交说明中的关键字
- 如果想得到同事满足多个搜索条件的提交,就必须用 -- all - match 选项。否则,满足任意一个条件的提交都会被匹配出来。
- 另一个使用的选项是路径,如果只关心某些文件或者目录的历史提交,可以在 git log 选项的最后指定它们的路径。因为是放在最后位置上的选项,所以用两个短划线(--)将之前的选项和后面限定的路径名隔开。
引用日志里的简称
$ git reflog
在你工作的同时,Git 在后台的工作之一就是保存一份引用日志 -- 一份记录最近几个月你的 HEAD 和分支引用的日志。可以通过上面的指令来查看。
$ git show HEAD@{n}
每次你的分支顶端因为某些原因被修改时,Git 就会为将信息保存在这个临时历史记录里面。你也可以使用这份数据来指明更早的分支。如果你想查看仓库中 HEAD 在前 n 次的值,你可以使用引用日志的输出中的 @{n} 引用
$ git show <branch>@{time}
你也可以使用这个语法来查看某个分支在一定时间前的位置。
祖先引用
还有一种指明某次提交的常用方法是通过它的祖先。如果你在引用最后加上一个 ^
,Git 将其理解为此次提交的父提交。
如果想查看上一次提交,你可以使用 HEAD^
,意思是“HEAD 的父提交”;
你也可以在 ^ 后添加一个数字,你可以使用 d921970^2
,意思是 d921970 的第二父提交。这种语言只在合并提交时有用,因为合并提交可能有多个父提交。
另一种指向祖先提交的方法是 ~
。这也是指向第一父提交,所以 HEAD~
和 HEAD^
是等价的。当你指定数字时候就明显不一样了。 HEAD~2
实质“第一父提交的第一父提交”,也就是“祖父提交” -- 它会根据你的指定次数检索第一父提交。
提交范围
双点
最常用的指明范围的方法是双点的语法。这种语法主要是让 Git 区分出可从一个分支中获得而不能从另一个分支中获得的提交。
$ git log master..branchA
意为选出所有可从 branchA 分支中获得而不能从 master 分支中获得的提交。
三点
这个可以指定被两个引用中的一个包含但又不被两者同时包含的分支。
$ git log master...branchA
意为选出可从 master 和 branchA 分支中获得,却又不被两个分支同时包含的提交。
撤销操作
修改最后一次提交
$ git commit --amend
此指令会将当前暂存区域的内容提交,同时覆盖上次的提交历史。
取消已暂存的文件
$ git reset HEAD <file>
此指令会将暂存区的修改进行撤销(unstage),使其重新放回工作区。
取回版本库里的版本
$ git checkout --<file>
此指令会将版本库里的文件取回并替换工作区的版本,因此会丢失工作区对文件的修改,慎用。
远程仓库的使用
查看当前远程库
$ git remote
该指令会列出每个远程库的简短名字,Git 使用 origin
作为默认的远程库, 来标识你所克隆的原始仓库。
$ git remote -v
--verbose 的简写,显示对应的克隆地址。
添加远程仓库
$ git remote add <shortname> <url>
可以制定一个简单的名字以便将来引用。
查看远程仓库详细信息
$ git remote show <remote-name>
从远程仓库抓取数据
$ git fetch <remote-name>
该指令会从远程仓库中拉取所有本地仓库中还没有的数据,但不会自动合并到当前工作分支。
推送数据到远程仓库
$ git push <remote-name> <branch-name>
该指令会将本地仓库中的数据推送到远程仓库。
远程仓库重命名
$ git remote rename <from-name> <to-name>
远程仓库的删除
$ git remote rm <remote-name>
版本标签
列出已有标签
$ git tag
新建标签
轻量级标签
$ git tag <version>
含附注的标签
$ git tag -a <version>
-a (annotated)
后面可用 -m
选项指定对应的标签说明 。
签署标签
$ git tag -s <version>
-s (signed)
需要 gpg 来签署标签
验证标签
$ git tag -v <tag-name>
-v (verify)
验证已经签署的标签。此命令会调用 GPG 来验证签名,所以你需要有签署者的公钥,存放在 keyring 中,才能验证。
后期加注标签
$ git tag [-a] <version> <校验和>
只需要校验和前几位即可。
分享标签
默认情况下,git push
指令并不会把标签传送到远端服务器上,只有通过显式命令才能分享标签到远端仓库。
$ git push <branch> <tagname>
版本回退
$ git reset --hard HEAD^
表示回退到上一个版本
$ git reset --hard <版本号>
表示回退到某个版本版本
分支
创建分支
$ git branch <branchname>
Git 保存着一个名为 HEAD 的特别指针,该指针指向正在工作中的本地分支。
切换分支
$ git checkout <branchname>
新建并切换分支
$ git checkout -b <branchname>
相当于上述两条指令的结合。
分支合并
$ git merge <branch>
合并分支前要先回到主分支,然后将要被合并的分支合并。
"Fast forward"
如果主分支是被合并分支的直接上游,Git 只需要把 master 分支指针直接右移,称为"Fast forward"。
正常合并
如果当前 master 分支指向的提交对象不是被合并分支的直接祖先,那么在合并时 Git 会进行一次简单的合并计算。
这样合并后的提交对象会拥有两个祖先,Git 可以自己决定哪个祖先才是最佳合并基础。
冲突合并
如果不同的分支都修改了同一个文件的同一部分,那么 Git 就无法将它们干净地合并在一起,这种情况下,只能人工裁决。
发生冲突时,Git 作了合并,但是没有提交,它会停下来等你解决冲突,这时可以使用 git status
来查看哪些文件发生冲突。
任何包含未解决冲突的文件都会以未合并 (unmerged) 的状态列出。Git 会在有冲突的文件里加入标准的冲突解决标记,可以通过它们来手工定位并解决这些冲突。
<<<<<<< HEAD
function funcInMaster () {
return "master";
=======
function funcInTest () {
return "In Test";
>>>>>>> test
可以看到 ======= 隔开的上半部分,是 HEAD (在执行合并命令时所在的分支,即 HEAD 指针指向的分支)中的内容。
如果你想用一个可视化的合并工具并引导你解决所有冲突。
$ git mergetool
分支删除
$ git branch -d <branchname>
分支管理
$ git branch
远程分支
远程分支使用 (远程仓库名) / (分支名) 的形式表示远程分支。
从远程服务器上同步数据到本地
$ git fetch <branch>
推送本地分支
$ git push <远程仓库名><分支名>:<本地分支推送到远程仓库时的别名>
跟踪远程分支
$ git checkout --track <远程仓库>/<分支名>
删除远程分支
$ git push <远程仓库>:<分支名>
分支的衍合
merge
merge
指令会把两个分支最近的快照以及两者最新的共同祖先进行三方合并,结果产生一个新的提交对象。
rebase
rebase
指令可以把在一个分支里的提交移到另一个分支里重放一遍。
$ git rebase <主分支> <特性分支>
该指令会先取出特性分支,然后在主分支上重演。
$ git rebase --onto