"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Johannes Thyssen Tishman <johannes@thyssentishman.com>
Subject:
standardize exit status across all usage functions
To:
gameoftrees@openbsd.org
Date:
Wed, 19 Nov 2025 10:10:50 +0000

Download raw body.

Thread
As discussed on IRC, I noticed that most GoT command-line tools exit
with status 1 and print to stderr when using the '-h' flag to print the
usage string of a command, e.g., got -h log. This is not consistent with
the behavior of using the '-h' flag without a command, e.g., got -h,
which exits with status 0 and prints to stdout. To me the latter is the
correct behavior, as it follows the user request and therefore should
exit with "success". This commit standardizes this behavior across
all[1] usage functions. The following exemplifies this change:

Without this commit:

command             prints to  exit status
------------------------------------------
got -h              stdout               0
got -h valid-cmd    stderr               1
got -h invalid-cmd  stderr               1

With this commit:

command             prints to  exit status
------------------------------------------
got -h              stdout               0
got -h valid-cmd    stdout               0
got -h invalid-cmd  stderr               1

Of course, if preferred, we could also do the opposite and make using
the '-h' flag without a command exit with status 1 and print to stderr.
This would yield a much smaller diff.

The test suite is passing, but I didn't run the tests for gotd, gotwebd
and gotsys as I currently don't have a spare machine to set up the
required environment and don't want to do it on my personal machine. I'd
appreciate if someone could check this.

[1] I believe I got most of them, but please let me know if I missed
any.

commit 7aba215b4c8f0122161bf51177ddf8c07c887193
from: Johannes Thyssen Tishman <jtt@openbsd.org>
date: Tue Nov 18 17:55:49 2025 UTC

standardize exit status across all usage functions

M  cvg/cvg.c              |  132+  113-
M  got/got.c              |  217+  187-
M  gotadmin/gotadmin.c    |   53+   45-
M  gotctl/gotctl.c        |   18+   15-
M  gotsys/gotsys.c        |   16+   14-
M  gotsysctl/gotsysctl.c  |    7+    6-
M  tog/tog.c              |   36+   31-

7 files changed, 479 insertions(+), 411 deletions(-)

commit - b825ad9bba095c5b64eb9f5bf57fb86a1ac0a52d
commit + 7aba215b4c8f0122161bf51177ddf8c07c887193
blob - 8221680034ffc1350574a4b3647128607e60218a
blob + 8bc47fb2cbcc88f89ff5dc2e9eb2cf7445f26c88
--- cvg/cvg.c
+++ cvg/cvg.c
@@ -93,30 +93,30 @@ catch_sigpipe(int signo)
 struct got_cmd {
 	const char	*cmd_name;
 	const struct got_error *(*cmd_main)(int, char *[]);
-	void		(*cmd_usage)(void);
+	void		(*cmd_usage)(int);
 	const char	*cmd_alias;
 };
 
 __dead static void	usage(int, int);
-__dead static void	usage_import(void);
-__dead static void	usage_clone(void);
-__dead static void	usage_checkout(void);
-__dead static void	usage_update(void);
-__dead static void	usage_log(void);
-__dead static void	usage_diff(void);
-__dead static void	usage_blame(void);
-__dead static void	usage_tree(void);
-__dead static void	usage_status(void);
-__dead static void	usage_tag(void);
-__dead static void	usage_add(void);
-__dead static void	usage_remove(void);
-__dead static void	usage_patch(void);
-__dead static void	usage_revert(void);
-__dead static void	usage_commit(void);
-__dead static void	usage_cherrypick(void);
-__dead static void	usage_backout(void);
-__dead static void	usage_cat(void);
-__dead static void	usage_info(void);
+__dead static void	usage_import(int);
+__dead static void	usage_clone(int);
+__dead static void	usage_checkout(int);
+__dead static void	usage_update(int);
+__dead static void	usage_log(int);
+__dead static void	usage_diff(int);
+__dead static void	usage_blame(int);
+__dead static void	usage_tree(int);
+__dead static void	usage_status(int);
+__dead static void	usage_tag(int);
+__dead static void	usage_add(int);
+__dead static void	usage_remove(int);
+__dead static void	usage_patch(int);
+__dead static void	usage_revert(int);
+__dead static void	usage_commit(int);
+__dead static void	usage_cherrypick(int);
+__dead static void	usage_backout(int);
+__dead static void	usage_cat(int);
+__dead static void	usage_info(int);
 
 static const struct got_error*		cmd_import(int, char *[]);
 static const struct got_error*		cmd_clone(int, char *[]);
@@ -233,7 +233,7 @@ main(int argc, char *argv[])
 			continue;
 
 		if (hflag)
-			cmd->cmd_usage();
+			cmd->cmd_usage(0);
 
 		error = cmd->cmd_main(argc, argv);
 		if (error && error->code != GOT_ERR_CANCELLED &&
@@ -324,11 +324,12 @@ apply_unveil(const char *repo_path, int repo_read_only
 }
 
 __dead static void
-usage_import(void)
+usage_import(int status)
 {
-	fprintf(stderr, "usage: %s import [-b branch] [-I pattern] [-m message] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s import [-b branch] [-I pattern] [-m message] "
 	    "[-r repository-path] directory\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static int
@@ -779,7 +780,7 @@ cmd_import(int argc, char *argv[])
 			}
 			break;
 		default:
-			usage_import();
+			usage_import(1);
 			/* NOTREACHED */
 		}
 	}
@@ -788,7 +789,7 @@ cmd_import(int argc, char *argv[])
 	argv += optind;
 
 	if (argc != 1)
-		usage_import();
+		usage_import(1);
 
 	if (repo_path == NULL) {
 		repo_path = getcwd(NULL, 0);
@@ -978,12 +979,13 @@ done:
 }
 
 __dead static void
-usage_clone(void)
+usage_clone(int status)
 {
-	fprintf(stderr, "usage: %s clone [-almqv] [-b branch] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s clone [-almqv] [-b branch] "
 	    "[-i identity-file] [-J jumphost] [-R reference] "
 	    "repository-URL [directory]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 struct got_fetch_progress_arg {
@@ -1590,7 +1592,7 @@ cmd_clone(int argc, char *argv[])
 				verbosity++;
 			break;
 		default:
-			usage_clone();
+			usage_clone(1);
 			break;
 		}
 	}
@@ -1617,7 +1619,7 @@ cmd_clone(int argc, char *argv[])
 	else if (argc == 2)
 		dirname = argv[1];
 	else
-		usage_clone();
+		usage_clone(1);
 
 	error = got_dial_parse_uri(&proto, &host, &port, &server_path,
 	    &repo_name, uri);
@@ -2018,12 +2020,13 @@ done:
 }
 
 __dead static void
-usage_checkout(void)
+usage_checkout(int status)
 {
-	fprintf(stderr, "usage: %s checkout [-Eq] [-b branch] [-c commit] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s checkout [-Eq] [-b branch] [-c commit] "
 	    "[-p path-prefix] repository-path [work-tree-path]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static void
@@ -2234,7 +2237,7 @@ cmd_checkout(int argc, char *argv[])
 			verbosity = -1;
 			break;
 		default:
-			usage_checkout();
+			usage_checkout(1);
 			/* NOTREACHED */
 		}
 	}
@@ -2289,7 +2292,7 @@ cmd_checkout(int argc, char *argv[])
 			}
 		}
 	} else
-		usage_checkout();
+		usage_checkout(1);
 
 	got_path_strip_trailing_slashes(repo_path);
 	got_path_strip_trailing_slashes(worktree_path);
@@ -2496,12 +2499,13 @@ print_merge_progress_stats(struct got_update_progress_
 }
 
 __dead static void
-usage_update(void)
+usage_update(int status)
 {
-	fprintf(stderr, "usage: %s update [-qtvX] [-c commit] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s update [-qtvX] [-c commit] "
 	    "[-i identity-file] [-J jumphost] [-r remote] [path ...]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -2721,7 +2725,7 @@ cmd_update(int argc, char *argv[])
 			delete_remote = 1;
 			break;
 		default:
-			usage_update();
+			usage_update(1);
 			break;
 		}
 	}
@@ -3932,12 +3936,13 @@ done:
 }
 
 __dead static void
-usage_log(void)
+usage_log(int status)
 {
-	fprintf(stderr, "usage: %s log [-bdPpRs] [-C number] [-c commit] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s log [-bdPpRs] [-C number] [-c commit] "
 	    "[-l N] [-r repository-path] [-S search-pattern] [-x commit] "
 	    "[path]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static int
@@ -4036,7 +4041,7 @@ cmd_log(int argc, char *argv[])
 			end_commit = optarg;
 			break;
 		default:
-			usage_log();
+			usage_log(1);
 			/* NOTREACHED */
 		}
 	}
