status 这个操作是干啥的就不细解释了,这个不知道的话是不太适合看这套教程的,先去补补 git 相关的知识。这集的代码写起来还比较简单,在开动之前先复习一下基础概念。
HEAD、index、workdir:
HEAD 是当前所在的分支的最后一次 commit ,重点是已经 commit 了的状态。
index 是 git_index_add 之后的状态。但是要注意一下,这指的并不一定是使用命令行的 git add 命令完成。仅仅是加到 index 中就算了,并不需要完成 git_index_write 把内存中的状态写入磁盘。
workdir 还没加到 index 之前的都算在 workdir 的状态。
libgit 实现 status 大体上有两个方案,一个是简单一些,可以得到的信息也相对比较少的;另一个可以获得更详细的信息。我们从简单的开始
1. 简单方案
int status_cb(const char *path, unsigned int status_flags, void *payload)
{
std::cout << "path: " << path;
std::cout << "\nflag: " << status_flags << std::endl;
return 0;
}
error = git_status_foreach(rep, status_cb, nullptr);
通过 callback 获取状态信息,
path 文件的相对路径
status_flags 是状态的枚举值
payload 是一个透传参数,从 git_status_foreach 第三个参数原样传入
关于状态的枚举值,这个枚举的声明是这样的:
/**
* Status flags for a single file.
*
* A combination of these values will be returned to indicate the status of
* a file. Status compares the working directory, the index, and the
* current HEAD of the repository. The `GIT_STATUS_INDEX` set of flags
* represents the status of file in the index relative to the HEAD, and the
* `GIT_STATUS_WT` set of flags represent the status of the file in the
* working directory relative to the index.
*/
typedef enum {
GIT_STATUS_CURRENT = 0,
GIT_STATUS_INDEX_NEW = (1u << 0),
GIT_STATUS_INDEX_MODIFIED = (1u << 1),
GIT_STATUS_INDEX_DELETED = (1u << 2),
GIT_STATUS_INDEX_RENAMED = (1u << 3),
GIT_STATUS_INDEX_TYPECHANGE = (1u << 4),
GIT_STATUS_WT_NEW = (1u << 7),
GIT_STATUS_WT_MODIFIED = (1u << 8),
GIT_STATUS_WT_DELETED = (1u << 9),
GIT_STATUS_WT_TYPECHANGE = (1u << 10),
GIT_STATUS_WT_RENAMED = (1u << 11),
GIT_STATUS_WT_UNREADABLE = (1u << 12),
GIT_STATUS_IGNORED = (1u << 14),
GIT_STATUS_CONFLICTED = (1u << 15),
} git_status_t;
IGNORED 是被忽略的文件,表示这个文件满足 .gitignore 中的规则。
CONFLICTED 是合并之后有冲突的文件。
GIT_STATUS_INDEX 开头的是 index 相对于 HEAD 的状态。
GIT_STATUS_WT 开头的是 workdir 相对于 index 的状态。
2. 详细方案
git_status_options opt = GIT_STATUS_OPTIONS_INIT;
git_status_list *statuses = nullptr;
size_t count = 0;
opt.flags = GIT_STATUS_OPT_DEFAULTS;
error = git_status_list_new(&statuses, rep, &opt);
count = git_status_list_entrycount(statuses);
std::cout << "count: " << count << std::endl;
for (size_t i = 0; i < count; ++i)
{
const git_status_entry *entry = git_status_byindex(statuses, i);
std::cout << "status: " << entry->index_to_workdir->status
<< "\tpath: " << entry->index_to_workdir->new_file.path << std::endl;
}
git_status_list_free(statuses);
1) 初始化选项
2) 获取 git_status_list
3) 遍历 list 取出 git_status_entry
typedef struct {
git_status_t status;
git_diff_delta *head_to_index;
git_diff_delta *index_to_workdir;
} git_status_entry;
git_status_entry 除了有文件状态的标示,还带有 diff 的详细信息,而且严格区分了 HEAD 相对 index ,和 index 相对 workdir。
关于 diff 有很多要详细解释的东西,就放到下回了,我得花点时间读注释去了……