diff --git a/README.md b/README.md index 3a26a72..f08f87c 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,13 @@ * Add references/tags * add lazy write optimization to write_object + write test for it * Define TearDown to delete created files from testing -* conversion between relative to absolute path in interpreter code +* conversion between relative to absolute path in interpreter code [DONE] * git_path speedup optimization * implement git update-ref * fix memory leaks -- no delete after newing git object -* git reset --medium(aka default) = just change index file to point to HEAD commit -* git reset --hard = do above + walkTreeAndReplace on HEAD commit +* git reset --medium(aka default) = just change index file to point to HEAD commit [DONE] +* git reset --hard = do above + walkTreeAndReplace on HEAD commit [DONE] * git log: walk HEAD backwards , printing as you go along * filter * --stat = call "git status" between each commit @@ -30,7 +30,7 @@ * -a: show all branches * nothing: create a new branch and switch to it(Note this is different from default behavior) * git cat-file = take the hash and try to find the file. If found, read it in using read_file and print the contents. Otherwise throw not found error -* git commit +* git commit [DONE] * command * cat-file [DONE] diff --git a/src/lib/commands.cpp b/src/lib/commands.cpp index 46d5b3d..70ad50e 100644 --- a/src/lib/commands.cpp +++ b/src/lib/commands.cpp @@ -59,6 +59,13 @@ void cmd_commit(const std::vector& args){ git_commit(args[1]); } +void cmd_reset(const std::vector& args){ + if (args.size() == 0 || args[0] == "--mixed") + git_reset(false); + else + git_reset(true); +} + void git_cat_file(fs::path obj, const std::string& fmt){ fs::path repo = repo_find(fs::current_path()); GitObject* object = read_object(repo, object_find(repo, obj, fmt)); @@ -115,7 +122,23 @@ void git_commit(std::string commit_message){ // New commit, write to file and update HEAD GitCommit* new_commit_obj = new GitCommit(git_path, index_tree_hash, parent_commit_hash, commit_message); std::string new_commit_hash = write_object(new_commit_obj, true); - write_file(head_path, new_commit_hash); + /* TODO Write to master instead of HEAD */ + write_file(ref_resolve(head_path, true), new_commit_hash); +} + +void git_reset(bool hard){ + fs::path worktree = repo_find(fs::current_path()); + fs::path git_path = worktree / ".cpp-git"; + // Get tree_hash from HEAD + std::string head_commit_hash = ref_resolve(git_path / "HEAD"); + GitCommit* head_commit = dynamic_cast(read_object(git_path, head_commit_hash)); + std::string head_commit_tree_hash = head_commit->tree_hash; + write_file(git_path / "index", head_commit_tree_hash); + + if (hard){ + GitTree* tree = dynamic_cast(read_object(git_path, head_commit_tree_hash)); + walk_tree_and_replace(worktree, tree); + } } @@ -292,12 +315,14 @@ std::string read_project_folder_and_write_tree(const fs::path& adding_directory, return output; } -std::string ref_resolve(const fs::path& path) { +std::string ref_resolve(const fs::path& path, bool return_file_path) { std::string data = read_file(path); //No content if it's an initial commit if (data.size() == 0) return ""; if (data.rfind("ref: ", 0) == 0) - return ref_resolve(repo_find(path)/ ".cpp-git" / data.substr(5)); + return ref_resolve(repo_find(path)/ ".cpp-git" / data.substr(5), return_file_path); + else if (return_file_path) + return path; else return data; } diff --git a/src/lib/commands.hpp b/src/lib/commands.hpp index eb6352e..bae5ab0 100644 --- a/src/lib/commands.hpp +++ b/src/lib/commands.hpp @@ -26,12 +26,14 @@ void cmd_checkout(const std::vector& args); void cmd_commit(const std::vector& args); void cmd_show_ref(const std::vector &args); void cmd_hash_object(const std::vector &args); +void cmd_reset(const std::vector& args); // Actual functions executing commands void git_cat_file(fs::path obj, const std::string& fmt); void git_init(fs::path project_base_path); void git_checkout(std::string hash); void git_commit(std::string commit_message); void git_hash_object(fs::path path, const std::string& fmt); +void git_reset(bool hard); int test_function(void); @@ -39,6 +41,6 @@ std::string git_add_file(const fs::path& file_path); std::string read_project_folder_and_write_tree(const fs::path& adding_directory, bool root = false); std::string git_add_folder(const fs::path folder_path); -std::string ref_resolve(const fs::path& path); +std::string ref_resolve(const fs::path& path, bool return_file_path = false); std::unordered_map ref_list(const fs::path& base_path); #endif diff --git a/test/test.cpp b/test/test.cpp index 5497655..43eb3ac 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -402,50 +402,100 @@ TEST(GitCommand, git_init){ ASSERT_TRUE(fs::exists(git_path / "HEAD")); ASSERT_TRUE(fs::exists(git_path / "objects")); ASSERT_TRUE(fs::exists(git_path / "branches")); + ASSERT_TRUE(fs::exists(git_path / "index")); ASSERT_TRUE(fs::exists(git_path / "refs" / "tags")); ASSERT_TRUE(fs::exists(git_path / "refs" / "heads")); ASSERT_TRUE(fs::exists(git_path / "refs" / "heads" / "master")); ASSERT_EQ(read_file(git_path / "HEAD"), "ref: refs/heads/master"); } +void add_testing_file(fs::path file_path, std::string content){ + write_file(file_path, content); + cmd_add(std::vector{file_path}); + std::cout<<"Finish adding a new file: "<< file_path <{txtfile}); - ASSERT_TRUE(fs::exists(git_path / "index")); - std::cout<<"Finish adding a new file"<(read_object(git_path, hash)); + ASSERT_EQ(commit_obj->commit_message, message); + std::cout<<"Finish testing content"<(read_object(git_path, commit_obj->tree_hash)); + ASSERT_EQ(tree_obj->directory.size(), 1); + ASSERT_EQ(tree_obj->directory[0].name, filename); + GitBlob* blob_obj = dynamic_cast(read_object(git_path, tree_obj->directory[0].hash)); + ASSERT_EQ(blob_obj->data, content); } catch (char const *e) { std::cout << e << std::endl; throw e; } - std::cout<<"Finish invoking git commit"<(read_object(git_path, hash)); - ASSERT_EQ(commit_obj->commit_message, message); - std::cout<<"Finish testing content"<(read_object(git_path, commit_obj->tree_hash)); - ASSERT_EQ(tree_obj->directory.size(), 1); - ASSERT_EQ(tree_obj->directory[0].name, filename); - GitBlob* blob_obj = dynamic_cast(read_object(git_path, tree_obj->directory[0].hash)); - ASSERT_EQ(blob_obj->data, content); + fs::current_path(".."); } +TEST(GitCommand, git_reset){ + fs::path worktree = "test_git_reset"; + git_folder_setup(worktree); + worktree = fs::canonical(worktree); + fs::path git_path = worktree / ".cpp-git"; + fs::current_path(worktree);//change working directory + auto get_HEAD_tree_hash = [&](){ + std::string head_commit_hash = ref_resolve(git_path / "HEAD"); + return dynamic_cast(read_object(git_path, head_commit_hash))->tree_hash; + }; + try{ + // git add a new file + std::string filename = "test.txt", content = "Now test git_rest command"; + add_testing_file(worktree / filename, content); + + // get the initial tree hash + std::string HEAD_tree_hash = get_HEAD_tree_hash(); + // test git reset --mixed as default; + ASSERT_NE(read_file(git_path / "index"), HEAD_tree_hash); + cmd_reset(std::vector{}); + ASSERT_EQ(read_file(git_path / "index"), HEAD_tree_hash); + ASSERT_EQ(read_file(worktree / filename), content); + + // test git reset --hard + // commit to change HEAD + add_testing_file(worktree / filename, content); + cmd_commit(std::vector{"-m", "Init commit"}); + HEAD_tree_hash = get_HEAD_tree_hash(); + // Add modified file + std::string new_content = "Now test git_rest command with '--hard' option"; + add_testing_file(worktree / filename, new_content); + ASSERT_NE(read_file(git_path / "index"), HEAD_tree_hash); + cmd_reset(std::vector{"--hard"}); + // test if index is reset to head and files are replaced + ASSERT_EQ(read_file(git_path / "index"), HEAD_tree_hash); + ASSERT_EQ(read_file(worktree / filename), content); + } + catch (char const *e) + { + std::cout << e << std::endl; + throw e; + } + fs::current_path(".."); +}