@@ -4083,7 +4088,7 @@ cmd_log(int argc, char *argv[])
 			}
 		}
 	} else if (argc != 0)
-		usage_log();
+		usage_log(1);
 
 	if (repo_path == NULL) {
 		repo_path = worktree ?
@@ -4212,12 +4217,13 @@ done:
 }
 
 __dead static void
-usage_diff(void)
+usage_diff(int status)
 {
-	fprintf(stderr, "usage: %s diff [-adPsw] [-C number] [-c commit] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s diff [-adPsw] [-C number] [-c commit] "
 	    "[-r repository-path] [object1 object2 | path ...]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 struct print_diff_arg {
@@ -4552,7 +4558,7 @@ cmd_diff(int argc, char *argv[])
 			ignore_whitespace = 1;
 			break;
 		default:
-			usage_diff();
+			usage_diff(1);
 			/* NOTREACHED */
 		}
 	}
@@ -4946,12 +4952,13 @@ done:
 }
 
 __dead static void
-usage_blame(void)
+usage_blame(int status)
 {
-	fprintf(stderr,
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp,
 	    "usage: %s blame [-c commit] [-r repository-path] path\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 struct blame_line {
@@ -5107,7 +5114,7 @@ cmd_blame(int argc, char *argv[])
 			got_path_strip_trailing_slashes(repo_path);
 			break;
 		default:
-			usage_blame();
+			usage_blame(1);
 			/* NOTREACHED */
 		}
 	}
@@ -5118,7 +5125,7 @@ cmd_blame(int argc, char *argv[])
 	if (argc == 1)
 		path = argv[0];
 	else
-		usage_blame();
+		usage_blame(1);
 
 	cwd = getcwd(NULL, 0);
 	if (cwd == NULL) {
@@ -5341,11 +5348,12 @@ done:
 }
 
 __dead static void
-usage_tree(void)
+usage_tree(int status)
 {
-	fprintf(stderr, "usage: %s tree [-iR] [-c commit] [-r repository-path] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s tree [-iR] [-c commit] [-r repository-path] "
 	    "[path]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -5496,7 +5504,7 @@ cmd_tree(int argc, char *argv[])
 			got_path_strip_trailing_slashes(repo_path);
 			break;
 		default:
-			usage_tree();
+			usage_tree(1);
 			/* NOTREACHED */
 		}
 	}
@@ -5507,7 +5515,7 @@ cmd_tree(int argc, char *argv[])
 	if (argc == 1)
 		path = argv[0];
 	else if (argc > 1)
-		usage_tree();
+		usage_tree(1);
 	else
 		path = NULL;
 
@@ -5641,11 +5649,12 @@ done:
 }
 
 __dead static void
-usage_status(void)
+usage_status(int status)
 {
-	fprintf(stderr, "usage: %s status [-I] [-S status-codes] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s status [-I] [-S status-codes] "
 	    "[-s status-codes] [path ...]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 struct got_status_arg {
@@ -5749,7 +5758,7 @@ cmd_status(int argc, char *argv[])
 			st.status_codes = optarg;
 			break;
 		default:
-			usage_status();
+			usage_status(1);
 			/* NOTREACHED */
 		}
 	}
@@ -5809,11 +5818,12 @@ done:
 }
 
 __dead static void
-usage_tag(void)
+usage_tag(int status)
 {
-	fprintf(stderr, "usage: %s tag [-lVv] [-c commit] [-m message] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s tag [-lVv] [-c commit] [-m message] "
 	    "[-r repository-path] [-s signer-id] name\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 #if 0
@@ -6287,7 +6297,7 @@ cmd_tag(int argc, char *argv[])
 				verbosity++;
 			break;
 		default:
-			usage_tag();
+			usage_tag(1);
 			/* NOTREACHED */
 		}
 	}
@@ -6312,9 +6322,9 @@ cmd_tag(int argc, char *argv[])
 				option_conflict('V', 's');
 		}
 		if (argc > 1)
-			usage_tag();
+			usage_tag(1);
 	} else if (argc != 1)
-		usage_tag();
+		usage_tag(1);
 
 	if (argc == 1)
 		tag_name = argv[0];
@@ -6464,10 +6474,11 @@ done:
 }
 
 __dead static void
-usage_add(void)
+usage_add(int status)
 {
-	fprintf(stderr, "usage: %s add [-IR] path ...\n", getprogname());
-	exit(1);
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s add [-IR] path ...\n", getprogname());
+	exit(status);
 }
 
 static const struct got_error *
@@ -6508,7 +6519,7 @@ cmd_add(int argc, char *argv[])
 			can_recurse = 1;
 			break;
 		default:
-			usage_add();
+			usage_add(1);
 			/* NOTREACHED */
 		}
 	}
@@ -6517,7 +6528,7 @@ cmd_add(int argc, char *argv[])
 	argv += optind;
 
 	if (argc < 1)
-		usage_add();
+		usage_add(1);
 
 	cwd = getcwd(NULL, 0);
 	if (cwd == NULL) {
@@ -6601,11 +6612,12 @@ done:
 }
 
 __dead static void
-usage_remove(void)
+usage_remove(int status)
 {
-	fprintf(stderr, "usage: %s remove [-fkR] [-s status-codes] path ...\n",
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s remove [-fkR] [-s status-codes] path ...\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -6673,7 +6685,7 @@ cmd_remove(int argc, char *argv[])
 			status_codes = optarg;
 			break;
 		default:
-			usage_remove();
+			usage_remove(1);
 			/* NOTREACHED */
 		}
 	}
@@ -6682,7 +6694,7 @@ cmd_remove(int argc, char *argv[])
 	argv += optind;
 
 	if (argc < 1)
-		usage_remove();
+		usage_remove(1);
 
 	cwd = getcwd(NULL, 0);
 	if (cwd == NULL) {
@@ -6767,11 +6779,12 @@ done:
 }
 
 __dead static void
-usage_patch(void)
+usage_patch(int status)
 {
-	fprintf(stderr, "usage: %s patch [-nR] [-c commit] [-p strip-count] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s patch [-nR] [-c commit] [-p strip-count] "
 	    "[patchfile]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -6925,7 +6938,7 @@ cmd_patch(int argc, char *argv[])
 			reverse = 1;
 			break;
 		default:
-			usage_patch();
+			usage_patch(1);
 			/* NOTREACHED */
 		}
 	}
@@ -6950,7 +6963,7 @@ cmd_patch(int argc, char *argv[])
 			goto done;
 		}
 	} else
-		usage_patch();
+		usage_patch(1);
 
 	if ((cwd = getcwd(NULL, 0)) == NULL) {
 		error = got_error_from_errno("getcwd");
@@ -7014,11 +7027,12 @@ done:
 }
 
 __dead static void
-usage_revert(void)
+usage_revert(int status)
 {
-	fprintf(stderr, "usage: %s revert [-pR] [-F response-script] path ...\n",
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s revert [-pR] [-F response-script] path ...\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -7382,7 +7396,7 @@ cmd_revert(int argc, char *argv[])
 			can_recurse = 1;
 			break;
 		default:
-			usage_revert();
+			usage_revert(1);
 			/* NOTREACHED */
 		}
 	}
@@ -7391,7 +7405,7 @@ cmd_revert(int argc, char *argv[])
 	argv += optind;
 
 	if (argc < 1)
-		usage_revert();
+		usage_revert(1);
 	if (patch_script_path && !pflag)
 		errx(1, "-F option can only be used together with -p option");
 
@@ -7497,12 +7511,13 @@ done:
 }
 
 __dead static void
-usage_commit(void)
+usage_commit(int status)
 {
-	fprintf(stderr, "usage: %s commit [-CNnS] [-A author] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s commit [-CNnS] [-A author] "
 	    "[-i identity-file] [-J jumphost] [-F path] [-m message] "
 	    "[path ...]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 struct collect_commit_logmsg_arg {
@@ -7878,7 +7893,7 @@ cmd_commit(int argc, char *argv[])
 			allow_bad_symlinks = 1;
 			break;
 		default:
-			usage_commit();
+			usage_commit(1);
 			/* NOTREACHED */
 		}
 	}
@@ -8331,11 +8346,12 @@ done:
 }
 
 __dead static void
-usage_cherrypick(void)
+usage_cherrypick(int status)
 {
-	fprintf(stderr, "usage: %s cherrypick [-lX] [commit-id]\n",
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s cherrypick [-lX] [commit-id]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -8367,7 +8383,7 @@ cmd_cherrypick(int argc, char *argv[])
 			remove_refs = 1;
 			break;
 		default:
-			usage_cherrypick();
+			usage_cherrypick(1);
 			/* NOTREACHED */
 		}
 	}
