make 'got update' bump the base commit ID of unchanged files This change makes it actually possible to get around commit-time out-of-dateness by running 'got update'. The test added with this commit shows that our out-of-dateness check is currently too simplistic; an update is required between any two commit operations! It would be better to allow commits to proceed until a situation arises where file content must be merged.
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
diff --git a/lib/worktree.c b/lib/worktree.c
index 813c260..c0b4a22 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -1447,6 +1447,29 @@ done:
return err;
}
+struct bump_base_commit_id_arg {
+ struct got_object_id *base_commit_id;
+ const char *path;
+ size_t path_len;
+ const char *entry_name;
+};
+
+/* Bump base commit ID of all files within an updated part of the work tree. */
+static const struct got_error *
+bump_base_commit_id(void *arg, struct got_fileindex_entry *ie)
+{
+ struct bump_base_commit_id_arg *a = arg;
+
+ if (a->entry_name) {
+ if (strcmp(ie->path, a->path) != 0)
+ return NULL;
+ } else if (!got_path_is_child(ie->path, a->path, a->path_len))
+ return NULL;
+
+ memcpy(ie->commit_sha1, a->base_commit_id->sha1, SHA1_DIGEST_LENGTH);
+ return NULL;
+}
+
const struct got_error *
got_worktree_checkout_files(struct got_worktree *worktree, const char *path,
struct got_repository *repo, got_worktree_checkout_cb progress_cb,
@@ -1584,6 +1607,18 @@ got_worktree_checkout_files(struct got_worktree *worktree, const char *path,
checkout_err = got_fileindex_diff_tree(fileindex, tree, relpath,
entry_name, repo, &diff_cb, &arg);
+ if (checkout_err == NULL) {
+ struct bump_base_commit_id_arg bbc_arg;
+ bbc_arg.base_commit_id = worktree->base_commit_id;
+ bbc_arg.entry_name = entry_name;
+ bbc_arg.path = path;
+ bbc_arg.path_len = strlen(path);
+ err = got_fileindex_for_each_entry_safe(fileindex,
+ bump_base_commit_id, &bbc_arg);
+ if (err)
+ goto done;
+ }
+
/* Try to sync the fileindex back to disk in any case. */
err = got_fileindex_write(fileindex, new_index);
if (err)
diff --git a/regress/cmdline/update.sh b/regress/cmdline/update.sh
index da70308..13de6cc 100755
--- a/regress/cmdline/update.sh
+++ b/regress/cmdline/update.sh
@@ -1424,6 +1424,72 @@ function test_update_to_commit_on_wrong_branch {
test_done "$testroot" "$ret"
}
+function test_update_bumps_base_commit_id {
+ local testroot=`test_init update_to_commit_on_wrong_branch`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "modified alpha" > $testroot/wt/alpha
+ (cd $testroot/wt && got commit -m "changed alpha" > $testroot/stdout)
+
+ local head_rev=`git_show_head $testroot/repo`
+ echo "M alpha" > $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
+
+ echo "modified beta" > $testroot/wt/beta
+ (cd $testroot/wt && got commit -m "changed beta" > $testroot/stdout \
+ 2> $testroot/stderr)
+
+ echo -n "" > $testroot/stdout.expected
+ echo "got: work tree must be updated before these changes can be committed" > $testroot/stderr.expected
+ cmp -s $testroot/stderr.expected $testroot/stderr
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stderr.expected $testroot/stderr
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # XXX At present, got requires users to run 'update' after 'commit'.
+ (cd $testroot/wt && got update > $testroot/stdout)
+
+ echo "Already up-to-date" > $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
+
+ (cd $testroot/wt && got commit -m "changed beta" > $testroot/stdout)
+
+ local head_rev=`git_show_head $testroot/repo`
+ echo "M beta" > $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
+
+ test_done "$testroot" "$ret"
+}
+
run_test test_update_basic
run_test test_update_adds_file
run_test test_update_deletes_file
@@ -1452,3 +1518,4 @@ run_test test_update_partial_dir
run_test test_update_moved_branch_ref
run_test test_update_to_another_branch
run_test test_update_to_commit_on_wrong_branch
+run_test test_update_bumps_base_commit_id