Git fork

Merge branch 'jk/submodule-remote-lookup-cleanup'

Updating submodules from the upstream did not work well when
submodule's HEAD is detached, which has been improved.

* jk/submodule-remote-lookup-cleanup:
submodule: look up remotes by URL first
submodule: move get_default_remote_submodule()
submodule--helper: improve logic for fallback remote name
remote: remove the_repository from some functions
dir: move starts_with_dot(_dot)_slash to dir.h
remote: fix tear down of struct remote
remote: remove branch->merge_name and fix branch_release()

+226 -131
+2 -2
branch.c
··· 230 230 return -1; 231 231 } 232 232 233 - if (branch->merge_nr < 1 || !branch->merge_name || !branch->merge_name[0]) { 233 + if (branch->merge_nr < 1 || !branch->merge || !branch->merge[0] || !branch->merge[0]->src) { 234 234 warning(_("asked to inherit tracking from '%s', but no merge configuration is set"), 235 235 bare_ref); 236 236 return -1; ··· 238 238 239 239 tracking->remote = branch->remote_name; 240 240 for (i = 0; i < branch->merge_nr; i++) 241 - string_list_append(tracking->srcs, branch->merge_name[i]); 241 + string_list_append(tracking->srcs, branch->merge[i]->src); 242 242 return 0; 243 243 } 244 244
+1 -1
builtin/pull.c
··· 490 490 } else 491 491 fprintf_ln(stderr, _("Your configuration specifies to merge with the ref '%s'\n" 492 492 "from the remote, but no such ref was fetched."), 493 - *curr_branch->merge_name); 493 + curr_branch->merge[0]->src); 494 494 exit(1); 495 495 } 496 496
+41 -65
builtin/submodule--helper.c
··· 41 41 typedef void (*each_submodule_fn)(const struct cache_entry *list_item, 42 42 void *cb_data); 43 43 44 - static int repo_get_default_remote(struct repository *repo, char **default_remote) 45 - { 46 - char *dest = NULL; 47 - struct strbuf sb = STRBUF_INIT; 48 - struct ref_store *store = get_main_ref_store(repo); 49 - const char *refname = refs_resolve_ref_unsafe(store, "HEAD", 0, NULL, 50 - NULL); 51 - 52 - if (!refname) 53 - return die_message(_("No such ref: %s"), "HEAD"); 54 - 55 - /* detached HEAD */ 56 - if (!strcmp(refname, "HEAD")) { 57 - *default_remote = xstrdup("origin"); 58 - return 0; 59 - } 60 - 61 - if (!skip_prefix(refname, "refs/heads/", &refname)) 62 - return die_message(_("Expecting a full ref name, got %s"), 63 - refname); 64 - 65 - strbuf_addf(&sb, "branch.%s.remote", refname); 66 - if (repo_config_get_string(repo, sb.buf, &dest)) 67 - *default_remote = xstrdup("origin"); 68 - else 69 - *default_remote = dest; 70 - 71 - strbuf_release(&sb); 72 - return 0; 73 - } 74 - 75 - static int get_default_remote_submodule(const char *module_path, char **default_remote) 76 - { 77 - struct repository subrepo; 78 - int ret; 79 - 80 - if (repo_submodule_init(&subrepo, the_repository, module_path, 81 - null_oid(the_hash_algo)) < 0) 82 - return die_message(_("could not get a repository handle for submodule '%s'"), 83 - module_path); 84 - ret = repo_get_default_remote(&subrepo, default_remote); 85 - repo_clear(&subrepo); 86 - 87 - return ret; 88 - } 89 - 90 44 static char *get_default_remote(void) 91 45 { 92 - char *default_remote; 93 - int code = repo_get_default_remote(the_repository, &default_remote); 94 - 95 - if (code) 96 - exit(code); 97 - 98 - return default_remote; 46 + return xstrdup(repo_default_remote(the_repository)); 99 47 } 100 48 101 49 static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet) ··· 120 68 strbuf_release(&remotesb); 121 69 122 70 return resolved_url; 71 + } 72 + 73 + static int get_default_remote_submodule(const char *module_path, char **default_remote) 74 + { 75 + const struct submodule *sub; 76 + struct repository subrepo; 77 + const char *remote_name = NULL; 78 + char *url = NULL; 79 + 80 + sub = submodule_from_path(the_repository, null_oid(the_hash_algo), module_path); 81 + if (sub && sub->url) { 82 + url = xstrdup(sub->url); 83 + 84 + /* Possibly a url relative to parent */ 85 + if (starts_with_dot_dot_slash(url) || 86 + starts_with_dot_slash(url)) { 87 + char *oldurl = url; 88 + 89 + url = resolve_relative_url(oldurl, NULL, 1); 90 + free(oldurl); 91 + } 92 + } 93 + 94 + if (repo_submodule_init(&subrepo, the_repository, module_path, 95 + null_oid(the_hash_algo)) < 0) 96 + return die_message(_("could not get a repository handle for submodule '%s'"), 97 + module_path); 98 + 99 + /* Look up by URL first */ 100 + if (url) 101 + remote_name = repo_remote_from_url(&subrepo, url); 102 + if (!remote_name) 103 + remote_name = repo_default_remote(&subrepo); 104 + 105 + *default_remote = xstrdup(remote_name); 106 + 107 + repo_clear(&subrepo); 108 + free(url); 109 + 110 + return 0; 123 111 } 124 112 125 113 /* the result should be freed by the caller. */ ··· 436 424 module_list_release(&list); 437 425 clear_pathspec(&pathspec); 438 426 return ret; 439 - } 440 - 441 - static int starts_with_dot_slash(const char *const path) 442 - { 443 - return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_SLASH | 444 - PATH_MATCH_XPLATFORM); 445 - } 446 - 447 - static int starts_with_dot_dot_slash(const char *const path) 448 - { 449 - return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH | 450 - PATH_MATCH_XPLATFORM); 451 427 } 452 428 453 429 struct init_cb {
+23
dir.h
··· 676 676 return path_match_flags(path, what | PATH_MATCH_NATIVE); 677 677 } 678 678 679 + /** 680 + * starts_with_dot_slash: convenience wrapper for 681 + * patch_match_flags() with PATH_MATCH_STARTS_WITH_DOT_SLASH and 682 + * PATH_MATCH_XPLATFORM. 683 + */ 684 + static inline int starts_with_dot_slash(const char *const path) 685 + { 686 + const enum path_match_flags what = PATH_MATCH_STARTS_WITH_DOT_SLASH; 687 + 688 + return path_match_flags(path, what | PATH_MATCH_XPLATFORM); 689 + } 690 + 691 + /** 692 + * starts_with_dot_dot_slash: convenience wrapper for 693 + * patch_match_flags() with PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH and 694 + * PATH_MATCH_XPLATFORM. 695 + */ 696 + static inline int starts_with_dot_dot_slash(const char *const path) 697 + { 698 + const enum path_match_flags what = PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH; 699 + 700 + return path_match_flags(path, what | PATH_MATCH_XPLATFORM); 701 + } 679 702 #endif
+92 -49
remote.c
··· 165 165 strvec_clear(&remote->url); 166 166 strvec_clear(&remote->pushurl); 167 167 168 + refspec_clear(&remote->push); 169 + refspec_clear(&remote->fetch); 170 + 168 171 free((char *)remote->receivepack); 169 172 free((char *)remote->uploadpack); 170 173 FREE_AND_NULL(remote->http_proxy); ··· 174 177 175 178 static void add_merge(struct branch *branch, const char *name) 176 179 { 177 - ALLOC_GROW(branch->merge_name, branch->merge_nr + 1, 180 + struct refspec_item *merge; 181 + 182 + ALLOC_GROW(branch->merge, branch->merge_nr + 1, 178 183 branch->merge_alloc); 179 - branch->merge_name[branch->merge_nr++] = name; 184 + 185 + merge = xcalloc(1, sizeof(*merge)); 186 + merge->src = xstrdup(name); 187 + 188 + branch->merge[branch->merge_nr++] = merge; 180 189 } 181 190 182 191 struct branches_hash_key { ··· 247 256 return ret; 248 257 } 249 258 259 + static void merge_clear(struct branch *branch) 260 + { 261 + for (int i = 0; i < branch->merge_nr; i++) { 262 + refspec_item_clear(branch->merge[i]); 263 + free(branch->merge[i]); 264 + } 265 + FREE_AND_NULL(branch->merge); 266 + branch->merge_nr = 0; 267 + } 268 + 250 269 static void branch_release(struct branch *branch) 251 270 { 252 271 free((char *)branch->name); 253 272 free((char *)branch->refname); 254 273 free(branch->remote_name); 255 274 free(branch->pushremote_name); 256 - for (int i = 0; i < branch->merge_nr; i++) 257 - refspec_item_clear(branch->merge[i]); 258 - free(branch->merge); 275 + merge_clear(branch); 259 276 } 260 277 261 278 static struct rewrite *make_rewrite(struct rewrites *r, ··· 317 334 type, remote->name, remote->name, remote->name); 318 335 } 319 336 320 - static void read_remotes_file(struct remote_state *remote_state, 321 - struct remote *remote) 337 + static void read_remotes_file(struct repository *repo, struct remote *remote) 322 338 { 323 339 struct strbuf buf = STRBUF_INIT; 324 - FILE *f = fopen_or_warn(repo_git_path_append(the_repository, &buf, 340 + FILE *f = fopen_or_warn(repo_git_path_append(repo, &buf, 325 341 "remotes/%s", remote->name), "r"); 326 342 327 343 if (!f) ··· 337 353 strbuf_rtrim(&buf); 338 354 339 355 if (skip_prefix(buf.buf, "URL:", &v)) 340 - add_url_alias(remote_state, remote, 356 + add_url_alias(repo->remote_state, remote, 341 357 skip_spaces(v)); 342 358 else if (skip_prefix(buf.buf, "Push:", &v)) 343 359 refspec_append(&remote->push, skip_spaces(v)); ··· 350 366 strbuf_release(&buf); 351 367 } 352 368 353 - static void read_branches_file(struct remote_state *remote_state, 354 - struct remote *remote) 369 + static void read_branches_file(struct repository *repo, struct remote *remote) 355 370 { 356 371 char *frag, *to_free = NULL; 357 372 struct strbuf buf = STRBUF_INIT; 358 - FILE *f = fopen_or_warn(repo_git_path_append(the_repository, &buf, 373 + FILE *f = fopen_or_warn(repo_git_path_append(repo, &buf, 359 374 "branches/%s", remote->name), "r"); 360 375 361 376 if (!f) ··· 382 397 if (frag) 383 398 *(frag++) = '\0'; 384 399 else 385 - frag = to_free = repo_default_branch_name(the_repository, 0); 400 + frag = to_free = repo_default_branch_name(repo, 0); 386 401 387 - add_url_alias(remote_state, remote, buf.buf); 402 + add_url_alias(repo->remote_state, remote, buf.buf); 388 403 refspec_appendf(&remote->fetch, "refs/heads/%s:refs/heads/%s", 389 404 frag, remote->name); 390 405 ··· 429 444 } else if (!strcmp(subkey, "merge")) { 430 445 if (!value) 431 446 return config_error_nonbool(key); 432 - add_merge(branch, xstrdup(value)); 447 + add_merge(branch, value); 433 448 } 434 449 return 0; 435 450 } ··· 681 696 branch, explicit); 682 697 } 683 698 684 - static struct remote *remotes_remote_get(struct remote_state *remote_state, 699 + static struct remote *remotes_remote_get(struct repository *repo, 685 700 const char *name); 686 701 687 702 char *remote_ref_for_branch(struct branch *branch, int for_push) ··· 692 707 if (branch) { 693 708 if (!for_push) { 694 709 if (branch->merge_nr) { 695 - return xstrdup(branch->merge_name[0]); 710 + return xstrdup(branch->merge[0]->src); 696 711 } 697 712 } else { 698 713 char *dst; ··· 700 715 the_repository->remote_state, branch, 701 716 NULL); 702 717 struct remote *remote = remotes_remote_get( 703 - the_repository->remote_state, remote_name); 718 + the_repository, remote_name); 704 719 705 720 if (remote && remote->push.nr && 706 721 (dst = apply_refspecs(&remote->push, ··· 757 772 } 758 773 759 774 static struct remote * 760 - remotes_remote_get_1(struct remote_state *remote_state, const char *name, 775 + remotes_remote_get_1(struct repository *repo, const char *name, 761 776 const char *(*get_default)(struct remote_state *, 762 777 struct branch *, int *)) 763 778 { 779 + struct remote_state *remote_state = repo->remote_state; 764 780 struct remote *ret; 765 781 int name_given = 0; 766 782 ··· 774 790 #ifndef WITH_BREAKING_CHANGES 775 791 if (valid_remote_nick(name) && have_git_dir()) { 776 792 if (!valid_remote(ret)) 777 - read_remotes_file(remote_state, ret); 793 + read_remotes_file(repo, ret); 778 794 if (!valid_remote(ret)) 779 - read_branches_file(remote_state, ret); 795 + read_branches_file(repo, ret); 780 796 } 781 797 #endif /* WITH_BREAKING_CHANGES */ 782 798 if (name_given && !valid_remote(ret)) ··· 790 806 } 791 807 792 808 static inline struct remote * 793 - remotes_remote_get(struct remote_state *remote_state, const char *name) 809 + remotes_remote_get(struct repository *repo, const char *name) 794 810 { 795 - return remotes_remote_get_1(remote_state, name, 796 - remotes_remote_for_branch); 811 + return remotes_remote_get_1(repo, name, remotes_remote_for_branch); 797 812 } 798 813 799 814 struct remote *remote_get(const char *name) 800 815 { 801 816 read_config(the_repository, 0); 802 - return remotes_remote_get(the_repository->remote_state, name); 817 + return remotes_remote_get(the_repository, name); 803 818 } 804 819 805 820 struct remote *remote_get_early(const char *name) 806 821 { 807 822 read_config(the_repository, 1); 808 - return remotes_remote_get(the_repository->remote_state, name); 823 + return remotes_remote_get(the_repository, name); 809 824 } 810 825 811 826 static inline struct remote * 812 - remotes_pushremote_get(struct remote_state *remote_state, const char *name) 827 + remotes_pushremote_get(struct repository *repo, const char *name) 813 828 { 814 - return remotes_remote_get_1(remote_state, name, 815 - remotes_pushremote_for_branch); 829 + return remotes_remote_get_1(repo, name, remotes_pushremote_for_branch); 816 830 } 817 831 818 832 struct remote *pushremote_get(const char *name) 819 833 { 820 834 read_config(the_repository, 0); 821 - return remotes_pushremote_get(the_repository->remote_state, name); 835 + return remotes_pushremote_get(the_repository, name); 822 836 } 823 837 824 838 int remote_is_configured(struct remote *remote, int in_repo) ··· 1722 1736 } 1723 1737 } 1724 1738 1725 - static void set_merge(struct remote_state *remote_state, struct branch *ret) 1739 + static void set_merge(struct repository *repo, struct branch *ret) 1726 1740 { 1727 1741 struct remote *remote; 1728 1742 char *ref; ··· 1731 1745 1732 1746 if (!ret) 1733 1747 return; /* no branch */ 1734 - if (ret->merge) 1748 + if (ret->set_merge) 1735 1749 return; /* already run */ 1736 1750 if (!ret->remote_name || !ret->merge_nr) { 1737 1751 /* 1738 1752 * no merge config; let's make sure we don't confuse callers 1739 1753 * with a non-zero merge_nr but a NULL merge 1740 1754 */ 1741 - ret->merge_nr = 0; 1755 + merge_clear(ret); 1742 1756 return; 1743 1757 } 1758 + ret->set_merge = 1; 1744 1759 1745 - remote = remotes_remote_get(remote_state, ret->remote_name); 1760 + remote = remotes_remote_get(repo, ret->remote_name); 1746 1761 1747 - CALLOC_ARRAY(ret->merge, ret->merge_nr); 1748 1762 for (i = 0; i < ret->merge_nr; i++) { 1749 - ret->merge[i] = xcalloc(1, sizeof(**ret->merge)); 1750 - ret->merge[i]->src = xstrdup(ret->merge_name[i]); 1751 1763 if (!remote_find_tracking(remote, ret->merge[i]) || 1752 1764 strcmp(ret->remote_name, ".")) 1753 1765 continue; 1754 - if (repo_dwim_ref(the_repository, ret->merge_name[i], 1755 - strlen(ret->merge_name[i]), &oid, &ref, 1766 + if (repo_dwim_ref(repo, ret->merge[i]->src, 1767 + strlen(ret->merge[i]->src), &oid, &ref, 1756 1768 0) == 1) 1757 1769 ret->merge[i]->dst = ref; 1758 1770 else 1759 - ret->merge[i]->dst = xstrdup(ret->merge_name[i]); 1771 + ret->merge[i]->dst = xstrdup(ret->merge[i]->src); 1760 1772 } 1761 1773 } 1762 1774 1763 - struct branch *branch_get(const char *name) 1775 + static struct branch *repo_branch_get(struct repository *repo, const char *name) 1764 1776 { 1765 1777 struct branch *ret; 1766 1778 1767 - read_config(the_repository, 0); 1779 + read_config(repo, 0); 1768 1780 if (!name || !*name || !strcmp(name, "HEAD")) 1769 - ret = the_repository->remote_state->current_branch; 1781 + ret = repo->remote_state->current_branch; 1770 1782 else 1771 - ret = make_branch(the_repository->remote_state, name, 1783 + ret = make_branch(repo->remote_state, name, 1772 1784 strlen(name)); 1773 - set_merge(the_repository->remote_state, ret); 1785 + set_merge(repo, ret); 1774 1786 return ret; 1775 1787 } 1776 1788 1789 + struct branch *branch_get(const char *name) 1790 + { 1791 + return repo_branch_get(the_repository, name); 1792 + } 1793 + 1794 + const char *repo_default_remote(struct repository *repo) 1795 + { 1796 + struct branch *branch; 1797 + 1798 + read_config(repo, 0); 1799 + branch = repo_branch_get(repo, "HEAD"); 1800 + 1801 + return remotes_remote_for_branch(repo->remote_state, branch, NULL); 1802 + } 1803 + 1804 + const char *repo_remote_from_url(struct repository *repo, const char *url) 1805 + { 1806 + read_config(repo, 0); 1807 + 1808 + for (int i = 0; i < repo->remote_state->remotes_nr; i++) { 1809 + struct remote *remote = repo->remote_state->remotes[i]; 1810 + if (!remote) 1811 + continue; 1812 + 1813 + if (remote_has_url(remote, url)) 1814 + return remote->name; 1815 + } 1816 + return NULL; 1817 + } 1818 + 1777 1819 int branch_has_merge_config(struct branch *branch) 1778 1820 { 1779 - return branch && !!branch->merge; 1821 + return branch && branch->set_merge; 1780 1822 } 1781 1823 1782 1824 int branch_merge_matches(struct branch *branch, ··· 1841 1883 return ret; 1842 1884 } 1843 1885 1844 - static const char *branch_get_push_1(struct remote_state *remote_state, 1886 + static const char *branch_get_push_1(struct repository *repo, 1845 1887 struct branch *branch, struct strbuf *err) 1846 1888 { 1889 + struct remote_state *remote_state = repo->remote_state; 1847 1890 struct remote *remote; 1848 1891 1849 1892 remote = remotes_remote_get( 1850 - remote_state, 1893 + repo, 1851 1894 remotes_pushremote_for_branch(remote_state, branch, NULL)); 1852 1895 if (!remote) 1853 1896 return error_buf(err, ··· 1914 1957 1915 1958 if (!branch->push_tracking_ref) 1916 1959 branch->push_tracking_ref = branch_get_push_1( 1917 - the_repository->remote_state, branch, err); 1960 + the_repository, branch, err); 1918 1961 return branch->push_tracking_ref; 1919 1962 } 1920 1963
+6 -2
remote.h
··· 9 9 10 10 struct option; 11 11 struct transport_ls_refs_options; 12 + struct repository; 12 13 13 14 /** 14 15 * The API gives access to the configuration related to remotes. It handles ··· 315 316 316 317 char *pushremote_name; 317 318 318 - /* An array of the "merge" lines in the configuration. */ 319 - const char **merge_name; 319 + /* True if set_merge() has been called to finalize the merge array */ 320 + int set_merge; 320 321 321 322 /** 322 323 * An array of the struct refspecs used for the merge lines. That is, ··· 337 338 const char *remote_for_branch(struct branch *branch, int *explicit); 338 339 const char *pushremote_for_branch(struct branch *branch, int *explicit); 339 340 char *remote_ref_for_branch(struct branch *branch, int for_push); 341 + 342 + const char *repo_default_remote(struct repository *repo); 343 + const char *repo_remote_from_url(struct repository *repo, const char *url); 340 344 341 345 /* returns true if the given branch has merge configuration given. */ 342 346 int branch_has_merge_config(struct branch *branch);
-12
submodule-config.c
··· 235 235 return 0; 236 236 } 237 237 238 - static int starts_with_dot_slash(const char *const path) 239 - { 240 - return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_SLASH | 241 - PATH_MATCH_XPLATFORM); 242 - } 243 - 244 - static int starts_with_dot_dot_slash(const char *const path) 245 - { 246 - return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH | 247 - PATH_MATCH_XPLATFORM); 248 - } 249 - 250 238 static int submodule_url_is_relative(const char *url) 251 239 { 252 240 return starts_with_dot_slash(url) || starts_with_dot_dot_slash(url);
+61
t/t7406-submodule-update.sh
··· 1137 1137 git clone --recurse-submodules top top-clean 1138 1138 ' 1139 1139 1140 + test_expect_success 'submodule update with multiple remotes' ' 1141 + test_when_finished "rm -fr top-cloned" && 1142 + cp -r top-clean top-cloned && 1143 + 1144 + # Create a commit in each repo, starting with bottom 1145 + test_commit -C bottom multiple_remote_commit && 1146 + # Create middle commit 1147 + git -C middle/bottom fetch && 1148 + git -C middle/bottom checkout -f FETCH_HEAD && 1149 + git -C middle add bottom && 1150 + git -C middle commit -m "multiple_remote_commit" && 1151 + # Create top commit 1152 + git -C top/middle fetch && 1153 + git -C top/middle checkout -f FETCH_HEAD && 1154 + git -C top add middle && 1155 + git -C top commit -m "multiple_remote_commit" && 1156 + 1157 + # rename the submodule remote 1158 + git -C top-cloned/middle remote rename origin upstream && 1159 + 1160 + # Add another remote 1161 + git -C top-cloned/middle remote add other bogus && 1162 + 1163 + # Make the update of "middle" a no-op, otherwise we error out 1164 + # because of its unmerged state 1165 + test_config -C top-cloned submodule.middle.update !true && 1166 + git -C top-cloned submodule update --recursive 2>actual.err && 1167 + cat >expect.err <<-\EOF && 1168 + EOF 1169 + test_cmp expect.err actual.err 1170 + ' 1171 + 1172 + test_expect_success 'submodule update with renamed remote' ' 1173 + test_when_finished "rm -fr top-cloned" && 1174 + cp -r top-clean top-cloned && 1175 + 1176 + # Create a commit in each repo, starting with bottom 1177 + test_commit -C bottom rename_commit && 1178 + # Create middle commit 1179 + git -C middle/bottom fetch && 1180 + git -C middle/bottom checkout -f FETCH_HEAD && 1181 + git -C middle add bottom && 1182 + git -C middle commit -m "rename_commit" && 1183 + # Create top commit 1184 + git -C top/middle fetch && 1185 + git -C top/middle checkout -f FETCH_HEAD && 1186 + git -C top add middle && 1187 + git -C top commit -m "rename_commit" && 1188 + 1189 + # rename the submodule remote 1190 + git -C top-cloned/middle remote rename origin upstream && 1191 + 1192 + # Make the update of "middle" a no-op, otherwise we error out 1193 + # because of its unmerged state 1194 + test_config -C top-cloned submodule.middle.update !true && 1195 + git -C top-cloned submodule update --recursive 2>actual.err && 1196 + cat >expect.err <<-\EOF && 1197 + EOF 1198 + test_cmp expect.err actual.err 1199 + ' 1200 + 1140 1201 test_expect_success 'submodule update should skip unmerged submodules' ' 1141 1202 test_when_finished "rm -fr top-cloned" && 1142 1203 cp -r top-clean top-cloned &&