Merge branch 'fc/transport-helper-fixes'
authorJunio C Hamano <gitster@pobox.com>
Tue, 18 Mar 2014 20:49:32 +0000 (13:49 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 18 Mar 2014 20:49:33 +0000 (13:49 -0700)
Updates transport-helper, fast-import and fast-export to allow the
ref mapping and ref deletion in a way similar to the natively
supported transports.

* fc/transport-helper-fixes:
remote-bzr: support the new 'force' option
test-hg.sh: tests are now expected to pass
transport-helper.c: do not overwrite forced bit
transport-helper: check for 'forced update' message
transport-helper: add 'force' to 'export' helpers
transport-helper: don't update refs in dry-run
transport-helper: mismerge fix

Documentation/gitremote-helpers.txt
contrib/remote-helpers/git-remote-bzr
contrib/remote-helpers/test-bzr.sh
contrib/remote-helpers/test-hg.sh
git-remote-testgit.sh
t/t5801-remote-helpers.sh
transport-helper.c
index c2908db76317c91cf5502065e9c4bf1d97da19bd..64f7ad26b40085ced91e73fd806c11e90ad2eb9a 100644 (file)
@@ -437,6 +437,10 @@ set by Git if the remote helper has the 'option' capability.
 'option check-connectivity' \{'true'|'false'\}::
        Request the helper to check connectivity of a clone.
 
+'option force' \{'true'|'false'\}::
+       Request the helper to perform a force update.  Defaults to
+       'false'.
+
 'option cloning \{'true'|'false'\}::
        Notify the helper this is a clone request (i.e. the current
        repository is guaranteed empty).
index 332aba784b8810120df8e1ddfafeb034a55337a3..5f4b2e3e160f60955e25f8b8fedf8c122dd5c73c 100755 (executable)
@@ -684,7 +684,8 @@ def do_export(parser):
                 peer = bzrlib.branch.Branch.open(peers[name],
                                                  possible_transports=transports)
                 try:
-                    peer.bzrdir.push_branch(branch, revision_id=revid)
+                    peer.bzrdir.push_branch(branch, revision_id=revid,
+                                            overwrite=force)
                 except bzrlib.errors.DivergedBranches:
                     print "error %s non-fast forward" % ref
                     continue
@@ -718,8 +719,32 @@ def do_capabilities(parser):
         print "*import-marks %s" % path
     print "*export-marks %s" % path
 
+    print "option"
     print
 
+class InvalidOptionValue(Exception):
+    pass
+
+def get_bool_option(val):
+    if val == 'true':
+        return True
+    elif val == 'false':
+        return False
+    else:
+        raise InvalidOptionValue()
+
+def do_option(parser):
+    global force
+    opt, val = parser[1:3]
+    try:
+        if opt == 'force':
+            force = get_bool_option(val)
+            print 'ok'
+        else:
+            print 'unsupported'
+    except InvalidOptionValue:
+        print "error '%s' is not a valid value for option '%s'" % (val, opt)
+
 def ref_is_valid(name):
     return not True in [c in name for c in '~^: \\']
 
@@ -882,6 +907,7 @@ def main(args):
     global is_tmp
     global branches, peers
     global transports
+    global force
 
     marks = None
     is_tmp = False
@@ -904,6 +930,7 @@ def main(args):
     branches = {}
     peers = {}
     transports = []
+    force = False
 
     if alias[5:] == url:
         is_tmp = True
@@ -936,6 +963,8 @@ def main(args):
             do_import(parser)
         elif parser.check('export'):
             do_export(parser)
+        elif parser.check('option'):
+            do_option(parser)
         else:
             die('unhandled command: %s' % line)
         sys.stdout.flush()
index 1e53ff9a584a302366dcbd647a2e27db3fd1b9fe..4f379c2ab499f2ca5556f844cbdcacb98fffa13c 100755 (executable)
@@ -66,13 +66,33 @@ test_expect_success 'pushing' '
        test_cmp expected actual
 '
 
+test_expect_success 'forced pushing' '
+       (
+       cd gitrepo &&
+       echo three-new >content &&
+       git commit -a --amend -m three-new &&
+       git push -f
+       ) &&
+
+       (
+       cd bzrrepo &&
+       # the forced update overwrites the bzr branch but not the bzr
+       # working directory (it tries to merge instead)
+       bzr revert
+       ) &&
+
+       echo three-new >expected &&
+       cat bzrrepo/content >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'roundtrip' '
        (
        cd gitrepo &&
        git pull &&
        git log --format="%s" -1 origin/master >actual
        ) &&
-       echo three >expected &&
+       echo three-new >expected &&
        test_cmp expected actual &&
 
        (cd gitrepo && git push && git pull) &&
index 5d128a5da9a1afd3bf441f58e75d4f02a64509d5..a933b1e30c6fe82393f3df1446333386d9795b12 100755 (executable)
@@ -680,7 +680,7 @@ test_expect_success 'remote big push fetch first' '
        )
 '
 
-test_expect_failure 'remote big push force' '
+test_expect_success 'remote big push force' '
        test_when_finished "rm -rf hgrepo gitrepo*" &&
 
        setup_big_push
@@ -710,7 +710,7 @@ test_expect_failure 'remote big push force' '
        check_bookmark hgrepo new_bmark six
 '
 
-test_expect_failure 'remote big push dry-run' '
+test_expect_success 'remote big push dry-run' '
        test_when_finished "rm -rf hgrepo gitrepo*" &&
 
        setup_big_push