@@ -8377,9 +8393,9 @@ cmd_cherrypick(int argc, char *argv[])
 
 	if (list_refs || remove_refs) {
 		if (argc != 0 && argc != 1)
-			usage_cherrypick();
+			usage_cherrypick(1);
 	} else if (argc != 1)
-		usage_cherrypick();
+		usage_cherrypick(1);
 	if (list_refs && remove_refs)
 		option_conflict('l', 'X');
 
@@ -8474,10 +8490,11 @@ done:
 }
 
 __dead static void
-usage_backout(void)
+usage_backout(int status)
 {
-	fprintf(stderr, "usage: %s backout [-lX] [commit-id]\n", getprogname());
-	exit(1);
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s backout [-lX] [commit-id]\n", getprogname());
+	exit(status);
 }
 
 static const struct got_error *
@@ -8509,7 +8526,7 @@ cmd_backout(int argc, char *argv[])
 			remove_refs = 1;
 			break;
 		default:
-			usage_backout();
+			usage_backout(1);
 			/* NOTREACHED */
 		}
 	}
@@ -8519,9 +8536,9 @@ cmd_backout(int argc, char *argv[])
 
 	if (list_refs || remove_refs) {
 		if (argc != 0 && argc != 1)
-			usage_backout();
+			usage_backout(1);
 	} else if (argc != 1)
-		usage_backout();
+		usage_backout(1);
 	if (list_refs && remove_refs)
 		option_conflict('l', 'X');
 
@@ -8619,11 +8636,12 @@ done:
 }
 
 __dead static void
-usage_cat(void)
+usage_cat(int status)
 {
-	fprintf(stderr, "usage: %s cat [-P] [-c commit] [-r repository-path] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s cat [-P] [-c commit] [-r repository-path] "
 	    "arg ...\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -8832,7 +8850,7 @@ cmd_cat(int argc, char *argv[])
 			got_path_strip_trailing_slashes(repo_path);
 			break;
 		default:
-			usage_cat();
+			usage_cat(1);
 			/* NOTREACHED */
 		}
 	}
@@ -8972,11 +8990,12 @@ done:
 }
 
 __dead static void
-usage_info(void)
+usage_info(int status)
 {
-	fprintf(stderr, "usage: %s info [path ...]\n",
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s info [path ...]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -9071,7 +9090,7 @@ cmd_info(int argc, char *argv[])
 	while ((ch = getopt(argc, argv, "")) != -1) {
 		switch (ch) {
 		default:
-			usage_info();
+			usage_info(1);
 			/* NOTREACHED */
 		}
 	}
blob - d6ded8622b2ce843759afedbfaabf40980e3a955
blob + 487b4865e729be9a32fd1157ab96adf4e609986e
--- got/got.c
+++ got/got.c
@@ -92,41 +92,41 @@ catch_sigpipe(int signo)
 struct got_cmd {
 	const char	*cmd_name;
 	const struct got_error *(*cmd_main)(int, char *[]);
-	void		(*cmd_usage)(void);
+	void		(*cmd_usage)(int);
 	const char	*cmd_alias;
 };
 
 __dead static void	usage(int, int);
-__dead static void	usage_init(void);
-__dead static void	usage_import(void);
-__dead static void	usage_clone(void);
-__dead static void	usage_fetch(void);
-__dead static void	usage_checkout(void);
-__dead static void	usage_update(void);
-__dead static void	usage_log(void);
-__dead static void	usage_diff(void);
-__dead static void	usage_blame(void);
-__dead static void	usage_tree(void);
-__dead static void	usage_status(void);
-__dead static void	usage_ref(void);
-__dead static void	usage_branch(void);
-__dead static void	usage_tag(void);
-__dead static void	usage_add(void);
-__dead static void	usage_remove(void);
-__dead static void	usage_patch(void);
-__dead static void	usage_revert(void);
-__dead static void	usage_commit(void);
-__dead static void	usage_send(void);
-__dead static void	usage_cherrypick(void);
-__dead static void	usage_backout(void);
-__dead static void	usage_rebase(void);
-__dead static void	usage_histedit(void);
-__dead static void	usage_integrate(void);
-__dead static void	usage_merge(void);
-__dead static void	usage_stage(void);
-__dead static void	usage_unstage(void);
-__dead static void	usage_cat(void);
-__dead static void	usage_info(void);
+__dead static void	usage_init(int);
+__dead static void	usage_import(int);
+__dead static void	usage_clone(int);
+__dead static void	usage_fetch(int);
+__dead static void	usage_checkout(int);
+__dead static void	usage_update(int);
+__dead static void	usage_log(int);
+__dead static void	usage_diff(int);
+__dead static void	usage_blame(int);
+__dead static void	usage_tree(int);
+__dead static void	usage_status(int);
+__dead static void	usage_ref(int);
+__dead static void	usage_branch(int);
+__dead static void	usage_tag(int);
+__dead static void	usage_add(int);
+__dead static void	usage_remove(int);
+__dead static void	usage_patch(int);
+__dead static void	usage_revert(int);
+__dead static void	usage_commit(int);
+__dead static void	usage_send(int);
+__dead static void	usage_cherrypick(int);
+__dead static void	usage_backout(int);
+__dead static void	usage_rebase(int);
+__dead static void	usage_histedit(int);
+__dead static void	usage_integrate(int);
+__dead static void	usage_merge(int);
+__dead static void	usage_stage(int);
+__dead static void	usage_unstage(int);
+__dead static void	usage_cat(int);
+__dead static void	usage_info(int);
 
 static const struct got_error*		cmd_init(int, char *[]);
 static const struct got_error*		cmd_import(int, char *[]);
@@ -265,7 +265,7 @@ main(int argc, char *argv[])
 			continue;
 
 		if (hflag)
-			cmd->cmd_usage();
+			cmd->cmd_usage(0);
 
 		error = cmd->cmd_main(argc, argv);
 		if (error && error->code != GOT_ERR_CANCELLED &&
@@ -356,12 +356,13 @@ apply_unveil(const char *repo_path, int repo_read_only
 }
 
 __dead static void
-usage_init(void)
+usage_init(int status)
 {
-	fprintf(stderr, "usage: %s init [-A hashing-algorithm] [-b branch]"
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s init [-A hashing-algorithm] [-b branch]"
 	    " repository-path\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -388,7 +389,7 @@ cmd_init(int argc, char *argv[])
 			head_name = optarg;
 			break;
 		default:
-			usage_init();
+			usage_init(1);
 			/* NOTREACHED */
 		}
 	}
@@ -401,7 +402,7 @@ cmd_init(int argc, char *argv[])
 		err(1, "pledge");
 #endif
 	if (argc != 1)
-		usage_init();
+		usage_init(1);
 
 	repo_path = strdup(argv[0]);
 	if (repo_path == NULL)
@@ -425,11 +426,12 @@ done:
 }
 
 __dead static void
-usage_import(void)
+usage_import(int status)
 {
-	fprintf(stderr, "usage: %s import [-b branch] [-I pattern] [-m message] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s import [-b branch] [-I pattern] [-m message] "
 	    "[-r repository-path] directory\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static int
@@ -881,7 +883,7 @@ cmd_import(int argc, char *argv[])
 			}
 			break;
 		default:
-			usage_import();
+			usage_import(1);
 			/* NOTREACHED */
 		}
 	}
@@ -890,7 +892,7 @@ cmd_import(int argc, char *argv[])
 	argv += optind;
 
 	if (argc != 1)
-		usage_import();
+		usage_import(1);
 
 	if (repo_path == NULL) {
 		repo_path = getcwd(NULL, 0);
@@ -1066,12 +1068,13 @@ done:
 }
 
 __dead static void
-usage_clone(void)
+usage_clone(int status)
 {
-	fprintf(stderr, "usage: %s clone [-almqv] [-b branch] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s clone [-almqv] [-b branch] "
 	    "[-i identity-file] [-J jumphost] [-R reference] "
 	    "repository-URL [directory]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 struct got_fetch_progress_arg {
@@ -1683,7 +1686,7 @@ cmd_clone(int argc, char *argv[])
 				verbosity++;
 			break;
 		default:
-			usage_clone();
+			usage_clone(1);
 			break;
 		}
 	}
@@ -1710,7 +1713,7 @@ cmd_clone(int argc, char *argv[])
 	else if (argc == 2)
 		dirname = argv[1];
 	else
-		usage_clone();
+		usage_clone(1);
 
 	error = got_dial_parse_uri(&proto, &host, &port, &server_path,
 	    &repo_name, uri);
@@ -2172,12 +2175,13 @@ done:
 }
 
 __dead static void
