从本地存储库克隆,然后推回更改

Clone from a local repository, then pushing back the changes

我在 /original/.git 的本地系统上有一个 git 存储库。现在,我已经在 /cloned_one/.git 中克隆了这个存储库。一切看起来都很好。在这里,我有与 /original 中相同的文件,这非常好。我创建一个新文件并提交它。现在,我的克隆回购是提前提交的。我想推送更改,但不知道如何推送!

它变得更加棘手,因为我对以下命令的多样性和确切的用例有点困惑。我知道其中的一些,并且实际上以某种方式与他们合作,但我看到很多用户在错误的地方使用它们,这让我感到困惑。不确定何时使用以下命令。

谢谢。

Git的远程仓库可以来自ssh、https和目录。

在你的例子中,

  • /original/.git 具有指向 github 的远程源(通过 ssh 或 https,例如:https://github.com/user/example.git
  • /cloned_one/.git 具有指向目录的远程源(例如:/original/.git

这看起来像某种链表:

[/cloned_one/.git] --origin--> [/original/.git] --origin--> [github]

这是重现此类设置的示例命令:

$ cd /tmp
$ git clone https://github.com/schacon/example.git original
Cloning into 'original'...
remote: Enumerating objects: 4, done.
remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 4
Receiving objects: 100% (4/4), 18.52 KiB | 3.70 MiB/s, done.
$ mkdir cloned_one
$ git clone /tmp/original cloned_one
Cloning into 'cloned_one'...
done.
$ cd cloned_one/
$ echo newfile > newfile.txt
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        newfile.txt

nothing added to commit but untracked files present (use "git add" to track)
$ git add newfile.txt 
$ git commit -m 'add new file'
[master e45e780] add new file
 1 file changed, 1 insertion(+)
 create mode 100644 newfile.txt
$ git remote -v
origin  /tmp/original (fetch)
origin  /tmp/original (push)
$ git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

现在,cloned_oneoriginal

提前 1 次提交

您可以将更改从 cloned_one 推送到 original,方法是(记得先推送到 cd /tmp/cloned_one):

  • git push
  • git push origin master
  • git push /tmp/original master

这里push的语法是指定你要push到哪里(比如:到origin,或者到/tmp/original目录),以及你要push到什么分支

$ cd /tmp/cloned_one/
$ git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean
$ git push
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 333 bytes | 333.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: is denied, because it will make the index and work tree inconsistent
remote: with what you pushed, and will require 'git reset --hard' to match
remote: the work tree to HEAD.
remote: 
remote: You can set the 'receive.denyCurrentBranch' configuration variable
remote: to 'ignore' or 'warn' in the remote repository to allow pushing into
remote: its current branch; however, this is not recommended unless you
remote: arranged to update its work tree to match what you pushed in some
remote: other way.
remote: 
remote: To squelch this message and still keep the default behaviour, set
remote: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
To /tmp/original
 ! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to '/tmp/original'

现在它说你无法推送到 /tmp/original 因为它不是一个裸仓库。您可以通过将 /tmp/original 更改为裸仓库来解决此问题,或者将其配置为在被推送到如下所示时更新其工作树:

$ cd /tmp/original/
$ git config receive.denyCurrentBranch updateInstead
$ cd /tmp/cloned_one/
$ git push
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 333 bytes | 333.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To /tmp/original
   c3d5e92..e45e780  master -> master

现在,如果您想将更改推送回 github(/tmp/original 的起源),您可以从 /tmp/original/tmp/cloned_one 推送它:

  • cd /tmp/original ; git push origin master
  • cd /tmp/cloned_one ; git push https://github.com/username/example.git

请注意,从 /tmp/original 推送时,您可以将目标指定为 origin(因为 /tmp/original 的来源来自 github)。当从 /tmp/cloned_one 推送时,您必须将目标指定为完整 URL.

您还可以将 cloned_one 的遥控器更改为指向 github(搜索 git 遥控器手册)

进一步阅读:

  • 什么是裸仓库?
    • 裸仓库只是一个普通的仓库,但没有签出文件(例如:只是 .git 目录),
    • What's the -practical- difference between a Bare and non-Bare repository?
    • https://mijingo.com/blog/what-is-a-bare-git-repository
    • 裸仓库的内容与非裸仓库中的 .git 目录相同(要将非裸仓库转换为裸仓库,您只需要 git 配置 -- bool core.bare true 并删除其工作目录)
  • 为什么会出现! [remote rejected] master -> master (branch is currently checked out)问题,您可以阅读:

所有关于 Git 命令

TL;DR

要将更改上传到克隆的存储库,请使用 git push。即使您克隆了本地计算机上的存储库,这也适用。

本地分支机构和远程分支机构

要理解事物,存储库通常有两组分支:

  • 您当地的分支机构
  • 远程分支

通常当您使用git branch列出分支时,它只会列出本地分支。但是您可以使用 git branch -a 列出所有这些:

在这里,这显示了我的本地分支以及远程分支(红色,表示它们是远程的)

当你运行git pull时,这实际上做了两个步骤:

  • 首先,它 运行s git fetch。这将根据您从中克隆的回购中的任何内容更新所有远程分支。请注意,这个 repo 实际上可能不在远程服务器上;它可能在您的本地计算机上,就像您的情况一样。
  • 其次,它 运行s git mergegit rebase 取决于您的配置选项。这会将您的远程分支合并到您的本地分支中。

这就是您的存储库更新的方式。

但是你会在不合并的情况下获取吗?

获取而不合并很有用,因为它允许您在远程更改合并到您的本地分支之前检查它们。可以这样做:

git fetch
git diff <your branch> origin/<your branch>

运行 这在我的一个存储库中,我看到我从中克隆的原始存储库发生了以下更改。 (这使用 diff-so-fancy 以稍微漂亮的方式显示更改,但在正常的 git 差异上看起来不错)。

TL;DR:您通常不需要获取,但提前查看更改会很好

合并与变基

合并 是当你获取两个独立的历史记录,并通过合并提交将它们连接在一起时。

大多数提交都有父级,但合并提交有两个父级(或者三个或更多,在章鱼合并的情况下)。初始提交的父项为零,但它们很特别,因为在它们之前没有任何内容。

我们可以看一下我正在处理的其中一个项目的提交图,以查看这方面的示例。在这里,我在几个功能分支中工作,然后为它们创建拉取请求以合并回主分支。

我认为这样的图表很漂亮,但有些人更喜欢线性历史,这就是重新定位的用武之地。

它不是将两个分支连接在一起,而是将一个分支折断,然后将其粘在另一个分支上。 This is a good article that goes into detail about it.

rebase 的作用是什么?

如果您在本地分支上有提交(例如,main),并且在远程分支上有新提交(例如,origin/main),那么通常,作为在拉动中,git 将合并两者,这样您的本地分支现在将拥有来自 origin/main.

的所有提交

这是我最喜欢变基而不是合并的一次:最好将本地提交 放在 远程提交之上,这样历史上就没有多个分支了.

我使用以下命令将变基设置为默认选项:

git config --global pull.rebase merges

这意味着“将我的本地提交重新设置为远程提交的基础,但保留我有意进行的任何合并(例如合并到功能分支中)”。这是一个很好的默认设置,它让我很开心。

git 推,git 推 --force

这就是您将本地更改获取到克隆存储库的方式。

git push 将上传您的更改,但如果远程存储库有您没有的更改(例如,因为同事在您之前推送给它),它将拒绝上传您的更改,因为那会引起冲突。解决这个问题很简单:

git pull
git push
  • 拉取通过合并或变基将您同事的更改与您的更改集成在一起,以便可以上传您的更改
  • 推送然后上传您的更改

那么 git push --force 呢?

使用这个命令要非常小心。它的主要目的是重写历史,如果机密被提交到 git 存储库,这偶尔是必要的,或者如果您出于其他原因需要永久删除文件。

如果您的同事对远程存储库进行了更改,强制推送将覆盖这些更改

如果你想覆盖你所做的提交,一个更安全的选择是 --force-with-lease,这将确保唯一被覆盖的更改是你的。

我是这样想的:存储库共享提交,但它们不共享 b运行ch 名称。

Git 存储库的核心是——边缘变得杂乱无章——实际上是一对数据库。两个数据库都很简单 key-value stores:

  • 其中一个——通常是迄今为止最大的——被丑陋的大哈希 ID 索引/访问。这些是提交哈希 ID 和其他内部 Git 对象哈希 ID。所以这是对象数据库(尽管 Git 通常不会这样引用它)。

  • 另一个将名称——b运行ch 名称、标签名称和所有其他类型的名称——映射到那些丑陋的大哈希 ID。这让我们这些可怜的人类使用Git;哈希 ID 不可用。这是名称数据库,每个名称映射到 恰好一个 哈希 ID。不止一个名称可以映射到一个特定的哈希 ID,而且许多哈希 ID 没有映射到它们的名称,所以如果你习惯用数学集合来思考,这是一个 non-injective,non-surjective 映射(参见 surjective function)。

对象数据库中的每个提交对象 都有一个唯一的哈希IDany 对象的哈希 ID,无论是否提交,都是 运行 对构成对象的数据进行加密哈希函数的结果(这就是 Git 进行一致性检查和 file-content-de-duplication)。但是由于提交的几个属性,每个提交本身都是唯一的,因此每个提交都有一个唯一的哈希 ID。1 使用这些提交哈希 ID,然后,任意两个 不同的 Git 存储库,使用兼容的 Git 软件——我称这些为“两个 Git”——两个 Git 可以立即判断它们是否具有是否有相同的提交,只是通过比较提交哈希 ID。2

这一切归结为,当我们将两个 Git 相互挂钩时,其中一个(发送者)会说 I have commit a123456...,会你喜欢吗? 对方回复 是的 不,谢谢,我已经有了那个 ,这允许发送方只向接收方发送发送方拥有而接收方缺少的提交。

这个过程——例如,发送我有而你没有的提交——是 git fetchgit push,具体取决于对话的发起者。如果您开始对话是为了获得我的提交,那么您正在使用 git fetch。如果我开始对话以向您发送提交,我正在使用 git push.


1任何熟悉 pigeonhole principle will immediately object that a hash function, even one with a 2160 range (SHA-1) or 2256 range (SHA-256), must eventually produce a collision. This is true, and when that happens, Git stops functioning, so the hashes must be big enough that "eventually" is enough decades or centuries away not to worry. (Due to the birthday problem 的人,这比一开始看起来要难。)

2由于提交形成的 DAG,我们可以做得比仅仅列出所有原始哈希 ID 更好,但是如果我们有两个相当小的存储库——比如说每个提交几千次——只列出所有哈希 ID 就足够容易了,看看谁有哪些提交。


这就是使用多个 Git 存储库的大部分内容

说真的,这种 t运行sfer 是我们所需要的,也是原始时期的全部Git,用于将两个 Git 相互连接起来。通过比较哈希 ID 并发送我有而你没有的提交,你最终会共享我的提交。如果我然后转身从你那里得到任何 you 有而 I 没有的提交,我们现在在我们有一组承诺。但这并不是使用Git的方便方式,所以我们现在添加一些额外的东西。

B运行ch 名称、标签名称、remote-tracking 名称等

人类不擅长哈希 ID:e9e5ba39a78c8f5057262d49e261b42a8660d5b9。说什么?可能有一些人可以向您重复 Git-repository-for-Git 标签哈希 ID 的列表,如果他们已经阅读过它们的话,但我有时会 t运行spose 这些字符,并且不不要费心去记住它们。这就是 computer 的用途。我让计算机为我记住哈希 ID:master 现在可能持有 e9e5ba39a78c8f5057262d49e261b42a8660d5b9。稍后,master 将保存一些 other 哈希 ID。无论它持有什么哈希 ID,也就是说,根据定义,latest commit on my master b运行ch in这个 Git 存储库。

当我们使用 git fetch 时,Git 会以一种很好的方式为我们维护所有这些东西。我们创建一个 remote——一个像 origin 这样的短名称——在它下面我们存储一个常规的 URL 比如 ssh://git@github.com/path/to/repo.git,或者一个像 /absolute/path/to/dir/.git,或任何合适的。3

既然我们 有了 这个简称,originfred 或者我们选择的任何东西, 我们的 Git 可以调用 他们的 Git——也就是说,我们的 Git 软件可以使用 ssh 或 https 或其他任何方式,与他们的 Git软件;我们的 Git 将在我们的存储库中运行,他们的 Git 将在他们的存储库中运行——一旦我们调用d up their Git,我们可以使用 git fetch 从他们那里获取提交。我们用一个简单的方法来做到这一点:

git fetch origin

例如。

他们的 Git 列出了他们的 b运行ch 名称和相应的提交哈希 ID。我们的 Git 检查这些哈希 ID 并使用它来确定它们是否有我们没有的提交。如果我们不限制我们的 Git,4 我们的 Git 现在带来了我们还没有的所有提交,所以现在我们分享他们的提交。

但是:我们的 b运行ch 名称是东西 我们 用来在 中查找特定提交我们的 存储库,我们出于某些特定原因喜欢。我们的 git fetch 不涉及我们的 b运行ch 名称。相反,我们的 Git 将他们的每个 b运行ch 名称更改为 remote-tracking 名称 .5 Git 通过将远程名称(在本例中为 origin)粘贴在 b运行ch 名称前面,加上一个削减。所以这就是 origin/mainorigin/master 的来源:那是 我们的副本 他们的 b运行 频道名称 .这是我们 Git 记住他们 Git 的 mainmaster(无论他们有哪个)的方式。

因此,git fetch 为我们提供了他们的 提交 ,但对我们自己的 b运行 没有做任何事情。由于 Git 使用的散列技巧, 所有 对象(包括所有提交)都是完全 read-only,因此此更新仅 添加新提交 到我们的存储库。我们共享他们的提交,但不共享他们的 b运行ch 名称。


3../d/.git这样的非常短的相对路径并不比origin更长或更难输入,所以对于这种情况,您可能想省略远程名称。但是不要这样做! Git 需要那个远程名称来构成 remote-tracking 名称。如果您跳过使用远程名称,则您使用的是原始模式,Git 仍然支持该模式,这只是 中的一个问题。

4您可以故意限制您的 git fetch 以减少网络流量或其他。大多数时候这几乎是不必要的,因为 Git 很聪明,只带入任何 需要的 对象。不过,在极少数情况下,它可能会有用。

5Git 调用这些 remote-tracking b运行ch names。它们不是 b运行ch 名称,无论如何也不在我们的存储库中。它们是我们 其他人 b运行ch 名字的副本。因此,从我们的角度来看,这些 non-branch 名称只是碰巧“跟踪”了其他人 (b运行ch) 的名称。 Git over-uses 动词 track 和形容词 b运行ch 都可以这种过度使用只是一点点。


从现在开始,您在本地工作,至少到 git push

此时您拥有的是:

  • 所有提交;
  • 你自己的 b运行ch 名字;和
  • 你的副本/记忆他们的名字运行。

您通过将特定提交 (git checkout) 提取到您的 工作树 和 Git 的 indexstaging area(同一事物的两个术语)。您最终会进行新的提交,这会添加到现有的提交中。当您进行新提交时,Git 会自动更新您当前的 b运行ch 名称,以便您的 b运行ch 名称自动包含您的新提交。

您问过有关合并和变基的问题,这些实际上都是相当大的主题,但在其他地方已经很好地涵盖了它们。请记住,git merge 主要表示 合并工作 。尽管 git merge 充满了通常的组合工作方式的例外情况,但这主要是通过进行新的提交来实现的。同时,git rebase 意味着 我对我的存储库中的一些提交感到满意,但是我不喜欢这些提交。我想将它们复制到一组 new-and-improved 提交中,并可选择在此过程中使用特殊技巧。

因为你真的不能改变任何现有的提交,复制意味着你得到重复——或者更确切地说,near-duplicates,“接近”部分取决于关于您正在更改的内容,假设您正在更改 某些内容 或者您只是 使用 原件。 rebase 的目标是 停止使用原件 并开始使用 near-duplicates。由于我们通常 find 我们的提交使用 b运行ch name,Git 通过 实现移动名称:

             K--L   <-- br2 (originals)
            /
...--F--G--H--I--J   <-- br1
                  \
                   K'-L'  <-- proposed new br2

<-- older ... newer -->

我们 Git 将 K 复制到 K',通过使用 J 作为基础提交改进副本,然后我们 Git 复制 LL',通过使用 K' 作为 L' 的基础来改进副本。这是行动中 rebase 的主要部分。但现在我们必须 停止使用 K-L,并开始使用 K'-L'。由于我们 find 通过 b运行ch names 提交,Git 只需要“剥离标签”提交 L 并将其粘贴到提交 L' 上。 Git 然后向后工作——这是 Git 中的一个普遍主题,它从最后开始并向后工作——从 L',所以现在你不 再看 K-L

因为 commits 是共享的并且 b运行ch 名称不是 ,如果你 得到 从一些 其他 Git 存储库 提交 K-L,你现在有一个问题:他们的 b运行ch 名称仍然引用提交 L,而不是您的新 L'.

git push 不只是颠倒过来的 git fetch

当你运行git push时,你:

  • 让你的 Git 打电话给其他人 Git;
  • 让你的 Git 做出 Git 特定的 承诺:不只是 我拥有而你没有的一切 而是 对某些 b运行ch 的每个提交 我有你没有的 (我有你没有的提交't,这是我选择的某个特定 b运行ch);
  • 最后,一旦这些提交完成,您礼貌地请求(常规 git push)或命令(git push --force他们的 Git 应该更新 他们的 b运行ch name.

当我们使用 git fetch 时,我们有这些友好的 remote-tracking 名称,我们的 Git 通过这些名称记住它们的 b运行ch 名称。 push 命令不关心友好性。我们只是建议用一些新的哈希 ID 完全覆盖他们的 b运行ch 名称。

如果我们发送给他们的提交 添加 到他们的 b运行ch 中,正如他们当时看到的那样,这个礼貌的请求-请将您的 b运行ch 名称 develop 设置为 a123456... 例如——可能没问题。他们有:

...--G--H   <-- develop

其中 H 代表 9876543... 或任何哈希 ID。我们向他们发送了提交 I-J:

...--G--H   <-- develop
         \
          I--J   <-- polite request to set "develop" to point to J

如果他们服从这个礼貌的请求,他们的提交 H 仍然可以找到,因为 Git 从 b运行ch 名称的提交开始倒退。 J 返回到 I,返回到 H,嘿,我们没有丢失任何提交!

不过,在 git rebase 之后,我们采用了一些现有的提交并将其丢弃,以支持 new-and-improved 替换。假设他们有:

             I--J   <-- br1
            /
...--F--G--H   <-- develop
            \
             K--L   <-- br2

他们的 存储库中,我们现在向他们发送一对提交 K'-L' 添加到提交 J:

                  K'-L'   <-- please set br2 here
                 /
             I--J   <-- br1
            /
...--F--G--H   <-- develop
            \
             K--L   <-- br2

他们将 br2 设置为指向 L' 而不是 L 这一礼貌的请求不会得到很好的接受。他们会说:不行!如果我这样做,我会失去提交! 当然,我们希望 他们失去 K-L,支持 K'-L'。但除非我们告诉他们,否则他们不知道。

这就是 git push --force 的用途。但是,如果他们的 Git 存储库非常活跃,也许我们之前 得到了 K-L,但现在他们有:

                  K'-L'   <-- please set br2 here
                 /
             I--J   <-- br1
            /
...--F--G--H   <-- develop
            \
             K--L--N   <-- br2

我们建议他们放弃整个 K-L-N 链,转而支持我们的 K'-L'

--force-with-lease选项就是试图改善这种情况。它在当前 Git 中工作得很好,但可能会有更新出现在不太正确的地方。 (我认为它应该保持“正确”,并且也有这样做的建议,所以我们拭目以待。)

裸仓库

当我们使用 Git 时,我们有一些提交 签出 。此提交来自我们的 current b运行ch 并且是我们的 current commit。我们可能正在处理新的提交。在这种状态下,Git 字面上 不能 接收到我们当前 b运行ch 的更新:那会把事情搞砸。6 所以 Git 将拒绝推送到 currently-checked-out b运行ch.

为了回避这个问题,意味着 接收 git push 请求的 Git 存储库通常设置为 bare 存储库。裸存储库是没有工作树的存储库。没有工作树,没有人可以在裸存储库中做任何工作。这意味着没有什么可以搞砸的,裸存储库总是可以收到推送。

还有其他方法可以解决此问题(receive.denyCurrentBranch 的配置设置),但避免该问题的另一个好方法是 避免 git push : 使用 git fetch 时使用两个不同的存储库,您可以控制它们。当你在 A 工作时总是从 B 获取数据,当你在 B 工作时总是从 A 获取数据,你 不能 踩到你自己。


6特别是,Git 的 index 包含当前提交的图像,由任何提议修改我们 git add 编辑的替换文件,我们添加的新文件,我们 git rm 编辑的 and/or 文件。 Git 将构建新的提交 fom 索引中的任何内容,新提交的父级将是当前提交,其哈希 ID 存储在 b运行ch 名称中。因此,更新 b运行ch name 也需要更新 index 和工作树 。如果我们正在做某事,那是个坏主意。即使我们不是,更新 b运行ch 名称也意味着我们的新提交可能会到达我们没有预料到的地方。整体形势严峻。

底线

在 Git,您在本地工作,提交。这些在你的存储库中:只有一个,你现在在其中,有一个工作树和Git的索引。7 要从其他 Git 获得提交,请使用 git fetchremote: 一个短名称,如 origin。使用 git remote add 添加更多遥控器,以添加更多要从 获取的位置。使用 git remote set-url 到 fiddle 和 URL 用于一个特定的遥控器,git remote remove 删除遥控器,git remote update 使 Git 从 all remotes.8 考虑将 fetch.prune 设置为 true 以解决我认为 [=109 中的历史错误=]默认值。9

git fetch 之后,您有 所有 次提交。和他们一起做任何你喜欢的事。将它们留在您的存储库中,对它们进行变基,等等。然后,如果另一个 Git 是设置为接收 git push 请求的 bare Git,请使用 git push 发送您的新提交并要求他们设置他们的 b运行ch 名称之一以记住您的提交:

  • 如果这会在他们的 Git 中创建一个 新名称,他们可能会允许它。
  • 如果这更新了一个名称使得旧的提交仍然存在,他们可能会允许它。
  • 如果这更新了一个名称以便停止在他们这边找到旧的提交,他们将拒绝它,除非你使用--force选项之一;使用 --force-with-lease 以确保安全。

如果另一个Git不是裸机,and/or你想直接在里​​面工作,改变你工作的地方,这样你现在在 other 存储库中,并使用 git fetch 获取您在 were 工作的存储库中所做的提交,a刚才。由于 fetch 本身总是安全的,10 这将是安全的。

总是,总是记住,如果你还没有提交某事,那不是在Git(还)。如果你已经 committed 它,它在提交中,即使在 mini-disasters 之后,你通常也可以取回它。11


7git worktree add把这张图复杂化了,这里就忽略吧。

8或者,使用git fetch --all:这就是--all的意思,所有遥控器git remote update 命令更高级,可以让您在这里做更多的事情。

9即运行:

git config --global fetch.prune true

一次,在这台特定机器上的全局配置中进行设置。当 git fetch 从某个远程 R 获取数据时,它会为每个 b[= 创建或更新 R/<em>b运行ch</em> 674=]ch 它在 R 上看到。但是如果 R 昨天和今天有一个名为 fancy42 的 b运行ch 那个 b运行ch 是 gone,你的 Git 没有做任何事情:它昨天在你 运行 git fetch 时创建了 fancy42,现在没有 fancy42 可以创建或更新,所以它没有' 创建或更新它。这给你留下了一个“陈旧的”fancy42.

启用 p运行ing 后,git fetchgit remote update 注意到他们的 fancy42 现在消失了,因此你也不应该有 R/fancy42。您的 Git 将删除它。这不是默认设置,因为它最初不是默认设置,现在更改它为时已晚。可能会有人喜欢甚至依赖它。如果您自己喜欢,请将 fetch.prune 设置为 false 而不要 运行 git remote prune.

10您可以将 git fetch 配置或强制设置为“不安全”,但除非您故意这样做或使用 git clone --mirror 这样做,你不会运行进入这个。

11此规则的一个大例外是 Git 数据库本身受到损坏。这往往发生在以下情况:

  • 存储库位于共享驱动器(Google Drive、iCloud、OneDrive 等);
  • 计算机崩溃或不正常关闭,导致 OS 无法将内容写入磁盘;
  • 计算机本身着火(这曾经是笔记本电脑的常见问题);或
  • 您使用 OS 强制删除 .git 目录中的 Git 存储库数据库。

不然这些东西还真是挺靠谱的。