libgit2使用教程(二) git add

主要内容:
1. git add <path>
2. git add .

示例代码:sample2

一、 open
上一篇初始化了一个 git 仓库,接下来开始使用我们本地的 git 仓库。几乎所有的操作都需要使用一个 git_repository 指针,所以第一步,我们先初始化这个指针。
如果是新创建一个仓库的话,使用上一篇的 git_repository_init 就可以了。如果是一个已有的仓库呢?
就用 git_repository_open 这个函数。这个函数很简单,两个参数,参数一是返回 git_repository 指针,参数二是仓库地址。

const char *path = "/Users/xiaochen/Documents/data";
git_repository *rep = nullptr;
int error = 0;
error = git_repository_open(&rep, path);

二、 add
add 就开始有些复杂了,我们要分情景讨论这个事。
1. add 指定文件
通过官方API我们找到了一个函数 git_index_add_bypath ,主要意思就是:通过指定 path 添加一个文件到 index [附一]
只有两个参数,参数一是 git_index 指针,参数二是指定文件的路径。
所以,我们要先拿到 git_index 的指针:

git_index* index = nullptr; 
git_repository_index(&index, rep);

拿到了 index 指针,就可以 add 了:

git_index_add_bypath(index, "file");

然后运行一下,没有报错,然后到我们的仓库调用 git status 看一下。

On branch masterInitial commit

Untracked files:
(use “git add …” to include in what will be committed)

file

nothing added to commit but untracked files present (use “git add” to track)

file 并没有被 add 进来,是什么原因呢?

其实,git_index_add_bypath 操作并没有失败,只不过它是对内存的操作,在程序结束的时候,并没有把内存中的 index 写到磁盘,如果要把 index 写到磁盘,需要调用一个函数:

/* Write the in-memory index to disk */ 
git_index_write(index);

好了,目前完整的 add 的代码就是:

git_index* index = nullptr; 

// get index 
git_repository_index(&index, rep); 

// git add file 
error = git_index_add_bypath(index, "file"); 
if (error < 0) 
{ 
    const git_error *e = giterr_last(); 
    std::cout << "Error: " << error << " / " << e->klass << " : " << e->message << std::endl;
} 
else 
{ 
    /* Write the in-memory index to disk */ 
    git_index_write(index); 
} 

// 
git_index_free(index);

2. add 全部
使用函数 git_index_add_all 可以把没有添加到 index 的改动全部添加到 index 中。写一个简单的测试代码:

git_index_add_all(index, nullptr, GIT_INDEX_ADD_DEFAULT, nullptr, nullptr); 
git_index_write(index);

有时候对于参数不知道到底要传什么,就可以先传个 null 或者 0,运行看程序给你报什么错,再根据具体的错误找解决方案。不过显然,这段代码的运行结果是符合我们的预期的,我们对这个仓库中所有文件的修改都被 add 到 index 中了。说明参数二 paths 传空,就相当于命令:
git add .
那么,后边两个参数的作用是什么的?
倒数第二个参数是一个函数指针 git_index_matched_path_cb ,而最后一个参数则是传递给这个回调函数的参数。
所以我们给 index 添加改动的时候,是可以通过这个回调函数获得一些信息的:

int index_matched_path_cb(const char *path, const char *matched_pathspec, void *payload)
{
    std::cout << "path: " << path << "\n";
    std::cout << "matched_pathspec: " << matched_pathspec << std::endl;
    return 0;
}

这个回调的参数一是有改动的文件路径,参数二是 git_index_add_all 的第二个参数中和这个文件路径匹配的 pathspec ,第三个参数是前边提到过的自定义参数。
最重要的是它的返回值:
0:正常添加
正数:跳过添加这个文件的改动
负数:直接报错返回,这个时候 git_index_add_all 将直接返回,返回值就是我们这个回调函数的返回值。

所以这个回调函数可以让我们根据自己的情况对批量添加做一个过滤。
然后,翻回头再说一下 git_index_add_all 的第二个参数[附二]。他是一个路径规则,不满足这个规则的文件将直接被跳过。也不会触发上边那个回调函数。满足规则的文件和对应的那一项规则,将成为回调函数的参数一和参数二。
所以调用的代码是这个样子的:

char *strs[1];
git_strarray paths = {nullptr, 0};
    
strs[0] = "dir/*";
paths.strings = strs;
paths.count = 1;
    
error = git_index_add_all(index, &paths, GIT_INDEX_ADD_DEFAULT, index_matched_path_cb, nullptr);
if (error < 0)
{
    const git_error *e = giterr_last();
    std::cout << "Error: " << error << " / " << e->klass << " : " << e->message << std::endl;
}
else
{
    /* Write the in-memory index to disk */
    git_index_write(index);
}

附一、解释一下 index
index 可以理解为一个存储区,存放被 add 进来的“改动”,add 的文件的改动被添加到 index ,commit 操作把这个 index 添加到本地仓库,可以通过 git rm —cached 从 index 中删除指定“文件”。只要不 commit 我们玩儿的就一直是同一个 index 。

附二、git_strarray
git_strarray 是一个结构体:

/** Array of strings */
typedef struct git_strarray {
    char **strings;
    size_t count;
} git_strarray;

strings 是一个字符串数组,count 是这个数组有多少个元素。
这个结构后边会经常用到,与多个路径相关的参数和返回值,都会使用这个结构。

《libgit2使用教程(二) git add》有一个想法

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

RSS
Follow by Email
YouTube
YouTube
Pinterest
fb-share-icon
LinkedIn
Share
VK
Weibo
WeChat
WhatsApp
Reddit
FbMessenger
Copy link
URL has been copied successfully!