summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Straub <bstraub@github.com>2012-07-27 20:29:06 -0700
committerBen Straub <bstraub@github.com>2012-07-27 20:31:05 -0700
commitb31667fb695dab0510cc5fc259e0569ff2a2ef41 (patch)
tree859bd97b8f4ec70a9605385fadea1da108556541
parent4d83399d35f0d3d489c50f2358bd5481a90ddce5 (diff)
downloadlibgit2-b31667fb695dab0510cc5fc259e0569ff2a2ef41.tar.gz
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_*.
-rw-r--r--include/git2/checkout.h23
-rw-r--r--src/checkout.c34
-rw-r--r--src/clone.c21
-rw-r--r--tests-clar/checkout/checkout.c70
-rw-r--r--tests-clar/resources/testrepo/.gitted/objects/16/8e4ebd1c667499548ae12403b19b22a5c5e925bin0 -> 147 bytes
-rw-r--r--tests-clar/resources/testrepo/.gitted/objects/62/eb56dabb4b9929bc15dd9263c2c733b13d2dccbin0 -> 50 bytes
-rw-r--r--tests-clar/resources/testrepo/.gitted/objects/66/3adb09143767984f7be83a91effa47e128c735bin0 -> 19 bytes
-rw-r--r--tests-clar/resources/testrepo/.gitted/objects/cf/80f8de9f1185bf3a05f993f6121880dd0cfbc9bin0 -> 162 bytes
-rw-r--r--tests-clar/resources/testrepo/.gitted/refs/heads/dir1
9 files changed, 107 insertions, 42 deletions
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
@@ -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
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
--- /dev/null
+++ b/tests-clar/resources/testrepo/.gitted/objects/16/8e4ebd1c667499548ae12403b19b22a5c5e925
Binary files 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
--- /dev/null
+++ b/tests-clar/resources/testrepo/.gitted/objects/62/eb56dabb4b9929bc15dd9263c2c733b13d2dcc
Binary files 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
--- /dev/null
+++ b/tests-clar/resources/testrepo/.gitted/objects/66/3adb09143767984f7be83a91effa47e128c735
Binary files 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
--- /dev/null
+++ b/tests-clar/resources/testrepo/.gitted/objects/cf/80f8de9f1185bf3a05f993f6121880dd0cfbc9
Binary files 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