commit ba580f687cd7280a6d7bffb1693077693c486056 from: Stefan Sperling date: Sun Mar 22 15:08:33 2020 UTC prevent 'got commit' from comitting empty sub-directories; found by tracey commit - 9c2e8939ca5f2599eac9d215a6e7747b3dbfe482 commit + ba580f687cd7280a6d7bffb1693077693c486056 blob - 34717c9e490a24f071ea53b060842a699b03a543 blob + f43056690320ca4d0531a3f1ae2b4550a70b31db --- lib/worktree.c +++ lib/worktree.c @@ -3843,13 +3843,13 @@ done: return err; } -static const struct got_error *write_tree(struct got_object_id **, +static const struct got_error *write_tree(struct got_object_id **, int *, struct got_tree_object *, const char *, struct got_pathlist_head *, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *); static const struct got_error * -write_subtree(struct got_object_id **new_subtree_id, +write_subtree(struct got_object_id **new_subtree_id, int *nentries, struct got_tree_entry *te, const char *parent_path, struct got_pathlist_head *commitable_paths, got_worktree_status_cb status_cb, void *status_arg, @@ -3867,8 +3867,8 @@ write_subtree(struct got_object_id **new_subtree_id, if (err) return err; - err = write_tree(new_subtree_id, subtree, subpath, commitable_paths, - status_cb, status_arg, repo); + err = write_tree(new_subtree_id, nentries, subtree, subpath, + commitable_paths, status_cb, status_arg, repo); got_object_tree_close(subtree); free(subpath); return err; @@ -4088,6 +4088,7 @@ make_subtree_for_added_blob(struct got_tree_entry **ne struct got_tree_entry *new_te; char *subtree_path; struct got_object_id *id = NULL; + int nentries; *new_tep = NULL; @@ -4106,7 +4107,7 @@ make_subtree_for_added_blob(struct got_tree_entry **ne err = got_error(GOT_ERR_NO_SPACE); goto done; } - err = write_tree(&id, NULL, subtree_path, + err = write_tree(&id, &nentries, NULL, subtree_path, commitable_paths, status_cb, status_arg, repo); if (err) { free(new_te); @@ -4122,7 +4123,7 @@ done: } static const struct got_error * -write_tree(struct got_object_id **new_tree_id, +write_tree(struct got_object_id **new_tree_id, int *nentries, struct got_tree_object *base_tree, const char *path_base_tree, struct got_pathlist_head *commitable_paths, got_worktree_status_cb status_cb, void *status_arg, @@ -4132,9 +4133,9 @@ write_tree(struct got_object_id **new_tree_id, struct got_pathlist_head paths; struct got_tree_entry *te, *new_te = NULL; struct got_pathlist_entry *pe; - int nentries = 0; TAILQ_INIT(&paths); + *nentries = 0; /* Insert, and recurse into, newly added entries first. */ TAILQ_FOREACH(pe, commitable_paths, entry) { @@ -4167,7 +4168,7 @@ write_tree(struct got_object_id **new_tree_id, err = insert_tree_entry(new_te, &paths); if (err) goto done; - nentries++; + (*nentries)++; } else { *slash = '\0'; /* trim trailing path components */ if (base_tree == NULL || @@ -4182,7 +4183,7 @@ write_tree(struct got_object_id **new_tree_id, err = insert_tree_entry(new_te, &paths); if (err) goto done; - nentries++; + (*nentries)++; } } } @@ -4203,7 +4204,7 @@ write_tree(struct got_object_id **new_tree_id, err = insert_tree_entry(new_te, &paths); if (err) goto done; - nentries++; + (*nentries)++; continue; } @@ -4219,11 +4220,18 @@ write_tree(struct got_object_id **new_tree_id, /* Avoid recursion into unmodified subtrees. */ if (modified) { struct got_object_id *new_id; - err = write_subtree(&new_id, te, + int nsubentries; + err = write_subtree(&new_id, + &nsubentries, te, path_base_tree, commitable_paths, status_cb, status_arg, repo); if (err) goto done; + if (nsubentries == 0) { + /* All entries were deleted. */ + free(new_id); + continue; + } memcpy(&new_te->id, new_id, sizeof(new_te->id)); free(new_id); @@ -4231,7 +4239,7 @@ write_tree(struct got_object_id **new_tree_id, err = insert_tree_entry(new_te, &paths); if (err) goto done; - nentries++; + (*nentries)++; continue; } @@ -4251,7 +4259,7 @@ write_tree(struct got_object_id **new_tree_id, err = insert_tree_entry(new_te, &paths); if (err) goto done; - nentries++; + (*nentries)++; } err = report_ct_status(ct, status_cb, status_arg); @@ -4265,13 +4273,13 @@ write_tree(struct got_object_id **new_tree_id, err = insert_tree_entry(new_te, &paths); if (err) goto done; - nentries++; + (*nentries)++; } } } /* Write new list of entries; deleted entries have been dropped. */ - err = got_object_tree_create(new_tree_id, &paths, nentries, repo); + err = got_object_tree_create(new_tree_id, &paths, *nentries, repo); done: got_pathlist_free(&paths); return err; @@ -4384,6 +4392,7 @@ commit_worktree(struct got_object_id **new_commit_id, struct got_object_id *head_commit_id2 = NULL; struct got_tree_object *head_tree = NULL; struct got_object_id *new_tree_id = NULL; + int nentries; struct got_object_id_queue parent_ids; struct got_object_qid *pid = NULL; char *logmsg = NULL; @@ -4438,8 +4447,8 @@ commit_worktree(struct got_object_id **new_commit_id, } /* Recursively write new tree objects. */ - err = write_tree(&new_tree_id, head_tree, "/", commitable_paths, - status_cb, status_arg, repo); + err = write_tree(&new_tree_id, &nentries, head_tree, "/", + commitable_paths, status_cb, status_arg, repo); if (err) goto done; blob - a131681c03b7c5c023fa5603baf9b704a0bc4779 blob + 270ee1fe177e6657aa51f55d0f13dae24a800402 --- regress/cmdline/commit.sh +++ regress/cmdline/commit.sh @@ -228,8 +228,49 @@ function test_commit_added_subdirs { echo "A d/f/new3" >> $testroot/stdout.expected echo "A d/new" >> $testroot/stdout.expected echo "A d/new2" >> $testroot/stdout.expected + echo "Created commit $head_rev" >> $testroot/stdout.expected + + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi + test_done "$testroot" "$ret" +} + +function test_commit_deleted_subdirs { + local testroot=`test_init commit_deleted_subdirs` + + got checkout $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + (cd $testroot/wt && got rm -R $testroot/wt/{epsilon,gamma} >/dev/null) + + (cd $testroot/wt && got commit -m 'test commit_deleted_subdirs' \ + > $testroot/stdout 2> $testroot/stderr) + + local head_rev=`git_show_head $testroot/repo` + echo "D epsilon/zeta" > $testroot/stdout.expected + echo "D gamma/delta" >> $testroot/stdout.expected echo "Created commit $head_rev" >> $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 + got tree -r $testroot/repo > $testroot/stdout + + echo "alpha" > $testroot/stdout.expected + echo "beta" >> $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout ret="$?" if [ "$ret" != "0" ]; then @@ -749,6 +790,7 @@ run_test test_commit_subdir run_test test_commit_single_file run_test test_commit_out_of_date run_test test_commit_added_subdirs +run_test test_commit_deleted_subdirs run_test test_commit_rejects_conflicted_file run_test test_commit_single_file_multiple run_test test_commit_added_and_modified_in_same_dir