From: Owen Taylor <otaylor@redhat.com>
To: git@vger.kernel.org
Cc: "Owen W. Taylor" <otaylor@fishsoup.net>
Subject: [PATCH 1/4] push: add --confirm option to ask before sending updates
Date: Sun, 13 Sep 2009 19:31:22 -0400 [thread overview]
Message-ID: <1252884685-9169-2-git-send-email-otaylor@redhat.com> (raw)
In-Reply-To: <1252884685-9169-1-git-send-email-otaylor@redhat.com>
From: Owen W. Taylor <otaylor@fishsoup.net>
When --confirm is specified, the refs being updated are displayed
to the user first, and the user is prompted whether to proceed
or not.
Signed-off-by: Owen W. Taylor <otaylor@fishsoup.net>
---
Documentation/git-push.txt | 9 ++++-
builtin-push.c | 8 +++--
builtin-send-pack.c | 4 ++-
send-pack.h | 3 +-
transport.c | 87 ++++++++++++++++++++++++++++++++++++++++----
transport.h | 3 +-
6 files changed, 98 insertions(+), 16 deletions(-)
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 58d2bd5..c0bbf16 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -9,8 +9,9 @@ git-push - Update remote refs along with associated objects
SYNOPSIS
--------
[verse]
-'git push' [--all | --mirror | --tags] [--dry-run] [--receive-pack=<git-receive-pack>]
- [--repo=<repository>] [-f | --force] [-v | --verbose]
+'git push' [--all | --mirror | --tags] [--dry-run] [--confirm]
+ [--receive-pack=<git-receive-pack>] [--repo=<repository>]
+ [-f | --force] [-v | --verbose]
[<repository> <refspec>...]
DESCRIPTION
@@ -85,6 +86,10 @@ nor in any Push line of the corresponding remotes file---see below).
--dry-run::
Do everything except actually send the updates.
+--confirm::
+ Print a summary of what will be done, and then ask the user
+ interactively before actually sending the updates.
+
--porcelain::
Produce machine-readable output. The output status line for each ref
will be tab-separated and sent to stdout instead of stderr. The full
diff --git a/builtin-push.c b/builtin-push.c
index 6eda372..231be5d 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -10,7 +10,7 @@
#include "parse-options.h"
static const char * const push_usage[] = {
- "git push [--all | --mirror] [--dry-run] [--porcelain] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
+ "git push [--all | --mirror] [--dry-run] [--confirm] [--porcelain] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
NULL,
};
@@ -141,6 +141,7 @@ static int do_push(const char *repo, int flags)
transport_get(remote, url[i]);
int err;
int nonfastforward;
+ int disconfirmed;
if (receivepack)
transport_set_option(transport,
TRANS_OPT_RECEIVEPACK, receivepack);
@@ -150,10 +151,10 @@ static int do_push(const char *repo, int flags)
if (flags & TRANSPORT_PUSH_VERBOSE)
fprintf(stderr, "Pushing to %s\n", url[i]);
err = transport_push(transport, refspec_nr, refspec, flags,
- &nonfastforward);
+ &nonfastforward, &disconfirmed);
err |= transport_disconnect(transport);
- if (!err)
+ if (!err || disconfirmed)
continue;
error("failed to push some refs to '%s'", url[i]);
@@ -182,6 +183,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
(TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
OPT_BOOLEAN( 0 , "tags", &tags, "push tags"),
+ OPT_BIT( 0 , "confirm", &flags, "ask before pushing", TRANSPORT_PUSH_CONFIRM),
OPT_BIT( 0 , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
OPT_BIT( 0, "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN),
OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
diff --git a/builtin-send-pack.c b/builtin-send-pack.c
index 37e528e..0264180 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -406,7 +406,9 @@ int send_pack(struct send_pack_args *args,
REF_STATUS_OK;
}
- packet_flush(out);
+ /* Don't flush until the second pass of 'git push --confirm' */
+ if (!(args->dry_run && args->confirm))
+ packet_flush(out);
if (new_refs && !args->dry_run) {
if (pack_objects(out, remote_refs, extra_have, args) < 0) {
for (ref = remote_refs; ref; ref = ref->next)
diff --git a/send-pack.h b/send-pack.h
index 8b3cf02..f2b9292 100644
--- a/send-pack.h
+++ b/send-pack.h
@@ -8,7 +8,8 @@ struct send_pack_args {
force_update:1,
use_thin_pack:1,
use_ofs_delta:1,
- dry_run:1;
+ dry_run:1,
+ confirm:1;
};
int send_pack(struct send_pack_args *args,
diff --git a/transport.c b/transport.c
index 4cb8077..aa1852d 100644
--- a/transport.c
+++ b/transport.c
@@ -766,14 +766,18 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
args.verbose = !!(flags & TRANSPORT_PUSH_VERBOSE);
args.quiet = !!(flags & TRANSPORT_PUSH_QUIET);
args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
+ args.confirm = !!(flags & TRANSPORT_PUSH_CONFIRM);
ret = send_pack(&args, data->fd, data->conn, remote_refs,
&data->extra_have);
- close(data->fd[1]);
- close(data->fd[0]);
- ret |= finish_connect(data->conn);
- data->conn = NULL;
+ /* On the first dry-run pass of --confirm, we need to leave the connection open */
+ if (!((flags & TRANSPORT_PUSH_CONFIRM) && (flags & TRANSPORT_PUSH_DRY_RUN))) {
+ close(data->fd[1]);
+ close(data->fd[0]);
+ ret |= finish_connect(data->conn);
+ data->conn = NULL;
+ }
return ret;
}
@@ -867,14 +871,37 @@ int transport_set_option(struct transport *transport,
return 1;
}
+static int prompt_yesno(const char *prompt)
+{
+ while (1) {
+ char buf[128];
+
+ fprintf(stderr, prompt);
+ if (!fgets(buf, sizeof(buf), stdin))
+ return 0;
+ if (buf[0] == 'y' || buf[0] == 'Y')
+ return 1;
+ else if (buf[0] == 'n' || buf[0] == 'N')
+ return 0;
+ }
+}
+
int transport_push(struct transport *transport,
int refspec_nr, const char **refspec, int flags,
- int * nonfastforward)
+ int * nonfastforward, int * disconfirmed)
{
+ *disconfirmed = 0;
+
verify_remote_names(refspec_nr, refspec);
- if (transport->push)
+ if (transport->push) {
+ if (flags & TRANSPORT_PUSH_CONFIRM) {
+ fprintf(stderr, "--confirm cannot be used with remote URL %s\n", transport->url);
+ return -1;
+ }
+
return transport->push(transport, refspec_nr, refspec, flags);
+ }
if (transport->push_refs) {
struct ref *remote_refs =
transport->get_refs_list(transport, 1);
@@ -883,6 +910,8 @@ int transport_push(struct transport *transport,
int verbose = flags & TRANSPORT_PUSH_VERBOSE;
int quiet = flags & TRANSPORT_PUSH_QUIET;
int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
+ int dry_run = flags & TRANSPORT_PUSH_DRY_RUN;
+ int confirm = flags & TRANSPORT_PUSH_CONFIRM;
int ret;
if (flags & TRANSPORT_PUSH_ALL)
@@ -895,14 +924,56 @@ int transport_push(struct transport *transport,
return -1;
}
+ /* --confirm is a no-op when --dry-run is also specified */
+ if (confirm && (dry_run || !isatty(0))) {
+ confirm = 0;
+ flags &= ~TRANSPORT_PUSH_CONFIRM;
+ }
+
+ if (confirm) {
+ struct ref *ref;
+ int proceed = 0;
+
+ ret = transport->push_refs(transport, remote_refs,
+ flags | TRANSPORT_PUSH_DRY_RUN);
+
+ /* Interaction with --porcelain: we do the first pass interactively
+ * to stderr with normal formatting, and then once the user has
+ * confirmed, send the porcelain-formatted output to stdout.
+ */
+ print_push_status(transport->url, remote_refs,
+ verbose, 0,
+ nonfastforward);
+
+ if (ret)
+ return ret;
+
+ if (!refs_pushed(remote_refs)) {
+ fprintf(stderr, "Everything up-to-date\n");
+ return 0;
+ }
+
+ proceed = prompt_yesno("Proceed [y/n]? ");
+ if (!proceed) {
+ *disconfirmed = 1;
+ return -1;
+ }
+
+ for (ref = remote_refs; ref; ref = ref->next)
+ ref->status = REF_STATUS_NONE;
+ }
+
ret = transport->push_refs(transport, remote_refs, flags);
- if (!quiet || push_had_errors(remote_refs))
+ /* For --confirm, we don't need to print the details again unless
+ * something unexpected happened (denyNonFastforwards=true perhaps)
+ */
+ if (!(quiet || (confirm && !porcelain)) || push_had_errors(remote_refs))
print_push_status(transport->url, remote_refs,
verbose | porcelain, porcelain,
nonfastforward);
- if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
+ if (!dry_run) {
struct ref *ref;
for (ref = remote_refs; ref; ref = ref->next)
update_tracking_ref(transport->remote, ref, verbose);
diff --git a/transport.h b/transport.h
index c14da6f..1d691d7 100644
--- a/transport.h
+++ b/transport.h
@@ -37,6 +37,7 @@ struct transport {
#define TRANSPORT_PUSH_VERBOSE 16
#define TRANSPORT_PUSH_PORCELAIN 32
#define TRANSPORT_PUSH_QUIET 64
+#define TRANSPORT_PUSH_CONFIRM 128
/* Returns a transport suitable for the url */
struct transport *transport_get(struct remote *, const char *);
@@ -70,7 +71,7 @@ int transport_set_option(struct transport *transport, const char *name,
int transport_push(struct transport *connection,
int refspec_nr, const char **refspec, int flags,
- int * nonfastforward);
+ int * nonfastforward, int * disconfirmed);
const struct ref *transport_get_remote_refs(struct transport *transport);
--
1.6.2.5
next prev parent reply other threads:[~2009-09-13 23:31 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-09-13 23:31 Patches for git-push --confirm and --show-subjects Owen Taylor
2009-09-13 23:31 ` Owen Taylor [this message]
2009-09-13 23:31 ` [PATCH 2/4] push: allow configuring default for --confirm Owen Taylor
2009-09-13 23:31 ` [PATCH 3/4] push: add --show-subjects option to show commit synopsis Owen Taylor
2009-09-13 23:31 ` [PATCH 4/4] push: allow configuring default for --show-subjects Owen Taylor
2009-09-14 0:47 ` Patches for git-push --confirm and --show-subjects Junio C Hamano
2009-09-14 0:53 ` Junio C Hamano
2009-09-14 2:35 ` Owen Taylor
2009-09-14 22:21 ` Daniel Barkalow
2009-09-14 23:18 ` Owen Taylor
2009-09-15 0:46 ` Junio C Hamano
2009-09-15 2:38 ` Owen Taylor
2009-09-15 5:50 ` Junio C Hamano
2009-09-15 11:50 ` Owen Taylor
2009-09-15 0:55 ` Daniel Barkalow
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1252884685-9169-2-git-send-email-otaylor@redhat.com \
--to=otaylor@redhat.com \
--cc=git@vger.kernel.org \
--cc=otaylor@fishsoup.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).