作者 | Artur Ampilogov
译者 | 刘雅梦
策划 | 丁晓昀
Git 是一种在软件开发中用于版本控制的主流工具。使用多个 Git 帐户并不罕见。你可能有一个账户用于个人项目,另一个单独的账户用于工作。正确配置和切换 Git 帐户是一项挑战。在本文中,我们将展示 Git 为帐户配置提供了什么,它的限制是什么,以及基于项目父目录位置自动切换帐户的解决方案。
帐户配置
Git 中的帐户配置有两个相互独立的部分组成。
首先,你需要连接到远程存储库。有多种方法可以做到这一点,但是一个主流的远程 Git 提供程序 Github,不赞成使用用户名和密码进行 HTTPS 连接。现在,安全外壳协议(Secure Shell Protocol),简称 SSH,是 Git 中使用的标准连接协议。在本文中,我还将使用 SSH 进行远程 Git 操作。
其次,如果可用,帐户的电子邮箱和名称会被添加到每个历史更改单元中,在 Git 中标记为“提交”(commit)。这个提交者(committer)的帐户与 SSH 凭据没有任何共同之处,如果配置错误,它可能会导致在工作中使用被个人电子邮箱污染的 Git 历史记录。
在下面的部分中,我将详细介绍每个配置单元。
SSH 密钥连接
SSH 提供了多种连接到远程主机的方式。一种主流的方法是使用 SSH 密钥。主要的 Git 提供程序,包括 GitHub、GitLab 和 Bitbucket,都支持这种类型的连接。密钥应该安全地存储在你的计算机上,并能在使用 SSH 进行远程操作请求时引用到它。
SSH 密钥的 默认存储目录是 <USER_HOME_DIR>/.ssh/ ,对于基于 Unix 的系统,它是 ~/.ssh/ ,对于 Windows,它是 %userprofile%\.ssh\
首先,我们将使用 Ed25519 签名对系统进行签名生成一个名为“ id_ed25519_personal ”的个人密钥。在基于 Unix 的系统中,运行如下指令:
> ssh-keygen -t ed25519 -f "~/.ssh/id_ed25519_personal" -C "[email protected]"
在 Windows 中:
> ssh-keygen -t ed25519 -f "%userprofile%/.ssh/id_ed25519_personal"-C "[email protected]"
在命令执行过程中,ssh-keygen 将会询问你有关密钥文件的密码口令信息。使用密码口令可以保护你的私钥免受未经授权的复制和使用,即使在计算机受损的情况下也是如此。但是,秘密口令的不便之处在于每次建立 SSH 连接时都需要输入口令。可以将密码缓存在钥匙链中以减少密码口令的输入,你可以按照 MacOS 和 Windows 的指南自行设置。我在终端中输入了一个空值,这导致了一个未加密的文件。
-C ”标识添加了一个字符串注释,该注释在连接过程中不会使用。为了了解你计划使用哪个帐户的密钥,添加电子邮箱注释是一种 很好的实践。
执行 ssh-keygen 命令将生成两个密钥:带有“ .pub ”后缀的公钥“ id_ed25519_personal.pub ”和不带后缀的私钥“ id_ed25519_personal ”。
远程 Git 提供程序允许在其帐户设置中添加 SSH 公钥。请查看 GitHub 和 GitLab 的说明,并确保你在没有对提供程序进行注释的情况下添加了自己的公钥内容。
类似地,我为“组织 A”和“组织 B”生成了 SSH 密钥。这些更改导致产生了如下的一个文件结构:
<home-directory>└── .ssh ├── id_ed25519_personal ├── id_ed25519_personal.pub ├── id_ed25519_organization_a ├── id_ed25519_organization_a.pub ├── id_ed25519_organization_b ├── id_ed25519_organization_b.pub
我们将会在所有的代码示例中使用这种位置样式。
另一种方法是将键分组到目录中,如下面的模式所示。
<home-directory>└── .ssh ├── personal │ ├── id_ed25519 │ └── id_ed25519.pub ├── organization-a │ ├── id_ed25519 │ └── id_ed25519.pub └── organization-b ├── id_ed25519 └── id_ed25519.pub
Git 存储库和分支
Git 中的基本工作单元是一个名为存储库的目录。我们可以选择任何目录来存储文件,并通过运行以下命令来启用 Git:
>cd <your-project-directory>> git init
Git 将在当前的终端路径中创建一个名为“.git”的隐藏文件夹。我们的目录现在已经成为了存储库。Git 将跟踪对文件的所有更改,允许我们提交这些更改,并将文件快照存储在“.git”文件夹中。
分支是 Git 的一个重要概念。每个分支都保存了一个快照,其中包含了所有存储库文件的特定版本。我们可以通过在分支之间切换来改变文件,从而偏离开发流程。
从历史上看,Git 创建的第一个分支被称为“ master ”,但我们可以更改它,GitHub 建议使用“ main ”名称,可以通过执行下面的 rename 命令实现:
> git branch --move master main
执行如下命令可以查看所有的本地分支和活动分支:
> git branch
为了能够将更改上传到远程存储库,我们可以使用以下命令链接到远程 URL:
> git remote add origin https://<provider>/<path>/<repository>.git
origin ”值是一个常规名称。我们可以指定任何其他远程存储库别名,甚至可以将多个远程 URL 添加到一个存储库中,例如:
> git remote add remote-provider2 https://<provider2>/<path>/<repository>.git
要列出所有链接的远程存储库,可以运行以下命令:
> git remote -v
然后,可以从远程存储库中获取更改,并使用“ git pull<remote id><remote branch> ”命令将其合并到本地版本上。例如:
> git pull origin main
类似地,我们可以使用“ git push <remote-id> <remote-branch> ”命令将更改推送到远程存储库。
为了简洁起见,我们将跳过描述如何将更改提交到本地存储库,但你可以查看 Atlasian、GitHub 和 GitLab 的文章。
在每个存储库中,Git 都将配置存储在一个位于 .git/config 的特定文件中。
存储库配置设置包括默认分支名称和远程存储库链接。GitHub 版本会包含如下的内容:
[remote "origin"] url = [email protected]:<organization>/<repository>.git[branch "main"] remote = origin
Git 配置的层次结构
Git 的设置可以分布在多个位置,Git 会根据层次结构对其进行合并。
第一个配置级别称为本地配置(local),位于存储库内部,可以覆盖所有其他设置。本地配置位于 <repository path>/.git/config 处。
要查看存储库的 Git 设置,可以运行:
> git config --list --local
第二个配置级别称为全局配置(global),应用于当前系统用户的所有存储库,或者换句话说,应用于<user_HOME_DIR> 中的所有内容。全局配置是可选的,如果存在全局配置,则默认文件的位置在基于 Unix 的系统中是“ ~/.gitconfig ”,在 Windows 中是“ %userprofile%\.gitconfig ”。要查看全局配置设置,可以执行如下命令:
> git config --list --global
如果全局配置不存在,则该命令可能会导致错误。
第三个配置级别为系统级(system),适用于所有操作系统用户及其存储库。配置文件可选,在基于 Unix 的系统中位于“ /etc/gitconfig ”,在 Windows 系统中位于“ C:\ProgramData\Git\config ”或“ <git-installation-path>\etc\config ”。要检查 Git 的系统级配置,可以运行以下命令:
> git config --list --system
由于该文件是可选的,因此该命令也可能导致错误。
本地级别优先于所有其他级别,全局级别优先于系统级别。在本地级的下面还有一个级别叫做 worktree,但是它的用法超出了本文的讨论范围。
Git 会合并存储库的所有配置设置:添加唯一的记录,并根据级别的层次结构覆盖具有相同密钥的设置。
想要查看最终合并的配置结果,可以在存储库中运行不带级别参数的命令:
> git config --list
Git 帐户切换的挑战
对于每个提交的更改,Git 都会在指定的情况下将作者的姓名和电子邮箱添加到历史记录中。
想要为当前存储库配置提交者设置,可以运行:
> git config --local user.name "Your name"> git config --local user.email "[email protected]"
文件“ <repository>/.git/config ”将包括以下内容:
[user]name = Your nameemail = [email protected]
我们还可以通过执行以下命令,在全局级别上为所有存储库指定默认的提交者设置:
> git config --global user.name "Your default name"> git config --global user.email "[email protected]"
在系统级别指定用户设置不太实际,因为用户可能会有不同的姓名和电子邮箱。因此,在 Git 中,只有两个实用的提交者设置选项:针对所有存储库的全局级别和针对单个存储库的本地级别。
将存储库分组到它们的父文件夹(personal、organization-a 或 organization-b)下是很方便的,并且可以得到一个如下的目录结构:
<path-to-projects>└── personal ├── open-source-repository-1 └── open-source-repository-N└── organization-a ├── organization-a-repository-1 └── organization-a-repository-N└── organization-b ├── organization-b-repository-1 └── organization-b-repository-N
对于使用的开源存储库,我想使用个人电子邮箱作为 Git 提交者,对于组织 A 使用该公司的电子邮箱,组织 B 使用另一个公司电子邮箱。如前所述,对于这种情况,Git 要求在每个存储库的本地级别指定用户配置。全局级别在这里没有帮助,因为它是针对所有存储库的,应用范围太广了。因此,假设 Git 配置使用如下的结构:
<path-to-projects>└── personal│ ├── open-source-repository-1│ │ ├──.gitconfig│ └── open-source-repository-N│ └── .gitconfig├── organization-a│ ├── organization-a-repository-1│ │ ├──.gitconfig│ └── organization-a-repository-N│ └── .gitconfig└── organization-b ├── organization-b-repository-1 │ ├──.gitconfig └── organization-b-repository-N └── .gitconfig
想要将远程存储库下载到我们的计算机,可以使用“ git clone ”命令。例如,对于组织 A:
>cd <path-to-projects>/organization-a> git clone [email protected]:organization-a/<repository>.git
克隆时,请确保使用了 Git SSH URL。GitHub 有一个专门的选项卡:
执行的命令将自动将远程 URL 设置添加到本地 Git 配置级别,但是我们必须手动指定用户名和用户电子邮箱的设置。每次克隆存储库时都应该进行手动配置。
一个更好的解决方案是为每个存储库组文件夹配置一次用户设置。优化的解决方案应具有如下的文件结构:
<path-to-projects>└── personal ├──.gitconfig ├── open-source-repository-1 └── open-source-repository-N└── organization-a ├──.gitconfig ├── organization-a-repository-1 └── organization-a-repository-N└── organization-b ├──.gitconfig ├── organization-b-repository-1 └── organization-b-repository-N
解决方案
父目录配置
首先,为每个组文件夹添加一个空的“ .gitconfig ”文件,如前一节所示。然后,用相应的用户信息填充每个配置文件。例如,“ <path-to-projects>/organization-a/.gitconfig ”可能有如下的内容:
[user]name = Your nameemail = [email protected]
其次,Git 必须知道在执行远程命令时要使用哪个 SSH 密钥。有一个特殊的 Git 配置部分,名为 core.sshCommand 。在每个“ .gitconfig ”文件中添加 SSH 密钥的路径,类似于如下组织 A 的示例:
[user]name = Your nameemail = [email protected][core]sshCommand = ssh -i ~/.ssh/id_ed25519_organization_a
全局条件配置
最后一步是让 Git 从存储库的父文件夹中加载设置。
Git 在 2.13 版本中引入了 条件配置引用,并在 2.23 版本中修复了 相关的缺陷。因此,在应用以下方法之前,可以通过运行“ git -v ”命令确保你的 Git 版本不低于 2.23。
将条件配置添加到位于 <USER_HOME_DIR>/.gitconfig 的全局 Git 配置文件中,添加内容类似于如下的示例:
[includeIf "gitdir:~/<path-to-projects>/personal/**"] path = ~/<path-to-projects>/personal/.gitconfig[includeIf "gitdir:~/<path-to-projects>/organization-a/**"] path = ~/<path-to-projects>/organization-a/.gitconfig[includeIf "gitdir:~/<path-to-projects>/organization-b/**"] path = ~/<path-to-projects>/organization-b/.gitconfig
让我们详细回顾下第一个配置块。
[includeIf "gitdir:~/<path-to-projects>/personal/**"] path = ~/<path-to-projects>/personal/.gitconfig
includeIf ”部分表示,如果满足条件,则位于 ~/<path-to-projects>/personal/.gitconfig 的另一个 Git 配置文件应包含在当前配置文件中。条件“ gitdir:~/<path-to-projects>/personal/** ”意味着 Git 将检查当前存储库是否位于目录 <USER_HOME_DIR>/<path-to-projects>/personal/ 中的任何一层中。
重新启动终端会话后,Git 将根据组存储库目录的配置自动加载特定的设置。
测试 Git 设置
要检查已经加载的设置,可以在存储库中运行以下命令:
> git config -l
对于组织 A 的任何存储库,结果都应该包括以下几行:
user.name=Your nameuser.email=your_email@organization-a.comcore.sshcommand=ssh -i ~/.ssh/id_ed25519_organization_a
如果在父目录 <path-to-projects>/organization-a> 中运行“ git config -l ”,也应显示相同的行。
类似地,其他组文件夹(personal 和 organization-b)及其存储库也应该相应地显示特定的设置。
还可以检查 Git 配置的确切参数。例如,如果只想显示用户电子邮箱,可以运行:
> git config --get user.email
SSH 用户帐户允许的所有远程操作也应该在 Git 中正常工作,而不会出现任何错误。
测试将存储库下载到组文件夹中,例如,对于组织 A:
>cd <path-to-projects>/organization-a> git clone <remote-repository-ssh-path>
成功下载存储库后,测试更改从远程 URL 中检索:
>cd <path-to-projects>/organization-a/org-A-repository-1> git pull origin <branch-name>
使用你最喜欢的集成开发环境(IDE)来完成测试,无论是 Visual Studio Code、Eclipse、Vim,还是 JetBrains 产品系列。所有相关的 Git 功能在 IDE 中都可以正常工作。
替代解决方案的缺点
互联网上有许多流行的替代解决方案,但与现有的解决方案相比,它们都有缺点。
一种替代方案是安装 direnv 工具。它允许我们用 shell 切换目录后执行自定义的脚本。这种方法有两个缺点。首先,我们必须安装能钩挂到操作系统终端内部的工具。其次,该解决方案不适用于 IDE。我们只能在终端 shell 中手动运行 Git 命令。
另一种替代方案是在 ~/.ssh/config 文件中设置不同的 SSH 主机绑定别名。对于 GitHub,可以设置如下所示:
Hostgh-personalHostnamegithub.comPreferredAuthenticationspublickeyIdentityFile~/.ssh/id_ed25519_personalHostgh-organization-aHostnamegithub.comPreferredAuthenticationspublickeyIdentityFile~/.ssh/id_ed25519_ogranization_a
然后,每次克隆存储库时,都需要引用其中一个主机别名,而不是 github.com。例如:
> git clone git@gh-organization-a:organization-a/<repository>.git
该解决方案可以适用于 IDE。但该方案的缺点是,每次要下载新的存储库时,都必须记住别名并手动更新克隆 URL。
本文的解决方案没有这样的限制。一旦设置了组文件夹配置,Git 操作将对其中的任何新存储库都适用。
结    论
Git 不允许我们在一个地方为一组存储库配置帐户设置。但是,可以根据带有特定全局配置的目录路径自动加载 Git 凭据。该解决方案不需要安装外部库,并且能与 IDE 兼容。
作者介绍
Artur Ampilogov 在信息技术领域拥有超过 15 年的经验,其中包括 12 年的全栈编程和软件架构经验。他热衷于设计和编程,喜欢帮助人们,并希望看到信息技术改善生活。
原文链接:
https://www.infoq.com/articles/how-to-use-multiple-github-accounts/
声明:本文为 InfoQ 翻译,未经许可禁止转载。
今日好文推荐
继续阅读
阅读原文