gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 21:48:51 26 4
gpt4 key购买 nike

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

首先,我位于分支 A,如下所示:

Branch:
A A0 --- A1
/
Master M

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

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

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 中现有实现使用的基本策略。让我们考虑一下实现强制 checkout (即忽略工作目录中任何修改的文件),因为这是一个更简单的情况。

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

您需要考虑您来自的旧 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