您如何以编程方式检查本地副本是否在遥控器后面?

时间:2018-08-14 11:38:21

标签: git parsing git-diff git-remote git-status

当前,我正在获取最新版本,然后运行git status,并在其中解析Your branch is up to date with 'origin/master'的输出,但这确实很不可靠。

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

我如何做到这一点?

1 个答案:

答案 0 :(得分:0)

要以编程方式获取当前分支与上游分支不同的提交的计数,请使用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的格式(当然也是只读的)。

  • 工作树,这就是您工作的地方。

    在这里,您可以读写每个文件。这些文件为普通格式,未压缩且特定于Git。您还可以在此处拥有Git未知的文件,但是在正确讨论此问题之前,我们需要覆盖第三个实体。

  • 索引,也称为临时区域,有时也称为缓存

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

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

    git add file真正要做的就是从工作树 中将文件复制到索引中的。这将替换索引中的先前版本,因此索引现在与工作树匹配。或者,如果您希望删除文件,git rm file将从索引工作树中删除该文件。


1 一个新的存储库根本没有提交,因此该规则有一个例外:HEAD 可以引用一个简单地执行的分支名称还不存在在全新的存储库中就是这种情况:HEAD表示当前分支是master,但是master实际上并不存在,直到您进行第一次提交。

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


git status的作用

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

git status的作用,除了在分支及其上游运行git rev-list --count --left-right并获得这些编号外, 2 在于它实际上运行了两个{{1} } s(使用git diff,因为它对详细的补丁程序不感兴趣):

  1. 比较--name-status进行索引。此处的不同都是这些准备提交的更改,因为如果您现在进行提交,则Git会对整个索引进行快照,并且该快照与 current 正是在这些文件中提交。

  2. 将索引与工作树比较。不管有什么不同,这些都是未上演提交的更改。在这些文件上运行HEAD后,索引副本将与工作树副本匹配,但不再与git add副本匹配,因此现在这些将是的更改进行提交。


2 请注意,HEAD首先会检查您是否在分支上,如果是,则检查分支具有上游设置。而且,这些都是内置的,因此不必运行单独的程序,但是原理是相同的。


未跟踪,甚至可能被忽略

我们现在也可以正确定义文件未跟踪的含义。很简单,未跟踪的文件就是不在索引中的文件。也就是说,如果我们使用git status从索引中删除文件(仅),或者如果我们在工作树中创建文件而没有在索引中创建相应的文件,则我们有一个工作树文件索引中没有相同的 name 。那是一个未跟踪的文件

如果未跟踪文件 git rm --cached通常会抱怨:它运行的将索引与工作树进行比较的差异表示 ah,这是其中的文件不在索引中的工作树,Git会告诉您它是未跟踪的。如果没有故意跟踪 ,可以通过在git status文件中列出该文件(或与其匹配的路径名模式)来关闭git status 。本质上,在抱怨某些文件未跟踪之前,Git会查看ignore指令。 3 但是,如果文件位于在索引中,则Git永远不会在任何文件中查找其名称。 .gitignore


3 ignore指令还告诉.gitignore,如果当前未跟踪该文件,则“添加所有内容”都应避免添加该文件。 >


上游和远程

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

请注意,您可以拥有多个遥控器!如果您在第二个URL上添加第二个远程git fetch origin,则fred会在那个 URL上调用Git,并更新您的git fetch fred,依此类推。因此,在{em> right 远程运行fred/master很重要。

运行没有附加名称的git fetch将为当前分支的上游获取远程,或者从git fetch获取当前分支的上游,或者没有当前分支,因此通常只是一个运行origin的问题。

子模块

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

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

更改哈希ID,超级项目中的HEAD将实际签出子模块的 current 哈希ID复制到存储库的索引中超级项目(哇!)。因此,如果您已移动子模块(通过此处的git add,则导航回到超级项目,在子模块路径上运行git checkout,现在超级项目的索引记录了正确的哈希ID,为下一个超级项目提交。

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