diff --git a/include/git2/checkout.h b/include/git2/checkout.h index 7a32cffa8..78367c29f 100644 --- a/include/git2/checkout.h +++ b/include/git2/checkout.h @@ -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 diff --git a/src/checkout.c b/src/checkout.c index 24d2149c8..81389a77a 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -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; } diff --git a/src/clone.c b/src/clone.c index 7ae32a067..9b7ab8945 100644 --- a/src/clone.c +++ b/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); diff --git a/tests-clar/checkout/checkout.c b/tests-clar/checkout/checkout.c index 53d95c410..856aca3fc 100644 --- a/tests-clar/checkout/checkout.c +++ b/tests-clar/checkout/checkout.c @@ -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"); +} diff --git a/tests-clar/resources/testrepo/.gitted/objects/16/8e4ebd1c667499548ae12403b19b22a5c5e925 b/tests-clar/resources/testrepo/.gitted/objects/16/8e4ebd1c667499548ae12403b19b22a5c5e925 new file mode 100644 index 000000000..d37b93e4f Binary files /dev/null and b/tests-clar/resources/testrepo/.gitted/objects/16/8e4ebd1c667499548ae12403b19b22a5c5e925 differ diff --git a/tests-clar/resources/testrepo/.gitted/objects/62/eb56dabb4b9929bc15dd9263c2c733b13d2dcc b/tests-clar/resources/testrepo/.gitted/objects/62/eb56dabb4b9929bc15dd9263c2c733b13d2dcc new file mode 100644 index 000000000..b669961d8 Binary files /dev/null and b/tests-clar/resources/testrepo/.gitted/objects/62/eb56dabb4b9929bc15dd9263c2c733b13d2dcc differ diff --git a/tests-clar/resources/testrepo/.gitted/objects/66/3adb09143767984f7be83a91effa47e128c735 b/tests-clar/resources/testrepo/.gitted/objects/66/3adb09143767984f7be83a91effa47e128c735 new file mode 100644 index 000000000..9ff5eb2b5 Binary files /dev/null and b/tests-clar/resources/testrepo/.gitted/objects/66/3adb09143767984f7be83a91effa47e128c735 differ diff --git a/tests-clar/resources/testrepo/.gitted/objects/cf/80f8de9f1185bf3a05f993f6121880dd0cfbc9 b/tests-clar/resources/testrepo/.gitted/objects/cf/80f8de9f1185bf3a05f993f6121880dd0cfbc9 new file mode 100644 index 000000000..7620c514f Binary files /dev/null and b/tests-clar/resources/testrepo/.gitted/objects/cf/80f8de9f1185bf3a05f993f6121880dd0cfbc9 differ diff --git a/tests-clar/resources/testrepo/.gitted/refs/heads/dir b/tests-clar/resources/testrepo/.gitted/refs/heads/dir new file mode 100644 index 000000000..e140e852b --- /dev/null +++ b/tests-clar/resources/testrepo/.gitted/refs/heads/dir @@ -0,0 +1 @@ +cf80f8de9f1185bf3a05f993f6121880dd0cfbc9