git: 看起来不像树枝的树枝

git: Branches that don't look like branches

我从来没有掌握 git 的诀窍,我只是断断续续地从事编程工作,所以我忘记了我的项目的状态。目前我不明白 git 告诉我的关于旧分支的内容。

git branch -a 说:

  dashboard
* master
  php7
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/php7

所以说我除了master还有两个分支:dashboardphp7。我清楚地记得 php7 - 这是一个包含许多提交的大量工作。我不记得了 dashboard,但名字告诉我它与哪个文件相关。

git branch --merged 说:

  dashboard
* master
  php7

显然两者合并了。但是 php7 在远程是已知的,而 dashboard 不是。我不记得为了达到这一点我做了什么 git 命令。

当我在 PHPStorm(或 git log --graph)中查看日志时,这两个看起来不像我期望的分支看起来像 - 没有带有提交的转向行。这是日志的最新部分:

谜团(至少对我而言):

另一方面,在日志的前面有一个非常明显的分支,它有两个提交然后被合并,它不在分支列表中: 我很乐意删除它(我不会为了怀旧而保留旧分支),但是 git branch -d texlabels 说: error: branch 'texlabels' not found. 日志中看起来最分支的东西不是分支?我的头好痛。

我相信你们 git 大师们会立即知道这一切意味着什么以及如何清理它 - 我期待清楚。

更新:

感谢 Kata 的详尽回答(很可能被接受)。但是我有一些后续问题很难在一个小评论中阅读(我希望评论可以更长并且具有更多格式),所以请耐心等待我更长的时间。我想他们可以通过评论或 Kata 添加到他的答案中来回答 - 无论有效。

Because it is not sure that in the past php7 was merged into master.

如果不确定php7是否合并,为什么会列在--merged中? (git 成为 "unsure" 的想法让我很担心......)我不知道以后如何移动分支负责人,所以这种情况不太可能发生。然而,有一次我在本地做了一些导致 Github 拒绝推送的事情(我想我可能已经将文件修改为已经推送的提交) - 其他人帮我看了看,我最终做了push -f(我是唯一的开发者)。也许这导致指针错位...

无论如何,我 知道 php7 代码是我当前代码库的一部分,因为它现在很高兴 运行 在 PHP7 上。我认识到有几个提交是在那个分支上完成的。事实上,有可能 all 从我创建 php7 到我合并它(46 次提交)的提交是在那个分支上完成的(即没有翻转回 master 到同时修复错误)。这是否可以解释为什么 DAG 中主线旁边没有额外的线?

如果是这样,那么也许 texlabels 是我为修复 master 上的错误而中断的唯一分支,因为它是 DAG 中唯一的额外行。此外,没有其他分支有 "Merge branch 'so-and-so'" 的条目 - 是因为没有任何主提交,合并不需要更改任何内容(只需移动指针)?

Because dashboard was created locally and has never pushed to remote.

哦,没想到基础推送是不包含分行信息的。显然 Github 知道 php7 因为我毫无疑问在检查时确实推送了。 (对吗?)

我现在也了解了标签,并且在我将项目部署到具有 PHP7 和其他差异的新服务器上时创建了一个标签。我很高兴不再有 php7dashboard 分支,只要我当前的代码库仍然是我当前的代码库。但是,如果您说它们的合并状态存在一些不确定性,那么删除它们是否安全? (删除东西听起来很可怕,但如果它只是一个指针......)

更新#2:

在 Kata 提到如果没有 --all 我可能看不到所有内容之后,我在 with/without 那个标志之间做了一个差异。我发现在我的 php7 工作的最开始,前四次提交是重复的,首先是在 "branchy-looking" 分支上(仅在 --all 中看到),然后在主线上其他一切。这是来自 git log --graph --decorate --all --oneline 的相关片段:

