Jens Lehmann wrote:
> Currently using "git mv" on a submodule moves the submodule's work tree in
> that of the superproject.
It's not "Currently": it's the result of your last two patches. The
wording is very unclear. Perhaps: As a result of the last two patches
in this series, a 'git mv' moves the submodule directory to a new path
in the superproject's worktree, and updates the cache entry in the
index appropriately.
> But the submodule's path setting in .gitmodules
> is left untouched, which is now inconsistent with the work tree and makes
> git commands that rely on the proper path -> name mapping (like status and
> diff) behave strangely.
I'm frankly a little surprised that your previous two patches didn't
break any tests. That's probably because we don't have enough tests
to exercise git-core with submodules. I'm not saying that it's a bad
thing though: submodules are still immature, and tight tests would get
in the way of new patches.
> Let "git mv" help here by not only moving the submodule's work tree but
> also updating the "submodule.<submodule name>.path" setting from the
> .gitmodules file and stage both.
> This doesn't happen when no .gitmodules
> file is found and only issues a warning when it doesn't have a section for
> this submodule. This is because the user might just use plain gitlinks
> without the .gitmodules file
How will git-core work without a .gitmodules? Shouldn't we create a
fresh .gitmodules here?
> or has already updated the path setting by
> hand before issuing the "git mv" command (in which case the warning
> reminds him that mv would have done that for him).
Shouldn't these two cases issue different warnings?
Besides, why is this explanation missing in your rm patch's commit message?
> diff --git a/builtin/mv.c b/builtin/mv.c
> index 609bbb8..36e5605 100644
> --- a/builtin/mv.c
> +++ b/builtin/mv.c
> @@ -239,6 +242,9 @@ int cmd_mv(int argc, const char **argv, const char
> *prefix)
> rename_cache_entry_at(pos, dst);
> }
>
> + if (gitmodules_modified)
> + stage_updated_gitmodules();
> +
I'm unhappy with this, but we I'll have to live with my
dissatisfaction until we get rid of ".gitmodules" (if that ever
happens). mv has a clear task: it should perform a filesystem mv,
manipulate the index, and write out the changed index. Adding an
unrelated file to the index has nothing to do with its primary task.
> diff --git a/submodule.c b/submodule.c
> index eba9b42..fb742b4 100644
> --- a/submodule.c
> +++ b/submodule.c
All my comments in the rm review apply here too, so I won't repeat myself.
> @@ -10,6 +10,7 @@
> #include "string-list.h"
> #include "sha1-array.h"
> #include "argv-array.h"
> +#include "blob.h"
Interesting. Let's see why you need blob.h.
> static struct string_list config_name_for_path;
> static struct string_list config_fetch_recurse_submodules_for_name;
> @@ -30,6 +31,67 @@ static struct sha1_array ref_tips_after_fetch;
> */
> static int gitmodules_is_unmerged;
>
> +/*
> + * Try to update the "path" entry in the "submodule.<name>" section of the
> + * .gitmodules file.
> + */
> +int update_path_in_gitmodules(const char *oldpath, const char *newpath)
> +{
> + struct strbuf entry = STRBUF_INIT;
> + struct string_list_item *path_option;
> +
> + if (!file_exists(".gitmodules")) /* Do nothing whithout .gitmodules */
> + return -1;
s/whithout/without. Why are you not returning an error()? Don't you
want to tell the user that no ".gitmodules" was found?
> +void stage_updated_gitmodules(void)
void return? Don't you want the caller to know whether we were
successful or not?
Why does the name contain "updated"? Why does the function care if I
updated the .gitmodules or not? It's just staging .gitmodules, as it
is on the filesystem.
> +{
> + struct strbuf buf = STRBUF_INIT;
> + struct stat st;
> + int pos;
> + struct cache_entry *ce;
> + int namelen = strlen(".gitmodules");
> +
> + pos = cache_name_pos(".gitmodules", strlen(".gitmodules"));
And you forgot about namelen just like that.
> + if (pos < 0) {
> + warning(_("could not find .gitmodules in index"));
> + return;
> + }
What could this mean? I might have an untracked .gitmodules file in
my worktree, or I might not have a .gitmodules file at all. Since
you're already checking the latter case in the previous function,
can't you persist the result, and return a more sensible error?
> + ce = active_cache[pos];
> + ce->ce_flags = namelen;
> + if (strbuf_read_file(&buf, ".gitmodules", 0) < 0)
> + die(_("reading updated .gitmodules failed"));
You're reading it because? What does "_updated_ .gitmodules" mean here?
> + if (lstat(".gitmodules", &st) < 0)
> + die_errno(_("unable to stat updated .gitmodules"));
> + fill_stat_cache_info(ce, &st);
> + ce->ce_mode = ce_mode_from_stat(ce, st.st_mode);
I don't understand why you're taking the pains to fill out a cache_entry.
> + if (remove_file_from_cache(".gitmodules") < 0)
> + die(_("unable to remove .gitmodules from index"));
You already have pos, so why not just remove_cache_entry_at()?
> + if (write_sha1_file(buf.buf, buf.len, blob_type, ce->sha1))
> + die(_("adding updated .gitmodules failed"));
Ah, you need blob.h for blob_type.
Wait, why are you just reading and writing .gitmodules? What changed?
And why are you manually writing a blob to the object store? Doesn't
git-core already do this if you just add it to the index? See the
S_IFLNK case in index_path().
What happens if there's a race? Shouldn't you be locking .gitmodules
before updating it, like we do with the index and just about
everything else?
> + if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
> + die(_("staging updated .gitmodules failed"));
This is all you need: it calls index_path() and writes your blob
object to the database.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html