Как удалить файл с помощью Objective-Git (libgit2)?

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

Вот примерный план соответствующей логики, которой в настоящее время следует моя программа при переключении «поэтапного» состояния файла:

- Fetch current GTIndex using GTRepository.indexWithError:
- Fetch GTIndexEntry for the file using GTIndex.entryWithPath:
- If the file has an index and GTIndexEntry.status == GTIndexEntryStatusUpdated:
    - Here's where I'm stuck

В соответствии с этим старым вопросом без ответа мне нужно найти информацию о файле в текущем HEAD. В таком случае я пришел к такой логике:

- Fetch head's GTReference using GTRepository.headReferenceWithError:
- If the reference resolves to a GTCommit object:
    - Fetch the GTTree using GTCommit.tree
    - Fetch the file's GTTreeEntry using GTTree.entryWithPath:error:
    - Stuck again! Do I convert GTTreeEntry to GTIndexEntry somehow?

Любое руководство приветствуется! Я не боюсь прыгать прямо в libgit2, если мне нужно (этот проект уже потребовал этого один или два раза), но, поскольку я работаю в Swift, я хотел бы избежать этого, если я могу, и «отменить» файл кажется такой стандартной процедурой, что я подумал, что не должен понимать, как классы Objective-Git связаны друг с другом.


person One Crayon    schedule 27.01.2016    source источник


Ответы (2)


Дав этому постоять немного дольше, я обнаружил, что на самом деле это намного проще, чем я это делал; вместо того, чтобы сравнивать дерево HEAD с активным индексом, вы можете просто использовать GTRepository.statusForFile:success:error: чтобы определить, является ли файл подготовленным, неподготовленным и т. д., а затем добавить, удалить или добавить большой двоичный объект для файла на основе что.

Оригинальный подход

(Возможно, он содержит полезную информацию для других в будущем.)

Это оказалось проще, чем казалось сначала, главным образом потому, что переход между GTTreeEntry и GTIndexEntry не нужен. Вместо этого мне просто нужно было захватить GTObject GTTreeEntry (который является большим двоичным объектом для файлов), а затем передать данные большого двоичного объекта в GTIndex.

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

- Fetch head's GTReference using GTRepository.headReferenceWithError:
- If the reference resolves to a GTCommit =>
    - Fetch the GTIndexEntry using GTIndex.entryWithPath:
    - If we have an index entry =>
        - Fetch the GTTree using GTCommit.tree
        - Fetch the GTTreeEntry using GTTree.entryWithPath:error:
        - If GTTreeEntry.SHA == GTIndexEntry.OID.SHA =>
            - GTIndex.addFile:error:
            (using this approach, it's possible to end up with identical
             tree and index entries, which means the file is unstaged)
        - Else if GTTreeEntry.type == GTObjectTypeBlob =>
            - Fetch GTBlob using GTTreeEntry.GTObject:error:
            - Pass GTBlob.data to GTIndex.addData:withPath:error:
        - Else if no GTTreeEntry => GTIndex.removeFile:error:
    - Else add the file/directory to the GTIndex (since we have no index entry)
    - Write the changes to disk with GTIndex.write:

Пара заметок в надежде, что они будут полезны будущим поколениям людей, бьющихся головой о в значительной степени недокументированной шкуре Objective-Git:

  • GTIndexEntry.status в этом сценарии бесполезен; он ссылается на некоторые флаги, которые используются внутри libgit2 во время построения индекса, но бесполезны для последующего определения состояния файлов. (Я, честно говоря, не уверен, почему эти флаги вообще выставляются Objective-Git)
  • Если вы хотите удалить/подставить все файлы в рабочем каталоге, вы можете попросить Objective-Git сделать большую часть работы, используя +diffIndexFromTree:inRepository:options:error: GTDiff.
person One Crayon    schedule 29.01.2016

Получив запись дерева из фиксации HEAD, вы можете извлечь из нее данные, чтобы заполнить новую запись индекса. Вам не нужно заполнять все поля, но по крайней мере установите path, mode и id. Вы можете скопировать их прямо из записи дерева. Затем используйте эквивалент git_index_add в target-git, чтобы обновить индекс новой записью.

Если файл не существовал в дереве HEAD (поскольку он не отслеживался ранее), вы можете просто удалить его из индекса с помощью git_index_remove_bypath.

person Jason Haslam    schedule 27.01.2016
comment
Спасибо, я рассмотрю эту возможность; в настоящее время завис над отдельной проблемой, которая прервала мое тестирование этого предложения (у меня удаление пути отлично работало для ранее неотслеживаемых файлов, но спасибо, что упомянули об этом тоже!). - person One Crayon; 29.01.2016