Add timestamp check to submodule status This is probably not the final form of this change, but this is a preliminary version of checking a timestamp to see if the cached working directory HEAD OID matches the current. Right now, this uses the timestamp on the index and is, like most of our timestamp checking, subject to having only second accuracy.
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
diff --git a/src/submodule.c b/src/submodule.c
index dcd58d0..e6ed7e3 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -9,9 +9,7 @@
#include "git2/config.h"
#include "git2/sys/config.h"
#include "git2/types.h"
-#include "git2/repository.h"
#include "git2/index.h"
-#include "git2/submodule.h"
#include "buffer.h"
#include "buf_text.h"
#include "vector.h"
@@ -544,6 +542,15 @@ const git_oid *git_submodule_wd_id(git_submodule *submodule)
{
assert(submodule);
+ /* if we know the submodule index timestamp and it has moved, then
+ * let's reload the working directory information for the submodule
+ */
+ if (submodule->wd_head_path != NULL &&
+ git_futils_filestamp_check(
+ &submodule->wd_stamp, submodule->wd_head_path))
+ submodule->flags &= ~GIT_SUBMODULE_STATUS__WD_OID_VALID;
+
+ /* load unless we think we have a valid oid */
if (!(submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)) {
git_repository *subrepo;
@@ -702,11 +709,36 @@ int git_submodule_open(
/* if we have opened the submodule successfully, let's grab the HEAD OID */
if (!error) {
+ git_buf buf = GIT_BUF_INIT;
+
+ /* For now, let's just the index timestamp...
+ *
+ * git_buf_joinpath(&buf, git_repository_path(*subrepo), GIT_HEAD_FILE);
+ * if (!git_path_exists(buf.ptr)) {
+ */
+ git_index *index;
+ if (!git_repository_index__weakptr(&index, *subrepo))
+ git_buf_sets(&buf, git_index_path(index));
+ else
+ git_buf_free(&buf);
+ /* } */
+
+ if (git_buf_len(&buf) > 0) {
+ git__free(submodule->wd_head_path);
+ submodule->wd_head_path = git_buf_detach(&buf);
+ }
+
if (!git_reference_name_to_id(
- &submodule->wd_oid, *subrepo, GIT_HEAD_FILE))
+ &submodule->wd_oid, *subrepo, GIT_HEAD_FILE)) {
+
submodule->flags |= GIT_SUBMODULE_STATUS__WD_OID_VALID;
- else
- giterr_clear();
+
+ if (submodule->wd_head_path)
+ git_futils_filestamp_check(
+ &submodule->wd_stamp, submodule->wd_head_path);
+ }
+
+ giterr_clear();
}
return error;
diff --git a/src/submodule.h b/src/submodule.h
index ba8e251..88d4f97 100644
--- a/src/submodule.h
+++ b/src/submodule.h
@@ -7,6 +7,10 @@
#ifndef INCLUDE_submodule_h__
#define INCLUDE_submodule_h__
+#include "git2/submodule.h"
+#include "git2/repository.h"
+#include "fileops.h"
+
/* Notes:
*
* Submodule information can be in four places: the index, the config files
@@ -44,43 +48,53 @@
* an entry for every submodule found in the HEAD and index, and for every
* submodule described in .gitmodules. The fields are as follows:
*
- * - `owner` is the git_repository containing this submodule
* - `name` is the name of the submodule from .gitmodules.
* - `path` is the path to the submodule from the repo root. It is almost
* always the same as `name`.
* - `url` is the url for the submodule.
- * - `tree_oid` is the SHA1 for the submodule path in the repo HEAD.
- * - `index_oid` is the SHA1 for the submodule recorded in the index.
- * - `workdir_oid` is the SHA1 for the HEAD of the checked out submodule.
* - `update` is a git_submodule_update_t value - see gitmodules(5) update.
+ * - `update_default` is the update value from the config
* - `ignore` is a git_submodule_ignore_t value - see gitmodules(5) ignore.
+ * - `ignore_default` is the ignore value from the config
* - `fetch_recurse` is 0 or 1 - see gitmodules(5) fetchRecurseSubmodules.
- * - `refcount` tracks how many hashmap entries there are for this submodule.
- * It only comes into play if the name and path of the submodule differ.
- * - `flags` is for internal use, tracking where this submodule has been
- * found (head, index, config, workdir) and other misc info about it.
+ *
+ * - `owner` is the git_repository containing this submodule
+ * - `flags` after for internal use, tracking where this submodule has been
+ * found (head, index, config, workdir) and known status info, etc.
+ * - `head_oid` is the SHA1 for the submodule path in the repo HEAD.
+ * - `index_oid` is the SHA1 for the submodule recorded in the index.
+ * - `wd_oid` is the SHA1 for the HEAD of the checked out submodule.
+ * - `wd_index_path` is the path to the index of the checked out submodule
+ * - `wd_last_index` is a timestamp of that submodule index so we can
+ * quickly check if the `wd_oid` should be rechecked
+ * - `refcount` tracks how many hash table entries in the
+ * git_submodule_cache there are for this submodule. It only comes into
+ * play if the name and path of the submodule differ.
*
* If the submodule has been added to .gitmodules but not yet git added,
- * then the `index_oid` will be valid and zero. If the submodule has been
- * deleted, but the delete has not been committed yet, then the `index_oid`
- * will be set, but the `url` will be NULL.
+ * then the `index_oid` will be zero but still marked valid. If the
+ * submodule has been deleted, but the delete has not been committed yet,
+ * then the `index_oid` will be set, but the `url` will be NULL.
*/
struct git_submodule {
- git_repository *owner;
+ /* information from config */
char *name;
char *path; /* important: may point to same string data as "name" */
char *url;
- uint32_t flags;
- git_oid head_oid;
- git_oid index_oid;
- git_oid wd_oid;
- /* information from config */
git_submodule_update_t update;
git_submodule_update_t update_default;
git_submodule_ignore_t ignore;
git_submodule_ignore_t ignore_default;
int fetch_recurse;
+
/* internal information */
+ git_repository *owner;
+ uint32_t flags;
+ git_oid head_oid;
+ git_oid index_oid;
+ git_oid wd_oid;
+ char *wd_head_path;
+ git_futils_filestamp wd_stamp;
int refcount;
};
diff --git a/tests-clar/diff/submodules.c b/tests-clar/diff/submodules.c
index 9b77897..c94fd57 100644
--- a/tests-clar/diff/submodules.c
+++ b/tests-clar/diff/submodules.c
@@ -333,29 +333,34 @@ void test_diff_submodules__invalid_cache(void)
check_diff_patches(diff, expected_unchanged);
git_diff_list_free(diff);
+ sleep(2);
+
/* commit changed index of submodule */
{
git_object *parent;
git_oid tree_id, commit_id;
git_tree *tree;
git_signature *sig;
+ git_reference *ref;
- cl_git_pass(git_revparse_single(&parent, smrepo, "HEAD"));
+ cl_git_pass(git_revparse_ext(&parent, &ref, smrepo, "HEAD"));
cl_git_pass(git_index_write_tree(&tree_id, smindex));
cl_git_pass(git_index_write(smindex));
cl_git_pass(git_tree_lookup(&tree, smrepo, &tree_id));
cl_git_pass(git_signature_new(&sig, "Sm Test", "sm@tester.test", 1372350000, 480));
cl_git_pass(git_commit_create_v(
- &commit_id, smrepo, "HEAD", sig, sig, NULL,
- "Move it", tree, 1, parent));
+ &commit_id, smrepo, git_reference_name(ref), sig, sig,
+ NULL, "Move it", tree, 1, parent));
git_object_free(parent);
git_tree_free(tree);
+ git_reference_free(ref);
git_signature_free(sig);
}
- /* THIS RELOAD SHOULD NOT BE REQUIRED */
+ /* THIS RELOAD SHOULD NOT BE REQUIRED
cl_git_pass(git_submodule_reload_all(g_repo));
cl_git_pass(git_submodule_lookup(&sm, g_repo, smpath));
+ */
git_submodule_set_ignore(sm, GIT_SUBMODULE_IGNORE_DIRTY);