Merge branch 'pw/add-p-edit-ita-path'
"add -p" now allows editing paths that were only added in intent. * pw/add-p-edit-ita-path: add -p: fix editing of intent-to-add paths
This commit is contained in:
		
							
								
								
									
										42
									
								
								add-patch.c
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								add-patch.c
									
									
									
									
									
								
							| @ -465,7 +465,7 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) | |||||||
| 	pend = p + plain->len; | 	pend = p + plain->len; | ||||||
| 	while (p != pend) { | 	while (p != pend) { | ||||||
| 		char *eol = memchr(p, '\n', pend - p); | 		char *eol = memchr(p, '\n', pend - p); | ||||||
| 		const char *deleted = NULL, *added = NULL, *mode_change = NULL; | 		const char *deleted = NULL, *mode_change = NULL; | ||||||
|  |  | ||||||
| 		if (!eol) | 		if (!eol) | ||||||
| 			eol = pend; | 			eol = pend; | ||||||
| @ -482,12 +482,11 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) | |||||||
| 		} else if (p == plain->buf) | 		} else if (p == plain->buf) | ||||||
| 			BUG("diff starts with unexpected line:\n" | 			BUG("diff starts with unexpected line:\n" | ||||||
| 			    "%.*s\n", (int)(eol - p), p); | 			    "%.*s\n", (int)(eol - p), p); | ||||||
| 		else if (file_diff->deleted || file_diff->added) | 		else if (file_diff->deleted) | ||||||
| 			; /* keep the rest of the file in a single "hunk" */ | 			; /* keep the rest of the file in a single "hunk" */ | ||||||
| 		else if (starts_with(p, "@@ ") || | 		else if (starts_with(p, "@@ ") || | ||||||
| 			 (hunk == &file_diff->head && | 			 (hunk == &file_diff->head && | ||||||
| 			  (skip_prefix(p, "deleted file", &deleted) || | 			  (skip_prefix(p, "deleted file", &deleted)))) { | ||||||
| 			   skip_prefix(p, "new file", &added)))) { |  | ||||||
| 			if (marker == '-' || marker == '+') | 			if (marker == '-' || marker == '+') | ||||||
| 				/* | 				/* | ||||||
| 				 * Should not happen; previous hunk did not end | 				 * Should not happen; previous hunk did not end | ||||||
| @ -505,8 +504,6 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) | |||||||
|  |  | ||||||
| 			if (deleted) | 			if (deleted) | ||||||
| 				file_diff->deleted = 1; | 				file_diff->deleted = 1; | ||||||
| 			else if (added) |  | ||||||
| 				file_diff->added = 1; |  | ||||||
| 			else if (parse_hunk_header(s, hunk) < 0) | 			else if (parse_hunk_header(s, hunk) < 0) | ||||||
| 				return -1; | 				return -1; | ||||||
|  |  | ||||||
| @ -515,6 +512,9 @@ static int parse_diff(struct add_p_state *s, const struct pathspec *ps) | |||||||
| 			 * split | 			 * split | ||||||
| 			 */ | 			 */ | ||||||
| 			marker = *p; | 			marker = *p; | ||||||
|  | 		} else if (hunk == &file_diff->head && | ||||||
|  | 			   starts_with(p, "new file")) { | ||||||
|  | 			file_diff->added = 1; | ||||||
| 		} else if (hunk == &file_diff->head && | 		} else if (hunk == &file_diff->head && | ||||||
| 			   skip_prefix(p, "old mode ", &mode_change) && | 			   skip_prefix(p, "old mode ", &mode_change) && | ||||||
| 			   is_octal(mode_change, eol - mode_change)) { | 			   is_octal(mode_change, eol - mode_change)) { | ||||||
| @ -1376,7 +1376,8 @@ static int patch_update_file(struct add_p_state *s, | |||||||
| 		ALLOW_EDIT = 1 << 6 | 		ALLOW_EDIT = 1 << 6 | ||||||
| 	} permitted = 0; | 	} permitted = 0; | ||||||
|  |  | ||||||
| 	if (!file_diff->hunk_nr) | 	/* Empty added files have no hunks */ | ||||||
|  | 	if (!file_diff->hunk_nr && !file_diff->added) | ||||||
| 		return 0; | 		return 0; | ||||||
|  |  | ||||||
| 	strbuf_reset(&s->buf); | 	strbuf_reset(&s->buf); | ||||||
| @ -1385,21 +1386,25 @@ static int patch_update_file(struct add_p_state *s, | |||||||
| 	for (;;) { | 	for (;;) { | ||||||
| 		if (hunk_index >= file_diff->hunk_nr) | 		if (hunk_index >= file_diff->hunk_nr) | ||||||
| 			hunk_index = 0; | 			hunk_index = 0; | ||||||
| 		hunk = file_diff->hunk + hunk_index; | 		hunk = file_diff->hunk_nr | ||||||
|  | 				? file_diff->hunk + hunk_index | ||||||
|  | 				: &file_diff->head; | ||||||
| 		undecided_previous = -1; | 		undecided_previous = -1; | ||||||
|  | 		undecided_next = -1; | ||||||
|  |  | ||||||
|  | 		if (file_diff->hunk_nr) { | ||||||
| 			for (i = hunk_index - 1; i >= 0; i--) | 			for (i = hunk_index - 1; i >= 0; i--) | ||||||
| 				if (file_diff->hunk[i].use == UNDECIDED_HUNK) { | 				if (file_diff->hunk[i].use == UNDECIDED_HUNK) { | ||||||
| 					undecided_previous = i; | 					undecided_previous = i; | ||||||
| 					break; | 					break; | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 		undecided_next = -1; |  | ||||||
| 			for (i = hunk_index + 1; i < file_diff->hunk_nr; i++) | 			for (i = hunk_index + 1; i < file_diff->hunk_nr; i++) | ||||||
| 				if (file_diff->hunk[i].use == UNDECIDED_HUNK) { | 				if (file_diff->hunk[i].use == UNDECIDED_HUNK) { | ||||||
| 					undecided_next = i; | 					undecided_next = i; | ||||||
| 					break; | 					break; | ||||||
| 				} | 				} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		/* Everything decided? */ | 		/* Everything decided? */ | ||||||
| 		if (undecided_previous < 0 && undecided_next < 0 && | 		if (undecided_previous < 0 && undecided_next < 0 && | ||||||
| @ -1407,6 +1412,7 @@ static int patch_update_file(struct add_p_state *s, | |||||||
| 			break; | 			break; | ||||||
|  |  | ||||||
| 		strbuf_reset(&s->buf); | 		strbuf_reset(&s->buf); | ||||||
|  | 		if (file_diff->hunk_nr) { | ||||||
| 			render_hunk(s, hunk, 0, colored, &s->buf); | 			render_hunk(s, hunk, 0, colored, &s->buf); | ||||||
| 			fputs(s->buf.buf, stdout); | 			fputs(s->buf.buf, stdout); | ||||||
|  |  | ||||||
| @ -1440,6 +1446,7 @@ static int patch_update_file(struct add_p_state *s, | |||||||
| 				permitted |= ALLOW_EDIT; | 				permitted |= ALLOW_EDIT; | ||||||
| 				strbuf_addstr(&s->buf, ",e"); | 				strbuf_addstr(&s->buf, ",e"); | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
| 		if (file_diff->deleted) | 		if (file_diff->deleted) | ||||||
| 			prompt_mode_type = PROMPT_DELETION; | 			prompt_mode_type = PROMPT_DELETION; | ||||||
| 		else if (file_diff->added) | 		else if (file_diff->added) | ||||||
| @ -1452,7 +1459,9 @@ static int patch_update_file(struct add_p_state *s, | |||||||
| 		color_fprintf(stdout, s->s.prompt_color, | 		color_fprintf(stdout, s->s.prompt_color, | ||||||
| 			      "(%"PRIuMAX"/%"PRIuMAX") ", | 			      "(%"PRIuMAX"/%"PRIuMAX") ", | ||||||
| 			      (uintmax_t)hunk_index + 1, | 			      (uintmax_t)hunk_index + 1, | ||||||
| 			      (uintmax_t)file_diff->hunk_nr); | 			      (uintmax_t)(file_diff->hunk_nr | ||||||
|  | 						? file_diff->hunk_nr | ||||||
|  | 						: 1)); | ||||||
| 		color_fprintf(stdout, s->s.prompt_color, | 		color_fprintf(stdout, s->s.prompt_color, | ||||||
| 			      _(s->mode->prompt_mode[prompt_mode_type]), | 			      _(s->mode->prompt_mode[prompt_mode_type]), | ||||||
| 			      s->buf.buf); | 			      s->buf.buf); | ||||||
| @ -1472,17 +1481,25 @@ soft_increment: | |||||||
| 			hunk->use = SKIP_HUNK; | 			hunk->use = SKIP_HUNK; | ||||||
| 			goto soft_increment; | 			goto soft_increment; | ||||||
| 		} else if (ch == 'a') { | 		} else if (ch == 'a') { | ||||||
|  | 			if (file_diff->hunk_nr) { | ||||||
| 				for (; hunk_index < file_diff->hunk_nr; hunk_index++) { | 				for (; hunk_index < file_diff->hunk_nr; hunk_index++) { | ||||||
| 					hunk = file_diff->hunk + hunk_index; | 					hunk = file_diff->hunk + hunk_index; | ||||||
| 					if (hunk->use == UNDECIDED_HUNK) | 					if (hunk->use == UNDECIDED_HUNK) | ||||||
| 						hunk->use = USE_HUNK; | 						hunk->use = USE_HUNK; | ||||||
| 				} | 				} | ||||||
|  | 			} else if (hunk->use == UNDECIDED_HUNK) { | ||||||
|  | 				hunk->use = USE_HUNK; | ||||||
|  | 			} | ||||||
| 		} else if (ch == 'd' || ch == 'q') { | 		} else if (ch == 'd' || ch == 'q') { | ||||||
|  | 			if (file_diff->hunk_nr) { | ||||||
| 				for (; hunk_index < file_diff->hunk_nr; hunk_index++) { | 				for (; hunk_index < file_diff->hunk_nr; hunk_index++) { | ||||||
| 					hunk = file_diff->hunk + hunk_index; | 					hunk = file_diff->hunk + hunk_index; | ||||||
| 					if (hunk->use == UNDECIDED_HUNK) | 					if (hunk->use == UNDECIDED_HUNK) | ||||||
| 						hunk->use = SKIP_HUNK; | 						hunk->use = SKIP_HUNK; | ||||||
| 				} | 				} | ||||||
|  | 			} else if (hunk->use == UNDECIDED_HUNK) { | ||||||
|  | 				hunk->use = SKIP_HUNK; | ||||||
|  | 			} | ||||||
| 			if (ch == 'q') { | 			if (ch == 'q') { | ||||||
| 				quit = 1; | 				quit = 1; | ||||||
| 				break; | 				break; | ||||||
| @ -1639,7 +1656,8 @@ soft_increment: | |||||||
| 		if (file_diff->hunk[i].use == USE_HUNK) | 		if (file_diff->hunk[i].use == USE_HUNK) | ||||||
| 			break; | 			break; | ||||||
|  |  | ||||||
| 	if (i < file_diff->hunk_nr) { | 	if (i < file_diff->hunk_nr || | ||||||
|  | 	    (!file_diff->hunk_nr && file_diff->head.use == USE_HUNK)) { | ||||||
| 		/* At least one hunk selected: apply */ | 		/* At least one hunk selected: apply */ | ||||||
| 		strbuf_reset(&s->buf); | 		strbuf_reset(&s->buf); | ||||||
| 		reassemble_patch(s, file_diff, 0, &s->buf); | 		reassemble_patch(s, file_diff, 0, &s->buf); | ||||||
|  | |||||||
| @ -754,13 +754,16 @@ sub parse_diff_header { | |||||||
| 	my $head = { TEXT => [], DISPLAY => [], TYPE => 'header' }; | 	my $head = { TEXT => [], DISPLAY => [], TYPE => 'header' }; | ||||||
| 	my $mode = { TEXT => [], DISPLAY => [], TYPE => 'mode' }; | 	my $mode = { TEXT => [], DISPLAY => [], TYPE => 'mode' }; | ||||||
| 	my $deletion = { TEXT => [], DISPLAY => [], TYPE => 'deletion' }; | 	my $deletion = { TEXT => [], DISPLAY => [], TYPE => 'deletion' }; | ||||||
| 	my $addition = { TEXT => [], DISPLAY => [], TYPE => 'addition' }; | 	my $addition; | ||||||
|  |  | ||||||
| 	for (my $i = 0; $i < @{$src->{TEXT}}; $i++) { | 	for (my $i = 0; $i < @{$src->{TEXT}}; $i++) { | ||||||
|  | 		if ($src->{TEXT}->[$i] =~ /^new file/) { | ||||||
|  | 			$addition = 1; | ||||||
|  | 			$head->{TYPE} = 'addition'; | ||||||
|  | 		} | ||||||
| 		my $dest = | 		my $dest = | ||||||
| 		   $src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ? $mode : | 		   $src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ? $mode : | ||||||
| 		   $src->{TEXT}->[$i] =~ /^deleted file/ ? $deletion : | 		   $src->{TEXT}->[$i] =~ /^deleted file/ ? $deletion : | ||||||
| 		   $src->{TEXT}->[$i] =~ /^new file/ ? $addition : |  | ||||||
| 		   $head; | 		   $head; | ||||||
| 		push @{$dest->{TEXT}}, $src->{TEXT}->[$i]; | 		push @{$dest->{TEXT}}, $src->{TEXT}->[$i]; | ||||||
| 		push @{$dest->{DISPLAY}}, $src->{DISPLAY}->[$i]; | 		push @{$dest->{DISPLAY}}, $src->{DISPLAY}->[$i]; | ||||||
| @ -1501,12 +1504,6 @@ sub patch_update_file { | |||||||
| 			push @{$deletion->{DISPLAY}}, @{$hunk->{DISPLAY}}; | 			push @{$deletion->{DISPLAY}}, @{$hunk->{DISPLAY}}; | ||||||
| 		} | 		} | ||||||
| 		@hunk = ($deletion); | 		@hunk = ($deletion); | ||||||
| 	} elsif (@{$addition->{TEXT}}) { |  | ||||||
| 		foreach my $hunk (@hunk) { |  | ||||||
| 			push @{$addition->{TEXT}}, @{$hunk->{TEXT}}; |  | ||||||
| 			push @{$addition->{DISPLAY}}, @{$hunk->{DISPLAY}}; |  | ||||||
| 		} |  | ||||||
| 		@hunk = ($addition); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	$num = scalar @hunk; | 	$num = scalar @hunk; | ||||||
| @ -1516,6 +1513,7 @@ sub patch_update_file { | |||||||
| 		my ($prev, $next, $other, $undecided, $i); | 		my ($prev, $next, $other, $undecided, $i); | ||||||
| 		$other = ''; | 		$other = ''; | ||||||
|  |  | ||||||
|  | 		last if ($ix and !$num); | ||||||
| 		if ($num <= $ix) { | 		if ($num <= $ix) { | ||||||
| 			$ix = 0; | 			$ix = 0; | ||||||
| 		} | 		} | ||||||
| @ -1548,8 +1546,9 @@ sub patch_update_file { | |||||||
| 				last; | 				last; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		last if (!$undecided); | 		last if (!$undecided && ($num || !$addition)); | ||||||
|  |  | ||||||
|  | 		if ($num) { | ||||||
| 			if ($hunk[$ix]{TYPE} eq 'hunk' && | 			if ($hunk[$ix]{TYPE} eq 'hunk' && | ||||||
| 			    hunk_splittable($hunk[$ix]{TEXT})) { | 			    hunk_splittable($hunk[$ix]{TEXT})) { | ||||||
| 				$other .= ',s'; | 				$other .= ',s'; | ||||||
| @ -1560,25 +1559,40 @@ sub patch_update_file { | |||||||
| 			for (@{$hunk[$ix]{DISPLAY}}) { | 			for (@{$hunk[$ix]{DISPLAY}}) { | ||||||
| 				print; | 				print; | ||||||
| 			} | 			} | ||||||
| 		print colored $prompt_color, "(", ($ix+1), "/$num) ", | 		} | ||||||
| 			sprintf(__($patch_update_prompt_modes{$patch_mode}{$hunk[$ix]{TYPE}}), $other); | 		my $type = $num ? $hunk[$ix]{TYPE} : $head->{TYPE}; | ||||||
|  | 		print colored $prompt_color, "(", ($ix+1), "/", ($num ? $num : 1), ") ", | ||||||
|  | 			sprintf(__($patch_update_prompt_modes{$patch_mode}{$type}), $other); | ||||||
|  |  | ||||||
| 		my $line = prompt_single_character; | 		my $line = prompt_single_character; | ||||||
| 		last unless defined $line; | 		last unless defined $line; | ||||||
| 		if ($line) { | 		if ($line) { | ||||||
| 			if ($line =~ /^y/i) { | 			if ($line =~ /^y/i) { | ||||||
|  | 				if ($num) { | ||||||
| 					$hunk[$ix]{USE} = 1; | 					$hunk[$ix]{USE} = 1; | ||||||
|  | 				} else { | ||||||
|  | 					$head->{USE} = 1; | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 			elsif ($line =~ /^n/i) { | 			elsif ($line =~ /^n/i) { | ||||||
|  | 				if ($num) { | ||||||
| 					$hunk[$ix]{USE} = 0; | 					$hunk[$ix]{USE} = 0; | ||||||
|  | 				} else { | ||||||
|  | 					$head->{USE} = 0; | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 			elsif ($line =~ /^a/i) { | 			elsif ($line =~ /^a/i) { | ||||||
|  | 				if ($num) { | ||||||
| 					while ($ix < $num) { | 					while ($ix < $num) { | ||||||
| 						if (!defined $hunk[$ix]{USE}) { | 						if (!defined $hunk[$ix]{USE}) { | ||||||
| 							$hunk[$ix]{USE} = 1; | 							$hunk[$ix]{USE} = 1; | ||||||
| 						} | 						} | ||||||
| 						$ix++; | 						$ix++; | ||||||
| 					} | 					} | ||||||
|  | 				} else { | ||||||
|  | 					$head->{USE} = 1; | ||||||
|  | 					$ix++; | ||||||
|  | 				} | ||||||
| 				next; | 				next; | ||||||
| 			} | 			} | ||||||
| 			elsif ($line =~ /^g(.*)/) { | 			elsif ($line =~ /^g(.*)/) { | ||||||
| @ -1613,20 +1627,29 @@ sub patch_update_file { | |||||||
| 				next; | 				next; | ||||||
| 			} | 			} | ||||||
| 			elsif ($line =~ /^d/i) { | 			elsif ($line =~ /^d/i) { | ||||||
|  | 				if ($num) { | ||||||
| 					while ($ix < $num) { | 					while ($ix < $num) { | ||||||
| 						if (!defined $hunk[$ix]{USE}) { | 						if (!defined $hunk[$ix]{USE}) { | ||||||
| 							$hunk[$ix]{USE} = 0; | 							$hunk[$ix]{USE} = 0; | ||||||
| 						} | 						} | ||||||
| 						$ix++; | 						$ix++; | ||||||
| 					} | 					} | ||||||
|  | 				} else { | ||||||
|  | 					$head->{USE} = 0; | ||||||
|  | 					$ix++; | ||||||
|  | 				} | ||||||
| 				next; | 				next; | ||||||
| 			} | 			} | ||||||
| 			elsif ($line =~ /^q/i) { | 			elsif ($line =~ /^q/i) { | ||||||
|  | 				if ($num) { | ||||||
| 					for ($i = 0; $i < $num; $i++) { | 					for ($i = 0; $i < $num; $i++) { | ||||||
| 						if (!defined $hunk[$i]{USE}) { | 						if (!defined $hunk[$i]{USE}) { | ||||||
| 							$hunk[$i]{USE} = 0; | 							$hunk[$i]{USE} = 0; | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
|  | 				} elsif (!defined $head->{USE}) { | ||||||
|  | 					$head->{USE} = 0; | ||||||
|  | 				} | ||||||
| 				$quit = 1; | 				$quit = 1; | ||||||
| 				last; | 				last; | ||||||
| 			} | 			} | ||||||
| @ -1743,7 +1766,7 @@ sub patch_update_file { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@hunk = coalesce_overlapping_hunks(@hunk); | 	@hunk = coalesce_overlapping_hunks(@hunk) if ($num); | ||||||
|  |  | ||||||
| 	my $n_lofs = 0; | 	my $n_lofs = 0; | ||||||
| 	my @result = (); | 	my @result = (); | ||||||
| @ -1753,7 +1776,7 @@ sub patch_update_file { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (@result) { | 	if (@result or $head->{USE}) { | ||||||
| 		my @patch = reassemble_patch($head->{TEXT}, @result); | 		my @patch = reassemble_patch($head->{TEXT}, @result); | ||||||
| 		my $apply_routine = $patch_mode_flavour{APPLY}; | 		my $apply_routine = $patch_mode_flavour{APPLY}; | ||||||
| 		&$apply_routine(@patch); | 		&$apply_routine(@patch); | ||||||
|  | |||||||
| @ -822,6 +822,44 @@ test_expect_success 'checkout -p works with pathological context lines' ' | |||||||
| 	test_cmp expect a | 	test_cmp expect a | ||||||
| ' | ' | ||||||
|  |  | ||||||
|  | # This should be called from a subshell as it sets a temporary editor | ||||||
|  | setup_new_file() { | ||||||
|  | 	write_script new-file-editor.sh <<-\EOF && | ||||||
|  | 	sed /^#/d "$1" >patch && | ||||||
|  | 	sed /^+c/d patch >"$1" | ||||||
|  | 	EOF | ||||||
|  | 	test_set_editor "$(pwd)/new-file-editor.sh" && | ||||||
|  | 	test_write_lines a b c d e f >new-file && | ||||||
|  | 	test_write_lines a b d e f >new-file-expect && | ||||||
|  | 	test_write_lines "@@ -0,0 +1,6 @@" +a +b +c +d +e +f >patch-expect | ||||||
|  | } | ||||||
|  |  | ||||||
|  | test_expect_success 'add -N followed by add -p patch editing' ' | ||||||
|  | 	git reset --hard && | ||||||
|  | 	( | ||||||
|  | 		setup_new_file && | ||||||
|  | 		git add -N new-file && | ||||||
|  | 		test_write_lines e n q | git add -p && | ||||||
|  | 		git cat-file blob :new-file >actual && | ||||||
|  | 		test_cmp new-file-expect actual && | ||||||
|  | 		test_cmp patch-expect patch | ||||||
|  | 	) | ||||||
|  | ' | ||||||
|  |  | ||||||
|  | test_expect_success 'checkout -p patch editing of added file' ' | ||||||
|  | 	git reset --hard && | ||||||
|  | 	( | ||||||
|  | 		setup_new_file && | ||||||
|  | 		git add new-file && | ||||||
|  | 		git commit -m "add new file" && | ||||||
|  | 		git rm new-file && | ||||||
|  | 		git commit -m "remove new file" && | ||||||
|  | 		test_write_lines e n q | git checkout -p HEAD^ && | ||||||
|  | 		test_cmp new-file-expect new-file && | ||||||
|  | 		test_cmp patch-expect patch | ||||||
|  | 	) | ||||||
|  | ' | ||||||
|  |  | ||||||
| test_expect_success 'show help from add--helper' ' | test_expect_success 'show help from add--helper' ' | ||||||
| 	git reset --hard && | 	git reset --hard && | ||||||
| 	cat >expect <<-EOF && | 	cat >expect <<-EOF && | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Junio C Hamano
					Junio C Hamano