Merge branch 'jk/warn-add-gitlink'
authorJunio C Hamano <gitster@pobox.com>
Sat, 24 Jun 2017 21:28:41 +0000 (14:28 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 24 Jun 2017 21:28:41 +0000 (14:28 -0700)
Using "git add d/i/r" when d/i/r is the top of the working tree of
a separate repository would create a gitlink in the index, which
would appear as a not-quite-initialized submodule to others. We
learned to give warnings when this happens.

* jk/warn-add-gitlink:
t: move "git add submodule" into test blocks
add: warn when adding an embedded repository

1  2 
Documentation/config.txt
advice.c
builtin/add.c
diff --combined Documentation/config.txt
index f6278a5ae6a1f554ddb8b9861d9067181b928bb5,e909239bc5707fb8a9b8fa68a80ede899a73f311..781ce3e855368ac04ea3b07cf291513e4bfb04df
@@@ -348,6 -348,9 +348,9 @@@ advice.*:
        rmHints::
                In case of failure in the output of linkgit:git-rm[1],
                show directions on how to proceed from the current state.
+       addEmbeddedRepo::
+               Advice on what to do when you've accidentally added one
+               git repo inside of another.
  --
  
  core.fileMode::
@@@ -3091,11 -3094,6 +3094,11 @@@ submodule.active:
        submodule's path to determine if the submodule is of interest to git
        commands.
  
 +submodule.recurse::
 +      Specifies if commands recurse into submodules by default. This
 +      applies to all commands that have a `--recurse-submodules` option.
 +      Defaults to false.
 +
  submodule.fetchJobs::
        Specifies how many submodules are fetched/cloned at the same time.
        A positive integer allows up to that number of submodules fetched
diff --combined advice.c
index 3fa04fca0b81ce0b4788ad3331ae759de805e0ff,e0611d52bdbaf269f39700ab3542b27f0846a319..d81e1cb7425b0f2d75461865b5c965a21ada5587
+++ b/advice.c
@@@ -1,5 -1,4 +1,5 @@@
  #include "cache.h"
 +#include "config.h"
  
  int advice_push_update_rejected = 1;
  int advice_push_non_ff_current = 1;
@@@ -16,6 -15,7 +16,7 @@@ int advice_detached_head = 1
  int advice_set_upstream_failure = 1;
  int advice_object_name_warning = 1;
  int advice_rm_hints = 1;
+ int advice_add_embedded_repo = 1;
  
  static struct {
        const char *name;
@@@ -36,6 -36,7 +37,7 @@@
        { "setupstreamfailure", &advice_set_upstream_failure },
        { "objectnamewarning", &advice_object_name_warning },
        { "rmhints", &advice_rm_hints },
+       { "addembeddedrepo", &advice_add_embedded_repo },
  
        /* make this an alias for backward compatibility */
        { "pushnonfastforward", &advice_push_update_rejected }
diff --combined builtin/add.c
index f2415e99f37d48e562913c17d8917bda4f892c09,d7cab1bd851f2e8074fac744ac2d27cd26fc9eb5..e888fb8c5f2a1fa2be33e834724460dec8072726
@@@ -4,7 -4,6 +4,7 @@@
   * Copyright (C) 2006 Linus Torvalds
   */
  #include "cache.h"
 +#include "config.h"
  #include "builtin.h"
  #include "lockfile.h"
  #include "dir.h"
@@@ -250,6 -249,7 +250,7 @@@ N_("The following paths are ignored by 
  
  static int verbose, show_only, ignored_too, refresh_only;
  static int ignore_add_errors, intent_to_add, ignore_missing;
+ static int warn_on_embedded_repo = 1;
  
  #define ADDREMOVE_DEFAULT 1
  static int addremove = ADDREMOVE_DEFAULT;
@@@ -283,6 -283,8 +284,8 @@@ static struct option builtin_add_option
        OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
        OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
        OPT_STRING( 0 , "chmod", &chmod_arg, N_("(+/-)x"), N_("override the executable bit of the listed files")),
+       OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo,
+                       N_("warn when adding an embedded repository")),
        OPT_END(),
  };
  
@@@ -296,6 -298,45 +299,45 @@@ static int add_config(const char *var, 
        return git_default_config(var, value, cb);
  }
  
+ static const char embedded_advice[] = N_(
+ "You've added another git repository inside your current repository.\n"
+ "Clones of the outer repository will not contain the contents of\n"
+ "the embedded repository and will not know how to obtain it.\n"
+ "If you meant to add a submodule, use:\n"
+ "\n"
+ "     git submodule add <url> %s\n"
+ "\n"
+ "If you added this path by mistake, you can remove it from the\n"
+ "index with:\n"
+ "\n"
+ "     git rm --cached %s\n"
+ "\n"
+ "See \"git help submodule\" for more information."
+ );
+ static void check_embedded_repo(const char *path)
+ {
+       struct strbuf name = STRBUF_INIT;
+       if (!warn_on_embedded_repo)
+               return;
+       if (!ends_with(path, "/"))
+               return;
+       /* Drop trailing slash for aesthetics */
+       strbuf_addstr(&name, path);
+       strbuf_strip_suffix(&name, "/");
+       warning(_("adding embedded git repository: %s"), name.buf);
+       if (advice_add_embedded_repo) {
+               advise(embedded_advice, name.buf, name.buf);
+               /* there may be multiple entries; advise only once */
+               advice_add_embedded_repo = 0;
+       }
+       strbuf_release(&name);
+ }
  static int add_files(struct dir_struct *dir, int flags)
  {
        int i, exit_status = 0;
                exit_status = 1;
        }
  
-       for (i = 0; i < dir->nr; i++)
+       for (i = 0; i < dir->nr; i++) {
+               check_embedded_repo(dir->entries[i]->name);
                if (add_file_to_index(&the_index, dir->entries[i]->name, flags)) {
                        if (!ignore_add_errors)
                                die(_("adding files failed"));
                        exit_status = 1;
                }
+       }
        return exit_status;
  }