Commit Diff


commit - 986288a659290f72e774dcf0cb43ba76b2c23c72
commit + 899fcfdf4534887848844329dae7327bd810a432
blob - 6ecd586ce8e361dfca580081aea01c71ea59b531
blob + 1109e3c97f334540e101df641fdfc3423cedb552
--- got/got.1
+++ got/got.1
@@ -1285,7 +1285,7 @@ option)
 .El
 .El
 .Tg pa
-.It Cm patch Op Ar patchfile
+.It Cm patch Oo Fl n Oc Op Ar patchfile
 .Dl Pq alias: Cm pa
 Apply changes from
 .Ar patchfile
@@ -1338,6 +1338,19 @@ Such changes can be viewed with
 and can be reverted with
 .Cm got revert
 if needed.
+.Pp
+The options for
+.Cm got patch
+are as follows:
+.Bl -tag -width Ds
+.It Fl n
+Do not make any modifications to the work tree.
+This can be used to check whether a patch would apply without issues.
+If the
+.Ar patchfile
+contains diffs that affect the same file multiple times the results
+displayed may be incorrect.
+.El
 .Tg rv
 .It Cm revert Oo Fl p Oc Oo Fl F Ar response-script Oc Oo Fl R Oc Ar path ...
 .Dl Pq alias: Cm rv
