Download raw body.
got patch: allow to reverse patches
(this needs the small refactoring i just sent too) as per title, add a flag to `got patch' to reverse a patch before applying it. I went with -R for consistency with patch(1). With the fixed got-read-patch, reverting a diff is dead easy: just swap the (from, lines) counters and swap every + with - before applying it. There's a small overlap in functionalities between `got revert' and `got patch -R' but I think it's useful to keep it. ok? ----------------------------------------------- commit 86e1ad73c6d5632b4f705a0ffc798e19d986795b (main) from: Omar Polo <op@omarpolo.com> date: Tue Apr 12 10:38:42 2022 UTC got_patch: allow to reverse a patch Allow to reverse a patch before applying it, and add the -R flag to `got patch'. While here, add the forgotten `-p strip-count' to usage_patch too. diff 0e6f5b49e77b526f4d1cfcada5b3e4a728dbe44f ba7d371282376d7ef7932c7ff6aeea2a74fcc671 blob - bd6e06c564ce9499b313b1d667097c58c2d16873 blob + b91cfb2cb4963721a9a86be9c2cdb397bc1a9278 --- got/got.1 +++ got/got.1 @@ -1285,7 +1285,7 @@ option) .El .El .Tg pa -.It Cm patch Oo Fl n Oc Oo Fl p Ar strip-count Oc Op Ar patchfile +.It Cm patch Oo Fl n Oc Oo Fl p Ar strip-count Oc Oo Fl R Oc Op Ar patchfile .Dl Pq alias: Cm pa Apply changes from .Ar patchfile @@ -1367,6 +1367,8 @@ and path prefixes generated by .Xr git-diff 1 will be recognized and stripped automatically. +.It Fl R +Reverse the patch before applying it. .El .Tg rv .It Cm revert Oo Fl p Oc Oo Fl F Ar response-script Oc Oo Fl R Oc Ar path ... blob - 634d14fbd0d903b762d975a43ede19d0b14de466 blob + 5eac6b2ce376db8d223ef8a91c9104c7a02725d0 --- got/got.c +++ got/got.c @@ -7152,8 +7152,8 @@ done: __dead static void usage_patch(void) { - fprintf(stderr, "usage: %s patch [-n] [patchfile]\n", - getprogname()); + fprintf(stderr, "usage: %s patch [-n] [-p strip-count] " + "[-R] [patchfile]\n", getprogname()); exit(1); } @@ -7242,10 +7242,10 @@ cmd_patch(int argc, char *argv[]) struct got_repository *repo = NULL; const char *errstr; char *cwd = NULL; - int ch, nop = 0, strip = -1; + int ch, nop = 0, strip = -1, reverse = 0; int patchfd; - while ((ch = getopt(argc, argv, "np:")) != -1) { + while ((ch = getopt(argc, argv, "np:R")) != -1) { switch (ch) { case 'n': nop = 1; @@ -7256,6 +7256,9 @@ cmd_patch(int argc, char *argv[]) errx(1, "pathname strip count is %s: %s", errstr, optarg); break; + case 'R': + reverse = 1; + break; default: usage_patch(); /* NOTREACHED */ @@ -7303,7 +7306,7 @@ cmd_patch(int argc, char *argv[]) err(1, "pledge"); #endif - error = got_patch(patchfd, worktree, repo, nop, strip, + error = got_patch(patchfd, worktree, repo, nop, strip, reverse, &patch_progress, NULL, check_cancelled, NULL); done: blob - 62c76b0eb2926a03364ef10e416183cdfa18f398 blob + bc2e95bb4fa535617bc28f76935a78e36dea8a3e --- include/got_patch.h +++ include/got_patch.h @@ -32,4 +32,4 @@ typedef const struct got_error *(*got_patch_progress_c */ const struct got_error * got_patch(int, struct got_worktree *, struct got_repository *, int, int, - got_patch_progress_cb, void *, got_cancel_cb, void *); + int, got_patch_progress_cb, void *, got_cancel_cb, void *); blob - fd8a331bcf22f2eae5872f93fe383f4de9dd7af6 blob + 556b5fc43838fc9d635d2795c68d11b20d0391ef --- lib/patch.c +++ lib/patch.c @@ -674,10 +674,39 @@ done: return err; } +static void +reverse_patch(struct got_patch *p) +{ + struct got_patch_hunk *h; + size_t i; + long tmp; + + STAILQ_FOREACH(h, &p->head, entries) { + tmp = h->old_from; + h->old_from = h->new_from; + h->new_from = tmp; + + tmp = h->old_lines; + h->old_lines = h->new_lines; + h->new_lines = tmp; + + tmp = h->old_nonl; + h->old_nonl = h->new_nonl; + h->new_nonl = tmp; + + for (i = 0; i < h->len; ++i) { + if (*h->lines[i] == '+') + *h->lines[i] = '-'; + else if (*h->lines[i] == '-') + *h->lines[i] = '+'; + } + } +} + const struct got_error * got_patch(int fd, struct got_worktree *worktree, struct got_repository *repo, - int nop, int strip, got_patch_progress_cb progress_cb, void *progress_arg, - got_cancel_cb cancel_cb, void *cancel_arg) + int nop, int strip, int reverse, got_patch_progress_cb progress_cb, + void *progress_arg, got_cancel_cb cancel_cb, void *cancel_arg) { const struct got_error *err = NULL; struct got_fileindex *fileindex = NULL; @@ -736,6 +765,9 @@ got_patch(int fd, struct got_worktree *worktree, struc if (err || done) break; + if (reverse) + reverse_patch(&p); + err = got_worktree_patch_check_path(p.old, p.new, &oldpath, &newpath, worktree, repo, fileindex); if (err == NULL) blob - 24c65df8f37d93d010464929c0370750824f4534 blob + f8a053a6f93237b3aa62a9f0e0f3df06d4922010 --- regress/cmdline/patch.sh +++ regress/cmdline/patch.sh @@ -1273,6 +1273,50 @@ EOF test_done $testroot 0 } +test_patch_reverse() { + local testroot=`test_init patch_reverse` + + got checkout $testroot/repo $testroot/wt > /dev/null + ret=$? + if [ $ret -ne 0 ]; then + test_done $testroot $ret + return 1 + fi + + cat <<EOF > $testroot/wt/patch +--- alpha ++++ alpha +@@ -1 +1 @@ +-ALPHA +\ No newline at end of file ++alpha +EOF + + (cd $testroot/wt && got patch -R patch) > $testroot/stdout + ret=$? + if [ $ret -ne 0 ]; then + test_done $testroot $ret + return 1 + fi + + echo "M alpha" > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done $testroot $ret + return 1 + fi + + echo -n ALPHA > $testroot/wt/alpha.expected + cmp -s $testroot/wt/alpha.expected $testroot/wt/alpha + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/wt/alpha.expected $testroot/wt/alpha + fi + test_done $testroot $ret +} + test_parseargs "$@" run_test test_patch_simple_add_file run_test test_patch_simple_rm_file @@ -1294,3 +1338,4 @@ run_test test_patch_with_offset run_test test_patch_prefer_new_path run_test test_patch_no_newline run_test test_patch_strip +run_test test_patch_reverse
got patch: allow to reverse patches