Download raw body.
histedit/rebase vs author/committer times
Stefan Sperling <stsp@stsp.name> wrote: > On Wed, Jul 20, 2022 at 05:44:30PM +0200, Omar Polo wrote: > > regarding the commit author vs committer turns out that we are already > > doing a sensible thing (i.e. keeping the original author when rebasing > > commits.) > > Sorry, I missed this patch and committed some overlapping changes, and > proposed a conflicting diff for histedit/rebase. Let's peel apart which > parts of our changes are not overlapping and continue based on that? sure, i've rebased the diff and tweaked the tests to only look for the times > > So, diff below just fixes the time accounting; the idea is: > > > > - use the current time when creating a new commit > > - don't call time(NULL) twice > > - when rebasing a commit use the old author_time and a new committer time > > > > from some tests this seems to put us in par with git, and I think that > > it's a sensible behaviour. > > My changes cover don't add preservation of the 'author' timestamp, > but cover the two other points you are addressing in pretty much > the same way. > > I suspect what most people looking at timestamps will want to know is > when a change arrived in the repository they are looking at. The author > timestamp may well be entirely meaningless in that case. > Since we always store the commit timestamp in the committer field, I > suppose preserving the author's timestamp will not hurt. Yep, that's my reasoning too. my initial goal actually your latest diff, i only failed to realize that we needed to reset the committer and not use the old committer, so i've just tweaked the time accounting. fwiw `git log' seems to show only the author time by default, which imho is confusing. > If we do this, we need to make sure that only the committer timestamp is > used for comparison purposes, such as when sorting commits on parallel > branches for linear display. i haven't thought about this issue and diff below doesn't address it. i'll see if this breaks things sometime soon. > And 'got log' and 'tog diff' only display one timestamp. This should be > the committer timestamp in all cases. Or do you see a reason to display > an author timestamp in any commands other than 'got cat'? i agree on showing the committer timestamp in all cases. there is an argument that can be made to show it in tog when switching the view from committer / author with '@' but i'm not pushing for it. have to admit that the more i look at this the more i'm realizing i'm doing this change only because that field exists, not for a real reason. so, i'd also be fine with dropping the patch > > git (somehow) keeps the authorship also when "squashing" commits. (i.e. > > you fold a commit from Alice with one did by you using 'git rebase -i' > > and the resulting commit will still be from alice.) not sure if this is > > my lazyness speaking, but i don't think `got histedit should follow the > > same behaviour in this case. > > What likely happens here is that author field of the last commit > in the folded series will be used? This is what would happen with > my proposed rebase/histedit patch. > > > (going out of topic) it would be nice to have a mean to change the > > commit metadata (author and committer) during histedit however. i was > > thinking of adding `author' and `committer' that, like `mesg', would > > allow to change those info in-line; i.e.: > > Yes, this could be useful in cases where the committer has made minor > edits mixed into a patch submitted by someone else. It is best practice > to commit a submitted patch as-is if possible, and then commit our own > follow-up tweaks on top. But there could be cases where committing > such a patch as-is could break things (e.g. break the build and thus > make future bisecting harder), so this feature would indeed be useful. > > > pick abcdefg commit 1 > > author Flan Hacker <flan@openbsd.org> > > committer Omar Polo <op@omarpolo.com> > > Overriding the committer is redundant. We already set committer info based > on values found in our run-time configuration. So I don't see how making it > possible to override the committer field would be useful. i thought of it as a mean to override the committer in case one has a wrong $GOT_AUTHOR set. akin to git commit --amend --reset-author if you want. but thinking more about it, we can get away without such feature: it's not a common error and it's still easy to work around it (save the commit id, histedit to drop it, `got cy $commit_id && got ci' or some equivalent incantation) > Forcing people to re-type the entire author name and email is a bit heavy. > I would only want to type it again if existing author info is incorrect or > invalid (e.g. would fail the email address check, if such a commit was > created somehow by some tool other than Got or Git). > > Should we also offer an alternative syntax which picks the author from a > given (possibly abbreviated) commit ID, e.g. like this? > > fold abcdefg commit 1 > fold 12345ae commit 2 > pick 890abcd commit 3 > author abcdefg i like it :) will think a bit about it here's the updated diff, but at this point i'm even fine with dropping it. diff /home/op/w/got commit - d3c1b7b8a777dac7004a87b1bcc27ed4b0562f26 path + /home/op/w/got blob - af59edb11f59ce50cc07c7c94d5fb05a9acc0f54 file + got/got.c --- got/got.c +++ got/got.c @@ -8484,9 +8484,11 @@ cmd_commit(int argc, char *argv[]) int allow_bad_symlinks = 0, non_interactive = 0, merge_in_progress = 0; struct got_pathlist_head paths; int *pack_fds = NULL; + time_t timestamp; TAILQ_INIT(&paths); cl_arg.logmsg_path = NULL; + timestamp = time(NULL); while ((ch = getopt(argc, argv, "A:F:m:NS")) != -1) { switch (ch) { @@ -8617,9 +8619,9 @@ cmd_commit(int argc, char *argv[]) cl_arg.branch_name += 11; } cl_arg.repo_path = got_repo_get_path(repo); - error = got_worktree_commit(&id, worktree, &paths, author, committer, - allow_bad_symlinks, collect_commit_logmsg, &cl_arg, - print_status, NULL, repo); + error = got_worktree_commit(&id, worktree, &paths, author, timestamp, + committer, timestamp, allow_bad_symlinks, + collect_commit_logmsg, &cl_arg, print_status, NULL, repo); if (error) { if (error->code != GOT_ERR_COMMIT_MSG_EMPTY && cl_arg.logmsg_path != NULL) blob - b2b02753e786580598a72d4ccfa4aeb006309afe file + include/got_worktree.h --- include/got_worktree.h +++ include/got_worktree.h @@ -241,7 +241,7 @@ typedef const struct got_error *(*got_worktree_commit_ */ const struct got_error *got_worktree_commit(struct got_object_id **, struct got_worktree *, struct got_pathlist_head *, const char *, - const char *, int, got_worktree_commit_msg_cb, void *, + time_t, const char *, time_t, int, got_worktree_commit_msg_cb, void *, got_worktree_status_cb, void *, struct got_repository *); /* Get the path of a commitable worktree item. */ blob - 718cf72db051a1e897c1d70657ac5f12fa7b1043 file + lib/worktree.c --- lib/worktree.c +++ lib/worktree.c @@ -5664,7 +5664,8 @@ commit_worktree(struct got_object_id **new_commit_id, struct got_object_id *head_commit_id, struct got_object_id *parent_id2, struct got_worktree *worktree, - const char *author, const char *committer, + const char *author, time_t author_time, + const char *committer, time_t committer_time, got_worktree_commit_msg_cb commit_msg_cb, void *commit_arg, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *repo) @@ -5681,7 +5682,6 @@ commit_worktree(struct got_object_id **new_commit_id, struct got_object_id_queue parent_ids; struct got_object_qid *pid = NULL; char *logmsg = NULL; - time_t timestamp; *new_commit_id = NULL; @@ -5750,9 +5750,9 @@ commit_worktree(struct got_object_id **new_commit_id, STAILQ_INSERT_TAIL(&parent_ids, pid, entry); nparents++; } - timestamp = time(NULL); err = got_object_commit_create(new_commit_id, new_tree_id, &parent_ids, - nparents, author, timestamp, committer, timestamp, logmsg, repo); + nparents, author, author_time, committer, committer_time, logmsg, + repo); if (logmsg != NULL) free(logmsg); if (err) @@ -5868,7 +5868,8 @@ check_non_staged_files(struct got_fileindex *fileindex const struct got_error * got_worktree_commit(struct got_object_id **new_commit_id, struct got_worktree *worktree, struct got_pathlist_head *paths, - const char *author, const char *committer, int allow_bad_symlinks, + const char *author, time_t author_time, const char *committer, + time_t committer_time, int allow_bad_symlinks, got_worktree_commit_msg_cb commit_msg_cb, void *commit_arg, got_worktree_status_cb status_cb, void *status_arg, struct got_repository *repo) @@ -5952,8 +5953,9 @@ got_worktree_commit(struct got_object_id **new_commit_ } err = commit_worktree(new_commit_id, &commitable_paths, - head_commit_id, NULL, worktree, author, committer, - commit_msg_cb, commit_arg, status_cb, status_arg, repo); + head_commit_id, NULL, worktree, author, author_time, committer, + committer_time, commit_msg_cb, commit_arg, status_cb, status_arg, + repo); if (err) goto done; @@ -6536,8 +6538,9 @@ rebase_commit(struct got_object_id **new_commit_id, /* NB: commit_worktree will call free(logmsg) */ err = commit_worktree(new_commit_id, &commitable_paths, head_commit_id, NULL, worktree, got_object_commit_get_author(orig_commit), - committer, collect_rebase_commit_msg, logmsg, rebase_status, NULL, - repo); + got_object_commit_get_author_time(orig_commit), + committer, time(NULL), collect_rebase_commit_msg, logmsg, + rebase_status, NULL, repo); if (err) goto done; @@ -7604,10 +7607,12 @@ got_worktree_merge_commit(struct got_object_id **new_c int have_staged_files = 0; struct merge_commit_msg_arg mcm_arg; char *fileindex_path = NULL; + time_t timestamp; *new_commit_id = NULL; TAILQ_INIT(&commitable_paths); + timestamp = time(NULL); err = get_fileindex_path(&fileindex_path, worktree); if (err) @@ -7664,8 +7669,9 @@ got_worktree_merge_commit(struct got_object_id **new_c mcm_arg.worktree = worktree; mcm_arg.branch_name = branch_name; err = commit_worktree(new_commit_id, &commitable_paths, - head_commit_id, branch_tip, worktree, author, committer, - merge_commit_msg_cb, &mcm_arg, status_cb, status_arg, repo); + head_commit_id, branch_tip, worktree, author, timestamp, + committer, timestamp, merge_commit_msg_cb, &mcm_arg, + status_cb, status_arg, repo); if (err) goto done; blob - 1264347441d2f3f6859d520ab1230f6161a9d666 file + regress/cmdline/histedit.sh --- regress/cmdline/histedit.sh +++ regress/cmdline/histedit.sh @@ -2157,6 +2157,58 @@ test_histedit_resets_committer() { test_done "$testroot" "$ret" } +test_histedit_keep_author_time() { + local testroot=`test_init keep_author_time` + local orig_commit=`git_show_head $testroot/repo` + local author='Flan Luck <flan_luck@openbsd.org>' + + got checkout $testroot/repo $testroot/wt >/dev/null + ret=$? + if [ $ret -ne 0 ]; then + test_done "$testroot" $ret + return 1 + fi + + echo "modified alpha on master" > $testroot/wt/alpha + (cd $testroot/wt && got commit -A "$author" -m 'edit alpha') >/dev/null + ret=$? + if [ $ret -ne 0 ]; then + test_done "$testroot" $ret + return 1 + fi + + (cd $testroot/wt && got cat master | grep ^author) \ + > $testroot/author.expected + + local new_commit=`git_show_head $testroot/repo` + + (cd $testroot/wt && got update -c $orig_commit) >/dev/null + ret=$? + if [ $ret -ne 0 ]; then + test_done "$testroot" $ret + return 1 + fi + + echo "pick $new_commit" > $testroot/histedit-script + echo "mesg edited alpha" >> $testroot/histedit-script + (cd $testroot/wt && got histedit -F $testroot/histedit-script) \ + >/dev/null + ret=$? + if [ $ret -ne 0 ]; then + test_done "$testroot" $ret + return 1 + fi + + (cd $testroot/wt && got cat master | grep ^author) \ + > $testroot/author + cmp -s $testroot/author $testroot/author.expected + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/author $testroot/author.expected + fi + test_done "$testroot" $ret +} + test_parseargs "$@" run_test test_histedit_no_op run_test test_histedit_swap @@ -2179,3 +2231,4 @@ run_test test_histedit_edit_only run_test test_histedit_prepend_line run_test test_histedit_mesg_invalid run_test test_histedit_resets_committer +run_test test_histedit_keep_author_time blob - 2bdfc42c631a9bad8763528b9082b0deacbed9d9 file + regress/cmdline/rebase.sh --- regress/cmdline/rebase.sh +++ regress/cmdline/rebase.sh @@ -1568,6 +1568,76 @@ test_rebase_resets_committer() { test_done "$testroot" "$ret" } +test_rebase_keep_author_time() { + local testroot=`test_init rebase_keep_author` + local commit0=`git_show_head $testroot/repo` + local author='Flan Luck <flan_luck@openbsd.org>' + + got checkout $testroot/repo $testroot/wt >/dev/null + ret=$? + if [ $ret -ne 0 ]; then + test_done "$testroot" $ret + return $ret + fi + + (cd $testroot/wt && got branch newbranch) >/dev/null + ret=$? + if [ $ret -ne 0 ]; then + test_done "$testroot" $ret + return $ret + fi + + echo 'modified alpha on branch' > $testroot/wt/alpha + (cd $testroot/wt && got commit -A "$author" -m 'edit alpha') >/dev/null + ret=$? + if [ $ret -ne 0 ]; then + test_done "$testroot" $ret + return $ret + fi + + (cd $testroot/wt && got cat newbranch | grep ^author) \ + > $testroot/author.expected + + (cd $testroot/wt && got update -b master) >/dev/null + ret=$? + if [ $ret -ne 0 ]; then + test_done "$testroot" $ret + return $ret + fi + + echo "modified zeta on master" > $testroot/wt/epsilon/zeta + (cd $testroot/wt && got commit -m 'edit zeta') >/dev/null + ret=$? + if [ $ret -ne 0 ]; then + test_done "$testroot" $ret + return $ret + fi + + (cd $testroot/wt && got update) >/dev/null + ret=$? + if [ $ret -ne 0 ]; then + test_done "$testroot" $ret + return $ret + fi + + (cd $testroot/wt && got rebase newbranch) >/dev/null + ret=$? + if [ $ret -ne 0 ]; then + test_done "$testroot" $ret + return $ret + fi + + (cd $testroot/wt && got cat newbranch | grep ^author) \ + > $testroot/author + + cmp -s $testroot/author $testroot/author.expected + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/author $testroot/author.expected + fi + test_done "$testroot" $ret +} + test_parseargs "$@" run_test test_rebase_basic run_test test_rebase_ancestry_check @@ -1584,3 +1654,4 @@ run_test test_rebase_trims_empty_dir run_test test_rebase_delete_missing_file run_test test_rebase_rm_add_rm_file run_test test_rebase_resets_committer +run_test test_rebase_keep_author_time
histedit/rebase vs author/committer times