Skip to content

Commit 1806c29

Browse files
pcloudsgitster
authored andcommitted
switch: make --orphan switch to an empty tree
Switching and creating branches always involves knowing the <start-point> to begin the new branch from. Sometimes, people want to create a new branch that does not have any commits yet; --orphan is a flag to allow that. --orphan overrides the default of HEAD for <start-point> instead causing us to start from an empty history with all tracked files removed from the index and working tree. The use of --orphan is incompatible with specifying a <start-point>. A note on the implementation. An alternative is just create a dummy commit in-core with empty tree and switch to it. But there's a chance the commit's SHA-1 may end up somewhere permanent like reflog. It's best to make sure "commit" pointer is NULL to avoid it. Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c45f0f5 commit 1806c29

File tree

1 file changed

+31
-8
lines changed

1 file changed

+31
-8
lines changed

builtin/checkout.c

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ struct checkout_opts {
5858
int switch_branch_doing_nothing_is_ok;
5959
int only_merge_on_switching_branches;
6060
int can_switch_when_in_progress;
61+
int orphan_from_empty_tree;
6162

6263
const char *new_branch;
6364
const char *new_branch_force;
@@ -568,15 +569,21 @@ static int merge_working_tree(const struct checkout_opts *opts,
568569
{
569570
int ret;
570571
struct lock_file lock_file = LOCK_INIT;
572+
struct tree *new_tree;
571573

572574
hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
573575
if (read_cache_preload(NULL) < 0)
574576
return error(_("index file corrupt"));
575577

576578
resolve_undo_clear();
579+
if (opts->new_orphan_branch && opts->orphan_from_empty_tree) {
580+
if (new_branch_info->commit)
581+
BUG("'switch --orphan' should never accept a commit as starting point");
582+
new_tree = parse_tree_indirect(the_hash_algo->empty_tree);
583+
} else
584+
new_tree = get_commit_tree(new_branch_info->commit);
577585
if (opts->discard_changes) {
578-
ret = reset_tree(get_commit_tree(new_branch_info->commit),
579-
opts, 1, writeout_error);
586+
ret = reset_tree(new_tree, opts, 1, writeout_error);
580587
if (ret)
581588
return ret;
582589
} else {
@@ -614,7 +621,8 @@ static int merge_working_tree(const struct checkout_opts *opts,
614621
&old_branch_info->commit->object.oid :
615622
the_hash_algo->empty_tree);
616623
init_tree_desc(&trees[0], tree->buffer, tree->size);
617-
tree = parse_tree_indirect(&new_branch_info->commit->object.oid);
624+
parse_tree(new_tree);
625+
tree = new_tree;
618626
init_tree_desc(&trees[1], tree->buffer, tree->size);
619627

620628
ret = unpack_trees(2, trees, &topts);
@@ -663,7 +671,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
663671
o.verbosity = 0;
664672
work = write_tree_from_memory(&o);
665673

666-
ret = reset_tree(get_commit_tree(new_branch_info->commit),
674+
ret = reset_tree(new_tree,
667675
opts, 1,
668676
writeout_error);
669677
if (ret)
@@ -672,13 +680,13 @@ static int merge_working_tree(const struct checkout_opts *opts,
672680
o.branch1 = new_branch_info->name;
673681
o.branch2 = "local";
674682
ret = merge_trees(&o,
675-
get_commit_tree(new_branch_info->commit),
683+
new_tree,
676684
work,
677685
get_commit_tree(old_branch_info->commit),
678686
&result);
679687
if (ret < 0)
680688
exit(128);
681-
ret = reset_tree(get_commit_tree(new_branch_info->commit),
689+
ret = reset_tree(new_tree,
682690
opts, 0,
683691
writeout_error);
684692
strbuf_release(&o.obuf);
@@ -696,7 +704,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
696704
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
697705
die(_("unable to write new index file"));
698706

699-
if (!opts->discard_changes && !opts->quiet)
707+
if (!opts->discard_changes && !opts->quiet && new_branch_info->commit)
700708
show_local_changes(&new_branch_info->commit->object, &opts->diff_options);
701709

702710
return 0;
@@ -897,7 +905,10 @@ static void orphaned_commit_warning(struct commit *old_commit, struct commit *ne
897905
add_pending_object(&revs, object, oid_to_hex(&object->oid));
898906

899907
for_each_ref(add_pending_uninteresting_ref, &revs);
900-
add_pending_oid(&revs, "HEAD", &new_commit->object.oid, UNINTERESTING);
908+
if (new_commit)
909+
add_pending_oid(&revs, "HEAD",
910+
&new_commit->object.oid,
911+
UNINTERESTING);
901912

902913
if (prepare_revision_walk(&revs))
903914
die(_("internal error in revision walk"));
@@ -932,6 +943,14 @@ static int switch_branches(const struct checkout_opts *opts,
932943
if (old_branch_info.path)
933944
skip_prefix(old_branch_info.path, "refs/heads/", &old_branch_info.name);
934945

946+
if (opts->new_orphan_branch && opts->orphan_from_empty_tree) {
947+
if (new_branch_info->name)
948+
BUG("'switch --orphan' should never accept a commit as starting point");
949+
new_branch_info->commit = NULL;
950+
new_branch_info->name = "(empty)";
951+
do_merge = 1;
952+
}
953+
935954
if (!new_branch_info->name) {
936955
new_branch_info->name = "HEAD";
937956
new_branch_info->commit = old_branch_info.commit;
@@ -1268,6 +1287,8 @@ static int checkout_branch(struct checkout_opts *opts,
12681287
if (opts->new_orphan_branch) {
12691288
if (opts->track != BRANCH_TRACK_UNSPECIFIED)
12701289
die(_("'%s' cannot be used with '%s'"), "--orphan", "-t");
1290+
if (opts->orphan_from_empty_tree && new_branch_info->name)
1291+
die(_("'%s' cannot take <start-point>"), "--orphan");
12711292
} else if (opts->force_detach) {
12721293
if (opts->track != BRANCH_TRACK_UNSPECIFIED)
12731294
die(_("'%s' cannot be used with '%s'"), "--detach", "-t");
@@ -1553,6 +1574,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
15531574
opts.accept_pathspec = 1;
15541575
opts.implicit_detach = 1;
15551576
opts.can_switch_when_in_progress = 1;
1577+
opts.orphan_from_empty_tree = 0;
15561578

15571579
options = parse_options_dup(checkout_options);
15581580
options = add_common_options(&opts, options);
@@ -1589,6 +1611,7 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
15891611
opts.only_merge_on_switching_branches = 1;
15901612
opts.implicit_detach = 0;
15911613
opts.can_switch_when_in_progress = 0;
1614+
opts.orphan_from_empty_tree = 1;
15921615

15931616
options = parse_options_dup(switch_options);
15941617
options = add_common_options(&opts, options);

0 commit comments

Comments
 (0)