Libgit2sharp: Вопрос: Как получить последний коммит, затронувший данный файл

Созданный на 18 нояб. 2011  ·  38Комментарии  ·  Источник: libgit2/libgit2sharp

Всем привет.

Я ищу метод, который вернет последнюю фиксацию, затронувшую данный файл.

Я просмотрел API, но не нашел метода, который, похоже, это делает.

Первый вопрос: было ли решение упущено из виду?
Второй вопрос: как получить последний коммит?

Спасибо.

Самый полезный комментарий

@Флоникс ,

Привет. Похоже, вы после чего-то вроде git log -1 --follow FILENAME

Первый вопрос: было ли решение упущено из виду?

Нет. Это еще не реализовано.

Второй вопрос: как получить последний коммит?

Очень просто. Это двухэтапный процесс:

Шаг первый:

  • Создавайте неудачные тесты, которые вы хотели бы видеть пройденными

Шаг второй:

  • Из имени файла извлеките Sha1 соответствующего большого двоичного объекта в базе данных объектов.
  • ... какой-то код...
  • Рекурсивно пройтись по родительским коммитам Head (остерегайтесь слияний)

    • Обнаружение переименований (один и тот же Sha, разные имена (остерегайтесь варианта использования дублирования файлов))

    • ... больше кода ...

    • Выявление изменений (одно и то же имя, разные Shas)

    • ... найти несколько новых тестов угловых случаев для обработки. Добавьте их...

    • ... все еще кодирую ...

  • Найдите хорошее имя API, чтобы обернуть это :)
  • Нажмите на новую ветку и откройте запрос на слияние
  • Разблокируйте достижение "Отличный вклад!" :здорово:

Все 38 Комментарий

@Флоникс ,

Привет. Похоже, вы после чего-то вроде git log -1 --follow FILENAME

Первый вопрос: было ли решение упущено из виду?

Нет. Это еще не реализовано.

Второй вопрос: как получить последний коммит?

Очень просто. Это двухэтапный процесс:

Шаг первый:

  • Создавайте неудачные тесты, которые вы хотели бы видеть пройденными

Шаг второй:

  • Из имени файла извлеките Sha1 соответствующего большого двоичного объекта в базе данных объектов.
  • ... какой-то код...
  • Рекурсивно пройтись по родительским коммитам Head (остерегайтесь слияний)

    • Обнаружение переименований (один и тот же Sha, разные имена (остерегайтесь варианта использования дублирования файлов))

    • ... больше кода ...

    • Выявление изменений (одно и то же имя, разные Shas)

    • ... найти несколько новых тестов угловых случаев для обработки. Добавьте их...

    • ... все еще кодирую ...

  • Найдите хорошее имя API, чтобы обернуть это :)
  • Нажмите на новую ветку и откройте запрос на слияние
  • Разблокируйте достижение "Отличный вклад!" :здорово:

@nulltoken ,

Это именно то, что я ищу.
Я надеялся, что это уже реализовано...

посмотрю через несколько дней. Может быть, я могу решить это.

Спасибо пока...

Привет, @Flonix , пожалуйста, взгляни на нашу дискуссию с @nulltoken на StackOverflow . Я планирую реализовать подход, который я упоминал там, и поделиться с вами Gist .

Привет, @shytikov ,

так что у нас одинаковые намерения ;-)
В настоящее время я читаю (и заканчиваю) свою книгу GIT. У меня были некоторые пробелы в отношении внутренних записей GIT Tree и Blob.

Пожалуйста, дайте мне знать, когда вы начнете внедрять.
Я надеюсь, что у меня будет время реализовать (неудачный) тест в течение следующих нескольких дней.

Некоторые самые первые мысли об API:

  • Параметр Commit startCommit , определяет, с чего начать обход истории
  • Параметр string filePath определяет, какой файл мы будем искать
  • Параметр int maxCommits , определяет, когда остановить обход истории
  • Результат: список (затронутых) коммитов, максимальная длина результирующего списка maxCommits

Все еще отсутствует: хорошее имя для имени метода...

@Flonix , @nulltoken

