Commit b31667fb by Ben Straub

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_*.
parent 4d83399d
......@@ -35,26 +35,31 @@ typedef struct git_checkout_opts {
} git_checkout_opts;
/**
* Updates files in the working tree to match the index.
* 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_index(git_repository *repo,
git_checkout_opts *opts,
git_indexer_stats *stats);
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 the commit pointed to by HEAD.
* Updates files in the working tree to match a commit pointed to by a ref.
*
* @param repo repository to check out (must be non-bare)
* @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_head(git_repository *repo,
git_checkout_opts *opts,
git_indexer_stats *stats);
GIT_EXTERN(int) git_checkout_reference(git_reference *ref,
git_checkout_opts *opts,
git_indexer_stats *stats);
/** @} */
GIT_END_DECL
......
......@@ -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;
}
......
......@@ -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");
}
cf80f8de9f1185bf3a05f993f6121880dd0cfbc9
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment