Git 工具:隐私、工作流和 Troubleshooting
权限模型¶
本地的 git 程序并不关注使用的「远程账号」,而只关心当前仓库的 user.name 和 user.email 配置,这两项配置决定了 git commit 记录的作者信息,GitHub 使用邮箱来归属统计贡献;远程账号只在与远程仓库进行 push pull clone 等交互时用于鉴权,使用 HTTPS 或者 SSH 凭据。
因此,对于「工作仓库用工作账号 commit,个人仓库用个人账号 commit」的需求,只需要做仓库级别的配置即可。
但是,对于 push 操作,GitHub 会记录执行 push 的账号,在 GitHub 的审计日志、活动记录、PR 关联等可见。clone 和 pull 在某些情况下也会在审计日志中留下痕迹。
GitHub 提供三种鉴权方式:
- HTTPS:这种方式要求提供 GitHub 账号名和在 GitHub 中生成的 token。在陌生设备上临时执行
clone等操作时较为便利,但由于 token 存在有效期限制,并且生成和保管都比较麻烦,不建议长期使用这种方式。 - SSH:使用本地操作系统配置的 SSH 私钥,与 GitHub 上配置的 SSH 公钥配对进行鉴权。
- GitHub CLI:为 Git 配置和接管 HTTPS 凭据的工具。通过 OAuth 授权获得 token 后自动交由 Git 的 HTTPS 凭据系统,相当于自动化 1 的过程。
这三种方式都可以实现「手动控制仓库使用哪一个身份进行鉴权」。
- HTTPS:对每个仓库手动操作,在
clonepushpull的时候都会询问账号名和 token。 - SSH:在本地生成两对 SSH 密钥,并为它们分别设置 SSH Host 别名。在 GitHub > Settings > SSH and GPG keys > Add new SSH Key 中添加刚刚生成的密钥对中,以
.pub结尾的公钥的文件内容。在 clone 的时候修改链接中的git@github.com:...为git@别名:...(使得上游仓库链接变成git@别名:...,对于存在的仓库可以用git remote set-url origin ...修改)。如果不假修改而直接使用# 生成两对密钥 ssh-keygen -t ed25519 -C "注释" -f ~/.ssh/id_ed25519_github_work ssh-keygen -t ed25519 -C "注释" -f ~/.ssh/id_ed25519_github_personal # 在 ~/.ssh/config 中配置别名 Host github-work HostName github.com User git IdentityFile ~/.ssh/id_ed25519_github_work Host github-personal HostName github.com User git IdentityFile ~/.ssh/id_ed25519_github_personal # clone git clone git@github-work:... # 工作仓库 git clone git@github-personal:... # 个人仓库git@github.com:...链接,会导致 SSH 尝试匹配密钥对,产生错误认证。 - GitHub CLI:通过
brew install gh安装(或其他包管理器,在其他操作系统上);使用gh auth login登录,登录时选择在 HTTPS 协议;使用gh auth status查看当前登录状态;使用gh auth switch切换账号。clonepushpull的时候会自动使用 GitHub CLI 的凭据。$ gh auth status github.com ✓ Logged in to github.com account work_account (keyring) - Active account: true - Git operations protocol: https - Token: gho_************************************ - Token scopes: 'gist', 'read:org', 'repo', 'workflow' ✓ Logged in to github.com account personal_account (keyring) - Active account: false - Git operations protocol: https - Token: gho_************************************ - Token scopes: 'gist', 'read:org', 'repo', 'workflow'
基础操作¶
从远程仓库克隆代码 git clone <url>;查看所有远程分支 git branch -a 创建本地分支以跟踪同名的远程分支 git checkout --track origin/<branch_name>。
创建新的分支 git branch <branch_name>。
切换到分支 git checkout <branch_name>。
创建新的分支并切换到此分支 git checkout -b <branch_name>。
查看上游仓库(远程地址) git remote -v。
修改上游仓库(远程地址) git remote set-url origin <url>。
将本地的分支 a 推送到远程的分支 b git push origin a:b。
重命名当前分支 git branch -m <new_name>。
将未提交的改动推入暂存栈 git stash;为此添加说明 git stash push -m "message"。
从暂存栈中取回改动 git stash pop。
将修改加入暂存区 git add <file>。
提交暂存区中的修改 git commit;只添加简短说明时 git commit -m "message"。
推送到远程仓库:git push。
拉取远程仓库的更改并合并到当前分支:git pull。
工作流:
git clone->git add->git commit->git pull-> 处理冲突 ->git commit提交冲突处理,如果不能自动处理冲突的话 ->git push。这个方法的好处是可以存档一份本地跑通的修改,在合并出错时可以回档。或者:
git clone->git stash->git pull->git stash pop-> 处理冲突 ->git add->git commit->git push。这个方法的好处是当远程和本地都对某个文件做了修改,不会产生的合并提交。
Troubleshooting¶
设置代理¶
使用下面的命令设置 git 的 http 代理,去掉 --global 参数只对当前仓库生效(下同)。
也可以指定只对某些地址使用代理(例如https://github.com)。
git 的代理配置不存在 https.proxy 选项,因此不必设置,文档:https://git-scm.com/docs/git-config#Documentation/git-config.txt-httpproxy。
如果 git 的代理设置并没有按预期运行,可以用 git config --list 查看是否有冲突的配置,使用 git config --unset xxx 取消冲突配置。
可以使用下面的命令查询某一项配置:
也支持使用正则表达式进行配置查询:
手动指定仓库域名的 DNS 解析¶
碰到以下问题:
$ git push
fatal: unable to access 'https://git.xxx.edu.cn/yyy/zzz.git/': Could not resolve host: git.xxx.edu.cn
假设没有管理员权限,并且已知域名 git.xxx.edu.cn 的 IP 地址为 10.1.2.3,使用 git 配置的 insteadOf 选项添加 URL 重写规则,使得每当 git 尝试访问 git.xxx.edu.cn 时,它会自动替换为 IP 地址。
git config --local url."http://10.1.2.3/".insteadOf "http://git.xxx.edu.cn/"
git config --local url."https://10.1.2.3/".insteadOf "https://git.xxx.edu.cn/"
git config --local url."ssh://git@10.1.2.3/".insteadOf "ssh://git@git.xxx.edu.cn/"
如果遇到 SSL 证书验证错误,可能是因为服务器的 SSL 证书是颁发给域名的而不是颁发给IP地址的。解决方案是为特定域名添加例外(需要确保该服务器是安全的):
重命名或删除被跟踪的文件¶
当需要重命名或删除被跟踪的文件时,使用 git mv 或 git rm,而不是直接使用 mv 或 rm。
递归地移动或删除(以移动为例)一个目录下的所有文件:git mv old_dir/* new_dir/。
只提交部分修改¶
使用 git add 将想要提交更改的文件添加到暂存区,然后再用 git commit 提交即可。在 vscode 中,可以通过直接点击文件后面的「暂存更改」按钮来将文件的修改添加到暂存区。这两个方式是等价的。
如果只想提交某个文件的部分修改,可以使用 git add -p,可以在随后唤起的交互模式中选择要添加到暂存区的修改。
修改 commit 记录的描述¶
使用 git commit --amend 即可修改上一次 commit 记录的描述。
如果需要修改倒数第 n 个 commit 记录的描述,则需要通过 git rebase -i 先变基到 HEAD~(n+1),然后在打开的文本编辑器内找到你想要修改的 commit,将行首的 pick 改为 reword,这将再次打开一个文本编辑器对选定的 commit 描述进行修改。最后,通过 git rebase --continue 回到 HEAD,这可能会造成远程仓库的历史记录与本地不一致。