Git 分支未显示所有分支

2024-02-12

我是 Git 的新手,我从 GitHub 克隆了一个分支,当我输入时会显示所有分支git branch。完成工作后,我成功地将其推送到新分支。之后,我将该文件夹复制到另一个目录(因为我想要备份以避免冲突),进入它,然后输入git branch。只显示了 3 个分支,因为我在 Github 上有 4 个分支。

我尝试通过将分支克隆到新文件夹中(键入git clone -b <branch-name> <repo-link-https>)现在只有我克隆的分支出现了。

请问有什么建议吗?


When you clone an existing repository, your Git makes a new and different repository, and copies into this new repository all1 of the commits and none of the branches from the original repository. The last step of git clone is to create one branch. This branch name is yours, not theirs; it's just spelled the same as one of their names.

当您使用克隆(一个不同的存储库)时,您可以向其中添加越来越多的分支。如果你添加所有same原始存储库中的分支,您现在拥有它们的所有提交and他们所有的分支名称(请注意,作为您自己的分支)。但在那之前,你就拥有了他们的所有commits。没关系,因为 Git 与分支无关。 Git 是关于commits.


1The precise description is much more complicated than this, but thinking of it as "copy all of their commits and none of their branches" will get you started.


我尝试通过将分支克隆到新文件夹中(键入git clone -b)现在只有我克隆的分支出现了。

When you make a new clone—which, again, is a new repository, where you get all of the previous repository's commits but none of its branches yet—the last step of the git clone command is to run a git checkout or git switch command2 that makes one branch. The -b flag exists so that you can tell your Git which of their branch names to copy, as the last step. If you omit the -b flag, your Git asks their Git repository—the one you're cloning—which branch they recommend. But either way you get only one branch.

你实际上并不需要any在 Git 中工作的分支名称。你确实需要some不过,分支名称是最好的名称。这就是为什么你的 Git 在末尾添加了一个名字git clone过程。你起的每一个名字都会让你多做一件事情。

要了解发生了什么,请继续阅读。如果您对当前问题已得到解答感到满意,则可以在此停止。


2The git switch command was first added in Git version 2.23, to split up the overly-complicated git checkout command into two separate commands, git switch and git restore. The existing git checkout remains; you can use it instead of the two new, simpler commands. The new simplified commands are in a sense safer, though: the git switch command tries to be very safe, as does the half of git checkout that it copied. The git restore command, however, is deliberately unsafe in that it will irrevocably destroy work; it copies the other half of git checkout. So if you use git checkout, you can accidentally invoke the "destroy my work" half when you think you're invoking the "safely do stuff" half.


Git 就是关于提交

要理解 Git 在这里做什么以及为什么这样做,首先要了解 Git 本身实际上就是关于提交的。这与分支无关,尽管分支名称可以帮助您(和 Git)find承诺。尽管提交,但这与文件无关contain文件。这实际上与提交有关:Git 所做的其他一切都是为了保留和添加提交。提交是事情的开始,也是其他一切的目的。

这意味着了解提交的含义至关重要is, 你怎么命名一个特定的提交,以及如何制作new犯罪。我们先从名字开始吧。

提交的真实名称是其哈希 ID

You might think that a branch name would name a commit—and it sort of does, but indirectly. In fact, every commit is named by its number. Each commit has a unique number. No other commit can ever have that number: once that commit is made, that number is allocated to that commit. Because that commit takes up that number forever, the number has to be really big, and it is. Currently, each Git commit gets one out of 2160 possible numbers.3 This number gets expressed in hexadecimal as a big ugly string like e31aba42fb12bdeb0f850829e008e1e3f43af500 https://github.com/git/git/commit/e31aba42fb12bdeb0f850829e008e1e3f43af500 (this is an actual commit in a Git repository for Git itself).

