allow 'got cherrypick' with a root commit (adds all files in commit)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
diff --git a/got/got.c b/got/got.c
index bf12b60..19de688 100644
--- a/got/got.c
+++ b/got/got.c
@@ -2699,12 +2699,9 @@ cmd_cherrypick(int argc, char *argv[])
if (error)
goto done;
pid = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit));
- if (pid == NULL) {
- error = got_error(GOT_ERR_ROOT_COMMIT);
- goto done;
- }
- error = got_worktree_merge_files(worktree, pid->id, commit_id,
- repo, update_progress, &did_something, check_cancelled, NULL);
+ error = got_worktree_merge_files(worktree, pid ? pid->id : NULL,
+ commit_id, repo, update_progress, &did_something, check_cancelled,
+ NULL);
if (error != NULL)
goto done;
diff --git a/include/got_error.h b/include/got_error.h
index 0186e72..e19e395 100644
--- a/include/got_error.h
+++ b/include/got_error.h
@@ -93,7 +93,7 @@
#define GOT_ERR_BRANCH_MOVED 77
#define GOT_ERR_OBJ_TOO_LARGE 78
#define GOT_ERR_SAME_BRANCH 79
-#define GOT_ERR_ROOT_COMMIT 80
+/* 80 is currently free for re-use */
#define GOT_ERR_MIXED_COMMITS 81
#define GOT_ERR_CONFLICTS 82
@@ -182,7 +182,7 @@ static const struct got_error {
"different branch; new head reference and/or update -b required" },
{ GOT_ERR_OBJ_TOO_LARGE, "object too large" },
{ GOT_ERR_SAME_BRANCH, "commit is already contained in this branch" },
- { GOT_ERR_ROOT_COMMIT, "specified commit has no parent commit" },
+ { 80, "unused error code" },
{ GOT_ERR_MIXED_COMMITS,"work tree contains files from multiple "
"base commits; the entire work tree must be updated first" },
{ GOT_ERR_CONFLICTS, "work tree contains conflicted files; these "
diff --git a/lib/worktree.c b/lib/worktree.c
index 12aa9cc..ca87d48 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -1881,20 +1881,22 @@ got_worktree_merge_files(struct got_worktree *worktree,
if (err)
goto done;
- err = got_object_id_by_path(&tree_id1, repo, commit_id1,
- worktree->path_prefix);
- if (err)
- goto done;
+ if (commit_id1) {
+ err = got_object_id_by_path(&tree_id1, repo, commit_id1,
+ worktree->path_prefix);
+ if (err)
+ goto done;
+
+ err = got_object_open_as_tree(&tree1, repo, tree_id1);
+ if (err)
+ goto done;
+ }
err = got_object_id_by_path(&tree_id2, repo, commit_id2,
worktree->path_prefix);
if (err)
goto done;
- err = got_object_open_as_tree(&tree1, repo, tree_id1);
- if (err)
- goto done;
-
err = got_object_open_as_tree(&tree2, repo, tree_id2);
if (err)
goto done;
diff --git a/regress/cmdline/cherrypick.sh b/regress/cmdline/cherrypick.sh
index 4aa318f..3562e91 100755
--- a/regress/cmdline/cherrypick.sh
+++ b/regress/cmdline/cherrypick.sh
@@ -93,4 +93,67 @@ function test_cherrypick_basic {
test_done "$testroot" "$ret"
}
+function test_cherrypick_root_commit {
+ local testroot=`test_init cherrypick_root_commit`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/repo && git checkout -q -b newbranch)
+ (cd $testroot/repo && git rm -q alpha)
+ (cd $testroot/repo && git rm -q beta)
+ (cd $testroot/repo && git rm -q epsilon/zeta)
+ (cd $testroot/repo && git rm -q gamma/delta)
+ mkdir -p $testroot/repo/epsilon
+ echo "new file on branch" > $testroot/repo/epsilon/new
+ (cd $testroot/repo && git add epsilon/new)
+ git_commit $testroot/repo -m "committing on newbranch"
+
+ echo "modified new file on branch" >> $testroot/repo/epsilon/new
+ git_commit $testroot/repo -m "committing on newbranch again"
+
+ tree=`git_show_tree $testroot/repo`
+ root_commit=`git_commit_tree $testroot/repo "new root commit" $tree`
+
+ (cd $testroot/wt && got cherrypick $root_commit > $testroot/stdout)
+
+ echo "A epsilon/new" > $testroot/stdout.expected
+ echo "merged commit $root_commit" >> $testroot/stdout.expected
+
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "new file on branch" > $testroot/content.expected
+ echo "modified new file on branch" >> $testroot/content.expected
+ cat $testroot/wt/epsilon/new > $testroot/content
+ cmp -s $testroot/content.expected $testroot/content
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/content.expected $testroot/content
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo 'A epsilon/new' > $testroot/stdout.expected
+
+ (cd $testroot/wt && got status > $testroot/stdout)
+
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
run_test test_cherrypick_basic
+run_test test_cherrypick_root_commit
diff --git a/regress/cmdline/common.sh b/regress/cmdline/common.sh
index 61ec844..4135c2b 100644
--- a/regress/cmdline/common.sh
+++ b/regress/cmdline/common.sh
@@ -44,6 +44,20 @@ function git_show_head
(cd $repo && git show --no-patch --pretty='format:%H')
}
+function git_show_tree
+{
+ local repo="$1"
+ (cd $repo && git show --no-patch --pretty='format:%T')
+}
+
+function git_commit_tree
+{
+ local repo="$1"
+ local msg="$2"
+ local tree="$3"
+ (cd $repo && git commit-tree -m "$msg" "$tree")
+}
+
function make_test_tree
{
repo="$1"