Удаление строк было выполнено, но вины нет

Некоторые строки были удалены из файла, и я хотел бы знать, когда и как это произошло.

Но: ошибочных коммитов не обнаружено. Действительно странно.

Вот git log, который показывает (последние изменения) фиксацию при добавлении строк:

$ git log --follow -p -- src/QsGeneralBundle/Repository/EmployeeRepository.php 
commit 80dc439aba2bf38ed7e95888dd21c1ba0f8960ce
Author: Benoit <[email protected]>
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

Есть какие-нибудь мысли по поводу этой тайны?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
88
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Предполагая, что src/QsGeneralBundle/Repository/EmployeeRepository.php никогда не переименовывался (или не входит в диапазон отображаемых коммитов), вы можете опустить --follow и вместо этого добавить --full-history и -m.

Здесь есть две проблемы:

  • Во-первых, изменение, которое вы ищете, вероятно, произошло во время слияния. Без -m (или некоторых других аргументов, которые также не являются значениями по умолчанию) git log игнорирует изменения все, зафиксированные во время слияния.

  • Во-вторых, когда вы указываете имя файла, такое как src/QsGeneralBundle/Repository/EmployeeRepository.php--follow или без него), Git включает Упрощение истории. Когда упрощение истории включено, Git просто не мешает посмотреть при некоторых коммитах. В частности, он не будет следовать за этапом слияния, которое (ошибочно, но см. сноску) не брать является изменением, которое, по вашему мнению, вносит слияние должен.

Следовательно, заставив упрощение истории сохранить все коммиты (--full-history) и заставив git log показывать коммиты слияния как дваgit diffs, вы сможете найти, где нужный коммит был (неправильно) удален.


Примечание: 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)

Git предполагает, что правые изменения — исправление ошибки — были вместо этого введение ошибки, которую человек, который сделал слияние, был умен и пропущен, сохраняя версию осталось на стороне, которая (по словам человека, выполняющего слияние, и следовательно, теперь, согласно Git, тоже) было «правильным». Фактически, этот коммит слияния был неправильно... но когда Git делает упрощение истории, Git предполагает, что это было правильно. Таким образом, на данный момент Git следует только левой части графа коммитов. Вы никогда не увидите исправление ошибки!

Единственный способ увидеть фиксацию с исправлением — избежать или отключить упрощение истории (пропустить имя файла или добавить --full-history). Но поскольку по умолчанию git log -p не будет отличать фиксацию слияния от фиксации исправления ошибки, даже этого недостаточно.


Дополнительная сноска: обратите внимание, что имена файлов в Git — это весь путь. Если файл назывался a/b/c.ext, а теперь называется a/d/c.ext, этот файл имеет два разных имени. Git не хранит каталоги/папки, что почему нельзя хранить пустой каталог. (Примечание к сноске: в каждом репозитории есть является пустой объект дерева, но его использование позже приводит к проблемам, поскольку Git продолжает пытаться преобразовать его в подмодуль — подробности см. в связанном вопросе.)

То, как Git справляется с настойчивостью вашего компьютера в использовании каталогов/папок, что позволяет вашей ОС предоставлять пустой, заключается в том, чтобы нянчиться с вашей ОС. Git просто извлекает файлы для фиксации, и если ваша ОС требует, чтобы файл с именем Git a/b/c.ext был создан как файл c.ext в папке b в папке a, тогда Git создает папку a, а затем папку a/b, чтобы создайте файл с именем a/b/c.ext. Если есть файлы нет, имя которых начинается с a/b, Git просто не Создайтеa/b в первую очередь.

В любом случае, фундаментальная проблема с --follow заключается в том, что его реализация — дрянной хак. Предположим, что история — т. е. обратная цепочка коммитов в репозитории — выглядит примерно так, с последующими коммитами справа:

...--I--J
         \
          M--N   <-- branch
         /
...--K--L