这个数字总是有效的:如果你有这个提交,那就是它的编号,并且git show e31aba42fb12bdeb0f850829e008e1e3f43af500例如,将显示它。如果没有歧义,您通常可以将数字缩写为前四个字符,因此如果您有 Git 的 Git 存储库的克隆,git show e31aba42fb12bdeb0f850829e008几乎可以保证工作。但git show e31a不是因为它可能是此提交或提交的缩写e31a17f741..., 例如。尽管e31ab今天有效,随着添加更多提交,它可能会停止工作。

These numbers look random, but aren't. In fact, each one is a cryptographic checksum of the complete contents of the commit.4 Git does a double-check when extracting any of its internal objects, including commits, that the checksum still matches, so as to detect storage failures: you tell Git to find a commit (or other object) by hash ID and it checks that the hash ID still matches. So this in turn means that no part of any commit—or any of Git's other internal objects—can ever change, either. You can make new ones, each of which gets a new and different ID, but this does not affect the existing ones, which remain in the repository.


3There are plans to redo the numbering system to use 2256 numbers, with some kind of ugly transition.

4In fact, all of Git's internal objects use this scheme. This means all saved objects are frozen for all time. This is how Git freezes and de-duplicates file contents, for instance.


提交中有什么内容

现在我们知道了一种(可以说是最深入的)通过哈希 ID 查找提交的方法,现在是时候查看每个提交中的内容了。每个提交都有两部分:

  • 一个提交持有一个完整快照您的所有文件。这是大多数提交的主要数据(通常也是存储库的大部分)。每个文件都存储为内部文件斑点对象,使用相同的哈希名称编码技巧。这会自动删除重复的文件,因此,如果您连续进行一百次提交并且大部分重复使用其大部分文件,它们实际上不会占用任何额外的空间。

  • 每个提交还包含一些metadata,或有关提交本身的信息:例如,谁制作的、何时制作以及为什么制作。 “为什么”部分是您的日志消息:您稍后对自己和/或其他人的解释。为什么是this比上一个承诺更好?或者至少,如果它不一定更好的话,为什么它有任何不同。此特定提交的目标可能是修复某些错误,或添加某些新功能,或为添加新功能做好准备,等等。提交本身具有更新的源代码,但不一定具有任何有关bug更新应该可以修复。这是你解释这一点的机会。

Git 为您生成并稍后使用的元数据中有一段您很少直接看到,那就是:每个提交都保存其前一个提交的原始哈希 ID。这串字符串一起提交,向后,进入以最新提交结束的提交链。

我们可以画这个。想象一下,我们有一个存储库,其中只有三个提交。我们将使用单个大写字母来代表提交,而不是真正的哈希 ID。第一次提交将是A,接下来将是B,第三次提交是commitC:

A <-B <-C

自提交以来C是最后一个,它有较早的提交B其元数据中的哈希 ID。我们这么说C 指着 B。同样的道理,提交B指着A。自从A是有史以来的第一个提交,它缺少这个向后指向的箭头:它不指向任何地方。 Git 称其为 a(或 the)根提交。这是我们停止逆向工作的地方。

我刚才提到,每次提交都有每个文件的完整快照。但如果你有 Gitshow一次提交,Git 向您展示了什么changed。 Git 如何以及为何这样做?

The why也许是最容易解释的。如果您想查看所有文件in提交,你可以查看提交。 Git 会将所有这些文件从提交中复制出来(请记住,它们以特殊的冻结 Git 格式存储,并进行了重复数据删除(并且也进行了压缩))到常规的普通计算机文件。您可能有一群比 Git 更强大的文件查看器:它们可以向您显示图像as图像、在文本编辑器中打开文本文档、使用 PDF 查看器打开 PDF 等等。但你的文件查看器可能can't将整个快照与之前的整个快照进行比较。 gitcan.

Git可以比较快照C对照快照B很容易,因为提交C保留提交B的哈希 ID。所以Git可以直接提取both承诺。此外,由于 Git 去重复文件的方式,Git 可以立即知道——甚至不需要bother提取——重复的文件。 Git只需要提取并比较不同的文件。 Git 会这样做,并构建一组更改,将旧文件变成新文件。这就是 Git 将向您展示的内容:这组指令。

