Difference between revisions of "Git (简体中文)"

From ArchWiki
Jump to: navigation, search
(Sync with English version.)
 
(9 intermediate revisions by 6 users not shown)
Line 1: Line 1:
[[Category: Version Control System (简体中文)]]
+
[[Category:Version Control System (简体中文)]]
[[Category: 简体中文]]
 
 
[[en:Git]]
 
[[en:Git]]
{{translateme (简体中文)}}
+
[[es:Git]]
{{Article summary start|摘要}}
+
[[ja:Git]]
{{Article summary text|安装和使用 Git 版本管理系统}}
+
{{TranslationStatus (简体中文)|Git|2018-05-04|520101}}
{{Article summary heading|相关页面}}
+
{{Related articles start (简体中文)}}
{{Article summary wiki|Super Quick Git Guide}}: Generally about contributing to pacman, although it still serves as a practical Git tutorial
+
{{Related|Gitweb}}
{{Article summary wiki|Gitweb}}
+
{{Related|Cgit}}
{{Article summary wiki|Cgit}}
+
{{Related|HTTP tunneling#Tunneling Git}}
{{Article summary wiki|Subversion}}
+
{{Related|Subversion (简体中文)}}
{{Article summary wiki|Concurrent Versions System}}
+
{{Related|Concurrent Versions System}}
{{Article summary link|github|http://github.com/}}
+
{{Related articles end}}
{{Article summary end}}
+
{{Quote|I've met people who thought that git is a front-end to GitHub. They were wrong, git is a front-end to the AUR.|[https://public-inbox.org/git/#didyoureallythinklinuswouldsaythat Linus T.]}}
  
[http://git-scm.com/ Git] 是一个 Linus Torvalds 编写的版本控制系统 (VCS),现在被用来维护 Linux 内核以及数以千计的其他项目,包括 [[Pacman (简体中文)|Pacman]](Arch 的软件包管理器)
+
[[wikipedia:Git (software)|Git]] 是一个由 Linux 内核作者 Linus Torvalds 编写的版本控制系统(VCS),现在被用来维护 [[AUR]] 软件包以及数以千计的其他项目,其中包括 Linux 内核。
  
有一个很全面的文档,包含了手册和教程,可以从 [http://git-scm.com/documentation 官方网站] 获得。
+
== 安装 ==
  
==安装==
+
[[Install|安装]] {{Pkg|git}} 软件包。要使用开发版本,请安装 {{AUR|git-git}} 软件包。当使用 ''git svn''、''git gui'' 和 ''gitk'' 等工具时请检查可选依赖项是否安装。
{{Pkg|git}} 可以用 [[pacman (简体中文)|Pacman]] 从 [extra] 仓库安装。如果你关心使用 Git 配合其他的 VCS 软件,邮件服务器,或者使用 Git 的图形界面,注意看可选的依赖。
 
  
Bash 自动完成 (例如,按 tab 来完成你正在键入的命令),只需要:
+
{{注意|要打开 ''git-gui'' 的拼写检查功能,请安装 {{Pkg|aspell}},同时还需要与 {{ic|LC_MESSAGES}} [[Environment variables (简体中文)|环境变量]] 相对应的字典文件。参阅 {{Bug|28181}} 和 [[aspell (简体中文)]]。}}
{{bc|source /usr/share/git/completion/git-completion.bash}}
 
另外,你可以安装 {{Pkg|bash-completion}} 软件包来自动为新的外壳加载自动完成。
 
  
如果你想使用 Git 内建的图形界面 (例如 {{Ic|gitk}} 或者 {{Ic|git gui}}) 你需要安装 {{Pkg|tk}} 软件包,否则你会遇到一个隐晦的错误信息:
+
== 配置 ==
{{bc|/usr/bin/gitk: line 3: exec: wish: not found.}}
+
 
 +
你至少需要设置好姓名和邮箱之后才能开始使用 Git:
 +
 
 +
$ git config --global user.name  "''John Doe''"
 +
$ git config --global user.email "''johndoe@example.com''"
 +
 
 +
参阅 [https://git-scm.com/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%88%9D%E6%AC%A1%E8%BF%90%E8%A1%8C-Git-%E5%89%8D%E7%9A%84%E9%85%8D%E7%BD%AE 起步 - 初次运行 Git 前的配置]。
 +
 
 +
更多设置选项可参阅 [[#提示与技巧]]。
 +
 
 +
== 基本用法 ==
 +
 
 +
一个 Git 版本库包含在一个名为 {{ic|.git}} 的目录内,该目录包含了修订历史以及其他元数据。版本库所跟踪的目录(默认为父目录)称为工作目录。在工作树进行的更改在被提交 (commit) 前需要先暂存 (stage) 起来。Git 还可以让你恢复以前提交的工作树文件。
 +
 
 +
参阅 [https://git-scm.com/book/zh/v2/%E8%B5%B7%E6%AD%A5-Git-%E5%9F%BA%E7%A1%80 起步 - Git 基础]。
 +
 
 +
=== 获取一个 Git 仓库 ===
 +
 
 +
* 初始化一个版本库
 +
:{{ic|git init}},参阅 {{man|1|git-init}}
 +
* 克隆 (clone) 一个现有的版本库
 +
:{{ic|git clone ''repository''}},参阅 {{man|1|git-clone}}
 +
 
 +
=== 记录更改 ===
 +
 
 +
Git 管理的项目存在一个暂存区 (staging area),即 git 目录中的 {{ic|index}} 文件,其中保存了即将包含在你下一次提交中的文件更改。要将某个修改过的文件记录下来,首先需要将修改后的文件添加到 index(暂存它),然后用 {{ic|git commit}} 命令将当前的 index 保存为一次新的提交。
 +
 
 +
==== 暂存 (stage) 更改 ====
 +
 
 +
* 将工作树中的文件更改添加至 index
 +
:{{ic|git add ''pathspec''}},参阅 {{man|1|git-add}}
 +
* 移除 index 中记录的文件更改
 +
:{{ic|git reset ''pathspec''}},参阅 {{man|1|git-reset}}
 +
* 显示即将提交的更改、未暂存的更改以及未被 git 跟踪的文件
 +
:{{ic|git status}},参阅 {{man|1|git-status}}
 +
 
 +
可以用 {{ic|.gitignore}} 文件来让 git 忽略某些未跟踪的文件,请参阅 {{man|5|gitignore}}。
 +
 
 +
Git 不会跟踪文件移动。合并时的文件移动检测仅基于内容的相似性。{{ic|git mv}} 命令仅仅是为了方便,它相当于:
 +
 
 +
$ mv -i foo bar
 +
$ git reset -- foo
 +
$ git add bar
 +
 
 +
==== 提交 (commit) 更改 ====
 +
 
 +
{{ic|git commit}} 命令将暂存区的更改保存至版本库,参阅 {{man|1|git-commit}}。
 +
 
 +
* {{ic|-m}} – 后面跟上提交消息作为参数直接提交,而不是打开默认的文本编辑器来写提交信息后再提交
 +
* {{ic|-a}} – 自动暂存已更改或已删除的文件(不会添加未跟踪的文件)
 +
* {{ic|--amend}} – 重做上次提交,用于修改提交消息或修改提交的文件
 +
 
 +
{{提示|建议经常性的提交小更改,并附上有意义的提交信息。}}
 +
 
 +
==== 选择修订版本 ====
 +
 
 +
Git 提供了多种方式来指定修订版本,参阅 {{man|7|gitrevisions}} 和 [https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E9%80%89%E6%8B%A9%E4%BF%AE%E8%AE%A2%E7%89%88%E6%9C%AC 选择修订版本]。
 +
 
 +
许多 Git 命令需要用修订版本作为参数。一次提交记录可以用下列任何一种方式表示:
 +
 
 +
* 某次提交的 SHA-1 哈希值(前7位通常足以唯一标识它)
 +
* 任意提交时的标签,如分支名称或 tag 名称
 +
* 标签 {{ic|HEAD}} 总是指向当前 check out 的提交(通常是分支的头部,除非你使用 ''git checkout'' 跳回到历史记录中的旧提交)
 +
* 以上任意一种表示方式加上 {{ic|~}} 都可以表示之前的提交。例如,{{ic|HEAD~}} 指向 {{ic|HEAD}} 的前一次提交,{{ic|HEAD~5}} 指向 {{ic|HEAD}} 5 次前的提交。
 +
 
 +
==== 查看更改 ====
 +
 
 +
查看不同提交间的修改处:
 +
 
 +
$ git diff HEAD HEAD~3
 +
 
 +
或者查看暂存区和工作树之间的不同:
 +
 
 +
$ git diff
 +
 
 +
查看修改历史(其中 "''-N''" 指定最近的 n 次修改):
 +
 
 +
$ git log -p ''(-N)''
 +
 
 +
=== 撤销修改 ===
 +
 
 +
* {{ic|git reset}} - 重置当前 HEAD 指针到指定状态,参阅 {{man|1|git-reset}}
 +
 
 +
* {{ic|git checkout}} - 恢复工作树中的文件,参阅 {{man|1|git-checkout}}
 +
 
 +
=== 分支 (branch) ===
 +
 
 +
Bug 修复和新功能通常在不同分支里测试。当一切就绪时它们就可以合并至默认(主)分支。
 +
 
 +
创建一个分支,其名称准确地反映了其目的:
 +
 
 +
$ git branch ''help-section-addition''
 +
 
 +
列出已存在的分支:
 +
 
 +
$ git branch
 +
 
 +
切换分支:
 +
 
 +
$ git checkout ''branch''
 +
 
 +
新建分支并切换至该分支:
 +
 
 +
$ git checkout -b ''branch''
 +
 
 +
将一个分支合并回主分支:
 +
 
 +
$ git checkout master
 +
$ git merge ''branch''
 +
 
 +
如果不存在冲突的话,所有更改将被合并。否则 Git 将显示一条错误信息,并通过给工作树中的文件加注释来记录冲突。添加的注释可以用 {{ic|git diff}} 显示。要解决冲突,必须编辑文件,删除注释,并提交最终版本。请参阅下面的 [[#处理合并 (merge)]]。
 +
 
 +
当一个分支使用完毕,可以这样删除:
 +
 
 +
$ git branch -d ''branch''
 +
 
 +
=== 多人合作 ===
 +
 
 +
一个典型的 Git 工作流像这样:
 +
 
 +
# 创建一个新仓库或克隆一个远程仓库。
 +
# 新建一个分支用于修改文件,然后提交这些修改。
 +
# 将多次提交合并在一起,这样更便于组织项目或更好地理解。
 +
# 把提交的分支合并回主分支。
 +
# (可选)将更改推送至远程服务器。
 +
 
 +
==== 合并请求 (pull requests) ====
 +
 
 +
在做出并提交更改后,贡献者可以请求原作者合并更改。这被称为 ''合并请求 (pull request)''。
 +
 
 +
如果用 pull:
 +
 
 +
$ git pull ''location'' master
 +
 
 +
''pull'' 命令相当于 ''fetch'' 和 ''merge'' 命令的结合。如果存在冲突(比如原作者在同一时间段内在相同位置做了更改),那就有必要手动解决冲突。
 +
 
 +
另一种方式是,原作者可以选择想要合并的更改。通过使用 ''fetch'' 命令(以及带有特殊 {{ic|FETCH_HEAD}} 标记的 ''log'' 命令),可以在决定如何处理合并请求 (pull request) 前查看该请求的内容:
 +
 
 +
$ git fetch ''location'' master
 +
$ git log -p HEAD..FETCH_HEAD
 +
$ git merge ''location'' master
 +
 
 +
==== 使用远程仓库 (remote) ====
 +
 
 +
远程 (remote) 是和本地相关联的远程仓库的别名。其实就是创建一个 ''label'' 来定义一个位置。这些 label 用于标识经常访问的仓库。
 +
 
 +
添加一个远程仓库:
 +
 
 +
$ git remote add ''label'' ''location''
 +
 
 +
获取远程库里的内容:
 +
 
 +
$ git fetch ''label''
 +
 
 +
显示本地主分支与远程主分支之间的差异:
 +
 
 +
$ git log -p master..''label''/master
 +
 
 +
查看当前仓库相关联的远程仓库:
 +
 
 +
$ git remote -v
 +
 
 +
当设置的远程仓库是本仓库的 fork 来源(项目的领导者),这个远程仓库会被定义为 ''upstream''(上游)。
 +
 
 +
==== 向某个仓库推送 (push) 修改 ====
 +
 
 +
从原作者处获得推送修改的权限之后,使用以下命令推送修改:
 +
 
 +
$ git push ''location'' ''branch''
 +
 
 +
当使用 ''git clone'' 获得这个仓库后,git 会把仓库的原始地址记录在名为 {{ic|origin}} 的变量中。
 +
 
 +
所以一次 ''典型的'' 推送可以这样做:
 +
 
 +
$ git push origin master
 +
 
 +
如果使用了 {{ic|-u}} ({{ic|--set-upstream-to}}) 选项,地址将会被记录下来,下次只要使用 {{ic|git push}} 就可以了。
 +
 
 +
==== 处理合并 (merge) ====
 +
 
 +
可以查看 Git Book 的 [https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%9A%84%E6%96%B0%E5%BB%BA%E4%B8%8E%E5%90%88%E5%B9%B6#遇到冲突时的分支合并 遇到冲突时的分支合并] 部分了解如何处理合并冲突。合并操作通常是可逆的,如果想返回合并前,可以使用 {{ic|--abort}} 命令(比如 {{ic|git merge --abort}} 或 {{ic|git pull --abort}})。
 +
 
 +
=== 历史记录和版本记录 ===
 +
 
 +
==== 在历史记录中搜索 ====
 +
 
 +
{{ic|git log}} 命令可以显示历史记录信息,其中包含每次提交的校验和、作者、日期,以及简略信息。''校验和'' 就是一次提交对象的 "对象名称",通常是一个 40 位的 SHA-1 哈希值。
 +
 
 +
对于具有较长信息的历史记录(其中 "''checksum''" 可以截取前几位,只要它是唯一的):
 +
 
 +
$ git show (''checksum'')
 +
 
 +
在被跟踪的文件中搜索 ''pattern'':
 +
 
 +
$ git grep ''pattern''
 +
 
 +
在 {{ic|.c}} 和 {{ic|.h}} 文件中搜索:
 +
 
 +
$ git grep ''pattern'' -- '*.[ch]'
 +
 
 +
==== 使用标签 (tag) ====
 +
 
 +
给某次提交打标签来标记这个版本:
 +
 
 +
$ git tag 2.14 ''checksum''
 +
 
 +
''Tag'' 通常是用于 [https://www.drupal.org/node/1066342 发布/标记版本] 的,但它可以是任何字符串。通常使用带注释的标签,因为它们会被添加到 Git 数据库中。
 +
 
 +
标记当前的提交:
 +
 
 +
$ git tag -a 2.14 -m "Version 2.14"
 +
 
 +
列出标签:
 +
 
 +
$ git tag -l
 +
 
 +
删除某个标签:
 +
 
 +
$ git tag -d 2.08
 +
 
 +
更新远程库中的标签:
 +
 
 +
$ git push --tags
 +
 
 +
==== 重新组织 commit ====
 +
 
 +
在提交合并请求之前,可能需要合并/重新组织 commit。这是通过 ''git rebase''(变基){{ic|--interactive}}完成的:
 +
 
 +
$ git rebase -i ''checksum''
 +
 
 +
然后会打开文本编辑器,其中包含指定范围内所有提交的摘要;这种情况下会包括最新提交 ({{ic|HEAD}}),但不包括 {{ic|''checksum''}} 表示的那次 commit。也可以使用数字来标记,例如用 {{ic|HEAD~3}},这会把最后三次提交变基:
 +
 
 +
pick d146cc7 Mountpoint test.
 +
pick 4f47712 Explain -o option in readme.
 +
pick 8a4d479 Rename documentation.
 +
 
 +
修改第一栏中的动作可以决定如何执行变基操作。可选的动作有:
 +
 
 +
* {{ic|pick}} — 原样保留每次提交(默认)。
 +
* {{ic|edit}} — 编辑文件和/或 commit 信息。
 +
* {{ic|reword}} — 编辑 commit 信息。
 +
* {{ic|squash}} — 合并/折叠到先前的提交中。
 +
* {{ic|fixup}} — 合并/折叠到先前的提交中并丢弃它们的信息。
 +
 
 +
提交会被重新排序或从历史记录中擦除(所以要非常小心)。编辑文件后,Git 将执行指定的操作;如果提示有合并问题待解决,请解决它们并使用 {{ic|git rebase --continue}} 来继续,或使用 {{ic|git rebase --abort}} 命令来取消操作。
 +
 
 +
{{注意|合并多次提交的操作只能应用于本地提交,它会导致其他人共享的存储库出现问题。}}
 +
 
 +
== 提示与技巧 ==
 +
 
 +
=== 使用 git-config ===
 +
 
 +
Git 从三个 ini 类型的配置文件里读取配置:
 +
 
 +
* {{ic|/etc/gitconfig}} 是应用于整个系统的默认配置文件
 +
* {{ic|~/.gitconfig}} 是应用于特定用户的配置文件
 +
* {{ic|.git/config}} 是应用于特定仓库的配置文件
 +
 
 +
这些文件可以直接编辑,但是更常用的方法是使用 ''git config'',下面是一些示范。
 +
 
 +
列出当前已配置的变量:
 +
 
 +
$ git config {--local,--global,--system} --list
 +
 
 +
将默认文本编辑器从 [[vim]] 改成 [[nano]]:
  
== 配置 ==
 
Git 从几个 INI 格式的配置文件中读取配置信息。在每一个 git 仓库中 {{ic|.git/config}} 被用来指定与本仓库有关的配置选项。每一个用户 ("global") 的配置文件在 {{ic|$HOME/.gitconfig}} 被用来作为仓库配置的备用配置。你也可以直接编辑文件,但是更推荐的方法是使用 git-config 工具。例如,
 
 
  $ git config --global core.editor "nano -w"
 
  $ git config --global core.editor "nano -w"
会添加 {{Ic|<nowiki>editor = nano -w</nowiki>}} 到 {{ic|~/.gitconfig}} 文件的 {{Ic|<nowiki>[core]</nowiki>}} 部分中。
 
  
[http://www.kernel.org/pub/software/scm/git/docs/git-config.html git-config 工具的 man page] 有一个很长的参数列表,列出所以可以设置的变量。
+
设置默认的推送 (push) 行为:
 +
 
 +
$ git config --global push.default simple
 +
 
 +
设置不同的 ''git difftool'' 工具(默认是 ''meld''):
 +
 
 +
$ git config --global diff.tool vimdiff
 +
 
 +
更多信息请参阅 {{man|1|git-config}} 和 [https://git-scm.com/book/zh/v2/%E8%87%AA%E5%AE%9A%E4%B9%89-Git-%E9%85%8D%E7%BD%AE-Git 配置 Git]。
 +
 
 +
=== 保持良好的礼仪 ===
 +
 
 +
* 当你想为一个现有的项目贡献时,请先阅读并理解这个项目的许可,因为它可能会过度限制你更改代码的权力。有些许可会在代码的所有权方面引起争议。
 +
* 理解这个项目的社区,以及你可以融入其中的程度。要了解项目的主要方向,可以阅读所有文档甚至是代码库的 [[#历史记录和版本记录|log]]
 +
* 当发起一个合并请求,或者提交一个补丁时,保证它是小改动并且有完善的文档;这将有助于项目维护者理解你的改动,并决定是否合并这些改动或是让你再改一下。
 +
* 如果贡献被拒绝,不要气馁,毕竟这是他们的项目。如果它很重要,请尽可能清楚和耐心地讨论这次贡献的理由,最终可能通过这种方法解决问题。
 +
 
 +
=== 加快身份验证 ===
 +
 
 +
每次向 Git 服务器推送时都要认证身份,你可能会想要避免这种麻烦。
  
这是一些你可能用到的常见的配置:
+
* 如果你是用 SSH 密钥来认证的,请使用 [[SSH keys (简体中文)#SSH agents|SSH agents]]。参阅 [[Secure Shell (简体中文)#加速 SSH]] 和 [[Secure Shell (简体中文)#保持在线]]。
$ git config --global user.name "Firstname Lastname"
+
* 如果你是用账号和密码来认证的,在服务器支持 SSH 的情况下请切换至 [[SSH keys (简体中文)|SSH keys]], 否则请尝试 [https://git-scm.com/docs/git-credential-cache git-credential-cache] 或 [https://git-scm.com/docs/git-credential-store git-credential-store]。
$ git config --global user.email "your_email@youremail.com"
 
$ git config --global color.ui true
 
$ git config --global --list
 
  
==基本用法==
+
=== 默认通讯协议 ===
  
===克隆一个版本库===
+
如果你正在使用一个上述那种复用的 SSH 连接,让 Git 使用 SSH 可能比使用 HTTPS 更快。同时,一些服务器(比如 AUR)只允许通过 SSH 推送更改。例如,像下面这样配置可以使得 Git 通过 SSH 访问 AUR 上的任何仓库。
  
git clone <repo location> <dir>
+
{{hc|~/.gitconfig|<nowiki>
 +
[url "ssh://aur@aur.archlinux.org/"]
 +
insteadOf &#61; https://aur.archlinux.org/
 +
insteadOf &#61; http://aur.archlinux.org/
 +
insteadOf &#61; git://aur.archlinux.org/
 +
</nowiki>}}
  
will clone a Git repository in a new directory inside your current directory. Leaving out {{ic|<dir>}}
+
=== Bash 自动补全 ===
will cause it to name the folder after the Git repository. For example,
 
  
git clone git@github.com:torvalds/linux.git
+
要启用 Bash 的自动补全,请在 [[Bash#Configuration_files|Bash 启动文件]] 里用 source 加载 {{ic|/usr/share/git/completion/git-completion.bash}} 文件。或者也可以安装 {{pkg|bash-completion}}。
  
clones Github's mirror of the Linux kernel into a directory named "linux".
+
=== Git 提示符 ===
  
===提交(commit)文件到版本库===
+
Git 包带有一个提示符脚本。要启用它,请用 source 加载 {{ic|/usr/share/git/completion/git-prompt.sh}} 脚本,然后使用 {{ic|%s}} 参数设置一个自定义 shell 提示符:
  
Git's commit process involves two steps:
+
* [[Bash]] 用户: {{ic|1=PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '}}
 +
* [[zsh]] 用户: {{ic|1=setopt PROMPT_SUBST ; PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '}}
  
# Add new files, add changes for existing files (both with {{ic|git add <files>}}), and/or remove files (with {{ic|git rm}}). These changes are put in a staging area called the index.
+
要自动完成这项工作,请参阅 [[Command-line shell#Configuration files]]。
# Call {{ic|git commit}} to commit the changes.
 
  
Git commit will open up a text editor to provide a commit message.
+
当切换至一个 Git 仓库所在目录时,shell 提示符会变成所在分支名称。也可以配置提示符来显示其他信息:
You can set this editor to whatever you want by changing the {{ic|core.editor}} option with {{ic|git config}}.
 
  
Alternatively, you can use {{ic|git commit -m <message>}} to supply the commit message without opening the text editor.
+
{| class="wikitable"
 +
|+
 +
! Shell variable !! Information
 +
|-
 +
| GIT_PS1_SHOWDIRTYSTATE    || 已暂存 (staged) 显示 '''+''',未暂存 (unstaged) 显示 '''*'''。
 +
|-
 +
| GIT_PS1_SHOWSTASHSTATE    || 已储藏 (stashed) 显示 '''$'''。
 +
|-
 +
| GIT_PS1_SHOWUNTRACKEDFILES || 有未跟踪文件时显示 '''%'''。
 +
|-
 +
| GIT_PS1_SHOWUPSTREAM      || '''<,>,<>''' 分别表示落后于上游、领先于上游、偏离上游。
 +
|}
  
Other useful commit tricks:
+
{{ic|GIT_PS1_SHOWUPSTREAM}} 需要设置为 {{ic|auto}} 才能使更改生效。
  
{{ic|git commit -a}} lets you commit changes you have made to files already under Git control
+
{{注意|如果发生了 {{ic|$(__git_ps1)}} 返回 {{ic|((unknown))}} 的情况,是因为有一个 {{ic|.git}} 文件夹在你当前的文件夹里面,但却不包含任何存储库,因此 Git 不认识它。这有可能发生在你把 {{ic|~/.git/config}} 误认为是 Git 的配置文件而不是 {{ic|~/.gitconfig}}。}}
without having to take the step of adding the changes to the index. You still have to add new files with git add.
 
  
{{ic|git add -p}} lets you commit specific parts of files you have changed.
+
你也可以使用来自 [[AUR]] 的自定义 git shell 提示符软件包,例如 {{AUR|bash-git-prompt}} 或 {{AUR|gittify}}
This is useful if you have made a bunch of changes that you think would be best split into several commits.
 
  
===将改动提交(push)到公共版本库===
+
=== 可视化显示 ===
  
To push your changes up to a server (such as Github), use
+
要了解已经完成了多少工作:
  
  git push <server name> <branch>
+
  $ git diff --stat
  
Adding {{ic|-u}} will make this server the default one to push to for this branch.
+
带有 fork 显示的 ''git log'':
If you have cloned the repository as described above, the server will default to the location you cloned the
 
repository from (nicknamed "origin") and the branch will default to the master branch.
 
In other words, if you have followed this guide's instructions in cloning, {{ic|git push}} will suffice.
 
You can set up Git to push to multiple servers if you want, but that is a more advanced topic.
 
Branches will be discussed later in this guide.
 
  
===从服务器公共版本库下载修改===
+
$ git log --graph --oneline --decorate
  
If you are working on multiple machines and want to update your local repository to what the server has, you use
+
给图形化的 ''git log'' 做一个别名(使用 ''git graph'' 即可显示经过修饰的 log):
  
  git pull <server name> <branch>
+
  $ git config --global alias.graph 'log --graph --oneline --decorate'
  
Similarly to push, the server name and branch should have sane defaults, so {{ic|git pull}} should suffice.
+
=== 关于提交 (commit) 的小提示 ===
Git pull is actually shorthand for doing two things:
 
  
# Calling {{ic|git fetch}}, which updates the local copy of what the server has. Such branches are called "remote" branches because they are mirroring remote servers.
+
重置为以前的提交(非常危险,这将会擦除所有内容并改写为特定提交):
# Calling {{ic|git merge}}, which merges what the remote branch has with what you have. If your commit history is the same as the server's commit history, you will be automatically fast-forwarded to the latest commit on the server. If your history does not match (maybe someone else has pushed commits since you last synced), the two histories will be merged.
 
  
It is not a bad idea to get into the practice of using these two commands instead of {{ic|git pull}}. This way you can
+
$ git reset --hard HEAD^
check to make sure that the server contains what you would expect before merging.
 
  
===查看历史记录===
+
如果远程仓库的地址发生变化,可以这样更新它的位置:
  
The command {{ic|git log}} shows the history of your current branch. Note that each commit is identified by a SHA-1 hash.
+
$ git remote set-url origin git@''address'':''user''/''repo''.git
The author, commit date, and commit message follow. A more useful command is
 
  
git log --graph --oneline --decorate
+
自动附加签名行到提交(将某个 姓名-电邮 签名添加到提交中,某些项目会要求这样做):
  
which provides a display similar to TortoiseGit's log window. It shows the following:
+
$ git commit -s
  
* The first 7 digits of each commit's SHA-1 hash (enough to be unique)
+
自动附加签名到补丁(使用 {{ic|git format-patch ''commit''}} 时生效):
* The {{ic|--graph}} option shows how any branches (if there are others) fork off from the current branch.
 
* The {{ic|--oneline}} option shows only the first line of each commit message
 
* The {{ic|--decorate}} option shows all commit labels (branches and tags)
 
  
It may be convenient to alias this command as {{ic|git graph}} by doing the following:
+
$ git config --local format.signoff true
  
git config --global alias.graph 'log --graph --oneline --decorate'
+
提交已更改文件的特定部分。如果有大量更改时,最好拆分成多个提交,这种情况下这个命令通常很有用:
  
Now typing {{ic|git graph}} will run {{ic|git log --graph --oneline --decorate}}.
+
$ git add -p
{{ic|git graph}} and {{ic|git log}} may be given the {{ic|--all}} flag in order to view all branches instead of just the current one.
 
Adding {{ic|--stat}} to one of these commands is also useful -
 
it shows which files each commit changed and how many lines were changed in each file.
 
  
===处理合并===
+
=== 对提交 (commit) 签名 ===
  
Merges happen when you pull, as a result of a rebase operation, and when you merge one branch into another.
+
Git 允许使用 [[GnuPG (简体中文)|GnuPG]] 对提交和标签进行签名,请参见 [https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E7%AD%BE%E7%BD%B2%E5%B7%A5%E4%BD%9C 签署工作]
Like other version control tools, when Git cannot automatically merge a commit, it turns to you.
 
See [http://git-scm.com/book/en/Git-Branching-Basic-Branching-and-Merging#Basic-Merge-Conflicts this section]
 
of the Git Book for an explanation on how to resolve merge conflicts.
 
If you screw up and would like to back out of the merge, you can usually abort the merge using the {{ic|--abort}} flag
 
with whatever command started the merge (e.g. {{ic|git merge --abort}}, {{ic|git pull --abort}}, {{ic|git rebase --abort}}).
 
  
==使用分布式版本控制系统==
+
{{注意|
 +
如果是借助 {{Pkg|pinentry}} 来进行 GPG 签名,请确保 {{ic|1=export GPG_TTY=$(tty)}}(或者使用 pinentry-tty),否则当 GPG 处于锁定状态时签名这一步会失败(因为它无法在 shell 提示符里询问 pin 码)。}}
  
The above commands only provide the basics.
+
配置 Git 使它自动对提交进行签名:
The real power and convenience in Git (and other distributed version control systems) come from leveraging its local commits and fast branching.
 
A typical Git workflow looks like this:
 
  
# Create and check out a branch to add a feature.
+
$ git config --global commit.gpgSign true
# Make as many commits as you would like on that branch while developing that feature.
 
# Squash, rearrange, and edit your commits until you are satisfied with the commits enough to push them to the central server and make them public.
 
# Merge your branch back into the main branch.
 
# Delete your branch, if you desire.
 
# Push your changes to the central server.
 
  
===创建一个分支===
+
=== 在非主分支上工作 ===
  
git branch <branch name>
+
偶尔项目维护人员会要求你在其他分支上完成工作。这些分支通常被称为 {{ic|devel}} 或 {{ic|testing}}。首先要克隆存储库。
  
can be used to create a branch that will branch off the current commit.
+
要进入不是主分支的分支(''git clone'' 只会显示主分支,但其他分支其实也是存在的,用 {{ic|git branch -a}} 可以显示出来):
After it has been created, you should switch to it using
 
  
  git checkout <branch name>
+
  $ git checkout -b ''branch'' origin/''branch''
  
A simpler method is to do both in one step with
+
然后就可以像平常一样编辑文件,但是要使得整个仓库都保持同步,下面这两个命令都要用:
  
  git checkout -b <branch name>
+
  $ git pull --all
 +
$ git push --all
  
To see a list of branches, and which branch is currently checked out, use
+
=== 直接将补丁发送至邮件列表 ===
  
git branch
+
如果你想直接将补丁发送至一个邮件列表,需要安装以下软件包:{{Pkg|perl-authen-sasl}},{{Pkg|perl-net-smtp-ssl}} 和 {{Pkg|perl-mime-tools}}。
  
===A word on commits===
+
确保你已经配置了用户名和邮件地址,可参阅 [[#配置]]。
  
Many of the following commands take commits as arguments. A commit can be identified by any of the following:
+
配置你的邮箱设置:
  
* Its 40-digit SHA-1 hash (the first 7 digits are usually sufficient to identify it uniquely)
+
$ git config --global sendemail.smtpserver ''smtp.example.com''
* Any commit label such as a branch or tag name
+
$ git config --global sendemail.smtpserverport ''587''
* The label {{ic|HEAD}} always refers to the currently checked-out commit (usually the head of the branch, unless you used {{ic|git checkout}} to jump back in history to an old commit)
+
$ git config --global sendemail.smtpencryption ''tls''
* Any of the above plus {{ic|~}} to refer to previous commits. For example, {{ic|HEAD~}} refers to one commit before {{ic|HEAD}} and {{ic|HEAD~5}} refers to five commits before {{ic|HEAD}}.
+
$ git config --global sendemail.smtpuser ''foobar@example.com''
  
===提交为检查点===
+
现在你应该可以将补丁发送至某个邮件列表了(可参阅[http://www.openembedded.org/wiki/How_to_submit_a_patch_to_OpenEmbedded#Sending_patches OpenEmbedded:How to submit a patch to OpenEmbedded#Sending patches]):
  
In Subversion and other older, centralized version control systems, commits are permanent - once you make them,
+
$ git add ''filename''
they are there on the server for everyone to see.
+
$ git commit -s
In Git, your commits are local and you can combine, rearrange, and edit them before pushing them to the server.
+
$ git send-email --to=''openembedded-core@lists.openembedded.org'' --confirm=always -M -1
This gives you more flexibility and lets you use commits as checkpoints. Commit early and commit often.
 
  
===编辑之前的提交===
+
== Git 服务器 ==
  
git commit --amend
+
这一节讲述如何配置使用不同的协议连接到存储库。
  
allows you to modify the previous commit. The contents of the index will be applied to it,
+
=== SSH 协议 ===
allowing you to add more files or changes you forgot to put in. You can also use it to edit the commit message,
 
if you would like.
 
  
===插入、重新排序和更改历史记录===
+
要使用 SSH 协议,首先要准备一个 SSH 公钥,可以按照 [[SSH keys (简体中文)]] 的指导来完成。要配置一个 SSH 服务器,请遵循 [[Secure Shell (简体中文)]] 的指导。
  
git rebase -i <commit>
+
当 SSH 生成了密钥之后,将 {{ic|~/.ssh/id_rsa.pub}} 文件的内容粘贴至服务器上的 {{ic|~/.ssh/authorized_keys}} 文件里(一行一个,同一个公钥确保在同一行)。现在 Git 仓库可以通过 SSH 来访问:
  
will bring up a list of all commits between {{ic|<commit>}} and the present, including {{ic|HEAD}} but excluding {{ic|<commit>}}.
+
$ git clone ''user''@''foobar.com'':''my_repository''.git
This command allows you rewrite history. To the left of each commit, a command is specified.
 
Your options are as follows:
 
  
* The "pick" command (the default) uses that commit in the rewritten history.
+
现在,如果你的 SSH 客户端的 {{ic|StrictHostKeyChecking}} 选项设为了 {{ic|ask}}(默认),你应该会收到来自 SSH 的问题,要你回答 yes/no。输入 {{ic|yes}} 然后回车,你的仓库就能被取出。同时,由于通过 SSH 协议访问,你现在应该有提交权限。
* The "reword" command lets you change a commit message without changing the commit's contents.
 
* The "edit" command will cause Git to pause during the history rewrite at this commit. You can then modify it with {{ic|git commit --amend}} or insert new commits.
 
* The "squash" command will cause a commit to be folded into the previous one. You will be prompted to enter a message for the combined commit.
 
* The "fixup" command works like squash, but discards the message of the commit being squashed instead of prompting for a new message.
 
* Commits can be erased from history by deleting them from the list of commits
 
* Commits can be re-ordered by re-ordering them in the list. When you are done modifying the list, Git will prompt you to resolve any resulting merge problems (after doing so, continue rebasing with {{ic|git rebase --continue}})
 
  
When you are done modifying the list, Git will perform the desired actions.
+
要把一个已存在的仓库改成使用 SSH 访问,需要重新定义一下远程地址:
If Git stops at a commit (due to merge conflicts caused by re-ordering the commits or due to the "edit" command),
 
use {{ic|git rebase --continue}} to resume. You can always back out of the rebase operation with {{ic|git rebase --abort}}.
 
  
{{warning|Only use {{ic|git rebase -i}} on local commits that have not yet been pushed to anybody else.
+
$ git remote set-url origin git@localhost:''my_repository''.git
Modifying commits that are on the central server will cause merge problems for obvious reasons.}}
 
  
{{note|Vim makes these rebase operations very simple since lines can be cut and pasted with few keystrokes.}}
+
要从非 22 端口连接,可以在每台主机的 {{ic|/etc/ssh/ssh_config}} 或 {{ic|~/.ssh/config}} 里配置。要为某个本地仓库设置端口(示例中用的 443 端口):
  
==Git提示符==
+
{{hc|.git/config|2=
The Git package comes with a prompt script. To enable the prompt addition you will need to source the git-prompt.sh script and add {{Ic|$(__git_ps1 " (%s)")}} to you PS1 variable.
+
[remote "origin"]
* Copy {{Ic|/usr/share/git/completion/git-prompt.sh}} to your home directory (e.g. {{Ic|~/.git-prompt.sh}}).
+
    url = ssh://''user''@''foobar''.com:443/~''my_repository''/repo.git
* Add the following line to your .bashrc/.zshrc:
+
}}
source ~/.git-prompt.sh
 
* For Bash:
 
PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
 
{{Note|For information about coloring your bash prompt see [[Color_Bash_Prompt]]}}
 
  
* For zsh:
+
你可以通过只允许用户执行 push 和 pull 操作来进一步提高 SSH 账户的安全性。这是通过将该账户的默认登录 shell 换成 git-shell 来实现的。在 [https://git-scm.com/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-%E9%85%8D%E7%BD%AE%E6%9C%8D%E5%8A%A1%E5%99%A8 配置服务器] 中对此有所描述。
PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
 
  
The {{Ic|%s}} is replaced by the current branch name. The git information is displayed only if you are navigating in a git repository. You can enable extra information by setting and exporting certain variables to a non-empty value as shown in the following table:
+
=== Smart HTTP 协议 ===
  
{| border="1"
+
通过使用 git-http 后端,Git 可以像使用 SSH 协议或 Git 协议一样高效地使用 HTTP(S) 协议。此外,它不仅可以从仓库中克隆或拉取更改,还可以通过 HTTP(S) 推送更改。
|+
 
! Variable !! Information
 
|-
 
| GIT_PS1_SHOWDIRTYSTATE || '''*''' for unstaged and '''+''' for staged changes
 
|-
 
| GIT_PS1_SHOWSTASHSTATE || '''$''' if something is stashed
 
|-
 
| GIT_PS1_SHOWUNTRACKEDFILES || '''%''' if there are untracked files
 
|}
 
  
==传输协议==
+
这个设置相当简单,因为你只需要安装 Apache Web 服务器({{pkg|apache}},启用 {{ic|mod_cgi}}、{{ic|mod_alias}} 和 {{ic|mod_env}}),当然还要安装 {{pkg|git}}。
===智能HTTP===
 
Since version 1.6.6 git is able to use the HTTP(S) protocol as efficiently as SSH or Git by utilizing the git-http-backend. Furthermore it is not only possible to clone or pull from repositories, but also to push into repositories over HTTP(S).
 
  
The setup for this is rather simple as all you need to have installed is the Apache web server (with mod_cgi, mod_alias, and mod_env enabled) and of course, git:
+
当你正在进行基本设置时,请将以下内容添加到 Apache 配置文件中,该配置文件通常位于:
# pacman -S apache git
 
  
Once you have your basic setup up and running, add the following to your Apache's config usually located at {{ic|/etc/httpd/conf/httpd.conf}}:
+
{{hc|/etc/httpd/conf/httpd.conf|
<Directory "/usr/lib/git-core*">
+
<Directory "/usr/lib/git-core*">
    Order allow,deny
+
    Require all granted
    Allow from all
+
</Directory>
</Directory>
 
 
   
 
   
SetEnv GIT_PROJECT_ROOT /srv/git
+
SetEnv GIT_PROJECT_ROOT /srv/git
SetEnv GIT_HTTP_EXPORT_ALL
+
SetEnv GIT_HTTP_EXPORT_ALL
ScriptAlias /git/ /usr/lib/git-core/git-http-backend/
+
ScriptAlias /git/ /usr/lib/git-core/git-http-backend/
 +
}}
 +
 
 +
这里假设你的 Git 仓库位于 {{ic|/srv/git}},并且你想用类似 {{ic|<nowiki>http(s)://your_address.tld/git/your_repo.git</nowiki>}} 的方式来访问它们。
 +
 
 +
{{注意|请确保 Apache 对你的仓库有读写权限。}}
 +
 
 +
如果需要更多详细文档,请访问:
 +
* https://git-scm.com/book/en/v2/Git-on-the-Server-Smart-HTTP
 +
* https://git-scm.com/docs/git-http-backend
  
The above example config assumes that your git repositories are located at {{ic|/srv/git}} and that you want to access them via something like <nowiki>http(s)://your_address.tld/git/your_repo.git</nowiki>. Feel free to customize this to your needs.
+
=== Git 协议 ===
  
{{Note|Of course you have to make sure that your Apache can read and write (if you want to enable push access) on your git repositories.}}
+
{{注意|Git 协议没有加密或认证机制,且只允许读取。}}
  
For more detailed documentation, visit the following links:
+
[[start|Start 并且 enable]] {{ic|git-daemon.socket}} 这个 systemd 单元。
* http://progit.org/2010/03/04/smart-http.html
 
* https://www.kernel.org/pub/software/scm/git/docs/v1.7.10.1/git-http-backend.html
 
  
===Git SSH===
+
守护程序会带有以下选项启动:
You first need to have a public SSH key. For that follow the guide at [[Using SSH Keys]]. To set up SSH itself, you need to follow the [[SSH]] guide. This assumes you have a public SSH key now and that your SSH is working.
 
Open your SSH key in your favorite editor (default public key name is {{ic|~/.ssh/id_rsa.pub}}), and copy its content ({{keypress|Ctrl+c}}).
 
Now go to your user where you have made your Git repository, since we now need to allow that SSH key to log in on that user to access the Git repository.
 
Open {{ic|~/.ssh/authorized_keys}} in your favorite editor, and paste the contents of id_rsa.pub in it. Be sure it is all on one line! That is important! It should look somewhat like this:
 
{{Warning|Do not copy the line below! It is an example! It will not work if you use that line!}}
 
<pre style='overflow:auto'>
 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCboOH6AotCh4OcwJgsB4AtXzDo9Gzhl+BAHuEvnDRHNSYIURqGN4CrP+b5Bx/iLrRFOBv58TcZz1jyJ2PaGwT74kvVOe9JCCdgw4nSMBV44cy+6cTJiv6f1tw8pHRS2H6nHC9SCSAWkMX4rpiSQ0wkhjug+GtBWOXDaotIzrFwLw== username@hostname
 
</pre>
 
Now you can checkout your Git repository this way (change where needed. Here it is using the git username and localhost):
 
git clone git@localhost:my_repository.git
 
You should now get an SSH yes/no question. Type {{ic|yes}} followed by {{keypress|Enter}}. Then you should have your repository checked out. Because this is with SSH, you also do have commit rights now. For that look at [[Git]] and [[Super Quick Git Guide]].
 
  
====特定非标准端口====
+
ExecStart=-/usr/lib/git-core/git-daemon --inetd --export-all --base-path=/srv/git
Connecting on a port other than 22 can be configured on a per-host basis in {{ic|/etc/ssh/ssh_config}} or {{ic|~/.ssh/config}}. To set up ports for a repository, specify the path in {{ic|.git/config}} using the port number {{ic|N}} and the ''absolute path'' {{ic|/PATH/TO/REPO}}:
 
ssh://user@example.org:N/PATH/TO/REPO
 
Typically the repository resides in the home directory of the user which allows you to use tilde-expansion. Thus to connect on port N=443,
 
url = git@example.org:repo.git
 
becomes:
 
url = ssh://git@example.org:443/~git/repo.git
 
  
===Git守护进程===
+
位于 {{ic|/srv/git/}} 目录下的仓库会被守护程序识别。客户端能以类似这样的方式连接:
{{Note|The git daemon only allows read access. For write access see [[#Git SSH]].}}
 
This will allow URLs like "git clone git://localhost/my_repository.git".
 
  
Edit the configuration file for git-daemon {{ic|/etc/conf.d/git-daemon.conf}} (GIT_REPO is a place with your git projects), then start git-daemon with root privileges:
+
$ git clone git://''location''/''repository''.git
# systemctl start git-daemon@
 
  
To run the git-daemon every time at boot, enable the service:
+
=== 设置访问权限 ===
# systemctl enable git-daemon@
 
  
Clients can now simply use:
+
要限制读取和/或写入权限,可以使用常规 Unix 权限控制。更多信息请参考 [https://github.com/sitaramc/gitolite/blob/d74e58b5de8c78bddd29b009ba2d606f7fcb4f2d/doc/overkill.mkd when gitolite is overkill]。
git clone git://localhost/my_repository.git
 
  
===Git版本库权限===
+
如果需要更加精细的访问控制,请参考 [[gitolite]] 和 [[gitosis]]。
To restrict read/write access, you can simply use Unix rights, see http://sitaramc.github.com/gitolite/doc/overkill.html
 
  
For a fine-grained rights access, see [[gitolite]] and [[gitosis]]
+
== 参考资料 ==
  
==参见==
+
* Git 手册页:{{man|1|git}}
* http://book.git-scm.com/index.html
+
* [https://git-scm.com/book/en/ Pro Git book]
* http://gitref.org/
+
* 来自 GitHub 的 [https://git.github.io/git-reference/ Git Reference]
* http://www.kernel.org/pub/software/scm/git/docs/
+
* [http://nathanhoad.net/git-workflow-forks-remotes-and-pull-requests Git workflow: Forks, remotes, and pull requests]
* http://help.github.com/
+
* [https://wiki.videolan.org/Git VideoLAN wiki article]
 +
* [https://gist.github.com/grawity/4392747 A comparison of protocols GitHubGist]
 +
* [https://gun.io/blog/how-to-github-fork-branch-and-pull-request How to GitHub]

Latest revision as of 07:33, 4 May 2018

翻译状态: 本文是英文页面 Git翻译,最后翻译时间:2018-05-04,点击这里可以查看翻译后英文页面的改动。
I've met people who thought that git is a front-end to GitHub. They were wrong, git is a front-end to the AUR.

Git 是一个由 Linux 内核作者 Linus Torvalds 编写的版本控制系统(VCS),现在被用来维护 AUR 软件包以及数以千计的其他项目,其中包括 Linux 内核。

安装

安装 git 软件包。要使用开发版本,请安装 git-gitAUR 软件包。当使用 git svngit guigitk 等工具时请检查可选依赖项是否安装。

注意: 要打开 git-gui 的拼写检查功能,请安装 aspell,同时还需要与 LC_MESSAGES 环境变量 相对应的字典文件。参阅 FS#28181aspell (简体中文)

配置

你至少需要设置好姓名和邮箱之后才能开始使用 Git:

$ git config --global user.name  "John Doe"
$ git config --global user.email "johndoe@example.com"

参阅 起步 - 初次运行 Git 前的配置

更多设置选项可参阅 #提示与技巧

基本用法

一个 Git 版本库包含在一个名为 .git 的目录内,该目录包含了修订历史以及其他元数据。版本库所跟踪的目录(默认为父目录)称为工作目录。在工作树进行的更改在被提交 (commit) 前需要先暂存 (stage) 起来。Git 还可以让你恢复以前提交的工作树文件。

参阅 起步 - Git 基础

获取一个 Git 仓库

  • 初始化一个版本库
git init,参阅 git-init(1)
  • 克隆 (clone) 一个现有的版本库
git clone repository,参阅 git-clone(1)

记录更改

Git 管理的项目存在一个暂存区 (staging area),即 git 目录中的 index 文件,其中保存了即将包含在你下一次提交中的文件更改。要将某个修改过的文件记录下来,首先需要将修改后的文件添加到 index(暂存它),然后用 git commit 命令将当前的 index 保存为一次新的提交。

暂存 (stage) 更改

  • 将工作树中的文件更改添加至 index
git add pathspec,参阅 git-add(1)
  • 移除 index 中记录的文件更改
git reset pathspec,参阅 git-reset(1)
  • 显示即将提交的更改、未暂存的更改以及未被 git 跟踪的文件
git status,参阅 git-status(1)

可以用 .gitignore 文件来让 git 忽略某些未跟踪的文件,请参阅 gitignore(5)

Git 不会跟踪文件移动。合并时的文件移动检测仅基于内容的相似性。git mv 命令仅仅是为了方便,它相当于:

$ mv -i foo bar
$ git reset -- foo
$ git add bar

提交 (commit) 更改

git commit 命令将暂存区的更改保存至版本库,参阅 git-commit(1)

  • -m – 后面跟上提交消息作为参数直接提交,而不是打开默认的文本编辑器来写提交信息后再提交
  • -a – 自动暂存已更改或已删除的文件(不会添加未跟踪的文件)
  • --amend – 重做上次提交,用于修改提交消息或修改提交的文件
提示: 建议经常性的提交小更改,并附上有意义的提交信息。

选择修订版本

Git 提供了多种方式来指定修订版本,参阅 gitrevisions(7)选择修订版本

许多 Git 命令需要用修订版本作为参数。一次提交记录可以用下列任何一种方式表示:

  • 某次提交的 SHA-1 哈希值(前7位通常足以唯一标识它)
  • 任意提交时的标签,如分支名称或 tag 名称
  • 标签 HEAD 总是指向当前 check out 的提交(通常是分支的头部,除非你使用 git checkout 跳回到历史记录中的旧提交)
  • 以上任意一种表示方式加上 ~ 都可以表示之前的提交。例如,HEAD~ 指向 HEAD 的前一次提交,HEAD~5 指向 HEAD 5 次前的提交。

查看更改

查看不同提交间的修改处:

$ git diff HEAD HEAD~3

或者查看暂存区和工作树之间的不同:

$ git diff

查看修改历史(其中 "-N" 指定最近的 n 次修改):

$ git log -p (-N)

撤销修改

  • git reset - 重置当前 HEAD 指针到指定状态,参阅 git-reset(1)

分支 (branch)

Bug 修复和新功能通常在不同分支里测试。当一切就绪时它们就可以合并至默认(主)分支。

创建一个分支,其名称准确地反映了其目的:

$ git branch help-section-addition

列出已存在的分支:

$ git branch

切换分支:

$ git checkout branch

新建分支并切换至该分支:

$ git checkout -b branch

将一个分支合并回主分支:

$ git checkout master
$ git merge branch

如果不存在冲突的话,所有更改将被合并。否则 Git 将显示一条错误信息,并通过给工作树中的文件加注释来记录冲突。添加的注释可以用 git diff 显示。要解决冲突,必须编辑文件,删除注释,并提交最终版本。请参阅下面的 #处理合并 (merge)

当一个分支使用完毕,可以这样删除:

$ git branch -d branch

多人合作

一个典型的 Git 工作流像这样:

  1. 创建一个新仓库或克隆一个远程仓库。
  2. 新建一个分支用于修改文件,然后提交这些修改。
  3. 将多次提交合并在一起,这样更便于组织项目或更好地理解。
  4. 把提交的分支合并回主分支。
  5. (可选)将更改推送至远程服务器。

合并请求 (pull requests)

在做出并提交更改后,贡献者可以请求原作者合并更改。这被称为 合并请求 (pull request)

如果用 pull:

$ git pull location master

pull 命令相当于 fetchmerge 命令的结合。如果存在冲突(比如原作者在同一时间段内在相同位置做了更改),那就有必要手动解决冲突。

另一种方式是,原作者可以选择想要合并的更改。通过使用 fetch 命令(以及带有特殊 FETCH_HEAD 标记的 log 命令),可以在决定如何处理合并请求 (pull request) 前查看该请求的内容:

$ git fetch location master
$ git log -p HEAD..FETCH_HEAD
$ git merge location master

使用远程仓库 (remote)

远程 (remote) 是和本地相关联的远程仓库的别名。其实就是创建一个 label 来定义一个位置。这些 label 用于标识经常访问的仓库。

添加一个远程仓库:

$ git remote add label location

获取远程库里的内容:

$ git fetch label

显示本地主分支与远程主分支之间的差异:

$ git log -p master..label/master

查看当前仓库相关联的远程仓库:

$ git remote -v

当设置的远程仓库是本仓库的 fork 来源(项目的领导者),这个远程仓库会被定义为 upstream(上游)。

向某个仓库推送 (push) 修改

从原作者处获得推送修改的权限之后,使用以下命令推送修改:

$ git push location branch

当使用 git clone 获得这个仓库后,git 会把仓库的原始地址记录在名为 origin 的变量中。

所以一次 典型的 推送可以这样做:

$ git push origin master

如果使用了 -u (--set-upstream-to) 选项,地址将会被记录下来,下次只要使用 git push 就可以了。

处理合并 (merge)

可以查看 Git Book 的 遇到冲突时的分支合并 部分了解如何处理合并冲突。合并操作通常是可逆的,如果想返回合并前,可以使用 --abort 命令(比如 git merge --abortgit pull --abort)。

历史记录和版本记录

在历史记录中搜索

git log 命令可以显示历史记录信息,其中包含每次提交的校验和、作者、日期,以及简略信息。校验和 就是一次提交对象的 "对象名称",通常是一个 40 位的 SHA-1 哈希值。

对于具有较长信息的历史记录(其中 "checksum" 可以截取前几位,只要它是唯一的):

$ git show (checksum)

在被跟踪的文件中搜索 pattern

$ git grep pattern

.c.h 文件中搜索:

$ git grep pattern -- '*.[ch]'

使用标签 (tag)

给某次提交打标签来标记这个版本:

$ git tag 2.14 checksum

Tag 通常是用于 发布/标记版本 的,但它可以是任何字符串。通常使用带注释的标签,因为它们会被添加到 Git 数据库中。

标记当前的提交:

$ git tag -a 2.14 -m "Version 2.14"

列出标签:

$ git tag -l

删除某个标签:

$ git tag -d 2.08

更新远程库中的标签:

$ git push --tags

重新组织 commit

在提交合并请求之前,可能需要合并/重新组织 commit。这是通过 git rebase(变基)--interactive完成的:

$ git rebase -i checksum

然后会打开文本编辑器,其中包含指定范围内所有提交的摘要;这种情况下会包括最新提交 (HEAD),但不包括 checksum 表示的那次 commit。也可以使用数字来标记,例如用 HEAD~3,这会把最后三次提交变基:

pick d146cc7 Mountpoint test.
pick 4f47712 Explain -o option in readme.
pick 8a4d479 Rename documentation.

修改第一栏中的动作可以决定如何执行变基操作。可选的动作有:

  • pick — 原样保留每次提交(默认)。
  • edit — 编辑文件和/或 commit 信息。
  • reword — 编辑 commit 信息。
  • squash — 合并/折叠到先前的提交中。
  • fixup — 合并/折叠到先前的提交中并丢弃它们的信息。

提交会被重新排序或从历史记录中擦除(所以要非常小心)。编辑文件后,Git 将执行指定的操作;如果提示有合并问题待解决,请解决它们并使用 git rebase --continue 来继续,或使用 git rebase --abort 命令来取消操作。

注意: 合并多次提交的操作只能应用于本地提交,它会导致其他人共享的存储库出现问题。

提示与技巧

使用 git-config

Git 从三个 ini 类型的配置文件里读取配置:

  • /etc/gitconfig 是应用于整个系统的默认配置文件
  • ~/.gitconfig 是应用于特定用户的配置文件
  • .git/config 是应用于特定仓库的配置文件

这些文件可以直接编辑,但是更常用的方法是使用 git config,下面是一些示范。

列出当前已配置的变量:

$ git config {--local,--global,--system} --list

将默认文本编辑器从 vim 改成 nano

$ git config --global core.editor "nano -w"

设置默认的推送 (push) 行为:

$ git config --global push.default simple

设置不同的 git difftool 工具(默认是 meld):

$ git config --global diff.tool vimdiff

更多信息请参阅 git-config(1)配置 Git

保持良好的礼仪

  • 当你想为一个现有的项目贡献时,请先阅读并理解这个项目的许可,因为它可能会过度限制你更改代码的权力。有些许可会在代码的所有权方面引起争议。
  • 理解这个项目的社区,以及你可以融入其中的程度。要了解项目的主要方向,可以阅读所有文档甚至是代码库的 log
  • 当发起一个合并请求,或者提交一个补丁时,保证它是小改动并且有完善的文档;这将有助于项目维护者理解你的改动,并决定是否合并这些改动或是让你再改一下。
  • 如果贡献被拒绝,不要气馁,毕竟这是他们的项目。如果它很重要,请尽可能清楚和耐心地讨论这次贡献的理由,最终可能通过这种方法解决问题。

加快身份验证

每次向 Git 服务器推送时都要认证身份,你可能会想要避免这种麻烦。

默认通讯协议

如果你正在使用一个上述那种复用的 SSH 连接,让 Git 使用 SSH 可能比使用 HTTPS 更快。同时,一些服务器(比如 AUR)只允许通过 SSH 推送更改。例如,像下面这样配置可以使得 Git 通过 SSH 访问 AUR 上的任何仓库。

~/.gitconfig
[url "ssh://aur@aur.archlinux.org/"]
	insteadOf = https://aur.archlinux.org/
	insteadOf = http://aur.archlinux.org/
	insteadOf = git://aur.archlinux.org/

Bash 自动补全

要启用 Bash 的自动补全,请在 Bash 启动文件 里用 source 加载 /usr/share/git/completion/git-completion.bash 文件。或者也可以安装 bash-completion

Git 提示符

Git 包带有一个提示符脚本。要启用它,请用 source 加载 /usr/share/git/completion/git-prompt.sh 脚本,然后使用 %s 参数设置一个自定义 shell 提示符:

  • Bash 用户: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
  • zsh 用户: setopt PROMPT_SUBST ; PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '

要自动完成这项工作,请参阅 Command-line shell#Configuration files

当切换至一个 Git 仓库所在目录时,shell 提示符会变成所在分支名称。也可以配置提示符来显示其他信息:

Shell variable Information
GIT_PS1_SHOWDIRTYSTATE 已暂存 (staged) 显示 +,未暂存 (unstaged) 显示 *
GIT_PS1_SHOWSTASHSTATE 已储藏 (stashed) 显示 $
GIT_PS1_SHOWUNTRACKEDFILES 有未跟踪文件时显示 %
GIT_PS1_SHOWUPSTREAM <,>,<> 分别表示落后于上游、领先于上游、偏离上游。

GIT_PS1_SHOWUPSTREAM 需要设置为 auto 才能使更改生效。

注意: 如果发生了 $(__git_ps1) 返回 ((unknown)) 的情况,是因为有一个 .git 文件夹在你当前的文件夹里面,但却不包含任何存储库,因此 Git 不认识它。这有可能发生在你把 ~/.git/config 误认为是 Git 的配置文件而不是 ~/.gitconfig

你也可以使用来自 AUR 的自定义 git shell 提示符软件包,例如 bash-git-promptAURgittifyAUR

可视化显示

要了解已经完成了多少工作:

$ git diff --stat

带有 fork 显示的 git log

$ git log --graph --oneline --decorate

给图形化的 git log 做一个别名(使用 git graph 即可显示经过修饰的 log):

$ git config --global alias.graph 'log --graph --oneline --decorate'

关于提交 (commit) 的小提示

重置为以前的提交(非常危险,这将会擦除所有内容并改写为特定提交):

$ git reset --hard HEAD^

如果远程仓库的地址发生变化,可以这样更新它的位置:

$ git remote set-url origin git@address:user/repo.git

自动附加签名行到提交(将某个 姓名-电邮 签名添加到提交中,某些项目会要求这样做):

$ git commit -s

自动附加签名到补丁(使用 git format-patch commit 时生效):

$ git config --local format.signoff true

提交已更改文件的特定部分。如果有大量更改时,最好拆分成多个提交,这种情况下这个命令通常很有用:

$ git add -p

对提交 (commit) 签名

Git 允许使用 GnuPG 对提交和标签进行签名,请参见 签署工作

注意: 如果是借助 pinentry 来进行 GPG 签名,请确保 export GPG_TTY=$(tty)(或者使用 pinentry-tty),否则当 GPG 处于锁定状态时签名这一步会失败(因为它无法在 shell 提示符里询问 pin 码)。

配置 Git 使它自动对提交进行签名:

$ git config --global commit.gpgSign true

在非主分支上工作

偶尔项目维护人员会要求你在其他分支上完成工作。这些分支通常被称为 develtesting。首先要克隆存储库。

要进入不是主分支的分支(git clone 只会显示主分支,但其他分支其实也是存在的,用 git branch -a 可以显示出来):

$ git checkout -b branch origin/branch

然后就可以像平常一样编辑文件,但是要使得整个仓库都保持同步,下面这两个命令都要用:

$ git pull --all
$ git push --all

直接将补丁发送至邮件列表

如果你想直接将补丁发送至一个邮件列表,需要安装以下软件包:perl-authen-saslperl-net-smtp-sslperl-mime-tools

确保你已经配置了用户名和邮件地址,可参阅 #配置

配置你的邮箱设置:

$ git config --global sendemail.smtpserver smtp.example.com
$ git config --global sendemail.smtpserverport 587
$ git config --global sendemail.smtpencryption tls
$ git config --global sendemail.smtpuser foobar@example.com

现在你应该可以将补丁发送至某个邮件列表了(可参阅OpenEmbedded:How to submit a patch to OpenEmbedded#Sending patches):

$ git add filename
$ git commit -s
$ git send-email --to=openembedded-core@lists.openembedded.org --confirm=always -M -1

Git 服务器

这一节讲述如何配置使用不同的协议连接到存储库。

SSH 协议

要使用 SSH 协议,首先要准备一个 SSH 公钥,可以按照 SSH keys (简体中文) 的指导来完成。要配置一个 SSH 服务器,请遵循 Secure Shell (简体中文) 的指导。

当 SSH 生成了密钥之后,将 ~/.ssh/id_rsa.pub 文件的内容粘贴至服务器上的 ~/.ssh/authorized_keys 文件里(一行一个,同一个公钥确保在同一行)。现在 Git 仓库可以通过 SSH 来访问:

$ git clone user@foobar.com:my_repository.git

现在,如果你的 SSH 客户端的 StrictHostKeyChecking 选项设为了 ask(默认),你应该会收到来自 SSH 的问题,要你回答 yes/no。输入 yes 然后回车,你的仓库就能被取出。同时,由于通过 SSH 协议访问,你现在应该有提交权限。

要把一个已存在的仓库改成使用 SSH 访问,需要重新定义一下远程地址:

$ git remote set-url origin git@localhost:my_repository.git

要从非 22 端口连接,可以在每台主机的 /etc/ssh/ssh_config~/.ssh/config 里配置。要为某个本地仓库设置端口(示例中用的 443 端口):

.git/config
[remote "origin"]
    url = ssh://user@foobar.com:443/~my_repository/repo.git

你可以通过只允许用户执行 push 和 pull 操作来进一步提高 SSH 账户的安全性。这是通过将该账户的默认登录 shell 换成 git-shell 来实现的。在 配置服务器 中对此有所描述。

Smart HTTP 协议

通过使用 git-http 后端,Git 可以像使用 SSH 协议或 Git 协议一样高效地使用 HTTP(S) 协议。此外,它不仅可以从仓库中克隆或拉取更改,还可以通过 HTTP(S) 推送更改。

这个设置相当简单,因为你只需要安装 Apache Web 服务器(apache,启用 mod_cgimod_aliasmod_env),当然还要安装 git

当你正在进行基本设置时,请将以下内容添加到 Apache 配置文件中,该配置文件通常位于:

/etc/httpd/conf/httpd.conf
<Directory "/usr/lib/git-core*">
    Require all granted
</Directory>
 
SetEnv GIT_PROJECT_ROOT /srv/git
SetEnv GIT_HTTP_EXPORT_ALL
ScriptAlias /git/ /usr/lib/git-core/git-http-backend/

这里假设你的 Git 仓库位于 /srv/git,并且你想用类似 http(s)://your_address.tld/git/your_repo.git 的方式来访问它们。

注意: 请确保 Apache 对你的仓库有读写权限。

如果需要更多详细文档,请访问:

Git 协议

注意: Git 协议没有加密或认证机制,且只允许读取。

Start 并且 enable git-daemon.socket 这个 systemd 单元。

守护程序会带有以下选项启动:

ExecStart=-/usr/lib/git-core/git-daemon --inetd --export-all --base-path=/srv/git

位于 /srv/git/ 目录下的仓库会被守护程序识别。客户端能以类似这样的方式连接:

$ git clone git://location/repository.git

设置访问权限

要限制读取和/或写入权限,可以使用常规 Unix 权限控制。更多信息请参考 when gitolite is overkill

如果需要更加精细的访问控制,请参考 gitolitegitosis

参考资料