且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

用libgit2卸载文件

更新时间:2023-12-04 22:33:34

请记住,Git是基于快照的,因此索引中的任何内容都将被提交。

没有任何停顿行动本身,因为它是依赖于上下文的。如果该文件是新的,那么删除它就是你做什么来取消它。否则,暂停和暂存操作是相同的操作,区别在于您在条目中使用的blob是该文件的旧版本。



由于您要移动文件回到他们在HEAD中的状态,应该不需要使用diff,而是拿起HEAD树并在那里查找你想要的条目(尽管从一瞥中我看不到包含 git_tree_entry_bypath()



如果我们写出一个糟糕的索引版本,那肯定是库中的一个bug,你打开一个问题,我们可以尝试重现它?


Using objective-git and libgit2 it has been fairly easy to stage a file ready for commit:

GTIndex *repoIndex = [self.repository indexWithError:&error];

[repoIndex removeFile:path error:&error];

if (status != GTFileStatusIgnored && status != GTFileStatusWorkingDeleted) {
    // Now add the file to the index
    [repoIndex addFile:path error:&error];
}

[repoIndex write:&error];

However un-staging a file is proving to be a tad more tricky. Simply removing it from the repository's index doesn't work as git then thinks the file has been deleted which makes sense. It seems what I need to do is change the index entry in the index to the one it was before it was staged.

I have tried doing the following, using diff to get the old diff delta and constructing a git_index_entry from that and inserting it:

GTIndex *repoIndex = [self.repository indexWithError:&error];
GTBranch *localBranch = [self.repository currentBranchWithError:&error];
GTCommit *localCommit = [localBranch targetCommitAndReturnError:&error];

GTDiff *indexCommitDiff = [GTDiff diffIndexFromTree:localCommit.tree inRepository:self.repository options:nil error:&error];

// Enumerate through the diff deltas until we get to the file we want to unstage
[indexCommitDiff enumerateDeltasUsingBlock:^(GTDiffDelta *delta, BOOL *stop) {

    NSString *deltaPath = delta.newFile.path;

    // Check if it matches the path we want to usntage
    if ([deltaPath isEqualToString:path]) {
        GTDiffFile *oldFile = delta.oldFile;

        NSString *oldFileSHA = oldFile.OID.SHA;
        git_oid oldFileOID;
        int status = git_oid_fromstr(&oldFileOID, oldFileSHA.fileSystemRepresentation);

        git_index_entry entry;
        entry.mode = oldFile.mode;
        entry.oid = oldFileOID;
        entry.path = oldFile.path.fileSystemRepresentation;

        [repoIndex removeFile:path error:&error];

        status = git_index_add(repoIndex.git_index, &entry);

        [repoIndex write:&error];
    }
}];

However this leaves the git index in a corrupt state resulting in any git command logging a fatal error:

fatal: Unknown index entry format bfff0000
fatal: Unknown index entry format bfff0000     

What is the correct way to un-stage a file using libgit2?

Remember that Git is snapshot-based, so whatever is in the index at commit time will be what's committed.

There is no unstage action by itself, as it's context-dependent. If the file is new, then removing it is what you do to unstage it. Otherwise, unstaging and staging are the same operation, with the difference that the blob you use in the entry is the old version of the file.

Since you want to move files back to their state in HEAD, there shouldn't be a need to use diff, but take the tree of HEAD and look up the entries you want there (though from a quick glance, I don't see objective-git wrapping git_tree_entry_bypath())

If we write out a bad version of the index, that's definitely a bug in the library, could you open an issue so we can try to reproduce it?