(请注意,Gitcreates按需提供的指令集。在您要求 Git 比较任意两个提交之前,Git 拥有的只是两个快照。您可以根据传递给比较命令的选项获得不同的指令集。例如,Git 可以根据单词进行差异检查,或者忽略某些类型的空白更改。 Git 在这方面的能力并不总是像我们希望的那样好,但是有一些我们可以使用的技巧。不过,它们超出了这个特定答案的范围。)

按分支名称查找提交

我们已经知道,如果我们记住大而难看的哈希 ID(或写下来),我们可以使用它们来查找提交。但这是荒谬的。我们有一个computer。为什么我们没有computer为我们写下哈希 ID?

这就是分支名称的作用。但这有点偷偷摸摸。分支名称的真正作用是仅存储last提交的哈希 ID。让我们再次绘制该三提交存储库,并添加一个名称,main,这标识了last commit:

A--B--C   <-- main

在这里,而不是试图remember C的哈希ID,我们只知道名字main为我们做到这一点。所以git checkout main(2.23 Git 之前)或git switch main(2.23 及更高版本)为我们提供当前最新的提交C——不管它有什么哈希 ID。

我们现在可以添加一个new name这也表明要承诺C:

A--B--C   <-- main, dev

现在我们还需要一件事:我们使用这些名称中的哪一个?现在,这并不重要,因为两个名字都选择提交C。但让我们附上特殊的名字HEAD两个分支名称之一,如下所示:

A--B--C   <-- main (HEAD), dev

If we git switch dev,我们重新附加特殊名称HEAD到名字dev, 像这样:

A--B--C   <-- main, dev (HEAD)

现在让我们做一个new犯罪。无需担心how我们进行了一次新的提交,让我们假设一切都已完成。这个新的提交D必然会指向现有的提交C,因为我们做了D from C。所以看起来像这样:

A--B--C
       \
        D

But D现在是latest提交,所以 Git 必须更新name。应该更新哪个名称?答案很明确:应该更新HEAD附加到:

A--B--C   <-- main
       \
        D   <-- dev (HEAD)

我们现在有两个分支名称,这两个名称指定了两个不同的“最新”提交。最新提交于main is C,以及最新提交dev is D。犯罪D指向回提交C,这又指向B,这又指向A;所以所有四个提交都是on branch dev,当其中三个处于开启状态时main.

如果我们切换回名字main并在那里进行新的提交,我们得到:

        E   <-- main (HEAD)
       /
A--B--C
       \
        D   <-- dev

这意味着我们现在有三个在两个分支上共享的提交,以及一个仅在main和一个仅在dev。现在我们need both用于查找所有五个提交的名称;一个名字会找到一个提交,这会找到三个shared提交,但我们需要其他名称来查找最后剩余的提交。

注意分支名称move。事实上,当我们进行新的提交时,它们会自动移动:无论哪个分支名称有HEAD附加到它的自动移动以包含新的提交。所有其他分支名称此时都保持不变,但因为它们是our分支名称,我们掌控。我们可以随时让 Git 移动这些名称。唯一的限制是我们必须有一个commit将名称移至。

克隆创造远程跟踪名称

当我们克隆其他人的存储库时,我们会得到他们的所有提交,但不会得到他们的任何分支。这是如何运作的?好吧,假设我们有上面的内容,有两个实际的分支名称main and dev选择提交E and D分别。我们现在做一个new我们复制所有五个提交的存储库,为我们提供:

        E
       /
A--B--C
       \
        D

We do actually need two names to find all the commits. But we don't need branch names. The other Git, working with the other repository, has branch names, because those are his branches that he'll move around as he makes new commits. So what our Git does is copy their names but change them. We have our Git take their branch names and create our remote-tracking names, by adding something—usually origin/—to the names.5 So we get:

        E   <-- origin/main
       /
