设置和配置
获取和创建项目
基本快照
分支和合并
共享和更新项目
检查和比较
补丁
调试
邮件
外部系统
服务器管理
指南
管理
底层命令
- 2.46.1 → 2.47.0 无更改
- 2.46.0 07/29/24
- 2.34.1 → 2.45.2 无更改
- 2.34.0 11/15/21
- 2.29.1 → 2.33.8 无更改
- 2.29.0 10/19/20
- 2.27.1 → 2.28.1 无更改
- 2.27.0 06/01/20
描述
本常见问题解答中的示例假设使用标准 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 中放置密码(必须进行百分比编码),但这并不安全,并且可能导致意外泄露凭据,因此不建议这样做。
- 如何更改我保存在凭据管理器中的密码或令牌?
-
通常,如果密码或令牌无效,Git 将将其删除并提示输入新的密码或令牌。但是,有时并非总是如此。要更改密码或令牌,你可以删除现有凭据,然后 Git 将提示输入新的凭据。要删除凭据,请使用类似以下的语法(替换你的用户名和主机名):
$ echo url=https://[email protected] | git credential reject
- 如何使用 HTTP 使用同一托管提供商的多个帐户?
-
通常,区分这些帐户的最简单方法是在 URL 中使用用户名。例如,如果你在
git.example.org
上拥有帐户author
和committer
,则可以使用 URL https://[email protected]/org1/project1.git 和 https://[email protected]/org2/project2.git。这样,当你使用凭据助手时,它会自动尝试查找你的帐户的正确凭据。如果你已经设置了远程仓库,则可以使用git remote set-url origin https://[email protected]/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
帐户(例如,[email protected]
)。如果你的提供商也是如此,则可以在 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
代替[email protected]
(例如,git remote set-url git@example_author:org1/project1.git
)。
传输
- 如何跨系统同步工作区?
-
首先,决定是否需要这样做。Git 在你使用典型的
git push
和git fetch
命令推送或拉取工作时效果最佳,并且并非设计用于跨系统共享工作区。这可能存在风险,并且在某些情况下会导致存储库损坏或数据丢失。通常,这样做会导致
git status
需要重新读取工作树中的每个文件。此外,Git 的安全模型不允许在不受信任的用户之间共享工作树,因此,只有在工作树仅由单个用户跨所有机器使用时,同步工作树才安全。重要的是,不要使用云同步服务来同步 Git 存储库的任何部分,因为这会导致损坏,例如丢失对象、更改或添加文件、损坏的引用以及各种其他问题。这些服务倾向于持续地逐个文件同步,并且不理解 Git 存储库的结构。如果它们在存储库更新过程中同步存储库,则尤其糟糕,因为这很可能导致不完整或部分更新,从而导致数据丢失。
可能发生的损坏类型的一个示例是关于引用状态的冲突,例如,双方最终在对方没有的某个分支上拥有不同的提交。这可能导致重要的对象变得无引用,并可能被
git gc
修剪,从而导致数据丢失。因此,最好使用正常的推送和拉取机制将您的工作推送到另一个系统或中央服务器。但是,这并不总是保留重要的数据,例如暂存区,因此有些人更喜欢在系统之间共享工作树。
如果您这样做,建议的方法是使用
rsync -a --delete-after
(理想情况下使用加密连接,例如使用ssh
)在存储库的根目录上。执行此操作时,您应确保以下几点-
如果您有其他工作树或单独的 Git 目录,则必须与主工作树和存储库同时同步它们。
-
您对目标目录成为源目录的精确副本感到满意,*删除其中已有的任何数据*。
-
存储库(包括所有工作树和 Git 目录)在传输期间处于静止状态(即,在其上没有进行任何类型的操作,包括后台操作,例如
git gc
以及由您的编辑器调用的操作)。请注意,即使按照这些建议,以这种方式同步也存在一些风险,因为它绕过了 Git 对存储库的正常完整性检查,因此建议进行备份。您可能还希望在同步后执行
git fsck
以验证目标系统上数据的完整性。
-
常见问题
- 我要求 Git 忽略各种文件,但它们仍然被跟踪
-
gitignore
文件确保 Git 未跟踪的某些文件保持未跟踪状态。但是,有时某些文件可能在添加到.gitignore
之前已被跟踪,因此它们仍然被跟踪。要取消跟踪和忽略文件/模式,请使用git rm --cached <file/pattern>
并将与<file>匹配的模式添加到.gitignore
中。有关详细信息,请参阅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,但当这种情况发生时,服务器可能尚未处理最终请求,因此在此时断开连接会中断该请求。使用 HTTP 代理的
~/.ssh/config
中的示例配置条目可能如下所示Host git.example.org User git ProxyCommand socat -t 10 - PROXY:proxy.example.org:%h:%p,proxyport=8080
请注意,在所有情况下,为了使 Git 正确工作,代理必须完全透明。代理不能以任何方式修改、篡改或缓冲连接,否则 Git 几乎肯定无法工作。请注意,许多代理(包括许多 TLS 中间盒、Windows 防病毒和防火墙程序(Windows Defender 和 Windows 防火墙除外)以及过滤代理)无法满足此标准,因此最终会导致 Git 出现故障。由于有许多问题报告以及它们糟糕的安全历史,我们建议不要使用这些类型的软件和设备。
合并和重新设置基准
- 使用 squash 合并多次合并长期存在的分支时可能出现哪些问题?
-
通常,使用 squash 合并多次合并两个分支时可能会出现各种问题。这些问题可能包括在
git log
输出、GUI 或使用...
表示法表示范围时看到额外的提交,以及可能需要反复重新解决冲突。当 Git 在两个分支之间执行普通合并时,它会考虑三个点:这两个分支和一个第三个提交(称为*合并基准*),该提交通常是提交的共同祖先。合并的结果是合并基准与每个头部之间更改的总和。当您使用常规合并提交合并两个分支时,这会导致一个新的提交,该提交最终会在再次合并时成为合并基准,因为现在有一个新的共同祖先。Git 不必考虑合并基准之前发生的更改,因此您不必重新解决之前解决的任何冲突。
当您执行 squash 合并时,不会创建合并提交;相反,来自一侧的更改将作为常规提交应用到另一侧。这意味着这些分支的合并基准不会改变,因此当 Git 去执行下一个合并时,它会考虑上次考虑的所有更改加上新的更改。这意味着任何冲突可能都需要重新解决。类似地,在
git diff
、git log
或 GUI 中使用...
表示法的任何内容都将导致显示自原始合并基准以来的所有更改。因此,如果您想重复合并两个长期存在的分支,最好始终使用常规合并提交。
- 如果我在两个分支上进行了更改,但在其中一个分支上 revert 了它,为什么合并这些分支会包含该更改?
-
默认情况下,当 Git 执行合并时,它使用名为
ort
策略的策略,该策略执行一个高级的三向合并。在这种情况下,当 Git 执行合并时,它会考虑三个点:两个头部和一个第三个点(称为*合并基准*),该点通常是这些提交的共同祖先。Git 根本不会考虑这些分支上发生的提交的历史记录或单个提交。因此,如果双方都有更改,而其中一方 revert 了该更改,则结果是包含该更改。这是因为代码在一侧发生了更改,而另一侧没有净更改,在这种情况下,Git 会采用该更改。
如果这对您来说是一个问题,您可以改用 rebase,将带有 revert 的分支重新设置基准到另一个分支。在这种情况下,rebase 会 revert 该更改,因为 rebase 会应用每个单独的提交,包括 revert。请注意,rebase 会重写历史记录,因此您应避免重新设置已发布分支的基准,除非您确定您对这样做感到满意。有关更多详细信息,请参阅git-rebase[1]中的 NOTES 部分。
钩子
- 如何使用钩子来阻止用户进行某些更改?
-
进行这些更改的唯一安全位置是在远程存储库(即 Git 服务器)上,通常在
pre-receive
钩子或持续集成 (CI) 系统中。这些是在其中可以有效执行策略的位置。通常会尝试使用
pre-commit
钩子(或对于提交消息,使用commit-msg
钩子)来检查这些内容,如果您是单独的开发人员并且希望工具帮助您,这很好。但是,在开发人员机器上使用钩子作为策略控制是无效的,因为用户可以使用--no-verify
绕过这些钩子而不会被发现(以及其他各种方法)。Git 假设用户控制着他们的本地存储库,并且不会尝试阻止或告发用户。此外,一些高级用户发现
pre-commit
钩子会妨碍使用临时提交来暂存正在进行的工作或创建修复提交的工作流程,因此最好将这些类型的检查推送到服务器。
跨平台问题
- 我在 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) 系统的一部分来检查此类约定。如果您的系统上使用了涂抹或清理过滤器,但先前提交的文件未运行涂抹或清理过滤器,则在任何平台上也可能发生永久修改的文件。要解决此问题,请在干净的工作树上运行以下命令
$ git add --renormalize .
- 在 Git 中存储文件的推荐方法是什么?
-
虽然 Git 可以存储和处理任何类型的任何文件,但有些设置比其他设置效果更好。通常,我们建议将文本文件存储为不带字节顺序标记 (BOM) 且使用 LF(Unix 样式)结尾的 UTF-8。我们还建议在提交消息中使用 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
这些设置可帮助工具为补丁等输出选择正确的格式,并使文件以平台的适当换行符检出。
GIT
git[1]套件的一部分