如何以编程方式检查本地副本是否在远程副本后面?

Oli*_*n04 3 git parsing git-diff git-remote git-status

目前我正在获取最新的,然后运行git status并解析输出,Your branch is up to date with 'origin/master'但这感觉就像一个黑客。

我已经研究过使用,git status --porcelain但这仅包括在系统上所做的文件更改,而不是在远程所做的更改。我不在乎实际进行了哪些更改,我只想知道是否存在任何更改(本地或远程)。

我将如何干净地实现这一目标?

tor*_*rek 5

要以编程方式获取当前分支与其上游分支上不同的提交计数,请使用git rev-list --count --left-right HEAD...@{upstream},或者git rev-list --count master...master@{upstream}例如。注意,这里的三个点,其中独立分支名称或HEADbranch@{upstream}该是如何git statusgit branch -vv打印ahead 1behind 2up to date或什么的。

请注意,这首先假设您在一个分支上,并且该分支一个上游要领先和/或落后。如果上游是远程跟踪名称,例如origin/master,则假定存储在远程跟踪名称中的值就是您想要存储在其中的值。

还有很多东西要知道

如果您正在编写这些内容的脚本,那么准确地了解(或定义)您所说的最新版本很重要

纯粹在本地——即,在一个存储库 + 工作树组合中——需要考虑三个实体:

  • 当前提交,又名HEAD.

    这可能是一个分离的 HEAD,其中HEAD包含原始哈希 ID,或者相反,在分支上,其中HEAD包含分支本身的名称。在分支上时,分支名称,例如master,包含当前提交的原始哈希 ID。无论哪种方式,HEAD始终指的是当前提交。1

    当前提交本身是只读的(完全)和永久的(大多数情况下——你可以故意放弃提交,之后它们最终会被删除)。您可以更改哪个提交是当前提交(例如,),但您不能更改提交本身。由于提交无法更改,因此根据定义,它永远不会“过时”:它是任何东西。像任何提交一样,当前提交有一些元数据(谁做的,什么时候做的,等等)以及每个文件的完整快照。git checkout different-commit

    存储在提交中的文件采用特殊的 Git-only 格式(当然是只读的)。

  • 工作树,这是简单的,你做你的工作。

    在这里,您可以读取和写入每个文件。这些文件采用普通格式,未压缩且特定于 Git。你也可以在这里有 Git 不知道的文件,但在我们正确讨论这个之前,我们需要涵盖第三个实体。

  • 指数,也叫暂存区域或有时缓存

    该索引有多种用途(因此有多个名称),但我认为最好将其描述为您将进行的下一次提交,如果您现在进行提交。也就是说,索引(实际上只是一个文件)包含 Git 制作新快照、放入新提交所需的所有信息。因此,索引包含将进入您下一次提交的所有文件

    索引中的文件被压缩,并且是 Git-only 格式,就像提交中的文件一样。但是,对于我们这里的目的而言,关键的区别在于索引中的文件可以更改。您可以将新文件放入索引中,也可以从索引中删除现有文件。

    所有这一切确实是一个文件复制工作树,进入该指数。这将替换索引中的先前版本,以便索引现在与工作树匹配。或者,如果您希望删除文件,请从索引工作树中删除该文件。git add filegit rm file


1级新的存储库具有完全没有提交,所以有一个例外:HEAD 可以指分支名称根本不存在。在一个全新的存储库中就是这种情况:HEAD说当前分支是master,但master在您进行第一次提交之前实际上并不存在。

(这 git checkout --orphan命令可以为另一个分支重新创建这种特殊的“在一个尚不存在的分支上”状态。这不是大多数人大多数时候会做的事情,但它可以出现在检查状态的程序中。)


什么 git status作用

由于索引和工作树都是可写的,它们都可能是“脏的”或以某种方式导致某些东西“过时”。如果您认为工作树文件是最新的,它可能是过期的索引副本,因为它与工作树副本不匹配。一旦工作树文件被复制到索引中,索引就不再与HEAD提交匹配,并且在某个时候需要一个新的提交。

git status除了运行git rev-list --count --left-right分支及其上游并获取这些数字之外,还有什么作用,2是它实际上运行了两个git diffs(--name-status因为它对详细补丁不感兴趣):

  1. 对比HEAD指数。无论这里有什么不同,这些都是为 commit 暂存的更改,因为如果您现在进行提交,Git 将对整个索引进行快照,并且该快照将与当前提交的这些文件完全不同。

  2. 将索引与工作树进行比较。不管这里有什么不同,这些都是没有为 commit 暂存的更改。一旦你git add在这些文件上运行,索引副本将匹配工作树副本,但不再匹配HEAD副本,所以现在这些将暂存以提交的更改。


2请注意,git status首先检查您是否某个分支上,如果是,则该分支是否具有上游设置。而且,这都是内置的,所以它不必运行单独的程序,但原理是一样的。


未跟踪,可能被忽略

我们现在也可以正确定义文件未被跟踪的含义。一个未跟踪的文件很简单,就是一个不在索引中的文件。也就是说,如果我们从索引中删除(只)的文件用git rm --cached,或者如果我们没有创建索引的相应文件中创建的工作树中的文件,我们有没有什么相同的工作树的文件在索引中。这是一个未跟踪的文件

如果文件未经跟踪,git status通常它抱怨道:在DIFF运行该指数比较了工作树说啊,这里是工作的树不在索引中的文件,和Git会告诉你,这未跟踪。如果它是故意未跟踪的,您可以git status通过在文件中列出该文件或匹配它的路径名模式来关闭它.gitignore。本质上,就在抱怨某个文件未被跟踪之前,Git 会查看 ignore 指令。3 但是,如果该文件在索引中,Git的从不寻找它的任何名称.gitignore


3 ignore 指令还告诉git add任何整体“添加所有内容”都应该避免添加该文件,如果它当前未被跟踪。


上游和远程

分支的上游可以是远程跟踪名称,例如origin/master. 这些名称是您的 Git 记住其他一些 Git 分支的方式。要更新 remote 的远程跟踪名称origin,您只需运行git fetch origin.

请注意,您可以拥有多个遥控器!如果您fred在第二个 URL 上添加第二个遥控器,git fetch fred将调用URL上的 Git ,并更新您的fred/master等等。所以它运行很重要git fetch遥控器。

git fetch不带附加名称运行将获取当前分支上游的远程,或者从origin当前分支没有上游,或者没有当前分支,所以这通常只是运行的问题git fetch

子模块

子模块实际上只是对另一个 Git 存储库的引用,但这给总体计划带来了全新的问题。每个 Git 存储库都有自己的HEAD、工作树和索引。这些可以像以前一样干净或脏,并且如果子模块未处于 detached-HEAD 状态,则子模块的分支可以在上游之前和/或之后。

然而,子模块存储库通常处于 detached-HEAD 状态。超级项目中的每个提交都列出了您的 Git 应该将子模块 Git 分离到的特定提交。当超级项目 Git 检出提交时,超级项目 Git 会将子模块的哈希 ID 存储到超级项目的索引中。这样每个新的超级项目提交都会记录正确的哈希 ID。

更改哈希 ID,git add在超级项目中将实际检出子模块的当前哈希 ID复制到超级项目存储库中的索引中(哇!)。所以如果你已经移动了子模块(通过git checkout那里),你导航回超级项目,git add在子模块路径上运行,现在超级项目的索引记录了正确的哈希 ID,为下一个超级项目提交做好准备。

(测试子模块是否在超级项目的索引所需的提交上比较困难。)