%% # 纲要 > 主干纲要、Hint/线索/路标 # Q&A #### 已明确 #### 待明确 > 当下仍存有的疑惑 **❓<font color="#c0504d"> 有什么问题?</font>** # Buffer ## 闪念 > sudden idea ## 候选资料 > Read it later %% # 远程仓库与本地仓库的关系 - **本地仓库可以==关联多个远程仓库==**,从而能够**从不同远程仓库拉取更新**,或是**将本地更新推送到不同远程仓库** - "**远程跟踪分支**" 是**对本地已知的"远程分支最新一次提交" 的==只读引用==**,**标识==本地已知的该远程分支最新指向的 commit==** - 当远程库的分支推进时,本地的 "**远程跟踪分支**" 引用仍然保留着上一次拉取时的指向,直到下一次通过 `git fetch` 拉取远程分支更新时,"**远程跟踪分支**" 才会同步指向 "**远程库中分支的最新一次提交**"。 - 通常会**为本地分支设置其==所关联的远程分支==,称之为"upstream"**,如**本地 `master` 分支关联于远程分支 `origin/master`**。 - 关联后,执行 `git push` 时会**将本地分支的更新推送到==关联的远程分支==**; - 关联后,执行 `git fetch` 时将**拉取==关联的远程分支的更新==**,更新本地所见的 "**远程跟踪分支**"的指向。 - 关联后,执行 `git pull` 时会**拉取==关联的远程分支的更新==并合并到本地当前分支**。 <br><br> # 远程仓库管理 ⭐——git remote | 相关命令 | | -------------------- | | `git remote` | | `git remote add` | | `git remote remove` | | `git remote rename` | | `git remote set-url` | ### 添加&删除关联的远程库 - `git remote add [OPTION] <name> <url>`: 为本地仓库**添加关联==远程仓库==** - `<name>`:指定远程仓库名(自定义),通常使用 `origin` 作为主远程库名称 - `<url>`:远程仓库地址 - `git remote rm <remote-name>`:删除关联的远程库 示例: ```shell git remote add origin [email protected]:DHDouglas/news-sys.git git remote add origin https://github.com/DHDouglas/news-sys.git ``` ### 查看已关联的远程库 - `git remote [-v]`:查看**远程库名称** - `-v`:显示**远程库的 url** ![[_attachment/05-工具/git 使用/git 远程仓库&远程分支管理.assets/IMG-git 远程仓库&远程分支管理-0244AF53E5D429D2C47E2D42C1DB757D.png|309]] - `git remote show <remote-name>` :查看**远程库的详细信息** - 详细信息:**Fetch/Push URL**,**远程 HEAD 所指分支**,**==git push 和 git pull 配置==** <br>![[_attachment/05-工具/git 使用/git 远程仓库&远程分支管理.assets/IMG-git 远程仓库&远程分支管理-756B511616A5B758DFEFB2ACDBF65E2C.png|363]] ### 修改已关联远程库的信息 - `git remote rename <oldname> <newname>`: **重命名**远程库名称 - `git remote set-url <remotename> <new-url>`: **修改**远程库的 **URL** > [!example] 示例:修改本地仓库关联的远程仓库的 url > > ```shell > git remote -v > # View existing remotes > # origin https://github.com/user/repo.git (fetch) > # origin https://github.com/user/repo.git (push) > > git remote set-url origin https://github.com/user/repo2.git > # Change the 'origin' remote's URL > > git remote -v > # Verify new remote URL > # origin https://github.com/user/repo2.git (fetch) > # origin https://github.com/user/repo2.git (push) > ``` > > ^gl1lub ### 添加&删除多个推送/拉取 URL ```shell # 添加推送URL git remote set-url --add --push origin https://github.com/user/repository.git git remote set-url --add --push origin https://gitlab.com/user/repository.git # 删除推送URL git remote set-url --delete --push origin https://gitlab.com/user/repository.git ``` > [!tip] 常用于一个项目==同时关联有多个远程库==如 github、gitee、gitlab,需要**同时推送**的情况 <br><br><br> # 远程分支管理 ⭐ ![[_attachment/05-工具/git 使用/git 远程仓库&远程分支管理.assets/IMG-git 远程仓库&远程分支管理-56A24FC5C6DB53357F7AD987881E9D4A.png|565]] 相关命令:git push、git fetch、git pull。 使用说明参见[^1]。 ## 设置&查看本地分支"跟踪"的远程分支 为**既有本地分支**设置其**所关联/跟踪的远程分支**,两种方式: - (1)通过 `git branch -u <upstream> [<branchname>]` 为**当前分支(或指定分支) 关联远程分支** - (2)通过 `git push -u <remote> <remote-branch>` **在首次推送时设置关联** ![[05-工具/git 使用/git 分支管理#^pcnp23]] ![[05-工具/git 使用/git 分支管理#查看本地分支 "跟踪" 的远程分支|git 分支管理]] ![[05-工具/git 使用/git 分支管理#取消本地分支 "跟踪" 远程分支|git 分支管理]] <br> ## 将远程跟踪分支检出为本地分支 等效命令: - `git checkout -b <branch> <remote/branch>`:创建名为 `<branch>` 的分支,其关联/跟踪于**远程分支`<remote/branch>`** - `git checkout --track <remote/branch>`:创建**与远程分支同名的==本地分支==**,其关联/跟踪于**远程分支`<remote/branch>`**。 > [!NOTE] > > 假设本地仓库存在一个**远程跟踪分支** `origin/ba`,**但没有任何本地分支"基于"该分支时**, > 可以**检出该远程跟踪分支**,得到一个**本地分支 `ba` 关联于该 `origin/ba`**, > 此后可以**对本地分支 `ba` 进行修改,并==推送==给所关联的远程分支 `origin/ba`**。 > > [!NOTE] 如果直接 git checkout 切换到一个不存在的分支,而**恰好有个名称相匹配的远程分支**时,则会**自动创建该跟踪分支**。 > > ![[_attachment/05-工具/git 使用/git 远程仓库&远程分支管理.assets/IMG-git 远程仓库&远程分支管理-9A380FF413FC1B7366E7514490763681.png]] > <br> ## 推送更新到远程分支——git push 将**本地仓库==当前分支==的变更**推送到**远程仓库==关联分支==或==指定分支==**: - `git push [OPTIONS] [<remote> [<refspec> ...]]` - `-u | --set-upstream`: 将**本地分支与指定的远程分支==关联==** 并 **推送变更**(此后可以只用 git push 推送) - `-f | --force`: **==强制推送==**,覆盖远程仓库中的提交 - `<remote>`:远程仓库名 - `<refspec>`:**远程仓库的指定分支** - 可为 `本地分支名:远程分支名` 形式,表示推送 "**==本地库指定分支==** 到 **==远程库指定分支==**" - `--all <remote>`:推送**所有本地分支到远程仓库** - `--tags <remote>`:推送**本地所有 tag 到远程仓库** - `-d | --delete <branch | tag>`:删除**远程仓库**中的**指定分支或标签** - `-n | --dry-run`:仅**模拟推送过程**,不实际推送任何数据 > [!NOTE] 若**当前本地分支已经与远程分支关联**,则直接执行 `git push` 即可推送到关联的远程分支 ```shell git remote add origin [email protected]:DHDouglas/git_test.git # 添加远程库 git branch -M main # 强制更改当前分支名为main git push -u origin main # 首次推送当前分支到远程库的main分支, 为当前分支指定关联于远程分支main .... git push # 当前分支已有关联的远程分支, 直接推送到关联分支. # 推送本地分支main到远程分支remote_branch(该远程分支不存在时自动创建) git push origin main:remote_branch # 推送本地仓库中的所有分支到远程仓库 git push --all origin # 删除远程仓库中的指定分支或标签 git push origin --delete feature-branch # 删除分支 git push origin --delete v1.0.0 # 删除标签 ``` > [!example] 删除远程库中的指定分支 > > ![[_attachment/05-工具/git 使用/git 远程仓库&远程分支管理.assets/IMG-git 远程仓库&远程分支管理-DC6E007A98BDD441F36124379A669262.png|278]] > > <br> ## 拉取远程分支的更新——git fetch **拉取远程仓库的所有更新(分支、标签等)到本地——更新本地的 "==远程跟踪分支==" 引用**: (即拉取远程分支的提交历史,更新记录到本地的 `.git/FETCH_HEAD` 文件中) - `git fetch [OPTIONS] [<remote> [<refspec> ...]]` - `--prune`:删除**本地仓库中**已被远程仓库删除的分支,用以**清理本地仓库** - `-n | --dry-run`:仅**模拟拉取过程**,不实际拉取任何数据 - **`--force` 或 `-f`**:强制更新本地的"**远程跟踪分支**"引用——**导致非快进合并**。 - `--all`:**拉取远程仓库所有分支的更新** ```shell git fetch --all # 获取远程仓库所有分支的更新 git fetch # 获取当前分支"关联的远程分支"的更新 git fetch origin main # 获取远程分支main的更新 ``` > [!info] `git fetch` 与 `git pull` 的区别 > > - `git fetch` **仅拉取远程仓库的更新到本地**,但 **==不会合并远程分支到当前分支==**; > - `git pull` 会合并远程分支到本地,等价于 `git fetch && git merge <remote/branch>` > > 为此,在执行`git fetch` 后若希望将获取到的更新合并于当前分支,可再手动执行以下操作: > > - `git merge origin/main`:将**获取到的远程分支==合并到当前分支==**。 > - `git rebase origin/main`:将**当前分支==变基==到远程分支的最新提交之后**。 比对本地 FETCH_HEAD 记录与远程仓库的版本号,拉取当前指向的远程分支的后续版本数据到本地, 即更新 FETCH_HEAD 如下图所示,`remotes/origin/HEAD -> origin/main` 即表示本地的“远程跟踪分支`origin/main`” 是对远程仓库的引用。 `git fetch`的作用即是更新远程跟踪分支,**获取远程仓库的最新提交历史并同步给本地的远程跟踪分支 `origin/main`。** ![image-20220823002705154|341](_attachment/05-工具/git%20使用/git%20远程仓库&远程分支管理.assets/IMG-git%20远程仓库&远程分支管理-3B24C003CAF864F4CA6B21318852C289.png) #### 检查 fetch 结果 - `git log FETCH_HEAD` 查看 fetch 日志 - `git log <branch>..origin/<branch>`:查**看本地分支与远程分支**之间的差异——二者之间尚未同步的提交 - `git diff <branch> origin/<branch>`:查看**本地分支和远程分支**之间的**文件差异**。 <br> ## 拉取&合并远程分支的更新——git pull **==拉取==远程分支的更新到本地并==自动合并==到当前分支(将产生一个==合并提交==)**: - `git pull [OPTIONS] [<remote> [<refspec> ...]]` - `--rebase`:**拉取更新后执行 rebase** 而不是 merge——将**当前分支上的所有本地提交==变基==到==远程分支的最新提交**==之后 - `--no-commit`:获取并合并更改,但不自动创建合并提交。 - `--squash`:将获取的**所有远程提交**压缩为**一个单独的提交**,而不是逐个合并。 - `--ff-only`:只允许**快进(fast-forward)合并**,**不会创建合并提交**。若不能进行快进合并将报告失败,。 - `--no-ff`:禁用快进合并,保证会**创建一个新的合并提交**——有助于在提交历史中**保留合并信息**。 - `-e | --edit`:在成功合并后,打开编辑器,编辑 commit 命令。 > [!NOTE] `git pull` 默认等价于 `git fetch && git merge <remote/branch>` 命令 > > ![[_attachment/05-工具/git 使用/git 远程仓库&远程分支管理.assets/IMG-git 远程仓库&远程分支管理-90F52962DBD09A40CDCAD8B0D5E95F73.png|655]] ```shell # 拉取当前分支关联的远程分支的更新, 且自动合并到当前分支、 git push # 拉取远程分支main的更新且合并到当前分支. git pull origin main # 等价于git fetch origin main && git merge origin/main # 拉取远程分支更新, 并将当前分支"变基"到关联的远程分支的最新提交之后 git pull --rebase origin main # 等价于 git fetch origin main && git rebase origin/main ``` > [!info] 配置 git pull 默认启用 `--rebase` > > `git config --global pull.rebase true` ![[05-工具/git 使用/git 分支管理#^otyima]] <br><br> # 远程仓库连接常见报错 🚨 ### Permission denied ![[_attachment/05-工具/git 使用/git 使用.assets/IMG-git 使用-6FE06376280E2E2B76444E84CD3B3153.png|680]] 原因:**git 未配置到 github 的 SSH 连接**,因此**对 github 的请求被拒绝**。 解决办法:参见[[#首次使用说明]] 以及官方说明[^2]。 ### Connection timed out 原因:防火墙禁用了 SSH 连接。 ![image-20240120095539217|642](_attachment/05-工具/git%20使用/git%20使用.assets/IMG-git%20使用-ABB2ED7EAC4BD50543733E454BA3C76E.png) 解决办法:将 SSH 默认的 22 端口改为 443,即**在 HTTPS 的 443 端口建立 ssh 连接**。 步骤: 1. 测试是否能**在 HTTPS 的 443 端口上使用 SSH**,如果显示如下说明可以使用。 > ![image-20240120100232127|612](_attachment/05-工具/git%20使用/git%20使用.assets/IMG-git%20使用-0DBFA0BB7083FF92929E612DB47EC119.png) 2. 设置 SSH,为到 `ssh.github.com` 的连接**指定使用端口 443**,编辑`~/.ssh/config` 文件,增加下列内容: > ![image-20240120100525674|559](_attachment/05-工具/git%20使用/git%20使用.assets/IMG-git%20使用-2536082030D5CBAC730BD488A3963F3A.png) 3. 检查设置是否成功: ```shell ssh -T [email protected] # 如果能够成功连接,则意味着可以直接git push上传到远程仓库了 ``` <br><br><br> # 参考资料 # Footnotes [^1]: [Git - 远程分支](https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E8%BF%9C%E7%A8%8B%E5%88%86%E6%94%AF) [^2]: [Error: Permission denied (publickey)](https://docs.github.com/en/authentication/troubleshooting-ssh/error-permission-denied-publickey) 、