* 3b1c25a Removal of .html files (won't work with the new server config) and $client in db connect file
* dccc3f3 minor edits
* 20a1aab remove .idea files from repo
* 629d891 Second day of cleanup for PHP7: various things, hacking away at errors one at a time (note: I
* a669fa0 First day of cleanup for PHP7:   * mysql_ to mysqli_ (major functions, anyway)   * convert my
| * 51738d1 (refs/original/refs/heads/php7) minor edits
| * f1aa0f9 remove .idea files from repo
| * 38aef9b (refs/original/refs/remotes/origin/php7) Second day of cleanup for PHP7: various things, ha
| * cfcaa51 First day of cleanup for PHP7:   * mysql_ to mysqli_ (major functions, anyway)   * convert
|/
* 294ef21 Feature: batch category delete

我猜测这种怪异是由于我不小心使用我的 VM 上的命令行来执行四个中的两个("remove .idea..." 和 "minor edits")而不是其他 OsakaWebbie 造成的他们中的。 (该用户未在 --oneline 中显示,但您可以在 Github 中看到它。)但无论它是如何发生的,我假设第一组(cfcaa51 至 51738d1)将在以下时间消失我删除了分支,但由于它们是重复的(而且我知道我当前的代码库反映了这些提交中的更改),应该没问题吧?

您最好将分支视为 (或指针)。 git log 向您显示的是提交的 DAG 和指向特定提交的头部列表。您当前可以看到的内容类似于:php7 head 指向此提交。过去你不知道php7头是怎么动的,因为git允许我们自由移动头。

关于git branch --merged [<commit>],查看它的document,该命令简单地显示了可以从<commit>到达的所有头。在您的例子中,<commit>HEAD,这意味着 master。所以结果很明显:dashboardmasterphp7 可以从 HEAD 到达。 请注意,默认情况下 git branch 不显示远程头,为此添加 -a 选项

现在我想你的问题可以得到解答了。

Commits I remember doing on the php7 branch are all on the same orange line as master. If I merged and then deleted the branch (logical), why is it still listed as a branch at all?

因为不确定过去php7被并入了master。即使是,它也可能总是在稍后的某个时候 php7 head 被移动,所以我们看不到由 php7 引起的合并的痕迹.

Why is there an extra "origin" label on the last of the php7 branch? I would think recent pushes would cause remote to look just like local, with only one "origin" label on the latest commit. Surely remote doesn't consider php7 to be not-yet-merged - that would be horrible, as that code is critical.

该标签仅表示当前有 2 个头 -- php7origin/php7 -- 指向该提交。

dashboard is not known by remote at all (https://github.com/OsakaWebbie/kizunadb) - how could that be?

因为dashboard是在本地创建的,从未推送到远程。

I would be happy to delete it (I don't keep old branches for nostalgia), but git branch -d texlabels says: error: branch 'texlabels' not found. The most branchy-looking thing in the log isn't a branch? My head hurts.

你知道 texlabels 头的存在只是因为你在提交消息中看到它的名字。但实际上那个头在过去被删除了,所以现在你不能再删除它。

更新:

回答@OsakaWebbie的更多问题

--merged选项的命名是基于这样的事实,在正常发展(即你不会异常移动头部,git reset例如),如果 head child 可以到达 head parent,则意味着 parent 在过去的某个时间点被合并到 child 中。换句话说,child 确实继承了 parent.

----------------------- child
         /
        /
     parent

但我很同情你,实际上complaints关于git命令及其选项的命名。

回到你php7头的故事,我想现在情况应该清楚了。

合并不一定会使两条路径合二为一。事实上,正如您所说,由于您切换到 php7 并向其附加了 46 次提交,因此您没有向 master 附加任何提交,因此合并之前的历史记录如下所示:

----------------- master
                    \
                     ----------------- php7

然后您切换回 master 并进行了合并:git merge php7。因为 php7master 的子项,所以合并的结果应该正好是 php7。因此,git 将简单地向前移动 master 并将其指向 php7 所指向的提交。这种合并称为fast-forward。那么你有:

-------------------
                    \
                     ----------------- php7, master

本质上是:

-------------------------------------- php7, master

但是合并 texlabels 头部时并没有发生快进。您创建了头部,切换到它,编写了一些代码并附加了一些提交。然后你切换回 master,还编写了一些代码并附加了一些提交。所以你有:

----------------- master
     \
      ----------- texlabels

如您所见,texlabels 不是 master 的子代。因此,这不能快进,将 texlabels 合并到 master 将导致:

----------------- (old master) -- master
     \                         /
      ----------- texlabels

这就是为什么它是历史上唯一看起来像树枝的东西。

关于您最后两个问题:

Oh, I didn't realize that a basic push doesn't include branch information. Apparently Github knows about php7 because I no doubt did pushes while it was checked out. (Is that right?)

git push <remote> [<head>] 只推送提供的 <head> (当然还有它的祖先提交)。如果未提供 <head>,则将使用 HEAD 指向的头部——在您的情况下为 php7。要推动所有正面,请使用 --all 选项。

But if you're saying that there is some uncertainty about their merge status, is it safe to delete them? (Deleting things sounds scary, but if it's merely a pointer...)

是的,heads 只是指针,但请注意:删除 head 后,一些提交可能会被放弃——即,它们无法从任何 head 到达——并且将被[清除(删除) =71=] 共 git。如果您确定要删除的内容,请继续。


更多注意事项:

  1. 这里的push -f没有关系,它在远程(例如losing some commits)而不是在本地引起意想不到的事情。
  2. 默认情况下 git log 仅显示可以从 HEAD 到达的提交,使用 --all 选项显示所有提交。

更新#2:

关于 4 次额外提交

很可能在提交 51738d1 minor edits 时,您发出了 git filter-branch command 来大量修改关于这 4 个提交的某些内容(我猜是修改作者姓名)。然后你创建了 4 个新提交(从 a669fa0 到 3b1c25a)。 4 个旧提交(从 cfcaa51 到 51738d1)仍然存在,因为它们仍然可以从头部到达 refs/original/...。这些头像是由 git filter-branch.

的备份机制创建的

你对 delete those 4 extra commits 是完全安全的。它们与 4 "main" 次提交完全无关。