Я провел вечер, анализируя код (это было чудесное время, правда!) и задал вам следующие вопросы:

  • Чтобы сделать все правильно, нам нужно реализовать на уровне C коммит в репозиторий libgit2 , но это займет время (и хождение по тонкому льду C). Является ли идеологически правильным делать обновления только для библиотеки libgit2sharp ?
  • Даже если мы решим обновить только libgit2sharp , возникает вопрос, должны ли мы реализовать фильтрацию по имени файла как часть класса фильтра фиксации (используется в методе QueryBy коллекции Commits ), что более близко к идеологии libgit2 , или поставить фильтрацию по имени файла как свойство _History_ или _Commits_ (например) объекта IndexEntry , что будет больше похоже на объектно-ориентированный подход?

Я сильно запутался, так как обновление метода QueryBy приводит либо к уродливому коду (реализация IEnumerable просто передает вызовы C-бэкэнду, и изменить его поведение под наши нужды будет сложно), либо обновление IndexEntry сделает libgit2sharp не таким тонким прокси к бэкэнду C...

Можете ли вы поделиться своей мыслью?

Ааа!!!

Кто-то сказал: «Независимо от того, насколько крут ваш код, вам будет стыдно, что вы написали его шесть месяцев спустя». Это относится и к сообщениям в системе отслеживания проблем. За исключением того, что вы чувствуете стыд намного быстрее :)

Мы получили класс RepositoryExtensions !!! Идеальное место для такого кода!

@шитиков , @nulltoken

Я думаю, мы должны сделать libgit2sharp как можно тоньше.
Но это не исключает, что нам придется обновлять/модифицировать и libgit2sharp...

Я не уверен, есть ли у libgit2 какая-то поддержка history walking . Я еще не очень хорошо знаком с кодом libgit2.
Так что я должен взглянуть на него...

@Flonix , у него есть revison walking API, позволяющий вам ограничить коллекцию коммитов _date_, _branch_, _tag_ и, возможно, чем-то еще. Но не _имя_файла_.

Как я понял из ответа @nulltoken , можно «предварительно ограничить» выбор фиксации на revison walking , а затем выполнить поиск в этой коллекции, например, с помощью _Linq_.

На данный момент я не думаю, что смогу придумать код C, ограничивающий выбор коммитов по имени файла (нужно потратить некоторое время на взлом libgit2), но легко добавить новый метод _ViewHistory_ в класс RepositoryExtensions .

Является ли этот подход способом libgit2sharp?

@Flonix , пожалуйста, взгляните на первый черновик в этой сути

Работа все еще продолжается, так как она не соответствует файлу, если он был переименован и изменен в том же коммите. И ти не в счет модификаций.

@шитиков ,

некоторые очень простые мысли после очень короткого взгляда на ваш код:

  • Выглядит неплохо
  • Чтобы ускорить и не ходить по всей (возможно очень длинной) истории можно ограничить максимальное количество коммитов в результате

(Если коммитов больше, чем n , вы можете начать дальнейший поиск с последнего коммита в результате, поэтому вам не нужно просматривать уже найденные коммиты...)

Вопрос 1 : Да, вы проходите через все коммиты, но упорядочены ли они?

Вопрос 2 : Не уверен, что насчет слияний...
Это зависит от вопроса 1...
Если они заказаны... Какой коммит-родитель будет взят для продолжения поиска?
Если они не заказаны... Возможно, нам придется их заказать ;-)

@Flonix , спасибо!

Остается много открытых вопросов, и они в основном касаются бэкэнда C...

Для ускорения кода нужно сделать две вещи:

  • Добавить переменную maxCommits ;
  • Остановить итерацию, если соответствующий SHA или путь не найден (файл отсутствует в репозитории — будет добавлен в следующем коммите);

Что касается упорядочивания коммитов... Это легко сделать, используя следующий синтаксис:

 foreach (Commit c in repository.Commits.QueryBy(filter))
 { ... }

Но это означает, что нам нужно передать методу filter . И поскольку я вижу дизайн libgit2sharp, было бы лучше реализовать это как часть Filter . Добавьте в этот класс еще два поля: IndexEntry (объект, содержащий как SHA, так и путь к файлу) и MaxCommits , чтобы ограничить их количество. И сделать результаты зависимыми от их значений.

Но чтобы сделать это правильно, нам нужно изменить код C, потому что IQueryableCommitCollection довольно тесно связан с нативными вызовами.

Что касается слияний, я не знаю... это определенно стоит проверить :)

