Merge pull request #1026 from nulltoken/repo/state repo: enhance git_repository_state() detection
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
diff --git a/include/git2/repository.h b/include/git2/repository.h
index d724315..4d12226 100644
--- a/include/git2/repository.h
+++ b/include/git2/repository.h
@@ -574,6 +574,12 @@ typedef enum {
GIT_REPOSITORY_STATE_MERGE,
GIT_REPOSITORY_STATE_REVERT,
GIT_REPOSITORY_STATE_CHERRY_PICK,
+ GIT_REPOSITORY_STATE_BISECT,
+ GIT_REPOSITORY_STATE_REBASE,
+ GIT_REPOSITORY_STATE_REBASE_INTERACTIVE,
+ GIT_REPOSITORY_STATE_REBASE_MERGE,
+ GIT_REPOSITORY_STATE_APPLY_MAILBOX,
+ GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE,
} git_repository_state_t;
/**
diff --git a/src/refs.h b/src/refs.h
index 7b6f961..a58bebd 100644
--- a/src/refs.h
+++ b/src/refs.h
@@ -33,6 +33,12 @@
#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_BISECT_LOG_FILE "BISECT_LOG"
+#define GIT_REBASE_MERGE_DIR "rebase-merge/"
+#define GIT_REBASE_MERGE_INTERACTIVE_FILE GIT_REBASE_MERGE_DIR "interactive"
+#define GIT_REBASE_APPLY_DIR "rebase-apply/"
+#define GIT_REBASE_APPLY_REBASING_FILE GIT_REBASE_APPLY_DIR "rebasing"
+#define GIT_REBASE_APPLY_APPLYING_FILE GIT_REBASE_APPLY_DIR "applying"
#define GIT_REFS_HEADS_MASTER_FILE GIT_REFS_HEADS_DIR "master"
#define GIT_STASH_FILE "stash"
diff --git a/src/repository.c b/src/repository.c
index fa4604b..0e416e0 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -1541,6 +1541,10 @@ cleanup:
return error;
}
+/**
+ * Loosely ported from git.git
+ * https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh#L198-289
+ */
int git_repository_state(git_repository *repo)
{
git_buf repo_path = GIT_BUF_INIT;
@@ -1548,15 +1552,30 @@ int git_repository_state(git_repository *repo)
assert(repo);
+ if (!git_repository_head_detached(repo))
+ return state;
+
if (git_buf_puts(&repo_path, repo->path_repository) < 0)
return -1;
- if (git_path_contains_file(&repo_path, GIT_MERGE_HEAD_FILE))
+ if (git_path_contains_file(&repo_path, GIT_REBASE_MERGE_INTERACTIVE_FILE))
+ state = GIT_REPOSITORY_STATE_REBASE_INTERACTIVE;
+ else if (git_path_contains_dir(&repo_path, GIT_REBASE_MERGE_DIR))
+ state = GIT_REPOSITORY_STATE_REBASE_MERGE;
+ else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_REBASING_FILE))
+ state = GIT_REPOSITORY_STATE_REBASE;
+ else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_APPLYING_FILE))
+ state = GIT_REPOSITORY_STATE_APPLY_MAILBOX;
+ else if (git_path_contains_dir(&repo_path, GIT_REBASE_APPLY_DIR))
+ state = GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE;
+ else 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;
+ else if(git_path_contains_file(&repo_path, GIT_BISECT_LOG_FILE))
+ state = GIT_REPOSITORY_STATE_BISECT;
git_buf_free(&repo_path);
return state;
diff --git a/tests-clar/repo/state.c b/tests-clar/repo/state.c
index 1ee8437..c0aba19 100644
--- a/tests-clar/repo/state.c
+++ b/tests-clar/repo/state.c
@@ -2,6 +2,7 @@
#include "buffer.h"
#include "refs.h"
#include "posix.h"
+#include "fileops.h"
static git_repository *_repo;
static git_buf _path;
@@ -17,31 +18,81 @@ void test_repo_state__cleanup(void)
git_buf_free(&_path);
}
-void test_repo_state__none(void)
+static void setup_simple_state(const char *filename)
{
- /* The repo should be at its default state */
- cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(_repo));
+ cl_git_pass(git_buf_joinpath(&_path, git_repository_path(_repo), filename));
+ git_futils_mkpath2file(git_buf_cstr(&_path), 0777);
+ cl_git_mkfile(git_buf_cstr(&_path), "dummy");
+
+ cl_git_pass(git_repository_detach_head(_repo));
}
-void test_repo_state__merge(void)
+static void assert_repo_state(git_repository_state_t state)
{
+ cl_assert_equal_i(state, git_repository_state(_repo));
+}
- /* 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__none_with_HEAD_attached(void)
+{
+ assert_repo_state(GIT_REPOSITORY_STATE_NONE);
+}
+
+void test_repo_state__none_with_HEAD_detached(void)
+{
+ cl_git_pass(git_repository_detach_head(_repo));
+ assert_repo_state(GIT_REPOSITORY_STATE_NONE);
+}
+
+void test_repo_state__merge(void)
+{
+ setup_simple_state(GIT_MERGE_HEAD_FILE);
+ assert_repo_state(GIT_REPOSITORY_STATE_MERGE);
}
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));
+ setup_simple_state(GIT_REVERT_HEAD_FILE);
+ assert_repo_state(GIT_REPOSITORY_STATE_REVERT);
}
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));
+ setup_simple_state(GIT_CHERRY_PICK_HEAD_FILE);
+ assert_repo_state(GIT_REPOSITORY_STATE_CHERRY_PICK);
+}
+
+void test_repo_state__bisect(void)
+{
+ setup_simple_state(GIT_BISECT_LOG_FILE);
+ assert_repo_state(GIT_REPOSITORY_STATE_BISECT);
+}
+
+void test_repo_state__rebase_interactive(void)
+{
+ setup_simple_state(GIT_REBASE_MERGE_INTERACTIVE_FILE);
+ assert_repo_state(GIT_REPOSITORY_STATE_REBASE_INTERACTIVE);
+}
+
+void test_repo_state__rebase_merge(void)
+{
+ setup_simple_state(GIT_REBASE_MERGE_DIR "whatever");
+ assert_repo_state(GIT_REPOSITORY_STATE_REBASE_MERGE);
+}
+
+void test_repo_state__rebase(void)
+{
+ setup_simple_state(GIT_REBASE_APPLY_REBASING_FILE);
+ assert_repo_state(GIT_REPOSITORY_STATE_REBASE);
+}
+
+void test_repo_state__apply_mailbox(void)
+{
+ setup_simple_state(GIT_REBASE_APPLY_APPLYING_FILE);
+ assert_repo_state(GIT_REPOSITORY_STATE_APPLY_MAILBOX);
+}
+
+void test_repo_state__apply_mailbox_or_rebase(void)
+{
+ setup_simple_state(GIT_REBASE_APPLY_DIR "whatever");
+ assert_repo_state(GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE);
}
diff --git a/tests-clar/reset/soft.c b/tests-clar/reset/soft.c
index fa20645..d51e3f1 100644
--- a/tests-clar/reset/soft.c
+++ b/tests-clar/reset/soft.c
@@ -117,6 +117,7 @@ void test_reset_soft__fails_when_merging(void)
{
git_buf merge_head_path = GIT_BUF_INIT;
+ cl_git_pass(git_repository_detach_head(repo));
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");
@@ -124,4 +125,6 @@ void test_reset_soft__fails_when_merging(void)
cl_assert_equal_i(GIT_EUNMERGED, git_reset(repo, target, GIT_RESET_SOFT));
cl_git_pass(p_unlink(git_buf_cstr(&merge_head_path)));
+
+ git_buf_free(&merge_head_path);
}