A--B--C
       \
        D   <-- origin/dev

Git 将拒绝附加特殊名称HEAD这些远程跟踪名称之一。HEAD只允许附加到branch姓名。所以我们的最后一步git clone是使用-b选项或他们的建议,选择这两个名称之一,并从中创建一个分支名称,如下所示:

        E   <-- main (HEAD), origin/main
       /
A--B--C
       \
        D   <-- origin/dev

注意我们的分行名称选择相同的提交作为我们的远程跟踪名称git clone由...制成their分店名称。但我们现在只有一个分支名称,而不是两个。如果我们运行:

git switch dev

这使用了 Git 提供的一个特殊功能,即找到它们的origin/dev并创造了我们自己的新名字dev:

        E   <-- main, origin/main
       /
A--B--C
       \
        D   <-- dev (HEAD), origin/dev

and now我们有两个分支名称。但我们一开始并没有。请注意,我们现在也有提交D签出,而不是提交E, 因为git switch (or git checkout,如果我们使用它)不仅切换分支,而且还选择分支名称标识的提交作为要签出的提交,因此可供我们使用。


5Technically, a remote-tracking name is in a separate namespace https://en.wikipedia.org/wiki/Namespace. Our Git doesn't just tack origin/ in front, it replaces refs/heads/ with refs/remotes/origin/. The name origin is actually a remote and we can have as many remotes as we like in our Git repository. But this is a topic for another question.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Git 分支未显示所有分支 的相关文章