@Flonix , @nulltoken ,

не могли бы вы посоветовать мне, как пропустить слияния при получении истории коммитов для файла. Кажется, SHA файла меняется, хотя на самом деле он не менялся. Есть ли общий подход к этому? Я не хочу запускать двоичное сравнение для файловых BLOB-объектов...

@Flonix , сегодня утром один «приятный» сюрприз: код, который я написал, недействителен для файлов, хранящихся в подпапках :) Объект « Дерево» содержит файлы только из корневой папки. Для просмотра других папок нам нужно проанализировать коллекцию деревьев, прикрепленных к текущему дереву! :здорово:

@шитиков

Да это правда. Для каждого (под)каталога существует одно дерево.
Вчера вечером я просмотрел код C libgit2. Реализована своего рода ревизионная ходьба.
На выходных посмотрю поближе.

@Flonix , я тоже хакаю. На данный момент я обнаружил, что можно _скрыть_ пакет коммитов от возврата пользователю. Но перед этим система должна определить список коммитов, в которых данный файл не изменялся, и передать эту информацию в качестве аргумента.

С нетерпением жду ответа от вас в понедельник.

@Flonix , я поднял этот вопрос в системе отслеживания проблем libgit2 .

@Flonix @shytikov Вау, эта ветка занята :)

Чтобы убедиться, что мы разделяем общее понимание, я настроил репозиторий для быстрого тестирования @ https://github.com/nulltoken/follow-test . Вики-страница описывает некоторые возможные варианты использования. Не стесняйтесь добавлять свои.

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

Как только вы получите, что код фильтрации C# возвращает правильные коммиты, было бы неплохо переупаковать его в метод CommitCollection.QueryBy() .

В конце концов, с точки зрения API, имя файла должно быть дополнительным необязательным свойством типа фильтра . Тестовый репозиторий будет перемещен в репозиторий LibGit2Sharp в каталоге Resources .

Пингуйте меня, если вам нужна помощь.

@шитиков

Каков ваш текущий статус?
Вы что-то реализовали?

@Flonix да, я взламываю внутренности git. Я пытаюсь понять, как я могу получить необходимую информацию из репозитория Git. На самом деле это превратилось для меня в большое развлечение: https://github.com/toolchain/IronGit (не бойтесь: это пока код качества пре-альфа).

Как только пойму, какой оптимальный способ создать журнал по имени файла, я интегрирую его в libgit2sharp .

@yorah Я не уверен, но я думаю, что Diff API может облегчить выполнение этой задачи ... Однако нам может понадобиться статус «Переименовано / Скопировано». Каково твое мнение?

Новичок во всем этом git, но начал работать над этими проблемами, чтобы изучить libgit2sharp. Не завершено/не прокомментировано/и т. д., но соответствует 2 из 3 вариантов использования в вариантах использования @nulltoken для последующего тестирования.

https://github.com/salerth/libgit2sharp/tree/follow

(Я должен добавить, что на данный момент у меня есть консольное приложение в качестве тестовой системы... оно уйдет, когда я проведу несколько тестов!)

Всем привет,

Были ли какие-либо разработки по этой функции? Где мы с этим. Если у меня будет время на этой/следующей неделе, я не против собрать что-нибудь вместе.

С уважением,
Фолкон

Привет @Folcon ,

Были ли какие-либо разработки по этой функции?

Хотя это обязательно произойдет в какой-то момент, libgit2 не реализует эту функцию.

Где мы с этим.

По этой теме ничего не объединено

Если у меня будет время на этой/следующей неделе, я не против собрать что-нибудь вместе.

Удивительный!

Меня отвлекли рабочие проекты, поэтому я так и не закончил это. В итоге он в основном работал, включая процент разницы в файлах для обнаружения переименования.

@nulltoken Спасибо за обновления.

@salerth Я предполагаю, что это здесь? https://github.com/salerth/libgit2sharp/tree/follow.

@Folcon Да, действительно, в основном в LibGit2Sharp/RepositoryExtensions.cs

Всем привет,

Извините, что я исчезла там, у меня наконец-то появилось немного времени на этой неделе, и я посмотрю на вещи, как я сказал ранее.

С уважением,
Фолкон

Всем привет,

