From: Junio C Hamano Date: Fri, 8 Apr 2016 21:29:11 +0000 (-0700) Subject: Merge branch 'jc/merge-refuse-new-root' X-Git-Tag: v2.9.0-rc0~144 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/d04aa7ec4738f90220b9e205326f17938b8f89d4?hp=-c Merge branch 'jc/merge-refuse-new-root' "git merge" used to allow merging two branches that have no common base by default, which led to a brand new history of an existing project created and then get pulled by an unsuspecting maintainer, which allowed an unnecessary parallel history merged into the existing project. The command has been taught not to allow this by default, with an escape hatch "--allow-unrelated-histories" option to be used in a rare event that merges histories of two projects that started their lives independently. * jc/merge-refuse-new-root: merge: refuse to create too cool a merge by default --- d04aa7ec4738f90220b9e205326f17938b8f89d4 diff --combined builtin/merge.c index 30b7bd54fa,e3db41b77a..41467e4277 --- a/builtin/merge.c +++ b/builtin/merge.c @@@ -64,6 -64,7 +64,7 @@@ static int option_renormalize static int verbosity; static int allow_rerere_auto; static int abort_current_merge; + static int allow_unrelated_histories; static int show_progress = -1; static int default_to_upstream = 1; static const char *sign_commit; @@@ -221,6 -222,8 +222,8 @@@ static struct option builtin_merge_opti OPT__VERBOSITY(&verbosity), OPT_BOOL(0, "abort", &abort_current_merge, N_("abort the current in-progress merge")), + OPT_BOOL(0, "allow-unrelated-histories", &allow_unrelated_histories, + N_("allow merging unrelated histories")), OPT_SET_INT(0, "progress", &show_progress, N_("force progress reporting"), 1), { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"), N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, @@@ -1187,7 -1190,6 +1190,7 @@@ int cmd_merge(int argc, const char **ar else head_commit = lookup_commit_or_die(head_sha1, "HEAD"); + init_diff_ui_defaults(); git_config(git_merge_config, NULL); if (branch_mergeoptions) @@@ -1258,12 -1260,12 +1261,12 @@@ builtin_merge_options); if (!head_commit) { - struct commit *remote_head; /* * If the merged head is a valid one there is no reason * to forbid "git merge" into a branch yet to be born. * We do the same for "git pull". */ + unsigned char *remote_head_sha1; if (squash) die(_("Squash commit into empty head not supported yet")); if (fast_forward == FF_NO) @@@ -1271,13 -1273,13 +1274,13 @@@ "an empty head")); remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv, NULL); - remote_head = remoteheads->item; - if (!remote_head) + if (!remoteheads) die(_("%s - not something we can merge"), argv[0]); if (remoteheads->next) die(_("Can merge only exactly one commit into empty head")); - read_empty(remote_head->object.oid.hash, 0); - update_ref("initial pull", "HEAD", remote_head->object.oid.hash, + remote_head_sha1 = remoteheads->item->object.oid.hash; + read_empty(remote_head_sha1, 0); + update_ref("initial pull", "HEAD", remote_head_sha1, NULL, 0, UPDATE_REFS_DIE_ON_ERR); goto done; } @@@ -1398,9 -1400,12 +1401,12 @@@ update_ref("updating ORIG_HEAD", "ORIG_HEAD", head_commit->object.oid.hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR); - if (remoteheads && !common) - ; /* No common ancestors found. We need a real merge. */ - else if (!remoteheads || + if (remoteheads && !common) { + /* No common ancestors found. */ + if (!allow_unrelated_histories) + die(_("refusing to merge unrelated histories")); + /* otherwise, we need a real merge. */ + } else if (!remoteheads || (!remoteheads->next && !common->next && common->item == remoteheads->item)) { /* diff --combined t/t5500-fetch-pack.sh index 9b9bec468a,2569580232..91a69fc33a --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@@ -14,7 -14,7 +14,7 @@@ test_description='Testing multi_ack pac add () { name=$1 && text="$@" && - branch=`echo $name | sed -e 's/^\(.\).*$/\1/'` && + branch=$(echo $name | sed -e 's/^\(.\).*$/\1/') && parents="" && shift && @@@ -50,18 -50,18 +50,18 @@@ pull_to_client () case "$heads" in *B*) echo $BTIP > .git/refs/heads/B;; esac && - git symbolic-ref HEAD refs/heads/`echo $heads \ - | sed -e "s/^\(.\).*$/\1/"` && + git symbolic-ref HEAD refs/heads/$(echo $heads \ + | sed -e "s/^\(.\).*$/\1/") && git fsck --full && mv .git/objects/pack/pack-* . && - p=`ls -1 pack-*.pack` && + p=$(ls -1 pack-*.pack) && git unpack-objects <$p && git fsck --full && - idx=`echo pack-*.idx` && - pack_count=`git show-index <$idx | wc -l` && + idx=$(echo pack-*.idx) && + pack_count=$(git show-index <$idx | wc -l) && test $pack_count = $count && rm -f pack-* ) @@@ -132,13 -132,13 +132,13 @@@ test_expect_success 'single given branc test_expect_success 'clone shallow depth 1' ' git clone --no-single-branch --depth 1 "file://$(pwd)/." shallow0 && - test "`git --git-dir=shallow0/.git rev-list --count HEAD`" = 1 + test "$(git --git-dir=shallow0/.git rev-list --count HEAD)" = 1 ' test_expect_success 'clone shallow depth 1 with fsck' ' git config --global fetch.fsckobjects true && git clone --no-single-branch --depth 1 "file://$(pwd)/." shallow0fsck && - test "`git --git-dir=shallow0fsck/.git rev-list --count HEAD`" = 1 && + test "$(git --git-dir=shallow0fsck/.git rev-list --count HEAD)" = 1 && git config --global --unset fetch.fsckobjects ' @@@ -147,7 -147,7 +147,7 @@@ test_expect_success 'clone shallow' ' test_expect_success 'clone shallow depth count' ' - test "`git --git-dir=shallow/.git rev-list --count HEAD`" = 2 + test "$(git --git-dir=shallow/.git rev-list --count HEAD)" = 2 ' test_expect_success 'clone shallow object count' ' @@@ -259,7 -259,8 +259,8 @@@ test_expect_success 'clone shallow obje test_expect_success 'pull in shallow repo with missing merge base' ' ( cd shallow && - test_must_fail git pull --depth 4 .. A + git fetch --depth 4 .. A + test_must_fail git merge --allow-unrelated-histories FETCH_HEAD ) ' @@@ -273,15 -274,16 +274,16 @@@ test_expect_success 'additional simple ' test_expect_success 'clone shallow depth count' ' - test "`git --git-dir=shallow/.git rev-list --count HEAD`" = 11 + test "$(git --git-dir=shallow/.git rev-list --count HEAD)" = 11 ' test_expect_success 'clone shallow object count' ' ( cd shallow && + git prune && git count-objects -v ) > count.shallow && - grep "^count: 55" count.shallow + grep "^count: 54" count.shallow ' test_expect_success 'fetch --no-shallow on full repo' ' @@@ -531,20 -533,6 +533,20 @@@ test_expect_success 'shallow fetch wit git fsck ) ' + +test_expect_success 'fetch-pack can fetch a raw sha1' ' + git init hidden && + ( + cd hidden && + test_commit 1 && + test_commit 2 && + git update-ref refs/hidden/one HEAD^ && + git config transfer.hiderefs refs/hidden && + git config uploadpack.allowtipsha1inwant true + ) && + git fetch-pack hidden $(git -C hidden rev-parse refs/hidden/one) +' + check_prot_path () { cat >expected <<-EOF && Diag: url=$1 diff --combined t/t9400-git-cvsserver-server.sh index d708cbf032,bc19811dde..432c61d246 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@@ -25,11 -25,11 +25,11 @@@ perl -e 'use DBI; use DBD::SQLite' >/de test_done } -WORKDIR=$(pwd) -SERVERDIR=$(pwd)/gitcvs.git +WORKDIR=$PWD +SERVERDIR=$PWD/gitcvs.git git_config="$SERVERDIR/config" CVSROOT=":fork:$SERVERDIR" -CVSWORK="$(pwd)/cvswork" +CVSWORK="$PWD/cvswork" CVS_SERVER=git-cvsserver export CVSROOT CVS_SERVER @@@ -45,7 -45,8 +45,8 @@@ test_expect_success 'setup' touch secondrootfile && git add secondrootfile && git commit -m "second root") && - git pull secondroot master && + git fetch secondroot master && + git merge --allow-unrelated-histories FETCH_HEAD && git clone -q --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 && GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true && GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" &&