某些行已从文件中删除,我想知道它何时以及如何发生。
但是:没有错误的提交被发现。真的很奇怪。
这里是git log
,它显示(作为最后的更改)添加行时的提交:
$ git log --follow -p -- src/QsGeneralBundle/Repository/EmployeeRepository.php
commit 80dc439aba2bf38ed7e95888dd21c1ba0f8960ce
Author: Benoit <benoit.guchet@gmail.Com>
Date: Tue Jul 16 18:31:38 2019 +0200
Opti Doctrine #814
diff --git a/src/QsGeneralBundle/Repository/EmployeeRepository.php b/src/QsGeneralBundle/Repository/EmployeeRepository.php
index 7dfc2f963..a3e916690 100644
--- a/src/QsGeneralBundle/Repository/EmployeeRepository.php
+++ b/src/QsGeneralBundle/Repository/EmployeeRepository.php
@@ -10,12 +10,15 @@ namespace QsGeneralBundle\Repository;
*/
class EmployeeRepository extends BaseRepository
{
- public function findAllQb() {
- $qb = $this->createQueryBuilder('e')
+ public function findAllQb() {
+ $qb = $this->createQueryBuilder('e')
->innerJoin('e.Account', 'a')
- ->orderBy('a.firstname', 'ASC')
- ->addOrderBy('a.lastname', 'ASC')
- ->andWhere('a.isEnabled = TRUE');
+ ->leftJoin('a.SpecificRole', 'r')
+ ->leftJoin('a.Contractor', 'c')
+ ->orderBy('a.firstname', 'ASC')
+ ->addOrderBy('a.lastname', 'ASC')
+ ->andWhere('a.isEnabled = TRUE')
+ ->select('e, a, r, c');
return $qb;
}
现在这是文件的当前内容:
<?php
namespace QsGeneralBundle\Repository;
/**
* Created by IntelliJ IDEA.
* User: Benoît Guchet
* Date: 16/11/2016
* Time: 13:26
*/
class EmployeeRepository extends BaseRepository
{
public function findAllQb() {
$qb = $this->createQueryBuilder('e')
->innerJoin('e.Account', 'a')
->orderBy('a.firstname', 'ASC')
->addOrderBy('a.lastname', 'ASC')
->andWhere('a.isEnabled = TRUE');
return $qb;
}
}
没有git status
所示的本地更改:
$ git status src/QsGeneralBundle/Repository/EmployeeRepository.php
On branch master
Your branch is ahead of 'origin/master' by 11 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
关于这个奥秘有什么想法吗?
答案 0 :(得分:1)
假设src/QsGeneralBundle/Repository/EmployeeRepository.php
从未被重命名(或不在显示的提交范围内),则可以省略--follow
并添加--full-history
和{{1 }}。
这里有两个问题:
首先,您要查找的更改可能发生在合并期间。如果没有-m
(或其他不是默认值的参数),-m
会忽略合并期间提交的所有所有更改。
第二,当您指定诸如git log
(带或不带src/QsGeneralBundle/Repository/EmployeeRepository.php
)之类的文件名时,Git会打开 History Simplification 。当简化历史记录功能时,Git只需不必担心一些提交。特别是,它不会遵循合并的内容(错误地-但请参见脚注)不会接受您认为合并应进行的更改。
因此,通过强制简化历史记录以保留所有提交(--follow
)并强制--full-history
将合并提交显示为两个 git log
,您应该能够找到(错误地)删除了您想要的提交的位置。
脚注:Git假定每次合并的结果都是正确结果。也就是说,假设合并提交在其右侧传入分支更改时有错误修复,而在其左侧更改时根本没有更改。进一步假设进行合并的人放弃了错误修复程序:
git diff
Git 假定,右侧的更改(错误修复)是错误的介绍,进行合并的人很聪明并且被忽略了,保留 left 端版本(根据进行合并的人,因此根据Git现在也是如此)是“正确的”。实际上,该合并提交是错误 ...,但是当Git进行“历史简化”时,Git认为这是正确的。因此,此时Git仅遵循提交图的左侧。您永远不会看到错误修复!
查看带有修订的提交的唯一方法是避免或禁用“历史记录简化”(省略文件名,或添加o another commit (has bug)
|
* merge commit (has bug, person who merged dropped the fix)
|\
o | main line work (has bug)
| |
| o fix for bug
|/
o main line work (has bug)
)。但是由于默认情况下,--full-history
不会将合并提交与错误修复提交进行区分,即使那样还不够。
其他脚注:请注意,在Git中,文件名是整个路径。如果文件名为git log -p
,现在又命名为a/b/c.ext
,则该文件有两个不同的名称。 Git不存储目录/文件夹,即why you cannot store an empty directory。 (脚注的旁注:每个存储库中都有一个 空树对象,但是稍后使用它会导致问题,因为Git一直试图将其转换为子模块-有关详细信息,请参见链接的问题。)
Git处理您的计算机坚持使用目录/文件夹的方式(这是允许您的OS提供 empty 的方式)是捆绑您的OS。 Git只是提取文件进行提交,并且如果您的操作系统要求将Git名称为a/d/c.ext
的文件创建为文件夹a/b/c.ext
中的文件c.ext
。然后,在文件夹b
中创建一个文件夹a
,然后再创建文件夹a
,以创建一个名为a/b
的文件。如果没有名称以a/b/c.ext
开头的 文件,则Git首先不会 create a/b
。
无论如何,a/b
的基本问题在于其实现是一个俗气的黑客。假设历史记录(即存储库中的提交链向后看)看起来像这样,后来的提交向右:
--follow
每个字母代表一个实际的提交哈希。在提交...--I--J
\
M--N <-- branch
/
...--K--L
中,您有一个名为N
的文件;在提交a/d/c.ext
中,该文件的名称为I
。 a/b/c.ext
处理此问题的方式是查看每个提交对,一次只看一步:
首先,Git查看git log --follow a/d/c.ext
对。
在M-N
中名为a/b/c.ext
的文件在M
中名为a/d/c.ext
的文件吗?如果是这样,那么Git在N
和J-M
对上工作后,Git将停止寻找L-M
并开始,而不是寻找{{ 1}}(旧名称,而不是当前名称)。
如果不是(如果它仍然是a/d/c.ext
中的a/b/c.ext
,则当Git比较a/d/c.ext
和M
或比较J
和M
时,它将查找L
(当前名称,而不是旧名称)。
接下来,Git会查看M
或a/d/c.ext
对,或者,如果进行“历史简化”并且没有强制 not 进行选择,则选择一对去看,而不是去看另一对,也不会跟随分支的那条腿。
如果在其中一对中重命名了文件,但在另一对中未重命名,则Git确实无法处理。如果没有J-M
,Git将选择一条腿跟随,并在某种程度上假装没有合并,并且重命名检测可以正常工作(尽管我不确定,{{1 }}在合并周围显示)。但是,如果没有在 中对文件进行重命名,那么我们仍然很好:文件仍然具有新名称,因此如果我们强制L-M
,则Git现在必须遍历在合并的两条腿上,Git都会这样做。假设它现在执行--full-history
部分:
Now Git现在比较提交git log
和--full-history
。文件在这里重命名了吗? 假设我们在这里重命名了 。实际上,Git自言自语:哈哈,让我们停止寻找I-J
;从现在开始,让我们寻找I
。 。当Git将提交J
与提交a/d/c.ext
之前的内容进行比较时,就可以了。
但是,经过一段合并之后,Git现在(无论如何在a/b/c.ext
下)可以返回并比较来自<的提交I
和I
。合并的另一段。 Git会检查文件--full-history
,因为这是它现在认为文件具有的路径。 但是该文件在合并的此分支中仍具有K
名称。结果是L
正在寻找错误的文件!
要使所有这些工作正常进行,a/b/c.ext
必须比实际情况更聪明。 a/d/c.ext
所做的只是更改要查找的一个文件名,而且它不记得在提交图的某些特定 part 中这样做了。 Git需要以某种方式将名称更改与图遍历相关联,并且每当它返回到图形“上”时就“撤消”更改(但是Git并没有真正上调:它实际上只是将提交放入优先级队列,这意味着没有放置此名称更改信息的地方。
如果所有名称更改都发生在“正确的”位置,则git log --follow
和git log --follow
可以很好地混合。例如,如果将名称从旧名称--follow
更改为--follow
是在--full-history
对中进行的,那么 all 较旧的提交都具有旧名称—然后,a/d/c.ext
和a/b/c.ext
沿合并的两条腿都没有问题:该文件在历史上仅具有M-N
中的一个名称,而--follow
则更改了一个名称在正确的时间命名。正是在 parallel 历史中,在多个不同的合并分支中发生名称更改时,这才搞砸了。