blob - 4bcea52af617043cda2fa50d87f21effce198199
blob + d595de198f4880c3458bb395b994e889acf68df3
--- got/got.c
+++ got/got.c
@@ -7132,7 +7132,7 @@ done:
 __dead static void
 usage_patch(void)
 {
-	fprintf(stderr, "usage: %s patch [patchfile]\n",
+	fprintf(stderr, "usage: %s patch [-n] [patchfile]\n",
 	    getprogname());
 	exit(1);
 }
@@ -7192,11 +7192,14 @@ cmd_patch(int argc, char *argv[])
 	struct got_worktree *worktree = NULL;
 	struct got_repository *repo = NULL;
 	char *cwd = NULL;
-	int ch;
+	int ch, nop = 0;
 	int patchfd;
 
-	while ((ch = getopt(argc, argv, "")) != -1) {
+	while ((ch = getopt(argc, argv, "n")) != -1) {
 		switch (ch) {
+		case 'n':
+			nop = 1;
+			break;
 		default:
 			usage_patch();
 			/* NOTREACHED */
@@ -7244,7 +7247,7 @@ cmd_patch(int argc, char *argv[])
 		err(1, "pledge");
 #endif
 
-	error = got_patch(patchfd, worktree, repo, &print_remove_status,
+	error = got_patch(patchfd, worktree, repo, nop, &print_remove_status,
 	    NULL, &add_progress, NULL, check_cancelled, NULL);
 
 done:
blob - 448bb17e65d75d8d5ba94bd577f5cde4fef566bf
blob + 5f28ffc619f1b4e32ba37ff8e5361c636009ba74
--- include/got_patch.h
+++ include/got_patch.h
@@ -21,6 +21,6 @@
  * The patch file descriptor *must* be seekable.
  */
 const struct got_error *
-got_patch(int, struct got_worktree *, struct got_repository *,
+got_patch(int, struct got_worktree *, struct got_repository *, int,
     got_worktree_delete_cb, void *, got_worktree_checkout_cb, void *,
     got_cancel_cb, void *);
blob - 71695e64b89d1a1b07daab61fb55d3c1883760ec
blob + 6e5ec0f2143d39ff9eeca89060522c5155706a77
--- lib/patch.c
+++ lib/patch.c
@@ -66,6 +66,7 @@ struct got_patch_hunk {
 };
 
 struct got_patch {
+	int	 nop;
 	char	*old;
 	char	*new;
 	STAILQ_HEAD(, got_patch_hunk) head;
@@ -399,6 +400,8 @@ patch_file(struct got_patch *p, const char *path, FILE
 		h = STAILQ_FIRST(&p->head);
 		if (h == NULL || STAILQ_NEXT(h, entries) != NULL)
 			return got_error(GOT_ERR_PATCH_MALFORMED);
+		if (p->nop)
+			return NULL;
 		for (i = 0; i < h->len; ++i) {
 			if (fprintf(tmp, "%s", h->lines[i]+1) < 0)
 				return got_error_from_errno("fprintf");
@@ -420,7 +423,8 @@ patch_file(struct got_patch *p, const char *path, FILE
 		err = locate_hunk(orig, h, &pos, &lineno);
 		if (err != NULL)
 			goto done;
-		err = copy(tmp, orig, copypos, pos);
+		if (!p->nop)
+			err = copy(tmp, orig, copypos, pos);
 		if (err != NULL)
 			goto done;
 		copypos = pos;
@@ -446,7 +450,8 @@ patch_file(struct got_patch *p, const char *path, FILE
 		if (err != NULL)
 			goto done;
 
-		err = apply_hunk(tmp, h, &lineno);
+		if (!p->nop)
+			err = apply_hunk(tmp, h, &lineno);
 		if (err != NULL)
 			goto done;
 		
@@ -465,7 +470,7 @@ patch_file(struct got_patch *p, const char *path, FILE
 			err = got_error_from_errno("fstat");
 		else if (sb.st_size != copypos)
 			err = got_error(GOT_ERR_PATCH_DONT_APPLY);
-	} else if (!feof(orig))
+	} else if (!p->nop && !feof(orig))
 		err = copy(tmp, orig, copypos, -1);
 
 done:
@@ -599,13 +604,17 @@ apply_patch(struct got_worktree *worktree, struct got_
 		goto done;
 	}
 
-	err = got_opentemp_named(&tmppath, &tmp, template);
+	if (!p->nop)
+		err = got_opentemp_named(&tmppath, &tmp, template);
 	if (err)
 		goto done;
 	err = patch_file(p, oldpath, tmp);
 	if (err)
 		goto done;
 
+	if (p->nop)
+		goto done;
+
 	if (p->old != NULL && p->new == NULL) {
 		err = got_worktree_schedule_delete(worktree, &oldpaths,
 		    0, NULL, delete_cb, delete_arg, repo, 0, 0);
@@ -645,7 +654,7 @@ done:
 
 const struct got_error *
 got_patch(int fd, struct got_worktree *worktree, struct got_repository *repo,
-    got_worktree_delete_cb delete_cb, void *delete_arg,
+    int nop, got_worktree_delete_cb delete_cb, void *delete_arg,
     got_worktree_checkout_cb add_cb, void *add_arg, got_cancel_cb cancel_cb,
     void *cancel_arg)
 {
@@ -695,6 +704,7 @@ got_patch(int fd, struct got_worktree *worktree, struc
 		if (err || done)
 			break;
 
+		p.nop = nop;
 		err = apply_patch(worktree, repo, &p, delete_cb, delete_arg,
 		    add_cb, add_arg, cancel_cb, cancel_arg);
 		patch_free(&p);
blob - 9a300a816a79b7eacef07263e7bd7cbce706ae25
blob + 41f290c529e09c20b73b0a6752c3351664a9559d
--- regress/cmdline/patch.sh
+++ regress/cmdline/patch.sh
@@ -910,7 +910,60 @@ EOF
 	ret=$?
 	if [ $ret -eq 0 ]; then
 		diff -u $testroot/stderr.expected $testroot/stderr
+	fi
+	test_done $testroot $ret
+}
+
+test_patch_nop() {
+	local testroot=`test_init patch_nop`
+
+	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
++cafe alpha
+--- beta
++++ /dev/null
+@@ -1 +0,0 @@
+-beta
+--- gamma/delta
++++ gamma/delta.new
+@@ -1 +1 @@
+-delta
++delta updated and renamed!
+EOF
+
+	(cd $testroot/wt && got patch -n patch)
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		test_done $testroot $ret
+		return 1
 	fi
+
+	# remove the patch to avoid the ? entry
+	rm $testroot/wt/patch
+
+	(cd $testroot/wt && got status) > $testroot/stdout
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		test_done $testroot $ret
+		return 1
+	fi
+
+	echo -n > $testroot/stdout.expected
+	cmp -s $testroot/stdout.expected $testroot/stdout
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+	fi
 	test_done $testroot $ret
 }
 
@@ -928,3 +981,4 @@ run_test test_patch_no_patch
 run_test test_patch_equals_for_context
 run_test test_patch_rename
 run_test test_patch_illegal_status
+run_test test_patch_nop