我有一个远程(非现场、托管)git存储库,我正在从两台笔记本电脑访问它。由于我是唯一一个使用这个存储库的人,所以我不需要有单独的分支。通常,当我提交并推送到存储库时,我会很快在另一台笔记本电脑上获取并合并。
我现在发现自己在两台计算机上都有一个不同版本的文件,git告诉我什么都不需要做,也没有更新。
在两台笔记本电脑上,当我键入时
git remote -v
我收到了完全相同的东西-远程存储库的地址
origin git@XYZ.com:myproj.git (fetch)
origin git@XYZ.com:myproj.git (push)
在两台笔记本电脑上,都会返回git状态调用:
On branch master
Your branch is up-to-date with 'origin/master'
如果我执行
git remote update
我收到
Fetching origin
然后我打电话给
git status -uno
我得到
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit
最后,如果我打电话给
git fetch origin
没有输出。如果我打电话给
git merge
我收到的回复
Already up-to-date.
当我键入时
git rev-parse HEAD
在两台笔记本电脑上,我都收到了完全相同的哈希值:
d353340c1.....8503b
据我所知,两台笔记本电脑都认为远程存储库的一切都是最新的,但其中一个文件在两台笔记本上明显不同。
这怎么可能呢?我该如何声明一切都是真正同步的?
一台笔记本电脑正在从命令行运行Ubuntu 16.04和git 2.7.4版本。另一个是Windows10,通过Mintty终端上的gitbash 2.19.0.Windows.1访问。
除了之外的所有,两个签出文件中的差异在这里看起来非常正常。假设这两个签出的文件是(显然——见下文)跟踪的文件,即在每台机器上的Git索引中,这种差异通常应该导致git status
,即两个系统中的至少一个系统上有not staged for commit
的变化。
在这一点上,可能会发生以下几件事:
- 文件实际上可能不在索引中,并且被忽略(但在注释中似乎已经排除了这一点)
- 该文件可能被错误地标记为";"干净";以便
git status
只是假设文件的工作树副本与文件的索引副本匹配 - 该文件可能是字面上的";清洁">
在我详细讨论案例2和案例3之前,这里有一个特殊的事实值得注意。使用Git时,您看到和使用的文件不在Git中。在Git中是的文件——存储在提交中——以一种特殊的只读、仅限Git、压缩和消除重复的形式存储,只有Git才能真正使用。因此,为了使用提交,Git必须将提交的复制到某个地方,将文件变成您可以实际使用的普通日常文件。这些文件在工作树或的工作树Git存储库中。(存储库通常位于工作树顶层的.git
子目录中。)
现在,情况1非常简单:
- Git的索引本身是一个复杂的问题,但它相当于要提交的所有文件的列表,包括截至下一次提交时,它们应该具有的已Git化的内容
- 在Git的索引中不是的文件将不会出现在下一次提交中(当然,您可以更改这一点,例如使用
git add
) - 存在于工作树中但不存在于Git索引中的文件,根据定义是未跟踪的文件
这就是不被跟踪的全部:它只需要存在于你的工作树中,但不存在于Git的索引中。未跟踪的文件通常会导致Git发出呜呜声,但如果列在.gitignore
中,Git就会停止发出呜呜声。这当然需要.gitignore
或.git/info/exclude
文件的存在。(您可以在主目录配置中有一个全局.gitignore
,但如果git check-ignore -v
导致文件被忽略,它会指出它。)
如果为该存储库定义了clean和smout过滤器(通过存储库中的.gitattributes
和一些Git配置文件中的过滤器定义),则可能发生情况3:
-
污点过滤器(如果有的话)负责在文件从Git出来时更改。当Git提取提交时,它首先将提交的所有文件复制到其索引中(以便它们可以进入下一次提交)1然后,Git将这些文件提取到您可以实际使用的版本中,这些版本将进入您的工作树。如果有污点过滤器,数据在到达工作树副本的途中会通过污点过滤器,因此工作树副本不需要与(展开的)索引副本匹配。
-
干净过滤器(如果有的话)负责在文件进入Git时更改。当您
git add
一个文件时,Git会压缩、编译和消除文件数据的重复。如果有一个干净的过滤器,Git会在开始压缩和Git化过程之前通过干净的过滤器运行数据。因此,干净的滤镜可以带走污迹滤镜放在中的东西。通过这种方式,您可以提交与实际使用的文件不同的文件2
根据使用的干净过滤器和污迹过滤器,可以想象,在两台不同的机器上,某些工作树文件的大部分内容会完全不同。这当然需要文件定义干净和污迹过滤器,而这又需要.gitattributes
或.git/info/attributes
文件。
这留下了最后一种可能性:情况2,Git认为文件是干净的(因为它是这样标记的),尽管它不是。克服这种情况的最简单方法是touch
文件(如果您有Unix/Linuxtouch
命令,请使用该命令)。这将文件上的修改时间戳设置为"0";现在";,这可能比保存在Git索引中的任何保存的修改时间戳(从"then"开始,几秒钟或更长时间)都要晚。
如果这些都不能找到或纠正问题,那么其他事情——一些非常神秘的事情,可能是Git错误——正在发生
1这太简单了:在某些情况下,Git的索引中已经有了一些东西,可以保留在原地。我们将忽略这些角落案例。
2至少在理论上,这是一种获得人们不断要求的东西的方法:拥有一个带有";本地配置";未提交的部分。不过,这样做也存在一些难以实现的问题。