From: Owen Taylor <otaylor@redhat.com>
To: git@vger.kernel.org
Cc: "Owen W. Taylor" <otaylor@fishsoup.net>
Subject: [PATCH 3/4] push: add --show-subjects option to show commit synopsis
Date: Sun, 13 Sep 2009 19:31:24 -0400 [thread overview]
Message-ID: <1252884685-9169-4-git-send-email-otaylor@redhat.com> (raw)
In-Reply-To: <1252884685-9169-3-git-send-email-otaylor@redhat.com>
From: Owen W. Taylor <otaylor@fishsoup.net>
When --show-subjects is specified, include a synopsis of added
and removed with each OK or REJECT_NONFASTFORWARD reference update.
(The code for printing the synposis is borrowed and adapted from
builtin-fmt-merge-msg.c)
Signed-off-by: Owen W. Taylor <otaylor@fishsoup.net>
---
Documentation/git-push.txt | 4 +
builtin-push.c | 3 +-
transport.c | 174 +++++++++++++++++++++++++++++++++++++++++---
transport.h | 1 +
4 files changed, 171 insertions(+), 11 deletions(-)
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index c0bbf16..c9fd033 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -142,6 +142,10 @@ useful if you write an alias or script around 'git-push'.
--verbose::
Run verbosely.
+--show-subjects::
+ When displaying ref updates, include a synopsis of what
+ commits are being added and removed.
+
include::urls-remotes.txt[]
OUTPUT
diff --git a/builtin-push.c b/builtin-push.c
index 63a0bb0..7c9e394 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] [--confirm] [--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] [--show-subjects] [<repository> <refspec>...]",
NULL,
};
@@ -177,6 +177,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_BIT('q', "quiet", &flags, "be quiet", TRANSPORT_PUSH_QUIET),
OPT_BIT('v', "verbose", &flags, "be verbose", TRANSPORT_PUSH_VERBOSE),
+ OPT_BIT(0, "show-subjects", &flags, "show commit subjects", TRANSPORT_PUSH_SHOW_SUBJECTS),
OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),
OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
diff --git a/transport.c b/transport.c
index aa1852d..c07291e 100644
--- a/transport.c
+++ b/transport.c
@@ -1,4 +1,6 @@
#include "cache.h"
+#include "commit.h"
+#include "diff.h"
#include "transport.h"
#include "run-command.h"
#include "pkt-line.h"
@@ -8,6 +10,7 @@
#include "bundle.h"
#include "dir.h"
#include "refs.h"
+#include "revision.h"
/* rsync support */
@@ -619,7 +622,151 @@ static const char *status_abbrev(unsigned char sha1[20])
return find_unique_abbrev(sha1, DEFAULT_ABBREV);
}
-static void print_ok_ref_status(struct ref *ref, int porcelain)
+struct list {
+ char **list;
+ unsigned nr, alloc;
+};
+
+static void append_to_list(struct list *list, char *value)
+{
+ if (list->nr == list->alloc) {
+ list->alloc += 32;
+ list->list = xrealloc(list->list, sizeof(char *) * list->alloc);
+ }
+ list->list[list->nr++] = value;
+}
+
+static void free_list(struct list *list)
+{
+ int i;
+
+ if (list->alloc == 0)
+ return;
+
+ for (i = 0; i < list->nr; i++) {
+ free(list->list[i]);
+ }
+ free(list->list);
+ list->nr = list->alloc = 0;
+}
+
+static void shortlog(struct commit *from, struct commit *to,
+ const char *heading, int limit)
+{
+ struct rev_info rev;
+ int i, count = 0;
+ struct commit *commit;
+ struct list subjects = { NULL, 0, 0 };
+ int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
+ const char *prefix;
+
+ init_revisions(&rev, NULL);
+ rev.commit_format = CMIT_FMT_ONELINE;
+ rev.limited = 1;
+ rev.ignore_merges = 0;
+
+ setup_revisions(0, NULL, &rev, NULL);
+
+ add_pending_object(&rev, &from->object, "");
+ add_pending_object(&rev, &to->object, "");
+ from->object.flags |= UNINTERESTING;
+ if (prepare_revision_walk(&rev))
+ die("revision walk setup failed");
+ while ((commit = get_revision(&rev)) != NULL) {
+ char *oneline, *bol, *eol;
+
+ count++;
+ if (subjects.nr > limit)
+ continue;
+
+ bol = strstr(commit->buffer, "\n\n");
+ if (bol) {
+ unsigned char c;
+ do {
+ c = *++bol;
+ } while (isspace(c));
+ if (!c)
+ bol = NULL;
+ }
+
+ if (!bol) {
+ append_to_list(&subjects, xstrdup(sha1_to_hex(commit->object.sha1)));
+ continue;
+ }
+
+ eol = strchr(bol, '\n');
+ if (eol) {
+ oneline = xmemdupz(bol, eol - bol);
+ } else {
+ oneline = xstrdup(bol);
+ }
+ append_to_list(&subjects, oneline);
+ }
+
+ if (heading || count > limit) {
+ fprintf(stderr, " ");
+ if (heading)
+ fprintf(stderr, "%s", heading);
+ if (heading && count > limit)
+ fprintf(stderr, " (%d)", count);
+ else if (count > limit)
+ fprintf(stderr, "%d commits", count);
+ fprintf(stderr, ":\n");
+ prefix = " ";
+ } else {
+ prefix = " ";
+ }
+
+ for (i = 0; i < count && i < limit; i++)
+ if (i == limit - 1 && count > limit)
+ fprintf(stderr, "%s...\n", prefix);
+ else
+ fprintf(stderr, "%s%s\n", prefix, subjects.list[i]);
+
+ clear_commit_marks(from, flags);
+ clear_commit_marks(to, flags);
+ free_commit_list(rev.commits);
+ rev.commits = NULL;
+ rev.pending.nr = 0;
+
+ free_list(&subjects);
+}
+
+/* Maximum lines number of subjects to show (including ...) */
+#define SUBJECTS_LIMIT 8
+
+static void print_subjects(struct ref *ref)
+{
+ struct commit *old;
+ struct commit *new;
+ struct commit_list *merge_bases;
+ int added = 1;
+ int removed = 1;
+
+ old = lookup_commit_reference_gently(ref->old_sha1, 1);
+ if (!old) {
+ fprintf(stderr, " Unknown changes (please run 'git fetch')\n");
+ return;
+ }
+ new = lookup_commit_reference(ref->new_sha1);
+
+ merge_bases = get_merge_bases(old, new, 1);
+ if (merge_bases && !merge_bases->next && merge_bases->item == old)
+ removed = 0;
+ if (merge_bases && !merge_bases->next && merge_bases->item == new)
+ added = 0;
+
+ if (added && !removed) {
+ shortlog(old, new, NULL, SUBJECTS_LIMIT);
+ } else {
+ if (added)
+ shortlog(old, new, "Added commits", SUBJECTS_LIMIT);
+ if (removed)
+ shortlog(new, old, "Removed commits", SUBJECTS_LIMIT);
+ }
+}
+
+static void print_ok_ref_status(struct ref *ref, int porcelain, int show_subjects)
{
if (ref->deletion)
print_ref_status('-', "[deleted]", ref, NULL, NULL, porcelain);
@@ -646,10 +793,13 @@ static void print_ok_ref_status(struct ref *ref, int porcelain)
strcat(quickref, status_abbrev(ref->new_sha1));
print_ref_status(type, quickref, ref, ref->peer_ref, msg, porcelain);
+
+ if (show_subjects)
+ print_subjects(ref);
}
}
-static int print_one_push_status(struct ref *ref, const char *dest, int count, int porcelain)
+static int print_one_push_status(struct ref *ref, const char *dest, int count, int show_subjects, int porcelain)
{
if (!count)
fprintf(stderr, "To %s\n", dest);
@@ -669,6 +819,8 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
case REF_STATUS_REJECT_NONFASTFORWARD:
print_ref_status('!', "[rejected]", ref, ref->peer_ref,
"non-fast forward", porcelain);
+ if (show_subjects)
+ print_subjects(ref);
break;
case REF_STATUS_REMOTE_REJECT:
print_ref_status('!', "[remote rejected]", ref,
@@ -681,7 +833,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
"remote failed to report status", porcelain);
break;
case REF_STATUS_OK:
- print_ok_ref_status(ref, porcelain);
+ print_ok_ref_status(ref, porcelain, show_subjects);
break;
}
@@ -689,7 +841,7 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
}
static void print_push_status(const char *dest, struct ref *refs,
- int verbose, int porcelain, int * nonfastforward)
+ int verbose, int show_subjects, int porcelain, int * nonfastforward)
{
struct ref *ref;
int n = 0;
@@ -697,19 +849,19 @@ static void print_push_status(const char *dest, struct ref *refs,
if (verbose) {
for (ref = refs; ref; ref = ref->next)
if (ref->status == REF_STATUS_UPTODATE)
- n += print_one_push_status(ref, dest, n, porcelain);
+ n += print_one_push_status(ref, dest, n, show_subjects, porcelain);
}
for (ref = refs; ref; ref = ref->next)
if (ref->status == REF_STATUS_OK)
- n += print_one_push_status(ref, dest, n, porcelain);
+ n += print_one_push_status(ref, dest, n, show_subjects, porcelain);
*nonfastforward = 0;
for (ref = refs; ref; ref = ref->next) {
if (ref->status != REF_STATUS_NONE &&
ref->status != REF_STATUS_UPTODATE &&
ref->status != REF_STATUS_OK)
- n += print_one_push_status(ref, dest, n, porcelain);
+ n += print_one_push_status(ref, dest, n, show_subjects, porcelain);
if (ref->status == REF_STATUS_REJECT_NONFASTFORWARD)
*nonfastforward = 1;
}
@@ -912,6 +1064,7 @@ int transport_push(struct transport *transport,
int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
int dry_run = flags & TRANSPORT_PUSH_DRY_RUN;
int confirm = flags & TRANSPORT_PUSH_CONFIRM;
+ int show_subjects = flags & TRANSPORT_PUSH_SHOW_SUBJECTS;
int ret;
if (flags & TRANSPORT_PUSH_ALL)
@@ -942,7 +1095,7 @@ int transport_push(struct transport *transport,
* confirmed, send the porcelain-formatted output to stdout.
*/
print_push_status(transport->url, remote_refs,
- verbose, 0,
+ verbose, show_subjects, 0,
nonfastforward);
if (ret)
@@ -970,8 +1123,9 @@ int transport_push(struct transport *transport,
*/
if (!(quiet || (confirm && !porcelain)) || push_had_errors(remote_refs))
print_push_status(transport->url, remote_refs,
- verbose | porcelain, porcelain,
- nonfastforward);
+ verbose | porcelain,
+ show_subjects && !confirm && !porcelain,
+ porcelain, nonfastforward);
if (!dry_run) {
struct ref *ref;
diff --git a/transport.h b/transport.h
index 1d691d7..6a002a3 100644
--- a/transport.h
+++ b/transport.h
@@ -38,6 +38,7 @@ struct transport {
#define TRANSPORT_PUSH_PORCELAIN 32
#define TRANSPORT_PUSH_QUIET 64
#define TRANSPORT_PUSH_CONFIRM 128
+#define TRANSPORT_PUSH_SHOW_SUBJECTS 256
/* Returns a transport suitable for the url */
struct transport *transport_get(struct remote *, const char *);
--
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 ` [PATCH 1/4] push: add --confirm option to ask before sending updates Owen Taylor
2009-09-13 23:31 ` [PATCH 2/4] push: allow configuring default for --confirm Owen Taylor
2009-09-13 23:31 ` Owen Taylor [this message]
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-4-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).