index 6d2f282d32212b605a1237bae224ecbba05cacd1..1c006a0518e247d58759df98602f6dae3935caf6 100755 (executable)
@@ -15,6 +15,8 @@ test -z "$refspec" && prefix="refs"
 
 export GIT_DIR="$url/.git"
 
+force=
+
 mkdir -p "$dir"
 
 if test -z "$GIT_REMOTE_TESTGIT_NO_MARKS"
@@ -39,6 +41,7 @@ do
                fi
                test -n "$GIT_REMOTE_TESTGIT_SIGNED_TAGS" && echo "signed-tags"
                test -n "$GIT_REMOTE_TESTGIT_NO_PRIVATE_UPDATE" && echo "no-private-update"
+               echo 'option'
                echo
                ;;
        list)
@@ -93,6 +96,7 @@ do
                before=$(git for-each-ref --format=' %(refname) %(objectname) ')
 
                git fast-import \
+                       ${force:+--force} \
                        ${testgitmarks:+"--import-marks=$testgitmarks"} \
                        ${testgitmarks:+"--export-marks=$testgitmarks"} \
                        --quiet
@@ -115,6 +119,20 @@ do
 
                echo
                ;;
+       option\ *)
+               read cmd opt val <<-EOF
+               $line
+               EOF
+               case $opt in
+               force)
+                       test $val = "true" && force="true" || force=
+                       echo "ok"
+                       ;;
+               *)
+                       echo "unsupported"
+                       ;;
+               esac
+               ;;
        '')
                exit
                ;;
index 613f69a254bab23e1f09126b4a7f3dca8692deaa..c33cc25805d2a913725355a183118a0dd5547800 100755 (executable)
@@ -94,6 +94,19 @@ test_expect_failure 'push new branch with old:new refspec' '
        compare_refs local HEAD server refs/heads/new-refspec
 '
 
+test_expect_success 'forced push' '
+       (cd local &&
+       git checkout -b force-test &&
+       echo content >> file &&
+       git commit -a -m eight &&
+       git push origin force-test &&
+       echo content >> file &&
+       git commit -a --amend -m eight-modified &&
+       git push --force origin force-test
+       ) &&
+       compare_refs local refs/heads/force-test server refs/heads/force-test
+'
+
 test_expect_success 'cloning without refspec' '
        GIT_REMOTE_TESTGIT_REFSPEC="" \
        git clone "testgit::${PWD}/server" local2 2>error &&
index ad72fbd53cb7bfc7fc037d98288b0cc831ea949a..86e1679c1e0e1e58ebe5297f4c5f48ca1a1f6418 100644 (file)
@@ -650,7 +650,7 @@ static int push_update_ref_status(struct strbuf *buf,
                                   struct ref *remote_refs)
 {
        char *refname, *msg;
-       int status;
+       int status, forced = 0;
 
        if (starts_with(buf->buf, "ok ")) {
                status = REF_STATUS_OK;
@@ -708,6 +708,11 @@ static int push_update_ref_status(struct strbuf *buf,
                        free(msg);
                        msg = NULL;
                }
+               else if (!strcmp(msg, "forced update")) {
+                       forced = 1;
+                       free(msg);
+                       msg = NULL;
+               }
        }
 
        if (*ref)
@@ -729,12 +734,14 @@ static int push_update_ref_status(struct strbuf *buf,
        }
 
        (*ref)->status = status;
+       (*ref)->forced_update |= forced;
        (*ref)->remote_status = msg;
        return !(status == REF_STATUS_OK);
 }
 
 static void push_update_refs_status(struct helper_data *data,
-                                   struct ref *remote_refs)
+                                   struct ref *remote_refs,
+                                   int flags)
 {
        struct strbuf buf = STRBUF_INIT;
        struct ref *ref = remote_refs;
@@ -748,7 +755,7 @@ static void push_update_refs_status(struct helper_data *data,
                if (push_update_ref_status(&buf, &ref, remote_refs))
                        continue;
 
-               if (!data->refspecs || data->no_private_update)
+               if (flags & TRANSPORT_PUSH_DRY_RUN || !data->refspecs || data->no_private_update)
                        continue;
 
                /* propagate back the update to the remote namespace */
@@ -839,7 +846,7 @@ static int push_refs_with_push(struct transport *transport,
        sendline(data, &buf);
        strbuf_release(&buf);
 
-       push_update_refs_status(data, remote_refs);
+       push_update_refs_status(data, remote_refs, flags);
        return 0;
 }
 
@@ -860,6 +867,11 @@ static int push_refs_with_export(struct transport *transport,
                        die("helper %s does not support dry-run", data->name);
        }
 
+       if (flags & TRANSPORT_PUSH_FORCE) {
+               if (set_helper_option(transport, "force", "true") != 0)
+                       warning("helper %s does not support 'force'", data->name);
+       }
+
        helper = get_helper(transport);
 
        write_constant(helper->in, "export\n");
@@ -881,9 +893,6 @@ static int push_refs_with_export(struct transport *transport,
                }
                free(private);
 
-               if (ref->deletion)
-                       die("remote-helpers do not support ref deletion");
-
                if (ref->peer_ref) {
                        if (strcmp(ref->peer_ref->name, ref->name))
                                die("remote-helpers do not support old:new syntax");
@@ -896,7 +905,7 @@ static int push_refs_with_export(struct transport *transport,
 
        if (finish_command(&exporter))
                die("Error while running fast-export");
-       push_update_refs_status(data, remote_refs);
+       push_update_refs_status(data, remote_refs, flags);
        return 0;
 }