Index: src/checkin.c ================================================================== --- src/checkin.c +++ src/checkin.c @@ -2161,11 +2161,15 @@ /* ** Autosync if autosync is enabled and this is not a private check-in. */ if( !g.markPrivate ){ - if( autosync_loop(SYNC_PULL, db_get_int("autosync-tries", 1), 1) ){ + int syncFlags = SYNC_PULL; + if( vid!=0 && !allowFork && !forceFlag ){ + syncFlags |= SYNC_CKIN_LOCK; + } + if( autosync_loop(syncFlags, db_get_int("autosync-tries", 1), 1) ){ fossil_exit(1); } } /* Require confirmation to continue with the check-in if there is @@ -2278,11 +2282,11 @@ "See https://fossil-scm.org/fossil/doc/trunk/www/branching.wiki#branching"); } sCiInfo.zBranch = db_get("main-branch", "trunk"); } }else if( sCiInfo.zBranch==0 && allowFork==0 && forceFlag==0 - && g.markPrivate==0 && !is_a_leaf(vid) + && g.markPrivate==0 && (g.ckinLockFail || !is_a_leaf(vid)) ){ /* Can't avoid duplicating this string because some C compilers ** refuse to see static const char zErr[] = "... as "constant" ** enough for a printf() style format string. (e.g. Clang 10) */ Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -190,10 +190,11 @@ FILE *httpOut; /* Send HTTP output here */ int xlinkClusterOnly; /* Set when cloning. Only process clusters */ int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */ int *aCommitFile; /* Array of files to be committed */ int markPrivate; /* All new artifacts are private if true */ + int ckinLockFail; /* Check-in lock failure received from server */ int clockSkewSeen; /* True if clocks on client and server out of sync */ int wikiFlags; /* Wiki conversion flags applied to %W */ char isHTTP; /* True if server/CGI modes, else assume CLI. */ char javascriptHyperlink; /* If true, set href= using script, not HTML */ Blob httpHeader; /* Complete text of the HTTP request header */ Index: src/xfer.c ================================================================== --- src/xfer.c +++ src/xfer.c @@ -1545,10 +1545,62 @@ send_unversioned_catalog(&xfer); } } uvCatalogSent = 1; } + + /* pragma ci-lock CHECKIN-HASH CLIENT-ID + ** + ** The client wants to make non-branch commit against the check-in + ** identified by CHECKIN-HASH. The server will remember this and + ** subsequent ci-lock request from different clients will generate + ** a ci-lock-fail pragma in the reply. + */ + if( blob_eq(&xfer.aToken[1], "ci-lock") + && xfer.nToken==4 + && blob_is_hname(&xfer.aToken[2]) + ){ + Stmt q; + sqlite3_int64 iNow = time(0); + int seenFault = 0; + db_prepare(&q, + "SELECT json_extract(value,'$.login')," + " mtime," + " json_extract(value,'$.clientid')," + " (SELECT rid FROM blob WHERE uuid=substr(name,9))," + " name" + " FROM config WHERE name GLOB 'ci-lock-*'" + ); + while( db_step(&q)==SQLITE_ROW ){ + int x = db_column_int(&q,3); + const char *zName = db_column_text(&q,4); + if( db_column_int64(&q,1)