Commit Diff


commit - a8db5ed88e635d83d1cf9b7e9bbe48eea50c192c
commit + 03415a1a67d78f2decd6e46d82288a224bd4454d
blob - bf12b60a1d19c91b549c6e2ef57d10957d4ca0f6
blob + 19de68852ed6874ce2254f35bf04bb2454d29ae6
--- got/got.c
+++ 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;
 
blob - 0186e720548b6da8fde30b6fd002a9076c3adc16
blob + e19e3956f955247d86d4c8d6910b38709f202a31
--- include/got_error.h
+++ 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 "
blob - 12aa9ccd65fa883e13a40a4a99de19bcb48a12dd
blob + ca87d48087173582492bf1fbb809c2e55b333e27
--- lib/worktree.c
+++ lib/worktree.c
@@ -1881,17 +1881,19 @@ 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;
 
blob - 4aa318fad89c144214430910ededa9950ba25d64
blob + 3562e9126cc0de852853d37ca03d9b6d6ccb92d5
--- regress/cmdline/cherrypick.sh
+++ 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
blob - 61ec8447fb8409a99d4916fd8fd5da60068a7a18
blob + 4135c2b665cb9eaecfe1d9ed4d76cd51551b0d01
--- regress/cmdline/common.sh
+++ 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"