где каждая буква соответствует фактическому хэшу коммита. В коммите N у вас есть файл с именем a/d/c.ext; в коммите I этот же файл имеет имя a/b/c.ext. способ, который git log --follow a/d/c.ext обрабатывает это, должен просматривать каждую пару коммитов, шаг за шагом:

  • Сначала Git смотрит на пару M-N.

    Находится ли файл с именем a/b/c.ext в M и a/d/c.ext в N? Если это так, то, как только Git обработает пары J-M и L-M, Git остановка будет искать a/d/c.ext и вместо этого начнет искать a/b/c.ext (старое имя, а не текущее).

    Если нет — если это все еще a/d/c.ext в M — тогда, когда Git сравнивает J и M или сравнивает L и M, он будет искать a/d/c.ext (текущее имя, а не старое имя).

  • Затем Git просматривает либо пару J-M, либо L-M — или, если выполняется упрощение истории, а не принудительно нет, выбирает одну из пар для просмотра и на самом деле не смотрит на другую пару, а также не следует за этой частью ветви. .

    Если файл переименовывается в одной из этих пар, но не в другой, Git действительно не может с этим справиться. Без --full-history Git выберет одну ногу, чтобы следовать, и в какой-то степени притворится, что слияния нет, и обнаружение переименования может работать (хотя я не уверен, что это так, учитывая другие странности, которые git log отображает вокруг слияний). Однако, если файл не переименован в пару либо, все в порядке: файл по-прежнему имеет свое новое имя, поэтому, если мы принудительно --full-history, чтобы Git теперь должен был пройти обе части слияния, Git сделает это. Допустим, теперь он выполняет часть I-J:

  • Теперь Git сравнивает коммиты I и J. Файл был переименован здесь? Допустим, это было, переименованное сюда. По сути, Git говорит себе: Ага, давайте перестанем искать a/d/c.ext; с этого момента давайте искать a/b/c.ext. Когда Git сравнивает фиксацию I с тем, что предшествует фиксации I, это работает.

  • Но, проследив какое-то время за этой частью слияния, Git теперь — в любом случае под --full-history — возвращается и сравнивает коммиты K и L из части разное слияния. Git проверяет файл a/b/c.ext, так как теперь он считает, что это путь к файлу. Но файл по-прежнему имеет имя a/d/c.ext в это ветке слияния. В результате git log --follow ищет неправильный файл!

Чтобы все это работало, git log --follow нужно быть способ умнее, чем есть на самом деле. Все, что делает --follow, — это изменяет одно имя файла, который он ищет, и не помнит, что он сделал это в каком-то конкретном часть графа фиксации. Git должен каким-то образом связать изменение имени с обходом графа и «отменять» изменение всякий раз, когда оно возвращается «вверх» по графу (но Git на самом деле не поднимается вверх: на самом деле он просто помещает коммиты в приоритетную очередь, что означает нет места для размещения этой информации об изменении имени).

Если все изменения имени происходят в «правильных» местах, --follow и --full-historyмогу хорошо сочетаются. Например, если изменение имени на a/d/c.ext из старого имени a/b/c.ext происходит в паре M-N, так что все более старые коммиты имеют старое имя — тогда --follow и --full-history не возникнет проблем после обеих частей слияния: файл имеет только одно имя из M в истории, а --follow меняет одно имя в нужное время. Это происходит, когда изменение имени происходит в истории параллельно, в нескольких разных ветках слияния.

Как ни странно, он никогда не переименовывался (только родительский подкаталог много лет назад), но git log даже не включает эту фиксацию последних изменений, в то время как git log --follow включает...

theredled 20.07.2019 12:50

В любом случае, спасибо, добавление --full-history -m действительно показывает мне, что виновато слияние. Git сделал это автоматически: / могу ли я доверять автоматическим слияниям git? Или я всегда должен все перепроверять?

theredled 20.07.2019 12:54

То же самое было сделано для многих файлов

theredled 20.07.2019 13:23

Git не хранит каталоги, Git хранит только файлы. Если имя файла когда-то было a/b/c, а теперь a/d/c, файл был переименован: имя файла представляет собой полную строку. Это не каталог, это просто часть имени файла!

torek 20.07.2019 18:54

Что касается того, что произошло при слиянии, вы можете повторить слияния, чтобы увидеть, действительно ли это сделал Git; и/или вы можете просмотреть два отличия от трех коммитов, чтобы увидеть, что увидел Git, что может заставить Git сделать это. Могу поспорить, что Git объявил конфликт во время слияния, и кто-то использовал -X или -s, чтобы «исправить» конфликт, проигнорировав одну сторону слияния (или сделал то же самое в инструменте слияния).

torek 20.07.2019 18:55

Другие вопросы по теме