Skip to content

Commit ebddf39

Browse files
dschogitster
authored andcommitted
sequencer: allow introducing new root commits
In the context of the new --rebase-merges mode, which was designed specifically to allow for changing the existing branch topology liberally, a user may want to extract commits into a completely fresh branch that starts with a newly-created root commit. This is now possible by inserting the command `reset [new root]` before `pick`ing the commit that wants to become a root commit. Example: reset [new root] pick 012345 a commit that is about to become a root commit pick 234567 this commit will have the previous one as parent This does not conflict with other uses of the `reset` command because `[new root]` is not (part of) a valid ref name: both the opening bracket as well as the space are illegal in ref names. Signed-off-by: Johannes Schindelin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 21d0764 commit ebddf39

File tree

2 files changed

+62
-12
lines changed

2 files changed

+62
-12
lines changed

sequencer.c

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2747,18 +2747,34 @@ static int do_reset(const char *name, int len, struct replay_opts *opts)
27472747
if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)
27482748
return -1;
27492749

2750-
/* Determine the length of the label */
2751-
for (i = 0; i < len; i++)
2752-
if (isspace(name[i]))
2753-
len = i;
2754-
2755-
strbuf_addf(&ref_name, "refs/rewritten/%.*s", len, name);
2756-
if (get_oid(ref_name.buf, &oid) &&
2757-
get_oid(ref_name.buf + strlen("refs/rewritten/"), &oid)) {
2758-
error(_("could not read '%s'"), ref_name.buf);
2759-
rollback_lock_file(&lock);
2760-
strbuf_release(&ref_name);
2761-
return -1;
2750+
if (len == 10 && !strncmp("[new root]", name, len)) {
2751+
if (!opts->have_squash_onto) {
2752+
const char *hex;
2753+
if (commit_tree("", 0, the_hash_algo->empty_tree,
2754+
NULL, &opts->squash_onto,
2755+
NULL, NULL))
2756+
return error(_("writing fake root commit"));
2757+
opts->have_squash_onto = 1;
2758+
hex = oid_to_hex(&opts->squash_onto);
2759+
if (write_message(hex, strlen(hex),
2760+
rebase_path_squash_onto(), 0))
2761+
return error(_("writing squash-onto"));
2762+
}
2763+
oidcpy(&oid, &opts->squash_onto);
2764+
} else {
2765+
/* Determine the length of the label */
2766+
for (i = 0; i < len; i++)
2767+
if (isspace(name[i]))
2768+
len = i;
2769+
2770+
strbuf_addf(&ref_name, "refs/rewritten/%.*s", len, name);
2771+
if (get_oid(ref_name.buf, &oid) &&
2772+
get_oid(ref_name.buf + strlen("refs/rewritten/"), &oid)) {
2773+
error(_("could not read '%s'"), ref_name.buf);
2774+
rollback_lock_file(&lock);
2775+
strbuf_release(&ref_name);
2776+
return -1;
2777+
}
27622778
}
27632779

27642780
memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));

t/t3430-rebase-merges.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,4 +241,38 @@ test_expect_success 'refuse to merge ancestors of HEAD' '
241241
test_cmp_rev HEAD $before
242242
'
243243

244+
test_expect_success 'root commits' '
245+
git checkout --orphan unrelated &&
246+
(GIT_AUTHOR_NAME="Parsnip" GIT_AUTHOR_EMAIL="[email protected]" \
247+
test_commit second-root) &&
248+
test_commit third-root &&
249+
cat >script-from-scratch <<-\EOF &&
250+
pick third-root
251+
label first-branch
252+
reset [new root]
253+
pick second-root
254+
merge first-branch # Merge the 3rd root
255+
EOF
256+
test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
257+
test_tick &&
258+
git rebase -i --force --root -r &&
259+
test "Parsnip" = "$(git show -s --format=%an HEAD^)" &&
260+
test $(git rev-parse second-root^0) != $(git rev-parse HEAD^) &&
261+
test $(git rev-parse second-root:second-root.t) = \
262+
$(git rev-parse HEAD^:second-root.t) &&
263+
test_cmp_graph HEAD <<-\EOF &&
264+
* Merge the 3rd root
265+
|\
266+
| * third-root
267+
* second-root
268+
EOF
269+
270+
: fast forward if possible &&
271+
before="$(git rev-parse --verify HEAD)" &&
272+
test_might_fail git config --unset sequence.editor &&
273+
test_tick &&
274+
git rebase -i --root -r &&
275+
test_cmp_rev HEAD $before
276+
'
277+
244278
test_done

0 commit comments

Comments
 (0)