Commit 5edb846e by Vicent Martí

Merge pull request #1013 from ethomson/reset_merge

reset changes for merge
parents 6f6b0c01 03bdb2ad
...@@ -28,6 +28,7 @@ enum { ...@@ -28,6 +28,7 @@ enum {
GIT_EUSER = -7, GIT_EUSER = -7,
GIT_EBAREREPO = -8, GIT_EBAREREPO = -8,
GIT_EORPHANEDHEAD = -9, GIT_EORPHANEDHEAD = -9,
GIT_EUNMERGED = -10,
GIT_PASSTHROUGH = -30, GIT_PASSTHROUGH = -30,
GIT_ITEROVER = -31, GIT_ITEROVER = -31,
......
...@@ -569,6 +569,22 @@ GIT_EXTERN(int) git_repository_set_head_detached( ...@@ -569,6 +569,22 @@ GIT_EXTERN(int) git_repository_set_head_detached(
GIT_EXTERN(int) git_repository_detach_head( GIT_EXTERN(int) git_repository_detach_head(
git_repository* repo); git_repository* repo);
typedef enum {
GIT_REPOSITORY_STATE_NONE,
GIT_REPOSITORY_STATE_MERGE,
GIT_REPOSITORY_STATE_REVERT,
GIT_REPOSITORY_STATE_CHERRY_PICK,
} git_repository_state_t;
/**
* Determines the status of a git repository - ie, whether an operation
* (merge, cherry-pick, etc) is in progress.
*
* @param repo Repository pointer
* @return The state of the repository
*/
GIT_EXTERN(int) git_repository_state(git_repository *repo);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
#endif #endif
/*
* Copyright (C) 2009-2012 the libgit2 contributors
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "repository.h"
#include "buffer.h"
#include "merge.h"
#include "refs.h"
#include "git2/repository.h"
#include "git2/merge.h"
#include "git2/reset.h"
int git_merge__cleanup(git_repository *repo)
{
int error = 0;
git_buf merge_head_path = GIT_BUF_INIT,
merge_mode_path = GIT_BUF_INIT,
merge_msg_path = GIT_BUF_INIT;
assert(repo);
if (git_buf_joinpath(&merge_head_path, repo->path_repository, GIT_MERGE_HEAD_FILE) < 0 ||
git_buf_joinpath(&merge_mode_path, repo->path_repository, GIT_MERGE_MODE_FILE) < 0 ||
git_buf_joinpath(&merge_mode_path, repo->path_repository, GIT_MERGE_MODE_FILE) < 0)
return -1;
if (git_path_isfile(merge_head_path.ptr)) {
if ((error = p_unlink(merge_head_path.ptr)) < 0)
goto cleanup;
}
if (git_path_isfile(merge_mode_path.ptr))
(void)p_unlink(merge_mode_path.ptr);
if (git_path_isfile(merge_msg_path.ptr))
(void)p_unlink(merge_msg_path.ptr);
cleanup:
git_buf_free(&merge_msg_path);
git_buf_free(&merge_mode_path);
git_buf_free(&merge_head_path);
return error;
}
/*
* Copyright (C) 2009-2012 the libgit2 contributors
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_merge_h__
#define INCLUDE_merge_h__
#include "git2/types.h"
#define GIT_MERGE_MSG_FILE "MERGE_MSG"
#define GIT_MERGE_MODE_FILE "MERGE_MODE"
#define MERGE_CONFIG_FILE_MODE 0666
int git_merge__cleanup(git_repository *repo);
#endif
...@@ -28,8 +28,11 @@ ...@@ -28,8 +28,11 @@
#define GIT_PACKEDREFS_FILE_MODE 0666 #define GIT_PACKEDREFS_FILE_MODE 0666
#define GIT_HEAD_FILE "HEAD" #define GIT_HEAD_FILE "HEAD"
#define GIT_ORIG_HEAD_FILE "ORIG_HEAD"
#define GIT_FETCH_HEAD_FILE "FETCH_HEAD" #define GIT_FETCH_HEAD_FILE "FETCH_HEAD"
#define GIT_MERGE_HEAD_FILE "MERGE_HEAD" #define GIT_MERGE_HEAD_FILE "MERGE_HEAD"
#define GIT_REVERT_HEAD_FILE "REVERT_HEAD"
#define GIT_CHERRY_PICK_HEAD_FILE "CHERRY_PICK_HEAD"
#define GIT_REFS_HEADS_MASTER_FILE GIT_REFS_HEADS_DIR "master" #define GIT_REFS_HEADS_MASTER_FILE GIT_REFS_HEADS_DIR "master"
#define GIT_REFNAME_MAX 1024 #define GIT_REFNAME_MAX 1024
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "filter.h" #include "filter.h"
#include "odb.h" #include "odb.h"
#include "remote.h" #include "remote.h"
#include "merge.h"
#define GIT_FILE_CONTENT_PREFIX "gitdir:" #define GIT_FILE_CONTENT_PREFIX "gitdir:"
...@@ -1348,15 +1349,13 @@ int git_repository_head_tree(git_tree **tree, git_repository *repo) ...@@ -1348,15 +1349,13 @@ int git_repository_head_tree(git_tree **tree, git_repository *repo)
return 0; return 0;
} }
#define MERGE_MSG_FILE "MERGE_MSG"
int git_repository_message(char *buffer, size_t len, git_repository *repo) int git_repository_message(char *buffer, size_t len, git_repository *repo)
{ {
git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT; git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
struct stat st; struct stat st;
int error; int error;
if (git_buf_joinpath(&path, repo->path_repository, MERGE_MSG_FILE) < 0) if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
return -1; return -1;
if ((error = p_stat(git_buf_cstr(&path), &st)) < 0) { if ((error = p_stat(git_buf_cstr(&path), &st)) < 0) {
...@@ -1382,7 +1381,7 @@ int git_repository_message_remove(git_repository *repo) ...@@ -1382,7 +1381,7 @@ int git_repository_message_remove(git_repository *repo)
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
int error; int error;
if (git_buf_joinpath(&path, repo->path_repository, MERGE_MSG_FILE) < 0) if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0)
return -1; return -1;
error = p_unlink(git_buf_cstr(&path)); error = p_unlink(git_buf_cstr(&path));
...@@ -1541,3 +1540,24 @@ cleanup: ...@@ -1541,3 +1540,24 @@ cleanup:
git_reference_free(new_head); git_reference_free(new_head);
return error; return error;
} }
int git_repository_state(git_repository *repo)
{
git_buf repo_path = GIT_BUF_INIT;
int state = GIT_REPOSITORY_STATE_NONE;
assert(repo);
if (git_buf_puts(&repo_path, repo->path_repository) < 0)
return -1;
if (git_path_contains_file(&repo_path, GIT_MERGE_HEAD_FILE))
state = GIT_REPOSITORY_STATE_MERGE;
else if(git_path_contains_file(&repo_path, GIT_REVERT_HEAD_FILE))
state = GIT_REPOSITORY_STATE_REVERT;
else if(git_path_contains_file(&repo_path, GIT_CHERRY_PICK_HEAD_FILE))
state = GIT_REPOSITORY_STATE_CHERRY_PICK;
git_buf_free(&repo_path);
return state;
}
...@@ -8,8 +8,10 @@ ...@@ -8,8 +8,10 @@
#include "common.h" #include "common.h"
#include "commit.h" #include "commit.h"
#include "tag.h" #include "tag.h"
#include "merge.h"
#include "git2/reset.h" #include "git2/reset.h"
#include "git2/checkout.h" #include "git2/checkout.h"
#include "git2/merge.h"
#define ERROR_MSG "Cannot perform reset" #define ERROR_MSG "Cannot perform reset"
...@@ -88,6 +90,12 @@ int git_reset( ...@@ -88,6 +90,12 @@ int git_reset(
goto cleanup; goto cleanup;
} }
if (reset_type == GIT_RESET_SOFT && (git_repository_state(repo) == GIT_REPOSITORY_STATE_MERGE)) {
giterr_set(GITERR_OBJECT, "%s (soft) while in the middle of a merge.", ERROR_MSG);
error = GIT_EUNMERGED;
goto cleanup;
}
//TODO: Check for unmerged entries //TODO: Check for unmerged entries
if (update_head(repo, commit) < 0) if (update_head(repo, commit) < 0)
...@@ -118,6 +126,11 @@ int git_reset( ...@@ -118,6 +126,11 @@ int git_reset(
goto cleanup; goto cleanup;
} }
if ((error = git_merge__cleanup(repo)) < 0) {
giterr_set(GITERR_INDEX, "%s - Failed to clean up merge data.", ERROR_MSG);
goto cleanup;
}
if (reset_type == GIT_RESET_MIXED) { if (reset_type == GIT_RESET_MIXED) {
error = 0; error = 0;
goto cleanup; goto cleanup;
......
#include "clar_libgit2.h"
#include "buffer.h"
#include "refs.h"
#include "posix.h"
static git_repository *_repo;
static git_buf _path;
void test_repo_state__initialize(void)
{
_repo = cl_git_sandbox_init("testrepo.git");
}
void test_repo_state__cleanup(void)
{
cl_git_sandbox_cleanup();
git_buf_free(&_path);
}
void test_repo_state__none(void)
{
/* The repo should be at its default state */
cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(_repo));
}
void test_repo_state__merge(void)
{
/* Then it should recognise that .git/MERGE_HEAD and friends mean their respective states */
cl_git_pass(git_buf_joinpath(&_path, git_repository_path(_repo), GIT_MERGE_HEAD_FILE));
cl_git_mkfile(git_buf_cstr(&_path), "dummy");
cl_assert_equal_i(GIT_REPOSITORY_STATE_MERGE, git_repository_state(_repo));
}
void test_repo_state__revert(void)
{
cl_git_pass(git_buf_joinpath(&_path, git_repository_path(_repo), GIT_REVERT_HEAD_FILE));
cl_git_mkfile(git_buf_cstr(&_path), "dummy");
cl_assert_equal_i(GIT_REPOSITORY_STATE_REVERT, git_repository_state(_repo));
}
void test_repo_state__cherry_pick(void)
{
cl_git_pass(git_buf_joinpath(&_path, git_repository_path(_repo), GIT_CHERRY_PICK_HEAD_FILE));
cl_git_mkfile(git_buf_cstr(&_path), "dummy");
cl_assert_equal_i(GIT_REPOSITORY_STATE_CHERRY_PICK, git_repository_state(_repo));
}
...@@ -58,3 +58,38 @@ void test_reset_hard__cannot_reset_in_a_bare_repository(void) ...@@ -58,3 +58,38 @@ void test_reset_hard__cannot_reset_in_a_bare_repository(void)
git_repository_free(bare); git_repository_free(bare);
} }
void test_reset_hard__cleans_up_merge(void)
{
git_buf merge_head_path = GIT_BUF_INIT,
merge_msg_path = GIT_BUF_INIT,
merge_mode_path = GIT_BUF_INIT,
orig_head_path = GIT_BUF_INIT;
cl_git_pass(git_buf_joinpath(&merge_head_path, git_repository_path(repo), "MERGE_HEAD"));
cl_git_mkfile(git_buf_cstr(&merge_head_path), "beefbeefbeefbeefbeefbeefbeefbeefbeefbeef\n");
cl_git_pass(git_buf_joinpath(&merge_msg_path, git_repository_path(repo), "MERGE_MSG"));
cl_git_mkfile(git_buf_cstr(&merge_head_path), "Merge commit 0017bd4ab1ec30440b17bae1680cff124ab5f1f6\n");
cl_git_pass(git_buf_joinpath(&merge_msg_path, git_repository_path(repo), "MERGE_MODE"));
cl_git_mkfile(git_buf_cstr(&merge_head_path), "");
cl_git_pass(git_buf_joinpath(&orig_head_path, git_repository_path(repo), "ORIG_HEAD"));
cl_git_mkfile(git_buf_cstr(&orig_head_path), "0017bd4ab1ec30440b17bae1680cff124ab5f1f6");
retrieve_target_from_oid(&target, repo, "0017bd4ab1ec30440b17bae1680cff124ab5f1f6");
cl_git_pass(git_reset(repo, target, GIT_RESET_HARD));
cl_assert(!git_path_exists(git_buf_cstr(&merge_head_path)));
cl_assert(!git_path_exists(git_buf_cstr(&merge_msg_path)));
cl_assert(!git_path_exists(git_buf_cstr(&merge_mode_path)));
cl_assert(git_path_exists(git_buf_cstr(&orig_head_path)));
cl_git_pass(p_unlink(git_buf_cstr(&orig_head_path)));
git_buf_free(&merge_head_path);
git_buf_free(&merge_msg_path);
git_buf_free(&merge_mode_path);
git_buf_free(&orig_head_path);
}
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "posix.h"
#include "reset_helpers.h" #include "reset_helpers.h"
#include "path.h"
#include "repo/repo_helpers.h" #include "repo/repo_helpers.h"
static git_repository *repo; static git_repository *repo;
...@@ -110,3 +112,16 @@ void test_reset_soft__resetting_against_an_orphaned_head_repo_makes_the_head_no_ ...@@ -110,3 +112,16 @@ void test_reset_soft__resetting_against_an_orphaned_head_repo_makes_the_head_no_
git_reference_free(head); git_reference_free(head);
} }
void test_reset_soft__fails_when_merging(void)
{
git_buf merge_head_path = GIT_BUF_INIT;
cl_git_pass(git_buf_joinpath(&merge_head_path, git_repository_path(repo), "MERGE_HEAD"));
cl_git_mkfile(git_buf_cstr(&merge_head_path), "beefbeefbeefbeefbeefbeefbeefbeefbeefbeef\n");
retrieve_target_from_oid(&target, repo, KNOWN_COMMIT_IN_BARE_REPO);
cl_assert_equal_i(GIT_EUNMERGED, git_reset(repo, target, GIT_RESET_SOFT));
cl_git_pass(p_unlink(git_buf_cstr(&merge_head_path)));
}
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