Merge master into aw/mirror-push
						commit
						0d9d89f61c
					
				|  | @ -0,0 +1,112 @@ | |||
| Like other projects, we also have some guidelines to keep to the | ||||
| code.  For git in general, three rough rules are: | ||||
|  | ||||
|  - Most importantly, we never say "It's in POSIX; we'll happily | ||||
|    ignore your needs should your system not conform to it." | ||||
|    We live in the real world. | ||||
|  | ||||
|  - However, we often say "Let's stay away from that construct, | ||||
|    it's not even in POSIX". | ||||
|  | ||||
|  - In spite of the above two rules, we sometimes say "Although | ||||
|    this is not in POSIX, it (is so convenient | makes the code | ||||
|    much more readable | has other good characteristics) and | ||||
|    practically all the platforms we care about support it, so | ||||
|    let's use it". | ||||
|  | ||||
|    Again, we live in the real world, and it is sometimes a | ||||
|    judgement call, the decision based more on real world | ||||
|    constraints people face than what the paper standard says. | ||||
|  | ||||
|  | ||||
| As for more concrete guidelines, just imitate the existing code | ||||
| (this is a good guideline, no matter which project you are | ||||
| contributing to).  But if you must have a list of rules, | ||||
| here they are. | ||||
|  | ||||
| For shell scripts specifically (not exhaustive): | ||||
|  | ||||
|  - We prefer $( ... ) for command substitution; unlike ``, it | ||||
|    properly nests.  It should have been the way Bourne spelled | ||||
|    it from day one, but unfortunately isn't. | ||||
|  | ||||
|  - We use ${parameter-word} and its [-=?+] siblings, and their | ||||
|    colon'ed "unset or null" form. | ||||
|  | ||||
|  - We use ${parameter#word} and its [#%] siblings, and their | ||||
|    doubled "longest matching" form. | ||||
|  | ||||
|  - We use Arithmetic Expansion $(( ... )). | ||||
|  | ||||
|  - No "Substring Expansion" ${parameter:offset:length}. | ||||
|  | ||||
|  - No shell arrays. | ||||
|  | ||||
|  - No strlen ${#parameter}. | ||||
|  | ||||
|  - No regexp ${parameter/pattern/string}. | ||||
|  | ||||
|  - We do not use Process Substitution <(list) or >(list). | ||||
|  | ||||
|  - We prefer "test" over "[ ... ]". | ||||
|  | ||||
|  - We do not write the noiseword "function" in front of shell | ||||
|    functions. | ||||
|  | ||||
| For C programs: | ||||
|  | ||||
|  - We use tabs to indent, and interpret tabs as taking up to | ||||
|    8 spaces. | ||||
|  | ||||
|  - We try to keep to at most 80 characters per line. | ||||
|  | ||||
|  - When declaring pointers, the star sides with the variable | ||||
|    name, i.e. "char *string", not "char* string" or | ||||
|    "char * string".  This makes it easier to understand code | ||||
|    like "char *string, c;". | ||||
|  | ||||
|  - We avoid using braces unnecessarily.  I.e. | ||||
|  | ||||
| 	if (bla) { | ||||
| 		x = 1; | ||||
| 	} | ||||
|  | ||||
|    is frowned upon.  A gray area is when the statement extends | ||||
|    over a few lines, and/or you have a lengthy comment atop of | ||||
|    it.  Also, like in the Linux kernel, if there is a long list | ||||
|    of "else if" statements, it can make sense to add braces to | ||||
|    single line blocks. | ||||
|  | ||||
|  - Try to make your code understandable.  You may put comments | ||||
|    in, but comments invariably tend to stale out when the code | ||||
|    they were describing changes.  Often splitting a function | ||||
|    into two makes the intention of the code much clearer. | ||||
|  | ||||
|  - Double negation is often harder to understand than no negation | ||||
|    at all. | ||||
|  | ||||
|  - Some clever tricks, like using the !! operator with arithmetic | ||||
|    constructs, can be extremely confusing to others.  Avoid them, | ||||
|    unless there is a compelling reason to use them. | ||||
|  | ||||
|  - Use the API.  No, really.  We have a strbuf (variable length | ||||
|    string), several arrays with the ALLOC_GROW() macro, a | ||||
|    path_list for sorted string lists, a hash map (mapping struct | ||||
|    objects) named "struct decorate", amongst other things. | ||||
|  | ||||
|  - When you come up with an API, document it. | ||||
|  | ||||
|  - The first #include in C files, except in platform specific | ||||
|    compat/ implementations, should be git-compat-util.h or another | ||||
|    header file that includes it, such as cache.h or builtin.h. | ||||
|  | ||||
|  - If you are planning a new command, consider writing it in shell | ||||
|    or perl first, so that changes in semantics can be easily | ||||
|    changed and discussed.  Many git commands started out like | ||||
|    that, and a few are still scripts. | ||||
|  | ||||
|  - Avoid introducing a new dependency into git. This means you | ||||
|    usually should stay away from scripting languages not already | ||||
|    used in the git core command set (unless your command is clearly | ||||
|    separate from it, such as an importer to convert random-scm-X | ||||
|    repositories to git). | ||||
|  | @ -63,8 +63,8 @@ Fixes since v1.5.3.4 | |||
|  | ||||
|  * Git segfaulted when reading an invalid .gitattributes file.  Fixed. | ||||
|  | ||||
|  * post-receive-email example hook fixed was fixed for | ||||
|    non-fast-forward updates. | ||||
|  * post-receive-email example hook was fixed for non-fast-forward | ||||
|    updates. | ||||
|  | ||||
|  * Documentation updates for supported (but previously undocumented) | ||||
|    options of "git-archive" and "git-reflog". | ||||
|  | @ -90,5 +90,5 @@ Fixes since v1.5.3.4 | |||
|  * "git-send-pack $remote frotz" segfaulted when there is nothing | ||||
|    named 'frotz' on the local end. | ||||
|  | ||||
|  * "git-rebase -interactive" did not handle its "--strategy" option | ||||
|  * "git-rebase --interactive" did not handle its "--strategy" option | ||||
|    properly. | ||||
|  |  | |||
|  | @ -0,0 +1,21 @@ | |||
| GIT v1.5.3.6 Release Notes | ||||
| ========================== | ||||
|  | ||||
| Fixes since v1.5.3.5 | ||||
| -------------------- | ||||
|  | ||||
|  * git-cvsexportcommit handles root commits better; | ||||
|  | ||||
|  * git-svn dcommit used to clobber when sending a series of | ||||
|    patches; | ||||
|  | ||||
|  * git-grep sometimes refused to work when your index was | ||||
|    unmerged; | ||||
|  | ||||
|  * Quite a lot of documentation clarifications. | ||||
|  | ||||
| -- | ||||
| exec >/var/tmp/1 | ||||
| O=v1.5.3.5-32-gcb6c162 | ||||
| echo O=`git describe refs/heads/maint` | ||||
| git shortlog --no-merges $O..refs/heads/maint | ||||
|  | @ -6,7 +6,10 @@ Updates since v1.5.3 | |||
|  | ||||
|  * Comes with much improved gitk. | ||||
|  | ||||
|  * git-reset is now built-in. | ||||
|  * "progress display" from many commands are a lot nicer to the | ||||
|    eye.  Transfer commands show throughput data. | ||||
|  | ||||
|  * git-reset is now built-in and its output can be squelched with -q. | ||||
|  | ||||
|  * git-send-email can optionally talk over ssmtp and use SMTP-AUTH. | ||||
|  | ||||
|  | @ -46,6 +49,28 @@ Updates since v1.5.3 | |||
|  | ||||
|  * Various Perforce importer updates. | ||||
|  | ||||
|  * git-lost-found was deprecated in favor of git-fsck's --lost-found | ||||
|    option. | ||||
|  | ||||
|  * git-svnimport was removed in favor of git-svn. | ||||
|  | ||||
|  * git-bisect learned "skip" action to mark untestable commits. | ||||
|  | ||||
|  * rename detection diff family, while detecting exact matches, | ||||
|    has been greatly optimized. | ||||
|  | ||||
|  * Example update and post-receive hooks have been improved. | ||||
|  | ||||
|  * In addition there are quite a few internal clean-ups. Notably | ||||
|  | ||||
|    - many fork/exec have been replaced with run-command API, | ||||
|      brought from the msysgit effort. | ||||
|  | ||||
|    - introduction and more use of the option parser API. | ||||
|  | ||||
|    - enhancement and more use of the strbuf API. | ||||
|  | ||||
|  | ||||
| Fixes since v1.5.3 | ||||
| ------------------ | ||||
|  | ||||
|  | @ -54,6 +79,6 @@ this release, unless otherwise noted. | |||
|  | ||||
| -- | ||||
| exec >/var/tmp/1 | ||||
| O=v1.5.3.4-450-g952a9e5 | ||||
| O=v1.5.3.5-618-g5d4138a | ||||
| echo O=`git describe refs/heads/master` | ||||
| git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint | ||||
|  |  | |||
|  | @ -20,9 +20,6 @@ Checklist (and a short version for the impatient): | |||
| 	Patch: | ||||
|  | ||||
| 	- use "git format-patch -M" to create the patch | ||||
| 	- send your patch to <git@vger.kernel.org>. If you use | ||||
| 	  git-send-email(1), please test it first by sending | ||||
| 	  email to yourself. | ||||
| 	- do not PGP sign your patch | ||||
| 	- do not attach your patch, but read in the mail | ||||
| 	  body, unless you cannot teach your mailer to | ||||
|  | @ -31,13 +28,15 @@ Checklist (and a short version for the impatient): | |||
| 	  corrupt whitespaces. | ||||
| 	- provide additional information (which is unsuitable for | ||||
| 	  the commit message) between the "---" and the diffstat | ||||
| 	- send the patch to the list (git@vger.kernel.org) and the | ||||
| 	  maintainer (gitster@pobox.com). | ||||
| 	- if you change, add, or remove a command line option or | ||||
| 	  make some other user interface change, the associated | ||||
| 	  documentation should be updated as well. | ||||
| 	- if your name is not writable in ASCII, make sure that | ||||
| 	  you send off a message in the correct encoding. | ||||
| 	- send the patch to the list (git@vger.kernel.org) and the | ||||
| 	  maintainer (gitster@pobox.com). If you use | ||||
| 	  git-send-email(1), please test it first by sending | ||||
| 	  email to yourself. | ||||
|  | ||||
| Long version: | ||||
|  | ||||
|  |  | |||
|  | @ -345,8 +345,8 @@ branch.<name>.mergeoptions:: | |||
| 	supported. | ||||
|  | ||||
| clean.requireForce:: | ||||
| 	A boolean to make git-clean do nothing unless given -f or -n.  Defaults | ||||
| 	to false. | ||||
| 	A boolean to make git-clean do nothing unless given -f | ||||
| 	or -n.   Defaults to true. | ||||
|  | ||||
| color.branch:: | ||||
| 	A boolean to enable/disable color in the output of | ||||
|  | @ -661,6 +661,15 @@ pack.threads:: | |||
| 	machines. The required amount of memory for the delta search window | ||||
| 	is however multiplied by the number of threads. | ||||
|  | ||||
| pack.indexVersion:: | ||||
| 	Specify the default pack index version.  Valid values are 1 for | ||||
| 	legacy pack index used by Git versions prior to 1.5.2, and 2 for | ||||
| 	the new pack index with capabilities for packs larger than 4 GB | ||||
| 	as well as proper protection against the repacking of corrupted | ||||
| 	packs.  Version 2 is selected and this config option ignored | ||||
| 	whenever the corresponding pack is larger than 2 GB.  Otherwise | ||||
| 	the default is 1. | ||||
|  | ||||
| pull.octopus:: | ||||
| 	The default merge strategy to use when pulling multiple branches | ||||
| 	at once. | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ git-cherry-pick - Apply the change introduced by an existing commit | |||
|  | ||||
| SYNOPSIS | ||||
| -------- | ||||
| 'git-cherry-pick' [--edit] [-n] [-x] <commit> | ||||
| 'git-cherry-pick' [--edit] [-n] [-m parent-number] [-x] <commit> | ||||
|  | ||||
| DESCRIPTION | ||||
| ----------- | ||||
|  | @ -44,6 +44,13 @@ OPTIONS | |||
| 	described above, and `-r` was to disable it.  Now the | ||||
| 	default is not to do `-x` so this option is a no-op. | ||||
|  | ||||
| -m parent-number|--mainline parent-number:: | ||||
| 	Usually you cannot revert a merge because you do not know which | ||||
| 	side of the merge should be considered the mainline.  This | ||||
| 	option specifies the parent number (starting from 1) of | ||||
| 	the mainline and allows cherry-pick to replay the change | ||||
| 	relative to the specified parent. | ||||
|  | ||||
| -n|--no-commit:: | ||||
| 	Usually the command automatically creates a commit with | ||||
| 	a commit log message stating which commit was | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ SYNOPSIS | |||
| 'git-clone' [--template=<template_directory>] | ||||
| 	  [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] | ||||
| 	  [-o <name>] [-u <upload-pack>] [--reference <repository>] | ||||
| 	  [--depth <depth>] <repository> [<directory>] | ||||
| 	  [--depth <depth>] [--] <repository> [<directory>] | ||||
|  | ||||
| DESCRIPTION | ||||
| ----------- | ||||
|  |  | |||
|  | @ -11,6 +11,10 @@ SYNOPSIS | |||
|  | ||||
| DESCRIPTION | ||||
| ----------- | ||||
|  | ||||
| *NOTE*: this command is deprecated.  Use gitlink:git-fsck[1] with | ||||
| the option '--lost-found' instead. | ||||
|  | ||||
| Finds dangling commits and tags from the object database, and | ||||
| creates refs to them in the .git/lost-found/ directory.  Commits and | ||||
| tags that dereference to commits are stored in .git/lost-found/commit, | ||||
|  |  | |||
|  | @ -8,8 +8,8 @@ git-reset - Reset current HEAD to the specified state | |||
| SYNOPSIS | ||||
| -------- | ||||
| [verse] | ||||
| 'git-reset' [--mixed | --soft | --hard] [<commit>] | ||||
| 'git-reset' [--mixed] <commit> [--] <paths>... | ||||
| 'git-reset' [--mixed | --soft | --hard] [-q] [<commit>] | ||||
| 'git-reset' [--mixed] [-q] <commit> [--] <paths>... | ||||
|  | ||||
| DESCRIPTION | ||||
| ----------- | ||||
|  | @ -45,6 +45,9 @@ OPTIONS | |||
| 	switched to. Any changes to tracked files in the working tree | ||||
| 	since <commit> are lost. | ||||
|  | ||||
| -q:: | ||||
| 	Be quiet, only report errors. | ||||
|  | ||||
| <commit>:: | ||||
| 	Commit to make the current HEAD. | ||||
|  | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ git-revert - Revert an existing commit | |||
|  | ||||
| SYNOPSIS | ||||
| -------- | ||||
| 'git-revert' [--edit | --no-edit] [-n] <commit> | ||||
| 'git-revert' [--edit | --no-edit] [-n] [-m parent-number] <commit> | ||||
|  | ||||
| DESCRIPTION | ||||
| ----------- | ||||
|  | @ -27,6 +27,13 @@ OPTIONS | |||
| 	message prior committing the revert. This is the default if | ||||
| 	you run the command from a terminal. | ||||
|  | ||||
| -m parent-number|--mainline parent-number:: | ||||
| 	Usually you cannot revert a merge because you do not know which | ||||
| 	side of the merge should be considered the mainline.  This | ||||
| 	option specifies the parent number (starting from 1) of | ||||
| 	the mainline and allows revert to reverse the change | ||||
| 	relative to the specified parent. | ||||
|  | ||||
| --no-edit:: | ||||
| 	With this option, `git-revert` will not start the commit | ||||
| 	message editor. | ||||
|  |  | |||
|  | @ -113,8 +113,7 @@ The --cc option must be repeated for each user you want on the cc list. | |||
| 	is not set, this will be prompted for. | ||||
|  | ||||
| --suppress-from, --no-suppress-from:: | ||||
|         If this is set, do not add the From: address to the cc: list, if it | ||||
|         shows up in a From: line. | ||||
|         If this is set, do not add the From: address to the cc: list. | ||||
|         Default is the value of 'sendemail.suppressfrom' configuration value; | ||||
|         if that is unspecified, default to --no-suppress-from. | ||||
|  | ||||
|  |  | |||
							
								
								
									
										9
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										9
									
								
								Makefile
								
								
								
								
							|  | @ -98,6 +98,8 @@ all:: | |||
| # Define OLD_ICONV if your library has an old iconv(), where the second | ||||
| # (input buffer pointer) parameter is declared with type (const char **). | ||||
| # | ||||
| # Define NO_DEFLATE_BOUND if your zlib does not have deflateBound. | ||||
| # | ||||
| # Define NO_R_TO_GCC_LINKER if your gcc does not like "-R/path/lib" | ||||
| # that tells runtime paths to dynamic libraries; | ||||
| # "-Wl,-rpath=/path/lib" is used instead. | ||||
|  | @ -298,7 +300,7 @@ DIFF_OBJS = \ | |||
| LIB_OBJS = \ | ||||
| 	blob.o commit.o connect.o csum-file.o cache-tree.o base85.o \ | ||||
| 	date.o diff-delta.o entry.o exec_cmd.o ident.o \ | ||||
| 	interpolate.o hash.o \ | ||||
| 	pretty.o interpolate.o hash.o \ | ||||
| 	lockfile.o \ | ||||
| 	patch-ids.o \ | ||||
| 	object.o pack-check.o pack-write.o patch-delta.o path.o pkt-line.o \ | ||||
|  | @ -662,6 +664,10 @@ ifdef OLD_ICONV | |||
| 	BASIC_CFLAGS += -DOLD_ICONV | ||||
| endif | ||||
|  | ||||
| ifdef NO_DEFLATE_BOUND | ||||
| 	BASIC_CFLAGS += -DNO_DEFLATE_BOUND | ||||
| endif | ||||
|  | ||||
| ifdef PPC_SHA1 | ||||
| 	SHA1_HEADER = "ppc/sha1.h" | ||||
| 	LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o | ||||
|  | @ -917,6 +923,7 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS) | |||
|  | ||||
| $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) | ||||
| $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) | ||||
| builtin-revert.o builtin-runstatus.o wt-status.o: wt-status.h | ||||
|  | ||||
| $(LIB_FILE): $(LIB_OBJS) | ||||
| 	$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) | ||||
|  |  | |||
|  | @ -2215,9 +2215,6 @@ int cmd_blame(int argc, const char **argv, const char *prefix) | |||
| 			argv[unk++] = arg; | ||||
| 	} | ||||
|  | ||||
| 	if (!incremental) | ||||
| 		setup_pager(); | ||||
|  | ||||
| 	if (!blame_move_score) | ||||
| 		blame_move_score = BLAME_DEFAULT_MOVE_SCORE; | ||||
| 	if (!blame_copy_score) | ||||
|  | @ -2345,6 +2342,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) | |||
| 		 * do not default to HEAD, but use the working tree | ||||
| 		 * or "--contents". | ||||
| 		 */ | ||||
| 		setup_work_tree(); | ||||
| 		sb.final = fake_working_tree_commit(path, contents_from); | ||||
| 		add_pending_object(&revs, &(sb.final->object), ":"); | ||||
| 	} | ||||
|  | @ -2411,6 +2409,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix) | |||
|  | ||||
| 	read_mailmap(&mailmap, ".mailmap", NULL); | ||||
|  | ||||
| 	if (!incremental) | ||||
| 		setup_pager(); | ||||
|  | ||||
| 	assign_blame(&sb, &revs, opt); | ||||
|  | ||||
| 	if (incremental) | ||||
|  |  | |||
|  | @ -148,7 +148,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds) | |||
|  | ||||
| 		if (!force && | ||||
| 		    !in_merge_bases(rev, &head_rev, 1)) { | ||||
| 			error("The branch '%s' is not a strict subset of " | ||||
| 			error("The branch '%s' is not an ancestor of " | ||||
| 				"your current HEAD.\n" | ||||
| 				"If you are sure you want to delete it, " | ||||
| 				"run 'git branch -D %s'.", argv[i], argv[i]); | ||||
|  | @ -282,7 +282,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, | |||
| 		commit = lookup_commit(item->sha1); | ||||
| 		if (commit && !parse_commit(commit)) { | ||||
| 			pretty_print_commit(CMIT_FMT_ONELINE, commit, | ||||
| 					    &subject, 0, NULL, NULL, 0); | ||||
| 					    &subject, 0, NULL, NULL, 0, 0); | ||||
| 			sub = subject.buf; | ||||
| 		} | ||||
| 		printf("%c %s%-*s%s %s %s\n", c, branch_get_color(color), | ||||
|  |  | |||
|  | @ -200,15 +200,11 @@ static void refresh_index_quietly(void) | |||
| 	discard_cache(); | ||||
| 	read_cache(); | ||||
| 	refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED); | ||||
| 	if (active_cache_changed) { | ||||
| 		if (write_cache(fd, active_cache, active_nr) || | ||||
| 		    close(fd) || | ||||
| 		    commit_locked_index(lock_file)) | ||||
| 			; /* | ||||
| 			   * silently ignore it -- we haven't mucked | ||||
| 			   * with the real index. | ||||
| 			   */ | ||||
| 	} | ||||
|  | ||||
| 	if (active_cache_changed && | ||||
| 	    !write_cache(fd, active_cache, active_nr) && !close(fd)) | ||||
| 		commit_locked_index(lock_file); | ||||
|  | ||||
| 	rollback_lock_file(lock_file); | ||||
| } | ||||
|  | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ static const char fetch_pack_usage[] = | |||
| #define MAX_IN_VAIN 256 | ||||
|  | ||||
| static struct commit_list *rev_list; | ||||
| static int non_common_revs, multi_ack, use_thin_pack, use_sideband; | ||||
| static int non_common_revs, multi_ack, use_sideband; | ||||
|  | ||||
| static void rev_list_push(struct commit *commit, int mark) | ||||
| { | ||||
|  | @ -178,7 +178,7 @@ static int find_common(int fd[2], unsigned char *result_sha1, | |||
| 				     (multi_ack ? " multi_ack" : ""), | ||||
| 				     (use_sideband == 2 ? " side-band-64k" : ""), | ||||
| 				     (use_sideband == 1 ? " side-band" : ""), | ||||
| 				     (use_thin_pack ? " thin-pack" : ""), | ||||
| 				     (args.use_thin_pack ? " thin-pack" : ""), | ||||
| 				     (args.no_progress ? " no-progress" : ""), | ||||
| 				     " ofs-delta"); | ||||
| 		else | ||||
|  |  | |||
							
								
								
									
										116
									
								
								builtin-fetch.c
								
								
								
								
							
							
						
						
									
										116
									
								
								builtin-fetch.c
								
								
								
								
							|  | @ -131,12 +131,6 @@ static struct ref *get_ref_map(struct transport *transport, | |||
| 	return ref_map; | ||||
| } | ||||
|  | ||||
| static void show_new(enum object_type type, unsigned char *sha1_new) | ||||
| { | ||||
| 	fprintf(stderr, "  %s: %s\n", typename(type), | ||||
| 		find_unique_abbrev(sha1_new, DEFAULT_ABBREV)); | ||||
| } | ||||
|  | ||||
| static int s_update_ref(const char *action, | ||||
| 			struct ref *ref, | ||||
| 			int check_old) | ||||
|  | @ -157,34 +151,38 @@ static int s_update_ref(const char *action, | |||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3) | ||||
|  | ||||
| static int update_local_ref(struct ref *ref, | ||||
| 			    const char *note, | ||||
| 			    int verbose) | ||||
| 			    const char *remote, | ||||
| 			    int verbose, | ||||
| 			    char *display) | ||||
| { | ||||
| 	char oldh[41], newh[41]; | ||||
| 	struct commit *current = NULL, *updated; | ||||
| 	enum object_type type; | ||||
| 	struct branch *current_branch = branch_get(NULL); | ||||
| 	const char *pretty_ref = ref->name + ( | ||||
| 		!prefixcmp(ref->name, "refs/heads/") ? 11 : | ||||
| 		!prefixcmp(ref->name, "refs/tags/") ? 10 : | ||||
| 		!prefixcmp(ref->name, "refs/remotes/") ? 13 : | ||||
| 		0); | ||||
|  | ||||
| 	*display = 0; | ||||
| 	type = sha1_object_info(ref->new_sha1, NULL); | ||||
| 	if (type < 0) | ||||
| 		die("object %s not found", sha1_to_hex(ref->new_sha1)); | ||||
|  | ||||
| 	if (!*ref->name) { | ||||
| 		/* Not storing */ | ||||
| 		if (verbose) { | ||||
| 			fprintf(stderr, "* fetched %s\n", note); | ||||
| 			show_new(type, ref->new_sha1); | ||||
| 		} | ||||
| 		if (verbose) | ||||
| 			sprintf(display, "* branch %s -> FETCH_HEAD", remote); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!hashcmp(ref->old_sha1, ref->new_sha1)) { | ||||
| 		if (verbose) { | ||||
| 			fprintf(stderr, "* %s: same as %s\n", | ||||
| 				ref->name, note); | ||||
| 			show_new(type, ref->new_sha1); | ||||
| 		} | ||||
| 		if (verbose) | ||||
| 			sprintf(display, "= %-*s %s -> %s", SUMMARY_WIDTH, | ||||
| 				"[up to date]", remote, pretty_ref); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
|  | @ -196,63 +194,65 @@ static int update_local_ref(struct ref *ref, | |||
| 		 * If this is the head, and it's not okay to update | ||||
| 		 * the head, and the old value of the head isn't empty... | ||||
| 		 */ | ||||
| 		fprintf(stderr, | ||||
| 			" * %s: Cannot fetch into the current branch.\n", | ||||
| 			ref->name); | ||||
| 		sprintf(display, "! %-*s %s -> %s  (can't  fetch in current branch)", | ||||
| 			SUMMARY_WIDTH, "[rejected]", remote, pretty_ref); | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	if (!is_null_sha1(ref->old_sha1) && | ||||
| 	    !prefixcmp(ref->name, "refs/tags/")) { | ||||
| 		fprintf(stderr, "* %s: updating with %s\n", | ||||
| 			ref->name, note); | ||||
| 		show_new(type, ref->new_sha1); | ||||
| 		sprintf(display, "- %-*s %s -> %s", | ||||
| 			SUMMARY_WIDTH, "[tag update]", remote, pretty_ref); | ||||
| 		return s_update_ref("updating tag", ref, 0); | ||||
| 	} | ||||
|  | ||||
| 	current = lookup_commit_reference_gently(ref->old_sha1, 1); | ||||
| 	updated = lookup_commit_reference_gently(ref->new_sha1, 1); | ||||
| 	if (!current || !updated) { | ||||
| 		char *msg; | ||||
| 		if (!strncmp(ref->name, "refs/tags/", 10)) | ||||
| 		const char *msg; | ||||
| 		const char *what; | ||||
| 		if (!strncmp(ref->name, "refs/tags/", 10)) { | ||||
| 			msg = "storing tag"; | ||||
| 		else | ||||
| 			what = "[new tag]"; | ||||
| 		} | ||||
| 		else { | ||||
| 			msg = "storing head"; | ||||
| 		fprintf(stderr, "* %s: storing %s\n", | ||||
| 			ref->name, note); | ||||
| 		show_new(type, ref->new_sha1); | ||||
| 			what = "[new branch]"; | ||||
| 		} | ||||
|  | ||||
| 		sprintf(display, "* %-*s %s -> %s", | ||||
| 			SUMMARY_WIDTH, what, remote, pretty_ref); | ||||
| 		return s_update_ref(msg, ref, 0); | ||||
| 	} | ||||
|  | ||||
| 	strcpy(oldh, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); | ||||
| 	strcpy(newh, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); | ||||
|  | ||||
| 	if (in_merge_bases(current, &updated, 1)) { | ||||
| 		fprintf(stderr, "* %s: fast forward to %s\n", | ||||
| 			ref->name, note); | ||||
| 		fprintf(stderr, "  old..new: %s..%s\n", oldh, newh); | ||||
| 		char quickref[83]; | ||||
| 		strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); | ||||
| 		strcat(quickref, ".."); | ||||
| 		strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); | ||||
| 		sprintf(display, "  %-*s %s -> %s  (fast forward)", | ||||
| 			SUMMARY_WIDTH, quickref, remote, pretty_ref); | ||||
| 		return s_update_ref("fast forward", ref, 1); | ||||
| 	} | ||||
| 	if (!force && !ref->force) { | ||||
| 		fprintf(stderr, | ||||
| 			"* %s: not updating to non-fast forward %s\n", | ||||
| 			ref->name, note); | ||||
| 		fprintf(stderr, | ||||
| 			"  old...new: %s...%s\n", oldh, newh); | ||||
| 	} else if (force || ref->force) { | ||||
| 		char quickref[84]; | ||||
| 		strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); | ||||
| 		strcat(quickref, "..."); | ||||
| 		strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); | ||||
| 		sprintf(display, "+ %-*s %s -> %s  (forced update)", | ||||
| 			SUMMARY_WIDTH, quickref, remote, pretty_ref); | ||||
| 		return s_update_ref("forced-update", ref, 1); | ||||
| 	} else { | ||||
| 		sprintf(display, "! %-*s %s -> %s  (non fast forward)", | ||||
| 			SUMMARY_WIDTH, "[rejected]", remote, pretty_ref); | ||||
| 		return 1; | ||||
| 	} | ||||
| 	fprintf(stderr, | ||||
| 		"* %s: forcing update to non-fast forward %s\n", | ||||
| 		ref->name, note); | ||||
| 	fprintf(stderr, "  old...new: %s...%s\n", oldh, newh); | ||||
| 	return s_update_ref("forced-update", ref, 1); | ||||
| } | ||||
|  | ||||
| static void store_updated_refs(const char *url, struct ref *ref_map) | ||||
| { | ||||
| 	FILE *fp; | ||||
| 	struct commit *commit; | ||||
| 	int url_len, i, note_len; | ||||
| 	int url_len, i, note_len, shown_url = 0; | ||||
| 	char note[1024]; | ||||
| 	const char *what, *kind; | ||||
| 	struct ref *rm; | ||||
|  | @ -315,8 +315,17 @@ static void store_updated_refs(const char *url, struct ref *ref_map) | |||
| 			rm->merge ? "" : "not-for-merge", | ||||
| 			note); | ||||
|  | ||||
| 		if (ref) | ||||
| 			update_local_ref(ref, note, verbose); | ||||
| 		if (ref) { | ||||
| 			update_local_ref(ref, what, verbose, note); | ||||
| 			if (*note) { | ||||
| 				if (!shown_url) { | ||||
| 					fprintf(stderr, "From %.*s\n", | ||||
| 							url_len, url); | ||||
| 					shown_url = 1; | ||||
| 				} | ||||
| 				fprintf(stderr, " %s\n", note); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	fclose(fp); | ||||
| } | ||||
|  | @ -376,9 +385,6 @@ static struct ref *find_non_local_tags(struct transport *transport, | |||
| 		if (!path_list_has_path(&existing_refs, ref_name) && | ||||
| 		    !path_list_has_path(&new_refs, ref_name) && | ||||
| 		    lookup_object(ref->old_sha1)) { | ||||
| 			fprintf(stderr, "Auto-following %s\n", | ||||
| 				ref_name); | ||||
|  | ||||
| 			path_list_insert(ref_name, &new_refs); | ||||
|  | ||||
| 			rm = alloc_ref(strlen(ref_name) + 1); | ||||
|  | @ -517,7 +523,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) | |||
| 			depth = argv[i]; | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (!strcmp(arg, "--quiet")) { | ||||
| 		if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) { | ||||
| 			quiet = 1; | ||||
| 			continue; | ||||
| 		} | ||||
|  |  | |||
|  | @ -175,7 +175,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix) | |||
| 	char buf[80]; | ||||
|  | ||||
| 	struct option builtin_gc_options[] = { | ||||
| 		OPT_BOOLEAN(0, "prune", &prune, "prune unreferenced loose objects"), | ||||
| 		OPT_BOOLEAN(0, "prune", &prune, "prune unreferenced objects"), | ||||
| 		OPT_BOOLEAN(0, "aggressive", &aggressive, "be more thorough (increased runtime)"), | ||||
| 		OPT_BOOLEAN(0, "auto", &auto_gc, "enable auto-gc mode"), | ||||
| 		OPT_END() | ||||
|  |  | |||
|  | @ -343,7 +343,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached) | |||
| 			memcpy(name + 2, ce->name, len + 1); | ||||
| 		} | ||||
| 		argv[argc++] = name; | ||||
| 		if (argc < MAXARGS && !ce_stage(ce)) | ||||
| 		if (argc < MAXARGS) | ||||
| 			continue; | ||||
| 		status = flush_grep(opt, argc, nr, argv, &kept); | ||||
| 		if (0 < status) | ||||
|  |  | |||
|  | @ -787,7 +787,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix) | |||
| 			struct strbuf buf; | ||||
| 			strbuf_init(&buf, 0); | ||||
| 			pretty_print_commit(CMIT_FMT_ONELINE, commit, | ||||
| 			                    &buf, 0, NULL, NULL, 0); | ||||
| 			                    &buf, 0, NULL, NULL, 0, 0); | ||||
| 			printf("%c %s %s\n", sign, | ||||
| 			       sha1_to_hex(commit->object.sha1), buf.buf); | ||||
| 			strbuf_release(&buf); | ||||
|  |  | |||
|  | @ -525,11 +525,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) | |||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	if (require_work_tree && !is_inside_work_tree()) { | ||||
| 		const char *work_tree = get_git_work_tree(); | ||||
| 		if (!work_tree || chdir(work_tree)) | ||||
| 			die("This operation must be run in a work tree"); | ||||
| 	} | ||||
| 	if (require_work_tree && !is_inside_work_tree()) | ||||
| 		setup_work_tree(); | ||||
|  | ||||
| 	pathspec = get_pathspec(prefix, argv + i); | ||||
|  | ||||
|  |  | |||
|  | @ -915,6 +915,7 @@ static void handle_info(void) | |||
| static int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, | ||||
| 		    const char *msg, const char *patch) | ||||
| { | ||||
| 	int peek; | ||||
| 	keep_subject = ks; | ||||
| 	metainfo_charset = encoding; | ||||
| 	fin = in; | ||||
|  | @ -935,6 +936,11 @@ static int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, | |||
| 	p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(char *)); | ||||
| 	s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(char *)); | ||||
|  | ||||
| 	do { | ||||
| 		peek = fgetc(in); | ||||
| 	} while (isspace(peek)); | ||||
| 	ungetc(peek, in); | ||||
|  | ||||
| 	/* process the email header */ | ||||
| 	while (read_one_header_line(line, sizeof(line), fin)) | ||||
| 		check_header(line, sizeof(line), p_hdr_data, 1); | ||||
|  |  | |||
|  | @ -101,20 +101,29 @@ static int populate_maildir_list(struct path_list *list, const char *path) | |||
| { | ||||
| 	DIR *dir; | ||||
| 	struct dirent *dent; | ||||
| 	char name[PATH_MAX]; | ||||
| 	char *subs[] = { "cur", "new", NULL }; | ||||
| 	char **sub; | ||||
|  | ||||
| 	if ((dir = opendir(path)) == NULL) { | ||||
| 		error("cannot opendir %s (%s)", path, strerror(errno)); | ||||
| 		return -1; | ||||
| 	for (sub = subs; *sub; ++sub) { | ||||
| 		snprintf(name, sizeof(name), "%s/%s", path, *sub); | ||||
| 		if ((dir = opendir(name)) == NULL) { | ||||
| 			if (errno == ENOENT) | ||||
| 				continue; | ||||
| 			error("cannot opendir %s (%s)", name, strerror(errno)); | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		while ((dent = readdir(dir)) != NULL) { | ||||
| 			if (dent->d_name[0] == '.') | ||||
| 				continue; | ||||
| 			snprintf(name, sizeof(name), "%s/%s", *sub, dent->d_name); | ||||
| 			path_list_insert(name, list); | ||||
| 		} | ||||
|  | ||||
| 		closedir(dir); | ||||
| 	} | ||||
|  | ||||
| 	while ((dent = readdir(dir)) != NULL) { | ||||
| 		if (dent->d_name[0] == '.') | ||||
| 			continue; | ||||
| 		path_list_insert(dent->d_name, list); | ||||
| 	} | ||||
|  | ||||
| 	closedir(dir); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | @ -122,19 +131,17 @@ static int split_maildir(const char *maildir, const char *dir, | |||
| 	int nr_prec, int skip) | ||||
| { | ||||
| 	char file[PATH_MAX]; | ||||
| 	char curdir[PATH_MAX]; | ||||
| 	char name[PATH_MAX]; | ||||
| 	int ret = -1; | ||||
| 	int i; | ||||
| 	struct path_list list = {NULL, 0, 0, 1}; | ||||
|  | ||||
| 	snprintf(curdir, sizeof(curdir), "%s/cur", maildir); | ||||
| 	if (populate_maildir_list(&list, curdir) < 0) | ||||
| 	if (populate_maildir_list(&list, maildir) < 0) | ||||
| 		goto out; | ||||
|  | ||||
| 	for (i = 0; i < list.nr; i++) { | ||||
| 		FILE *f; | ||||
| 		snprintf(file, sizeof(file), "%s/%s", curdir, list.items[i].path); | ||||
| 		snprintf(file, sizeof(file), "%s/%s", maildir, list.items[i].path); | ||||
| 		f = fopen(file, "r"); | ||||
| 		if (!f) { | ||||
| 			error("cannot open mail %s (%s)", file, strerror(errno)); | ||||
|  | @ -152,10 +159,9 @@ static int split_maildir(const char *maildir, const char *dir, | |||
| 		fclose(f); | ||||
| 	} | ||||
|  | ||||
| 	path_list_clear(&list, 1); | ||||
|  | ||||
| 	ret = skip; | ||||
| out: | ||||
| 	path_list_clear(&list, 1); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
|  | @ -164,6 +170,7 @@ static int split_mbox(const char *file, const char *dir, int allow_bare, | |||
| { | ||||
| 	char name[PATH_MAX]; | ||||
| 	int ret = -1; | ||||
| 	int peek; | ||||
|  | ||||
| 	FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r"); | ||||
| 	int file_done = 0; | ||||
|  | @ -173,6 +180,11 @@ static int split_mbox(const char *file, const char *dir, int allow_bare, | |||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	do { | ||||
| 		peek = fgetc(f); | ||||
| 	} while (isspace(peek)); | ||||
| 	ungetc(peek, f); | ||||
|  | ||||
| 	if (fgets(buf, sizeof(buf), f) == NULL) { | ||||
| 		/* empty stdin is OK */ | ||||
| 		if (f != stdin) { | ||||
|  |  | |||
|  | @ -57,7 +57,7 @@ struct object_entry { | |||
|  * nice "minimum seek" order. | ||||
|  */ | ||||
| static struct object_entry *objects; | ||||
| static struct object_entry **written_list; | ||||
| static struct pack_idx_entry **written_list; | ||||
| static uint32_t nr_objects, nr_alloc, nr_result, nr_written; | ||||
|  | ||||
| static int non_empty; | ||||
|  | @ -577,7 +577,7 @@ static off_t write_one(struct sha1file *f, | |||
| 		e->idx.offset = 0; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	written_list[nr_written++] = e; | ||||
| 	written_list[nr_written++] = &e->idx; | ||||
|  | ||||
| 	/* make sure off_t is sufficiently large not to wrap */ | ||||
| 	if (offset > offset + size) | ||||
|  | @ -599,7 +599,7 @@ static void write_pack_file(void) | |||
|  | ||||
| 	if (do_progress) | ||||
| 		progress_state = start_progress("Writing objects", nr_result); | ||||
| 	written_list = xmalloc(nr_objects * sizeof(struct object_entry *)); | ||||
| 	written_list = xmalloc(nr_objects * sizeof(*written_list)); | ||||
|  | ||||
| 	do { | ||||
| 		unsigned char sha1[20]; | ||||
|  | @ -651,9 +651,8 @@ static void write_pack_file(void) | |||
| 			umask(mode); | ||||
| 			mode = 0444 & ~mode; | ||||
|  | ||||
| 			idx_tmp_name = write_idx_file(NULL, | ||||
| 					(struct pack_idx_entry **) written_list, | ||||
| 					nr_written, sha1); | ||||
| 			idx_tmp_name = write_idx_file(NULL, written_list, | ||||
| 						      nr_written, sha1); | ||||
| 			snprintf(tmpname, sizeof(tmpname), "%s-%s.pack", | ||||
| 				 base_name, sha1_to_hex(sha1)); | ||||
| 			if (adjust_perm(pack_tmp_name, mode)) | ||||
|  | @ -677,7 +676,7 @@ static void write_pack_file(void) | |||
|  | ||||
| 		/* mark written objects as written to previous pack */ | ||||
| 		for (j = 0; j < nr_written; j++) { | ||||
| 			written_list[j]->idx.offset = (off_t)-1; | ||||
| 			written_list[j]->offset = (off_t)-1; | ||||
| 		} | ||||
| 		nr_remaining -= nr_written; | ||||
| 	} while (nr_remaining && i < nr_objects); | ||||
|  | @ -1768,6 +1767,12 @@ static int git_pack_config(const char *k, const char *v) | |||
| #endif | ||||
| 		return 0; | ||||
| 	} | ||||
| 	if (!strcmp(k, "pack.indexversion")) { | ||||
| 		pack_idx_default_version = git_config_int(k, v); | ||||
| 		if (pack_idx_default_version > 2) | ||||
| 			die("bad pack.indexversion=%d", pack_idx_default_version); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return git_default_config(k, v); | ||||
| } | ||||
|  | ||||
|  |  | |||
|  | @ -7,8 +7,12 @@ | |||
| #include "builtin.h" | ||||
| #include "remote.h" | ||||
| #include "transport.h" | ||||
| #include "parse-options.h" | ||||
|  | ||||
| static const char push_usage[] = "git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]"; | ||||
| static const char * const push_usage[] = { | ||||
| 	"git-push [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]", | ||||
| 	NULL, | ||||
| }; | ||||
|  | ||||
| static int thin, verbose; | ||||
| static const char *receivepack; | ||||
|  | @ -85,63 +89,43 @@ static int do_push(const char *repo, int flags) | |||
|  | ||||
| int cmd_push(int argc, const char **argv, const char *prefix) | ||||
| { | ||||
| 	int i; | ||||
| 	int flags = 0; | ||||
| 	int all = 0; | ||||
| 	int dry_run = 0; | ||||
| 	int force = 0; | ||||
| 	int tags = 0; | ||||
| 	const char *repo = NULL;	/* default repository */ | ||||
|  | ||||
| 	for (i = 1; i < argc; i++) { | ||||
| 		const char *arg = argv[i]; | ||||
| 	struct option options[] = { | ||||
| 		OPT__VERBOSE(&verbose), | ||||
| 		OPT_STRING( 0 , "repo", &repo, "repository", "repository"), | ||||
| 		OPT_BOOLEAN( 0 , "all", &all, "push all refs"), | ||||
| 		OPT_BOOLEAN( 0 , "tags", &tags, "push tags"), | ||||
| 		OPT_BOOLEAN( 0 , "dry-run", &dry_run, "dry run"), | ||||
| 		OPT_BOOLEAN('f', "force", &force, "force updates"), | ||||
| 		OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"), | ||||
| 		OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"), | ||||
| 		OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"), | ||||
| 		OPT_END() | ||||
| 	}; | ||||
|  | ||||
| 		if (arg[0] != '-') { | ||||
| 			repo = arg; | ||||
| 			i++; | ||||
| 			break; | ||||
| 		} | ||||
| 		if (!strcmp(arg, "-v")) { | ||||
| 			verbose=1; | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (!prefixcmp(arg, "--repo=")) { | ||||
| 			repo = arg+7; | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (!strcmp(arg, "--all")) { | ||||
| 			flags |= TRANSPORT_PUSH_ALL; | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (!strcmp(arg, "--dry-run")) { | ||||
| 			flags |= TRANSPORT_PUSH_DRY_RUN; | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (!strcmp(arg, "--tags")) { | ||||
| 			add_refspec("refs/tags/*"); | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) { | ||||
| 			flags |= TRANSPORT_PUSH_FORCE; | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (!strcmp(arg, "--thin")) { | ||||
| 			thin = 1; | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (!strcmp(arg, "--no-thin")) { | ||||
| 			thin = 0; | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (!prefixcmp(arg, "--receive-pack=")) { | ||||
| 			receivepack = arg + 15; | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (!prefixcmp(arg, "--exec=")) { | ||||
| 			receivepack = arg + 7; | ||||
| 			continue; | ||||
| 		} | ||||
| 		usage(push_usage); | ||||
| 	argc = parse_options(argc, argv, options, push_usage, 0); | ||||
|  | ||||
| 	if (force) | ||||
| 		flags |= TRANSPORT_PUSH_FORCE; | ||||
| 	if (dry_run) | ||||
| 		flags |= TRANSPORT_PUSH_DRY_RUN; | ||||
| 	if (tags) | ||||
| 		add_refspec("refs/tags/*"); | ||||
| 	if (all) | ||||
| 		flags |= TRANSPORT_PUSH_ALL; | ||||
|  | ||||
| 	if (argc > 0) { | ||||
| 		repo = argv[0]; | ||||
| 		set_refspecs(argv + 1, argc - 1); | ||||
| 	} | ||||
| 	set_refspecs(argv + i, argc - i); | ||||
| 	if ((flags & TRANSPORT_PUSH_ALL) && refspec) | ||||
| 		usage(push_usage); | ||||
| 		usage_with_options(push_usage, options); | ||||
|  | ||||
| 	return do_push(repo, flags); | ||||
| } | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ | |||
| #include "tree.h" | ||||
|  | ||||
| static const char builtin_reset_usage[] = | ||||
| "git-reset [--mixed | --soft | --hard]  [<commit-ish>] [ [--] <paths>...]"; | ||||
| "git-reset [--mixed | --soft | --hard] [-q] [<commit-ish>] [ [--] <paths>...]"; | ||||
|  | ||||
| static char *args_to_str(const char **argv) | ||||
| { | ||||
|  | @ -113,10 +113,17 @@ static int update_index_refresh(void) | |||
| 	return run_command_v_opt(argv_update_index, RUN_GIT_CMD); | ||||
| } | ||||
|  | ||||
| struct update_cb_data { | ||||
| 	int index_fd; | ||||
| 	struct lock_file *lock; | ||||
| 	int exit_code; | ||||
| }; | ||||
|  | ||||
| static void update_index_from_diff(struct diff_queue_struct *q, | ||||
| 		struct diff_options *opt, void *data) | ||||
| { | ||||
| 	int i; | ||||
| 	struct update_cb_data *cb = data; | ||||
|  | ||||
| 	/* do_diff_cache() mangled the index */ | ||||
| 	discard_cache(); | ||||
|  | @ -133,29 +140,34 @@ static void update_index_from_diff(struct diff_queue_struct *q, | |||
| 		} else | ||||
| 			remove_file_from_cache(one->path); | ||||
| 	} | ||||
|  | ||||
| 	cb->exit_code = write_cache(cb->index_fd, active_cache, active_nr) || | ||||
| 		close(cb->index_fd) || | ||||
| 		commit_locked_index(cb->lock); | ||||
| } | ||||
|  | ||||
| static int read_from_tree(const char *prefix, const char **argv, | ||||
| 		unsigned char *tree_sha1) | ||||
| { | ||||
|         struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); | ||||
| 	int index_fd; | ||||
| 	struct diff_options opt; | ||||
| 	struct update_cb_data cb; | ||||
|  | ||||
| 	memset(&opt, 0, sizeof(opt)); | ||||
| 	diff_tree_setup_paths(get_pathspec(prefix, (const char **)argv), &opt); | ||||
| 	opt.output_format = DIFF_FORMAT_CALLBACK; | ||||
| 	opt.format_callback = update_index_from_diff; | ||||
| 	opt.format_callback_data = &cb; | ||||
|  | ||||
| 	index_fd = hold_locked_index(lock, 1); | ||||
| 	cb.lock = xcalloc(1, sizeof(struct lock_file)); | ||||
| 	cb.index_fd = hold_locked_index(cb.lock, 1); | ||||
| 	cb.exit_code = 0; | ||||
| 	read_cache(); | ||||
| 	if (do_diff_cache(tree_sha1, &opt)) | ||||
| 		return 1; | ||||
| 	diffcore_std(&opt); | ||||
| 	diff_flush(&opt); | ||||
| 	return write_cache(index_fd, active_cache, active_nr) || | ||||
| 		close(index_fd) || | ||||
| 		commit_locked_index(lock); | ||||
|  | ||||
| 	return cb.exit_code; | ||||
| } | ||||
|  | ||||
| static void prepend_reflog_action(const char *action, char *buf, size_t size) | ||||
|  | @ -173,7 +185,7 @@ static const char *reset_type_names[] = { "mixed", "soft", "hard", NULL }; | |||
|  | ||||
| int cmd_reset(int argc, const char **argv, const char *prefix) | ||||
| { | ||||
| 	int i = 1, reset_type = NONE, update_ref_status = 0; | ||||
| 	int i = 1, reset_type = NONE, update_ref_status = 0, quiet = 0; | ||||
| 	const char *rev = "HEAD"; | ||||
| 	unsigned char sha1[20], *orig = NULL, sha1_orig[20], | ||||
| 				*old_orig = NULL, sha1_old_orig[20]; | ||||
|  | @ -185,7 +197,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) | |||
| 	reflog_action = args_to_str(argv); | ||||
| 	setenv("GIT_REFLOG_ACTION", reflog_action, 0); | ||||
|  | ||||
| 	if (i < argc) { | ||||
| 	while (i < argc) { | ||||
| 		if (!strcmp(argv[i], "--mixed")) { | ||||
| 			reset_type = MIXED; | ||||
| 			i++; | ||||
|  | @ -198,6 +210,12 @@ int cmd_reset(int argc, const char **argv, const char *prefix) | |||
| 			reset_type = HARD; | ||||
| 			i++; | ||||
| 		} | ||||
| 		else if (!strcmp(argv[i], "-q")) { | ||||
| 			quiet = 1; | ||||
| 			i++; | ||||
| 		} | ||||
| 		else | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| 	if (i < argc && argv[i][0] != '-') | ||||
|  | @ -258,7 +276,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) | |||
|  | ||||
| 	switch (reset_type) { | ||||
| 	case HARD: | ||||
| 		if (!update_ref_status) | ||||
| 		if (!update_ref_status && !quiet) | ||||
| 			print_new_head_line(commit); | ||||
| 		break; | ||||
| 	case SOFT: /* Nothing else to do. */ | ||||
|  |  | |||
|  | @ -86,7 +86,8 @@ static void show_commit(struct commit *commit) | |||
| 		struct strbuf buf; | ||||
| 		strbuf_init(&buf, 0); | ||||
| 		pretty_print_commit(revs.commit_format, commit, | ||||
| 					&buf, revs.abbrev, NULL, NULL, revs.date_mode); | ||||
| 				    &buf, revs.abbrev, NULL, NULL, | ||||
| 				    revs.date_mode, 0); | ||||
| 		if (buf.len) | ||||
| 			printf("%s%c", buf.buf, hdr_termination); | ||||
| 		strbuf_release(&buf); | ||||
|  |  | |||
|  | @ -30,7 +30,7 @@ static const char * const cherry_pick_usage[] = { | |||
| 	NULL | ||||
| }; | ||||
|  | ||||
| static int edit, no_replay, no_commit, needed_deref; | ||||
| static int edit, no_replay, no_commit, needed_deref, mainline; | ||||
| static enum { REVERT, CHERRY_PICK } action; | ||||
| static struct commit *commit; | ||||
|  | ||||
|  | @ -50,12 +50,14 @@ static void parse_args(int argc, const char **argv) | |||
| 		OPT_BOOLEAN('e', "edit", &edit, "edit the commit message"), | ||||
| 		OPT_BOOLEAN('x', NULL, &no_replay, "append commit name when cherry-picking"), | ||||
| 		OPT_BOOLEAN('r', NULL, &noop, "no-op (backward compatibility)"), | ||||
| 		OPT_INTEGER('m', "mainline", &mainline, "parent number"), | ||||
| 		OPT_END(), | ||||
| 	}; | ||||
|  | ||||
| 	if (parse_options(argc, argv, options, usage_str, 0) != 1) | ||||
| 		usage_with_options(usage_str, options); | ||||
| 	arg = argv[0]; | ||||
|  | ||||
| 	if (get_sha1(arg, sha1)) | ||||
| 		die ("Cannot find '%s'", arg); | ||||
| 	commit = (struct commit *)parse_object(sha1); | ||||
|  | @ -226,7 +228,7 @@ static int merge_recursive(const char *base_sha1, | |||
| static int revert_or_cherry_pick(int argc, const char **argv) | ||||
| { | ||||
| 	unsigned char head[20]; | ||||
| 	struct commit *base, *next; | ||||
| 	struct commit *base, *next, *parent; | ||||
| 	int i; | ||||
| 	char *oneline, *reencoded_message = NULL; | ||||
| 	const char *message, *encoding; | ||||
|  | @ -261,8 +263,29 @@ static int revert_or_cherry_pick(int argc, const char **argv) | |||
|  | ||||
| 	if (!commit->parents) | ||||
| 		die ("Cannot %s a root commit", me); | ||||
| 	if (commit->parents->next) | ||||
| 		die ("Cannot %s a multi-parent commit.", me); | ||||
| 	if (commit->parents->next) { | ||||
| 		/* Reverting or cherry-picking a merge commit */ | ||||
| 		int cnt; | ||||
| 		struct commit_list *p; | ||||
|  | ||||
| 		if (!mainline) | ||||
| 			die("Commit %s is a merge but no -m option was given.", | ||||
| 			    sha1_to_hex(commit->object.sha1)); | ||||
|  | ||||
| 		for (cnt = 1, p = commit->parents; | ||||
| 		     cnt != mainline && p; | ||||
| 		     cnt++) | ||||
| 			p = p->next; | ||||
| 		if (cnt != mainline || !p) | ||||
| 			die("Commit %s does not have parent %d", | ||||
| 			    sha1_to_hex(commit->object.sha1), mainline); | ||||
| 		parent = p->item; | ||||
| 	} else if (0 < mainline) | ||||
| 		die("Mainline was specified but commit %s is not a merge.", | ||||
| 		    sha1_to_hex(commit->object.sha1)); | ||||
| 	else | ||||
| 		parent = commit->parents->item; | ||||
|  | ||||
| 	if (!(message = commit->buffer)) | ||||
| 		die ("Cannot get commit message for %s", | ||||
| 				sha1_to_hex(commit->object.sha1)); | ||||
|  | @ -291,14 +314,14 @@ static int revert_or_cherry_pick(int argc, const char **argv) | |||
| 		char *oneline_body = strchr(oneline, ' '); | ||||
|  | ||||
| 		base = commit; | ||||
| 		next = commit->parents->item; | ||||
| 		next = parent; | ||||
| 		add_to_msg("Revert \""); | ||||
| 		add_to_msg(oneline_body + 1); | ||||
| 		add_to_msg("\"\n\nThis reverts commit "); | ||||
| 		add_to_msg(sha1_to_hex(commit->object.sha1)); | ||||
| 		add_to_msg(".\n"); | ||||
| 	} else { | ||||
| 		base = commit->parents->item; | ||||
| 		base = parent; | ||||
| 		next = commit; | ||||
| 		set_author_ident_env(message); | ||||
| 		add_message_to_msg(message); | ||||
|  |  | |||
|  | @ -155,6 +155,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix) | |||
| 	if (!argc) | ||||
| 		usage_with_options(builtin_rm_usage, builtin_rm_options); | ||||
|  | ||||
| 	if (!index_only) | ||||
| 		setup_work_tree(); | ||||
|  | ||||
| 	pathspec = get_pathspec(prefix, argv); | ||||
| 	seen = NULL; | ||||
| 	for (i = 0; pathspec[i] ; i++) | ||||
|  |  | |||
|  | @ -266,7 +266,7 @@ static void show_one_commit(struct commit *commit, int no_name) | |||
| 	strbuf_init(&pretty, 0); | ||||
| 	if (commit->object.parsed) { | ||||
| 		pretty_print_commit(CMIT_FMT_ONELINE, commit, | ||||
| 					&pretty, 0, NULL, NULL, 0); | ||||
| 				    &pretty, 0, NULL, NULL, 0, 0); | ||||
| 		pretty_str = pretty.buf; | ||||
| 	} | ||||
| 	if (!prefixcmp(pretty_str, "[PATCH] ")) | ||||
|  |  | |||
|  | @ -81,17 +81,16 @@ static int show_reference(const char *refname, const unsigned char *sha1, | |||
| 		} | ||||
| 		printf("%-15s ", refname); | ||||
|  | ||||
| 		sp = buf = read_sha1_file(sha1, &type, &size); | ||||
| 		if (!buf) | ||||
| 		buf = read_sha1_file(sha1, &type, &size); | ||||
| 		if (!buf || !size) | ||||
| 			return 0; | ||||
| 		if (!size) { | ||||
|  | ||||
| 		/* skip header */ | ||||
| 		sp = strstr(buf, "\n\n"); | ||||
| 		if (!sp) { | ||||
| 			free(buf); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		/* skip header */ | ||||
| 		while (sp + 1 < buf + size && | ||||
| 				!(sp[0] == '\n' && sp[1] == '\n')) | ||||
| 			sp++; | ||||
| 		/* only take up to "lines" lines, and strip the signature */ | ||||
| 		for (i = 0, sp += 2; | ||||
| 				i < filter->lines && sp < buf + size && | ||||
|  |  | |||
							
								
								
									
										3
									
								
								bundle.c
								
								
								
								
							
							
						
						
									
										3
									
								
								bundle.c
								
								
								
								
							|  | @ -23,7 +23,8 @@ static void add_to_ref_list(const unsigned char *sha1, const char *name, | |||
| } | ||||
|  | ||||
| /* returns an fd */ | ||||
| int read_bundle_header(const char *path, struct bundle_header *header) { | ||||
| int read_bundle_header(const char *path, struct bundle_header *header) | ||||
| { | ||||
| 	char buffer[1024]; | ||||
| 	int fd; | ||||
| 	long fpos; | ||||
|  |  | |||
							
								
								
									
										3
									
								
								cache.h
								
								
								
								
							
							
						
						
									
										3
									
								
								cache.h
								
								
								
								
							|  | @ -7,7 +7,7 @@ | |||
| #include SHA1_HEADER | ||||
| #include <zlib.h> | ||||
|  | ||||
| #if ZLIB_VERNUM < 0x1200 | ||||
| #if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200 | ||||
| #define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11) | ||||
| #endif | ||||
|  | ||||
|  | @ -222,6 +222,7 @@ extern const char *get_git_work_tree(void); | |||
| #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES" | ||||
|  | ||||
| extern const char **get_pathspec(const char *prefix, const char **pathspec); | ||||
| extern void setup_work_tree(void); | ||||
| extern const char *setup_git_directory_gently(int *); | ||||
| extern const char *setup_git_directory(void); | ||||
| extern const char *prefix_path(const char *prefix, int len, const char *path); | ||||
|  |  | |||
							
								
								
									
										719
									
								
								commit.c
								
								
								
								
							
							
						
						
									
										719
									
								
								commit.c
								
								
								
								
							|  | @ -3,7 +3,6 @@ | |||
| #include "commit.h" | ||||
| #include "pkt-line.h" | ||||
| #include "utf8.h" | ||||
| #include "interpolate.h" | ||||
| #include "diff.h" | ||||
| #include "revision.h" | ||||
|  | ||||
|  | @ -27,46 +26,6 @@ struct sort_node | |||
|  | ||||
| const char *commit_type = "commit"; | ||||
|  | ||||
| static struct cmt_fmt_map { | ||||
| 	const char *n; | ||||
| 	size_t cmp_len; | ||||
| 	enum cmit_fmt v; | ||||
| } cmt_fmts[] = { | ||||
| 	{ "raw",	1,	CMIT_FMT_RAW }, | ||||
| 	{ "medium",	1,	CMIT_FMT_MEDIUM }, | ||||
| 	{ "short",	1,	CMIT_FMT_SHORT }, | ||||
| 	{ "email",	1,	CMIT_FMT_EMAIL }, | ||||
| 	{ "full",	5,	CMIT_FMT_FULL }, | ||||
| 	{ "fuller",	5,	CMIT_FMT_FULLER }, | ||||
| 	{ "oneline",	1,	CMIT_FMT_ONELINE }, | ||||
| 	{ "format:",	7,	CMIT_FMT_USERFORMAT}, | ||||
| }; | ||||
|  | ||||
| static char *user_format; | ||||
|  | ||||
| enum cmit_fmt get_commit_format(const char *arg) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	if (!arg || !*arg) | ||||
| 		return CMIT_FMT_DEFAULT; | ||||
| 	if (*arg == '=') | ||||
| 		arg++; | ||||
| 	if (!prefixcmp(arg, "format:")) { | ||||
| 		if (user_format) | ||||
| 			free(user_format); | ||||
| 		user_format = xstrdup(arg + 7); | ||||
| 		return CMIT_FMT_USERFORMAT; | ||||
| 	} | ||||
| 	for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) { | ||||
| 		if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) && | ||||
| 		    !strncmp(arg, cmt_fmts[i].n, strlen(arg))) | ||||
| 			return cmt_fmts[i].v; | ||||
| 	} | ||||
|  | ||||
| 	die("invalid --pretty format: %s", arg); | ||||
| } | ||||
|  | ||||
| static struct commit *check_commit(struct object *obj, | ||||
| 				   const unsigned char *sha1, | ||||
| 				   int quiet) | ||||
|  | @ -460,684 +419,6 @@ void clear_commit_marks(struct commit *commit, unsigned int mark) | |||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Generic support for pretty-printing the header | ||||
|  */ | ||||
| static int get_one_line(const char *msg) | ||||
| { | ||||
| 	int ret = 0; | ||||
|  | ||||
| 	for (;;) { | ||||
| 		char c = *msg++; | ||||
| 		if (!c) | ||||
| 			break; | ||||
| 		ret++; | ||||
| 		if (c == '\n') | ||||
| 			break; | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* High bit set, or ISO-2022-INT */ | ||||
| static int non_ascii(int ch) | ||||
| { | ||||
| 	ch = (ch & 0xff); | ||||
| 	return ((ch & 0x80) || (ch == 0x1b)); | ||||
| } | ||||
|  | ||||
| static int is_rfc2047_special(char ch) | ||||
| { | ||||
| 	return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_')); | ||||
| } | ||||
|  | ||||
| static void add_rfc2047(struct strbuf *sb, const char *line, int len, | ||||
| 		       const char *encoding) | ||||
| { | ||||
| 	int i, last; | ||||
|  | ||||
| 	for (i = 0; i < len; i++) { | ||||
| 		int ch = line[i]; | ||||
| 		if (non_ascii(ch)) | ||||
| 			goto needquote; | ||||
| 		if ((i + 1 < len) && (ch == '=' && line[i+1] == '?')) | ||||
| 			goto needquote; | ||||
| 	} | ||||
| 	strbuf_add(sb, line, len); | ||||
| 	return; | ||||
|  | ||||
| needquote: | ||||
| 	strbuf_grow(sb, len * 3 + strlen(encoding) + 100); | ||||
| 	strbuf_addf(sb, "=?%s?q?", encoding); | ||||
| 	for (i = last = 0; i < len; i++) { | ||||
| 		unsigned ch = line[i] & 0xFF; | ||||
| 		/* | ||||
| 		 * We encode ' ' using '=20' even though rfc2047 | ||||
| 		 * allows using '_' for readability.  Unfortunately, | ||||
| 		 * many programs do not understand this and just | ||||
| 		 * leave the underscore in place. | ||||
| 		 */ | ||||
| 		if (is_rfc2047_special(ch) || ch == ' ') { | ||||
| 			strbuf_add(sb, line + last, i - last); | ||||
| 			strbuf_addf(sb, "=%02X", ch); | ||||
| 			last = i + 1; | ||||
| 		} | ||||
| 	} | ||||
| 	strbuf_add(sb, line + last, len - last); | ||||
| 	strbuf_addstr(sb, "?="); | ||||
| } | ||||
|  | ||||
| static void add_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb, | ||||
| 			 const char *line, enum date_mode dmode, | ||||
| 			 const char *encoding) | ||||
| { | ||||
| 	char *date; | ||||
| 	int namelen; | ||||
| 	unsigned long time; | ||||
| 	int tz; | ||||
| 	const char *filler = "    "; | ||||
|  | ||||
| 	if (fmt == CMIT_FMT_ONELINE) | ||||
| 		return; | ||||
| 	date = strchr(line, '>'); | ||||
| 	if (!date) | ||||
| 		return; | ||||
| 	namelen = ++date - line; | ||||
| 	time = strtoul(date, &date, 10); | ||||
| 	tz = strtol(date, NULL, 10); | ||||
|  | ||||
| 	if (fmt == CMIT_FMT_EMAIL) { | ||||
| 		char *name_tail = strchr(line, '<'); | ||||
| 		int display_name_length; | ||||
| 		if (!name_tail) | ||||
| 			return; | ||||
| 		while (line < name_tail && isspace(name_tail[-1])) | ||||
| 			name_tail--; | ||||
| 		display_name_length = name_tail - line; | ||||
| 		filler = ""; | ||||
| 		strbuf_addstr(sb, "From: "); | ||||
| 		add_rfc2047(sb, line, display_name_length, encoding); | ||||
| 		strbuf_add(sb, name_tail, namelen - display_name_length); | ||||
| 		strbuf_addch(sb, '\n'); | ||||
| 	} else { | ||||
| 		strbuf_addf(sb, "%s: %.*s%.*s\n", what, | ||||
| 			      (fmt == CMIT_FMT_FULLER) ? 4 : 0, | ||||
| 			      filler, namelen, line); | ||||
| 	} | ||||
| 	switch (fmt) { | ||||
| 	case CMIT_FMT_MEDIUM: | ||||
| 		strbuf_addf(sb, "Date:   %s\n", show_date(time, tz, dmode)); | ||||
| 		break; | ||||
| 	case CMIT_FMT_EMAIL: | ||||
| 		strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822)); | ||||
| 		break; | ||||
| 	case CMIT_FMT_FULLER: | ||||
| 		strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, dmode)); | ||||
| 		break; | ||||
| 	default: | ||||
| 		/* notin' */ | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int is_empty_line(const char *line, int *len_p) | ||||
| { | ||||
| 	int len = *len_p; | ||||
| 	while (len && isspace(line[len-1])) | ||||
| 		len--; | ||||
| 	*len_p = len; | ||||
| 	return !len; | ||||
| } | ||||
|  | ||||
| static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb, | ||||
| 			const struct commit *commit, int abbrev) | ||||
| { | ||||
| 	struct commit_list *parent = commit->parents; | ||||
|  | ||||
| 	if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) || | ||||
| 	    !parent || !parent->next) | ||||
| 		return; | ||||
|  | ||||
| 	strbuf_addstr(sb, "Merge:"); | ||||
|  | ||||
| 	while (parent) { | ||||
| 		struct commit *p = parent->item; | ||||
| 		const char *hex = NULL; | ||||
| 		const char *dots; | ||||
| 		if (abbrev) | ||||
| 			hex = find_unique_abbrev(p->object.sha1, abbrev); | ||||
| 		if (!hex) | ||||
| 			hex = sha1_to_hex(p->object.sha1); | ||||
| 		dots = (abbrev && strlen(hex) != 40) ?  "..." : ""; | ||||
| 		parent = parent->next; | ||||
|  | ||||
| 		strbuf_addf(sb, " %s%s", hex, dots); | ||||
| 	} | ||||
| 	strbuf_addch(sb, '\n'); | ||||
| } | ||||
|  | ||||
| static char *get_header(const struct commit *commit, const char *key) | ||||
| { | ||||
| 	int key_len = strlen(key); | ||||
| 	const char *line = commit->buffer; | ||||
|  | ||||
| 	for (;;) { | ||||
| 		const char *eol = strchr(line, '\n'), *next; | ||||
|  | ||||
| 		if (line == eol) | ||||
| 			return NULL; | ||||
| 		if (!eol) { | ||||
| 			eol = line + strlen(line); | ||||
| 			next = NULL; | ||||
| 		} else | ||||
| 			next = eol + 1; | ||||
| 		if (eol - line > key_len && | ||||
| 		    !strncmp(line, key, key_len) && | ||||
| 		    line[key_len] == ' ') { | ||||
| 			return xmemdupz(line + key_len + 1, eol - line - key_len - 1); | ||||
| 		} | ||||
| 		line = next; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static char *replace_encoding_header(char *buf, const char *encoding) | ||||
| { | ||||
| 	struct strbuf tmp; | ||||
| 	size_t start, len; | ||||
| 	char *cp = buf; | ||||
|  | ||||
| 	/* guess if there is an encoding header before a \n\n */ | ||||
| 	while (strncmp(cp, "encoding ", strlen("encoding "))) { | ||||
| 		cp = strchr(cp, '\n'); | ||||
| 		if (!cp || *++cp == '\n') | ||||
| 			return buf; | ||||
| 	} | ||||
| 	start = cp - buf; | ||||
| 	cp = strchr(cp, '\n'); | ||||
| 	if (!cp) | ||||
| 		return buf; /* should not happen but be defensive */ | ||||
| 	len = cp + 1 - (buf + start); | ||||
|  | ||||
| 	strbuf_init(&tmp, 0); | ||||
| 	strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1); | ||||
| 	if (is_encoding_utf8(encoding)) { | ||||
| 		/* we have re-coded to UTF-8; drop the header */ | ||||
| 		strbuf_remove(&tmp, start, len); | ||||
| 	} else { | ||||
| 		/* just replaces XXXX in 'encoding XXXX\n' */ | ||||
| 		strbuf_splice(&tmp, start + strlen("encoding "), | ||||
| 					  len - strlen("encoding \n"), | ||||
| 					  encoding, strlen(encoding)); | ||||
| 	} | ||||
| 	return strbuf_detach(&tmp, NULL); | ||||
| } | ||||
|  | ||||
| static char *logmsg_reencode(const struct commit *commit, | ||||
| 			     const char *output_encoding) | ||||
| { | ||||
| 	static const char *utf8 = "utf-8"; | ||||
| 	const char *use_encoding; | ||||
| 	char *encoding; | ||||
| 	char *out; | ||||
|  | ||||
| 	if (!*output_encoding) | ||||
| 		return NULL; | ||||
| 	encoding = get_header(commit, "encoding"); | ||||
| 	use_encoding = encoding ? encoding : utf8; | ||||
| 	if (!strcmp(use_encoding, output_encoding)) | ||||
| 		if (encoding) /* we'll strip encoding header later */ | ||||
| 			out = xstrdup(commit->buffer); | ||||
| 		else | ||||
| 			return NULL; /* nothing to do */ | ||||
| 	else | ||||
| 		out = reencode_string(commit->buffer, | ||||
| 				      output_encoding, use_encoding); | ||||
| 	if (out) | ||||
| 		out = replace_encoding_header(out, output_encoding); | ||||
|  | ||||
| 	free(encoding); | ||||
| 	return out; | ||||
| } | ||||
|  | ||||
| static void fill_person(struct interp *table, const char *msg, int len) | ||||
| { | ||||
| 	int start, end, tz = 0; | ||||
| 	unsigned long date; | ||||
| 	char *ep; | ||||
|  | ||||
| 	/* parse name */ | ||||
| 	for (end = 0; end < len && msg[end] != '<'; end++) | ||||
| 		; /* do nothing */ | ||||
| 	start = end + 1; | ||||
| 	while (end > 0 && isspace(msg[end - 1])) | ||||
| 		end--; | ||||
| 	table[0].value = xmemdupz(msg, end); | ||||
|  | ||||
| 	if (start >= len) | ||||
| 		return; | ||||
|  | ||||
| 	/* parse email */ | ||||
| 	for (end = start + 1; end < len && msg[end] != '>'; end++) | ||||
| 		; /* do nothing */ | ||||
|  | ||||
| 	if (end >= len) | ||||
| 		return; | ||||
|  | ||||
| 	table[1].value = xmemdupz(msg + start, end - start); | ||||
|  | ||||
| 	/* parse date */ | ||||
| 	for (start = end + 1; start < len && isspace(msg[start]); start++) | ||||
| 		; /* do nothing */ | ||||
| 	if (start >= len) | ||||
| 		return; | ||||
| 	date = strtoul(msg + start, &ep, 10); | ||||
| 	if (msg + start == ep) | ||||
| 		return; | ||||
|  | ||||
| 	table[5].value = xmemdupz(msg + start, ep - (msg + start)); | ||||
|  | ||||
| 	/* parse tz */ | ||||
| 	for (start = ep - msg + 1; start < len && isspace(msg[start]); start++) | ||||
| 		; /* do nothing */ | ||||
| 	if (start + 1 < len) { | ||||
| 		tz = strtoul(msg + start + 1, NULL, 10); | ||||
| 		if (msg[start] == '-') | ||||
| 			tz = -tz; | ||||
| 	} | ||||
|  | ||||
| 	interp_set_entry(table, 2, show_date(date, tz, DATE_NORMAL)); | ||||
| 	interp_set_entry(table, 3, show_date(date, tz, DATE_RFC2822)); | ||||
| 	interp_set_entry(table, 4, show_date(date, tz, DATE_RELATIVE)); | ||||
| 	interp_set_entry(table, 6, show_date(date, tz, DATE_ISO8601)); | ||||
| } | ||||
|  | ||||
| void format_commit_message(const struct commit *commit, | ||||
|                            const void *format, struct strbuf *sb) | ||||
| { | ||||
| 	struct interp table[] = { | ||||
| 		{ "%H" },	/* commit hash */ | ||||
| 		{ "%h" },	/* abbreviated commit hash */ | ||||
| 		{ "%T" },	/* tree hash */ | ||||
| 		{ "%t" },	/* abbreviated tree hash */ | ||||
| 		{ "%P" },	/* parent hashes */ | ||||
| 		{ "%p" },	/* abbreviated parent hashes */ | ||||
| 		{ "%an" },	/* author name */ | ||||
| 		{ "%ae" },	/* author email */ | ||||
| 		{ "%ad" },	/* author date */ | ||||
| 		{ "%aD" },	/* author date, RFC2822 style */ | ||||
| 		{ "%ar" },	/* author date, relative */ | ||||
| 		{ "%at" },	/* author date, UNIX timestamp */ | ||||
| 		{ "%ai" },	/* author date, ISO 8601 */ | ||||
| 		{ "%cn" },	/* committer name */ | ||||
| 		{ "%ce" },	/* committer email */ | ||||
| 		{ "%cd" },	/* committer date */ | ||||
| 		{ "%cD" },	/* committer date, RFC2822 style */ | ||||
| 		{ "%cr" },	/* committer date, relative */ | ||||
| 		{ "%ct" },	/* committer date, UNIX timestamp */ | ||||
| 		{ "%ci" },	/* committer date, ISO 8601 */ | ||||
| 		{ "%e" },	/* encoding */ | ||||
| 		{ "%s" },	/* subject */ | ||||
| 		{ "%b" },	/* body */ | ||||
| 		{ "%Cred" },	/* red */ | ||||
| 		{ "%Cgreen" },	/* green */ | ||||
| 		{ "%Cblue" },	/* blue */ | ||||
| 		{ "%Creset" },	/* reset color */ | ||||
| 		{ "%n" },	/* newline */ | ||||
| 		{ "%m" },	/* left/right/bottom */ | ||||
| 	}; | ||||
| 	enum interp_index { | ||||
| 		IHASH = 0, IHASH_ABBREV, | ||||
| 		ITREE, ITREE_ABBREV, | ||||
| 		IPARENTS, IPARENTS_ABBREV, | ||||
| 		IAUTHOR_NAME, IAUTHOR_EMAIL, | ||||
| 		IAUTHOR_DATE, IAUTHOR_DATE_RFC2822, IAUTHOR_DATE_RELATIVE, | ||||
| 		IAUTHOR_TIMESTAMP, IAUTHOR_ISO8601, | ||||
| 		ICOMMITTER_NAME, ICOMMITTER_EMAIL, | ||||
| 		ICOMMITTER_DATE, ICOMMITTER_DATE_RFC2822, | ||||
| 		ICOMMITTER_DATE_RELATIVE, ICOMMITTER_TIMESTAMP, | ||||
| 		ICOMMITTER_ISO8601, | ||||
| 		IENCODING, | ||||
| 		ISUBJECT, | ||||
| 		IBODY, | ||||
| 		IRED, IGREEN, IBLUE, IRESET_COLOR, | ||||
| 		INEWLINE, | ||||
| 		ILEFT_RIGHT, | ||||
| 	}; | ||||
| 	struct commit_list *p; | ||||
| 	char parents[1024]; | ||||
| 	unsigned long len; | ||||
| 	int i; | ||||
| 	enum { HEADER, SUBJECT, BODY } state; | ||||
| 	const char *msg = commit->buffer; | ||||
|  | ||||
| 	if (ILEFT_RIGHT + 1 != ARRAY_SIZE(table)) | ||||
| 		die("invalid interp table!"); | ||||
|  | ||||
| 	/* these are independent of the commit */ | ||||
| 	interp_set_entry(table, IRED, "\033[31m"); | ||||
| 	interp_set_entry(table, IGREEN, "\033[32m"); | ||||
| 	interp_set_entry(table, IBLUE, "\033[34m"); | ||||
| 	interp_set_entry(table, IRESET_COLOR, "\033[m"); | ||||
| 	interp_set_entry(table, INEWLINE, "\n"); | ||||
|  | ||||
| 	/* these depend on the commit */ | ||||
| 	if (!commit->object.parsed) | ||||
| 		parse_object(commit->object.sha1); | ||||
| 	interp_set_entry(table, IHASH, sha1_to_hex(commit->object.sha1)); | ||||
| 	interp_set_entry(table, IHASH_ABBREV, | ||||
| 			find_unique_abbrev(commit->object.sha1, | ||||
| 				DEFAULT_ABBREV)); | ||||
| 	interp_set_entry(table, ITREE, sha1_to_hex(commit->tree->object.sha1)); | ||||
| 	interp_set_entry(table, ITREE_ABBREV, | ||||
| 			find_unique_abbrev(commit->tree->object.sha1, | ||||
| 				DEFAULT_ABBREV)); | ||||
| 	interp_set_entry(table, ILEFT_RIGHT, | ||||
| 			 (commit->object.flags & BOUNDARY) | ||||
| 			 ? "-" | ||||
| 			 : (commit->object.flags & SYMMETRIC_LEFT) | ||||
| 			 ? "<" | ||||
| 			 : ">"); | ||||
|  | ||||
| 	parents[1] = 0; | ||||
| 	for (i = 0, p = commit->parents; | ||||
| 			p && i < sizeof(parents) - 1; | ||||
| 			p = p->next) | ||||
| 		i += snprintf(parents + i, sizeof(parents) - i - 1, " %s", | ||||
| 			sha1_to_hex(p->item->object.sha1)); | ||||
| 	interp_set_entry(table, IPARENTS, parents + 1); | ||||
|  | ||||
| 	parents[1] = 0; | ||||
| 	for (i = 0, p = commit->parents; | ||||
| 			p && i < sizeof(parents) - 1; | ||||
| 			p = p->next) | ||||
| 		i += snprintf(parents + i, sizeof(parents) - i - 1, " %s", | ||||
| 			find_unique_abbrev(p->item->object.sha1, | ||||
| 				DEFAULT_ABBREV)); | ||||
| 	interp_set_entry(table, IPARENTS_ABBREV, parents + 1); | ||||
|  | ||||
| 	for (i = 0, state = HEADER; msg[i] && state < BODY; i++) { | ||||
| 		int eol; | ||||
| 		for (eol = i; msg[eol] && msg[eol] != '\n'; eol++) | ||||
| 			; /* do nothing */ | ||||
|  | ||||
| 		if (state == SUBJECT) { | ||||
| 			table[ISUBJECT].value = xmemdupz(msg + i, eol - i); | ||||
| 			i = eol; | ||||
| 		} | ||||
| 		if (i == eol) { | ||||
| 			state++; | ||||
| 			/* strip empty lines */ | ||||
| 			while (msg[eol + 1] == '\n') | ||||
| 				eol++; | ||||
| 		} else if (!prefixcmp(msg + i, "author ")) | ||||
| 			fill_person(table + IAUTHOR_NAME, | ||||
| 					msg + i + 7, eol - i - 7); | ||||
| 		else if (!prefixcmp(msg + i, "committer ")) | ||||
| 			fill_person(table + ICOMMITTER_NAME, | ||||
| 					msg + i + 10, eol - i - 10); | ||||
| 		else if (!prefixcmp(msg + i, "encoding ")) | ||||
| 			table[IENCODING].value = | ||||
| 				xmemdupz(msg + i + 9, eol - i - 9); | ||||
| 		i = eol; | ||||
| 	} | ||||
| 	if (msg[i]) | ||||
| 		table[IBODY].value = xstrdup(msg + i); | ||||
|  | ||||
| 	len = interpolate(sb->buf + sb->len, strbuf_avail(sb), | ||||
| 				format, table, ARRAY_SIZE(table)); | ||||
| 	if (len > strbuf_avail(sb)) { | ||||
| 		strbuf_grow(sb, len); | ||||
| 		interpolate(sb->buf + sb->len, strbuf_avail(sb) + 1, | ||||
| 					format, table, ARRAY_SIZE(table)); | ||||
| 	} | ||||
| 	strbuf_setlen(sb, sb->len + len); | ||||
| 	interp_clear_table(table, ARRAY_SIZE(table)); | ||||
| } | ||||
|  | ||||
| static void pp_header(enum cmit_fmt fmt, | ||||
| 		      int abbrev, | ||||
| 		      enum date_mode dmode, | ||||
| 		      const char *encoding, | ||||
| 		      const struct commit *commit, | ||||
| 		      const char **msg_p, | ||||
| 		      struct strbuf *sb) | ||||
| { | ||||
| 	int parents_shown = 0; | ||||
|  | ||||
| 	for (;;) { | ||||
| 		const char *line = *msg_p; | ||||
| 		int linelen = get_one_line(*msg_p); | ||||
|  | ||||
| 		if (!linelen) | ||||
| 			return; | ||||
| 		*msg_p += linelen; | ||||
|  | ||||
| 		if (linelen == 1) | ||||
| 			/* End of header */ | ||||
| 			return; | ||||
|  | ||||
| 		if (fmt == CMIT_FMT_RAW) { | ||||
| 			strbuf_add(sb, line, linelen); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (!memcmp(line, "parent ", 7)) { | ||||
| 			if (linelen != 48) | ||||
| 				die("bad parent line in commit"); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (!parents_shown) { | ||||
| 			struct commit_list *parent; | ||||
| 			int num; | ||||
| 			for (parent = commit->parents, num = 0; | ||||
| 			     parent; | ||||
| 			     parent = parent->next, num++) | ||||
| 				; | ||||
| 			/* with enough slop */ | ||||
| 			strbuf_grow(sb, num * 50 + 20); | ||||
| 			add_merge_info(fmt, sb, commit, abbrev); | ||||
| 			parents_shown = 1; | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		 * MEDIUM == DEFAULT shows only author with dates. | ||||
| 		 * FULL shows both authors but not dates. | ||||
| 		 * FULLER shows both authors and dates. | ||||
| 		 */ | ||||
| 		if (!memcmp(line, "author ", 7)) { | ||||
| 			strbuf_grow(sb, linelen + 80); | ||||
| 			add_user_info("Author", fmt, sb, line + 7, dmode, encoding); | ||||
| 		} | ||||
| 		if (!memcmp(line, "committer ", 10) && | ||||
| 		    (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) { | ||||
| 			strbuf_grow(sb, linelen + 80); | ||||
| 			add_user_info("Commit", fmt, sb, line + 10, dmode, encoding); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void pp_title_line(enum cmit_fmt fmt, | ||||
| 			  const char **msg_p, | ||||
| 			  struct strbuf *sb, | ||||
| 			  const char *subject, | ||||
| 			  const char *after_subject, | ||||
| 			  const char *encoding, | ||||
| 			  int plain_non_ascii) | ||||
| { | ||||
| 	struct strbuf title; | ||||
|  | ||||
| 	strbuf_init(&title, 80); | ||||
|  | ||||
| 	for (;;) { | ||||
| 		const char *line = *msg_p; | ||||
| 		int linelen = get_one_line(line); | ||||
|  | ||||
| 		*msg_p += linelen; | ||||
| 		if (!linelen || is_empty_line(line, &linelen)) | ||||
| 			break; | ||||
|  | ||||
| 		strbuf_grow(&title, linelen + 2); | ||||
| 		if (title.len) { | ||||
| 			if (fmt == CMIT_FMT_EMAIL) { | ||||
| 				strbuf_addch(&title, '\n'); | ||||
| 			} | ||||
| 			strbuf_addch(&title, ' '); | ||||
| 		} | ||||
| 		strbuf_add(&title, line, linelen); | ||||
| 	} | ||||
|  | ||||
| 	strbuf_grow(sb, title.len + 1024); | ||||
| 	if (subject) { | ||||
| 		strbuf_addstr(sb, subject); | ||||
| 		add_rfc2047(sb, title.buf, title.len, encoding); | ||||
| 	} else { | ||||
| 		strbuf_addbuf(sb, &title); | ||||
| 	} | ||||
| 	strbuf_addch(sb, '\n'); | ||||
|  | ||||
| 	if (plain_non_ascii) { | ||||
| 		const char *header_fmt = | ||||
| 			"MIME-Version: 1.0\n" | ||||
| 			"Content-Type: text/plain; charset=%s\n" | ||||
| 			"Content-Transfer-Encoding: 8bit\n"; | ||||
| 		strbuf_addf(sb, header_fmt, encoding); | ||||
| 	} | ||||
| 	if (after_subject) { | ||||
| 		strbuf_addstr(sb, after_subject); | ||||
| 	} | ||||
| 	if (fmt == CMIT_FMT_EMAIL) { | ||||
| 		strbuf_addch(sb, '\n'); | ||||
| 	} | ||||
| 	strbuf_release(&title); | ||||
| } | ||||
|  | ||||
| static void pp_remainder(enum cmit_fmt fmt, | ||||
| 			 const char **msg_p, | ||||
| 			 struct strbuf *sb, | ||||
| 			 int indent) | ||||
| { | ||||
| 	int first = 1; | ||||
| 	for (;;) { | ||||
| 		const char *line = *msg_p; | ||||
| 		int linelen = get_one_line(line); | ||||
| 		*msg_p += linelen; | ||||
|  | ||||
| 		if (!linelen) | ||||
| 			break; | ||||
|  | ||||
| 		if (is_empty_line(line, &linelen)) { | ||||
| 			if (first) | ||||
| 				continue; | ||||
| 			if (fmt == CMIT_FMT_SHORT) | ||||
| 				break; | ||||
| 		} | ||||
| 		first = 0; | ||||
|  | ||||
| 		strbuf_grow(sb, linelen + indent + 20); | ||||
| 		if (indent) { | ||||
| 			memset(sb->buf + sb->len, ' ', indent); | ||||
| 			strbuf_setlen(sb, sb->len + indent); | ||||
| 		} | ||||
| 		strbuf_add(sb, line, linelen); | ||||
| 		strbuf_addch(sb, '\n'); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, | ||||
| 				  struct strbuf *sb, int abbrev, | ||||
| 				  const char *subject, const char *after_subject, | ||||
| 				  enum date_mode dmode) | ||||
| { | ||||
| 	unsigned long beginning_of_body; | ||||
| 	int indent = 4; | ||||
| 	const char *msg = commit->buffer; | ||||
| 	int plain_non_ascii = 0; | ||||
| 	char *reencoded; | ||||
| 	const char *encoding; | ||||
|  | ||||
| 	if (fmt == CMIT_FMT_USERFORMAT) { | ||||
| 		format_commit_message(commit, user_format, sb); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	encoding = (git_log_output_encoding | ||||
| 		    ? git_log_output_encoding | ||||
| 		    : git_commit_encoding); | ||||
| 	if (!encoding) | ||||
| 		encoding = "utf-8"; | ||||
| 	reencoded = logmsg_reencode(commit, encoding); | ||||
| 	if (reencoded) { | ||||
| 		msg = reencoded; | ||||
| 	} | ||||
|  | ||||
| 	if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) | ||||
| 		indent = 0; | ||||
|  | ||||
| 	/* After-subject is used to pass in Content-Type: multipart | ||||
| 	 * MIME header; in that case we do not have to do the | ||||
| 	 * plaintext content type even if the commit message has | ||||
| 	 * non 7-bit ASCII character.  Otherwise, check if we need | ||||
| 	 * to say this is not a 7-bit ASCII. | ||||
| 	 */ | ||||
| 	if (fmt == CMIT_FMT_EMAIL && !after_subject) { | ||||
| 		int i, ch, in_body; | ||||
|  | ||||
| 		for (in_body = i = 0; (ch = msg[i]); i++) { | ||||
| 			if (!in_body) { | ||||
| 				/* author could be non 7-bit ASCII but | ||||
| 				 * the log may be so; skip over the | ||||
| 				 * header part first. | ||||
| 				 */ | ||||
| 				if (ch == '\n' && msg[i+1] == '\n') | ||||
| 					in_body = 1; | ||||
| 			} | ||||
| 			else if (non_ascii(ch)) { | ||||
| 				plain_non_ascii = 1; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb); | ||||
| 	if (fmt != CMIT_FMT_ONELINE && !subject) { | ||||
| 		strbuf_addch(sb, '\n'); | ||||
| 	} | ||||
|  | ||||
| 	/* Skip excess blank lines at the beginning of body, if any... */ | ||||
| 	for (;;) { | ||||
| 		int linelen = get_one_line(msg); | ||||
| 		int ll = linelen; | ||||
| 		if (!linelen) | ||||
| 			break; | ||||
| 		if (!is_empty_line(msg, &ll)) | ||||
| 			break; | ||||
| 		msg += linelen; | ||||
| 	} | ||||
|  | ||||
| 	/* These formats treat the title line specially. */ | ||||
| 	if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) | ||||
| 		pp_title_line(fmt, &msg, sb, subject, | ||||
| 			      after_subject, encoding, plain_non_ascii); | ||||
|  | ||||
| 	beginning_of_body = sb->len; | ||||
| 	if (fmt != CMIT_FMT_ONELINE) | ||||
| 		pp_remainder(fmt, &msg, sb, indent); | ||||
| 	strbuf_rtrim(sb); | ||||
|  | ||||
| 	/* Make sure there is an EOLN for the non-oneline case */ | ||||
| 	if (fmt != CMIT_FMT_ONELINE) | ||||
| 		strbuf_addch(sb, '\n'); | ||||
|  | ||||
| 	/* | ||||
| 	 * The caller may append additional body text in e-mail | ||||
| 	 * format.  Make sure we did not strip the blank line | ||||
| 	 * between the header and the body. | ||||
| 	 */ | ||||
| 	if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body) | ||||
| 		strbuf_addch(sb, '\n'); | ||||
| 	free(reencoded); | ||||
| } | ||||
|  | ||||
| struct commit *pop_commit(struct commit_list **stack) | ||||
| { | ||||
| 	struct commit_list *top = *stack; | ||||
|  |  | |||
							
								
								
									
										4
									
								
								commit.h
								
								
								
								
							
							
						
						
									
										4
									
								
								commit.h
								
								
								
								
							|  | @ -61,13 +61,15 @@ enum cmit_fmt { | |||
| 	CMIT_FMT_UNSPECIFIED, | ||||
| }; | ||||
|  | ||||
| extern int non_ascii(int); | ||||
| extern enum cmit_fmt get_commit_format(const char *arg); | ||||
| extern void format_commit_message(const struct commit *commit, | ||||
|                                   const void *format, struct strbuf *sb); | ||||
| extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit*, | ||||
|                                 struct strbuf *, | ||||
|                                 int abbrev, const char *subject, | ||||
|                                 const char *after_subject, enum date_mode); | ||||
|                                 const char *after_subject, enum date_mode, | ||||
| 				int non_ascii_present); | ||||
|  | ||||
| /** Removes the first commit from a list sorted by date, and adds all | ||||
|  * of its parents. | ||||
|  |  | |||
|  | @ -18,7 +18,6 @@ | |||
| #include <errno.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/socket.h> | ||||
| #include <netinet/in.h> | ||||
| #include <arpa/inet.h> | ||||
| #include <stdio.h> | ||||
|  |  | |||
|  | @ -18,7 +18,6 @@ | |||
| #include <errno.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/socket.h> | ||||
| #include <netinet/in.h> | ||||
| #include <arpa/inet.h> | ||||
| #include <stdio.h> | ||||
|  |  | |||
|  | @ -38,3 +38,4 @@ NO_STRCASESTR=@NO_STRCASESTR@ | |||
| NO_STRLCPY=@NO_STRLCPY@ | ||||
| NO_SETENV=@NO_SETENV@ | ||||
| NO_ICONV=@NO_ICONV@ | ||||
| NO_DEFLATE_BOUND=@NO_DEFLATE_BOUND@ | ||||
|  |  | |||
							
								
								
									
										26
									
								
								configure.ac
								
								
								
								
							
							
						
						
									
										26
									
								
								configure.ac
								
								
								
								
							|  | @ -73,7 +73,7 @@ fi \ | |||
| AC_ARG_WITH([lib], | ||||
|  [AS_HELP_STRING([--with-lib=ARG], | ||||
|                  [ARG specifies alternative name for lib directory])], | ||||
|  [if test "$withval" = "no" -o "$withval" = "yes"; then \ | ||||
|  [if test "$withval" = "no" || test "$withval" = "yes"; then \ | ||||
| 	AC_MSG_WARN([You should provide name for --with-lib=ARG]); \ | ||||
| else \ | ||||
| 	GIT_CONF_APPEND_LINE(lib=$withval); \ | ||||
|  | @ -182,6 +182,26 @@ AC_SUBST(NEEDS_LIBICONV) | |||
| AC_SUBST(NO_ICONV) | ||||
| test -n "$NEEDS_LIBICONV" && LIBS="$LIBS -liconv" | ||||
| # | ||||
| # Define NO_DEFLATE_BOUND if deflateBound is missing from zlib. | ||||
| AC_DEFUN([ZLIBTEST_SRC], [ | ||||
| #include <zlib.h> | ||||
|  | ||||
| int main(void) | ||||
| { | ||||
| 	deflateBound(0, 0); | ||||
| 	return 0; | ||||
| } | ||||
| ]) | ||||
| AC_MSG_CHECKING([for deflateBound in -lz]) | ||||
| old_LIBS="$LIBS" | ||||
| LIBS="$LIBS -lz" | ||||
| AC_LINK_IFELSE(ZLIBTEST_SRC, | ||||
| 	[AC_MSG_RESULT([yes])], | ||||
| 	[AC_MSG_RESULT([no]) | ||||
| 	NO_DEFLATE_BOUND=yes]) | ||||
| LIBS="$old_LIBS" | ||||
| AC_SUBST(NO_DEFLATE_BOUND) | ||||
| # | ||||
| # Define NEEDS_SOCKET if linking with libc is not enough (SunOS, | ||||
| # Patrick Mauritz). | ||||
| AC_CHECK_LIB([c], [socket], | ||||
|  | @ -245,9 +265,9 @@ AC_RUN_IFELSE( | |||
| 	[AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT], | ||||
| 		[[char buf[64]; | ||||
| 		if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5) | ||||
| 		  exit(1); | ||||
| 		  return 1; | ||||
| 		else if (strcmp(buf, "12345")) | ||||
| 		  exit(2);]])], | ||||
| 		  return 2;]])], | ||||
| 	[ac_cv_c_c99_format=yes], | ||||
| 	[ac_cv_c_c99_format=no]) | ||||
| ]) | ||||
|  |  | |||
|  | @ -71,6 +71,79 @@ def isP4Exec(kind): | |||
|     a plus sign, it is also executable""" | ||||
|     return (re.search(r"(^[cku]?x)|\+.*x", kind) != None) | ||||
|  | ||||
| def setP4ExecBit(file, mode): | ||||
|     # Reopens an already open file and changes the execute bit to match | ||||
|     # the execute bit setting in the passed in mode. | ||||
|  | ||||
|     p4Type = "+x" | ||||
|  | ||||
|     if not isModeExec(mode): | ||||
|         p4Type = getP4OpenedType(file) | ||||
|         p4Type = re.sub('^([cku]?)x(.*)', '\\1\\2', p4Type) | ||||
|         p4Type = re.sub('(.*?\+.*?)x(.*?)', '\\1\\2', p4Type) | ||||
|         if p4Type[-1] == "+": | ||||
|             p4Type = p4Type[0:-1] | ||||
|  | ||||
|     system("p4 reopen -t %s %s" % (p4Type, file)) | ||||
|  | ||||
| def getP4OpenedType(file): | ||||
|     # Returns the perforce file type for the given file. | ||||
|  | ||||
|     result = read_pipe("p4 opened %s" % file) | ||||
|     match = re.match(".*\((.+)\)$", result) | ||||
|     if match: | ||||
|         return match.group(1) | ||||
|     else: | ||||
|         die("Could not determine file type for %s" % file) | ||||
|  | ||||
| def diffTreePattern(): | ||||
|     # This is a simple generator for the diff tree regex pattern. This could be | ||||
|     # a class variable if this and parseDiffTreeEntry were a part of a class. | ||||
|     pattern = re.compile(':(\d+) (\d+) (\w+) (\w+) ([A-Z])(\d+)?\t(.*?)((\t(.*))|$)') | ||||
|     while True: | ||||
|         yield pattern | ||||
|  | ||||
| def parseDiffTreeEntry(entry): | ||||
|     """Parses a single diff tree entry into its component elements. | ||||
|  | ||||
|     See git-diff-tree(1) manpage for details about the format of the diff | ||||
|     output. This method returns a dictionary with the following elements: | ||||
|  | ||||
|     src_mode - The mode of the source file | ||||
|     dst_mode - The mode of the destination file | ||||
|     src_sha1 - The sha1 for the source file | ||||
|     dst_sha1 - The sha1 fr the destination file | ||||
|     status - The one letter status of the diff (i.e. 'A', 'M', 'D', etc) | ||||
|     status_score - The score for the status (applicable for 'C' and 'R' | ||||
|                    statuses). This is None if there is no score. | ||||
|     src - The path for the source file. | ||||
|     dst - The path for the destination file. This is only present for | ||||
|           copy or renames. If it is not present, this is None. | ||||
|  | ||||
|     If the pattern is not matched, None is returned.""" | ||||
|  | ||||
|     match = diffTreePattern().next().match(entry) | ||||
|     if match: | ||||
|         return { | ||||
|             'src_mode': match.group(1), | ||||
|             'dst_mode': match.group(2), | ||||
|             'src_sha1': match.group(3), | ||||
|             'dst_sha1': match.group(4), | ||||
|             'status': match.group(5), | ||||
|             'status_score': match.group(6), | ||||
|             'src': match.group(7), | ||||
|             'dst': match.group(10) | ||||
|         } | ||||
|     return None | ||||
|  | ||||
| def isModeExec(mode): | ||||
|     # Returns True if the given git mode represents an executable file, | ||||
|     # otherwise False. | ||||
|     return mode[-3:] == "755" | ||||
|  | ||||
| def isModeExecChanged(src_mode, dst_mode): | ||||
|     return isModeExec(src_mode) != isModeExec(dst_mode) | ||||
|  | ||||
| def p4CmdList(cmd, stdin=None, stdin_mode='w+b'): | ||||
|     cmd = "p4 -G %s" % cmd | ||||
|     if verbose: | ||||
|  | @ -494,18 +567,23 @@ class P4Submit(Command): | |||
|         else: | ||||
|             print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id)) | ||||
|             diffOpts = ("", "-M")[self.detectRename] | ||||
|             diff = read_pipe_lines("git diff-tree -r --name-status %s \"%s^\" \"%s\"" % (diffOpts, id, id)) | ||||
|             diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id)) | ||||
|         filesToAdd = set() | ||||
|         filesToDelete = set() | ||||
|         editedFiles = set() | ||||
|         filesToChangeExecBit = {} | ||||
|         for line in diff: | ||||
|             modifier = line[0] | ||||
|             path = line[1:].strip() | ||||
|             diff = parseDiffTreeEntry(line) | ||||
|             modifier = diff['status'] | ||||
|             path = diff['src'] | ||||
|             if modifier == "M": | ||||
|                 system("p4 edit \"%s\"" % path) | ||||
|                 if isModeExecChanged(diff['src_mode'], diff['dst_mode']): | ||||
|                     filesToChangeExecBit[path] = diff['dst_mode'] | ||||
|                 editedFiles.add(path) | ||||
|             elif modifier == "A": | ||||
|                 filesToAdd.add(path) | ||||
|                 filesToChangeExecBit[path] = diff['dst_mode'] | ||||
|                 if path in filesToDelete: | ||||
|                     filesToDelete.remove(path) | ||||
|             elif modifier == "D": | ||||
|  | @ -513,9 +591,11 @@ class P4Submit(Command): | |||
|                 if path in filesToAdd: | ||||
|                     filesToAdd.remove(path) | ||||
|             elif modifier == "R": | ||||
|                 src, dest = line.strip().split("\t")[1:3] | ||||
|                 src, dest = diff['src'], diff['dst'] | ||||
|                 system("p4 integrate -Dt \"%s\" \"%s\"" % (src, dest)) | ||||
|                 system("p4 edit \"%s\"" % (dest)) | ||||
|                 if isModeExecChanged(diff['src_mode'], diff['dst_mode']): | ||||
|                     filesToChangeExecBit[dest] = diff['dst_mode'] | ||||
|                 os.unlink(dest) | ||||
|                 editedFiles.add(dest) | ||||
|                 filesToDelete.add(src) | ||||
|  | @ -568,6 +648,11 @@ class P4Submit(Command): | |||
|             system("p4 revert \"%s\"" % f) | ||||
|             system("p4 delete \"%s\"" % f) | ||||
|  | ||||
|         # Set/clear executable bits | ||||
|         for f in filesToChangeExecBit.keys(): | ||||
|             mode = filesToChangeExecBit[f] | ||||
|             setP4ExecBit(f, mode) | ||||
|  | ||||
|         logMessage = "" | ||||
|         if not self.directSubmit: | ||||
|             logMessage = extractLogMessageFromGitCommit(id) | ||||
|  |  | |||
|  | @ -2,24 +2,26 @@ | |||
| # | ||||
| # Copyright (c) 2007 Andy Parkins | ||||
| # | ||||
| # An example hook script to mail out commit update information.  This hook sends emails | ||||
| # listing new revisions to the repository introduced by the change being reported.  The | ||||
| # rule is that (for branch updates) each commit will appear on one email and one email | ||||
| # only. | ||||
| # An example hook script to mail out commit update information.  This hook | ||||
| # sends emails listing new revisions to the repository introduced by the | ||||
| # change being reported.  The rule is that (for branch updates) each commit | ||||
| # will appear on one email and one email only. | ||||
| # | ||||
| # This hook is stored in the contrib/hooks directory.  Your distribution will have put | ||||
| # this somewhere standard.  You should make this script executable then link to it in | ||||
| # the repository you would like to use it in.  For example, on debian the hook is stored | ||||
| # in /usr/share/doc/git-core/contrib/hooks/post-receive-email: | ||||
| # This hook is stored in the contrib/hooks directory.  Your distribution | ||||
| # will have put this somewhere standard.  You should make this script | ||||
| # executable then link to it in the repository you would like to use it in. | ||||
| # For example, on debian the hook is stored in | ||||
| # /usr/share/doc/git-core/contrib/hooks/post-receive-email: | ||||
| # | ||||
| #  chmod a+x post-receive-email | ||||
| #  cd /path/to/your/repository.git | ||||
| #  ln -sf /usr/share/doc/git-core/contrib/hooks/post-receive-email hooks/post-receive | ||||
| # | ||||
| # This hook script assumes it is enabled on the central repository of a project, with | ||||
| # all users pushing only to it and not between each other.  It will still work if you | ||||
| # don't operate in that style, but it would become possible for the email to be from | ||||
| # someone other than the person doing the push. | ||||
| # This hook script assumes it is enabled on the central repository of a | ||||
| # project, with all users pushing only to it and not between each other.  It | ||||
| # will still work if you don't operate in that style, but it would become | ||||
| # possible for the email to be from someone other than the person doing the | ||||
| # push. | ||||
| # | ||||
| # Config | ||||
| # ------ | ||||
|  | @ -28,15 +30,17 @@ | |||
| #   emails for every ref update. | ||||
| # hooks.announcelist | ||||
| #   This is the list that all pushes of annotated tags will go to.  Leave it | ||||
| #   blank to default to the mailinglist field.  The announce emails lists the | ||||
| #   short log summary of the changes since the last annotated tag. | ||||
| # hook.envelopesender | ||||
| #   If set then the -f option is passed to sendmail to allow the envelope sender | ||||
| #   address to be set | ||||
| #   blank to default to the mailinglist field.  The announce emails lists | ||||
| #   the short log summary of the changes since the last annotated tag. | ||||
| # hooks.envelopesender | ||||
| #   If set then the -f option is passed to sendmail to allow the envelope | ||||
| #   sender address to be set | ||||
| # hooks.emailprefix | ||||
| #   All emails have their subjects prefixed with this prefix, or "[SCM]" | ||||
| #   if emailprefix is unset, to aid filtering | ||||
| # | ||||
| # Notes | ||||
| # ----- | ||||
| # All emails have their subjects prefixed with "[SCM]" to aid filtering. | ||||
| # All emails include the headers "X-Git-Refname", "X-Git-Oldrev", | ||||
| # "X-Git-Newrev", and "X-Git-Reftype" to enable fine tuned filtering and | ||||
| # give information for debugging. | ||||
|  | @ -49,8 +53,8 @@ | |||
| # this is and calls the appropriate body-generation routine after outputting | ||||
| # the common header | ||||
| # | ||||
| # Note this function doesn't actually generate any email output, that is taken | ||||
| # care of by the functions it calls: | ||||
| # Note this function doesn't actually generate any email output, that is | ||||
| # taken care of by the functions it calls: | ||||
| #  - generate_email_header | ||||
| #  - generate_create_XXXX_email | ||||
| #  - generate_update_XXXX_email | ||||
|  | @ -152,10 +156,6 @@ generate_email() | |||
| 	fi | ||||
|  | ||||
| 	# Email parameters | ||||
| 	# The committer will be obtained from the latest existing rev; so | ||||
| 	# for a deletion it will be the oldrev, for the others, then newrev | ||||
| 	committer=$(git show --pretty=full -s $rev | sed -ne "s/^Commit: //p" | | ||||
| 		sed -ne 's/\(.*\) </"\1" </p') | ||||
| 	# The email subject will contain the best description of the ref | ||||
| 	# that we can build from the parameters | ||||
| 	describe=$(git describe $rev 2>/dev/null) | ||||
|  | @ -186,7 +186,7 @@ generate_email_header() | |||
| 	# Generate header | ||||
| 	cat <<-EOF | ||||
| 	To: $recipients | ||||
| 	Subject: ${EMAILPREFIX}$projectdesc $refname_type, $short_refname, ${change_type}d. $describe | ||||
| 	Subject: ${emailprefix}$projectdesc $refname_type, $short_refname, ${change_type}d. $describe | ||||
| 	X-Git-Refname: $refname | ||||
| 	X-Git-Reftype: $refname_type | ||||
| 	X-Git-Oldrev: $oldrev | ||||
|  | @ -225,8 +225,9 @@ generate_create_branch_email() | |||
| 	echo $LOGBEGIN | ||||
| 	# This shows all log entries that are not already covered by | ||||
| 	# another ref - i.e. commits that are now accessible from this | ||||
| 	# ref that were previously not accessible (see generate_update_branch_email | ||||
| 	# for the explanation of this command) | ||||
| 	# ref that were previously not accessible | ||||
| 	# (see generate_update_branch_email for the explanation of this | ||||
| 	# command) | ||||
| 	git rev-parse --not --branches | grep -v $(git rev-parse $refname) | | ||||
| 	git rev-list --pretty --stdin $newrev | ||||
| 	echo $LOGEND | ||||
|  | @ -254,9 +255,10 @@ generate_update_branch_email() | |||
| 	# | ||||
| 	#  git-rev-list N ^O ^X ^N | ||||
| 	# | ||||
| 	# So, we need to build up the list more carefully.  git-rev-parse will | ||||
| 	# generate a list of revs that may be fed into git-rev-list.  We can get | ||||
| 	# it to make the "--not --all" part and then filter out the "^N" with: | ||||
| 	# So, we need to build up the list more carefully.  git-rev-parse | ||||
| 	# will generate a list of revs that may be fed into git-rev-list. | ||||
| 	# We can get it to make the "--not --all" part and then filter out | ||||
| 	# the "^N" with: | ||||
| 	# | ||||
| 	#  git-rev-parse --not --all | grep -v N | ||||
| 	# | ||||
|  | @ -266,16 +268,17 @@ generate_update_branch_email() | |||
| 	#  git-rev-list N ^O ^X | ||||
| 	# | ||||
| 	# This leaves a problem when someone else updates the repository | ||||
| 	# while this script is running.  Their new value of the ref we're working | ||||
| 	# on would be included in the "--not --all" output; and as our $newrev | ||||
| 	# would be an ancestor of that commit, it would exclude all of our | ||||
| 	# commits.  What we really want is to exclude the current value of | ||||
| 	# $refname from the --not list, rather than N itself.  So: | ||||
| 	# while this script is running.  Their new value of the ref we're | ||||
| 	# working on would be included in the "--not --all" output; and as | ||||
| 	# our $newrev would be an ancestor of that commit, it would exclude | ||||
| 	# all of our commits.  What we really want is to exclude the current | ||||
| 	# value of $refname from the --not list, rather than N itself.  So: | ||||
| 	# | ||||
| 	#  git-rev-parse --not --all | grep -v $(git-rev-parse $refname) | ||||
| 	# | ||||
| 	# Get's us to something pretty safe (apart from the small time between | ||||
| 	# refname being read, and git-rev-parse running - for that, I give up) | ||||
| 	# Get's us to something pretty safe (apart from the small time | ||||
| 	# between refname being read, and git-rev-parse running - for that, | ||||
| 	# I give up) | ||||
| 	# | ||||
| 	# | ||||
| 	# Next problem, consider this: | ||||
|  | @ -283,18 +286,18 @@ generate_update_branch_email() | |||
| 	#          \ | ||||
| 	#           * --- X --- * --- N ($newrev) | ||||
| 	# | ||||
| 	# That is to say, there is no guarantee that oldrev is a strict subset of | ||||
| 	# newrev (it would have required a --force, but that's allowed).  So, we | ||||
| 	# can't simply say rev-list $oldrev..$newrev.  Instead we find the common | ||||
| 	# base of the two revs and list from there. | ||||
| 	# That is to say, there is no guarantee that oldrev is a strict | ||||
| 	# subset of newrev (it would have required a --force, but that's | ||||
| 	# allowed).  So, we can't simply say rev-list $oldrev..$newrev. | ||||
| 	# Instead we find the common base of the two revs and list from | ||||
| 	# there. | ||||
| 	# | ||||
| 	# As above, we need to take into account the presence of X; if another | ||||
| 	# branch is already in the repository and points at some of the revisions | ||||
| 	# that we are about to output - we don't want them.  The solution is as | ||||
| 	# before: git-rev-parse output filtered. | ||||
| 	# As above, we need to take into account the presence of X; if | ||||
| 	# another branch is already in the repository and points at some of | ||||
| 	# the revisions that we are about to output - we don't want them. | ||||
| 	# The solution is as before: git-rev-parse output filtered. | ||||
| 	# | ||||
| 	# Finally, tags: | ||||
| 	#   1 --- 2 --- O --- T --- 3 --- 4 --- N | ||||
| 	# Finally, tags: 1 --- 2 --- O --- T --- 3 --- 4 --- N | ||||
| 	# | ||||
| 	# Tags pushed into the repository generate nice shortlog emails that | ||||
| 	# summarise the commits between them and the previous tag.  However, | ||||
|  | @ -302,13 +305,14 @@ generate_update_branch_email() | |||
| 	# for a branch update.  Therefore we still want to output revisions | ||||
| 	# that have been output on a tag email. | ||||
| 	# | ||||
| 	# Luckily, git-rev-parse includes just the tool.  Instead of using "--all" | ||||
| 	# we use "--branches"; this has the added benefit that "remotes/" will | ||||
| 	# be ignored as well. | ||||
| 	# Luckily, git-rev-parse includes just the tool.  Instead of using | ||||
| 	# "--all" we use "--branches"; this has the added benefit that | ||||
| 	# "remotes/" will be ignored as well. | ||||
|  | ||||
| 	# List all of the revisions that were removed by this update, in a fast forward | ||||
| 	# update, this list will be empty, because rev-list O ^N is empty.  For a non | ||||
| 	# fast forward, O ^N is the list of removed revisions | ||||
| 	# List all of the revisions that were removed by this update, in a | ||||
| 	# fast forward update, this list will be empty, because rev-list O | ||||
| 	# ^N is empty.  For a non fast forward, O ^N is the list of removed | ||||
| 	# revisions | ||||
| 	fast_forward="" | ||||
| 	rev="" | ||||
| 	for rev in $(git rev-list $newrev..$oldrev) | ||||
|  | @ -321,10 +325,10 @@ generate_update_branch_email() | |||
| 	fi | ||||
|  | ||||
| 	# List all the revisions from baserev to newrev in a kind of | ||||
| 	# "table-of-contents"; note this list can include revisions that have | ||||
| 	# already had notification emails and is present to show the full detail | ||||
| 	# of the change from rolling back the old revision to the base revision and | ||||
| 	# then forward to the new revision | ||||
| 	# "table-of-contents"; note this list can include revisions that | ||||
| 	# have already had notification emails and is present to show the | ||||
| 	# full detail of the change from rolling back the old revision to | ||||
| 	# the base revision and then forward to the new revision | ||||
| 	for rev in $(git rev-list $oldrev..$newrev) | ||||
| 	do | ||||
| 		revtype=$(git cat-file -t "$rev") | ||||
|  | @ -334,19 +338,20 @@ generate_update_branch_email() | |||
| 	if [ "$fast_forward" ]; then | ||||
| 		echo "      from  $oldrev ($oldrev_type)" | ||||
| 	else | ||||
| 		#  1. Existing revisions were removed.  In this case newrev is a | ||||
| 		#     subset of oldrev - this is the reverse of a fast-forward, | ||||
| 		#     a rewind | ||||
| 		#  2. New revisions were added on top of an old revision, this is | ||||
| 		#     a rewind and addition. | ||||
| 		#  1. Existing revisions were removed.  In this case newrev | ||||
| 		#     is a subset of oldrev - this is the reverse of a | ||||
| 		#     fast-forward, a rewind | ||||
| 		#  2. New revisions were added on top of an old revision, | ||||
| 		#     this is a rewind and addition. | ||||
|  | ||||
| 		# (1) certainly happened, (2) possibly.  When (2) hasn't happened, | ||||
| 		# we set a flag to indicate that no log printout is required. | ||||
| 		# (1) certainly happened, (2) possibly.  When (2) hasn't | ||||
| 		# happened, we set a flag to indicate that no log printout | ||||
| 		# is required. | ||||
|  | ||||
| 		echo "" | ||||
|  | ||||
| 		# Find the common ancestor of the old and new revisions and compare | ||||
| 		# it with newrev | ||||
| 		# Find the common ancestor of the old and new revisions and | ||||
| 		# compare it with newrev | ||||
| 		baserev=$(git merge-base $oldrev $newrev) | ||||
| 		rewind_only="" | ||||
| 		if [ "$baserev" = "$newrev" ]; then | ||||
|  | @ -387,21 +392,22 @@ generate_update_branch_email() | |||
| 		git rev-parse --not --branches | grep -v $(git rev-parse $refname) | | ||||
| 		git rev-list --pretty --stdin $oldrev..$newrev | ||||
|  | ||||
| 		# XXX: Need a way of detecting whether git rev-list actually outputted | ||||
| 		# anything, so that we can issue a "no new revisions added by this | ||||
| 		# update" message | ||||
| 		# XXX: Need a way of detecting whether git rev-list actually | ||||
| 		# outputted anything, so that we can issue a "no new | ||||
| 		# revisions added by this update" message | ||||
|  | ||||
| 		echo $LOGEND | ||||
| 	else | ||||
| 		echo "No new revisions were added by this update." | ||||
| 	fi | ||||
|  | ||||
| 	# The diffstat is shown from the old revision to the new revision.  This | ||||
| 	# is to show the truth of what happened in this change.  There's no point | ||||
| 	# showing the stat from the base to the new revision because the base | ||||
| 	# is effectively a random revision at this point - the user will be | ||||
| 	# interested in what this revision changed - including the undoing of | ||||
| 	# previous revisions in the case of non-fast forward updates. | ||||
| 	# The diffstat is shown from the old revision to the new revision. | ||||
| 	# This is to show the truth of what happened in this change. | ||||
| 	# There's no point showing the stat from the base to the new | ||||
| 	# revision because the base is effectively a random revision at this | ||||
| 	# point - the user will be interested in what this revision changed | ||||
| 	# - including the undoing of previous revisions in the case of | ||||
| 	# non-fast forward updates. | ||||
| 	echo "" | ||||
| 	echo "Summary of changes:" | ||||
| 	git diff-tree --stat --summary --find-copies-harder $oldrev..$newrev | ||||
|  | @ -448,7 +454,8 @@ generate_update_atag_email() | |||
| # | ||||
| generate_atag_email() | ||||
| { | ||||
| 	# Use git-for-each-ref to pull out the individual fields from the tag | ||||
| 	# Use git-for-each-ref to pull out the individual fields from the | ||||
| 	# tag | ||||
| 	eval $(git for-each-ref --shell --format=' | ||||
| 	tagobject=%(*objectname) | ||||
| 	tagtype=%(*objecttype) | ||||
|  | @ -459,8 +466,10 @@ generate_atag_email() | |||
| 	echo "   tagging  $tagobject ($tagtype)" | ||||
| 	case "$tagtype" in | ||||
| 	commit) | ||||
|  | ||||
| 		# If the tagged object is a commit, then we assume this is a | ||||
| 		# release, and so we calculate which tag this tag is replacing | ||||
| 		# release, and so we calculate which tag this tag is | ||||
| 		# replacing | ||||
| 		prevtag=$(git describe --abbrev=0 $newrev^ 2>/dev/null) | ||||
|  | ||||
| 		if [ -n "$prevtag" ]; then | ||||
|  | @ -477,25 +486,27 @@ generate_atag_email() | |||
| 	echo "" | ||||
| 	echo $LOGBEGIN | ||||
|  | ||||
| 	# Show the content of the tag message; this might contain a change log | ||||
| 	# or release notes so is worth displaying. | ||||
| 	# Show the content of the tag message; this might contain a change | ||||
| 	# log or release notes so is worth displaying. | ||||
| 	git cat-file tag $newrev | sed -e '1,/^$/d' | ||||
|  | ||||
| 	echo "" | ||||
| 	case "$tagtype" in | ||||
| 	commit) | ||||
| 		# Only commit tags make sense to have rev-list operations performed | ||||
| 		# on them | ||||
| 		# Only commit tags make sense to have rev-list operations | ||||
| 		# performed on them | ||||
| 		if [ -n "$prevtag" ]; then | ||||
| 			# Show changes since the previous release | ||||
| 			git rev-list --pretty=short "$prevtag..$newrev" | git shortlog | ||||
| 		else | ||||
| 			# No previous tag, show all the changes since time began | ||||
| 			# No previous tag, show all the changes since time | ||||
| 			# began | ||||
| 			git rev-list --pretty=short $newrev | git shortlog | ||||
| 		fi | ||||
| 		;; | ||||
| 	*) | ||||
| 		# XXX: Is there anything useful we can do for non-commit objects? | ||||
| 		# XXX: Is there anything useful we can do for non-commit | ||||
| 		# objects? | ||||
| 		;; | ||||
| 	esac | ||||
|  | ||||
|  | @ -544,13 +555,14 @@ generate_update_general_email() | |||
| # | ||||
| generate_general_email() | ||||
| { | ||||
| 	# Unannotated tags are more about marking a point than releasing a version; | ||||
| 	# therefore we don't do the shortlog summary that we do for annotated tags | ||||
| 	# above - we simply show that the point has been marked, and print the log | ||||
| 	# message for the marked point for reference purposes | ||||
| 	# Unannotated tags are more about marking a point than releasing a | ||||
| 	# version; therefore we don't do the shortlog summary that we do for | ||||
| 	# annotated tags above - we simply show that the point has been | ||||
| 	# marked, and print the log message for the marked point for | ||||
| 	# reference purposes | ||||
| 	# | ||||
| 	# Note this section also catches any other reference type (although there | ||||
| 	# aren't any) and deals with them in the same way. | ||||
| 	# Note this section also catches any other reference type (although | ||||
| 	# there aren't any) and deals with them in the same way. | ||||
|  | ||||
| 	echo "" | ||||
| 	if [ "$newrev_type" = "commit" ]; then | ||||
|  | @ -558,10 +570,10 @@ generate_general_email() | |||
| 		git show --no-color --root -s $newrev | ||||
| 		echo $LOGEND | ||||
| 	else | ||||
| 		# What can we do here?  The tag marks an object that is not a commit, | ||||
| 		# so there is no log for us to display.  It's probably not wise to | ||||
| 		# output git-cat-file as it could be a binary blob.  We'll just say how | ||||
| 		# big it is | ||||
| 		# What can we do here?  The tag marks an object that is not | ||||
| 		# a commit, so there is no log for us to display.  It's | ||||
| 		# probably not wise to output git-cat-file as it could be a | ||||
| 		# binary blob.  We'll just say how big it is | ||||
| 		echo "$newrev is a $newrev_type, and is $(git cat-file -s $newrev) bytes long." | ||||
| 	fi | ||||
| } | ||||
|  | @ -590,7 +602,6 @@ send_mail() | |||
| # ---------------------------- main() | ||||
|  | ||||
| # --- Constants | ||||
| EMAILPREFIX="[SCM] " | ||||
| LOGBEGIN="- Log -----------------------------------------------------------------" | ||||
| LOGEND="-----------------------------------------------------------------------" | ||||
|  | ||||
|  | @ -604,8 +615,8 @@ if [ -z "$GIT_DIR" ]; then | |||
| fi | ||||
|  | ||||
| projectdesc=$(sed -ne '1p' "$GIT_DIR/description") | ||||
| # Check if the description is unchanged from it's default, and shorten it to a | ||||
| # more manageable length if it is | ||||
| # Check if the description is unchanged from it's default, and shorten it to | ||||
| # a more manageable length if it is | ||||
| if expr "$projectdesc" : "Unnamed repository.*$" >/dev/null | ||||
| then | ||||
| 	projectdesc="UNNAMED PROJECT" | ||||
|  | @ -614,13 +625,15 @@ fi | |||
| recipients=$(git repo-config hooks.mailinglist) | ||||
| announcerecipients=$(git repo-config hooks.announcelist) | ||||
| envelopesender=$(git-repo-config hooks.envelopesender) | ||||
| emailprefix=$(git-repo-config hooks.emailprefix || echo '[SCM] ') | ||||
|  | ||||
| # --- Main loop | ||||
| # Allow dual mode: run from the command line just like the update hook, or if | ||||
| # no arguments are given then run as a hook script | ||||
| # Allow dual mode: run from the command line just like the update hook, or | ||||
| # if no arguments are given then run as a hook script | ||||
| if [ -n "$1" -a -n "$2" -a -n "$3" ]; then | ||||
| 	# Output to the terminal in command line mode - if someone wanted to | ||||
| 	# resend an email; they could redirect the output to sendmail themselves | ||||
| 	# resend an email; they could redirect the output to sendmail | ||||
| 	# themselves | ||||
| 	PAGER= generate_email $2 $3 $1 | ||||
| else | ||||
| 	while read oldrev newrev refname | ||||
|  |  | |||
							
								
								
									
										10
									
								
								daemon.c
								
								
								
								
							
							
						
						
									
										10
									
								
								daemon.c
								
								
								
								
							|  | @ -406,7 +406,8 @@ static struct daemon_service daemon_service[] = { | |||
| 	{ "receive-pack", "receivepack", receive_pack, 0, 1 }, | ||||
| }; | ||||
|  | ||||
| static void enable_service(const char *name, int ena) { | ||||
| static void enable_service(const char *name, int ena) | ||||
| { | ||||
| 	int i; | ||||
| 	for (i = 0; i < ARRAY_SIZE(daemon_service); i++) { | ||||
| 		if (!strcmp(daemon_service[i].name, name)) { | ||||
|  | @ -417,7 +418,8 @@ static void enable_service(const char *name, int ena) { | |||
| 	die("No such service %s", name); | ||||
| } | ||||
|  | ||||
| static void make_service_overridable(const char *name, int ena) { | ||||
| static void make_service_overridable(const char *name, int ena) | ||||
| { | ||||
| 	int i; | ||||
| 	for (i = 0; i < ARRAY_SIZE(daemon_service); i++) { | ||||
| 		if (!strcmp(daemon_service[i].name, name)) { | ||||
|  | @ -540,7 +542,7 @@ static int execute(struct sockaddr *addr) | |||
| 		if (addr->sa_family == AF_INET) { | ||||
| 			struct sockaddr_in *sin_addr = (void *) addr; | ||||
| 			inet_ntop(addr->sa_family, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf)); | ||||
| 			port = sin_addr->sin_port; | ||||
| 			port = ntohs(sin_addr->sin_port); | ||||
| #ifndef NO_IPV6 | ||||
| 		} else if (addr && addr->sa_family == AF_INET6) { | ||||
| 			struct sockaddr_in6 *sin6_addr = (void *) addr; | ||||
|  | @ -550,7 +552,7 @@ static int execute(struct sockaddr *addr) | |||
| 			inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1); | ||||
| 			strcat(buf, "]"); | ||||
|  | ||||
| 			port = sin6_addr->sin6_port; | ||||
| 			port = ntohs(sin6_addr->sin6_port); | ||||
| #endif | ||||
| 		} | ||||
| 		loginfo("Connection from %s:%d", addrbuf, port); | ||||
|  |  | |||
							
								
								
									
										3
									
								
								dir.c
								
								
								
								
							
							
						
						
									
										3
									
								
								dir.c
								
								
								
								
							|  | @ -298,7 +298,8 @@ int excluded(struct dir_struct *dir, const char *pathname) | |||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static struct dir_entry *dir_entry_new(const char *pathname, int len) { | ||||
| static struct dir_entry *dir_entry_new(const char *pathname, int len) | ||||
| { | ||||
| 	struct dir_entry *ent; | ||||
|  | ||||
| 	ent = xmalloc(sizeof(*ent) + len + 1); | ||||
|  |  | |||
|  | @ -275,7 +275,8 @@ exit_if_skipped_commits () { | |||
| 	if expr "$_tried" : ".*[|].*" > /dev/null ; then | ||||
| 		echo "There are only 'skip'ped commit left to test." | ||||
| 		echo "The first bad commit could be any of:" | ||||
| 		echo "$_tried" | sed -e 's/[|]/\n/g' | ||||
| 		echo "$_tried" | sed -e 's/[|]/\ | ||||
| /g' | ||||
| 		echo "We cannot bisect more!" | ||||
| 		exit 2 | ||||
| 	fi | ||||
|  |  | |||
|  | @ -20,12 +20,16 @@ require_work_tree | |||
| ignored= | ||||
| ignoredonly= | ||||
| cleandir= | ||||
| disabled="`git config --bool clean.requireForce`" | ||||
| rmf="rm -f --" | ||||
| rmrf="rm -rf --" | ||||
| rm_refuse="echo Not removing" | ||||
| echo1="echo" | ||||
|  | ||||
| # requireForce used to default to false but now it defaults to true. | ||||
| # IOW, lack of explicit "clean.requireForce = false" is taken as | ||||
| # "clean.requireForce = true". | ||||
| disabled=$(git config --bool clean.requireForce || echo true) | ||||
|  | ||||
| while test $# != 0 | ||||
| do | ||||
| 	case "$1" in | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ die() { | |||
| } | ||||
|  | ||||
| usage() { | ||||
| 	die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [--depth <n>] [-n] <repo> [<dir>]" | ||||
| 	die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [--depth <n>] [-n] [--] <repo> [<dir>]" | ||||
| } | ||||
|  | ||||
| get_repo_base() { | ||||
|  | @ -160,6 +160,9 @@ while | |||
| 	*,--depth) | ||||
| 		shift | ||||
| 		depth="--depth=$1";; | ||||
| 	*,--) | ||||
| 		shift | ||||
| 		break ;; | ||||
| 	*,-*) usage ;; | ||||
| 	*) break ;; | ||||
| 	esac | ||||
|  |  | |||
|  | @ -381,4 +381,17 @@ static inline int strtoul_ui(char const *s, int base, unsigned int *result) | |||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static inline int strtol_i(char const *s, int base, int *result) | ||||
| { | ||||
| 	long ul; | ||||
| 	char *p; | ||||
|  | ||||
| 	errno = 0; | ||||
| 	ul = strtol(s, &p, base); | ||||
| 	if (errno || *p || p == s || (int) ul != ul) | ||||
| 		return -1; | ||||
| 	*result = ul; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  |  | |||
|  | @ -818,6 +818,7 @@ while (<CVS>) { | |||
| 		$state = 4; | ||||
| 	} elsif ($state == 4 and s/^Branch:\s+//) { | ||||
| 		s/\s+$//; | ||||
| 		tr/_/\./ if ( $opt_u ); | ||||
| 		s/[\/]/$opt_s/g; | ||||
| 		$branch = $_; | ||||
| 		$state = 5; | ||||
|  |  | |||
|  | @ -15,7 +15,7 @@ browser="`git config --get instaweb.browser`" | |||
| port=`git config --get instaweb.port` | ||||
| module_path="`git config --get instaweb.modulepath`" | ||||
|  | ||||
| conf=$GIT_DIR/gitweb/httpd.conf | ||||
| conf="$GIT_DIR/gitweb/httpd.conf" | ||||
|  | ||||
| # Defaults: | ||||
|  | ||||
|  | @ -32,7 +32,7 @@ start_httpd () { | |||
| 	httpd_only="`echo $httpd | cut -f1 -d' '`" | ||||
| 	if case "$httpd_only" in /*) : ;; *) which $httpd_only >/dev/null;; esac | ||||
| 	then | ||||
| 		$httpd $fqgitdir/gitweb/httpd.conf | ||||
| 		$httpd "$fqgitdir/gitweb/httpd.conf" | ||||
| 	else | ||||
| 		# many httpds are installed in /usr/sbin or /usr/local/sbin | ||||
| 		# these days and those are not in most users $PATHs | ||||
|  | @ -185,14 +185,14 @@ server.pid-file = "$fqgitdir/pid" | |||
| cgi.assign = ( ".cgi" => "" ) | ||||
| mimetype.assign = ( ".css" => "text/css" ) | ||||
| EOF | ||||
| 	test "$local" = true && echo 'server.bind = "127.0.0.1"' >> "$conf" | ||||
| 	test x"$local" = xtrue && echo 'server.bind = "127.0.0.1"' >> "$conf" | ||||
| } | ||||
|  | ||||
| apache2_conf () { | ||||
| 	test -z "$module_path" && module_path=/usr/lib/apache2/modules | ||||
| 	mkdir -p "$GIT_DIR/gitweb/logs" | ||||
| 	bind= | ||||
| 	test "$local" = true && bind='127.0.0.1:' | ||||
| 	test x"$local" = xtrue && bind='127.0.0.1:' | ||||
| 	echo 'text/css css' > $fqgitdir/mime.types | ||||
| 	cat > "$conf" <<EOF | ||||
| ServerName "git-instaweb" | ||||
|  | @ -245,7 +245,7 @@ EOF | |||
| } | ||||
|  | ||||
| script=' | ||||
| s#^\(my\|our\) $projectroot =.*#\1 $projectroot = "'`dirname $fqgitdir`'";# | ||||
| s#^\(my\|our\) $projectroot =.*#\1 $projectroot = "'$(dirname "$fqgitdir")'";# | ||||
| s#\(my\|our\) $gitbin =.*#\1 $gitbin = "'$GIT_EXEC_PATH'";# | ||||
| s#\(my\|our\) $projects_list =.*#\1 $projects_list = $projectroot;# | ||||
| s#\(my\|our\) $git_temp =.*#\1 $git_temp = "'$fqgitdir/gitweb/tmp'";#' | ||||
|  | @ -265,8 +265,8 @@ gitweb_css () { | |||
| EOFGITWEB | ||||
| } | ||||
|  | ||||
| gitweb_cgi $GIT_DIR/gitweb/gitweb.cgi | ||||
| gitweb_css $GIT_DIR/gitweb/gitweb.css | ||||
| gitweb_cgi "$GIT_DIR/gitweb/gitweb.cgi" | ||||
| gitweb_css "$GIT_DIR/gitweb/gitweb.css" | ||||
|  | ||||
| case "$httpd" in | ||||
| *lighttpd*) | ||||
|  | @ -285,6 +285,5 @@ webrick) | |||
| esac | ||||
|  | ||||
| start_httpd | ||||
| test -z "$browser" && browser=echo | ||||
| url=http://127.0.0.1:$port | ||||
| $browser $url || echo $url | ||||
| "$browser" $url || echo $url | ||||
|  |  | |||
|  | @ -4,6 +4,8 @@ USAGE='' | |||
| SUBDIRECTORY_OK='Yes' | ||||
| . git-sh-setup | ||||
|  | ||||
| echo "WARNING: '$0' is deprecated in favor of 'git fsck --lost-found'" >&2 | ||||
|  | ||||
| if [ "$#" != "0" ] | ||||
| then | ||||
|     usage | ||||
|  |  | |||
|  | @ -391,7 +391,7 @@ do | |||
| 	-s|--strategy) | ||||
| 		case "$#,$1" in | ||||
| 		*,*=*) | ||||
| 			STRATEGY="-s `expr "z$1" : 'z-[^=]*=\(.*\)'`" ;; | ||||
| 			STRATEGY="-s "$(expr "z$1" : 'z-[^=]*=\(.*\)') ;; | ||||
| 		1,*) | ||||
| 			usage ;; | ||||
| 		*) | ||||
|  |  | |||
|  | @ -24,13 +24,13 @@ headrev=`git rev-parse --verify "$head"^0` || exit | |||
| merge_base=`git merge-base $baserev $headrev` || | ||||
| die "fatal: No commits in common between $base and $head" | ||||
|  | ||||
| url="`get_remote_url "$url"`" | ||||
| branch=`git peek-remote "$url" \ | ||||
| url=$(get_remote_url "$url") | ||||
| branch=$(git peek-remote "$url" \ | ||||
| 	| sed -n -e "/^$headrev	refs.heads./{ | ||||
| 		s/^.*	refs.heads.// | ||||
| 		p | ||||
| 		q | ||||
| 	}"` | ||||
| 	}") | ||||
| if [ -z "$branch" ]; then | ||||
| 	echo "warn: No branch of $url is at:" >&2 | ||||
| 	git log --max-count=1 --pretty='format:warn:   %h: %s' $headrev >&2 | ||||
|  |  | |||
|  | @ -88,8 +88,7 @@ Options: | |||
|  | ||||
|    --smtp-ssl     If set, connects to the SMTP server using SSL. | ||||
|  | ||||
|    --suppress-from Suppress sending emails to yourself if your address | ||||
|                   appears in a From: line. Defaults to off. | ||||
|    --suppress-from Suppress sending emails to yourself. Defaults to off. | ||||
|  | ||||
|    --thread       Specify that the "In-Reply-To:" header should be set on all | ||||
|                   emails. Defaults to on. | ||||
|  | @ -353,7 +352,7 @@ sub expand_aliases { | |||
|  | ||||
| if (!defined $initial_subject && $compose) { | ||||
| 	do { | ||||
| 		$_ = $term->readline("What subject should the emails start with? ", | ||||
| 		$_ = $term->readline("What subject should the initial email start with? ", | ||||
| 			$initial_subject); | ||||
| 	} while (!defined $_); | ||||
| 	$initial_subject = $_; | ||||
|  | @ -730,6 +729,7 @@ foreach my $t (@files) { | |||
| 			if (/^(Signed-off-by|Cc): (.*)$/i && $signed_off_cc) { | ||||
| 				my $c = $2; | ||||
| 				chomp $c; | ||||
| 				next if ($c eq $sender and $suppress_from); | ||||
| 				push @cc, $c; | ||||
| 				printf("(sob) Adding cc: %s from line '%s'\n", | ||||
| 					$c, $_) unless $quiet; | ||||
|  | @ -745,6 +745,7 @@ foreach my $t (@files) { | |||
| 			my $c = $_; | ||||
| 			$c =~ s/^\s*//g; | ||||
| 			$c =~ s/\n$//g; | ||||
| 			next if ($c eq $sender and $suppress_from); | ||||
| 			push @cc, $c; | ||||
| 			printf("(cc-cmd) Adding cc: %s from: '%s'\n", | ||||
| 				$c, $cc_cmd) unless $quiet; | ||||
|  |  | |||
|  | @ -73,7 +73,7 @@ resolve_relative_url () | |||
| module_name() | ||||
| { | ||||
| 	# Do we have "submodule.<something>.path = $1" defined in .gitmodules file? | ||||
| 	re=$(printf '%s' "$1" | sed -e 's/\([^a-zA-Z0-9_]\)/\\\1/g') | ||||
| 	re=$(printf '%s' "$1" | sed -e 's/[].[^$\\*]/\\&/g') | ||||
| 	name=$( GIT_CONFIG=.gitmodules \ | ||||
| 		git config --get-regexp '^submodule\..*\.path$' | | ||||
| 		sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' ) | ||||
|  |  | |||
							
								
								
									
										50
									
								
								git-svn.perl
								
								
								
								
							
							
						
						
									
										50
									
								
								git-svn.perl
								
								
								
								
							|  | @ -252,7 +252,7 @@ Usage: $0 <command> [options] [arguments]\n | |||
| 		next if $cmd && $cmd ne $_; | ||||
| 		next if /^multi-/; # don't show deprecated commands | ||||
| 		print $fd '  ',pack('A17',$_),$cmd{$_}->[1],"\n"; | ||||
| 		foreach (keys %{$cmd{$_}->[2]}) { | ||||
| 		foreach (sort keys %{$cmd{$_}->[2]}) { | ||||
| 			# mixed-case options are for .git/config only | ||||
| 			next if /[A-Z]/ && /^[a-z]+$/i; | ||||
| 			# prints out arguments as they should be passed: | ||||
|  | @ -406,7 +406,8 @@ sub cmd_dcommit { | |||
| 		     "If these changes depend on each other, re-running ", | ||||
| 		     "without --no-rebase will be required." | ||||
| 	} | ||||
| 	foreach my $d (@$linear_refs) { | ||||
| 	while (1) { | ||||
| 		my $d = shift @$linear_refs or last; | ||||
| 		unless (defined $last_rev) { | ||||
| 			(undef, $last_rev, undef) = cmt_metadata("$d~1"); | ||||
| 			unless (defined $last_rev) { | ||||
|  | @ -439,14 +440,14 @@ sub cmd_dcommit { | |||
|  | ||||
| 			# we always want to rebase against the current HEAD, | ||||
| 			# not any head that was passed to us | ||||
| 			my @diff = command('diff-tree', 'HEAD', | ||||
| 			my @diff = command('diff-tree', $d, | ||||
| 			                   $gs->refname, '--'); | ||||
| 			my @finish; | ||||
| 			if (@diff) { | ||||
| 				@finish = rebase_cmd(); | ||||
| 				print STDERR "W: HEAD and ", $gs->refname, | ||||
| 				print STDERR "W: $d and ", $gs->refname, | ||||
| 				             " differ, using @finish:\n", | ||||
| 				             "@diff"; | ||||
| 				             join("\n", @diff), "\n"; | ||||
| 			} else { | ||||
| 				print "No changes between current HEAD and ", | ||||
| 				      $gs->refname, | ||||
|  | @ -455,6 +456,45 @@ sub cmd_dcommit { | |||
| 				@finish = qw/reset --mixed/; | ||||
| 			} | ||||
| 			command_noisy(@finish, $gs->refname); | ||||
| 			if (@diff) { | ||||
| 				@refs = (); | ||||
| 				my ($url_, $rev_, $uuid_, $gs_) = | ||||
| 				              working_head_info($head, \@refs); | ||||
| 				my ($linear_refs_, $parents_) = | ||||
| 				              linearize_history($gs_, \@refs); | ||||
| 				if (scalar(@$linear_refs) != | ||||
| 				    scalar(@$linear_refs_)) { | ||||
| 					fatal "# of revisions changed ", | ||||
| 					  "\nbefore:\n", | ||||
| 					  join("\n", @$linear_refs), | ||||
| 					  "\n\nafter:\n", | ||||
| 					  join("\n", @$linear_refs_), "\n", | ||||
| 					  'If you are attempting to commit ', | ||||
| 					  "merges, try running:\n\t", | ||||
| 					  'git rebase --interactive', | ||||
| 					  '--preserve-merges ', | ||||
| 					  $gs->refname, | ||||
| 					  "\nBefore dcommitting"; | ||||
| 				} | ||||
| 				if ($url_ ne $url) { | ||||
| 					fatal "URL mismatch after rebase: ", | ||||
| 					      "$url_ != $url"; | ||||
| 				} | ||||
| 				if ($uuid_ ne $uuid) { | ||||
| 					fatal "uuid mismatch after rebase: ", | ||||
| 					      "$uuid_ != $uuid"; | ||||
| 				} | ||||
| 				# remap parents | ||||
| 				my (%p, @l, $i); | ||||
| 				for ($i = 0; $i < scalar @$linear_refs; $i++) { | ||||
| 					my $new = $linear_refs_->[$i] or next; | ||||
| 					$p{$new} = | ||||
| 						$parents->{$linear_refs->[$i]}; | ||||
| 					push @l, $new; | ||||
| 				} | ||||
| 				$parents = \%p; | ||||
| 				$linear_refs = \@l; | ||||
| 			} | ||||
| 			$last_rev = $cmt_rev; | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
							
								
								
									
										13
									
								
								git.c
								
								
								
								
							
							
						
						
									
										13
									
								
								git.c
								
								
								
								
							|  | @ -249,14 +249,9 @@ static int run_command(struct cmd_struct *p, int argc, const char **argv) | |||
| 		prefix = setup_git_directory(); | ||||
| 	if (p->option & USE_PAGER) | ||||
| 		setup_pager(); | ||||
| 	if (p->option & NEED_WORK_TREE) { | ||||
| 		const char *work_tree = get_git_work_tree(); | ||||
| 		const char *git_dir = get_git_dir(); | ||||
| 		if (!is_absolute_path(git_dir)) | ||||
| 			set_git_dir(make_absolute_path(git_dir)); | ||||
| 		if (!work_tree || chdir(work_tree)) | ||||
| 			die("%s must be run in a work tree", p->cmd); | ||||
| 	} | ||||
| 	if (p->option & NEED_WORK_TREE) | ||||
| 		setup_work_tree(); | ||||
|  | ||||
| 	trace_argv_printf(argv, argc, "trace: built-in: git"); | ||||
|  | ||||
| 	status = p->fn(argc, argv, prefix); | ||||
|  | @ -347,7 +342,7 @@ static void handle_internal_command(int argc, const char **argv) | |||
| 		{ "rev-list", cmd_rev_list, RUN_SETUP }, | ||||
| 		{ "rev-parse", cmd_rev_parse, RUN_SETUP }, | ||||
| 		{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE }, | ||||
| 		{ "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE }, | ||||
| 		{ "rm", cmd_rm, RUN_SETUP }, | ||||
| 		{ "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE }, | ||||
| 		{ "send-pack", cmd_send_pack, RUN_SETUP }, | ||||
| 		{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER }, | ||||
|  |  | |||
|  | @ -611,6 +611,15 @@ sub href(%) { | |||
| 	); | ||||
| 	my %mapping = @mapping; | ||||
|  | ||||
| 	if ($params{-replay}) { | ||||
| 		while (my ($name, $symbol) = each %mapping) { | ||||
| 			if (!exists $params{$name}) { | ||||
| 				# to allow for multivalued params we use arrayref form | ||||
| 				$params{$name} = [ $cgi->param($symbol) ]; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	$params{'project'} = $project unless exists $params{'project'}; | ||||
|  | ||||
| 	my ($use_pathinfo) = gitweb_check_feature('pathinfo'); | ||||
|  | @ -1423,20 +1432,121 @@ sub git_get_type { | |||
| 	return $type; | ||||
| } | ||||
|  | ||||
| # repository configuration | ||||
| our $config_file = ''; | ||||
| our %config; | ||||
|  | ||||
| # store multiple values for single key as anonymous array reference | ||||
| # single values stored directly in the hash, not as [ <value> ] | ||||
| sub hash_set_multi { | ||||
| 	my ($hash, $key, $value) = @_; | ||||
|  | ||||
| 	if (!exists $hash->{$key}) { | ||||
| 		$hash->{$key} = $value; | ||||
| 	} elsif (!ref $hash->{$key}) { | ||||
| 		$hash->{$key} = [ $hash->{$key}, $value ]; | ||||
| 	} else { | ||||
| 		push @{$hash->{$key}}, $value; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| # return hash of git project configuration | ||||
| # optionally limited to some section, e.g. 'gitweb' | ||||
| sub git_parse_project_config { | ||||
| 	my $section_regexp = shift; | ||||
| 	my %config; | ||||
|  | ||||
| 	local $/ = "\0"; | ||||
|  | ||||
| 	open my $fh, "-|", git_cmd(), "config", '-z', '-l', | ||||
| 		or return; | ||||
|  | ||||
| 	while (my $keyval = <$fh>) { | ||||
| 		chomp $keyval; | ||||
| 		my ($key, $value) = split(/\n/, $keyval, 2); | ||||
|  | ||||
| 		hash_set_multi(\%config, $key, $value) | ||||
| 			if (!defined $section_regexp || $key =~ /^(?:$section_regexp)\./o); | ||||
| 	} | ||||
| 	close $fh; | ||||
|  | ||||
| 	return %config; | ||||
| } | ||||
|  | ||||
| # convert config value to boolean, 'true' or 'false' | ||||
| # no value, number > 0, 'true' and 'yes' values are true | ||||
| # rest of values are treated as false (never as error) | ||||
| sub config_to_bool { | ||||
| 	my $val = shift; | ||||
|  | ||||
| 	# strip leading and trailing whitespace | ||||
| 	$val =~ s/^\s+//; | ||||
| 	$val =~ s/\s+$//; | ||||
|  | ||||
| 	return (!defined $val ||               # section.key | ||||
| 	        ($val =~ /^\d+$/ && $val) ||   # section.key = 1 | ||||
| 	        ($val =~ /^(?:true|yes)$/i));  # section.key = true | ||||
| } | ||||
|  | ||||
| # convert config value to simple decimal number | ||||
| # an optional value suffix of 'k', 'm', or 'g' will cause the value | ||||
| # to be multiplied by 1024, 1048576, or 1073741824 | ||||
| sub config_to_int { | ||||
| 	my $val = shift; | ||||
|  | ||||
| 	# strip leading and trailing whitespace | ||||
| 	$val =~ s/^\s+//; | ||||
| 	$val =~ s/\s+$//; | ||||
|  | ||||
| 	if (my ($num, $unit) = ($val =~ /^([0-9]*)([kmg])$/i)) { | ||||
| 		$unit = lc($unit); | ||||
| 		# unknown unit is treated as 1 | ||||
| 		return $num * ($unit eq 'g' ? 1073741824 : | ||||
| 		               $unit eq 'm' ?    1048576 : | ||||
| 		               $unit eq 'k' ?       1024 : 1); | ||||
| 	} | ||||
| 	return $val; | ||||
| } | ||||
|  | ||||
| # convert config value to array reference, if needed | ||||
| sub config_to_multi { | ||||
| 	my $val = shift; | ||||
|  | ||||
| 	return ref($val) ? $val : [ $val ]; | ||||
| } | ||||
|  | ||||
| sub git_get_project_config { | ||||
| 	my ($key, $type) = @_; | ||||
|  | ||||
| 	# key sanity check | ||||
| 	return unless ($key); | ||||
| 	$key =~ s/^gitweb\.//; | ||||
| 	return if ($key =~ m/\W/); | ||||
|  | ||||
| 	my @x = (git_cmd(), 'config'); | ||||
| 	if (defined $type) { push @x, $type; } | ||||
| 	push @x, "--get"; | ||||
| 	push @x, "gitweb.$key"; | ||||
| 	my $val = qx(@x); | ||||
| 	chomp $val; | ||||
| 	return ($val); | ||||
| 	# type sanity check | ||||
| 	if (defined $type) { | ||||
| 		$type =~ s/^--//; | ||||
| 		$type = undef | ||||
| 			unless ($type eq 'bool' || $type eq 'int'); | ||||
| 	} | ||||
|  | ||||
| 	# get config | ||||
| 	if (!defined $config_file || | ||||
| 	    $config_file ne "$git_dir/config") { | ||||
| 		%config = git_parse_project_config('gitweb'); | ||||
| 		$config_file = "$git_dir/config"; | ||||
| 	} | ||||
|  | ||||
| 	# ensure given type | ||||
| 	if (!defined $type) { | ||||
| 		return $config{"gitweb.$key"}; | ||||
| 	} elsif ($type eq 'bool') { | ||||
| 		# backward compatibility: 'git config --bool' returns true/false | ||||
| 		return config_to_bool($config{"gitweb.$key"}) ? 'true' : 'false'; | ||||
| 	} elsif ($type eq 'int') { | ||||
| 		return config_to_int($config{"gitweb.$key"}); | ||||
| 	} | ||||
| 	return $config{"gitweb.$key"}; | ||||
| } | ||||
|  | ||||
| # get hash of given path at given ref | ||||
|  | @ -1496,7 +1606,9 @@ sub git_get_path_by_hash { | |||
| sub git_get_project_description { | ||||
| 	my $path = shift; | ||||
|  | ||||
| 	open my $fd, "$projectroot/$path/description" or return undef; | ||||
| 	$git_dir = "$projectroot/$path"; | ||||
| 	open my $fd, "$projectroot/$path/description" | ||||
| 		or return git_get_project_config('description'); | ||||
| 	my $descr = <$fd>; | ||||
| 	close $fd; | ||||
| 	if (defined $descr) { | ||||
|  | @ -1508,7 +1620,11 @@ sub git_get_project_description { | |||
| sub git_get_project_url_list { | ||||
| 	my $path = shift; | ||||
|  | ||||
| 	open my $fd, "$projectroot/$path/cloneurl" or return; | ||||
| 	$git_dir = "$projectroot/$path"; | ||||
| 	open my $fd, "$projectroot/$path/cloneurl" | ||||
| 		or return wantarray ? | ||||
| 		@{ config_to_multi(git_get_project_config('url')) } : | ||||
| 		   config_to_multi(git_get_project_config('url')); | ||||
| 	my @git_project_url_list = map { chomp; $_ } <$fd>; | ||||
| 	close $fd; | ||||
|  | ||||
|  | @ -1990,12 +2106,12 @@ sub parse_difftree_raw_line { | |||
| 		$res{'to_mode'} = $2; | ||||
| 		$res{'from_id'} = $3; | ||||
| 		$res{'to_id'} = $4; | ||||
| 		$res{'status'} = $5; | ||||
| 		$res{'status'} = $res{'status_str'} = $5; | ||||
| 		$res{'similarity'} = $6; | ||||
| 		if ($res{'status'} eq 'R' || $res{'status'} eq 'C') { # renamed or copied | ||||
| 			($res{'from_file'}, $res{'to_file'}) = map { unquote($_) } split("\t", $7); | ||||
| 		} else { | ||||
| 			$res{'file'} = unquote($7); | ||||
| 			$res{'from_file'} = $res{'to_file'} = $res{'file'} = unquote($7); | ||||
| 		} | ||||
| 	} | ||||
| 	# '::100755 100755 100755 60e79ca1b01bc8b057abe17ddab484699a7f5fdb 94067cc5f73388f33722d52ae02f44692bc07490 94067cc5f73388f33722d52ae02f44692bc07490 MR	git-gui/git-gui.sh' | ||||
|  | @ -2006,6 +2122,7 @@ sub parse_difftree_raw_line { | |||
| 		$res{'to_mode'} = pop @{$res{'from_mode'}}; | ||||
| 		$res{'from_id'} = [ split(' ', $3) ]; | ||||
| 		$res{'to_id'} = pop @{$res{'from_id'}}; | ||||
| 		$res{'status_str'} = $4; | ||||
| 		$res{'status'} = [ split('', $4) ]; | ||||
| 		$res{'to_file'} = unquote($5); | ||||
| 	} | ||||
|  | @ -2062,7 +2179,10 @@ sub parse_from_to_diffinfo { | |||
| 		fill_from_file_info($diffinfo, @parents) | ||||
| 			unless exists $diffinfo->{'from_file'}; | ||||
| 		for (my $i = 0; $i < $diffinfo->{'nparents'}; $i++) { | ||||
| 			$from->{'file'}[$i] = $diffinfo->{'from_file'}[$i] || $diffinfo->{'to_file'}; | ||||
| 			$from->{'file'}[$i] = | ||||
| 				defined $diffinfo->{'from_file'}[$i] ? | ||||
| 				        $diffinfo->{'from_file'}[$i] : | ||||
| 				        $diffinfo->{'to_file'}; | ||||
| 			if ($diffinfo->{'status'}[$i] ne "A") { # not new (added) file | ||||
| 				$from->{'href'}[$i] = href(action=>"blob", | ||||
| 				                           hash_base=>$parents[$i], | ||||
|  | @ -2074,7 +2194,7 @@ sub parse_from_to_diffinfo { | |||
| 		} | ||||
| 	} else { | ||||
| 		# ordinary (not combined) diff | ||||
| 		$from->{'file'} = $diffinfo->{'from_file'} || $diffinfo->{'file'}; | ||||
| 		$from->{'file'} = $diffinfo->{'from_file'}; | ||||
| 		if ($diffinfo->{'status'} ne "A") { # not new (added) file | ||||
| 			$from->{'href'} = href(action=>"blob", hash_base=>$hash_parent, | ||||
| 			                       hash=>$diffinfo->{'from_id'}, | ||||
|  | @ -2084,7 +2204,7 @@ sub parse_from_to_diffinfo { | |||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	$to->{'file'} = $diffinfo->{'to_file'} || $diffinfo->{'file'}; | ||||
| 	$to->{'file'} = $diffinfo->{'to_file'}; | ||||
| 	if (!is_deleted($diffinfo)) { # file exists in result | ||||
| 		$to->{'href'} = href(action=>"blob", hash_base=>$hash, | ||||
| 		                     hash=>$diffinfo->{'to_id'}, | ||||
|  | @ -2505,7 +2625,7 @@ sub format_paging_nav { | |||
|  | ||||
| 	if ($page > 0) { | ||||
| 		$paging_nav .= " ⋅ " . | ||||
| 			$cgi->a({-href => href(action=>$action, hash=>$hash, page=>$page-1), | ||||
| 			$cgi->a({-href => href(-replay=>1, page=>$page-1), | ||||
| 			         -accesskey => "p", -title => "Alt-p"}, "prev"); | ||||
| 	} else { | ||||
| 		$paging_nav .= " ⋅ prev"; | ||||
|  | @ -2513,7 +2633,7 @@ sub format_paging_nav { | |||
|  | ||||
| 	if ($nrevs >= (100 * ($page+1)-1)) { | ||||
| 		$paging_nav .= " ⋅ " . | ||||
| 			$cgi->a({-href => href(action=>$action, hash=>$hash, page=>$page+1), | ||||
| 			$cgi->a({-href => href(-replay=>1, page=>$page+1), | ||||
| 			         -accesskey => "n", -title => "Alt-n"}, "next"); | ||||
| 	} else { | ||||
| 		$paging_nav .= " ⋅ next"; | ||||
|  | @ -2818,7 +2938,7 @@ sub fill_from_file_info { | |||
| sub is_deleted { | ||||
| 	my $diffinfo = shift; | ||||
|  | ||||
| 	return $diffinfo->{'to_id'} eq ('0' x 40); | ||||
| 	return $diffinfo->{'status_str'} =~ /D/; | ||||
| } | ||||
|  | ||||
| # does patch correspond to [previous] difftree raw line | ||||
|  | @ -2829,7 +2949,7 @@ sub is_patch_split { | |||
| 	my ($diffinfo, $patchinfo) = @_; | ||||
|  | ||||
| 	return defined $diffinfo && defined $patchinfo | ||||
| 		&& ($diffinfo->{'to_file'} || $diffinfo->{'file'}) eq $patchinfo->{'to_file'}; | ||||
| 		&& $diffinfo->{'to_file'} eq $patchinfo->{'to_file'}; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | @ -3898,11 +4018,11 @@ sub git_blame2 { | |||
| 		or die_error(undef, "Open git-blame failed"); | ||||
| 	git_header_html(); | ||||
| 	my $formats_nav = | ||||
| 		$cgi->a({-href => href(action=>"blob", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, | ||||
| 		$cgi->a({-href => href(action=>"blob", -replay=>1)}, | ||||
| 		        "blob") . | ||||
| 		" | " . | ||||
| 		$cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)}, | ||||
| 			"history") . | ||||
| 		$cgi->a({-href => href(action=>"history", -replay=>1)}, | ||||
| 		        "history") . | ||||
| 		" | " . | ||||
| 		$cgi->a({-href => href(action=>"blame", file_name=>$file_name)}, | ||||
| 		        "HEAD"); | ||||
|  | @ -4178,18 +4298,15 @@ sub git_blob { | |||
| 		if (defined $file_name) { | ||||
| 			if ($have_blame) { | ||||
| 				$formats_nav .= | ||||
| 					$cgi->a({-href => href(action=>"blame", hash_base=>$hash_base, | ||||
| 					                       hash=>$hash, file_name=>$file_name)}, | ||||
| 					$cgi->a({-href => href(action=>"blame", -replay=>1)}, | ||||
| 					        "blame") . | ||||
| 					" | "; | ||||
| 			} | ||||
| 			$formats_nav .= | ||||
| 				$cgi->a({-href => href(action=>"history", hash_base=>$hash_base, | ||||
| 				                       hash=>$hash, file_name=>$file_name)}, | ||||
| 				$cgi->a({-href => href(action=>"history", -replay=>1)}, | ||||
| 				        "history") . | ||||
| 				" | " . | ||||
| 				$cgi->a({-href => href(action=>"blob_plain", | ||||
| 				                       hash=>$hash, file_name=>$file_name)}, | ||||
| 				$cgi->a({-href => href(action=>"blob_plain", -replay=>1)}, | ||||
| 				        "raw") . | ||||
| 				" | " . | ||||
| 				$cgi->a({-href => href(action=>"blob", | ||||
|  | @ -4197,7 +4314,8 @@ sub git_blob { | |||
| 				        "HEAD"); | ||||
| 		} else { | ||||
| 			$formats_nav .= | ||||
| 				$cgi->a({-href => href(action=>"blob_plain", hash=>$hash)}, "raw"); | ||||
| 				$cgi->a({-href => href(action=>"blob_plain", -replay=>1)}, | ||||
| 				        "raw"); | ||||
| 		} | ||||
| 		git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); | ||||
| 		git_print_header_div('commit', esc_html($co{'title'}), $hash_base); | ||||
|  | @ -4260,8 +4378,7 @@ sub git_tree { | |||
| 		my @views_nav = (); | ||||
| 		if (defined $file_name) { | ||||
| 			push @views_nav, | ||||
| 				$cgi->a({-href => href(action=>"history", hash_base=>$hash_base, | ||||
| 				                       hash=>$hash, file_name=>$file_name)}, | ||||
| 				$cgi->a({-href => href(action=>"history", -replay=>1)}, | ||||
| 				        "history"), | ||||
| 				$cgi->a({-href => href(action=>"tree", | ||||
| 				                       hash_base=>"HEAD", file_name=>$file_name)}, | ||||
|  | @ -4435,7 +4552,7 @@ sub git_log { | |||
| 	} | ||||
| 	if ($#commitlist >= 100) { | ||||
| 		print "<div class=\"page_nav\">\n"; | ||||
| 		print $cgi->a({-href => href(action=>"log", hash=>$hash, page=>$page+1), | ||||
| 		print $cgi->a({-href => href(-replay=>1, page=>$page+1), | ||||
| 			       -accesskey => "n", -title => "Alt-n"}, "next"); | ||||
| 		print "</div>\n"; | ||||
| 	} | ||||
|  | @ -4667,8 +4784,8 @@ sub git_blobdiff { | |||
| 		} | ||||
|  | ||||
| 		%diffinfo = parse_difftree_raw_line($difftree[0]); | ||||
| 		$file_parent ||= $diffinfo{'from_file'} || $file_name || $diffinfo{'file'}; | ||||
| 		$file_name   ||= $diffinfo{'to_file'}   || $diffinfo{'file'}; | ||||
| 		$file_parent ||= $diffinfo{'from_file'} || $file_name; | ||||
| 		$file_name   ||= $diffinfo{'to_file'}; | ||||
|  | ||||
| 		$hash_parent ||= $diffinfo{'from_id'}; | ||||
| 		$hash        ||= $diffinfo{'to_id'}; | ||||
|  | @ -4729,10 +4846,7 @@ sub git_blobdiff { | |||
| 	# header | ||||
| 	if ($format eq 'html') { | ||||
| 		my $formats_nav = | ||||
| 			$cgi->a({-href => href(action=>"blobdiff_plain", | ||||
| 			                       hash=>$hash, hash_parent=>$hash_parent, | ||||
| 			                       hash_base=>$hash_base, hash_parent_base=>$hash_parent_base, | ||||
| 			                       file_name=>$file_name, file_parent=>$file_parent)}, | ||||
| 			$cgi->a({-href => href(action=>"blobdiff_plain", -replay=>1)}, | ||||
| 			        "raw"); | ||||
| 		git_header_html(undef, $expires); | ||||
| 		if (defined $hash_base && (my %co = parse_commit($hash_base))) { | ||||
|  | @ -4806,8 +4920,7 @@ sub git_commitdiff { | |||
| 	my $formats_nav; | ||||
| 	if ($format eq 'html') { | ||||
| 		$formats_nav = | ||||
| 			$cgi->a({-href => href(action=>"commitdiff_plain", | ||||
| 			                       hash=>$hash, hash_parent=>$hash_parent)}, | ||||
| 			$cgi->a({-href => href(action=>"commitdiff_plain", -replay=>1)}, | ||||
| 			        "raw"); | ||||
|  | ||||
| 		if (defined $hash_parent && | ||||
|  | @ -5002,27 +5115,20 @@ sub git_history { | |||
| 			                       file_name=>$file_name)}, | ||||
| 			        "first"); | ||||
| 		$paging_nav .= " ⋅ " . | ||||
| 			$cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base, | ||||
| 			                       file_name=>$file_name, page=>$page-1), | ||||
| 			$cgi->a({-href => href(-replay=>1, page=>$page-1), | ||||
| 			         -accesskey => "p", -title => "Alt-p"}, "prev"); | ||||
| 	} else { | ||||
| 		$paging_nav .= "first"; | ||||
| 		$paging_nav .= " ⋅ prev"; | ||||
| 	} | ||||
| 	if ($#commitlist >= 100) { | ||||
| 		$paging_nav .= " ⋅ " . | ||||
| 			$cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base, | ||||
| 			                       file_name=>$file_name, page=>$page+1), | ||||
| 			         -accesskey => "n", -title => "Alt-n"}, "next"); | ||||
| 	} else { | ||||
| 		$paging_nav .= " ⋅ next"; | ||||
| 	} | ||||
| 	my $next_link = ''; | ||||
| 	if ($#commitlist >= 100) { | ||||
| 		$next_link = | ||||
| 			$cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base, | ||||
| 			                       file_name=>$file_name, page=>$page+1), | ||||
| 			$cgi->a({-href => href(-replay=>1, page=>$page+1), | ||||
| 			         -accesskey => "n", -title => "Alt-n"}, "next"); | ||||
| 		$paging_nav .= " ⋅ $next_link"; | ||||
| 	} else { | ||||
| 		$paging_nav .= " ⋅ next"; | ||||
| 	} | ||||
|  | ||||
| 	git_header_html(); | ||||
|  | @ -5092,30 +5198,23 @@ sub git_search { | |||
| 				                       searchtext=>$searchtext, searchtype=>$searchtype)}, | ||||
| 				        "first"); | ||||
| 			$paging_nav .= " ⋅ " . | ||||
| 				$cgi->a({-href => href(action=>"search", hash=>$hash, | ||||
| 				                       searchtext=>$searchtext, searchtype=>$searchtype, | ||||
| 				                       page=>$page-1), | ||||
| 				$cgi->a({-href => href(-replay=>1, page=>$page-1), | ||||
| 				         -accesskey => "p", -title => "Alt-p"}, "prev"); | ||||
| 		} else { | ||||
| 			$paging_nav .= "first"; | ||||
| 			$paging_nav .= " ⋅ prev"; | ||||
| 		} | ||||
| 		if ($#commitlist >= 100) { | ||||
| 			$paging_nav .= " ⋅ " . | ||||
| 				$cgi->a({-href => href(action=>"search", hash=>$hash, | ||||
| 				                       searchtext=>$searchtext, searchtype=>$searchtype, | ||||
| 				                       page=>$page+1), | ||||
| 				         -accesskey => "n", -title => "Alt-n"}, "next"); | ||||
| 		} else { | ||||
| 			$paging_nav .= " ⋅ next"; | ||||
| 		} | ||||
| 		my $next_link = ''; | ||||
| 		if ($#commitlist >= 100) { | ||||
| 			$next_link = | ||||
| 				$cgi->a({-href => href(action=>"search", hash=>$hash, | ||||
| 				                       searchtext=>$searchtext, searchtype=>$searchtype, | ||||
| 				                       page=>$page+1), | ||||
| 				$cgi->a({-href => href(-replay=>1, page=>$page+1), | ||||
| 				         -accesskey => "n", -title => "Alt-n"}, "next"); | ||||
| 			$paging_nav .= " ⋅ $next_link"; | ||||
| 		} else { | ||||
| 			$paging_nav .= " ⋅ next"; | ||||
| 		} | ||||
|  | ||||
| 		if ($#commitlist >= 100) { | ||||
| 		} | ||||
|  | ||||
| 		git_print_page_nav('','', $hash,$co{'tree'},$hash, $paging_nav); | ||||
|  | @ -5314,7 +5413,7 @@ sub git_shortlog { | |||
| 	my $next_link = ''; | ||||
| 	if ($#commitlist >= 100) { | ||||
| 		$next_link = | ||||
| 			$cgi->a({-href => href(action=>"shortlog", hash=>$hash, page=>$page+1), | ||||
| 			$cgi->a({-href => href(-replay=>1, page=>$page+1), | ||||
| 			         -accesskey => "n", -title => "Alt-n"}, "next"); | ||||
| 	} | ||||
|  | ||||
|  |  | |||
							
								
								
									
										3
									
								
								help.c
								
								
								
								
							
							
						
						
									
										3
									
								
								help.c
								
								
								
								
							|  | @ -79,7 +79,8 @@ static void uniq(struct cmdnames *cmds) | |||
| 	cmds->cnt = j; | ||||
| } | ||||
|  | ||||
| static void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes) { | ||||
| static void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes) | ||||
| { | ||||
| 	int ci, cj, ei; | ||||
| 	int cmp; | ||||
|  | ||||
|  |  | |||
							
								
								
									
										15
									
								
								http-push.c
								
								
								
								
							
							
						
						
									
										15
									
								
								http-push.c
								
								
								
								
							|  | @ -2241,7 +2241,11 @@ static int delete_remote_branch(char *pattern, int force) | |||
|  | ||||
| 		/* Remote branch must be an ancestor of remote HEAD */ | ||||
| 		if (!verify_merge_base(head_sha1, remote_ref->old_sha1)) { | ||||
| 			return error("The branch '%s' is not a strict subset of your current HEAD.\nIf you are sure you want to delete it, run:\n\t'git http-push -D %s %s'", remote_ref->name, remote->url, pattern); | ||||
| 			return error("The branch '%s' is not an ancestor " | ||||
| 				     "of your current HEAD.\n" | ||||
| 				     "If you are sure you want to delete it," | ||||
| 				     " run:\n\t'git http-push -D %s %s'", | ||||
| 				     remote_ref->name, remote->url, pattern); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|  | @ -2417,16 +2421,17 @@ int main(int argc, char **argv) | |||
| 			if (!has_sha1_file(ref->old_sha1) || | ||||
| 			    !ref_newer(ref->peer_ref->new_sha1, | ||||
| 				       ref->old_sha1)) { | ||||
| 				/* We do not have the remote ref, or | ||||
| 				/* | ||||
| 				 * We do not have the remote ref, or | ||||
| 				 * we know that the remote ref is not | ||||
| 				 * an ancestor of what we are trying to | ||||
| 				 * push.  Either way this can be losing | ||||
| 				 * commits at the remote end and likely | ||||
| 				 * we were not up to date to begin with. | ||||
| 				 */ | ||||
| 				error("remote '%s' is not a strict " | ||||
| 				      "subset of local ref '%s'. " | ||||
| 				      "maybe you are not up-to-date and " | ||||
| 				error("remote '%s' is not an ancestor of\n" | ||||
| 				      "local '%s'.\n" | ||||
| 				      "Maybe you are not up-to-date and " | ||||
| 				      "need to pull first?", | ||||
| 				      ref->name, | ||||
| 				      ref->peer_ref->name); | ||||
|  |  | |||
							
								
								
									
										13
									
								
								index-pack.c
								
								
								
								
							
							
						
						
									
										13
									
								
								index-pack.c
								
								
								
								
							|  | @ -683,6 +683,17 @@ static void final(const char *final_pack_name, const char *curr_pack_name, | |||
| 	} | ||||
| } | ||||
|  | ||||
| static int git_index_pack_config(const char *k, const char *v) | ||||
| { | ||||
| 	if (!strcmp(k, "pack.indexversion")) { | ||||
| 		pack_idx_default_version = git_config_int(k, v); | ||||
| 		if (pack_idx_default_version > 2) | ||||
| 			die("bad pack.indexversion=%d", pack_idx_default_version); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return git_default_config(k, v); | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	int i, fix_thin_pack = 0; | ||||
|  | @ -693,6 +704,8 @@ int main(int argc, char **argv) | |||
| 	struct pack_idx_entry **idx_objects; | ||||
| 	unsigned char sha1[20]; | ||||
|  | ||||
| 	git_config(git_index_pack_config); | ||||
|  | ||||
| 	for (i = 1; i < argc; i++) { | ||||
| 		char *arg = argv[i]; | ||||
|  | ||||
|  |  | |||
							
								
								
									
										15
									
								
								log-tree.c
								
								
								
								
							
							
						
						
									
										15
									
								
								log-tree.c
								
								
								
								
							|  | @ -125,6 +125,18 @@ static unsigned int digits_in_number(unsigned int number) | |||
| 	return result; | ||||
| } | ||||
|  | ||||
| static int has_non_ascii(const char *s) | ||||
| { | ||||
| 	int ch; | ||||
| 	if (!s) | ||||
| 		return 0; | ||||
| 	while ((ch = *s++) != '\0') { | ||||
| 		if (non_ascii(ch)) | ||||
| 			return 1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void show_log(struct rev_info *opt, const char *sep) | ||||
| { | ||||
| 	struct strbuf msgbuf; | ||||
|  | @ -273,7 +285,8 @@ void show_log(struct rev_info *opt, const char *sep) | |||
| 	 */ | ||||
| 	strbuf_init(&msgbuf, 0); | ||||
| 	pretty_print_commit(opt->commit_format, commit, &msgbuf, | ||||
| 				  abbrev, subject, extra_headers, opt->date_mode); | ||||
| 			    abbrev, subject, extra_headers, opt->date_mode, | ||||
| 			    has_non_ascii(opt->add_signoff)); | ||||
|  | ||||
| 	if (opt->add_signoff) | ||||
| 		append_signoff(&msgbuf, opt->add_signoff); | ||||
|  |  | |||
|  | @ -22,6 +22,41 @@ enum parse_opt_option_flags { | |||
| struct option; | ||||
| typedef int parse_opt_cb(const struct option *, const char *arg, int unset); | ||||
|  | ||||
| /* | ||||
|  * `type`:: | ||||
|  *   holds the type of the option, you must have an OPTION_END last in your | ||||
|  *   array. | ||||
|  * | ||||
|  * `short_name`:: | ||||
|  *   the character to use as a short option name, '\0' if none. | ||||
|  * | ||||
|  * `long_name`:: | ||||
|  *   the long option name, without the leading dashes, NULL if none. | ||||
|  * | ||||
|  * `value`:: | ||||
|  *   stores pointers to the values to be filled. | ||||
|  * | ||||
|  * `argh`:: | ||||
|  *   token to explain the kind of argument this option wants. Keep it | ||||
|  *   homogenous across the repository. | ||||
|  * | ||||
|  * `help`:: | ||||
|  *   the short help associated to what the option does. | ||||
|  *   Must never be NULL (except for OPTION_END). | ||||
|  *   OPTION_GROUP uses this pointer to store the group header. | ||||
|  * | ||||
|  * `flags`:: | ||||
|  *   mask of parse_opt_option_flags. | ||||
|  *   PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs) | ||||
|  *   PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs | ||||
|  * | ||||
|  * `callback`:: | ||||
|  *   pointer to the callback to use for OPTION_CALLBACK. | ||||
|  * | ||||
|  * `defval`:: | ||||
|  *   default value to fill (*->value) with for PARSE_OPT_OPTARG. | ||||
|  *   CALLBACKS can use it like they want. | ||||
|  */ | ||||
| struct option { | ||||
| 	enum parse_opt_type type; | ||||
| 	int short_name; | ||||
|  | @ -32,8 +67,6 @@ struct option { | |||
|  | ||||
| 	int flags; | ||||
| 	parse_opt_cb *callback; | ||||
| 	/* holds default value for PARSE_OPT_OPTARG, | ||||
| 	   though callbacks can use it like they want */ | ||||
| 	intptr_t defval; | ||||
| }; | ||||
|  | ||||
|  |  | |||
|  | @ -812,7 +812,7 @@ sub _cmd_exec { | |||
| 		$self->wc_subdir() and chdir($self->wc_subdir()); | ||||
| 	} | ||||
| 	_execv_git_cmd(@args); | ||||
| 	die "exec failed: $!"; | ||||
| 	die qq[exec "@args" failed: $!]; | ||||
| } | ||||
|  | ||||
| # Execute the given Git command ($_[0]) with arguments ($_[1..]) | ||||
|  |  | |||
|  | @ -0,0 +1,723 @@ | |||
| #include "cache.h" | ||||
| #include "commit.h" | ||||
| #include "interpolate.h" | ||||
| #include "utf8.h" | ||||
| #include "diff.h" | ||||
| #include "revision.h" | ||||
|  | ||||
| static struct cmt_fmt_map { | ||||
| 	const char *n; | ||||
| 	size_t cmp_len; | ||||
| 	enum cmit_fmt v; | ||||
| } cmt_fmts[] = { | ||||
| 	{ "raw",	1,	CMIT_FMT_RAW }, | ||||
| 	{ "medium",	1,	CMIT_FMT_MEDIUM }, | ||||
| 	{ "short",	1,	CMIT_FMT_SHORT }, | ||||
| 	{ "email",	1,	CMIT_FMT_EMAIL }, | ||||
| 	{ "full",	5,	CMIT_FMT_FULL }, | ||||
| 	{ "fuller",	5,	CMIT_FMT_FULLER }, | ||||
| 	{ "oneline",	1,	CMIT_FMT_ONELINE }, | ||||
| 	{ "format:",	7,	CMIT_FMT_USERFORMAT}, | ||||
| }; | ||||
|  | ||||
| static char *user_format; | ||||
|  | ||||
| enum cmit_fmt get_commit_format(const char *arg) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	if (!arg || !*arg) | ||||
| 		return CMIT_FMT_DEFAULT; | ||||
| 	if (*arg == '=') | ||||
| 		arg++; | ||||
| 	if (!prefixcmp(arg, "format:")) { | ||||
| 		if (user_format) | ||||
| 			free(user_format); | ||||
| 		user_format = xstrdup(arg + 7); | ||||
| 		return CMIT_FMT_USERFORMAT; | ||||
| 	} | ||||
| 	for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) { | ||||
| 		if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) && | ||||
| 		    !strncmp(arg, cmt_fmts[i].n, strlen(arg))) | ||||
| 			return cmt_fmts[i].v; | ||||
| 	} | ||||
|  | ||||
| 	die("invalid --pretty format: %s", arg); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Generic support for pretty-printing the header | ||||
|  */ | ||||
| static int get_one_line(const char *msg) | ||||
| { | ||||
| 	int ret = 0; | ||||
|  | ||||
| 	for (;;) { | ||||
| 		char c = *msg++; | ||||
| 		if (!c) | ||||
| 			break; | ||||
| 		ret++; | ||||
| 		if (c == '\n') | ||||
| 			break; | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* High bit set, or ISO-2022-INT */ | ||||
| int non_ascii(int ch) | ||||
| { | ||||
| 	ch = (ch & 0xff); | ||||
| 	return ((ch & 0x80) || (ch == 0x1b)); | ||||
| } | ||||
|  | ||||
| static int is_rfc2047_special(char ch) | ||||
| { | ||||
| 	return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_')); | ||||
| } | ||||
|  | ||||
| static void add_rfc2047(struct strbuf *sb, const char *line, int len, | ||||
| 		       const char *encoding) | ||||
| { | ||||
| 	int i, last; | ||||
|  | ||||
| 	for (i = 0; i < len; i++) { | ||||
| 		int ch = line[i]; | ||||
| 		if (non_ascii(ch)) | ||||
| 			goto needquote; | ||||
| 		if ((i + 1 < len) && (ch == '=' && line[i+1] == '?')) | ||||
| 			goto needquote; | ||||
| 	} | ||||
| 	strbuf_add(sb, line, len); | ||||
| 	return; | ||||
|  | ||||
| needquote: | ||||
| 	strbuf_grow(sb, len * 3 + strlen(encoding) + 100); | ||||
| 	strbuf_addf(sb, "=?%s?q?", encoding); | ||||
| 	for (i = last = 0; i < len; i++) { | ||||
| 		unsigned ch = line[i] & 0xFF; | ||||
| 		/* | ||||
| 		 * We encode ' ' using '=20' even though rfc2047 | ||||
| 		 * allows using '_' for readability.  Unfortunately, | ||||
| 		 * many programs do not understand this and just | ||||
| 		 * leave the underscore in place. | ||||
| 		 */ | ||||
| 		if (is_rfc2047_special(ch) || ch == ' ') { | ||||
| 			strbuf_add(sb, line + last, i - last); | ||||
| 			strbuf_addf(sb, "=%02X", ch); | ||||
| 			last = i + 1; | ||||
| 		} | ||||
| 	} | ||||
| 	strbuf_add(sb, line + last, len - last); | ||||
| 	strbuf_addstr(sb, "?="); | ||||
| } | ||||
|  | ||||
| static void add_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb, | ||||
| 			 const char *line, enum date_mode dmode, | ||||
| 			 const char *encoding) | ||||
| { | ||||
| 	char *date; | ||||
| 	int namelen; | ||||
| 	unsigned long time; | ||||
| 	int tz; | ||||
| 	const char *filler = "    "; | ||||
|  | ||||
| 	if (fmt == CMIT_FMT_ONELINE) | ||||
| 		return; | ||||
| 	date = strchr(line, '>'); | ||||
| 	if (!date) | ||||
| 		return; | ||||
| 	namelen = ++date - line; | ||||
| 	time = strtoul(date, &date, 10); | ||||
| 	tz = strtol(date, NULL, 10); | ||||
|  | ||||
| 	if (fmt == CMIT_FMT_EMAIL) { | ||||
| 		char *name_tail = strchr(line, '<'); | ||||
| 		int display_name_length; | ||||
| 		if (!name_tail) | ||||
| 			return; | ||||
| 		while (line < name_tail && isspace(name_tail[-1])) | ||||
| 			name_tail--; | ||||
| 		display_name_length = name_tail - line; | ||||
| 		filler = ""; | ||||
| 		strbuf_addstr(sb, "From: "); | ||||
| 		add_rfc2047(sb, line, display_name_length, encoding); | ||||
| 		strbuf_add(sb, name_tail, namelen - display_name_length); | ||||
| 		strbuf_addch(sb, '\n'); | ||||
| 	} else { | ||||
| 		strbuf_addf(sb, "%s: %.*s%.*s\n", what, | ||||
| 			      (fmt == CMIT_FMT_FULLER) ? 4 : 0, | ||||
| 			      filler, namelen, line); | ||||
| 	} | ||||
| 	switch (fmt) { | ||||
| 	case CMIT_FMT_MEDIUM: | ||||
| 		strbuf_addf(sb, "Date:   %s\n", show_date(time, tz, dmode)); | ||||
| 		break; | ||||
| 	case CMIT_FMT_EMAIL: | ||||
| 		strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822)); | ||||
| 		break; | ||||
| 	case CMIT_FMT_FULLER: | ||||
| 		strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, dmode)); | ||||
| 		break; | ||||
| 	default: | ||||
| 		/* notin' */ | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int is_empty_line(const char *line, int *len_p) | ||||
| { | ||||
| 	int len = *len_p; | ||||
| 	while (len && isspace(line[len-1])) | ||||
| 		len--; | ||||
| 	*len_p = len; | ||||
| 	return !len; | ||||
| } | ||||
|  | ||||
| static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb, | ||||
| 			const struct commit *commit, int abbrev) | ||||
| { | ||||
| 	struct commit_list *parent = commit->parents; | ||||
|  | ||||
| 	if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) || | ||||
| 	    !parent || !parent->next) | ||||
| 		return; | ||||
|  | ||||
| 	strbuf_addstr(sb, "Merge:"); | ||||
|  | ||||
| 	while (parent) { | ||||
| 		struct commit *p = parent->item; | ||||
| 		const char *hex = NULL; | ||||
| 		const char *dots; | ||||
| 		if (abbrev) | ||||
| 			hex = find_unique_abbrev(p->object.sha1, abbrev); | ||||
| 		if (!hex) | ||||
| 			hex = sha1_to_hex(p->object.sha1); | ||||
| 		dots = (abbrev && strlen(hex) != 40) ?  "..." : ""; | ||||
| 		parent = parent->next; | ||||
|  | ||||
| 		strbuf_addf(sb, " %s%s", hex, dots); | ||||
| 	} | ||||
| 	strbuf_addch(sb, '\n'); | ||||
| } | ||||
|  | ||||
| static char *get_header(const struct commit *commit, const char *key) | ||||
| { | ||||
| 	int key_len = strlen(key); | ||||
| 	const char *line = commit->buffer; | ||||
|  | ||||
| 	for (;;) { | ||||
| 		const char *eol = strchr(line, '\n'), *next; | ||||
|  | ||||
| 		if (line == eol) | ||||
| 			return NULL; | ||||
| 		if (!eol) { | ||||
| 			eol = line + strlen(line); | ||||
| 			next = NULL; | ||||
| 		} else | ||||
| 			next = eol + 1; | ||||
| 		if (eol - line > key_len && | ||||
| 		    !strncmp(line, key, key_len) && | ||||
| 		    line[key_len] == ' ') { | ||||
| 			return xmemdupz(line + key_len + 1, eol - line - key_len - 1); | ||||
| 		} | ||||
| 		line = next; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static char *replace_encoding_header(char *buf, const char *encoding) | ||||
| { | ||||
| 	struct strbuf tmp; | ||||
| 	size_t start, len; | ||||
| 	char *cp = buf; | ||||
|  | ||||
| 	/* guess if there is an encoding header before a \n\n */ | ||||
| 	while (strncmp(cp, "encoding ", strlen("encoding "))) { | ||||
| 		cp = strchr(cp, '\n'); | ||||
| 		if (!cp || *++cp == '\n') | ||||
| 			return buf; | ||||
| 	} | ||||
| 	start = cp - buf; | ||||
| 	cp = strchr(cp, '\n'); | ||||
| 	if (!cp) | ||||
| 		return buf; /* should not happen but be defensive */ | ||||
| 	len = cp + 1 - (buf + start); | ||||
|  | ||||
| 	strbuf_init(&tmp, 0); | ||||
| 	strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1); | ||||
| 	if (is_encoding_utf8(encoding)) { | ||||
| 		/* we have re-coded to UTF-8; drop the header */ | ||||
| 		strbuf_remove(&tmp, start, len); | ||||
| 	} else { | ||||
| 		/* just replaces XXXX in 'encoding XXXX\n' */ | ||||
| 		strbuf_splice(&tmp, start + strlen("encoding "), | ||||
| 					  len - strlen("encoding \n"), | ||||
| 					  encoding, strlen(encoding)); | ||||
| 	} | ||||
| 	return strbuf_detach(&tmp, NULL); | ||||
| } | ||||
|  | ||||
| static char *logmsg_reencode(const struct commit *commit, | ||||
| 			     const char *output_encoding) | ||||
| { | ||||
| 	static const char *utf8 = "utf-8"; | ||||
| 	const char *use_encoding; | ||||
| 	char *encoding; | ||||
| 	char *out; | ||||
|  | ||||
| 	if (!*output_encoding) | ||||
| 		return NULL; | ||||
| 	encoding = get_header(commit, "encoding"); | ||||
| 	use_encoding = encoding ? encoding : utf8; | ||||
| 	if (!strcmp(use_encoding, output_encoding)) | ||||
| 		if (encoding) /* we'll strip encoding header later */ | ||||
| 			out = xstrdup(commit->buffer); | ||||
| 		else | ||||
| 			return NULL; /* nothing to do */ | ||||
| 	else | ||||
| 		out = reencode_string(commit->buffer, | ||||
| 				      output_encoding, use_encoding); | ||||
| 	if (out) | ||||
| 		out = replace_encoding_header(out, output_encoding); | ||||
|  | ||||
| 	free(encoding); | ||||
| 	return out; | ||||
| } | ||||
|  | ||||
| static void fill_person(struct interp *table, const char *msg, int len) | ||||
| { | ||||
| 	int start, end, tz = 0; | ||||
| 	unsigned long date; | ||||
| 	char *ep; | ||||
|  | ||||
| 	/* parse name */ | ||||
| 	for (end = 0; end < len && msg[end] != '<'; end++) | ||||
| 		; /* do nothing */ | ||||
| 	start = end + 1; | ||||
| 	while (end > 0 && isspace(msg[end - 1])) | ||||
| 		end--; | ||||
| 	table[0].value = xmemdupz(msg, end); | ||||
|  | ||||
| 	if (start >= len) | ||||
| 		return; | ||||
|  | ||||
| 	/* parse email */ | ||||
| 	for (end = start + 1; end < len && msg[end] != '>'; end++) | ||||
| 		; /* do nothing */ | ||||
|  | ||||
| 	if (end >= len) | ||||
| 		return; | ||||
|  | ||||
| 	table[1].value = xmemdupz(msg + start, end - start); | ||||
|  | ||||
| 	/* parse date */ | ||||
| 	for (start = end + 1; start < len && isspace(msg[start]); start++) | ||||
| 		; /* do nothing */ | ||||
| 	if (start >= len) | ||||
| 		return; | ||||
| 	date = strtoul(msg + start, &ep, 10); | ||||
| 	if (msg + start == ep) | ||||
| 		return; | ||||
|  | ||||
| 	table[5].value = xmemdupz(msg + start, ep - (msg + start)); | ||||
|  | ||||
| 	/* parse tz */ | ||||
| 	for (start = ep - msg + 1; start < len && isspace(msg[start]); start++) | ||||
| 		; /* do nothing */ | ||||
| 	if (start + 1 < len) { | ||||
| 		tz = strtoul(msg + start + 1, NULL, 10); | ||||
| 		if (msg[start] == '-') | ||||
| 			tz = -tz; | ||||
| 	} | ||||
|  | ||||
| 	interp_set_entry(table, 2, show_date(date, tz, DATE_NORMAL)); | ||||
| 	interp_set_entry(table, 3, show_date(date, tz, DATE_RFC2822)); | ||||
| 	interp_set_entry(table, 4, show_date(date, tz, DATE_RELATIVE)); | ||||
| 	interp_set_entry(table, 6, show_date(date, tz, DATE_ISO8601)); | ||||
| } | ||||
|  | ||||
| void format_commit_message(const struct commit *commit, | ||||
|                            const void *format, struct strbuf *sb) | ||||
| { | ||||
| 	struct interp table[] = { | ||||
| 		{ "%H" },	/* commit hash */ | ||||
| 		{ "%h" },	/* abbreviated commit hash */ | ||||
| 		{ "%T" },	/* tree hash */ | ||||
| 		{ "%t" },	/* abbreviated tree hash */ | ||||
| 		{ "%P" },	/* parent hashes */ | ||||
| 		{ "%p" },	/* abbreviated parent hashes */ | ||||
| 		{ "%an" },	/* author name */ | ||||
| 		{ "%ae" },	/* author email */ | ||||
| 		{ "%ad" },	/* author date */ | ||||
| 		{ "%aD" },	/* author date, RFC2822 style */ | ||||
| 		{ "%ar" },	/* author date, relative */ | ||||
| 		{ "%at" },	/* author date, UNIX timestamp */ | ||||
| 		{ "%ai" },	/* author date, ISO 8601 */ | ||||
| 		{ "%cn" },	/* committer name */ | ||||
| 		{ "%ce" },	/* committer email */ | ||||
| 		{ "%cd" },	/* committer date */ | ||||
| 		{ "%cD" },	/* committer date, RFC2822 style */ | ||||
| 		{ "%cr" },	/* committer date, relative */ | ||||
| 		{ "%ct" },	/* committer date, UNIX timestamp */ | ||||
| 		{ "%ci" },	/* committer date, ISO 8601 */ | ||||
| 		{ "%e" },	/* encoding */ | ||||
| 		{ "%s" },	/* subject */ | ||||
| 		{ "%b" },	/* body */ | ||||
| 		{ "%Cred" },	/* red */ | ||||
| 		{ "%Cgreen" },	/* green */ | ||||
| 		{ "%Cblue" },	/* blue */ | ||||
| 		{ "%Creset" },	/* reset color */ | ||||
| 		{ "%n" },	/* newline */ | ||||
| 		{ "%m" },	/* left/right/bottom */ | ||||
| 	}; | ||||
| 	enum interp_index { | ||||
| 		IHASH = 0, IHASH_ABBREV, | ||||
| 		ITREE, ITREE_ABBREV, | ||||
| 		IPARENTS, IPARENTS_ABBREV, | ||||
| 		IAUTHOR_NAME, IAUTHOR_EMAIL, | ||||
| 		IAUTHOR_DATE, IAUTHOR_DATE_RFC2822, IAUTHOR_DATE_RELATIVE, | ||||
| 		IAUTHOR_TIMESTAMP, IAUTHOR_ISO8601, | ||||
| 		ICOMMITTER_NAME, ICOMMITTER_EMAIL, | ||||
| 		ICOMMITTER_DATE, ICOMMITTER_DATE_RFC2822, | ||||
| 		ICOMMITTER_DATE_RELATIVE, ICOMMITTER_TIMESTAMP, | ||||
| 		ICOMMITTER_ISO8601, | ||||
| 		IENCODING, | ||||
| 		ISUBJECT, | ||||
| 		IBODY, | ||||
| 		IRED, IGREEN, IBLUE, IRESET_COLOR, | ||||
| 		INEWLINE, | ||||
| 		ILEFT_RIGHT, | ||||
| 	}; | ||||
| 	struct commit_list *p; | ||||
| 	char parents[1024]; | ||||
| 	unsigned long len; | ||||
| 	int i; | ||||
| 	enum { HEADER, SUBJECT, BODY } state; | ||||
| 	const char *msg = commit->buffer; | ||||
|  | ||||
| 	if (ILEFT_RIGHT + 1 != ARRAY_SIZE(table)) | ||||
| 		die("invalid interp table!"); | ||||
|  | ||||
| 	/* these are independent of the commit */ | ||||
| 	interp_set_entry(table, IRED, "\033[31m"); | ||||
| 	interp_set_entry(table, IGREEN, "\033[32m"); | ||||
| 	interp_set_entry(table, IBLUE, "\033[34m"); | ||||
| 	interp_set_entry(table, IRESET_COLOR, "\033[m"); | ||||
| 	interp_set_entry(table, INEWLINE, "\n"); | ||||
|  | ||||
| 	/* these depend on the commit */ | ||||
| 	if (!commit->object.parsed) | ||||
| 		parse_object(commit->object.sha1); | ||||
| 	interp_set_entry(table, IHASH, sha1_to_hex(commit->object.sha1)); | ||||
| 	interp_set_entry(table, IHASH_ABBREV, | ||||
| 			find_unique_abbrev(commit->object.sha1, | ||||
| 				DEFAULT_ABBREV)); | ||||
| 	interp_set_entry(table, ITREE, sha1_to_hex(commit->tree->object.sha1)); | ||||
| 	interp_set_entry(table, ITREE_ABBREV, | ||||
| 			find_unique_abbrev(commit->tree->object.sha1, | ||||
| 				DEFAULT_ABBREV)); | ||||
| 	interp_set_entry(table, ILEFT_RIGHT, | ||||
| 			 (commit->object.flags & BOUNDARY) | ||||
| 			 ? "-" | ||||
| 			 : (commit->object.flags & SYMMETRIC_LEFT) | ||||
| 			 ? "<" | ||||
| 			 : ">"); | ||||
|  | ||||
| 	parents[1] = 0; | ||||
| 	for (i = 0, p = commit->parents; | ||||
| 			p && i < sizeof(parents) - 1; | ||||
| 			p = p->next) | ||||
| 		i += snprintf(parents + i, sizeof(parents) - i - 1, " %s", | ||||
| 			sha1_to_hex(p->item->object.sha1)); | ||||
| 	interp_set_entry(table, IPARENTS, parents + 1); | ||||
|  | ||||
| 	parents[1] = 0; | ||||
| 	for (i = 0, p = commit->parents; | ||||
| 			p && i < sizeof(parents) - 1; | ||||
| 			p = p->next) | ||||
| 		i += snprintf(parents + i, sizeof(parents) - i - 1, " %s", | ||||
| 			find_unique_abbrev(p->item->object.sha1, | ||||
| 				DEFAULT_ABBREV)); | ||||
| 	interp_set_entry(table, IPARENTS_ABBREV, parents + 1); | ||||
|  | ||||
| 	for (i = 0, state = HEADER; msg[i] && state < BODY; i++) { | ||||
| 		int eol; | ||||
| 		for (eol = i; msg[eol] && msg[eol] != '\n'; eol++) | ||||
| 			; /* do nothing */ | ||||
|  | ||||
| 		if (state == SUBJECT) { | ||||
| 			table[ISUBJECT].value = xmemdupz(msg + i, eol - i); | ||||
| 			i = eol; | ||||
| 		} | ||||
| 		if (i == eol) { | ||||
| 			state++; | ||||
| 			/* strip empty lines */ | ||||
| 			while (msg[eol + 1] == '\n') | ||||
| 				eol++; | ||||
| 		} else if (!prefixcmp(msg + i, "author ")) | ||||
| 			fill_person(table + IAUTHOR_NAME, | ||||
| 					msg + i + 7, eol - i - 7); | ||||
| 		else if (!prefixcmp(msg + i, "committer ")) | ||||
| 			fill_person(table + ICOMMITTER_NAME, | ||||
| 					msg + i + 10, eol - i - 10); | ||||
| 		else if (!prefixcmp(msg + i, "encoding ")) | ||||
| 			table[IENCODING].value = | ||||
| 				xmemdupz(msg + i + 9, eol - i - 9); | ||||
| 		i = eol; | ||||
| 	} | ||||
| 	if (msg[i]) | ||||
| 		table[IBODY].value = xstrdup(msg + i); | ||||
|  | ||||
| 	len = interpolate(sb->buf + sb->len, strbuf_avail(sb), | ||||
| 				format, table, ARRAY_SIZE(table)); | ||||
| 	if (len > strbuf_avail(sb)) { | ||||
| 		strbuf_grow(sb, len); | ||||
| 		interpolate(sb->buf + sb->len, strbuf_avail(sb) + 1, | ||||
| 					format, table, ARRAY_SIZE(table)); | ||||
| 	} | ||||
| 	strbuf_setlen(sb, sb->len + len); | ||||
| 	interp_clear_table(table, ARRAY_SIZE(table)); | ||||
| } | ||||
|  | ||||
| static void pp_header(enum cmit_fmt fmt, | ||||
| 		      int abbrev, | ||||
| 		      enum date_mode dmode, | ||||
| 		      const char *encoding, | ||||
| 		      const struct commit *commit, | ||||
| 		      const char **msg_p, | ||||
| 		      struct strbuf *sb) | ||||
| { | ||||
| 	int parents_shown = 0; | ||||
|  | ||||
| 	for (;;) { | ||||
| 		const char *line = *msg_p; | ||||
| 		int linelen = get_one_line(*msg_p); | ||||
|  | ||||
| 		if (!linelen) | ||||
| 			return; | ||||
| 		*msg_p += linelen; | ||||
|  | ||||
| 		if (linelen == 1) | ||||
| 			/* End of header */ | ||||
| 			return; | ||||
|  | ||||
| 		if (fmt == CMIT_FMT_RAW) { | ||||
| 			strbuf_add(sb, line, linelen); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (!memcmp(line, "parent ", 7)) { | ||||
| 			if (linelen != 48) | ||||
| 				die("bad parent line in commit"); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (!parents_shown) { | ||||
| 			struct commit_list *parent; | ||||
| 			int num; | ||||
| 			for (parent = commit->parents, num = 0; | ||||
| 			     parent; | ||||
| 			     parent = parent->next, num++) | ||||
| 				; | ||||
| 			/* with enough slop */ | ||||
| 			strbuf_grow(sb, num * 50 + 20); | ||||
| 			add_merge_info(fmt, sb, commit, abbrev); | ||||
| 			parents_shown = 1; | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		 * MEDIUM == DEFAULT shows only author with dates. | ||||
| 		 * FULL shows both authors but not dates. | ||||
| 		 * FULLER shows both authors and dates. | ||||
| 		 */ | ||||
| 		if (!memcmp(line, "author ", 7)) { | ||||
| 			strbuf_grow(sb, linelen + 80); | ||||
| 			add_user_info("Author", fmt, sb, line + 7, dmode, encoding); | ||||
| 		} | ||||
| 		if (!memcmp(line, "committer ", 10) && | ||||
| 		    (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) { | ||||
| 			strbuf_grow(sb, linelen + 80); | ||||
| 			add_user_info("Commit", fmt, sb, line + 10, dmode, encoding); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void pp_title_line(enum cmit_fmt fmt, | ||||
| 			  const char **msg_p, | ||||
| 			  struct strbuf *sb, | ||||
| 			  const char *subject, | ||||
| 			  const char *after_subject, | ||||
| 			  const char *encoding, | ||||
| 			  int plain_non_ascii) | ||||
| { | ||||
| 	struct strbuf title; | ||||
|  | ||||
| 	strbuf_init(&title, 80); | ||||
|  | ||||
| 	for (;;) { | ||||
| 		const char *line = *msg_p; | ||||
| 		int linelen = get_one_line(line); | ||||
|  | ||||
| 		*msg_p += linelen; | ||||
| 		if (!linelen || is_empty_line(line, &linelen)) | ||||
| 			break; | ||||
|  | ||||
| 		strbuf_grow(&title, linelen + 2); | ||||
| 		if (title.len) { | ||||
| 			if (fmt == CMIT_FMT_EMAIL) { | ||||
| 				strbuf_addch(&title, '\n'); | ||||
| 			} | ||||
| 			strbuf_addch(&title, ' '); | ||||
| 		} | ||||
| 		strbuf_add(&title, line, linelen); | ||||
| 	} | ||||
|  | ||||
| 	strbuf_grow(sb, title.len + 1024); | ||||
| 	if (subject) { | ||||
| 		strbuf_addstr(sb, subject); | ||||
| 		add_rfc2047(sb, title.buf, title.len, encoding); | ||||
| 	} else { | ||||
| 		strbuf_addbuf(sb, &title); | ||||
| 	} | ||||
| 	strbuf_addch(sb, '\n'); | ||||
|  | ||||
| 	if (plain_non_ascii) { | ||||
| 		const char *header_fmt = | ||||
| 			"MIME-Version: 1.0\n" | ||||
| 			"Content-Type: text/plain; charset=%s\n" | ||||
| 			"Content-Transfer-Encoding: 8bit\n"; | ||||
| 		strbuf_addf(sb, header_fmt, encoding); | ||||
| 	} | ||||
| 	if (after_subject) { | ||||
| 		strbuf_addstr(sb, after_subject); | ||||
| 	} | ||||
| 	if (fmt == CMIT_FMT_EMAIL) { | ||||
| 		strbuf_addch(sb, '\n'); | ||||
| 	} | ||||
| 	strbuf_release(&title); | ||||
| } | ||||
|  | ||||
| static void pp_remainder(enum cmit_fmt fmt, | ||||
| 			 const char **msg_p, | ||||
| 			 struct strbuf *sb, | ||||
| 			 int indent) | ||||
| { | ||||
| 	int first = 1; | ||||
| 	for (;;) { | ||||
| 		const char *line = *msg_p; | ||||
| 		int linelen = get_one_line(line); | ||||
| 		*msg_p += linelen; | ||||
|  | ||||
| 		if (!linelen) | ||||
| 			break; | ||||
|  | ||||
| 		if (is_empty_line(line, &linelen)) { | ||||
| 			if (first) | ||||
| 				continue; | ||||
| 			if (fmt == CMIT_FMT_SHORT) | ||||
| 				break; | ||||
| 		} | ||||
| 		first = 0; | ||||
|  | ||||
| 		strbuf_grow(sb, linelen + indent + 20); | ||||
| 		if (indent) { | ||||
| 			memset(sb->buf + sb->len, ' ', indent); | ||||
| 			strbuf_setlen(sb, sb->len + indent); | ||||
| 		} | ||||
| 		strbuf_add(sb, line, linelen); | ||||
| 		strbuf_addch(sb, '\n'); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, | ||||
| 				  struct strbuf *sb, int abbrev, | ||||
| 				  const char *subject, const char *after_subject, | ||||
| 				  enum date_mode dmode, int plain_non_ascii) | ||||
| { | ||||
| 	unsigned long beginning_of_body; | ||||
| 	int indent = 4; | ||||
| 	const char *msg = commit->buffer; | ||||
| 	char *reencoded; | ||||
| 	const char *encoding; | ||||
|  | ||||
| 	if (fmt == CMIT_FMT_USERFORMAT) { | ||||
| 		format_commit_message(commit, user_format, sb); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	encoding = (git_log_output_encoding | ||||
| 		    ? git_log_output_encoding | ||||
| 		    : git_commit_encoding); | ||||
| 	if (!encoding) | ||||
| 		encoding = "utf-8"; | ||||
| 	reencoded = logmsg_reencode(commit, encoding); | ||||
| 	if (reencoded) { | ||||
| 		msg = reencoded; | ||||
| 	} | ||||
|  | ||||
| 	if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) | ||||
| 		indent = 0; | ||||
|  | ||||
| 	/* After-subject is used to pass in Content-Type: multipart | ||||
| 	 * MIME header; in that case we do not have to do the | ||||
| 	 * plaintext content type even if the commit message has | ||||
| 	 * non 7-bit ASCII character.  Otherwise, check if we need | ||||
| 	 * to say this is not a 7-bit ASCII. | ||||
| 	 */ | ||||
| 	if (fmt == CMIT_FMT_EMAIL && !after_subject) { | ||||
| 		int i, ch, in_body; | ||||
|  | ||||
| 		for (in_body = i = 0; (ch = msg[i]); i++) { | ||||
| 			if (!in_body) { | ||||
| 				/* author could be non 7-bit ASCII but | ||||
| 				 * the log may be so; skip over the | ||||
| 				 * header part first. | ||||
| 				 */ | ||||
| 				if (ch == '\n' && msg[i+1] == '\n') | ||||
| 					in_body = 1; | ||||
| 			} | ||||
| 			else if (non_ascii(ch)) { | ||||
| 				plain_non_ascii = 1; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	pp_header(fmt, abbrev, dmode, encoding, commit, &msg, sb); | ||||
| 	if (fmt != CMIT_FMT_ONELINE && !subject) { | ||||
| 		strbuf_addch(sb, '\n'); | ||||
| 	} | ||||
|  | ||||
| 	/* Skip excess blank lines at the beginning of body, if any... */ | ||||
| 	for (;;) { | ||||
| 		int linelen = get_one_line(msg); | ||||
| 		int ll = linelen; | ||||
| 		if (!linelen) | ||||
| 			break; | ||||
| 		if (!is_empty_line(msg, &ll)) | ||||
| 			break; | ||||
| 		msg += linelen; | ||||
| 	} | ||||
|  | ||||
| 	/* These formats treat the title line specially. */ | ||||
| 	if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) | ||||
| 		pp_title_line(fmt, &msg, sb, subject, | ||||
| 			      after_subject, encoding, plain_non_ascii); | ||||
|  | ||||
| 	beginning_of_body = sb->len; | ||||
| 	if (fmt != CMIT_FMT_ONELINE) | ||||
| 		pp_remainder(fmt, &msg, sb, indent); | ||||
| 	strbuf_rtrim(sb); | ||||
|  | ||||
| 	/* Make sure there is an EOLN for the non-oneline case */ | ||||
| 	if (fmt != CMIT_FMT_ONELINE) | ||||
| 		strbuf_addch(sb, '\n'); | ||||
|  | ||||
| 	/* | ||||
| 	 * The caller may append additional body text in e-mail | ||||
| 	 * format.  Make sure we did not strip the blank line | ||||
| 	 * between the header and the body. | ||||
| 	 */ | ||||
| 	if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body) | ||||
| 		strbuf_addch(sb, '\n'); | ||||
| 	free(reencoded); | ||||
| } | ||||
							
								
								
									
										5
									
								
								quote.c
								
								
								
								
							
							
						
						
									
										5
									
								
								quote.c
								
								
								
								
							|  | @ -26,7 +26,7 @@ void sq_quote_buf(struct strbuf *dst, const char *src) | |||
|  | ||||
| 	strbuf_addch(dst, '\''); | ||||
| 	while (*src) { | ||||
| 		size_t len = strcspn(src, "'\\"); | ||||
| 		size_t len = strcspn(src, "'!"); | ||||
| 		strbuf_add(dst, src, len); | ||||
| 		src += len; | ||||
| 		while (need_bs_quote(*src)) { | ||||
|  | @ -131,7 +131,8 @@ static signed char const sq_lookup[256] = { | |||
| 	/* 0x80 */ /* set to 0 */ | ||||
| }; | ||||
|  | ||||
| static inline int sq_must_quote(char c) { | ||||
| static inline int sq_must_quote(char c) | ||||
| { | ||||
| 	return sq_lookup[(unsigned char)c] + quote_path_fully > 0; | ||||
| } | ||||
|  | ||||
|  |  | |||
							
								
								
									
										10
									
								
								setup.c
								
								
								
								
							
							
						
						
									
										10
									
								
								setup.c
								
								
								
								
							|  | @ -206,6 +206,16 @@ static const char *set_work_tree(const char *dir) | |||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| void setup_work_tree(void) | ||||
| { | ||||
| 	const char *work_tree = get_git_work_tree(); | ||||
| 	const char *git_dir = get_git_dir(); | ||||
| 	if (!is_absolute_path(git_dir)) | ||||
| 		set_git_dir(make_absolute_path(git_dir)); | ||||
| 	if (!work_tree || chdir(work_tree)) | ||||
| 		die("This operation must be run in a work tree"); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * We cannot decide in this function whether we are in the work tree or | ||||
|  * not, since the config can only be read _after_ this function was called. | ||||
|  |  | |||
							
								
								
									
										8
									
								
								strbuf.h
								
								
								
								
							
							
						
						
									
										8
									
								
								strbuf.h
								
								
								
								
							|  | @ -23,12 +23,12 @@ | |||
|  *    that way: | ||||
|  * | ||||
|  *    strbuf_grow(sb, SOME_SIZE); | ||||
|  *    // ... here the memory areay starting at sb->buf, and of length | ||||
|  *    // sb_avail(sb) is all yours, and you are sure that sb_avail(sb) is at | ||||
|  *    // least SOME_SIZE | ||||
|  *       ... Here, the memory array starting at sb->buf, and of length | ||||
|  *       ... strbuf_avail(sb) is all yours, and you are sure that | ||||
|  *       ... strbuf_avail(sb) is at least SOME_SIZE. | ||||
|  *    strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE); | ||||
|  * | ||||
|  *    Of course, SOME_OTHER_SIZE must be smaller or equal to sb_avail(sb). | ||||
|  *    Of course, SOME_OTHER_SIZE must be smaller or equal to strbuf_avail(sb). | ||||
|  * | ||||
|  *    Doing so is safe, though if it has to be done in many places, adding the | ||||
|  *    missing API to the strbuf module is the way to go. | ||||
|  |  | |||
|  | @ -205,7 +205,7 @@ test_expect_success \ | |||
| 	 echo $h_TEST >.git/MERGE_HEAD && | ||||
| 	 GIT_AUTHOR_DATE="2005-05-26 23:45" \ | ||||
| 	 GIT_COMMITTER_DATE="2005-05-26 23:45" git-commit -F M && | ||||
| 	 h_MERGED=$(git rev-parse --verify HEAD) | ||||
| 	 h_MERGED=$(git rev-parse --verify HEAD) && | ||||
| 	 rm -f M' | ||||
|  | ||||
| cat >expect <<EOF | ||||
|  |  | |||
|  | @ -0,0 +1,123 @@ | |||
| #!/bin/sh | ||||
|  | ||||
| test_description='cherry picking and reverting a merge | ||||
|  | ||||
| 		b---c | ||||
| 	       /   / | ||||
| 	initial---a | ||||
|  | ||||
| ' | ||||
|  | ||||
| . ./test-lib.sh | ||||
|  | ||||
| test_expect_success setup ' | ||||
|  | ||||
| 	>A && | ||||
| 	>B && | ||||
| 	git add A B && | ||||
| 	git commit -m "Initial" && | ||||
| 	git tag initial && | ||||
| 	git branch side && | ||||
| 	echo new line >A && | ||||
| 	git commit -m "add line to A" A && | ||||
| 	git tag a && | ||||
| 	git checkout side && | ||||
| 	echo new line >B && | ||||
| 	git commit -m "add line to B" B && | ||||
| 	git tag b && | ||||
| 	git checkout master && | ||||
| 	git merge side && | ||||
| 	git tag c | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'cherry-pick a non-merge with -m should fail' ' | ||||
|  | ||||
| 	git reset --hard && | ||||
| 	git checkout a^0 && | ||||
| 	! git cherry-pick -m 1 b && | ||||
| 	git diff --exit-code a -- | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'cherry pick a merge without -m should fail' ' | ||||
|  | ||||
| 	git reset --hard && | ||||
| 	git checkout a^0 && | ||||
| 	! git cherry-pick c && | ||||
| 	git diff --exit-code a -- | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'cherry pick a merge (1)' ' | ||||
|  | ||||
| 	git reset --hard && | ||||
| 	git checkout a^0 && | ||||
| 	git cherry-pick -m 1 c && | ||||
| 	git diff --exit-code c | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'cherry pick a merge (2)' ' | ||||
|  | ||||
| 	git reset --hard && | ||||
| 	git checkout b^0 && | ||||
| 	git cherry-pick -m 2 c && | ||||
| 	git diff --exit-code c | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'cherry pick a merge relative to nonexistent parent should fail' ' | ||||
|  | ||||
| 	git reset --hard && | ||||
| 	git checkout b^0 && | ||||
| 	! git cherry-pick -m 3 c | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'revert a non-merge with -m should fail' ' | ||||
|  | ||||
| 	git reset --hard && | ||||
| 	git checkout c^0 && | ||||
| 	! git revert -m 1 b && | ||||
| 	git diff --exit-code c | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'revert a merge without -m should fail' ' | ||||
|  | ||||
| 	git reset --hard && | ||||
| 	git checkout c^0 && | ||||
| 	! git revert c && | ||||
| 	git diff --exit-code c | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'revert a merge (1)' ' | ||||
|  | ||||
| 	git reset --hard && | ||||
| 	git checkout c^0 && | ||||
| 	git revert -m 1 c && | ||||
| 	git diff --exit-code a -- | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'revert a merge (2)' ' | ||||
|  | ||||
| 	git reset --hard && | ||||
| 	git checkout c^0 && | ||||
| 	git revert -m 2 c && | ||||
| 	git diff --exit-code b -- | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'revert a merge relative to nonexistent parent should fail' ' | ||||
|  | ||||
| 	git reset --hard && | ||||
| 	git checkout c^0 && | ||||
| 	! git revert -m 3 c && | ||||
| 	git diff --exit-code c | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_done | ||||
|  | @ -0,0 +1,42 @@ | |||
| #!/bin/sh | ||||
|  | ||||
| test_description='format-patch -s should force MIME encoding as needed' | ||||
|  | ||||
| . ./test-lib.sh | ||||
|  | ||||
| test_expect_success setup ' | ||||
|  | ||||
| 	>F && | ||||
| 	git add F && | ||||
| 	git commit -m initial && | ||||
| 	echo new line >F && | ||||
|  | ||||
| 	test_tick && | ||||
| 	git commit -m "This adds some lines to F" F | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'format normally' ' | ||||
|  | ||||
| 	git format-patch --stdout -1 >output && | ||||
| 	! grep Content-Type output | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'format with signoff without funny signer name' ' | ||||
|  | ||||
| 	git format-patch -s --stdout -1 >output && | ||||
| 	! grep Content-Type output | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'format with non ASCII signer name' ' | ||||
|  | ||||
| 	GIT_COMMITTER_NAME="$B$O$^$N(B $B$U$K$*$&(B" \ | ||||
| 	git format-patch -s --stdout -1 >output && | ||||
| 	grep Content-Type output | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_done | ||||
|  | ||||
|  | @ -1,3 +1,6 @@ | |||
|      | ||||
| 	 | ||||
|      | ||||
| From nobody Mon Sep 17 00:00:00 2001 | ||||
| From: A U Thor <a.u.thor@example.com> | ||||
| Date: Fri, 9 Jun 2006 00:44:16 -0700 | ||||
|  |  | |||
|  | @ -208,4 +208,11 @@ test_expect_success 'fetch with a non-applying branch.<name>.merge' ' | |||
| 	git fetch blub | ||||
| ' | ||||
|  | ||||
| # the strange name is: a\!'b | ||||
| test_expect_success 'quoting of a strangely named repo' ' | ||||
| 	! git fetch "a\\!'\''b" > result 2>&1 && | ||||
| 	cat result && | ||||
| 	grep "fatal: '\''a\\\\!'\''b'\''" result | ||||
| ' | ||||
|  | ||||
| test_done | ||||
|  |  | |||
|  | @ -402,4 +402,11 @@ test_expect_success 'test resetting the index at give paths' ' | |||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'resetting an unmodified path is a no-op' ' | ||||
| 	git reset --hard && | ||||
| 	git reset -- file1 && | ||||
| 	git diff-files --exit-code && | ||||
| 	git diff-index --cached --exit-code HEAD | ||||
| ' | ||||
|  | ||||
| test_done | ||||
|  |  | |||
|  | @ -77,7 +77,7 @@ test_expect_success "checkout with dirty tree without -m" ' | |||
| test_expect_success "checkout -m with dirty tree" ' | ||||
|  | ||||
| 	git checkout -f master && | ||||
| 	git clean && | ||||
| 	git clean -f && | ||||
|  | ||||
| 	fill 0 1 2 3 4 5 6 7 8 >one && | ||||
| 	git checkout -m side && | ||||
|  | @ -99,7 +99,7 @@ test_expect_success "checkout -m with dirty tree" ' | |||
|  | ||||
| test_expect_success "checkout -m with dirty tree, renamed" ' | ||||
|  | ||||
| 	git checkout -f master && git clean && | ||||
| 	git checkout -f master && git clean -f && | ||||
|  | ||||
| 	fill 1 2 3 4 5 7 8 >one && | ||||
| 	if git checkout renamer | ||||
|  | @ -121,7 +121,7 @@ test_expect_success "checkout -m with dirty tree, renamed" ' | |||
|  | ||||
| test_expect_success 'checkout -m with merge conflict' ' | ||||
|  | ||||
| 	git checkout -f master && git clean && | ||||
| 	git checkout -f master && git clean -f && | ||||
|  | ||||
| 	fill 1 T 3 4 5 6 S 8 >one && | ||||
| 	if git checkout renamer | ||||
|  | @ -144,7 +144,7 @@ test_expect_success 'checkout -m with merge conflict' ' | |||
|  | ||||
| test_expect_success 'checkout to detach HEAD' ' | ||||
|  | ||||
| 	git checkout -f renamer && git clean && | ||||
| 	git checkout -f renamer && git clean -f && | ||||
| 	git checkout renamer^ && | ||||
| 	H=$(git rev-parse --verify HEAD) && | ||||
| 	M=$(git show-ref -s --verify refs/heads/master) && | ||||
|  | @ -160,7 +160,7 @@ test_expect_success 'checkout to detach HEAD' ' | |||
|  | ||||
| test_expect_success 'checkout to detach HEAD with branchname^' ' | ||||
|  | ||||
| 	git checkout -f master && git clean && | ||||
| 	git checkout -f master && git clean -f && | ||||
| 	git checkout renamer^ && | ||||
| 	H=$(git rev-parse --verify HEAD) && | ||||
| 	M=$(git show-ref -s --verify refs/heads/master) && | ||||
|  | @ -176,7 +176,7 @@ test_expect_success 'checkout to detach HEAD with branchname^' ' | |||
|  | ||||
| test_expect_success 'checkout to detach HEAD with HEAD^0' ' | ||||
|  | ||||
| 	git checkout -f master && git clean && | ||||
| 	git checkout -f master && git clean -f && | ||||
| 	git checkout HEAD^0 && | ||||
| 	H=$(git rev-parse --verify HEAD) && | ||||
| 	M=$(git show-ref -s --verify refs/heads/master) && | ||||
|  |  | |||
							
								
								
									
										114
									
								
								t/t7300-clean.sh
								
								
								
								
							
							
						
						
									
										114
									
								
								t/t7300-clean.sh
								
								
								
								
							|  | @ -7,6 +7,8 @@ test_description='git-clean basic tests' | |||
|  | ||||
| . ./test-lib.sh | ||||
|  | ||||
| git config clean.requireForce no | ||||
|  | ||||
| test_expect_success 'setup' ' | ||||
|  | ||||
| 	mkdir -p src && | ||||
|  | @ -37,6 +39,93 @@ test_expect_success 'git-clean' ' | |||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'git-clean src/' ' | ||||
|  | ||||
| 	mkdir -p build docs && | ||||
| 	touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && | ||||
| 	git-clean src/ && | ||||
| 	test -f Makefile && | ||||
| 	test -f README && | ||||
| 	test -f src/part1.c && | ||||
| 	test -f src/part2.c && | ||||
| 	test -f a.out && | ||||
| 	test ! -f src/part3.c && | ||||
| 	test -f docs/manual.txt && | ||||
| 	test -f obj.o && | ||||
| 	test -f build/lib.so | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'git-clean src/ src/' ' | ||||
|  | ||||
| 	mkdir -p build docs && | ||||
| 	touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && | ||||
| 	git-clean src/ src/ && | ||||
| 	test -f Makefile && | ||||
| 	test -f README && | ||||
| 	test -f src/part1.c && | ||||
| 	test -f src/part2.c && | ||||
| 	test -f a.out && | ||||
| 	test ! -f src/part3.c && | ||||
| 	test -f docs/manual.txt && | ||||
| 	test -f obj.o && | ||||
| 	test -f build/lib.so | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'git-clean with prefix' ' | ||||
|  | ||||
| 	mkdir -p build docs && | ||||
| 	touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && | ||||
| 	(cd src/ && git-clean) && | ||||
| 	test -f Makefile && | ||||
| 	test -f README && | ||||
| 	test -f src/part1.c && | ||||
| 	test -f src/part2.c && | ||||
| 	test -f a.out && | ||||
| 	test ! -f src/part3.c && | ||||
| 	test -f docs/manual.txt && | ||||
| 	test -f obj.o && | ||||
| 	test -f build/lib.so | ||||
|  | ||||
| ' | ||||
| test_expect_success 'git-clean -d with prefix and path' ' | ||||
|  | ||||
| 	mkdir -p build docs src/feature && | ||||
| 	touch a.out src/part3.c src/feature/file.c docs/manual.txt obj.o build/lib.so && | ||||
| 	(cd src/ && git-clean -d feature/) && | ||||
| 	test -f Makefile && | ||||
| 	test -f README && | ||||
| 	test -f src/part1.c && | ||||
| 	test -f src/part2.c && | ||||
| 	test -f a.out && | ||||
| 	test -f src/part3.c && | ||||
| 	test ! -f src/feature/file.c && | ||||
| 	test -f docs/manual.txt && | ||||
| 	test -f obj.o && | ||||
| 	test -f build/lib.so | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'git-clean symbolic link' ' | ||||
|  | ||||
| 	mkdir -p build docs && | ||||
| 	touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && | ||||
| 	ln -s docs/manual.txt src/part4.c | ||||
| 	git-clean && | ||||
| 	test -f Makefile && | ||||
| 	test -f README && | ||||
| 	test -f src/part1.c && | ||||
| 	test -f src/part2.c && | ||||
| 	test ! -f a.out && | ||||
| 	test ! -f src/part3.c && | ||||
| 	test ! -f src/part4.c && | ||||
| 	test -f docs/manual.txt && | ||||
| 	test -f obj.o && | ||||
| 	test -f build/lib.so | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'git-clean -n' ' | ||||
|  | ||||
| 	mkdir -p build docs && | ||||
|  | @ -71,6 +160,24 @@ test_expect_success 'git-clean -d' ' | |||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'git-clean -d src/ examples/' ' | ||||
|  | ||||
| 	mkdir -p build docs examples && | ||||
| 	touch a.out src/part3.c docs/manual.txt obj.o build/lib.so examples/1.c && | ||||
| 	git-clean -d src/ examples/ && | ||||
| 	test -f Makefile && | ||||
| 	test -f README && | ||||
| 	test -f src/part1.c && | ||||
| 	test -f src/part2.c && | ||||
| 	test -f a.out && | ||||
| 	test ! -f src/part3.c && | ||||
| 	test ! -f examples/1.c && | ||||
| 	test -f docs/manual.txt && | ||||
| 	test -f obj.o && | ||||
| 	test -f build/lib.so | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'git-clean -x' ' | ||||
|  | ||||
| 	mkdir -p build docs && | ||||
|  | @ -139,6 +246,13 @@ test_expect_success 'git-clean -d -X' ' | |||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'clean.requireForce defaults to true' ' | ||||
|  | ||||
| 	git config --unset clean.requireForce && | ||||
| 	! git-clean | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'clean.requireForce' ' | ||||
|  | ||||
| 	git config clean.requireForce true && | ||||
|  |  | |||
|  | @ -0,0 +1,56 @@ | |||
| #!/bin/sh | ||||
| # | ||||
| # Copyright (c) 2007 Eric Wong | ||||
| test_description='git-svn dcommit clobber series' | ||||
| . ./lib-git-svn.sh | ||||
|  | ||||
| test_expect_success 'initialize repo' " | ||||
| 	mkdir import && | ||||
| 	cd import && | ||||
| 	awk 'BEGIN { for (i = 1; i < 64; i++) { print i } }' > file | ||||
| 	svn import -m 'initial' . $svnrepo && | ||||
| 	cd .. && | ||||
| 	git svn init $svnrepo && | ||||
| 	git svn fetch && | ||||
| 	test -e file | ||||
| 	" | ||||
|  | ||||
| test_expect_success '(supposedly) non-conflicting change from SVN' " | ||||
| 	test x\"\`sed -n -e 58p < file\`\" = x58 && | ||||
| 	test x\"\`sed -n -e 61p < file\`\" = x61 && | ||||
| 	svn co $svnrepo tmp && | ||||
| 	cd tmp && | ||||
| 		perl -i -p -e 's/^58\$/5588/' file && | ||||
| 		perl -i -p -e 's/^61\$/6611/' file && | ||||
| 		test x\"\`sed -n -e 58p < file\`\" = x5588 && | ||||
| 		test x\"\`sed -n -e 61p < file\`\" = x6611 && | ||||
| 		svn commit -m '58 => 5588, 61 => 6611' && | ||||
| 		cd .. | ||||
| 	" | ||||
|  | ||||
| test_expect_success 'some unrelated changes to git' " | ||||
| 	echo hi > life && | ||||
| 	git update-index --add life && | ||||
| 	git commit -m hi-life && | ||||
| 	echo bye >> life && | ||||
| 	git commit -m bye-life life | ||||
| 	" | ||||
|  | ||||
| test_expect_success 'change file but in unrelated area' " | ||||
| 	test x\"\`sed -n -e 4p < file\`\" = x4 && | ||||
| 	test x\"\`sed -n -e 7p < file\`\" = x7 && | ||||
| 	perl -i -p -e 's/^4\$/4444/' file && | ||||
| 	perl -i -p -e 's/^7\$/7777/' file && | ||||
| 	test x\"\`sed -n -e 4p < file\`\" = x4444 && | ||||
| 	test x\"\`sed -n -e 7p < file\`\" = x7777 && | ||||
| 	git commit -m '4 => 4444, 7 => 7777' file && | ||||
| 	git svn dcommit && | ||||
| 	svn up tmp && | ||||
| 	cd tmp && | ||||
| 		test x\"\`sed -n -e 4p < file\`\" = x4444 && | ||||
| 		test x\"\`sed -n -e 7p < file\`\" = x7777 && | ||||
| 		test x\"\`sed -n -e 58p < file\`\" = x5588 && | ||||
| 		test x\"\`sed -n -e 61p < file\`\" = x6611 | ||||
| 	" | ||||
|  | ||||
| test_done | ||||
|  | @ -86,4 +86,9 @@ test_expect_success 'verify post-merge ancestry' " | |||
| 	git cat-file commit refs/heads/svn^ | grep '^friend$' | ||||
| 	" | ||||
|  | ||||
| test_expect_success 'verify merge commit message' " | ||||
| 	git rev-list --pretty=raw -1 refs/heads/svn | \ | ||||
| 	  grep \"    Merge branch 'merge' into svn\" | ||||
| 	" | ||||
|  | ||||
| test_done | ||||
|  |  | |||
|  | @ -31,7 +31,6 @@ our \$projects_list = ""; | |||
| our \$export_ok = ""; | ||||
| our \$strict_export = ""; | ||||
|  | ||||
| CGI::Carp::set_programname("gitweb/gitweb.cgi"); | ||||
| EOF | ||||
|  | ||||
| 	cat >.git/description <<EOF | ||||
|  | @ -558,4 +557,27 @@ test_expect_success \ | |||
| 	'gitweb_run "p=.git;a=tree;opt=--no-merges"' | ||||
| test_debug 'cat gitweb.log' | ||||
|  | ||||
| # ---------------------------------------------------------------------- | ||||
| # gitweb config and repo config | ||||
|  | ||||
| cat >>gitweb_config.perl <<EOF | ||||
|  | ||||
| \$feature{'blame'}{'override'} = 1; | ||||
| \$feature{'snapshot'}{'override'} = 1; | ||||
| EOF | ||||
|  | ||||
| test_expect_success \ | ||||
| 	'config override: tree view, features disabled in repo config' \ | ||||
| 	'git config gitweb.blame no && | ||||
| 	 git config gitweb.snapshot none && | ||||
| 	 gitweb_run "p=.git;a=tree"' | ||||
| test_debug 'cat gitweb.log' | ||||
|  | ||||
| test_expect_success \ | ||||
| 	'config override: tree view, features enabled in repo config' \ | ||||
| 	'git config gitweb.blame yes && | ||||
| 	 git config gitweb.snapshot "zip,tgz, tbz2" && | ||||
| 	 gitweb_run "p=.git;a=tree"' | ||||
| test_debug 'cat gitweb.log' | ||||
|  | ||||
| test_done | ||||
|  |  | |||
|  | @ -10,6 +10,12 @@ | |||
| # hooks.allowunannotated | ||||
| #   This boolean sets whether unannotated tags will be allowed into the | ||||
| #   repository.  By default they won't be. | ||||
| # hooks.allowdeletetag | ||||
| #   This boolean sets whether deleting tags will be allowed in the | ||||
| #   repository.  By default they won't be. | ||||
| # hooks.allowdeletebranch | ||||
| #   This boolean sets whether deleting branches will be allowed in the | ||||
| #   repository.  By default they won't be. | ||||
| # | ||||
|  | ||||
| # --- Command line | ||||
|  | @ -32,18 +38,20 @@ fi | |||
|  | ||||
| # --- Config | ||||
| allowunannotated=$(git-repo-config --bool hooks.allowunannotated) | ||||
| allowdeletebranch=$(git-repo-config --bool hooks.allowdeletebranch) | ||||
| allowdeletetag=$(git-repo-config --bool hooks.allowdeletetag) | ||||
|  | ||||
| # check for no description | ||||
| projectdesc=$(sed -e '1p' "$GIT_DIR/description") | ||||
| if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb" ]; then | ||||
| projectdesc=$(sed -e '1q' "$GIT_DIR/description") | ||||
| if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb." ]; then | ||||
| 	echo "*** Project description file hasn't been set" >&2 | ||||
| 	exit 1 | ||||
| fi | ||||
|  | ||||
| # --- Check types | ||||
| # if $newrev is 0000...0000, it's a commit to delete a branch | ||||
| # if $newrev is 0000...0000, it's a commit to delete a ref. | ||||
| if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then | ||||
| 	newrev_type=commit | ||||
| 	newrev_type=delete | ||||
| else | ||||
| 	newrev_type=$(git-cat-file -t $newrev) | ||||
| fi | ||||
|  | @ -58,15 +66,36 @@ case "$refname","$newrev_type" in | |||
| 			exit 1 | ||||
| 		fi | ||||
| 		;; | ||||
| 	refs/tags/*,delete) | ||||
| 		# delete tag | ||||
| 		if [ "$allowdeletetag" != "true" ]; then | ||||
| 			echo "*** Deleting a tag is not allowed in this repository" >&2 | ||||
| 			exit 1 | ||||
| 		fi | ||||
| 		;; | ||||
| 	refs/tags/*,tag) | ||||
| 		# annotated tag | ||||
| 		;; | ||||
| 	refs/heads/*,commit) | ||||
| 		# branch | ||||
| 		;; | ||||
| 	refs/heads/*,delete) | ||||
| 		# delete branch | ||||
| 		if [ "$allowdeletebranch" != "true" ]; then | ||||
| 			echo "*** Deleting a branch is not allowed in this repository" >&2 | ||||
| 			exit 1 | ||||
| 		fi | ||||
| 		;; | ||||
| 	refs/remotes/*,commit) | ||||
| 		# tracking branch | ||||
| 		;; | ||||
| 	refs/remotes/*,delete) | ||||
| 		# delete tracking branch | ||||
| 		if [ "$allowdeletebranch" != "true" ]; then | ||||
| 			echo "*** Deleting a tracking branch is not allowed in this repository" >&2 | ||||
| 			exit 1 | ||||
| 		fi | ||||
| 		;; | ||||
| 	*) | ||||
| 		# Anything else (is there anything else?) | ||||
| 		echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 | ||||
|  |  | |||
|  | @ -381,7 +381,8 @@ static int disconnect_walker(struct transport *transport) | |||
| } | ||||
|  | ||||
| #ifndef NO_CURL | ||||
| static int curl_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) { | ||||
| static int curl_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) | ||||
| { | ||||
| 	const char **argv; | ||||
| 	int argc; | ||||
| 	int err; | ||||
|  | @ -647,7 +648,8 @@ static int fetch_refs_via_pack(struct transport *transport, | |||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int git_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) { | ||||
| static int git_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) | ||||
| { | ||||
| 	struct git_transport_data *data = transport->data; | ||||
| 	struct send_pack_args args; | ||||
|  | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano