From patchwork Fri Jun 2 10:25:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Couder X-Patchwork-Id: 13265056 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 45A78C7EE29 for ; Fri, 2 Jun 2023 10:29:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235487AbjFBK3Q (ORCPT ); Fri, 2 Jun 2023 06:29:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49732 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232921AbjFBK2l (ORCPT ); Fri, 2 Jun 2023 06:28:41 -0400 Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 19B2F1729 for ; Fri, 2 Jun 2023 03:26:41 -0700 (PDT) Received: by mail-wm1-x32d.google.com with SMTP id 5b1f17b1804b1-3f6a6b9c079so17922025e9.1 for ; Fri, 02 Jun 2023 03:26:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1685701566; x=1688293566; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=KxpvNFvJnRpwZpW3piDtJ/hKH98TDXtBseRPfJghvMY=; b=hcx6YuGu3eaXxbtWavdSn1yxaSabAhM/4ejH7faFoPi4oeo1fBHlhIAwBDgR927FWI gUH2uIVddrTIuU9HIqFIsJgUgq0W1eP/uHwRZ7TUb86UYHp8MuABeVFUyVqiKpuRps1E +cbcS/r/7hlsfRc/qMH2N1Z+WMb3WaI416mOAqE5h9/6r5r9pK+yl1yrp1ZihBaAE1fr LUKi05EewYUfQOBZpYnMZ5R9DcKLGk5mSvvo4YKyc7WdwgkhGhhYvXm+o50/VbPj0UeC 8IdvcIAnuvrcRyprzj0jI3Ij4XUy5wo4oF/raJ3wv8XY63wPfG+UhpIoKUA9Byn4TLXq 1ecA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1685701566; x=1688293566; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=KxpvNFvJnRpwZpW3piDtJ/hKH98TDXtBseRPfJghvMY=; b=Ymam/TPed1jTM8TdhbwY4AWEFNGuuuIXgcCWsfb8BFSkPXXWUOyrqj4LEPGApx+838 +z319ylTwvpc5aRxirlqk4fjwD+KGSQbZar6sKOH0aVa2ZTvgk15PuWdcoiju5GZ7sks knwgtNE9j/bny2kMabojhg7hyR+A9IjfNOBh5uK/buhQx16vgNPp/io5+s5l22Oe3Lkw FBLJ7x15GVby5LphdO63I67mtLdIkfRnNXfdfhXbdIC1A1EUJvNgaSHs/oUevJHVd/Pf VPliDbkvfbrWnYWyg8sEdiFHsguE47QPsQzWWYDXPjNjzpQ5GZsS31wy3Zmfk9gnIOmV 9YBQ== X-Gm-Message-State: AC+VfDwrQzTXE/DuZgRV5DWZc/2ili2/k7PBlCGfebwqeDqSvnJDo91e SzvSXAeUX8aIZnPNg9OVjj79rdoaxANvyw== X-Google-Smtp-Source: ACHHUZ44BA5O2LKgk0XO6i8pB3qv0FxkJb6kI5KBT5Cbumd9FnRY9HOZ81YZ1xyl9k8HNX36QofV6A== X-Received: by 2002:a7b:c84f:0:b0:3f5:aa2:288b with SMTP id c15-20020a7bc84f000000b003f50aa2288bmr1521673wml.0.1685701566223; Fri, 02 Jun 2023 03:26:06 -0700 (PDT) Received: from christian-Precision-5550.. ([2a04:cec0:1169:70dc:520b:5de9:c23d:7cde]) by smtp.gmail.com with ESMTPSA id 18-20020a05600c029200b003f601a31ca2sm1468035wmk.33.2023.06.02.03.26.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 02 Jun 2023 03:26:05 -0700 (PDT) From: Christian Couder To: git@vger.kernel.org Cc: Junio C Hamano , Patrick Steinhardt , Johannes Schindelin , Elijah Newren , John Cai , Derrick Stolee , Phillip Wood , Felipe Contreras , Calvin Wan , Christian Couder Subject: [PATCH v3 10/15] replay: make it a minimal server side command Date: Fri, 2 Jun 2023 12:25:28 +0200 Message-ID: <20230602102533.876905-11-christian.couder@gmail.com> X-Mailer: git-send-email 2.41.0.15.ga6d88fc8f0 In-Reply-To: <20230602102533.876905-1-christian.couder@gmail.com> References: <20230509175347.1714141-1-christian.couder@gmail.com> <20230602102533.876905-1-christian.couder@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Elijah Newren We want this command to be a minimal command that just does server side picking of commits, displaying the results on stdout for higher level scripts to consume. So let's simplify it: * remove the worktree and index reading/writing, * remove the ref (and reflog) updating, * remove the assumptions tying us to HEAD, since (a) this is not a rebase and (b) we want to be able to pick commits in a bare repo, i.e. to/from branches that are not checked out and not the main branch, * remove unneeded includes, * handle rebasing multiple branches by printing on stdout the update ref commands that should be performed. The output can be piped into `git update-ref --stdin` for the ref updates to happen. In the future to make it easier for users to use this command directly maybe an option can be added to automatically pipe its output into `git update-ref`. Co-authored-by: Christian Couder Signed-off-by: Elijah Newren Signed-off-by: Christian Couder --- builtin/replay.c | 78 ++++++++---------------- t/t6429-merge-sequence-rename-caching.sh | 39 +++++++----- 2 files changed, 51 insertions(+), 66 deletions(-) diff --git a/builtin/replay.c b/builtin/replay.c index 3b86fe140f..9385973ffc 100644 --- a/builtin/replay.c +++ b/builtin/replay.c @@ -6,10 +6,7 @@ #include "git-compat-util.h" #include "builtin.h" -#include "cache-tree.h" -#include "commit.h" #include "environment.h" -#include "gettext.h" #include "hex.h" #include "lockfile.h" #include "merge-ort.h" @@ -17,8 +14,6 @@ #include "parse-options.h" #include "refs.h" #include "revision.h" -#include "sequencer.h" -#include "setup.h" #include "strvec.h" #include #include @@ -101,6 +96,7 @@ static struct commit *pick_regular_commit(struct commit *pickme, pickme_tree = repo_get_commit_tree(the_repository, pickme); base_tree = repo_get_commit_tree(the_repository, base); + merge_opt->branch1 = short_commit_name(last_commit); merge_opt->branch2 = short_commit_name(pickme); merge_opt->ancestor = xstrfmt("parent of %s", merge_opt->branch2); @@ -121,15 +117,12 @@ int cmd_replay(int argc, const char **argv, const char *prefix) { struct commit *onto; const char *onto_name = NULL; - struct commit *last_commit = NULL, *last_picked_commit = NULL; - struct lock_file lock = LOCK_INIT; + struct commit *last_commit = NULL; struct strvec rev_walk_args = STRVEC_INIT; struct rev_info revs; struct commit *commit; struct merge_options merge_opt; - struct tree *head_tree; struct merge_result result; - struct strbuf reflog_msg = STRBUF_INIT; struct strbuf branch_name = STRBUF_INIT; int ret = 0; @@ -160,10 +153,6 @@ int cmd_replay(int argc, const char **argv, const char *prefix) onto = peel_committish(onto_name); strbuf_addf(&branch_name, "refs/heads/%s", argv[2]); - repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR); - if (repo_read_index(the_repository) < 0) - BUG("Could not read index"); - repo_init_revisions(the_repository, &revs, prefix); strvec_pushl(&rev_walk_args, "", argv[2], "--not", argv[1], NULL); @@ -189,58 +178,45 @@ int cmd_replay(int argc, const char **argv, const char *prefix) init_merge_options(&merge_opt, the_repository); memset(&result, 0, sizeof(result)); merge_opt.show_rename_progress = 0; - merge_opt.branch1 = "HEAD"; - head_tree = repo_get_commit_tree(the_repository, onto); - result.tree = head_tree; + result.tree = repo_get_commit_tree(the_repository, onto); last_commit = onto; while ((commit = get_revision(&revs))) { - struct commit *pick; + const struct name_decoration *decoration; if (!commit->parents) die(_("replaying down to root commit is not supported yet!")); if (commit->parents->next) die(_("replaying merge commits is not supported yet!")); - pick = pick_regular_commit(commit, last_commit, &merge_opt, &result); - if (!pick) + last_commit = pick_regular_commit(commit, last_commit, &merge_opt, &result); + if (!last_commit) break; - last_commit = pick; - last_picked_commit = commit; + + decoration = get_name_decoration(&commit->object); + if (!decoration) + continue; + + while (decoration) { + if (decoration->type == DECORATION_REF_LOCAL) { + printf("update %s %s %s\n", + decoration->name, + oid_to_hex(&last_commit->object.oid), + oid_to_hex(&commit->object.oid)); + } + decoration = decoration->next; + } } + /* Cleanup */ merge_finalize(&merge_opt, &result); + ret = result.clean; - if (result.clean < 0) - exit(128); - - if (result.clean) { - strbuf_addf(&reflog_msg, "finish rebase %s onto %s", - oid_to_hex(&last_picked_commit->object.oid), - oid_to_hex(&last_commit->object.oid)); - if (update_ref(reflog_msg.buf, branch_name.buf, - &last_commit->object.oid, - &last_picked_commit->object.oid, - REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) { - error(_("could not update %s"), argv[2]); - die("Failed to update %s", argv[2]); - } - if (create_symref("HEAD", branch_name.buf, reflog_msg.buf) < 0) - die(_("unable to update HEAD")); - } else { - strbuf_addf(&reflog_msg, "rebase progress up to %s", - oid_to_hex(&last_picked_commit->object.oid)); - if (update_ref(reflog_msg.buf, "HEAD", - &last_commit->object.oid, - &onto->object.oid, - REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) { - error(_("could not update %s"), argv[2]); - die("Failed to update %s", argv[2]); - } - } - ret = (result.clean == 0); cleanup: - strbuf_release(&reflog_msg); strbuf_release(&branch_name); release_revisions(&revs); - return ret; + + /* Return */ + if (ret < 0) + exit(128); + return ret ? 0 : 1; } diff --git a/t/t6429-merge-sequence-rename-caching.sh b/t/t6429-merge-sequence-rename-caching.sh index 7670b72008..099aefeffc 100755 --- a/t/t6429-merge-sequence-rename-caching.sh +++ b/t/t6429-merge-sequence-rename-caching.sh @@ -71,8 +71,9 @@ test_expect_success 'caching renames does not preclude finding new ones' ' git switch upstream && - git replay --onto HEAD upstream~1 topic && - git reset --hard topic && + git replay --onto HEAD upstream~1 topic >out && + git update-ref --stdin tracked-files && test_line_count = 2 tracked-files && @@ -140,7 +141,9 @@ test_expect_success 'cherry-pick both a commit and its immediate revert' ' GIT_TRACE2_PERF="$(pwd)/trace.output" && export GIT_TRACE2_PERF && - git replay --onto HEAD upstream~1 topic && + git replay --onto HEAD upstream~1 topic >out && + git update-ref --stdin calls && test_line_count = 1 calls @@ -198,8 +201,9 @@ test_expect_success 'rename same file identically, then reintroduce it' ' GIT_TRACE2_PERF="$(pwd)/trace.output" && export GIT_TRACE2_PERF && - git replay --onto HEAD upstream~1 topic && - git reset --hard topic && + git replay --onto HEAD upstream~1 topic >out && + git update-ref --stdin tracked && test_line_count = 2 tracked && @@ -275,8 +279,9 @@ test_expect_success 'rename same file identically, then add file to old dir' ' GIT_TRACE2_PERF="$(pwd)/trace.output" && export GIT_TRACE2_PERF && - git replay --onto HEAD upstream~1 topic && - git reset --hard topic && + git replay --onto HEAD upstream~1 topic >out && + git update-ref --stdin tracked && test_line_count = 4 tracked && @@ -451,8 +456,9 @@ test_expect_success 'dir rename unneeded, then add new file to old dir' ' GIT_TRACE2_PERF="$(pwd)/trace.output" && export GIT_TRACE2_PERF && - git replay --onto HEAD upstream~1 topic && - git reset --hard topic && + git replay --onto HEAD upstream~1 topic >out && + git update-ref --stdin calls && test_line_count = 2 calls && @@ -517,8 +523,9 @@ test_expect_success 'dir rename unneeded, then rename existing file into old dir GIT_TRACE2_PERF="$(pwd)/trace.output" && export GIT_TRACE2_PERF && - git replay --onto HEAD upstream~1 topic && - git reset --hard topic && + git replay --onto HEAD upstream~1 topic >out && + git update-ref --stdin calls && test_line_count = 3 calls && @@ -619,8 +626,9 @@ test_expect_success 'caching renames only on upstream side, part 1' ' GIT_TRACE2_PERF="$(pwd)/trace.output" && export GIT_TRACE2_PERF && - git replay --onto HEAD upstream~1 topic && - git reset --hard topic && + git replay --onto HEAD upstream~1 topic >out && + git update-ref --stdin calls && test_line_count = 1 calls && @@ -677,8 +685,9 @@ test_expect_success 'caching renames only on upstream side, part 2' ' GIT_TRACE2_PERF="$(pwd)/trace.output" && export GIT_TRACE2_PERF && - git replay --onto HEAD upstream~1 topic && - git reset --hard topic && + git replay --onto HEAD upstream~1 topic >out && + git update-ref --stdin calls && test_line_count = 2 calls &&