"cannot set OID on symbolic reference" 尝试使用 libgit2 快进时
"cannot set OID on symbolic reference" when trying to fast-forward with libgit2
注意: 我标记了 C 和 C++ 因为 libgit2 是一个 C 库,我正在为常见的 git 命令编写一个 C++ 包装器.我们将在这里看到 C 和 C++ 代码,就我而言,如果我得到一个 并不重要面向C或C++的解决方案(如果需要我会自己改编)。
当分支可快进时(使用 libgit2).我只想在必要时执行合并。
我的策略如下(我删除了错误检查,......为了只针对基本要素并使代码尽可能简单):
// INFO: I assume here I already have an open repository in a "repo" variable.
// Do the fetch --> works fine
// ...
// Compare HEAD and FETCH_HEAD
git_oid head_id;
git_reference_name_to_id(&head_id, repo, "HEAD");
git_oid fetch_head_id;
git_reference_name_to_id(&fetch_head_id, repo, "FETCH_HEAD");
if(!git_oid_equal(&fetch_head_id, &head_id)) // A pull is needed
{
// Check if we can fast-forward or need a merge
git_annotated_commit * fetch_head_annotated_commit = nullptr;
git_annotated_commit_lookup(&fetch_head_annotated_commit, repo, &fetch_head_id);
git_merge_analysis_t an_out;
git_merge_preference_t pref_out;
git_merge_analysis(&an_out, &pref_out, repo, const_cast<const git_annotated_commit **>(&fetch_head_annotated_commit),1);
if(an_out & GIT_MERGE_ANALYSIS_FASTFORWARD) // A fast-forward is possible
{
git_reference * head_ref = nullptr;
git_reference_lookup(&head_ref, repo, "HEAD");
git_reference * new_head_ref = nullptr;
git_reference_set_target(&new_head_ref, head_ref, &fetch_head_id, "");
git_checkout_head(repo, nullptr);
git_reference_free(new_head_ref);
git_reference_free(head_ref);
}
else // A merge is needed
{
// Do the merge and create the related commit
// ...
}
git_annotated_commit_free(fetch_head_annotated_commit);
}
奇怪的是条件 if(an_out & GIT_MERGE_ANALYSIS_FASTFORWARD)
是 true
但是当我 运行 函数 git_reference_set_target(&new_head_ref, head_ref, &fetch_head_id, "");
时,我得到以下错误:
"cannot set OID on symbolic reference"
我进行了研究,我在 source code of libgit2 in refs.c 中找到了您可以在下面看到的内容:
static int ensure_is_an_updatable_direct_reference(git_reference *ref)
{
if (ref->type == GIT_REFERENCE_DIRECT)
return 0;
git_error_set(GIT_ERROR_REFERENCE, "cannot set OID on symbolic reference");
return -1;
}
int git_reference_set_target(
git_reference **out,
git_reference *ref,
const git_oid *id,
const char *log_message)
{
int error;
git_repository *repo;
assert(out && ref && id);
repo = ref->db->repo;
if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0)
return error;
return git_reference_create_matching(out, repo, ref->name, id, 1, &ref->target.oid, log_message);
}
通过阅读这段代码,我们可以看到问题是 ref
参数,在我的例子中是 "HEAD" 引用,不是一个 "updatable direct reference".
换句话说,没有找到从 "HEAD" 到 "FETCH_HEAD" 的直接路径(因为我通过了 fetch_head_id
).
我不明白的是,如果我是正确的,检查分支是否可以快进的方法是验证它是否存在 [=80= 之间的直接路径]和"FETCH_HEAD".
所以输入条件听到它说不是"updatable direct reference"在我心里似乎很矛盾。
我的问题是:我错过了什么?我误解了什么?(我知道这个问题很广泛,这就是为什么我提供了尽可能多的细节)。
如果有任何提示可以帮助我解决问题并使其正常运行,我将不胜感激。
今天早上我才发现自己很笨:)
在我的例子中,"HEAD" 是对 "refs/heads/master" 的符号引用。所以错误通知的是我需要传递直接引用,而不是别名。
注意: 我标记了 C 和 C++ 因为 libgit2 是一个 C 库,我正在为常见的 git 命令编写一个 C++ 包装器.我们将在这里看到 C 和 C++ 代码,就我而言,如果我得到一个 并不重要面向C或C++的解决方案(如果需要我会自己改编)。
当分支可快进时(使用 libgit2).我只想在必要时执行合并。
我的策略如下(我删除了错误检查,......为了只针对基本要素并使代码尽可能简单):
// INFO: I assume here I already have an open repository in a "repo" variable.
// Do the fetch --> works fine
// ...
// Compare HEAD and FETCH_HEAD
git_oid head_id;
git_reference_name_to_id(&head_id, repo, "HEAD");
git_oid fetch_head_id;
git_reference_name_to_id(&fetch_head_id, repo, "FETCH_HEAD");
if(!git_oid_equal(&fetch_head_id, &head_id)) // A pull is needed
{
// Check if we can fast-forward or need a merge
git_annotated_commit * fetch_head_annotated_commit = nullptr;
git_annotated_commit_lookup(&fetch_head_annotated_commit, repo, &fetch_head_id);
git_merge_analysis_t an_out;
git_merge_preference_t pref_out;
git_merge_analysis(&an_out, &pref_out, repo, const_cast<const git_annotated_commit **>(&fetch_head_annotated_commit),1);
if(an_out & GIT_MERGE_ANALYSIS_FASTFORWARD) // A fast-forward is possible
{
git_reference * head_ref = nullptr;
git_reference_lookup(&head_ref, repo, "HEAD");
git_reference * new_head_ref = nullptr;
git_reference_set_target(&new_head_ref, head_ref, &fetch_head_id, "");
git_checkout_head(repo, nullptr);
git_reference_free(new_head_ref);
git_reference_free(head_ref);
}
else // A merge is needed
{
// Do the merge and create the related commit
// ...
}
git_annotated_commit_free(fetch_head_annotated_commit);
}
奇怪的是条件 if(an_out & GIT_MERGE_ANALYSIS_FASTFORWARD)
是 true
但是当我 运行 函数 git_reference_set_target(&new_head_ref, head_ref, &fetch_head_id, "");
时,我得到以下错误:
"cannot set OID on symbolic reference"
我进行了研究,我在 source code of libgit2 in refs.c 中找到了您可以在下面看到的内容:
static int ensure_is_an_updatable_direct_reference(git_reference *ref) { if (ref->type == GIT_REFERENCE_DIRECT) return 0; git_error_set(GIT_ERROR_REFERENCE, "cannot set OID on symbolic reference"); return -1; } int git_reference_set_target( git_reference **out, git_reference *ref, const git_oid *id, const char *log_message) { int error; git_repository *repo; assert(out && ref && id); repo = ref->db->repo; if ((error = ensure_is_an_updatable_direct_reference(ref)) < 0) return error; return git_reference_create_matching(out, repo, ref->name, id, 1, &ref->target.oid, log_message); }
通过阅读这段代码,我们可以看到问题是 ref
参数,在我的例子中是 "HEAD" 引用,不是一个 "updatable direct reference".
换句话说,没有找到从 "HEAD" 到 "FETCH_HEAD" 的直接路径(因为我通过了 fetch_head_id
).
我不明白的是,如果我是正确的,检查分支是否可以快进的方法是验证它是否存在 [=80= 之间的直接路径]和"FETCH_HEAD".
所以输入条件听到它说不是"updatable direct reference"在我心里似乎很矛盾。
我的问题是:我错过了什么?我误解了什么?(我知道这个问题很广泛,这就是为什么我提供了尽可能多的细节)。
如果有任何提示可以帮助我解决问题并使其正常运行,我将不胜感激。
今天早上我才发现自己很笨:)
在我的例子中,"HEAD" 是对 "refs/heads/master" 的符号引用。所以错误通知的是我需要传递直接引用,而不是别名。