-usage_fetch(void)
+usage_fetch(int status)
 {
-	fprintf(stderr, "usage: %s fetch [-adlqtvX] [-b branch] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s fetch [-adlqtvX] [-b branch] "
 	    "[-i identity-file] [-J jumphost] [-R reference] "
 	    "[-r repository-path] [remote-repository]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -2495,7 +2499,7 @@ cmd_fetch(int argc, char *argv[])
 			delete_remote = 1;
 			break;
 		default:
-			usage_fetch();
+			usage_fetch(1);
 			break;
 		}
 	}
@@ -2534,7 +2538,7 @@ cmd_fetch(int argc, char *argv[])
 	} else if (argc == 1)
 		remote_name = argv[0];
 	else
-		usage_fetch();
+		usage_fetch(1);
 
 	cwd = getcwd(NULL, 0);
 	if (cwd == NULL) {
@@ -2960,12 +2964,13 @@ done:
 
 
 __dead static void
-usage_checkout(void)
+usage_checkout(int status)
 {
-	fprintf(stderr, "usage: %s checkout [-Eq] [-b branch] [-c commit] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s checkout [-Eq] [-b branch] [-c commit] "
 	    "[-p path-prefix] repository-path [work-tree-path]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static void
@@ -3176,7 +3181,7 @@ cmd_checkout(int argc, char *argv[])
 			verbosity = -1;
 			break;
 		default:
-			usage_checkout();
+			usage_checkout(1);
 			/* NOTREACHED */
 		}
 	}
@@ -3231,7 +3236,7 @@ cmd_checkout(int argc, char *argv[])
 			}
 		}
 	} else
-		usage_checkout();
+		usage_checkout(1);
 
 	got_path_strip_trailing_slashes(repo_path);
 	got_path_strip_trailing_slashes(worktree_path);
@@ -3463,11 +3468,12 @@ print_merge_progress_stats(struct got_update_progress_
 }
 
 __dead static void
-usage_update(void)
+usage_update(int status)
 {
-	fprintf(stderr, "usage: %s update [-q] [-b branch] [-c commit] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s update [-q] [-b branch] [-c commit] "
 	    "[path ...]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -3679,7 +3685,7 @@ cmd_update(int argc, char *argv[])
 			verbosity = -1;
 			break;
 		default:
-			usage_update();
+			usage_update(1);
 			/* NOTREACHED */
 		}
 	}
@@ -4731,12 +4737,13 @@ done:
 }
 
 __dead static void
-usage_log(void)
+usage_log(int status)
 {
-	fprintf(stderr, "usage: %s log [-bdPpRst] [-C number] [-c commit] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s log [-bdPpRst] [-C number] [-c commit] "
 	    "[-l N] [-r repository-path] [-S search-pattern] [-x commit] "
 	    "[path]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static int
@@ -4840,7 +4847,7 @@ cmd_log(int argc, char *argv[])
 			end_commit = optarg;
 			break;
 		default:
-			usage_log();
+			usage_log(1);
 			/* NOTREACHED */
 		}
 	}
@@ -4888,7 +4895,7 @@ cmd_log(int argc, char *argv[])
 			}
 		}
 	} else if (argc != 0)
-		usage_log();
+		usage_log(1);
 
 	if (repo_path == NULL) {
 		repo_path = worktree ?
@@ -5032,12 +5039,13 @@ done:
 }
 
 __dead static void
-usage_diff(void)
+usage_diff(int status)
 {
-	fprintf(stderr, "usage: %s diff [-adPsw] [-C number] [-c commit] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s diff [-adPsw] [-C number] [-c commit] "
 	    "[-r repository-path] [object1 object2 | path ...]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 struct print_diff_arg {
@@ -5400,7 +5408,7 @@ cmd_diff(int argc, char *argv[])
 			ignore_whitespace = 1;
 			break;
 		default:
-			usage_diff();
+			usage_diff(1);
 			/* NOTREACHED */
 		}
 	}
@@ -5807,12 +5815,13 @@ done:
 }
 
 __dead static void
-usage_blame(void)
+usage_blame(int status)
 {
-	fprintf(stderr,
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp,
 	    "usage: %s blame [-c commit] [-r repository-path] path\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 struct blame_line {
@@ -5968,7 +5977,7 @@ cmd_blame(int argc, char *argv[])
 			got_path_strip_trailing_slashes(repo_path);
 			break;
 		default:
-			usage_blame();
+			usage_blame(1);
 			/* NOTREACHED */
 		}
 	}
@@ -5979,7 +5988,7 @@ cmd_blame(int argc, char *argv[])
 	if (argc == 1)
 		path = argv[0];
 	else
-		usage_blame();
+		usage_blame(1);
 
 	cwd = getcwd(NULL, 0);
 	if (cwd == NULL) {
@@ -6213,11 +6222,12 @@ done:
 }
 
 __dead static void
-usage_tree(void)
+usage_tree(int status)
 {
-	fprintf(stderr, "usage: %s tree [-iR] [-c commit] [-r repository-path] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s tree [-iR] [-c commit] [-r repository-path] "
 	    "[path]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -6368,7 +6378,7 @@ cmd_tree(int argc, char *argv[])
 			got_path_strip_trailing_slashes(repo_path);
 			break;
 		default:
-			usage_tree();
+			usage_tree(1);
 			/* NOTREACHED */
 		}
 	}
@@ -6379,7 +6389,7 @@ cmd_tree(int argc, char *argv[])
 	if (argc == 1)
 		path = argv[0];
 	else if (argc > 1)
-		usage_tree();
+		usage_tree(1);
 	else
 		path = NULL;
 
@@ -6524,11 +6534,12 @@ done:
 }
 
 __dead static void
-usage_status(void)
+usage_status(int status)
 {
-	fprintf(stderr, "usage: %s status [-I] [-S status-codes] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s status [-I] [-S status-codes] "
 	    "[-s status-codes] [path ...]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 struct got_status_arg {
@@ -6682,7 +6693,7 @@ cmd_status(int argc, char *argv[])
 			st.status_codes = optarg;
 			break;
 		default:
-			usage_status();
+			usage_status(1);
 			/* NOTREACHED */
 		}
 	}
@@ -6752,11 +6763,12 @@ done:
 }
 
 __dead static void
-usage_ref(void)
+usage_ref(int status)
 {
-	fprintf(stderr, "usage: %s ref [-dlt] [-c object] [-r repository-path] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s ref [-dlt] [-c object] [-r repository-path] "
 	    "[-s reference] [name]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -6915,7 +6927,7 @@ cmd_ref(int argc, char *argv[])
 			sort_by_time = 1;
 			break;
 		default:
-			usage_ref();
+			usage_ref(1);
 			/* NOTREACHED */
 		}
 	}
@@ -6940,7 +6952,7 @@ cmd_ref(int argc, char *argv[])
 
 	if (do_list) {
 		if (argc != 0 && argc != 1)
-			usage_ref();
+			usage_ref(1);
 		if (argc == 1) {
 			refname = strdup(argv[0]);
 			if (refname == NULL) {
@@ -6950,7 +6962,7 @@ cmd_ref(int argc, char *argv[])
 		}
 	} else {
 		if (argc != 1)
-			usage_ref();
+			usage_ref(1);
 		refname = strdup(argv[0]);
 		if (refname == NULL) {
 			error = got_error_from_errno("strdup");
@@ -7016,7 +7028,7 @@ cmd_ref(int argc, char *argv[])
 		error = add_symref(repo, refname, symref_target);
 	else {
 		if (obj_arg == NULL)
-			usage_ref();
+			usage_ref(1);
 
 		error = got_keyword_to_idstr(&keyword_idstr, obj_arg,
 		    repo, worktree);
@@ -7043,11 +7055,12 @@ done:
 }
 
 __dead static void
-usage_branch(void)
+usage_branch(int status)
 {
-	fprintf(stderr, "usage: %s branch [-lnt] [-c commit] [-d name] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s branch [-lnt] [-c commit] [-d name] "
 	    "[-r repository-path] [name]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -7310,7 +7323,7 @@ cmd_branch(int argc, char *argv[])
 			sort_by_time = 1;
 			break;
 		default:
-			usage_branch();
+			usage_branch(1);
 			/* NOTREACHED */
 		}
 	}
@@ -7331,9 +7344,9 @@ cmd_branch(int argc, char *argv[])
 
 	if (do_list || delref) {
 		if (argc > 0)
-			usage_branch();
+			usage_branch(1);
 	} else if (!do_show && argc != 1)
-		usage_branch();
+		usage_branch(1);
 
 	cwd = getcwd(NULL, 0);
 	if (cwd == NULL) {
@@ -7488,11 +7501,12 @@ done:
 
 
 __dead static void
-usage_tag(void)
+usage_tag(int status)
 {
-	fprintf(stderr, "usage: %s tag [-lsVv] [-c commit] [-m message] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s tag [-lsVv] [-c commit] [-m message] "
 	    "[-r repository-path] [-S signer-id] name\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 #if 0
@@ -8046,7 +8060,7 @@ cmd_tag(int argc, char *argv[])
 				verbosity++;
 			break;
 		default:
-			usage_tag();
+			usage_tag(1);
 			/* NOTREACHED */
 		}
 	}
@@ -8073,9 +8087,9 @@ cmd_tag(int argc, char *argv[])
 				option_conflict('V', 'S');
 		}
 		if (argc > 1)
-			usage_tag();
+			usage_tag(1);
 	} else if (argc != 1)
-		usage_tag();
+		usage_tag(1);
 
 	if (argc == 1)
 		tag_name = argv[0];
@@ -8240,10 +8254,11 @@ done:
 }
 
 __dead static void
-usage_add(void)
+usage_add(int status)
 {
-	fprintf(stderr, "usage: %s add [-IR] path ...\n", getprogname());
-	exit(1);
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s add [-IR] path ...\n", getprogname());
+	exit(status);
 }
 
 static const struct got_error *
@@ -8284,7 +8299,7 @@ cmd_add(int argc, char *argv[])
 			can_recurse = 1;
 			break;
 		default:
-			usage_add();
+			usage_add(1);
 			/* NOTREACHED */
 		}
 	}