Итак, я потратил некоторое время на просмотр всего, что здесь есть.

@salerth Какой вариант использования вам не хватает? Ваш вывод для последующего теста соответствует ожидаемым результатам @nulltoken https://github.com/nulltoken/follow-test/wiki .

Кажется, что вы это сделали, по крайней мере, на первый взгляд. Я собираюсь провести еще несколько тестов, чтобы убедиться, что это работает так, как я ожидаю, но где вы видели сбой? В противном случае максимум, что я могу предложить, это немного почистить его;)...

С уважением,
Фолкон

Привет, ребята,

Если вы чувствуете, что сейчас подходящий момент, как насчет того, чтобы перебазировать его на последнюю версию vNext , перенести тестовые примеры на фикстуру xUnit (может быть, FollowFixture.cs ?) и открыть PR?

У меня нет проблем с этим, я хотел бы, чтобы @salerth перезвонил на всякий случай, если мы пропустили какой-то вариант использования?

Нет, насколько мне известно, он работал во всех вариантах использования, которые я мог использовать. Все, что я оставил в своем списке дел для этого, — это модульные тесты, затем очистка, проверка того, что все в нужном месте и т. д. Я также пробовал только с довольно небольшими репозиториями, поэтому не был уверен в производительности на гораздо большей истории.

В основном я хотел, чтобы кто-то просто просмотрел его, так как я впервые столкнулся с внутренностями git, поэтому не был уверен, что это лучший способ снять шкуру с этого конкретного кота.

На самом деле мне интересно, есть ли способ обновить объект репо перед просмотром истории? Если это уже не происходит?

Я получаю сообщение "сгенерировать новое исключение LibGit2SharpException(String.Format("Не удается найти файл с именем "{0}" в текущем индексе.", filePath));" если репо недавно было обновлено в файловой системе, когда вызывается команда истории, и я не уверен, что это не вызвано устаревшим объектом, если это возможно? Это единственное объяснение, которое приходит на ум. Начну упаковывать код :)...

В основном индекс устарел, он не содержит записей о вновь добавленных объектах, хотя они и появляются в коммитах.

Кто-нибудь реализовал оригинальную функцию, о которой просил @Flonix ? Если нет, то я хотел бы помочь. Мне это тоже нужно.

Кто-нибудь реализовал оригинальную функцию, о которой просил @Flonix ? Если нет, то я хотел бы помочь. Мне это тоже нужно.

@ nmartin867 Не то, чтобы я знал.

@Folcon Похоже, мы можем извлечь выгоду из встроенной поддержки работы @arrbee в libgit2. См. этот комментарий для получения дополнительной информации.

Следующий код может получить последнюю фиксацию, которая изменила GitObject, а также Blob/Tree/GitLink.

using (var repo = new Repository(@"path\to\libgit2"))
{
    var path = @"src/blob.c";
    var commit = repo.Head.Tip;
    var gitObj = commit[path].Target;

    var set = new HashSet<string>();
    var queue = new Queue<Commit>();
    queue.Enqueue(commit);
    set.Add(commit.Sha);

    while (queue.Count > 0)
    {
        commit = queue.Dequeue();
        var go = false;
        foreach (var parent in commit.Parents)
        {
            var tree = parent[path];
            if (tree == null)
                continue;
            var eq = tree.Target.Sha == gitObj.Sha;
            if (eq && set.Add(parent.Sha))
                queue.Enqueue(parent);
            go = go || eq;
        }
        if (!go)
            break;
    }

    // output is: 49781a0  Blame: minor cleanup
    Console.WriteLine("{0}  {1}", commit.Sha.Substring(0, 7), commit.MessageShort);
}

Как обсуждалось на https://github.com/libgit2/libgit2/issues/495 , также мы можем реализовать последнюю выполненную фиксацию для древовидного представления, которое похоже на древовидное представление github.

Я бы предложил реализовать две функции на уровне libgit2, а не на уровне libgit2sharp, потому что libgit2 имеет более эффективный пул объектов, чем libgit2sharp.

Я бы предложил реализовать две функции на уровне libgit2, а не на уровне libgit2sharp, потому что libgit2 имеет более эффективный пул объектов, чем libgit2sharp.

:+1:

963 должен исправить это

Была ли эта страница полезной?
0 / 5 - 0 рейтинги