
git和github相关记录
持续记录 git 和 github 使用过程中,之前没有注意过的点
初始化配置
初始化配置包括,下载 git、注册 github、配置 user 信息和代理,配置之后的信息会保存在.gitconfig 文件中。
配置命令:
git config --global user.name "your_name"
git config --global user.email "your_email"
git config --global http.proxy http://127.0.0.1:7890
git config --global https.proxy http://127.0.0.1:7890
127.0.0.1:7890 是 Clash 在本机开放的代理入口,不是 GitHub 的地址,也不是远程代理节点的地址。这个代理配置的意思是,告诉 Git 访问 HTTP/HTTPS 远程仓库时,把网络请求先交给本机 Clash。如果设置代理后关闭 Clash,Git 仍会尝试连接 127.0.0.1:7890,这时由于 Git 已经被固定配置为必须经过这个本地代理,往往直接失败。SSH 使用另一套网络程序和协议,和这个配置无关。
git 工作流示意
这张图是 Git 最经典的一张工作流示意图,它描述了代码从你修改到提交到远程仓库的整个生命周期,以及几个最常用命令分别作用在哪一步。
协作开发的一种工作流如下
# 首先将协作仓库 fork 一份到自己名下
git clone <my_repo_url> # 克隆自己名下的仓库到本地
git remote add upstream <cooperate_repo_url> # 添加协作的远程仓库
git fetch upstream # 获取协作仓库的最新修改
# 当前在 main 分支上维护,协作仓库更新后,需要同步到自己仓库
git fetch upstream
git switch main
git merge upstream/main
git push origin main
# 当前在 featire 分支上开发新功能,协作仓库更新后,需要同步到自己仓库
git fetch upstream
git switch feature
git rebase upstream/main
git push --force-with-lease origin feature
另外,建议 main 分支尽量保持和协作仓库一致,自己的提交都放在 feature 分支,这样同步最干净,提 PR 时冲突也少。
拓展阅读:团队开发中的 GitFlow 工作流
常用 git 命令
git initgit addgit commitgit remote addgit clonegit branchgit switchgit loggit refloggit statusgit diffgit blamegit restoregit resetgit revertgit fetchgit mergegit rebasegit cherry-pickgit stashgit pullgit pushgit worktreegit bisect
branch
分支本质上是对提交的一种会自动移动的标签。
git branch -v # 查看所有本地分支
git branch -r # 查看所有本地保存的远程跟踪分支
git branch -a # 查看所有本地和本地保存的远程跟踪分支
创建分支的命令如下,默认从 HEAD 创建
git branch <新分支名> # 只创建不切换
git switch -c <新分支名> # 创建并切换,现代 Git 推荐的方式
git checkout -c <新分支名> # 创建并切换,旧写法
git switch -c <新分支名> master # 从指定分支创建
git switch -c <新分支名> abc123 # 从指定提交创建
新分支默认只存在于本地,第一次推送时会在远程创建同名分支。
删除分支的命令如下
git push origin --delete feature # 删除远程分支
git branch -d feature # 删除本地分支
tag
tag 是 Git 中的固定标签,不会随着新提交而自动向前移动,通常用来给某个重要提交起一个容易记住的名字。
git tag v1.0.0 # 给当前提交创建标签
git tag v1.0.0 abc123 # 给指定提交创建标签
git tag -d v1.0.0 # 删除本地标签
创建标签后,默认只存在于本地,如果需要让远程仓库上也存在,同样需要推送。
git push origin v1.0.0 # 推送指定标签
git push origin --tags # 推送所有本地标签
git push origin --delete v1.0.0 # 删除远程标签
commit amend
git commit 可以加—amend 参数,表示用当前暂存区和新的提交信息,重新生成最近一次提交,替换原来的提交。用于已经 git commit 之后
git commit --amend # 打开编辑器修改提交信息
git commit --amend -m "正确的提交信息" # 直接指定新信息
git add test.py
git commit --amend --no-edit # 不修改提交信息,用于补充忘记提交的文件
另外,amend 只能修订当前 HEAD,修改更早的提交需要交互式 rebase。
checkout 和 switch
这俩的效果都是,让 HEAD 指向选定的分支或提交,并把暂存区和工作目录切换到该分支对应的版本。checkout 和 switch 操作都是在本地已有的分支和提交之间切换,是纯本地操作;clone、fetch、pull 等操作才涉及从远程获取内容。
对于一个已经存在的 master 分支:git checkout master 和 git switch master 的效果完全相同,都是让 HEAD 指向 master,并把暂存区和工作目录切换到该分支对应的版本。两者区别在于命令职责,git switch 是专用的分支切换命令,而 git checkout 除了切换分支外,还可以恢复文件,例如 git checkout -- file.txt 的效果是将 file.txt 恢复到暂存区的状态,git checkout abc123 -- file.txt 的效果是将 file.txt 恢复到 abc123 这次提交的状态。而现代 Git 专用的恢复文件命令是 git restore。另外,git checkout <提交哈希> 会直接进入 detached HEAD;而 git switch --detach <提交哈希> 需要明确写 —detach,降低误操作概率。
git log
git log 用于查看 Git 的提交历史,默认会从当前 HEAD 开始,沿着父提交向前查找,通常按从新到旧显示
完整提交哈希
作者姓名和邮箱
提交时间
提交信息
用 git log 命令可以查看当前本地和远程的各个分支分别处于哪个 commit 上,以及当前位于哪个分支,在哪个检出的版本上。注意 origin/master 只是最近一次 fetch/pull 后记录的远程状态,不一定代表服务器此刻的最新状态。常用简洁输出格式,每个提交显示一行:git log --oneline。另外,执行 git log 之后终端会进入 less 查看器,按 q 键可以退出。
git reflog
相较于只能看 commit 的 git log,git reflog 可以查看 HEAD 曾经去过哪里;这一功能可以用于修复 reset、rebase 等带来的 commit 遗失的情况。但 git reflog 本质上是记录本地引用的移动历史,不会记录远程仓库的历史,能恢复的也仅仅是本地仓库曾经 ref 过的 commit。
git status
git status 用于查看当前 Git 仓库处于什么状态,反映 HEAD(最近提交)、暂存区和工作目录之间的状态差异,并输出以下信息
当前在哪个分支,或者是否处于 detached HEAD
本地分支是否领先或落后 upstream
哪些修改已经暂存
哪些修改尚未暂存
哪些文件尚未被 Git 跟踪
是否存在合并冲突
是否正在执行 merge、rebase、cherry-pick 等操作
git diff
git diff 用于查看两个状态之间具体有哪些文件内容差异。
git diff # 默认查看暂存区与工作目录之间的差异,即已修改但还未暂存的部分
git diff --staged # 查看本地提交与暂存区的差异,即已暂存但还未提交的部分
git diff HEAD # 查看HEAD与工作目录之间的差异,即已修改未提交的所有改动
git diff -- file.txt # 查看某个文件的修改
git diff -- src/ # 查看某个目录的修改
git diff <提交1> <提交2> # 比较两个提交
git diff master feature # 比较两个分支
git blame
可以看某个提交中某一行是谁写的,具体的用法用到再查吧,希望不要有用到这个命令的时候。
git reset
git reset 的作用是:把当前分支、暂存区,必要时还有工作目录,重置到指定提交的状态。针对提交来说,作用是移动当前分支的位置;针对文件来说,作用是重置暂存区,常用于取消 git add。
针对提交的 reset 命令有三种模式,假设当前提交历史为
A <- B <- C master、HEAD
以 reset 上一次提交(HEAD~1 表示当前提交的上一个提交,也就是 B)为例
git reset --soft HEAD~1
git reset --mixed HEAD~1
git reset --hard HEAD~1
执行之后的提交历史都会变成
A <- B master、HEAD
三种模式的区别如下:
- —soft:暂存区保持不变,工作目录保持不变。即提交 C 不再属于 master 的当前历史,但 C 中的修改仍保留在暂存区,可以马上重新提交, 适合提交信息写错、提交内容需要重新组织等情况。不过如果只是修改最近一次提交信息,通常直接使用
git commit --amend更方便。 - —mixed(默认模式):暂存区重置到目标提交,工作目录保持不变。C 中的修改仍留在工作目录,修改不再位于暂存区,需要重新 git add。
- —hard:暂存区重置到目标提交,工作目录重置到目标提交。master 回到 B,暂存区恢复为 B,工作目录中的已跟踪文件恢复为 B,C 中的修改以及其他未提交的已跟踪文件修改都会被丢弃。
针对文件的 reset 命令为
git reset -- file.txt
这种写法不会移动分支,也不会修改工作目录文件,只会把 file.txt 从暂存区撤下来,相当于撤销了 git add file.txt 。不过现代 Git 推荐写成 git restore --staged file.txt,两者完全等价。
取消全部暂存可以执行
git reset
或
git reset --mixed HEAD
两者完全等价,即当前分支不移动,只把整个暂存区恢复到 HEAD,工作目录修改仍保留。
如果是尚未推送的本地提交或者纯个人开发,可以使用 git reset,否则如果是已推送到远程的提交,尤其是多人协作开发时,不要随便使用针对提交的 reset,这可能会破坏别人的提交历史,这种情况建议使用 git revert。
git revert
git revert 的作用是:通过创建一个新的提交,抵消某个旧提交引入的修改。它不会删除旧提交,也不会把分支指针向后移动,适合撤销已经推送到远程的提交。注意 revert 不是把仓库恢复到某个提交之前,而是反向应用某个提交引入的变化。
git revert HEAD # 抵消最近一次提交
git revert --no-commit HEAD # 只生成反向修改,不创建提交
git revert <commit_hash> # 抵消指定提交,通常会打开编辑器让用户确认新提交的信息
git revert --no-edit <commit_hash> # 抵消指定提交,跳过编辑器确认并使用默认信息
如果旧提交涉及的代码后来又被修改,则会产生冲突,建议手动解决。
git add <冲突文件>
git revert --continue
不想继续也可以取消整个 revert
git revert --abort
git fetch
git fetch 的作用是:从远程仓库下载本地还没有的提交、分支和相关对象,并更新本地的远程跟踪分支,但不修改当前本地分支和工作目录,即只有本地记录的 origin/master 被更新;本地 master、HEAD 和工作目录都不会改变。
git fetch # 获取当前默认远程仓库
git fetch origin # 获取指定的远程仓库
git fetch --all # 获取所有已配置的远程仓库
git merge
git merge 的作用是:把另一个分支的提交和修改整合到当前分支中,方向由当前分支决定。一个具体的例子:把 feature 合并进 master
git switch master
git merge feature
合并时存在以下几种情况:
-
fast-forward 合并:master 没有产生新提交,即 feature 分支的改动已经是基于 master 分支最新的提交进行的,即
A -> B master \ C -> D feature此时 Git 只需要把 master 向前移动即可,不会产生额外的合并提交。
A -> B -> C -> D ↑ master、feature使用
git merge --ff-only feature命令,表示只允许这种合并,如果两个分支已经分叉则命令会停止。 -
普通 merge 合并:如果 master 分支和 feature 分支都有自己的新提交,即
C master / A -> B \ D -> E feature合并后 Git 会创建一个合并提交 M,M 有两个父提交,master 分支的提交更新为 M,feature 分支的提交保持不变。
C --------\ / M master A -> B / \ / D -> E --/ ↑ feature -
squash 合并:把 feature 分支的所有修改压成一次普通提交,这会得到功能分支的最终修改,但不会创建具有两个父提交的真正 merge commit,也不会记录分支之的合并关系。
git switch master git merge --squash feature git commit -m "合并 feature 功能"
对于普通 merge,在 git add <已解决冲突的文件> 之后,也可以使用 git commit 命令完成合并提交,两者在普通 merge 时效果等价,唯一的区别在于 git merge --continue 会使用 Git 已准备好的默认合并提交信息;git commit -m "..." 可以指定合并提交信息。(所谓不普通的 merge,指的是 rebase 或 cherry-pick,这俩可能还有后续提交需要继续处理,不能简单用 git commit 代替整个继续流程)
如果要放弃本次 merge
git merge --abort
对于远程分支,git merge 本身不会连接远程服务器,应该先获取远程仓库的最新状态
git fetch origin
git switch master
git merge origin/master
git rebase
git rebase 的作用是:把当前分支上的一组提交,重新应用到另一个提交之后,即更换这些提交的基础。一个具体的例子,把 feature 分支 rebase 到 master 分支
git switch feature
git rebase master
假设分支历史是:
C master
/
A -> B
\
D -> E feature
Git 会找出 feature 独有的提交 D、E -> 将 feature 移动到 main 的 C -> 依次重新应用 D、E 的修改。rebase 之后结果如下,其中 D’、E’ 是新提交,即使内容相同,由于父提交发生了变化,因此提交哈希也会变化。
A -> B -> C -> D' -> E' feature
↑
master
如果要放弃本次 rebase
git rebase --abort
rebase 会逐个重新应用提交,和 merge 一样可能遇到冲突。
另外,rebase 会改写提交历史,不要 rebase 已经推送且其他人可能基于它继续开发的提交,否则其他人的历史会与新历史不一致。因此,rebase 更适合整理尚未共享的本地提交,而 merge 适合共享历史。
git cherry-pick
git cherry-pick 的作用是:选择某一个或几个已有提交,把这些提交引入的修改重新应用到当前分支,并生成新的提交,可以理解为“只挑需要的提交”。一个具体的例子如下
假设提交历史是:
C master
/
A -> B
\
D -> E feature
其中提交 E 修复了一个重要 bug。现在只想把 E 的修改带到 master,不想合并整个 feature。
git switch master
git cherry-pick <E的提交哈希>
执行结果:
C -> E' master
/
A -> B
\
D -> E feature
原提交 E 仍然在 feature,master 上产生了新提交 E’。cherry-pick 不是复制整个 E 的项目快照,而是计算 E 的父提交 -> E 之间的修改,然后把这些修改应用到当前 HEAD 上。
cherry-pick 也可以挑选多个提交,通常按照从旧到新的顺序排列
git cherry-pick abc123 def456 789abcd
git cherry-pick A..C # 挑选不包括 A 在内的从 A 到 C 的连续提交
git cherry-pick A^..C # 挑选包括 A 在内的从 A 到 C 的连续提交,A^ 表示 A 的父提交
只把修改放入暂存区和工作目录,但暂时不提交。可以继续挑选其它提交,最后统一提交
git cherry-pick --no-commit abc123
git cherry-pick -n abc123 # 简写
记录原提交来源,-x 会在新提交信息中增加类似内容:(cherry picked from commit abc123…)
git cherry-pick -x abc123
适合在不同发布分支之间移植修复,方便之后追踪来源。
发生冲突时需要手动解决冲突,然后继续 cherry-pick
git status
# 手动解决冲突
git add <已解决文件>
git cherry-pick --continue
如果要取消:
git cherry-pick --skip # 取消当前正在挑选的提交
git cherry-pick --abort # 取消整个cherry-pick
在一次 cherry-pick 了多个提交时,两种取消是有区别的。
git stash
git stash 的作用是:把尚未提交的修改临时收起来,让工作目录恢复到较干净的状态,之后再把修改取回来。假设当前状态是:HEAD 为已提交的版本 A,暂存区为已经 git add 的版本 B,工作目录为继续修改之后的版本 C。
git stash push # 默认不会保存未跟踪文件和被.gitignore忽略的文件
git stash push -u # 保存未跟踪文件,但不会保存被.gitignore忽略的文件
git stash push -a # 保存未跟踪文件和被.gitignore忽略的文件
Git 会将暂存区和工作目录中已跟踪文件的修改保存到储藏区(注意和暂存区区分开),然后将暂存区和工作目录都恢复到 HEAD 的版本 A 状态,当前分支和 HEAD 不会移动,也不会产生当前分支上的提交。
查看储藏区内容
git stash list # 查看储藏列表
git stash show -p stash@{0} # 查看某一次具体的储藏内容
应用和删除储藏区内容
git stash apply # 应用最新储藏,但保留储藏记录
git stash apply stash@{1} # 应用指定储藏
git stash pop # 将最新储藏的内容恢复到工作区,默认不恢复暂存区(所有恢复出来的文件都是未暂存状态),成功后删除储藏记录
git stash pop --index # 将最新储藏的内容恢复到工作区,并且恢复暂存区,成功后删除储藏记录
git stash drop stash@{0} # 删除指定储藏
如果 pop 发生冲突,Git 会保留该 stash,避免修改丢失。
git stash 常用于临时切换任务,假设本身在 feature 分支上,且存在未提交的更改
git stash push -u -m "某个功能开发到一半"
git switch master
# 处理其它事情
git switch feature
git stash pop
git pull
git pull 的作用是:从远程仓库获取最新提交,并把它们整合到当前所在的本地分支,相当于 git fetch + git merge。
假设本地当前位于 master 分支,基本用法是
git pull origin master
如果之前执行过 git pull -u origin master,即指定过 upstream(默认跟踪和比较的远程分支),后续可以直接执行 git pull 或 git push
如果当前位于 feature,执行
git pull origin master
这会把远程 master 整合进当前 feature,并不会自动切换到本地 master。
若要更新本地 master,应执行
git switch master
git pull origin master
git pull 能保留不冲突的本地修改,发生冲突时需要手动解决。
git push
git push 的作用是:把本地已经创建的提交传输到远程仓库,并尝试更新远程分支或标签。git push 只会推送已提交的内容,暂存区和储存区的修改不会被推送。基本用法是
git push origin master
这一命令实际上同时指定了远程分支和本地分支,git push 的完整语法为
git push <远程仓库名> <本地分支>:<远程分支>
git push origin master:master # 这是完整写法
当本地分支和远程分支同名时,Git 允许省略冒号和远程目标,表示把本地 master 推送到 origin 的同名 master 分支。当只写一个分支名时,表示省略冒号和远程目标,即指定本地分支。所以即使当前位于 feature,该命令仍然推送本地 master。如果远程没有对应的同名分支,Git 会创建它。
git push 在远程含有本地不存在的提交历史时会发生冲突,需要手动解决。正常处理方式是先获取并整合
git fetch origin
git rebase origin/master
git push
或者使用 merge
git fetch origin
git merge origin/master
git push
如果因为 amend 或 rebase 有意改写了自己独占分支的历史,可以使用:
git push --force-with-lease
这是一种带安全检查的强制推送,它会先检查远程分支是否仍处于本地预期的位置,通常在 rebase、amend 或 reset 改写提交历史后使用。
假设原来:
远程:A -> B -> C
本地:A -> B -> C
执行 amend 或 rebase 后,本地提交被重新生成:
远程:A -> B -> C
本地:A -> B' -> C'
因为本地历史不再包含远程的 C,普通推送会拒绝,此时可以执行:
git push --force-with-lease origin feature
Git 会先检查:远程 feature 是否仍然位于我上次看到的位置。如果远程没有被其他人更新,允许强制改成:
A -> B' -> C'
如果其他人已经推送了 D:
远程实际状态: A -> B -> C -> D
本地记录 origin/feature:A -> B' -> C'
Git 发现远程实际位置和你预期的不一致,就会拒绝推送,以避免覆盖别人的 D。
注意,git push --force-with-lease 只适合于自己独占的功能分支,禁止在多人共同使用的 master/main 上随意强推。
绝对禁止使用 git push --force 进行强行推送,尤其是在多人共同使用的 master/main 分支上,一般 master/main 的远程分支也会设置保护来禁止强制推送。
git worktree
git worktree 可以同时把同一个 Git 仓库检出(checkout)到多个目录,每个目录可以处于不同的分支。比如当前在 main 分支,要同时开发一个新功能(feature 分支),修一个线上 bug(hotfix),又不想丢掉当前 main 分支中开发中的代码。可以执行
# 需要已有feature和hotfix分支
git worktree add ../project-feature feature
git worktree add ../project-hotfix hotfix
两个命令会分别在当前目录的上一级新建 project-feature 目录(处在 feature 分支)和新建 project-hotfix 目录(处在 hotfix 分支)。
执行之后,几个目录共用一个.git,即 Git 的对象数据库(.git/objects)、提交历史等是共享的,因此通常只多占工作目录中文件的空间,而不会复制整个仓库历史。
查看所有 worktree
git worktree list
新建不存在的分支
git worktree add -b feature/login ../login main # 从 main 创建 feature/login 分支,放在../login目录
删除 worktree,注意目录也会一起删除(要求工作区干净,否则 Git 会阻止删除)
git worktree remove ../login
另外,一个分支只能被一个 worktree 检出,Git 不允许同一个分支同时被多个 worktree 检出,以避免对同一分支在不同目录中进行互相不知情的修改。
git bisect
用于二分法查找 bug,找到第一个坏 commit。Git 负责按二分法进行 commit 跳转,由人进行测试并将结果告诉 Git。
git bisect start
git bisect bad
git bisect good 1
合并与冲突处理
开始合并前最好先检查工作区是否干净,如果有会导致冲突的未提交修改,Git 就会拒绝合并,稳妥做法是先提交或暂存
git stash push -u
git merge feature
git stash pop
Git 合并文件的方式是,找出两个分支的共同祖先,然后比较“共同祖先 -> 当前分支的修改”和“共同祖先 -> 被合并分支的修改”。如果修改位于不同文件或不同位置,Git 会自动合并;如果双方修改了同一部分内容,则会出现冲突。冲突文件中会出现如下标记:
<<<<<<< HEAD
当前分支的内容
=======
传入分支的内容
>>>>>>> feature
在编辑器中还会提示选择保留”当前的更改“或“传入的更改”,两者具体所指的分支取决于当前所在的分支。
- 当前的更改(Current Change):当前检出的分支,也就是 HEAD 所在分支的内容
- 传入的更改(Incoming Change):正在合并进来的那个分支的内容
例如
git switch master
git merge feature
那么当前的更改指 HEAD 所在的 master 分支的更改,传入的更改指 merge 进来的 feature 分支的更改。
冲突的处理流程如下:
git status
# 手动修改冲突文件,删除冲突标记
git add <已解决冲突的文件>
git merge --continue
游离头问题
HEAD 可以理解为 Git 的“当前位置指针”,用于指示现在检出的版本在哪里,以及指示新的提交应该添加到哪里。正常情况下创建新提交:提交前:HEAD -> master -> A,提交后:HEAD -> master -> B -> A(Git 提交的箭头是从新提交指向旧提交)。
detached HEAD 即“分离头指针”,表示 HEAD 没有指向某个本地分支,而是直接指向某次提交,这在查看旧版本、运行测试时很常见。detached HEAD 的风险在于,如果在 detached HEAD 状态下创建提交,新提交不属于任何分支;切换走后,再想找到会比较麻烦。因此如果已经在 detached HEAD 状态下做了有用的提交,应先创建分支保存它:
git switch -c my-new-branch
这行命令的意思是:以当前提交为起点,创建名为 my-new-branch 的本地分支,并立即切换到该分支。
远程仓库名
执行 git clone 时,Git 通常自动把源仓库命名为 origin。远程仓库名只是当前本地仓库里的别名,不会改变服务器上的仓库名称。同一个本地仓库中的远程名称不能重复。除非有多个远程仓库,否则沿用 origin 最省事,因为部分脚本和文档默认使用这个名字。
一个本地 Git 仓库可以配置多个远程仓库,origin 只是克隆时默认创建的第一个远程名称,并不是唯一允许的名字。使用命令 git remote -v 可以查看本地仓库配置的所有远程仓库。
master 和 origin/master
origin 是远程仓库地址的本地别名,本地 master 是实际开发和提交的本地分支,本地 origin/master 是本地保存的远程 master 状态记录,远程 master 是 GitHub 服务器上真正的 master。origin/master 通常被称为“远程分支”,但更准确地说,它是保存在本地的远程跟踪分支,记录你上次与远程通信时,远程 master 所在的位置,不是服务器上的实时分支。
HTTPS 和 SSH
这俩是访问远程仓库时的两种网络通讯协议,不影响 Git 功能,区别只是连接及认证方式。 个人长期使用通常可以选择 SSH;临时环境、服务器受限网络或希望少配置时,HTTPS 更方便。已有仓库也可以用命令 git remote set-url origin <your_address> 随时切换,仓库的连接方式(HTTPS 或 SSH)保存在每个本地仓库的远程地址配置中。
| 对比项 | HTTPS | SSH |
|---|---|---|
| 地址格式 | https://github.com/user/repo.git | git@github.com: user/repo.git |
| 加密方式 | HTTPS/TLS 加密 | SSH 加密 |
| 克隆公开仓库 | 通常无需登录 | 本机需配置 SSH key |
| 访问私有仓库 | Token、凭据管理器或网页登录授权 | SSH key |
| 日常推送 | 需要凭据管理器保存认证 | 配好 key 后无需重复认证 |
执行 git push 命令时,大致会经过:根据远程地址选择 SSH 或 HTTPS→ 自动取得 SSH 私钥或 HTTPS Token→ 远程平台根据凭据识别账户 → 检查该账户是否有仓库写权限 → 有权限的情况下完成项远程仓库的推送。
HTTPS 在第一次推送的网页登录完成后,通常会由 Git Credential Manager、系统钥匙串或其它凭据助手保存 Token。SSH 需要在本机生成 SSH 密钥对,私钥留在本机,公钥添加到 GitHub、GitLab 或公司的 Git 服务器。SSH key 的管理,通常是一台机器一个,添加到 GitHub/GitLab 账户后,本台机器即可访问这个账户有权限的所有仓库。
一台机器可以有多个账户以及多个 key,因此在访问远程仓库遇到权限问题时,需要确认远程仓库识别到了本地的哪个账户;HTTPS 的凭据同理,也需要确认凭据管理器当前缓存的是哪一个账户。仓库“有权限”只代表某个远程账户有权限;推送时远程服务器还要确认:你当前到底以哪个账户、哪把 SSH key 或哪份 HTTPS 凭据登录。
SSH 认证主要有两个方向,SSH 私钥用于向服务器证明“我是谁”,known_hosts 保存的是本机曾经连接过的 SSH 服务器的身份信息,用来确认“对面的服务器是谁”,里面会写入 Github 的主机公钥。以后再次连接时,SSH 会对比服务器发来的公钥是否与 known_hosts 中保存的一致,不一致时会发出安全警告,这是为了防止中间人攻击,比如有人伪装成 GitHub 截获你的连接。
评论
评论正在加载…