mirror of
https://git.proxmox.com/git/libgit2
synced 2026-01-01 19:51:38 +00:00
Checkout: add head- and ref-centric checkouts.
Renamed git_checkout_index to what it really was, and removed duplicate code from clone.c. Added git_checkout_ref, which updates HEAD and hands off to git_checkout_head. Added tests for the options the caller can pass to git_checkout_*.
This commit is contained in:
parent
4d83399d35
commit
b31667fb69
@ -34,28 +34,33 @@ typedef struct git_checkout_opts {
|
||||
int file_open_flags; /* default is O_CREAT | O_TRUNC | O_WRONLY */
|
||||
} git_checkout_opts;
|
||||
|
||||
/**
|
||||
* Updates files in the working tree to match the index.
|
||||
*
|
||||
* @param repo repository to check out (must be non-bare)
|
||||
* @param opts specifies checkout options (may be NULL)
|
||||
* @return 0 on success, GIT_ERROR otherwise (use git_error_last for information about the error)
|
||||
*/
|
||||
GIT_EXTERN(int) git_checkout_index(git_repository *repo,
|
||||
git_checkout_opts *opts,
|
||||
git_indexer_stats *stats);
|
||||
|
||||
/**
|
||||
* Updates files in the working tree to match the commit pointed to by HEAD.
|
||||
*
|
||||
* @param repo repository to check out (must be non-bare)
|
||||
* @param opts specifies checkout options (may be NULL)
|
||||
* @param stats structure through which progress information is reported
|
||||
* @return 0 on success, GIT_ERROR otherwise (use git_error_last for information about the error)
|
||||
*/
|
||||
GIT_EXTERN(int) git_checkout_head(git_repository *repo,
|
||||
git_checkout_opts *opts,
|
||||
git_indexer_stats *stats);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Updates files in the working tree to match a commit pointed to by a ref.
|
||||
*
|
||||
* @param ref reference to follow to a commit
|
||||
* @param opts specifies checkout options (may be NULL)
|
||||
* @param stats structure through which progress information is reported
|
||||
* @return 0 on success, GIT_ERROR otherwise (use git_error_last for information about the error)
|
||||
*/
|
||||
GIT_EXTERN(int) git_checkout_reference(git_reference *ref,
|
||||
git_checkout_opts *opts,
|
||||
git_indexer_stats *stats);
|
||||
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
||||
|
||||
@ -145,7 +145,7 @@ static int checkout_walker(const char *path, const git_tree_entry *entry, void *
|
||||
}
|
||||
|
||||
|
||||
int git_checkout_index(git_repository *repo, git_checkout_opts *opts, git_indexer_stats *stats)
|
||||
int git_checkout_head(git_repository *repo, git_checkout_opts *opts, git_indexer_stats *stats)
|
||||
{
|
||||
int retcode = GIT_ERROR;
|
||||
git_indexer_stats dummy_stats;
|
||||
@ -188,12 +188,14 @@ int git_checkout_index(git_repository *repo, git_checkout_opts *opts, git_indexe
|
||||
payload.repo = repo;
|
||||
if (git_repository_odb(&payload.odb, repo) < 0) return GIT_ERROR;
|
||||
|
||||
/* TODO: stats->total is never calculated. */
|
||||
|
||||
if (!git_repository_head_tree(&tree, repo)) {
|
||||
/* Checkout the files */
|
||||
if (!git_tree_walk(tree, checkout_walker, GIT_TREEWALK_POST, &payload)) {
|
||||
retcode = 0;
|
||||
git_index *idx;
|
||||
if (!(retcode = git_repository_index(&idx, repo))) {
|
||||
/* TODO: Make git_index_read_tree fill in stats->total */
|
||||
if (!(retcode = git_index_read_tree(idx, tree))) {
|
||||
retcode = git_tree_walk(tree, checkout_walker, GIT_TREEWALK_POST, &payload);
|
||||
}
|
||||
git_index_free(idx);
|
||||
}
|
||||
git_tree_free(tree);
|
||||
}
|
||||
@ -203,11 +205,25 @@ int git_checkout_index(git_repository *repo, git_checkout_opts *opts, git_indexe
|
||||
}
|
||||
|
||||
|
||||
int git_checkout_head(git_repository *repo, git_checkout_opts *opts, git_indexer_stats *stats)
|
||||
int git_checkout_reference(git_reference *ref,
|
||||
git_checkout_opts *opts,
|
||||
git_indexer_stats *stats)
|
||||
{
|
||||
/* TODO: read HEAD into index */
|
||||
git_repository *repo= git_reference_owner(ref);
|
||||
git_reference *head = NULL;
|
||||
int retcode = GIT_ERROR;
|
||||
|
||||
return git_checkout_index(repo, opts, stats);
|
||||
if ((retcode = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0)
|
||||
return retcode;
|
||||
|
||||
if ((retcode = git_reference_set_target(head, git_reference_name(ref))) < 0)
|
||||
goto gcr_cleanup;
|
||||
|
||||
retcode = git_checkout_head(git_reference_owner(ref), opts, stats);
|
||||
|
||||
gcr_cleanup:
|
||||
git_reference_free(head);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
21
src/clone.c
21
src/clone.c
@ -96,25 +96,8 @@ static int update_head_to_new_branch(git_repository *repo, const git_oid *target
|
||||
git_reference *head;
|
||||
if (!git_reference_lookup(&head, repo, GIT_HEAD_FILE)) {
|
||||
git_buf targetbuf = GIT_BUF_INIT;
|
||||
if (!git_buf_printf(&targetbuf, "refs/heads/%s", name) && /* TODO: "refs/heads" constant? */
|
||||
!git_reference_set_target(head, git_buf_cstr(&targetbuf))) {
|
||||
/* Read the tree into the index */
|
||||
git_commit *commit;
|
||||
if (!git_commit_lookup(&commit, repo, target)) {
|
||||
git_tree *tree;
|
||||
if (!git_commit_tree(&tree, commit)) {
|
||||
git_index *index;
|
||||
if (!git_repository_index(&index, repo)) {
|
||||
if (!git_index_read_tree(index, tree)) {
|
||||
git_index_write(index);
|
||||
retcode = 0;
|
||||
}
|
||||
git_index_free(index);
|
||||
}
|
||||
git_tree_free(tree);
|
||||
}
|
||||
git_commit_free(commit);
|
||||
}
|
||||
if (!git_buf_printf(&targetbuf, "refs/heads/%s", name)) {
|
||||
retcode = git_reference_set_target(head, git_buf_cstr(&targetbuf));
|
||||
}
|
||||
git_buf_free(&targetbuf);
|
||||
git_reference_free(head);
|
||||
|
||||
@ -38,12 +38,12 @@ void test_checkout_checkout__bare(void)
|
||||
{
|
||||
cl_git_sandbox_cleanup();
|
||||
g_repo = cl_git_sandbox_init("testrepo.git");
|
||||
cl_git_fail(git_checkout_index(g_repo, NULL, NULL));
|
||||
cl_git_fail(git_checkout_head(g_repo, NULL, NULL));
|
||||
}
|
||||
|
||||
void test_checkout_checkout__default(void)
|
||||
{
|
||||
cl_git_pass(git_checkout_index(g_repo, NULL, NULL));
|
||||
cl_git_pass(git_checkout_head(g_repo, NULL, NULL));
|
||||
test_file_contents("./testrepo/README", "hey there\n");
|
||||
test_file_contents("./testrepo/branch_file.txt", "hi\nbye!\n");
|
||||
test_file_contents("./testrepo/new.txt", "my new file\n");
|
||||
@ -57,7 +57,7 @@ void test_checkout_checkout__crlf(void)
|
||||
"README text eol=cr\n"
|
||||
"new.txt text eol=lf\n";
|
||||
cl_git_mkfile("./testrepo/.gitattributes", attributes);
|
||||
cl_git_pass(git_checkout_index(g_repo, NULL, NULL));
|
||||
cl_git_pass(git_checkout_head(g_repo, NULL, NULL));
|
||||
/* test_file_contents("./testrepo/README", "hey there\n"); */
|
||||
/* test_file_contents("./testrepo/new.txt", "my new file\n"); */
|
||||
/* test_file_contents("./testrepo/branch_file.txt", "hi\r\nbye!\r\n"); */
|
||||
@ -80,7 +80,7 @@ void test_checkout_checkout__symlinks(void)
|
||||
{
|
||||
/* First try with symlinks forced on */
|
||||
enable_symlinks(true);
|
||||
cl_git_pass(git_checkout_index(g_repo, NULL, NULL));
|
||||
cl_git_pass(git_checkout_head(g_repo, NULL, NULL));
|
||||
|
||||
#ifdef GIT_WIN32
|
||||
test_file_contents("./testrepo/link_to_new.txt", "new.txt");
|
||||
@ -101,7 +101,67 @@ void test_checkout_checkout__symlinks(void)
|
||||
cl_git_sandbox_cleanup();
|
||||
g_repo = cl_git_sandbox_init("testrepo");
|
||||
enable_symlinks(false);
|
||||
cl_git_pass(git_checkout_index(g_repo, NULL, NULL));
|
||||
cl_git_pass(git_checkout_head(g_repo, NULL, NULL));
|
||||
|
||||
test_file_contents("./testrepo/link_to_new.txt", "new.txt");
|
||||
}
|
||||
|
||||
void test_checkout_checkout__existing_file_options(void)
|
||||
{
|
||||
git_checkout_opts opts = {0};
|
||||
cl_git_mkfile("./testrepo/new.txt", "This isn't what's stored!");
|
||||
opts.existing_file_action = GIT_CHECKOUT_SKIP_EXISTING;
|
||||
cl_git_pass(git_checkout_head(g_repo, &opts, NULL));
|
||||
test_file_contents("./testrepo/new.txt", "This isn't what's stored!");
|
||||
opts.existing_file_action = GIT_CHECKOUT_OVERWRITE_EXISTING;
|
||||
cl_git_pass(git_checkout_head(g_repo, &opts, NULL));
|
||||
test_file_contents("./testrepo/new.txt", "my new file\n");
|
||||
}
|
||||
|
||||
void test_checkout_checkout__disable_filters(void)
|
||||
{
|
||||
git_checkout_opts opts = {0};
|
||||
cl_git_mkfile("./testrepo/.gitattributes", "*.txt text eol=crlf\n");
|
||||
/* TODO cl_git_pass(git_checkout_head(g_repo, &opts, NULL));*/
|
||||
/* TODO test_file_contents("./testrepo/new.txt", "my new file\r\n");*/
|
||||
opts.disable_filters = true;
|
||||
cl_git_pass(git_checkout_head(g_repo, &opts, NULL));
|
||||
test_file_contents("./testrepo/new.txt", "my new file\n");
|
||||
}
|
||||
|
||||
void test_checkout_checkout__dir_modes(void)
|
||||
{
|
||||
#ifndef GIT_WIN32
|
||||
git_checkout_opts opts = {0};
|
||||
struct stat st;
|
||||
git_reference *ref;
|
||||
|
||||
cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/heads/dir"));
|
||||
|
||||
opts.dir_mode = 0600;
|
||||
cl_git_pass(git_checkout_reference(ref, &opts, NULL));
|
||||
cl_git_pass(p_stat("./testrepo/a", &st));
|
||||
cl_assert_equal_i(st.st_mode & 0777, 0600);
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_checkout_checkout__file_modes(void)
|
||||
{
|
||||
git_checkout_opts opts = {0};
|
||||
struct stat st;
|
||||
|
||||
opts.file_mode = 0700;
|
||||
cl_git_pass(git_checkout_head(g_repo, &opts, NULL));
|
||||
cl_git_pass(p_stat("./testrepo/new.txt", &st));
|
||||
cl_assert_equal_i(st.st_mode & 0777, 0700);
|
||||
}
|
||||
|
||||
void test_checkout_checkout__open_flags(void)
|
||||
{
|
||||
git_checkout_opts opts = {0};
|
||||
|
||||
cl_git_mkfile("./testrepo/new.txt", "hi\n");
|
||||
opts.file_open_flags = O_CREAT | O_RDWR | O_APPEND;
|
||||
cl_git_pass(git_checkout_head(g_repo, &opts, NULL));
|
||||
test_file_contents("./testrepo/new.txt", "hi\nmy new file\n");
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
tests-clar/resources/testrepo/.gitted/refs/heads/dir
Normal file
1
tests-clar/resources/testrepo/.gitted/refs/heads/dir
Normal file
@ -0,0 +1 @@
|
||||
cf80f8de9f1185bf3a05f993f6121880dd0cfbc9
|
||||
Loading…
Reference in New Issue
Block a user