@@ -8293,7 +8308,7 @@ cmd_add(int argc, char *argv[])
 	argv += optind;
 
 	if (argc < 1)
-		usage_add();
+		usage_add(1);
 
 	cwd = getcwd(NULL, 0);
 	if (cwd == NULL) {
@@ -8377,11 +8392,12 @@ done:
 }
 
 __dead static void
-usage_remove(void)
+usage_remove(int status)
 {
-	fprintf(stderr, "usage: %s remove [-fkR] [-s status-codes] path ...\n",
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s remove [-fkR] [-s status-codes] path ...\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -8449,7 +8465,7 @@ cmd_remove(int argc, char *argv[])
 			status_codes = optarg;
 			break;
 		default:
-			usage_remove();
+			usage_remove(1);
 			/* NOTREACHED */
 		}
 	}
@@ -8458,7 +8474,7 @@ cmd_remove(int argc, char *argv[])
 	argv += optind;
 
 	if (argc < 1)
-		usage_remove();
+		usage_remove(1);
 
 	cwd = getcwd(NULL, 0);
 	if (cwd == NULL) {
@@ -8543,11 +8559,12 @@ done:
 }
 
 __dead static void
-usage_patch(void)
+usage_patch(int status)
 {
-	fprintf(stderr, "usage: %s patch [-nR] [-c commit] [-p strip-count] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s patch [-nR] [-c commit] [-p strip-count] "
 	    "[patchfile]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -8701,7 +8718,7 @@ cmd_patch(int argc, char *argv[])
 			reverse = 1;
 			break;
 		default:
-			usage_patch();
+			usage_patch(1);
 			/* NOTREACHED */
 		}
 	}
@@ -8726,7 +8743,7 @@ cmd_patch(int argc, char *argv[])
 			goto done;
 		}
 	} else
-		usage_patch();
+		usage_patch(1);
 
 	if ((cwd = getcwd(NULL, 0)) == NULL) {
 		error = got_error_from_errno("getcwd");
@@ -8797,11 +8814,12 @@ done:
 }
 
 __dead static void
-usage_revert(void)
+usage_revert(int status)
 {
-	fprintf(stderr, "usage: %s revert [-pR] [-F response-script] path ...\n",
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s revert [-pR] [-F response-script] path ...\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -9172,7 +9190,7 @@ cmd_revert(int argc, char *argv[])
 			can_recurse = 1;
 			break;
 		default:
-			usage_revert();
+			usage_revert(1);
 			/* NOTREACHED */
 		}
 	}
@@ -9181,7 +9199,7 @@ cmd_revert(int argc, char *argv[])
 	argv += optind;
 
 	if (argc < 1)
-		usage_revert();
+		usage_revert(1);
 	if (patch_script_path && !pflag)
 		errx(1, "-F option can only be used together with -p option");
 
@@ -9287,11 +9305,12 @@ done:
 }
 
 __dead static void
-usage_commit(void)
+usage_commit(int status)
 {
-	fprintf(stderr, "usage: %s commit [-CNnS] [-A author] [-F path] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s commit [-CNnS] [-A author] [-F path] "
 	    "[-m message] [path ...]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 struct collect_commit_logmsg_arg {
@@ -9648,7 +9667,7 @@ cmd_commit(int argc, char *argv[])
 			allow_bad_symlinks = 1;
 			break;
 		default:
-			usage_commit();
+			usage_commit(1);
 			/* NOTREACHED */
 		}
 	}
@@ -9814,12 +9833,13 @@ done:
 }
 
 __dead static void
-usage_send(void)
+usage_send(int status)
 {
-	fprintf(stderr, "usage: %s send [-afqTv] [-b branch] [-d branch] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s send [-afqTv] [-b branch] [-d branch] "
 	    "[-i identity-file] [-J jumphost] [-r repository-path] [-t tag] "
 	    "[remote-repository]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static void
@@ -10104,7 +10124,7 @@ cmd_send(int argc, char *argv[])
 				verbosity++;
 			break;
 		default:
-			usage_send();
+			usage_send(1);
 			/* NOTREACHED */
 		}
 	}
@@ -10122,7 +10142,7 @@ cmd_send(int argc, char *argv[])
 	else if (argc == 1)
 		remote_name = argv[0];
 	else
-		usage_send();
+		usage_send(1);
 
 	cwd = getcwd(NULL, 0);
 	if (cwd == NULL) {
@@ -10631,11 +10651,12 @@ done:
 }
 
 __dead static void
-usage_cherrypick(void)
+usage_cherrypick(int status)
 {
-	fprintf(stderr, "usage: %s cherrypick [-lX] [commit-id]\n",
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s cherrypick [-lX] [commit-id]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -10667,7 +10688,7 @@ cmd_cherrypick(int argc, char *argv[])
 			remove_refs = 1;
 			break;
 		default:
-			usage_cherrypick();
+			usage_cherrypick(1);
 			/* NOTREACHED */
 		}
 	}
@@ -10677,9 +10698,9 @@ cmd_cherrypick(int argc, char *argv[])
 
 	if (list_refs || remove_refs) {
 		if (argc != 0 && argc != 1)
-			usage_cherrypick();
+			usage_cherrypick(1);
 	} else if (argc != 1)
-		usage_cherrypick();
+		usage_cherrypick(1);
 	if (list_refs && remove_refs)
 		option_conflict('l', 'X');
 
@@ -10780,10 +10801,11 @@ done:
 }
 
 __dead static void
-usage_backout(void)
+usage_backout(int status)
 {
-	fprintf(stderr, "usage: %s backout [-lX] [commit-id]\n", getprogname());
-	exit(1);
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s backout [-lX] [commit-id]\n", getprogname());
+	exit(status);
 }
 
 static const struct got_error *
@@ -10815,7 +10837,7 @@ cmd_backout(int argc, char *argv[])
 			remove_refs = 1;
 			break;
 		default:
-			usage_backout();
+			usage_backout(1);
 			/* NOTREACHED */
 		}
 	}
@@ -10825,9 +10847,9 @@ cmd_backout(int argc, char *argv[])
 
 	if (list_refs || remove_refs) {
 		if (argc != 0 && argc != 1)
-			usage_backout();
+			usage_backout(1);
 	} else if (argc != 1)
-		usage_backout();
+		usage_backout(1);
 	if (list_refs && remove_refs)
 		option_conflict('l', 'X');
 
@@ -10931,10 +10953,11 @@ done:
 }
 
 __dead static void
-usage_rebase(void)
+usage_rebase(int status)
 {
-	fprintf(stderr, "usage: %s rebase [-aCclX] [branch]\n", getprogname());
-	exit(1);
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s rebase [-aCclX] [branch]\n", getprogname());
+	exit(status);
 }
 
 static void
@@ -11659,7 +11682,7 @@ cmd_rebase(int argc, char *argv[])
 			delete_backups = 1;
 			break;
 		default:
-			usage_rebase();
+			usage_rebase(1);
 			/* NOTREACHED */
 		}
 	}
@@ -11677,7 +11700,7 @@ cmd_rebase(int argc, char *argv[])
 		if (delete_backups)
 			option_conflict('l', 'X');
 		if (argc != 0 && argc != 1)
