gpt4 book ai didi

git - 使用 libgit2 checkout 分支时如何更新工作树?

转载 作者:行者123 更新时间:2023-12-02 04:50:00 26 4
gpt4 key购买 nike

我正在尝试使用旧版本的 libgit2(没有 checkout.h)实现类似 checkout 的功能。

首先,我在分支 A 上,它看起来像:

Branch:
A A0 --- A1
/
Master M

每次提交都会创建一个同名文件,例如,标记为 A1 的提交会创建一个文件 A1。如果此时我查看 gitk,一切看起来都完全符合我的要求。

现在我创建一个新分支,B ,我想添加一个 promise :

Branch:
A A0 --- A1
/
Master M
\
B B0

但是,当我使用我的代码“ checkout ”B 时,它使 A0 和 A1 未被跟踪,而不是像我期望的那样删除它们:

(B)$ git status
# On branch B
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# A0
# A1
nothing added to commit but untracked files present (use "git add" to track)

因此,我认为我的 checkout 代码中缺少某些内容,即:

void Checkout(const char *branch_name, git_commit *branch_tip) {
// Update index & tree
git_tree *tree;
git_commit_tree(&tree, branch_tip);
git_index_read_tree(index_, tree);
git_index_write(index_);
git_tree_free(tree);

// Reset head
string branch_ref = string("refs/heads/") + branch_name;
git_reference *head;
git_reference_lookup(&head, repo_, kGitHeadFile);
git_reference_set_target(head, branch_ref.c_str());
git_reference_free(head);
}

(请注意,我实际上正在检查真实代码中的每一行的返回码,并且所有内容都返回 0,只是不想把这里的事情搞得一团糟。)

据我所知,此代码与 git 文档描述的内容相匹配 git checkout <branch> :

To prepare for working on <branch>, switch to it by updating
the index and the files in the working tree, and by pointing
HEAD at the branch.

我需要运行一些...“更新工作树”命令吗?

最佳答案

如果你必须自己写这个,你可以看看libgit2中现有实现使用的基本策略。让我们考虑实现强制 check out (即忽略工作目录中的任何修改文件),因为这是一个简单得多的情况。

您没有提到您的 libgit2 有多旧。假设您可以访问 diff 功能,我将编写以下内容,我什至会使用一些更新的访问器函数来获取 diff 数据。如果这些访问器函数在您的版本中不可用,您可能需要重新设计以使用回调函数。我相信,如果核心差异功能不可用,那么您的 libgit2 太旧了,无法用于此目的。

您需要考虑您来自的旧 HEAD 和您要移动到的新 HEAD,以便了解哪些文件将被删除(相对于工作目录中未跟踪的文件)。在 libgit2 中最简单的事情是这样的:

git_diff_list *diff;
git_diff_delta *delta;
git_blob *blob;
size_t i;
FILE *fp;

git_diff_tree_to_tree(&diff, repo, from_tree, to_tree, NULL);

for (i = 0; i < git_diff_num_deltas(diff); ++i) {
git_diff_get_patch(NULL, &delta, diff, i);

switch (delta->status) {
case GIT_DELTA_ADDED:
case GIT_DELTA_MODIFIED:
/* file was added or modified between the two commits */
git_blob_lookup(&blob, repo, &delta->new_file.oid);

fp = fopen(delta->new_file.path, "w");
fwrite(git_blob_rawdata(blob), git_blob_rawsize(blob), 1, fp);
fclose(fp);

git_blob_free(blob);
break;

case GIT_DELTA_DELETED:
/* file was removed between the two commits */
unlink(delta->old_file.path);
break;

default:
/* no change required */
}
}

git_diff_list_free(diff);

/* now update the index with the tree we just wrote out */
git_index_read_tree(index, to_tree);
git_index_write(index);

/* and do the other stuff you have to update the HEAD */

上面的实际代码有很多问题需要您解决:

  1. delta->new_file.pathdelta->old_file.path 中的路径是相对于版本库的工作目录,而不是当前工作目录进程,因此打开和取消链接文件的调用需要相应地调整路径
  2. 代码根本不处理目录。在打开文件之前,您必须创建包含该文件的目录。删除文件后,如果它是目录中的最后一个文件,则必须删除包含该文件的目录。如果您有一个分支,其中一个目录变成一个常规文件,反之亦然,您将必须在添加之前处理删除。
  3. 代码不做任何错误检查,这是个坏主意
  4. 此代码忽略索引中未决的更改和工作目录中的修改。但我们谈论的是强制 checkout ,所以你得到你得到的。
  5. 上面的代码是我随手写的,所以可能有错别字等。

根据您的用例,也许可以忽略类型更改(即变成 blob 的目录等)并且模拟 --force 可能是可以接受的。如果没有,那么这真的开始变成大量代码。

关于git - 使用 libgit2 checkout 分支时如何更新工作树?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19034971/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com