随机推荐

  • 为什么 Python 的 `re.split()` 不在零长度匹配上进行分割?

    一个特别的怪癖 否则相当强大 rePython中的模块是re split 永远不会在零长度匹配上分割字符串 http docs python org library re html re split 例如 如果我想沿单词边界分割字符串 gt
  • 导入时出现玩笑错误:意外的令牌导入

    我见过类似的问题 但仍然找不到可行的解决方案 我正在尝试将 Jest 集成到一个工作项目中 该项目在数百个地方使用导入 导出默认值 以下测试确实适用于使用 require 的 Jest const bar require flows foo
  • 谷歌地图覆盖层

    我试图在我的谷歌地图上放一个图层来覆盖它 不必与谷歌地图进行任何交互 它只是一层在另一层之上 我现在有什么 div div div div 在地图 div 中 我放置了谷歌地图 覆盖层的背景与地图 div 一样大 但谷歌地图始终将自己放在顶
  • 在 Emacs Lisp 中插入整月的日期

    我正在 Emacs Lisp 中进行一些编程 但我不完全确定如何处理某些事情 我正在尝试插入一整月的日期 每个日期都在一个新行上 如下列表所示 January 2009 年 1 月 1 日星期一 02 01 09 星期二 03 01 09
  • 如何在 Android Studio 3.0.0 中使用数据绑定和 Kotlin

    我刚刚开始使用 Android Studio 3 0 0 但每次尝试构建项目时都会收到此错误 Error Circular dependency between the following tasks app compileDebugKot
  • Eclipse - 可执行 jar 文件错误

    当我使用 eclipse 功能导出 可执行 jar 等时 当它制作罐子时我收到一条消息 JAR 导出已完成 但有警告 查看具体信息 详细信息 无法读取 JAR 文件 classpath 原因 打开 zip 文件时出错 我不知道这意味着什么以
  • 无法在 pandas 数据框中按时间戳建立索引

    我拿了一张 Excel 工作表 其中包含日期和一些值 并希望将它们转换为 pandas 数据框 并仅选择特定日期之间的行 由于某种原因 我无法按日期索引选择行 Excel 文件中的原始数据 MCU Timestamp 50D 10P1 10
  • 是否可以在 Android 中以编程方式卸载软件包

    软件包可以自行卸载吗 如果一个包共享相同的 userId 和签名 可以卸载另一个包吗 Uri packageURI Uri parse package your packagename here Intent uninstallIntent
  • 在 C/C++ 中, char* arrayName[][] 是指向指针的指针还是指向指针的指针?

    我将多维数组理解为指向指针的指针 但也许我错了 例如 我认为 char var char var char var char var or char var char var char var or char var or char var
  • 如何使动态数量的 div 均匀地占据其容器中的所有空间?

    我有一个容器 其中有动态数量的 div 我希望所有的 div 都适合在一行上而不换行 以便每个 div 具有相同的宽度 div 的数量和屏幕的大小都可以改变 我希望有一个CSS解决方案 In 这把小提琴 http jsfiddle net
  • Workflow Foundation 4.5“表达式活动类型‘CSharpValue`1’需要编译才能运行。”

    我正在通过入门教程 http msdn microsoft com en us library dd489454 aspx对于 WF45 我遇到了一个看起来其他人也遇到过的问题 但与我遇到的方式不同 我希望其他人能为我找到解决方案 当我完成
  • 如何在 F# 中实现异步而不是并行

    坚持使用异步获取许多网页的常见示例 我如何异步分拆多个 数百个 网页请求 然后等待所有请求完成 然后再进行下一步 Async AsParallel 一次处理几个请求 由 CPU 上的核心数量控制 抓取网页不是 CPU 密集型操作 我对 As
  • 使用 PyMC3 进行贝叶斯概率矩阵分解 (BPMF):使用“NUTS”的 PositiveDefiniteError

    我已经实施了贝叶斯概率矩阵分解 https www cs toronto edu amnih papers bpmf pdf算法使用pymc3在Python中 我还实现了它的前身 概率矩阵分解 PMF 看我之前的问题 https stats
  • 检查电子邮件是否存在php

    我有一个问题 我有一个 php 脚本来检查电子邮件地址是否存在 但雅虎 hotmail aol 和其他提供商似乎接受任何电子邮件 并且不会拒绝无效电子邮件 只有 Gmail 和 stackoverflow com 等许多域拒绝无效电子邮件
  • 在 Spring Security 3.2 中使每个请求都使用 https

    我使用 spring security 3 2 使用命名空间配置 并且我想让所有调用都为 https 我知道这会降低大约 1 10 的性能 但我仍然想实现它 我知道你 可能会从 tomcat 本身实现这一点 但我想在 security xm
  • 没有 HTML 转义的 Django 表单值

    我需要设置 Django forms ChoiceField 来显示货币符号 由于 django 表单转义了所有 HTML ASCII 字符 我无法得到 或英镑 显示货币符号
  • python中的3D图像旋转

    我有以下图像 I1 我没有捕捉到它 我从谷歌下载的 我将已知的单应性 h 应用到 I1 以获得以下图像 I2 我想假设相机拍摄了上面这张 I2 的照片 我找到了这个 相机 的相机矩阵 令这个相机矩阵为k 现在 我想围绕相机轴旋转该图像 I2
  • 以编程方式拦截我的应用程序中包含的 Android 3rd 方库发起的流量

    我正在尝试编写一些代码来拦截来自 到我的 Android 应用程序的任何网络流量 包括来自非 root 设备上的第 3 方库的流量 有办法做到吗 None
  • 淡出任何接近 UIScollView 边缘的内容

    正如标题所示 当一些 UIImageView 越来越接近 UIScrollView 的四个边缘中的任何一个时 我试图为它们提供淡出效果 由于用户可以拖动 UIImages 如果他将它们拖向边缘 它们就会开始淡出 而不是像 UIScrollV
  • Git 分支未显示所有分支

    我是 Git 的新手 我从 GitHub 克隆了一个分支 当我输入时会显示所有分支git branch 完成工作后 我成功地将其推送到新分支 之后 我将该文件夹复制到另一个目录 因为我想要备份以避免冲突 进入它 然后输入git branch