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

From ArchWiki
Jump to: navigation, search
m (Use rc.d tool)
(Full sync with English Version.)
 
(10 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-04-17|516679}}
{{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 (简体中文)#保持在线]]。
 +
* 如果你是用账号和密码来认证的,在服务器支持 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]。
 +
 
 +
=== 默认通讯协议 ===
 +
 
 +
如果你正在使用一个上述那种复用的 SSH 连接,让 Git 使用 SSH 可能比使用 HTTPS 更快。同时,一些服务器(比如 AUR)只允许通过 SSH 推送更改。例如,像下面这样配置可以使得 Git 通过 SSH 访问 AUR 上的任何仓库。
 +
 
 +
{{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>}}
 +
 
 +
=== Bash 自动补全 ===
 +
 
 +
要启用 Bash 的自动补全,请在 [[Bash#Configuration_files|Bash 启动文件]] 里用 source 加载 {{ic|/usr/share/git/completion/git-completion.bash}} 文件。或者也可以安装 {{pkg|bash-completion}}。
 +
 
 +
=== Git 提示符 ===
 +
 
 +
Git 包带有一个提示符脚本。要启用它,请在 [[Autostarting (简体中文)#Shells|shell 启动文件]] 里用 source 加载 {{ic|/usr/share/git/completion/git-prompt.sh}} 脚本,然后使用 {{ic|%s}} 参数设置一个自定义 shell 提示符:
 +
 
 +
* [[Bash]] 用户: {{ic|1=PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '}}
 +
* [[zsh]] 用户: {{ic|1=setopt PROMPT_SUBST ; PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '}}
 +
 
 +
当切换至一个 Git 仓库所在目录时,shell 提示符会变成所在分支名称。也可以配置提示符来显示其他信息:
 +
 
 +
{| class="wikitable"
 +
|+
 +
! Shell variable !! Information
 +
|-
 +
| GIT_PS1_SHOWDIRTYSTATE    || 已暂存 (staged) 显示 '''+''',未暂存 (unstaged) 显示 '''*'''。
 +
|-
 +
| GIT_PS1_SHOWSTASHSTATE    || 已储藏 (stashed) 显示 '''$'''。
 +
|-
 +
| GIT_PS1_SHOWUNTRACKEDFILES || 有未跟踪文件时显示 '''%'''。
 +
|-
 +
| GIT_PS1_SHOWUPSTREAM      || '''<,>,<>''' 分别表示落后于上游、领先于上游、偏离上游。
 +
|}
 +
 
 +
{{ic|GIT_PS1_SHOWUPSTREAM}} 需要设置为 {{ic|auto}} 才能使更改生效。
 +
 
 +
{{注意|如果发生了 {{ic|$(__git_ps1)}} 返回 {{ic|((unknown))}} 的情况,是因为有一个 {{ic|.git}} 文件夹在你当前的文件夹里面,但却不包含任何存储库,因此 Git 不认识它。这有可能发生在你把 {{ic|~/.git/config}} 误认为是 Git 的配置文件而不是 {{ic|~/.gitconfig}}。}}
 +
 
 +
你也可以使用来自 [[AUR]] 的自定义 git shell 提示符软件包,例如 {{AUR|bash-git-prompt}} 或 {{AUR|gittify}}。
 +
 
 +
=== 可视化显示 ===
 +
 
 +
要了解已经完成了多少工作:
 +
 
 +
$ 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
 +
 
 +
自动附加签名到补丁(使用 {{ic|git format-patch ''commit''}} 时生效):
 +
 
 +
$ git config --local format.signoff true
 +
 
 +
提交已更改文件的特定部分。如果有大量更改时,最好拆分成多个提交,这种情况下这个命令通常很有用:
 +
 
 +
$ git add -p
 +
 
 +
=== 对提交 (commit) 签名 ===
 +
 
 +
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 签署工作]
 +
 
 +
{{注意|
 +
如果是借助 {{Pkg|pinentry}} 来进行 GPG 签名,请确保 {{ic|1=export GPG_TTY=$(tty)}}(或者使用 pinentry-tty),否则当 GPG 处于锁定状态时签名这一步会失败(因为它无法在 shell 提示符里询问 pin 码)。}}
 +
 
 +
配置 Git 使它自动对提交进行签名:
 +
 
 +
$ git config --global commit.gpgSign true
 +
 
 +
=== 在非主分支上工作 ===
 +
 
 +
偶尔项目维护人员会要求你在其他分支上完成工作。这些分支通常被称为 {{ic|devel}} 或 {{ic|testing}}。首先要克隆存储库。
 +
 
 +
要进入不是主分支的分支(''git clone'' 只会显示主分支,但其他分支其实也是存在的,用 {{ic|git branch -a}} 可以显示出来):
 +
 
 +
$ git checkout -b ''branch'' origin/''branch''
 +
 
 +
然后就可以像平常一样编辑文件,但是要使得整个仓库都保持同步,下面这两个命令都要用:
 +
 
 +
$ git pull --all
 +
$ git push --all
 +
 
 +
=== 直接将补丁发送至邮件列表 ===
 +
 
 +
如果你想直接将补丁发送至一个邮件列表,需要安装以下软件包:{{Pkg|perl-authen-sasl}},{{Pkg|perl-net-smtp-ssl}} 和 {{Pkg|perl-mime-tools}}。
  
这是一些你可能用到的常见的配置:
+
确保你已经配置了用户名和邮件地址,可参阅 [[#配置]]。
$ git config --global user.name "Firstname Lastname"
 
$ git config --global user.email "your_email@youremail.com"
 
$ git config --global color.ui true
 
$ git config --global --list
 
  
==备忘单==
+
配置你的邮箱设置:
内容来自很多地方,很多来自这个不错的教程 http://schacon.github.com/git/gittutorial.html
 
  
另外可以参考 [[Super Quick Git Guide]].
+
$ 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''
  
Pull 网络脚本,用以下命令:
+
现在你应该可以将补丁发送至某个邮件列表了(可参阅[http://www.openembedded.org/wiki/How_to_submit_a_patch_to_OpenEmbedded#Sending_patches OpenEmbedded:How to submit a patch to OpenEmbedded#Sending patches]):
git clone <nowiki>http://archlinux.org/~james/projects/network.git</nowiki>
 
更新以存在的克隆
 
git pull origin
 
提交(Commit)更改
 
git commit -a -m "changelog message"
 
创建新分支
 
git branch somebranch
 
切换到新分支
 
git checkout differentbranch
 
合并分支到现在活动的分支
 
git merge somebranch
 
删除分支
 
git branch -d somebranch
 
Push a local branch or tag to a remote repository
 
git push REMOTENAME BRANCHNAME
 
在远程仓库删除一个分支或标签
 
git push REMOTENAME :BRANCHNAME
 
两个分支比较
 
git diff master..somebranch
 
两个提交ID(可以在 git 日志找到)比较
 
git diff e9780c7cba2855350e914fde227a79bb63c1351d..8b014e40346b38b3b9bfc41359b4e8a68e804c0d
 
最后两次提交比较
 
git diff HEAD^ HEAD
 
两个分支之间制作补丁 (follows same syntax as git diff afaik)
 
git format-patch master..somebranch
 
或者更好的办法: http://wiki.winehq.org/GitWine#head-f7a29e7ed999b5924748a60c5a1cd4a019032d26
 
git format-patch -o out origin
 
设置 [[nano]] 为默认编辑器
 
git config --global core.editor "nano -w"
 
  
==Git Prompt==
+
$ git add ''filename''
The {{pkg|git}} package comes with a Bash completion file. This file also contains the necessary functions to provide Git information on your Bash or zsh shell prompt. To enable it add {{Ic|$(__git_ps1 " (%s)")}} to you PS1 variable.
+
  $ git commit -s
* For Bash:
+
  $ git send-email --to=''openembedded-core@lists.openembedded.org'' --confirm=always -M -1
  PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
 
* For zsh:
 
  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:
+
== Git 服务器 ==
  
{| border="1"
+
这一节讲述如何配置使用不同的协议连接到存储库。
|+
 
! 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
 
|}
 
  
In addition you can set the {{Ic|GIT_PS1_SHOWUPSTREAM}} variable to {{Ic|"auto"}} in order to see {{Ic|'''<'''}} if you are behind upstream, {{Ic|'''>'''}} if you are ahead and {{Ic|'''<>'''}} if you have diverged.
+
=== SSH 协议 ===
  
{{Note|If you do not use Bash completion consider sourcing {{ic|/usr/share/git/completion/git-completion.bash}} in your {{ic|~/.bashrc}}/{{ic|~/.zshrc}}.}}
+
要使用 SSH 协议,首先要准备一个 SSH 公钥,可以按照 [[SSH keys (简体中文)]] 的指导来完成。要配置一个 SSH 服务器,请遵循 [[Secure Shell (简体中文)]] 的指导。
  
==Transfer Protocols==
+
当 SSH 生成了密钥之后,将 {{ic|~/.ssh/id_rsa.pub}} 文件的内容粘贴至服务器上的 {{ic|~/.ssh/authorized_keys}} 文件里(一行一个,同一个公钥确保在同一行)。现在 Git 仓库可以通过 SSH 来访问:
===Smart 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 webserver (with mod_cgi, mod_alias, and mod_env enabled) and of course, git:
+
$ git clone ''user''@''foobar.com'':''my_repository''.git
# 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}}:
+
现在,如果你的 SSH 客户端的 {{ic|StrictHostKeyChecking}} 选项设为了 {{ic|ask}}(默认),你应该会收到来自 SSH 的问题,要你回答 yes/no。输入 {{ic|yes}} 然后回车,你的仓库就能被取出。同时,由于通过 SSH 协议访问,你现在应该有提交权限。
<Directory "/usr/lib/git-core*">
+
 
    Order allow,deny
+
要把一个已存在的仓库改成使用 SSH 访问,需要重新定义一下远程地址:
    Allow from all
+
 
</Directory>
+
$ git remote set-url origin git@localhost:''my_repository''.git
 +
 
 +
要从非 22 端口连接,可以在每台主机的 {{ic|/etc/ssh/ssh_config}} 或 {{ic|~/.ssh/config}} 里配置。要为某个本地仓库设置端口(示例中用的 443 端口):
 +
 
 +
{{hc|.git/config|2=
 +
[remote "origin"]
 +
    url = ssh://''user''@''foobar''.com:443/~''my_repository''/repo.git
 +
}}
 +
 
 +
你可以通过只允许用户执行 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 配置服务器] 中对此有所描述。
 +
 
 +
=== Smart HTTP 协议 ===
 +
 
 +
通过使用 git-http 后端,Git 可以像使用 SSH 协议或 Git 协议一样高效地使用 HTTP(S) 协议。此外,它不仅可以从仓库中克隆或拉取更改,还可以通过 HTTP(S) 推送更改。
 +
 
 +
这个设置相当简单,因为你只需要安装 Apache Web 服务器({{pkg|apache}},启用 {{ic|mod_cgi}}、{{ic|mod_alias}} 和 {{ic|mod_env}}),当然还要安装 {{pkg|git}}。
 +
 
 +
当你正在进行基本设置时,请将以下内容添加到 Apache 配置文件中,该配置文件通常位于:
 +
 
 +
{{hc|/etc/httpd/conf/httpd.conf|
 +
<Directory "/usr/lib/git-core*">
 +
    Require all granted
 +
</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
 
* http://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 setup SSH itself you need to follow the [[SSH]] guide. I assume you have a public SSH key now and your SSH is working.
 
Open your SSH key in your favorite editor (default public key name is id_rsa.pub and is located in {{ic|~/.ssh}}) and copy its content (CTRL + C).
 
Now go to your user where you have made your git repository, since we now need to allow that SSH key to login on that user to access the GIT repository.
 
Open this file in your favorite editor (i use nano)
 
nano ~/.ssh/authorized_keys
 
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 repo 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 yes followed by enter. Then you should have your repository checked out. Since this is with SSH you also do have commit rights now. For that look at [[Git]] and [[Super Quick Git Guide]].
 
  
====Specifying a non-standard port====
+
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 ''N'' and the '''absolute path''' ''/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 Daemon===
+
位于 {{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 configuration file for git-dameon {{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
# rc.d start git-daemon
 
  
To run the git-daemon every time at boot, just append {{Ic|git-daemon}} to {{Ic|DAEMONS}} line in [[rc.conf]].
+
=== 设置访问权限 ===
  
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 repositories rights ===
+
如果需要更加精细的访问控制,请参考 [[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 11:40, 17 April 2018

翻译状态: 本文是英文页面 Git翻译,最后翻译时间:2018-04-17,点击这里可以查看翻译后英文页面的改动。
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 包带有一个提示符脚本。要启用它,请在 shell 启动文件 里用 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)")]\$ '

当切换至一个 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

参考资料