builtin-log.c 4.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*
 * Builtin "git log" and related commands (show, whatchanged)
 *
 * (C) Copyright 2006 Linus Torvalds
 *		 2006 Junio Hamano
 */
#include "cache.h"
#include "commit.h"
#include "diff.h"
#include "revision.h"
#include "log-tree.h"
12
#include "builtin.h"
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70

static int cmd_log_wc(int argc, const char **argv, char **envp,
		      struct rev_info *rev)
{
	struct commit *commit;

	rev->abbrev = DEFAULT_ABBREV;
	rev->commit_format = CMIT_FMT_DEFAULT;
	rev->verbose_header = 1;
	argc = setup_revisions(argc, argv, rev, "HEAD");

	if (argc > 1)
		die("unrecognized argument: %s", argv[1]);

	prepare_revision_walk(rev);
	setup_pager();
	while ((commit = get_revision(rev)) != NULL) {
		log_tree_commit(rev, commit);
		free(commit->buffer);
		commit->buffer = NULL;
	}
	return 0;
}

int cmd_whatchanged(int argc, const char **argv, char **envp)
{
	struct rev_info rev;

	init_revisions(&rev);
	rev.diff = 1;
	rev.diffopt.recursive = 1;
	return cmd_log_wc(argc, argv, envp, &rev);
}

int cmd_show(int argc, const char **argv, char **envp)
{
	struct rev_info rev;

	init_revisions(&rev);
	rev.diff = 1;
	rev.diffopt.recursive = 1;
	rev.combine_merges = 1;
	rev.dense_combined_merges = 1;
	rev.always_show_header = 1;
	rev.ignore_merges = 0;
	rev.no_walk = 1;
	return cmd_log_wc(argc, argv, envp, &rev);
}

int cmd_log(int argc, const char **argv, char **envp)
{
	struct rev_info rev;

	init_revisions(&rev);
	rev.always_show_header = 1;
	rev.diffopt.recursive = 1;
	return cmd_log_wc(argc, argv, envp, &rev);
}
71

72 73 74 75 76 77
static int istitlechar(char c)
{
	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
		(c >= '0' && c <= '9') || c == '.' || c == '_';
}

78
static FILE *realstdout = NULL;
79
static char *output_directory = NULL;
80

81 82 83 84
static void reopen_stdout(struct commit *commit, int nr)
{
	char filename[1024];
	char *sol;
85
	int len = 0;
86

87 88 89 90 91 92
	if (output_directory) {
		strncpy(filename, output_directory, 1010);
		len = strlen(filename);
		if (filename[len - 1] != '/')
			filename[len++] = '/';
	}
93

94
	sprintf(filename + len, "%04d", nr);
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
	len = strlen(filename);

	sol = strstr(commit->buffer, "\n\n");
	if (sol) {
		int j, space = 1;

		sol += 2;
		/* strip [PATCH] or [PATCH blabla] */
		if (!strncmp(sol, "[PATCH", 6)) {
			char *eos = strchr(sol + 6, ']');
			if (eos) {
				while (isspace(*eos))
					eos++;
				sol = eos;
			}
		}

		for (j = 0; len < 1024 - 6 && sol[j] && sol[j] != '\n'; j++) {
			if (istitlechar(sol[j])) {
				if (space) {
					filename[len++] = '-';
					space = 0;
				}
				filename[len++] = sol[j];
				if (sol[j] == '.')
					while (sol[j + 1] == '.')
						j++;
			} else
				space = 1;
		}
		while (filename[len - 1] == '.' || filename[len - 1] == '-')
			len--;
	}
	strcpy(filename + len, ".txt");
129
	fprintf(realstdout, "%s\n", filename);
130 131 132
	freopen(filename, "w", stdout);
}

133 134 135 136 137
int cmd_format_patch(int argc, const char **argv, char **envp)
{
	struct commit *commit;
	struct commit **list = NULL;
	struct rev_info rev;
138
	int nr = 0, total, i, j;
139
	int use_stdout = 0;
140
	int numbered = 0;
141 142 143 144 145 146 147 148 149 150 151

	init_revisions(&rev);
	rev.commit_format = CMIT_FMT_EMAIL;
	rev.verbose_header = 1;
	rev.diff = 1;
	rev.diffopt.with_raw = 0;
	rev.diffopt.with_stat = 1;
	rev.combine_merges = 0;
	rev.ignore_merges = 1;
	rev.diffopt.output_format = DIFF_FORMAT_PATCH;

152 153 154 155 156 157 158
	/*
	 * Parse the arguments before setup_revisions(), or something
	 * like "git fmt-patch -o a123 HEAD^.." may fail; a123 is
	 * possibly a valid SHA1.
	 */
	for (i = 1, j = 1; i < argc; i++) {
		if (!strcmp(argv[i], "--stdout"))
159
			use_stdout = 1;
160 161 162
		else if (!strcmp(argv[i], "-n") ||
				!strcmp(argv[i], "--numbered"))
			numbered = 1;
163 164 165 166 167 168 169 170 171 172
		else if (!strcmp(argv[i], "-o")) {
			if (argc < 3)
				die ("Which directory?");
			if (mkdir(argv[i + 1], 0777) < 0 && errno != EEXIST)
				die("Could not create directory %s",
						argv[i + 1]);
			output_directory = strdup(argv[i + 1]);
			i++;
		} else
			argv[j++] = argv[i];
173
	}
174 175 176 177 178
	argc = j;

	argc = setup_revisions(argc, argv, &rev, "HEAD");
	if (argc > 1)
		die ("unrecognized argument: %s", argv[1]);
179

180 181 182
	if (!use_stdout)
		realstdout = fdopen(dup(1), "w");

183 184
	prepare_revision_walk(&rev);
	while ((commit = get_revision(&rev)) != NULL) {
185 186 187
		/* ignore merges */
		if (commit->parents && commit->parents->next)
			continue;
188 189 190 191
		nr++;
		list = realloc(list, nr * sizeof(list[0]));
		list[nr - 1] = commit;
	}
192
	total = nr;
193 194
	if (numbered)
		rev.total = total;
195 196 197
	while (0 <= --nr) {
		int shown;
		commit = list[nr];
198
		rev.nr = total - nr;
199
		if (!use_stdout)
200
			reopen_stdout(commit, rev.nr);
201 202 203 204 205
		shown = log_tree_commit(&rev, commit);
		free(commit->buffer);
		commit->buffer = NULL;
		if (shown)
			printf("-- \n%s\n\n", git_version_string);
206 207
		if (!use_stdout)
			fclose(stdout);
208
	}
209 210
	if (output_directory)
		free(output_directory);
211 212 213 214
	free(list);
	return 0;
}