-			usage_rebase();
+			usage_rebase(1);
 	} else if (delete_backups) {
 		if (abort_rebase)
 			option_conflict('X', 'a');
@@ -11688,7 +11711,7 @@ cmd_rebase(int argc, char *argv[])
 		if (list_backups)
 			option_conflict('l', 'X');
 		if (argc != 0 && argc != 1)
-			usage_rebase();
+			usage_rebase(1);
 	} else if (allow_conflict) {
 		if (abort_rebase)
 			option_conflict('C', 'a');
@@ -11696,12 +11719,12 @@ cmd_rebase(int argc, char *argv[])
 			errx(1, "-C option requires -c");
 	} else {
 		if (abort_rebase && continue_rebase)
-			usage_rebase();
+			usage_rebase(1);
 		else if (abort_rebase || continue_rebase) {
 			if (argc != 0)
-				usage_rebase();
+				usage_rebase(1);
 		} else if (argc != 1)
-			usage_rebase();
+			usage_rebase(1);
 	}
 
 	cwd = getcwd(NULL, 0);
@@ -12084,11 +12107,12 @@ done:
 }
 
 __dead static void
-usage_histedit(void)
+usage_histedit(int status)
 {
-	fprintf(stderr, "usage: %s histedit [-aCcdeflmX] [-F histedit-script] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s histedit [-aCcdeflmX] [-F histedit-script] "
 	    "[branch]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 #define GOT_HISTEDIT_PICK 'p'
@@ -12962,7 +12986,7 @@ cmd_histedit(int argc, char *argv[])
 			delete_backups = 1;
 			break;
 		default:
-			usage_histedit();
+			usage_histedit(1);
 			/* NOTREACHED */
 		}
 	}
@@ -13038,7 +13062,7 @@ cmd_histedit(int argc, char *argv[])
 		if (delete_backups)
 			option_conflict('l', 'X');
 		if (argc != 0 && argc != 1)
-			usage_histedit();
+			usage_histedit(1);
 	} else if (delete_backups) {
 		if (abort_edit)
 			option_conflict('X', 'a');
@@ -13059,11 +13083,11 @@ cmd_histedit(int argc, char *argv[])
 		if (list_backups)
 			option_conflict('X', 'l');
 		if (argc != 0 && argc != 1)
-			usage_histedit();
+			usage_histedit(1);
 	} else if (allow_conflict && !continue_edit)
 		errx(1, "-C option requires -c");
 	else if (argc != 0)
-		usage_histedit();
+		usage_histedit(1);
 
 	cwd = getcwd(NULL, 0);
 	if (cwd == NULL) {
@@ -13526,10 +13550,11 @@ done:
 }
 
 __dead static void
-usage_integrate(void)
+usage_integrate(int status)
 {
-	fprintf(stderr, "usage: %s integrate branch\n", getprogname());
-	exit(1);
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s integrate branch\n", getprogname());
+	exit(status);
 }
 
 static const struct got_error *
@@ -13556,7 +13581,7 @@ cmd_integrate(int argc, char *argv[])
 	while ((ch = getopt(argc, argv, "")) != -1) {
 		switch (ch) {
 		default:
-			usage_integrate();
+			usage_integrate(1);
 			/* NOTREACHED */
 		}
 	}
@@ -13565,7 +13590,7 @@ cmd_integrate(int argc, char *argv[])
 	argv += optind;
 
 	if (argc != 1)
-		usage_integrate();
+		usage_integrate(1);
 	branch_arg = argv[0];
 
 	cwd = getcwd(NULL, 0);
@@ -13692,10 +13717,11 @@ done:
 }
 
 __dead static void
-usage_merge(void)
+usage_merge(int status)
 {
-	fprintf(stderr, "usage: %s merge [-aCcn] [branch]\n", getprogname());
-	exit(1);
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s merge [-aCcn] [branch]\n", getprogname());
+	exit(status);
 }
 
 static const struct got_error *
@@ -13743,7 +13769,7 @@ cmd_merge(int argc, char *argv[])
 			interrupt_merge = 1;
 			break;
 		default:
-			usage_merge();
+			usage_merge(1);
 			/* NOTREACHED */
 		}
 	}
@@ -13770,9 +13796,9 @@ cmd_merge(int argc, char *argv[])
 	}
 	if (abort_merge || continue_merge) {
 		if (argc != 0)
-			usage_merge();
+			usage_merge(1);
 	} else if (argc != 1)
-		usage_merge();
+		usage_merge(1);
 
 	cwd = getcwd(NULL, 0);
 	if (cwd == NULL) {
@@ -14049,11 +14075,12 @@ done:
 }
 
 __dead static void
-usage_stage(void)
+usage_stage(int status)
 {
-	fprintf(stderr, "usage: %s stage [-lpS] [-F response-script] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s stage [-lpS] [-F response-script] "
 	    "[path ...]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -14120,7 +14147,7 @@ cmd_stage(int argc, char *argv[])
 			allow_bad_symlinks = 1;
 			break;
 		default:
-			usage_stage();
+			usage_stage(1);
 			/* NOTREACHED */
 		}
 	}
@@ -14210,11 +14237,12 @@ done:
 }
 
 __dead static void
-usage_unstage(void)
+usage_unstage(int status)
 {
-	fprintf(stderr, "usage: %s unstage [-p] [-F response-script] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s unstage [-p] [-F response-script] "
 	    "[path ...]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 
@@ -14250,7 +14278,7 @@ cmd_unstage(int argc, char *argv[])
 			pflag = 1;
 			break;
 		default:
-			usage_unstage();
+			usage_unstage(1);
 			/* NOTREACHED */
 		}
 	}
@@ -14331,11 +14359,12 @@ done:
 }
 
 __dead static void
-usage_cat(void)
+usage_cat(int status)
 {
-	fprintf(stderr, "usage: %s cat [-P] [-c commit] [-r repository-path] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s cat [-P] [-c commit] [-r repository-path] "
 	    "arg ...\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -14545,7 +14574,7 @@ cmd_cat(int argc, char *argv[])
 			got_path_strip_trailing_slashes(repo_path);
 			break;
 		default:
-			usage_cat();
+			usage_cat(1);
 			/* NOTREACHED */
 		}
 	}
@@ -14700,11 +14729,12 @@ done:
 }
 
 __dead static void
-usage_info(void)
+usage_info(int status)
 {
-	fprintf(stderr, "usage: %s info [path ...]\n",
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s info [path ...]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -14798,7 +14828,7 @@ cmd_info(int argc, char *argv[])
 	while ((ch = getopt(argc, argv, "")) != -1) {
 		switch (ch) {
 		default:
-			usage_info();
+			usage_info(1);
 			/* NOTREACHED */
 		}
 	}
blob - a634d86f4c245b3288c0f76c18f1ccf81d285d62
blob + 5f0e26f25beeb96eb63f446ad8f7fbbd61c7d10c
--- gotadmin/gotadmin.c
+++ gotadmin/gotadmin.c
@@ -78,19 +78,19 @@ check_cancelled(void *arg)
 struct gotadmin_cmd {
 	const char	*cmd_name;
 	const struct got_error *(*cmd_main)(int, char *[]);
-	void		(*cmd_usage)(void);
+	void		(*cmd_usage)(int);
 	const char	*cmd_alias;
 };
 
 __dead static void	usage(int, int);
-__dead static void	usage_init(void);
-__dead static void	usage_info(void);
-__dead static void	usage_pack(void);
-__dead static void	usage_indexpack(void);
-__dead static void	usage_listpack(void);
-__dead static void	usage_cleanup(void);
-__dead static void	usage_dump(void);
-__dead static void	usage_load(void);
+__dead static void	usage_init(int);
+__dead static void	usage_info(int);
+__dead static void	usage_pack(int);
+__dead static void	usage_indexpack(int);
+__dead static void	usage_listpack(int);
+__dead static void	usage_cleanup(int);
+__dead static void	usage_dump(int);
+__dead static void	usage_load(int);
 
 static const struct got_error*		cmd_init(int, char *[]);
 static const struct got_error*		cmd_info(int, char *[]);
@@ -179,7 +179,7 @@ main(int argc, char *argv[])
 			continue;
 
 		if (hflag)
-			cmd->cmd_usage();
+			cmd->cmd_usage(0);
 
 		error = cmd->cmd_main(argc, argv);
 		if (error && error->code != GOT_ERR_CANCELLED &&
@@ -238,11 +238,12 @@ apply_unveil(const char *repo_path, int repo_read_only
 }
 
 __dead static void
-usage_info(void)
+usage_info(int status)
 {
-	fprintf(stderr, "usage: %s info [-r repository-path]\n",
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s info [-r repository-path]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -279,12 +280,13 @@ done:
 }
 
 __dead static void
-usage_init(void)
+usage_init(int status)
 {
-	fprintf(stderr, "usage: %s init [-A hashing-algorithm] [-b branch]"
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s init [-A hashing-algorithm] [-b branch]"
 	    " repository-path\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -316,7 +318,7 @@ cmd_init(int argc, char *argv[])
 			head_name = optarg;
 			break;
 		default:
-			usage_init();
+			usage_init(1);
 			/* NOTREACHED */
 		}
 	}
@@ -325,7 +327,7 @@ cmd_init(int argc, char *argv[])
 	argv += optind;
 
 	if (argc != 1)
-		usage_init();
+		usage_init(1);
 
 	repo_path = strdup(argv[0]);
 	if (repo_path == NULL)
@@ -376,7 +378,7 @@ cmd_info(int argc, char *argv[])
 			got_path_strip_trailing_slashes(repo_path);
 			break;
 		default:
-			usage_info();
+			usage_info(1);
 			/* NOTREACHED */
 		}
 	}
@@ -474,11 +476,12 @@ done:
 }
 
 __dead static void
-usage_pack(void)
+usage_pack(int status)
 {
-	fprintf(stderr, "usage: %s pack [-aDq] [-r repository-path] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s pack [-aDq] [-r repository-path] "
 	    "[-x reference] [reference ...]\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 struct got_pack_progress_arg {
@@ -768,7 +771,7 @@ cmd_pack(int argc, char *argv[])
 				return error;
 			break;
 		default:
-			usage_pack();
+			usage_pack(1);
 			/* NOTREACHED */
 		}
 	}
@@ -873,11 +876,12 @@ done:
 }
 
 __dead static void
