diff --git a/src/submodule.c b/src/submodule.c index dcd58d016..e6ed7e33e 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 ba8e2518e..88d4f97c7 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 9b77897b7..c94fd57c6 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);