设置和配置
获取和创建项目
基本快照
分支与合并
共享和更新项目
检查和比较
打补丁
调试
电子邮件
外部系统
服务器管理
指南
管理
底层命令
- 2.46.1 → 2.50.1 无更改
-
2.46.0
2024-07-29
- 2.34.1 → 2.45.4 无更改
-
2.34.0
2021-11-15
- 2.29.1 → 2.33.8 无变更
-
2.29.0
2020-10-19
- 2.27.1 → 2.28.1 无变更
-
2.27.0
2020-06-01
描述
本常见问题解答中的示例假定使用标准的 POSIX shell(如 bash
或 dash
),以及用户 A U Thor(其在托管服务提供商 git.example.org
上的帐户名为 author
)。
配置
user.name
中应该填写什么?-
您应该填写您的个人姓名,通常是名字和姓氏的组合。例如,Git 的现任维护者使用“Junio C Hamano”。这将是您每次提交时存储的姓名部分。
此配置对远程服务的身份验证没有任何影响;有关身份验证,请参阅 git-config[1] 中的
credential.username
。
http.postBuffer
到底有什么作用?-
此选项更改 Git 在通过 HTTP 或 HTTPS 向远程推送数据时使用的缓冲区大小。如果数据大于此大小,处理 Git HTTP 支持的 libcurl 将使用分块传输编码,因为它无法预先知道推送数据的大小。
除非您知道远程服务器或中间代理不支持 HTTP/1.1(它引入了分块传输编码)或者已知在处理分块数据时存在问题,否则将此值保留为默认大小即可。这通常被(错误地)建议作为通用推送问题的解决方案,但由于几乎所有服务器和代理都至少支持 HTTP/1.1,因此增加此值通常无法解决大多数推送问题。一个无法正确支持 HTTP/1.1 和分块传输编码的服务器或代理在今天的互联网上作用不大,因为它会中断大量流量。
请注意,增加此值会增加 Git 在通过 HTTP 或 HTTPS 进行每次相关推送时使用的内存,因为整个缓冲区都会被分配,无论是否全部使用。因此,最好将其保留为默认值,除非您确定需要不同的值。
- 如何配置不同的编辑器?
-
如果您没有专门为 Git 指定编辑器,它将默认使用您通过
VISUAL
或EDITOR
环境变量配置的编辑器,如果两者都未指定,则使用系统默认编辑器(通常是vi
)。由于有些人觉得vi
难以使用或偏爱其他编辑器,因此可能需要更改所使用的编辑器。如果您想为大多数需要编辑器的程序配置一个通用编辑器,您可以编辑您的 shell 配置文件(例如,
~/.bashrc
或~/.zshenv
),在其中添加一行设置EDITOR
或VISUAL
环境变量为适当的值。例如,如果您偏爱nano
编辑器,那么您可以这样写:export VISUAL=nano
如果您想专门为 Git 配置一个编辑器,您可以设置
core.editor
配置值或GIT_EDITOR
环境变量。有关这些选项的查询顺序的详细信息,请参阅 git-var[1]。请注意,在所有情况下,编辑器值都将传递给 shell,因此任何包含空格的参数都应正确引用。此外,如果您的编辑器在调用时通常会从终端分离,您应该指定一个参数使其不这样做,否则 Git 将看不到任何更改。一个在 Windows 上解决这两个问题的配置示例是配置 "C:\Program Files\Vim\gvim.exe" --nofork,它引用了带空格的文件名并指定了
--nofork
选项以避免进程后台化。
凭据
- 如何在通过 HTTP 推送时指定凭据?
-
最简单的方法是通过
credential.helper
配置使用凭据助手。大多数系统都提供了一个标准选项来与系统凭据管理器集成。例如,Git for Windows 提供wincred
凭据管理器,macOS 有osxkeychain
凭据管理器,而带有标准桌面环境的 Unix 系统可以使用libsecret
凭据管理器。所有这些都将凭据存储在加密存储中,以确保您的密码或令牌安全。此外,您可以使用
store
凭据管理器,它将凭据存储在您的主目录中的文件中;或者使用cache
凭据管理器,它不会永久存储您的凭据,但会在一定时间内阻止您被提示输入凭据。您也可以在提示时直接输入密码。虽然可以将密码(必须经过百分比编码)放在 URL 中,但这并不是特别安全,并且可能导致凭据意外暴露,因此不推荐这样做。
- 如何使用同一个托管服务提供商的多个 HTTP 帐户?
-
通常,区分这些帐户最简单的方法是在 URL 中使用用户名。例如,如果您在
git.example.org
上拥有author
和committer
帐户,您可以使用 URL https://author@git.example.org/org1/project1.git 和 https://committer@git.example.org/org2/project2.git。这样,当您使用凭据助手时,它将自动尝试查找您的帐户的正确凭据。如果您已经设置了远程仓库,您可以使用类似git
remote
set-url
origin
https://author@git.example.org/org1/project1.git
的命令更改 URL(有关详细信息,请参阅 git-remote[1])。
- 如何使用同一个托管服务提供商的多个 SSH 帐户?
-
对于大多数支持 SSH 的托管服务提供商,单个密钥对唯一标识一个用户。因此,要使用多个帐户,需要为每个帐户创建密钥对。如果您使用的是相当现代的 OpenSSH 版本,您可以使用类似
ssh-keygen
-t
ed25519
-f
~/.ssh/id_committer
的命令创建一个新的密钥对。然后您可以向托管服务提供商注册公钥(在这种情况下是~/.ssh/id_committer.pub
;请注意.pub
后缀)。大多数托管服务提供商使用单个 SSH 账户进行推送;也就是说,所有用户都推送到
git
账户(例如,git@git.example.org
)。如果您的提供商也是如此,您可以在 SSH 中设置多个别名,以明确使用哪个密钥对。例如,您可以在~/.ssh/config
中写入类似以下内容,并替换为正确的私钥文件:# This is the account for author on git.example.org. Host example_author HostName git.example.org User git # This is the key pair registered for author with git.example.org. IdentityFile ~/.ssh/id_author IdentitiesOnly yes # This is the account for committer on git.example.org. Host example_committer HostName git.example.org User git # This is the key pair registered for committer with git.example.org. IdentityFile ~/.ssh/id_committer IdentitiesOnly yes
然后,您可以调整您的推送 URL,使用
git@example_author
或git@example_committer
来代替git@example.org
(例如,git
remote
set-url
git@example_author:org1/project1.git
)。
传输
- 如何在系统间同步工作区?
-
首先,决定您是否要这样做。Git 在您使用典型的
git
push
和git
fetch
命令推送或拉取您的工作时效果最佳,并且不设计用于在系统间共享工作区。这具有潜在风险,在某些情况下可能导致仓库损坏或数据丢失。通常,这样做会导致
git
status
需要重新读取工作区中的每个文件。此外,Git 的安全模型不允许在不信任的用户之间共享工作区,因此只有当工作区仅由一个用户在所有机器上使用时,同步工作区才是安全的。重要的是不要使用云同步服务来同步 Git 仓库的任何部分,因为这可能导致损坏,例如对象丢失、文件更改或添加、引用损坏以及各种其他问题。这些服务倾向于持续按文件同步,并且不理解 Git 仓库的结构。如果在仓库更新过程中同步,情况会特别糟糕,因为这很可能导致不完整或部分更新,从而导致数据丢失。
可能发生的损坏示例是关于引用的状态冲突,导致双方在某个分支上都拥有对方没有的不同提交。这可能导致重要对象变得不被引用,并可能被
git
gc
清理,从而导致数据丢失。因此,最好使用正常的推送和拉取机制,将您的工作推送到另一个系统或中央服务器。然而,这并不总是能保留重要数据,例如暂存区内容(stashes),因此有些人更喜欢在系统之间共享工作区。
如果您这样做,推荐的方法是对仓库根目录使用
rsync
-a
--delete-after
(理想情况下使用加密连接,例如ssh
)。当您这样做时,应确保以下几点:-
如果您有额外的
worktrees
或一个独立的 Git 目录,它们必须与主工作区和仓库同时同步。 -
您接受目标目录是源目录的精确副本,删除已有的任何数据。
-
在传输期间,仓库(包括所有工作区和 Git 目录)处于静止状态(即,没有进行任何类型的操作,包括后台操作如
git
gc
和您的编辑器调用的操作)。请注意,即使有这些建议,以这种方式同步仍存在一定风险,因为它绕过了 Git 对仓库的正常完整性检查,因此建议进行备份。您可能还希望在同步后在目标系统上运行
git
fsck
来验证数据的完整性。
-
常见问题
- 我要求 Git 忽略某些文件,但它们仍然被跟踪
-
gitignore
文件确保某些未被 Git 跟踪的文件保持未跟踪状态。然而,有时特定文件在被添加到.gitignore
之前可能已经被跟踪,因此它们仍然处于被跟踪状态。要取消跟踪并忽略文件/模式,请使用 git rm --cached <file/pattern> 并向.gitignore
添加一个与 <file> 匹配的模式。有关详细信息,请参阅 gitignore[5]。
- 我怎么知道应该执行 fetch 还是 pull?
-
fetch 从远程仓库存储最新更改的副本,而不修改工作区或当前分支。然后您可以随意检查、合并、在其之上变基或忽略上游更改。pull 包含一次 fetch,然后立即进行合并或变基。请参阅 git-pull[1]。
- 我可以使用代理与 Git 吗?
-
是的,Git 支持使用代理。Git 遵循 Unix 上常用的标准
http_proxy
、https_proxy
和no_proxy
环境变量,也可以通过http.proxy
和类似的 HTTPS 选项进行配置(参见 git-config[1])。http.proxy
和相关选项可以根据每个 URL 模式进行自定义。此外,Git 理论上可以与网络上存在的透明代理正常运行。对于 SSH,Git 可以使用 OpenSSH 的
ProxyCommand
支持代理。常用的工具包括netcat
和socat
。但是,它们必须配置为在标准输入看到 EOF 时不退出,这通常意味着netcat
将需要-q
,而socat
将需要超时,例如-t
10
。这是必需的,因为 Git SSH 服务器知道不再有请求的方式是在标准输入上遇到 EOF,但当发生这种情况时,服务器可能尚未处理最终请求,因此此时断开连接将中断该请求。一个在
~/.ssh/config
中使用 HTTP 代理的配置条目可能如下所示:Host git.example.org User git ProxyCommand socat -t 10 - PROXY:proxy.example.org:%h:%p,proxyport=8080
请注意,在所有情况下,为了使 Git 正常工作,代理必须完全透明。代理不能以任何方式修改、篡改或缓冲连接,否则 Git 几乎肯定会无法工作。请注意,许多代理,包括许多 TLS 中间盒、Windows Defender 和 Windows Firewall 之外的 Windows 杀毒软件和防火墙程序,以及过滤代理,都未能达到此标准,结果导致 Git 无法正常工作。鉴于大量问题报告及其糟糕的安全历史,我们不建议使用这些类别的软件和设备。
合并与变基
- 使用 squash 合并来合并长期分支会发生什么问题?
-
一般来说,使用 squash 合并多次合并两个分支时可能会出现各种问题。这可能包括在
git
log
输出、GUI 或使用 ... 符号表示范围时看到额外的提交,以及可能需要反复重新解决冲突的问题。当 Git 对两个分支进行正常合并时,它会考虑三个点:这两个分支和一个称为合并基础的第三个提交,通常是这些提交的共同祖先。合并的结果是合并基础与每个头之间的更改的总和。当您使用常规合并提交合并两个分支时,这将生成一个新的提交,当它们再次合并时,该提交将成为新的合并基础,因为现在有了一个新的共同祖先。Git 无需考虑合并基础之前发生的更改,因此您不必重新解决之前解决过的任何冲突。
当您执行 squash 合并时,不会创建合并提交;相反,一方的更改将作为常规提交应用到另一方。这意味着这些分支的合并基础不会改变,因此当 Git 执行下一次合并时,它会考虑上次考虑的所有更改以及新的更改。这意味着任何冲突可能需要重新解决。同样,任何在
git
diff
、git
log
或 GUI 中使用 ... 符号的操作都将显示自原始合并基础以来的所有更改。因此,如果您想反复合并两个长期分支,最好始终使用常规合并提交。
- 如果我在两个分支上都进行了更改,但在一个分支上撤销了该更改,为什么这些分支的合并仍然包含该更改?
-
默认情况下,当 Git 进行合并时,它使用一种称为
ort
策略的方法,这是一种高级的三向合并。在这种情况下,当 Git 执行合并时,它只考虑三个点:两个头和一个称为合并基础的第三个点,该点通常是这些提交的共同祖先。Git 完全不考虑这些分支上发生的历史或单个提交。因此,如果两边都有更改,而其中一边撤销了该更改,结果是包含该更改。这是因为代码在一边发生了更改,而另一边没有净更改,在这种情况下,Git 采用该更改。
如果这对您来说是个问题,您可以改为进行 rebase,将带有撤销的那个分支 rebase 到另一个分支上。在这种情况下,rebase 将撤销更改,因为 rebase 会应用每个单独的提交,包括撤销。请注意,rebase 会重写历史记录,因此除非您确定可以接受,否则应避免对已发布的(published)分支进行 rebase。有关更多详细信息,请参阅 git-rebase[1] 中的 NOTES 部分。
钩子
- 如何使用钩子来阻止用户进行某些更改?
-
进行这些更改的唯一安全位置是远程仓库(即 Git 服务器),通常在
pre-receive
钩子或持续集成 (CI) 系统中。这些是政策可以有效执行的位置。尝试使用
pre-commit
钩子(或者对于提交消息,使用commit-msg
钩子)来检查这些事情是很常见的,如果您是单独开发者并希望工具帮助您,这非常有用。然而,在开发者机器上使用钩子作为策略控制是无效的,因为用户可以(通过各种其他方式)使用--no-verify
绕过这些钩子而不被发现。Git 假定用户控制其本地仓库,并且不会试图阻止或告发用户。此外,一些高级用户发现
pre-commit
钩子会妨碍使用临时提交来暂存进行中的工作或创建 fixup 提交的工作流程,因此最好还是将此类检查推送到服务器。
跨平台问题
- 我使用 Windows,并且我的文本文件被检测为二进制文件。
-
当您以 UTF-8 格式存储文本文件时,Git 的工作效果最佳。Windows 上的许多程序支持 UTF-8,但有些不支持,只使用小端 UTF-16 格式,Git 会将其检测为二进制文件。如果您的程序不能使用 UTF-8,您可以指定一个工作区编码,指示您的文件应该以何种编码检出,同时仍将这些文件以 UTF-8 存储在仓库中。这允许 git-diff[1] 等工具按预期工作,同时仍允许您的工具工作。
为此,您可以指定一个带有
working-tree-encoding
属性的 gitattributes[5] 模式。例如,以下模式将所有 C 语言文件设置为使用 UTF-16LE-BOM,这是 Windows 上常见的编码:*.c working-tree-encoding=UTF-16LE-BOM
您需要运行
git
add
--renormalize
才能使其生效。请注意,如果您在跨平台使用的项目中进行这些更改,您可能希望在每个用户的配置文件中或$GIT_DIR/info/attributes
中的文件中进行更改,因为在仓库的.gitattributes
文件中进行更改将应用于仓库的所有用户。有关标准化行尾的信息,请参阅以下条目,并参阅 gitattributes[5] 获取有关属性文件的更多信息。
- 我使用 Windows,并且 `git diff` 显示我的文件末尾有
^M
。 -
默认情况下,Git 期望文件以 Unix 行尾存储。因此,作为 Windows 行尾一部分的回车符(
^M
)会显示出来,因为它被视为尾随空白。Git 默认只在新行上显示尾随空白,而不显示现有行上的。您可以将文件以 Unix 行尾存储在仓库中,并自动将其转换为您平台的行尾。为此,请将配置选项
core.eol
设置为native
,并参阅关于推荐存储设置的问题以获取有关如何将文件配置为文本或二进制的信息。如果您不想从行尾删除回车符,也可以使用
core.whitespace
设置来控制此行为。
- 为什么我有一个文件总是显示为已修改?
-
在内部,Git 总是将文件名存储为字节序列,并且不执行任何编码或大小写折叠。然而,Windows 和 macOS 默认都会对文件名执行大小写折叠。因此,可能会出现多个文件名仅大小写不同的文件或目录。Git 可以很好地处理这个问题,但文件系统只能存储其中一个文件,因此当 Git 读取另一个文件以查看其内容时,它看起来会已修改。
最好删除其中一个文件,这样您就只剩下一个文件。在其他方面干净的工作区上,您可以使用以下命令(假设有两个文件
AFile.txt
和afile.txt
)来完成此操作:$ git rm --cached AFile.txt $ git commit -m 'Remove files conflicting in case' $ git checkout .
这避免了对磁盘的实际操作,但会删除额外的文件。您的项目可能倾向于采用命名约定,例如全部小写名称,以避免此问题再次发生;可以使用
pre-receive
钩子或作为持续集成 (CI) 系统的一部分来检查此类约定。如果您的系统上正在使用 smudge 或 clean 过滤器,但文件之前在未运行 smudge 或 clean 过滤器的情况下提交,则在任何平台上也可能出现永久修改的文件。要解决此问题,请在其他方面干净的工作区上运行以下命令:
$ git add --renormalize .
- 在 Git 中存储文件的推荐方式是什么?
-
虽然 Git 可以存储和处理任何类型的文件,但有些设置比其他设置效果更好。一般来说,我们建议文本文件以 UTF-8 编码存储,不带字节顺序标记(BOM),并使用 LF(Unix 风格)行尾。我们还建议在提交消息中使用 UTF-8(同样,不带 BOM)。这些设置在跨平台和使用诸如
git
diff
和git
merge
等工具时效果最佳。此外,如果您可以在基于文本和非基于文本的存储格式之间进行选择,我们建议将文件存储为文本格式,并在必要时将其转换为其他格式。例如,每行一个记录的基于文本的 SQL 转储在差异比较和合并方面比实际的数据库文件效果好得多。类似地,Markdown 和 AsciiDoc 等基于文本的格式比 Microsoft Word 和 PDF 等二进制格式效果更好。
类似地,通常不建议在仓库中存储二进制依赖项(例如共享库或 JAR 文件)或构建产品。依赖项和构建产品最好存储在制品或包服务器上,仓库中只存储引用、URL 和哈希值。
我们还建议设置一个 gitattributes[5] 文件,以明确标记哪些文件是文本文件,哪些是二进制文件。如果您希望 Git 猜测,可以将属性
text=auto
设置为自动检测。对于文本文件,Git 通常会确保在仓库中使用 LF 行尾。
core.autocrlf
和core.eol
配置变量指定检出任何文本文件时遵循的行尾约定。您还可以使用eol
属性(例如eol=crlf
)来覆盖哪些文件获得何种行尾处理。例如,通常 shell 文件必须有 LF 行尾,批处理文件必须有 CRLF 行尾,因此在某些项目中以下设置可能适用:
# By default, guess. * text=auto # Mark all C files as text. *.c text # Ensure all shell files have LF endings and all batch files have CRLF # endings in the working tree and both have LF in the repo. *.sh text eol=lf *.bat text eol=crlf # Mark all JPEG files as binary. *.jpg binary
这些设置有助于工具为补丁等输出选择正确的格式,并使文件以适合平台的正确行尾检出。