-usage_indexpack(void)
+usage_indexpack(int status)
 {
-	fprintf(stderr, "usage: %s indexpack packfile-path\n",
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s indexpack packfile-path\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -896,7 +900,7 @@ cmd_indexpack(int argc, char *argv[])
 	while ((ch = getopt(argc, argv, "")) != -1) {
 		switch (ch) {
 		default:
-			usage_indexpack();
+			usage_indexpack(1);
 			/* NOTREACHED */
 		}
 	}
@@ -905,7 +909,7 @@ cmd_indexpack(int argc, char *argv[])
 	argv += optind;
 
 	if (argc != 1)
-		usage_indexpack();
+		usage_indexpack(1);
 
 	packfile_path = realpath(argv[0], NULL);
 	if (packfile_path == NULL)
@@ -964,11 +968,12 @@ done:
 }
 
 __dead static void
-usage_listpack(void)
+usage_listpack(int status)
 {
-	fprintf(stderr, "usage: %s listpack [-hs] packfile-path\n",
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s listpack [-hs] packfile-path\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 struct gotadmin_list_pack_cb_args {
@@ -1088,7 +1093,7 @@ cmd_listpack(int argc, char *argv[])
 			show_stats = 1;
 			break;
 		default:
-			usage_listpack();
+			usage_listpack(1);
 			/* NOTREACHED */
 		}
 	}
@@ -1097,7 +1102,7 @@ cmd_listpack(int argc, char *argv[])
 	argv += optind;
 
 	if (argc != 1)
-		usage_listpack();
+		usage_listpack(1);
 	packfile_path = realpath(argv[0], NULL);
 	if (packfile_path == NULL)
 		return got_error_from_errno2("realpath", argv[0]);
@@ -1156,11 +1161,12 @@ done:
 }
 
 __dead static void
-usage_cleanup(void)
+usage_cleanup(int status)
 {
-	fprintf(stderr, "usage: %s cleanup [-anpq] [-r repository-path]\n",
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s cleanup [-anpq] [-r repository-path]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 struct got_cleanup_progress_arg {
@@ -1312,7 +1318,7 @@ cmd_cleanup(int argc, char *argv[])
 			got_path_strip_trailing_slashes(repo_path);
 			break;
 		default:
-			usage_cleanup();
+			usage_cleanup(1);
 			/* NOTREACHED */
 		}
 	}
@@ -1423,11 +1429,12 @@ done:
 }
 
 __dead static void
-usage_dump(void)
+usage_dump(int status)
 {
-	fprintf(stderr, "usage: %s dump [-q] [-r repository-path] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s dump [-q] [-r repository-path] "
 	    "[-x reference] [reference]...\n", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -1476,7 +1483,7 @@ cmd_dump(int argc, char *argv[])
 				return error;
 			break;
 		default:
-			usage_dump();
+			usage_dump(1);
 			/* NOTREACHED */
 		}
 	}
@@ -1560,12 +1567,13 @@ cmd_dump(int argc, char *argv[])
 }
 
 __dead static void
-usage_load(void)
+usage_load(int status)
 {
-	fprintf(stderr, "usage: %s load [-nq] [-l bundle-file] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s load [-nq] [-l bundle-file] "
 	    "[-r repository-path] [reference ...]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -1728,7 +1736,7 @@ cmd_load(int argc, char *argv[])
 			got_path_strip_trailing_slashes(repo_path);
 			break;
 		default:
-			usage_load();
+			usage_load(1);
 			/* NOTREACHED */
 		}
 	}
blob - ba3588ddde2c7eb0c059072c4c19bf295c4e9309
blob + 0bf685348b6f10685490b269d97d163329cc757b
--- gotctl/gotctl.c
+++ gotctl/gotctl.c
@@ -57,14 +57,14 @@
 struct gotctl_cmd {
 	const char	*cmd_name;
 	const struct got_error *(*cmd_main)(int, char *[], int);
-	void		(*cmd_usage)(void);
+	void		(*cmd_usage)(int);
 };
 
 __dead static void	usage(int, int);
 
-__dead static void	usage_info(void);
-__dead static void	usage_stop(void);
-__dead static void	usage_reload(void);
+__dead static void	usage_info(int);
+__dead static void	usage_stop(int);
+__dead static void	usage_reload(int);
 
 static const struct got_error*		cmd_info(int, char *[], int);
 static const struct got_error*		cmd_stop(int, char *[], int);
@@ -77,10 +77,11 @@ static const struct gotctl_cmd gotctl_commands[] = {
 };
 
 __dead static void
-usage_info(void)
+usage_info(int status)
 {
-	fprintf(stderr, "usage: %s info\n", getprogname());
-	exit(1);
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s info\n", getprogname());
+	exit(status);
 }
 
 static const struct got_error *
@@ -223,10 +224,11 @@ cmd_info(int argc, char *argv[], int gotd_sock)
 }
 
 __dead static void
-usage_stop(void)
+usage_stop(int status)
 {
-	fprintf(stderr, "usage: %s stop\n", getprogname());
-	exit(1);
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s stop\n", getprogname());
+	exit(status);
 }
 
 static const struct got_error *
@@ -276,11 +278,12 @@ cmd_stop(int argc, char *argv[], int gotd_sock)
 }
 
 __dead static void
-usage_reload(void)
+usage_reload(int status)
 {
-	fprintf(stderr, "usage: %s reload [-c config-file] [-s secrets]\n",
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s reload [-c config-file] [-s secrets]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -353,7 +356,7 @@ cmd_reload(int argc, char *argv[], int gotd_sock)
 			}
 			break;
 		default:
-			usage_reload();
+			usage_reload(1);
 			/* NOTREACHED */
 		}
 	}
@@ -633,7 +636,7 @@ main(int argc, char *argv[])
 			continue;
 
 		if (hflag)
-			cmd->cmd_usage();
+			cmd->cmd_usage(0);
 #ifdef PROFILE
 		if (unveil("gmon.out", "rwc") != 0)
 			err(1, "unveil", "gmon.out");
blob - 584ac4aa540ecb67f99cf1c3451ceab525de382e
blob + e984d13834daccca804ab945569fb2bd305b85c4
--- gotsys/gotsys.c
+++ gotsys/gotsys.c
@@ -53,13 +53,13 @@
 struct gotsys_cmd {
 	const char	*cmd_name;
 	const struct got_error *(*cmd_main)(int, char *[]);
-	void		(*cmd_usage)(void);
+	void		(*cmd_usage)(int);
 };
 
 __dead static void	usage(int, int);
 
-__dead static void	usage_apply(void);
-__dead static void	usage_check(void);
+__dead static void	usage_apply(int);
+__dead static void	usage_check(int);
 
 static const struct got_error*		cmd_apply(int, char *[]);
 static const struct got_error*		cmd_check(int, char *[]);
@@ -161,11 +161,12 @@ done:
 
 
 __dead static void
-usage_apply(void)
+usage_apply(int status)
 {
-	fprintf(stderr, "usage: %s apply [-f socket] [-r repository] "
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s apply [-f socket] [-r repository] "
 	    "[-c commit] [-w] [filename]", getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -260,7 +261,7 @@ cmd_apply(int argc, char *argv[])
 			wait = 1;
 			break;
 		default:
-			usage_apply();
+			usage_apply(1);
 			/* NOTREACHED */
 			break;
 		}
@@ -270,7 +271,7 @@ cmd_apply(int argc, char *argv[])
 	argv += optind;
 
 	if (argc > 1)
-		usage_apply();
+		usage_apply(1);
 
 	filename = (argc == 1 ? argv[0] : GOTSYSD_SYSCONF_FILENAME);
 
@@ -442,10 +443,11 @@ done:
 }
 
 __dead static void
-usage_check(void)
+usage_check(int status)
 {
-	fprintf(stderr, "usage: %s check [-q] [-f file]\n", getprogname());
-	exit(1);
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s check [-q] [-f file]\n", getprogname());
+	exit(status);
 }
 
 static const struct got_error *
@@ -510,7 +512,7 @@ cmd_check(int argc, char *argv[])
 			got_path_strip_trailing_slashes(configfile);
 			break;
 		default:
-			usage_check();
+			usage_check(1);
 			/* NOTREACHED */
 			break;
 		}
@@ -519,7 +521,7 @@ cmd_check(int argc, char *argv[])
 	argv += optind;
 
 	if (argc > 0)
-		usage_check();
+		usage_check(1);
 
 	if (fd != STDIN_FILENO && configfile == NULL) {
 		configfile = strdup(GOTSYSD_SYSCONF_FILENAME);
@@ -658,7 +660,7 @@ main(int argc, char *argv[])
 			continue;
 
 		if (hflag)
-			cmd->cmd_usage();
+			cmd->cmd_usage(0);
 
 		error = cmd->cmd_main(argc, argv);
 		if (error) {
blob - 3a0aa6a460994a7fa1dd97daa92a164a566c0b16
blob + 976250e45de2e8df2fa667f58fc4ef47644b45db
--- gotsysctl/gotsysctl.c
+++ gotsysctl/gotsysctl.c
@@ -61,12 +61,12 @@ catch_sigint(int signo)
 struct gotsysctl_cmd {
 	const char	*cmd_name;
 	const struct got_error *(*cmd_main)(int, char *[], int);
-	void		(*cmd_usage)(void);
+	void		(*cmd_usage)(int);
 };
 
 __dead static void	usage(int, int);
 
-__dead static void	usage_info(void);
+__dead static void	usage_info(int);
 
 static const struct got_error*		cmd_info(int, char *[], int);
 
@@ -75,10 +75,11 @@ static const struct gotsysctl_cmd gotsysctl_commands[]
 };
 
 __dead static void
-usage_info(void)
+usage_info(int status)
 {
-	fprintf(stderr, "usage: %s info\n", getprogname());
-	exit(1);
+	FILE *fp = (status == 0) ? stdout : stderr;
+	fprintf(fp, "usage: %s info\n", getprogname());
+	exit(status);
 }
 
 static const struct got_error *
@@ -286,7 +287,7 @@ main(int argc, char *argv[])
 			continue;
 
 		if (hflag)
-			cmd->cmd_usage();
+			cmd->cmd_usage(0);
 
 		gotsysd_sock = connect_gotsysd(socket_path);
 		if (gotsysd_sock == -1)
blob - 44b2d7f8b746631a2dcc8691478e5b582881c5e3
blob + d3ec8991a224394ba68fc8cf5feb7f2fabeae71b
--- tog/tog.c
+++ tog/tog.c
@@ -78,15 +78,15 @@
 struct tog_cmd {
 	const char *name;
 	const struct got_error *(*cmd_main)(int, char *[]);
-	void (*cmd_usage)(void);
+	void (*cmd_usage)(int);
 };
 
 __dead static void	usage(int, int);
-__dead static void	usage_log(void);
-__dead static void	usage_diff(void);
-__dead static void	usage_blame(void);
-__dead static void	usage_tree(void);
-__dead static void	usage_ref(void);
+__dead static void	usage_log(int);
+__dead static void	usage_diff(int);
+__dead static void	usage_blame(int);
+__dead static void	usage_tree(int);
+__dead static void	usage_ref(int);
 
 static const struct got_error*	cmd_log(int, char *[]);
 static const struct got_error*	cmd_diff(int, char *[]);
@@ -2241,13 +2241,14 @@ done:
 }
 
 __dead static void
-usage_log(void)
+usage_log(int status)
 {
+	FILE *fp = (status == 0) ? stdout : stderr;
 	endwin();
-	fprintf(stderr,
+	fprintf(fp,
 	    "usage: %s log [-b] [-c commit] [-r repository-path] [path]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 /* Create newly allocated wide-character string equivalent to a byte string. */
@@ -5287,7 +5288,7 @@ cmd_log(int argc, char *argv[])
 				    optarg);
 			break;
 		default:
-			usage_log();
+			usage_log(1);
 			/* NOTREACHED */
 		}
 	}
@@ -5296,7 +5297,7 @@ cmd_log(int argc, char *argv[])
 	argv += optind;
 
 	if (argc > 1)
-		usage_log();
+		usage_log(1);
 
 	error = got_repo_pack_fds_open(&pack_fds);
 	if (error != NULL)
@@ -5423,13 +5424,14 @@ done:
 }
 
 __dead static void
-usage_diff(void)
+usage_diff(int status)
 {
+	FILE *fp = (status == 0) ? stdout : stderr;
 	endwin();
-	fprintf(stderr, "usage: %s diff [-asw] [-C number] [-c commit] "
+	fprintf(fp, "usage: %s diff [-asw] [-C number] [-c commit] "
 	    "[-r repository-path] [object1 object2 | path ...]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static int
@@ -7500,7 +7502,7 @@ cmd_diff(int argc, char *argv[])
 			ignore_whitespace = 1;
 			break;
 		default:
-			usage_diff();
+			usage_diff(1);
 			/* NOTREACHED */
 		}
 	}
@@ -7790,13 +7792,14 @@ done:
 }
 
 __dead static void
-usage_blame(void)
+usage_blame(int status)
 {
+	FILE *fp = (status == 0) ? stdout : stderr;
 	endwin();
-	fprintf(stderr,
+	fprintf(fp,
 	    "usage: %s blame [-c commit] [-r repository-path] path\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 struct tog_blame_line {
@@ -8811,7 +8814,7 @@ cmd_blame(int argc, char *argv[])
 				    optarg);
 			break;
 		default:
-			usage_blame();
+			usage_blame(1);
 			/* NOTREACHED */
 		}
 	}
@@ -8820,7 +8823,7 @@ cmd_blame(int argc, char *argv[])
 	argv += optind;
 
 	if (argc != 1)
-		usage_blame();
+		usage_blame(1);
 
 	error = got_repo_pack_fds_open(&pack_fds);
 	if (error != NULL)
@@ -9770,13 +9773,14 @@ input_tree_view(struct tog_view **new_view, struct tog
 }
 
 __dead static void
-usage_tree(void)
+usage_tree(int status)
 {
+	FILE *fp = (status == 0) ? stdout : stderr;
 	endwin();
-	fprintf(stderr,
+	fprintf(fp,
 	    "usage: %s tree [-c commit] [-r repository-path] [path]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -9808,7 +9812,7 @@ cmd_tree(int argc, char *argv[])
 				    optarg);
 			break;
 		default:
-			usage_tree();
+			usage_tree(1);
 			/* NOTREACHED */
 		}
 	}
@@ -9817,7 +9821,7 @@ cmd_tree(int argc, char *argv[])
 	argv += optind;
 
 	if (argc > 1)
-		usage_tree();
+		usage_tree(1);
 
 	error = got_repo_pack_fds_open(&pack_fds);
 	if (error != NULL)
@@ -10675,12 +10679,13 @@ input_ref_view(struct tog_view **new_view, struct tog_
 }
 
 __dead static void
-usage_ref(void)
+usage_ref(int status)
 {
+	FILE *fp = (status == 0) ? stdout : stderr;
 	endwin();
-	fprintf(stderr, "usage: %s ref [-r repository-path]\n",
+	fprintf(fp, "usage: %s ref [-r repository-path]\n",
 	    getprogname());
-	exit(1);
+	exit(status);
 }
 
 static const struct got_error *
@@ -10703,7 +10708,7 @@ cmd_ref(int argc, char *argv[])
 				    optarg);
 			break;
 		default:
-			usage_ref();
+			usage_ref(1);
 			/* NOTREACHED */
 		}
 	}
@@ -10712,7 +10717,7 @@ cmd_ref(int argc, char *argv[])
 	argv += optind;
 
 	if (argc > 1)
-		usage_ref();
+		usage_ref(1);
 
 	error = got_repo_pack_fds_open(&pack_fds);
 	if (error != NULL)
@@ -11764,7 +11769,7 @@ main(int argc, char *argv[])
 		error = tog_log_with_path(argc, argv);
 	} else {
 		if (hflag)
-			cmd->cmd_usage();
+			cmd->cmd_usage(0);
 		else
 			error = cmd->cmd_main(argc, cmd_argv ? cmd_argv : argv);
 	}