Merge branch 'master' of git://repo.or.cz/alt-git

This commit is contained in:
Johannes Sixt
2009-05-25 08:38:05 +02:00
129 changed files with 2228 additions and 981 deletions

View File

@@ -604,6 +604,12 @@ color.pager::
A boolean to enable/disable colored output when the pager is in
use (default is true).
color.showbranch::
A boolean to enable/disable color in the output of
linkgit:git-show-branch[1]. May be set to `always`,
`false` (or `never`) or `auto` (or `true`), in which case colors are used
only when the output is to a terminal. Defaults to false.
color.status::
A boolean to enable/disable color in the output of
linkgit:git-status[1]. May be set to `always`,

View File

@@ -9,7 +9,7 @@ SYNOPSIS
--------
[verse]
'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
[--all | [--update | -u]] [--intent-to-add | -N]
[--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N]
[--refresh] [--ignore-errors] [--] <filepattern>...
DESCRIPTION
@@ -76,6 +76,15 @@ OPTIONS
bypassed and the 'patch' subcommand is invoked using each of
the specified filepatterns before exiting.
-e, \--edit::
Open the diff vs. the index in an editor and let the user
edit it. After the editor was closed, adjust the hunk headers
and apply the patch to the index.
+
*NOTE*: Obviously, if you change anything else than the first character
on lines beginning with a space or a minus, the patch will no longer
apply.
-u::
--update::
Update only files that git already knows about, staging modified

View File

@@ -42,6 +42,8 @@ imposes the following rules on how references are named:
. They cannot contain a sequence `@{`.
- They cannot contain a `\\`.
These rules make it easy for shell script based tools to parse
reference names, pathname expansion by the shell when a reference name is used
unquoted (by mistake), and also avoids ambiguities in certain

View File

@@ -82,8 +82,10 @@ Output Format
-------------
<mode> SP <type> SP <object> TAB <file>
When the `-z` option is not used, TAB, LF, and backslash characters
Unless the `-z` option is used, TAB, LF, and backslash characters
in pathnames are represented as `\t`, `\n`, and `\\`, respectively.
This output format is compatible with what '--index-info --stdin' of
'git update-index' expects.
When the `-l` option is used, format changes to

View File

@@ -231,8 +231,7 @@ OPTIONS
-s <strategy>::
--strategy=<strategy>::
Use the given merge strategy; can be supplied more than
once to specify them in the order they should be tried.
Use the given merge strategy.
If there is no `-s` option, a built-in list of strategies
is used instead ('git-merge-recursive' when merging a single
head, 'git-merge-octopus' otherwise). This implies --merge.

View File

@@ -30,6 +30,11 @@ OPTIONS
Only meaningful in `--parseopt` mode. Tells the option parser to echo
out the first `--` met instead of skipping it.
--sq-quote::
Use 'git-rev-parse' in shell quoting mode (see SQ-QUOTE
section below). In contrast to the `--sq` option below, this
mode does only quoting. Nothing else is done to command input.
--revs-only::
Do not output flags and parameters not meant for
'git-rev-list' command.
@@ -64,7 +69,8 @@ OPTIONS
properly quoted for consumption by shell. Useful when
you expect your parameter to contain whitespaces and
newlines (e.g. when using pickaxe `-S` with
'git-diff-\*').
'git-diff-\*'). In contrast to the `--sq-quote` option,
the command input is still interpreted as usual.
--not::
When showing object names, prefix them with '{caret}' and
@@ -406,6 +412,33 @@ C? option C with an optional argument"
eval `echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?`
------------
SQ-QUOTE
--------
In `--sq-quote` mode, 'git-rev-parse' echoes on the standard output a
single line suitable for `sh(1)` `eval`. This line is made by
normalizing the arguments following `--sq-quote`. Nothing other than
quoting the arguments is done.
If you want command input to still be interpreted as usual by
'git-rev-parse' before the output is shell quoted, see the `--sq`
option.
Example
~~~~~~~
------------
$ cat >your-git-script.sh <<\EOF
#!/bin/sh
args=$(git rev-parse --sq-quote "$@") # quote user-supplied arguments
command="git frotz -n24 $args" # and use it inside a handcrafted
# command line
eval "$command"
EOF
$ sh your-git-script.sh "a b'c"
------------
EXAMPLES
--------

View File

@@ -69,9 +69,12 @@ and In-Reply-To headers will be used unless they are removed.
Missing From or In-Reply-To headers will be prompted for.
--from=<address>::
Specify the sender of the emails. This will default to
the value GIT_COMMITTER_IDENT, as returned by "git var -l".
The user will still be prompted to confirm this entry.
Specify the sender of the emails. If not specified on the command line,
the value of the 'sendemail.from' configuration option is used. If
neither the command line option nor 'sendemail.from' are set, then the
user will be prompted for the value. The default for the prompt will be
the value of GIT_AUTHOR_IDENT, or GIT_COMMITTER_IDENT if that is not
set, as returned by "git var -l".
--in-reply-to=<identifier>::
Specify the contents of the first In-Reply-To header.

View File

@@ -10,6 +10,7 @@ SYNOPSIS
[verse]
'git show-branch' [--all] [--remotes] [--topo-order] [--current]
[--more=<n> | --list | --independent | --merge-base]
[--color | --no-color]
[--no-name | --sha1-name] [--topics] [<rev> | <glob>]...
'git show-branch' (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]
@@ -107,6 +108,14 @@ OPTIONS
When no explicit <ref> parameter is given, it defaults to the
current branch (or `HEAD` if it is detached).
--color::
Color the status sign (one of these: `*` `!` `+` `-`) of each commit
corresponding to the branch it's in.
--no-color::
Turn off colored output, even when the configuration file gives the
default to color output.
Note that --more, --list, --independent and --merge-base options
are mutually exclusive.

View File

@@ -9,10 +9,12 @@ git-submodule - Initialize, update or inspect submodules
SYNOPSIS
--------
[verse]
'git submodule' [--quiet] add [-b branch] [--] <repository> <path>
'git submodule' [--quiet] add [-b branch]
[--reference <repository>] [--] <repository> <path>
'git submodule' [--quiet] status [--cached] [--] [<path>...]
'git submodule' [--quiet] init [--] [<path>...]
'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--] [<path>...]
'git submodule' [--quiet] update [--init] [-N|--no-fetch]
[--reference <repository>] [--] [<path>...]
'git submodule' [--quiet] summary [--summary-limit <n>] [commit] [--] [<path>...]
'git submodule' [--quiet] foreach <command>
'git submodule' [--quiet] sync [--] [<path>...]
@@ -177,6 +179,14 @@ OPTIONS
This option is only valid for the update command.
Don't fetch new objects from the remote site.
--reference <repository>::
This option is only valid for add and update commands. These
commands sometimes need to clone a remote repository. In this case,
this option will be passed to the linkgit:git-clone[1] command.
+
*NOTE*: Do *not* use this option unless you have read the note
for linkgit:git-clone[1]'s --reference and --shared options carefully.
<path>...::
Paths to submodule(s). When specified this will restrict the command
to only operate on the submodules found at the specified paths.

View File

@@ -398,6 +398,14 @@ after the authors-file is modified should continue operation.
config key: svn.authorsfile
--authors-prog=<filename>::
If this option is specified, for each SVN committer name that does not
exist in the authors file, the given file is executed with the committer
name as the first argument. The program is expected to return a single
line of the form "Name <email>", which will be treated as if included in
the authors file.
-q::
--quiet::
Make 'git-svn' less verbose. Specify a second time to make it

View File

@@ -137,6 +137,10 @@ There are some macros to easily define options:
Introduce a boolean option.
If used, `int_var` is bitwise-ored with `mask`.
`OPT_NEGBIT(short, long, &int_var, description, mask)`::
Introduce a boolean option.
If used, `int_var` is bitwise-anded with the inverted `mask`.
`OPT_SET_INT(short, long, &int_var, description, integer)`::
Introduce a boolean option.
If used, set `int_var` to `integer`.
@@ -166,6 +170,14 @@ There are some macros to easily define options:
`OPT_ARGUMENT(long, description)`::
Introduce a long-option argument that will be kept in `argv[]`.
`OPT_NUMBER_CALLBACK(&var, description, func_ptr)`::
Recognize numerical options like -123 and feed the integer as
if it was an argument to the function given by `func_ptr`.
The result will be put into `var`. There can be only one such
option definition. It cannot be negated and it takes no
arguments. Short options that happen to be digits take
precedence over it.
The last element of the array must be `OPT_END()`.
@@ -198,7 +210,7 @@ The function must be defined in this form:
The callback mechanism is as follows:
* Inside `funct`, the only interesting member of the structure
* Inside `func`, the only interesting member of the structure
given by `opt` is the void pointer `opt->value`.
`\*opt->value` will be the value that is saved into `var`, if you
use `OPT_CALLBACK()`.

View File

@@ -175,6 +175,9 @@ all::
# Define OBJECT_CREATION_USES_RENAMES if your operating systems has problems
# when hardlinking a file to another name and unlinking the original file right
# away (some NTFS drivers seem to zero the contents in that scenario).
#
# Define NO_CROSS_DIRECTORY_HARDLINKS if you plan to distribute the installed
# programs as a tar, where bin/ and libexec/ might be on different file systems.
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -750,6 +753,7 @@ endif
ifeq ($(uname_S),OpenBSD)
NO_STRCASESTR = YesPlease
NO_MEMMEM = YesPlease
USE_ST_TIMESPEC = YesPlease
NEEDS_LIBICONV = YesPlease
BASIC_CFLAGS += -I/usr/local/include
BASIC_LDFLAGS += -L/usr/local/lib
@@ -1250,7 +1254,6 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
$(QUIET_GEN)$(RM) $@ $@+ && \
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
-e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
$@.sh >$@+ && \
@@ -1551,6 +1554,7 @@ endif
bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
{ $(RM) "$$execdir/git-add$X" && \
test -z "$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
ln "$$bindir/git$X" "$$execdir/git-add$X" 2>/dev/null || \
cp "$$bindir/git$X" "$$execdir/git-add$X"; } && \
{ for p in $(filter-out git-add$X,$(BUILT_INS)); do \

View File

@@ -38,10 +38,7 @@ int split_cmdline(char *cmdline, const char ***argv)
while (cmdline[++src]
&& isspace(cmdline[src]))
; /* skip */
if (count >= size) {
size += 16;
*argv = xrealloc(*argv, sizeof(char *) * size);
}
ALLOC_GROW(*argv, count+1, size);
(*argv)[count++] = cmdline + dst;
} else if (!quoted && (c == '\'' || c == '"')) {
quoted = c;
@@ -72,6 +69,9 @@ int split_cmdline(char *cmdline, const char ***argv)
return error("unclosed quote");
}
ALLOC_GROW(*argv, count+1, size);
(*argv)[count] = NULL;
return count;
}

456
bisect.c
View File

@@ -6,15 +6,30 @@
#include "list-objects.h"
#include "quote.h"
#include "sha1-lookup.h"
#include "run-command.h"
#include "bisect.h"
static unsigned char (*skipped_sha1)[20];
static int skipped_sha1_nr;
static int skipped_sha1_alloc;
struct sha1_array {
unsigned char (*sha1)[20];
int sha1_nr;
int sha1_alloc;
int sorted;
};
static const char **rev_argv;
static int rev_argv_nr;
static int rev_argv_alloc;
static struct sha1_array good_revs;
static struct sha1_array skipped_revs;
static const unsigned char *current_bad_sha1;
struct argv_array {
const char **argv;
int argv_nr;
int argv_alloc;
};
static const char *argv_diff_tree[] = {"diff-tree", "--pretty", NULL, NULL};
static const char *argv_checkout[] = {"checkout", "-q", NULL, "--", NULL};
static const char *argv_show_branch[] = {"show-branch", NULL, NULL};
/* bits #0-15 in revision.h */
@@ -398,23 +413,37 @@ struct commit_list *find_bisection(struct commit_list *list,
return best;
}
static void argv_array_push(struct argv_array *array, const char *string)
{
ALLOC_GROW(array->argv, array->argv_nr + 1, array->argv_alloc);
array->argv[array->argv_nr++] = string;
}
static void argv_array_push_sha1(struct argv_array *array,
const unsigned char *sha1,
const char *format)
{
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, format, sha1_to_hex(sha1));
argv_array_push(array, strbuf_detach(&buf, NULL));
}
static void sha1_array_push(struct sha1_array *array,
const unsigned char *sha1)
{
ALLOC_GROW(array->sha1, array->sha1_nr + 1, array->sha1_alloc);
hashcpy(array->sha1[array->sha1_nr++], sha1);
}
static int register_ref(const char *refname, const unsigned char *sha1,
int flags, void *cb_data)
{
if (!strcmp(refname, "bad")) {
ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
rev_argv[rev_argv_nr++] = xstrdup(sha1_to_hex(sha1));
current_bad_sha1 = sha1;
} else if (!prefixcmp(refname, "good-")) {
const char *hex = sha1_to_hex(sha1);
char *good = xmalloc(strlen(hex) + 2);
*good = '^';
memcpy(good + 1, hex, strlen(hex) + 1);
ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
rev_argv[rev_argv_nr++] = good;
sha1_array_push(&good_revs, sha1);
} else if (!prefixcmp(refname, "skip-")) {
ALLOC_GROW(skipped_sha1, skipped_sha1_nr + 1,
skipped_sha1_alloc);
hashcpy(skipped_sha1[skipped_sha1_nr++], sha1);
sha1_array_push(&skipped_revs, sha1);
}
return 0;
@@ -425,7 +454,7 @@ static int read_bisect_refs(void)
return for_each_ref_in("refs/bisect/", register_ref, NULL);
}
void read_bisect_paths(void)
void read_bisect_paths(struct argv_array *array)
{
struct strbuf str = STRBUF_INIT;
const char *filename = git_path("BISECT_NAMES");
@@ -440,8 +469,8 @@ void read_bisect_paths(void)
strbuf_trim(&str);
quoted = strbuf_detach(&str, NULL);
res = sq_dequote_to_argv(quoted, &rev_argv,
&rev_argv_nr, &rev_argv_alloc);
res = sq_dequote_to_argv(quoted, &array->argv,
&array->argv_nr, &array->argv_alloc);
if (res)
die("Badly quoted content in file '%s': %s",
filename, quoted);
@@ -451,26 +480,45 @@ void read_bisect_paths(void)
fclose(fp);
}
static int skipcmp(const void *a, const void *b)
static int array_cmp(const void *a, const void *b)
{
return hashcmp(a, b);
}
static void prepare_skipped(void)
static void sort_sha1_array(struct sha1_array *array)
{
qsort(skipped_sha1, skipped_sha1_nr, sizeof(*skipped_sha1), skipcmp);
qsort(array->sha1, array->sha1_nr, sizeof(*array->sha1), array_cmp);
array->sorted = 1;
}
static const unsigned char *skipped_sha1_access(size_t index, void *table)
static const unsigned char *sha1_access(size_t index, void *table)
{
unsigned char (*skipped)[20] = table;
return skipped[index];
unsigned char (*array)[20] = table;
return array[index];
}
static int lookup_skipped(unsigned char *sha1)
static int lookup_sha1_array(struct sha1_array *array,
const unsigned char *sha1)
{
return sha1_pos(sha1, skipped_sha1, skipped_sha1_nr,
skipped_sha1_access);
if (!array->sorted)
sort_sha1_array(array);
return sha1_pos(sha1, array->sha1, array->sha1_nr, sha1_access);
}
static char *join_sha1_array_hex(struct sha1_array *array, char delim)
{
struct strbuf joined_hexs = STRBUF_INIT;
int i;
for (i = 0; i < array->sha1_nr; i++) {
strbuf_addstr(&joined_hexs, sha1_to_hex(array->sha1[i]));
if (i + 1 < array->sha1_nr)
strbuf_addch(&joined_hexs, delim);
}
return strbuf_detach(&joined_hexs, NULL);
}
struct commit_list *filter_skipped(struct commit_list *list,
@@ -481,15 +529,14 @@ struct commit_list *filter_skipped(struct commit_list *list,
*tried = NULL;
if (!skipped_sha1_nr)
if (!skipped_revs.sha1_nr)
return list;
prepare_skipped();
while (list) {
struct commit_list *next = list->next;
list->next = NULL;
if (0 <= lookup_skipped(list->item->object.sha1)) {
if (0 <= lookup_sha1_array(&skipped_revs,
list->item->object.sha1)) {
/* Move current to tried list */
*tried = list;
tried = &list->next;
@@ -508,49 +555,328 @@ struct commit_list *filter_skipped(struct commit_list *list,
static void bisect_rev_setup(struct rev_info *revs, const char *prefix)
{
struct argv_array rev_argv = { NULL, 0, 0 };
int i;
init_revisions(revs, prefix);
revs->abbrev = 0;
revs->commit_format = CMIT_FMT_UNSPECIFIED;
/* argv[0] will be ignored by setup_revisions */
ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
rev_argv[rev_argv_nr++] = xstrdup("bisect_rev_setup");
/* rev_argv.argv[0] will be ignored by setup_revisions */
argv_array_push(&rev_argv, xstrdup("bisect_rev_setup"));
argv_array_push_sha1(&rev_argv, current_bad_sha1, "%s");
for (i = 0; i < good_revs.sha1_nr; i++)
argv_array_push_sha1(&rev_argv, good_revs.sha1[i], "^%s");
argv_array_push(&rev_argv, xstrdup("--"));
read_bisect_paths(&rev_argv);
argv_array_push(&rev_argv, NULL);
setup_revisions(rev_argv.argv_nr, rev_argv.argv, revs, NULL);
revs->limited = 1;
}
static void bisect_common(struct rev_info *revs, int *reaches, int *all)
{
if (prepare_revision_walk(revs))
die("revision walk setup failed");
if (revs->tree_objects)
mark_edges_uninteresting(revs->commits, revs, NULL);
revs->commits = find_bisection(revs->commits, reaches, all,
!!skipped_revs.sha1_nr);
}
static void exit_if_skipped_commits(struct commit_list *tried,
const unsigned char *bad)
{
if (!tried)
return;
printf("There are only 'skip'ped commits left to test.\n"
"The first bad commit could be any of:\n");
print_commit_list(tried, "%s\n", "%s\n");
if (bad)
printf("%s\n", sha1_to_hex(bad));
printf("We cannot bisect more!\n");
exit(2);
}
static int is_expected_rev(const unsigned char *sha1)
{
const char *filename = git_path("BISECT_EXPECTED_REV");
struct stat st;
struct strbuf str = STRBUF_INIT;
FILE *fp;
int res = 0;
if (stat(filename, &st) || !S_ISREG(st.st_mode))
return 0;
fp = fopen(filename, "r");
if (!fp)
return 0;
if (strbuf_getline(&str, fp, '\n') != EOF)
res = !strcmp(str.buf, sha1_to_hex(sha1));
strbuf_release(&str);
fclose(fp);
return res;
}
static void mark_expected_rev(char *bisect_rev_hex)
{
int len = strlen(bisect_rev_hex);
const char *filename = git_path("BISECT_EXPECTED_REV");
int fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (fd < 0)
die("could not create file '%s': %s",
filename, strerror(errno));
bisect_rev_hex[len] = '\n';
write_or_die(fd, bisect_rev_hex, len + 1);
bisect_rev_hex[len] = '\0';
if (close(fd) < 0)
die("closing file %s: %s", filename, strerror(errno));
}
static int bisect_checkout(char *bisect_rev_hex)
{
int res;
mark_expected_rev(bisect_rev_hex);
argv_checkout[2] = bisect_rev_hex;
res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
if (res)
exit(res);
argv_show_branch[1] = bisect_rev_hex;
return run_command_v_opt(argv_show_branch, RUN_GIT_CMD);
}
static struct commit *get_commit_reference(const unsigned char *sha1)
{
struct commit *r = lookup_commit_reference(sha1);
if (!r)
die("Not a valid commit name %s", sha1_to_hex(sha1));
return r;
}
static struct commit **get_bad_and_good_commits(int *rev_nr)
{
int len = 1 + good_revs.sha1_nr;
struct commit **rev = xmalloc(len * sizeof(*rev));
int i, n = 0;
rev[n++] = get_commit_reference(current_bad_sha1);
for (i = 0; i < good_revs.sha1_nr; i++)
rev[n++] = get_commit_reference(good_revs.sha1[i]);
*rev_nr = n;
return rev;
}
static void handle_bad_merge_base(void)
{
if (is_expected_rev(current_bad_sha1)) {
char *bad_hex = sha1_to_hex(current_bad_sha1);
char *good_hex = join_sha1_array_hex(&good_revs, ' ');
fprintf(stderr, "The merge base %s is bad.\n"
"This means the bug has been fixed "
"between %s and [%s].\n",
bad_hex, bad_hex, good_hex);
exit(3);
}
fprintf(stderr, "Some good revs are not ancestor of the bad rev.\n"
"git bisect cannot work properly in this case.\n"
"Maybe you mistake good and bad revs?\n");
exit(1);
}
void handle_skipped_merge_base(const unsigned char *mb)
{
char *mb_hex = sha1_to_hex(mb);
char *bad_hex = sha1_to_hex(current_bad_sha1);
char *good_hex = join_sha1_array_hex(&good_revs, ' ');
fprintf(stderr, "Warning: the merge base between %s and [%s] "
"must be skipped.\n"
"So we cannot be sure the first bad commit is "
"between %s and %s.\n"
"We continue anyway.\n",
bad_hex, good_hex, mb_hex, bad_hex);
free(good_hex);
}
/*
* "check_merge_bases" checks that merge bases are not "bad".
*
* - If one is "bad", it means the user assumed something wrong
* and we must exit with a non 0 error code.
* - If one is "good", that's good, we have nothing to do.
* - If one is "skipped", we can't know but we should warn.
* - If we don't know, we should check it out and ask the user to test.
*/
static void check_merge_bases(void)
{
struct commit_list *result;
int rev_nr;
struct commit **rev = get_bad_and_good_commits(&rev_nr);
result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1, 0);
for (; result; result = result->next) {
const unsigned char *mb = result->item->object.sha1;
if (!hashcmp(mb, current_bad_sha1)) {
handle_bad_merge_base();
} else if (0 <= lookup_sha1_array(&good_revs, mb)) {
continue;
} else if (0 <= lookup_sha1_array(&skipped_revs, mb)) {
handle_skipped_merge_base(mb);
} else {
printf("Bisecting: a merge base must be tested\n");
exit(bisect_checkout(sha1_to_hex(mb)));
}
}
free(rev);
free_commit_list(result);
}
/*
* This function runs the command "git rev-list $_good ^$_bad"
* and returns 1 if it produces some output, 0 otherwise.
*/
static int check_ancestors(void)
{
struct argv_array rev_argv = { NULL, 0, 0 };
struct strbuf str = STRBUF_INIT;
int i, result = 0;
struct child_process rls;
FILE *rls_fout;
argv_array_push(&rev_argv, xstrdup("rev-list"));
argv_array_push_sha1(&rev_argv, current_bad_sha1, "^%s");
for (i = 0; i < good_revs.sha1_nr; i++)
argv_array_push_sha1(&rev_argv, good_revs.sha1[i], "%s");
argv_array_push(&rev_argv, NULL);
memset(&rls, 0, sizeof(rls));
rls.argv = rev_argv.argv;
rls.out = -1;
rls.git_cmd = 1;
if (start_command(&rls))
die("Could not launch 'git rev-list' command.");
rls_fout = fdopen(rls.out, "r");
while (strbuf_getline(&str, rls_fout, '\n') != EOF) {
strbuf_trim(&str);
if (*str.buf) {
result = 1;
break;
}
}
fclose(rls_fout);
finish_command(&rls);
return result;
}
/*
* "check_good_are_ancestors_of_bad" checks that all "good" revs are
* ancestor of the "bad" rev.
*
* If that's not the case, we need to check the merge bases.
* If a merge base must be tested by the user, its source code will be
* checked out to be tested by the user and we will exit.
*/
static void check_good_are_ancestors_of_bad(const char *prefix)
{
const char *filename = git_path("BISECT_ANCESTORS_OK");
struct stat st;
int fd;
if (!current_bad_sha1)
die("a bad revision is needed");
/* Check if file BISECT_ANCESTORS_OK exists. */
if (!stat(filename, &st) && S_ISREG(st.st_mode))
return;
/* Bisecting with no good rev is ok. */
if (good_revs.sha1_nr == 0)
return;
if (check_ancestors())
check_merge_bases();
/* Create file BISECT_ANCESTORS_OK. */
fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (fd < 0)
warning("could not create file '%s': %s",
filename, strerror(errno));
else
close(fd);
}
/*
* We use the convention that exiting with an exit code 10 means that
* the bisection process finished successfully.
* In this case the calling shell script should exit 0.
*/
int bisect_next_all(const char *prefix)
{
struct rev_info revs;
struct commit_list *tried;
int reaches = 0, all = 0, nr;
const unsigned char *bisect_rev;
char bisect_rev_hex[41];
if (read_bisect_refs())
die("reading bisect refs failed");
ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
rev_argv[rev_argv_nr++] = xstrdup("--");
read_bisect_paths();
ALLOC_GROW(rev_argv, rev_argv_nr + 1, rev_argv_alloc);
rev_argv[rev_argv_nr++] = NULL;
setup_revisions(rev_argv_nr, rev_argv, revs, NULL);
revs->limited = 1;
}
int bisect_next_vars(const char *prefix)
{
struct rev_info revs;
struct rev_list_info info;
int reaches = 0, all = 0;
memset(&info, 0, sizeof(info));
info.revs = &revs;
info.bisect_show_flags = BISECT_SHOW_TRIED | BISECT_SHOW_STRINGED;
check_good_are_ancestors_of_bad(prefix);
bisect_rev_setup(&revs, prefix);
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
if (revs.tree_objects)
mark_edges_uninteresting(revs.commits, &revs, NULL);
bisect_common(&revs, &reaches, &all);
revs.commits = find_bisection(revs.commits, &reaches, &all,
!!skipped_sha1_nr);
revs.commits = filter_skipped(revs.commits, &tried, 0);
return show_bisect_vars(&info, reaches, all);
if (!revs.commits) {
/*
* We should exit here only if the "bad"
* commit is also a "skip" commit.
*/
exit_if_skipped_commits(tried, NULL);
printf("%s was both good and bad\n",
sha1_to_hex(current_bad_sha1));
exit(1);
}
bisect_rev = revs.commits->item->object.sha1;
memcpy(bisect_rev_hex, sha1_to_hex(bisect_rev), 41);
if (!hashcmp(bisect_rev, current_bad_sha1)) {
exit_if_skipped_commits(tried, current_bad_sha1);
printf("%s is first bad commit\n", bisect_rev_hex);
argv_diff_tree[2] = bisect_rev_hex;
run_command_v_opt(argv_diff_tree, RUN_GIT_CMD);
/* This means the bisection process succeeded. */
exit(10);
}
nr = all - reaches - 1;
printf("Bisecting: %d revisions left to test after this "
"(roughly %d steps)\n", nr, estimate_bisect_steps(all));
return bisect_checkout(bisect_rev_hex);
}

View File

@@ -9,10 +9,13 @@ extern struct commit_list *filter_skipped(struct commit_list *list,
struct commit_list **tried,
int show_all);
extern void print_commit_list(struct commit_list *list,
const char *format_cur,
const char *format_last);
/* bisect_show_flags flags in struct rev_list_info */
#define BISECT_SHOW_ALL (1<<0)
#define BISECT_SHOW_TRIED (1<<1)
#define BISECT_SHOW_STRINGED (1<<2)
struct rev_list_info {
struct rev_info *revs;
@@ -24,6 +27,8 @@ struct rev_list_info {
extern int show_bisect_vars(struct rev_list_info *info, int reaches, int all);
extern int bisect_next_vars(const char *prefix);
extern int bisect_next_all(const char *prefix);
extern int estimate_bisect_steps(int all);
#endif

View File

@@ -10,12 +10,14 @@
#include "cache-tree.h"
#include "run-command.h"
#include "parse-options.h"
#include "diff.h"
#include "revision.h"
static const char * const builtin_add_usage[] = {
"git add [options] [--] <filepattern>...",
NULL
};
static int patch_interactive, add_interactive;
static int patch_interactive, add_interactive, edit_interactive;
static int take_worktree_changes;
static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)
@@ -61,7 +63,7 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p
fill_pathspec_matches(pathspec, seen, specs);
for (i = 0; i < specs; i++) {
if (!seen[i] && !file_exists(pathspec[i]))
if (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]))
die("pathspec '%s' did not match any files",
pathspec[i]);
}
@@ -187,6 +189,51 @@ int interactive_add(int argc, const char **argv, const char *prefix)
return status;
}
int edit_patch(int argc, const char **argv, const char *prefix)
{
char *file = xstrdup(git_path("ADD_EDIT.patch"));
const char *apply_argv[] = { "apply", "--recount", "--cached",
file, NULL };
struct child_process child;
struct rev_info rev;
int out;
struct stat st;
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
if (read_cache() < 0)
die ("Could not read the index");
init_revisions(&rev, prefix);
rev.diffopt.context = 7;
argc = setup_revisions(argc, argv, &rev, NULL);
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
out = open(file, O_CREAT | O_WRONLY, 0644);
if (out < 0)
die ("Could not open '%s' for writing.", file);
rev.diffopt.file = fdopen(out, "w");
rev.diffopt.close_file = 1;
if (run_diff_files(&rev, 0))
die ("Could not write patch");
launch_editor(file, NULL, NULL);
if (stat(file, &st))
die("Could not stat '%s'", file);
if (!st.st_size)
die("Empty patch. Aborted.");
memset(&child, 0, sizeof(child));
child.git_cmd = 1;
child.argv = apply_argv;
if (run_command(&child))
die ("Could not apply '%s'", file);
unlink(file);
return 0;
}
static struct lock_file lock_file;
static const char ignore_error[] =
@@ -201,6 +248,7 @@ static struct option builtin_add_options[] = {
OPT_GROUP(""),
OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and apply"),
OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"),
OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
@@ -251,14 +299,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)
int require_pathspec;
argc = parse_options(argc, argv, builtin_add_options,
builtin_add_usage, 0);
builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
if (patch_interactive)
add_interactive = 1;
if (add_interactive)
exit(interactive_add(argc, argv, prefix));
exit(interactive_add(argc - 1, argv + 1, prefix));
git_config(add_config, NULL);
if (edit_interactive)
return(edit_patch(argc, argv, prefix));
argc--;
argv++;
if (addremove && take_worktree_changes)
die("-A and -u are mutually incompatible");
if ((addremove || take_worktree_changes) && !argc) {

View File

@@ -2781,7 +2781,7 @@ static void remove_file(struct patch *patch, int rmdir_empty)
if (rmdir(patch->old_name))
warning("unable to remove submodule %s",
patch->old_name);
} else if (!unlink(patch->old_name) && rmdir_empty) {
} else if (!unlink_or_warn(patch->old_name) && rmdir_empty) {
remove_path(patch->old_name);
}
}
@@ -2891,7 +2891,7 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned
if (!try_create_file(newpath, mode, buf, size)) {
if (!rename(newpath, path))
return;
unlink(newpath);
unlink_or_warn(newpath);
break;
}
if (errno != EEXIST)

View File

@@ -4,24 +4,24 @@
#include "bisect.h"
static const char * const git_bisect_helper_usage[] = {
"git bisect--helper --next-vars",
"git bisect--helper --next-all",
NULL
};
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
{
int next_vars = 0;
int next_all = 0;
struct option options[] = {
OPT_BOOLEAN(0, "next-vars", &next_vars,
"output next bisect step variables"),
OPT_BOOLEAN(0, "next-all", &next_all,
"perform 'git bisect next'"),
OPT_END()
};
argc = parse_options(argc, argv, options, git_bisect_helper_usage, 0);
if (!next_vars)
if (!next_all)
usage_with_options(git_bisect_helper_usage, options);
/* next-vars */
return bisect_next_vars(prefix);
/* next-all */
return bisect_next_all(prefix);
}

View File

@@ -216,7 +216,7 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
newfd = hold_locked_index(lock_file, 1);
if (read_cache() < 0)
if (read_cache_preload(pathspec) < 0)
return error("corrupt index file");
if (source_tree)
@@ -366,7 +366,7 @@ static int merge_working_tree(struct checkout_opts *opts,
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
int newfd = hold_locked_index(lock_file, 1);
if (read_cache() < 0)
if (read_cache_preload(NULL) < 0)
return error("corrupt index file");
if (opts->force) {
@@ -541,14 +541,6 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
parse_commit(new->commit);
}
/*
* If we were on a detached HEAD, but we are now moving to
* a new commit, we want to mention the old commit once more
* to remind the user that it might be lost.
*/
if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
describe_detached_head("Previous HEAD position was", old.commit);
if (!old.commit && !opts->force) {
if (!opts->quiet) {
warning("You appear to be on a branch yet to be born.");
@@ -561,6 +553,14 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
if (ret)
return ret;
/*
* If we were on a detached HEAD, but have now moved to
* a new commit, we want to mention the old commit once more
* to remind the user that it might be lost.
*/
if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
describe_detached_head("Previous HEAD position was", old.commit);
update_refs_for_switch(opts, &old, new);
ret = post_checkout_hook(old.commit, new->commit, 1);

View File

@@ -104,11 +104,12 @@ static char *get_repo_path(const char *repo, int *is_bundle)
static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
{
const char *end = repo + strlen(repo), *start;
char *dir;
/*
* Strip trailing slashes and /.git
* Strip trailing spaces, slashes and /.git
*/
while (repo < end && is_dir_sep(end[-1]))
while (repo < end && (is_dir_sep(end[-1]) || isspace(end[-1])))
end--;
if (end - repo > 5 && is_dir_sep(end[-5]) &&
!strncmp(end - 4, ".git", 4)) {
@@ -140,10 +141,33 @@ static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
if (is_bare) {
struct strbuf result = STRBUF_INIT;
strbuf_addf(&result, "%.*s.git", (int)(end - start), start);
return strbuf_detach(&result, 0);
dir = strbuf_detach(&result, 0);
} else
dir = xstrndup(start, end - start);
/*
* Replace sequences of 'control' characters and whitespace
* with one ascii space, remove leading and trailing spaces.
*/
if (*dir) {
char *out = dir;
int prev_space = 1 /* strip leading whitespace */;
for (end = dir; *end; ++end) {
char ch = *end;
if ((unsigned char)ch < '\x20')
ch = '\x20';
if (isspace(ch)) {
if (prev_space)
continue;
prev_space = 1;
} else
prev_space = 0;
*out++ = ch;
}
*out = '\0';
if (out > dir && prev_space)
out[-1] = '\0';
}
return xstrndup(start, end - start);
return dir;
}
static void strip_trailing_slashes(char *dir)
@@ -228,7 +252,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest)
}
if (unlink(dest->buf) && errno != ENOENT)
die("failed to unlink %s", dest->buf);
die("failed to unlink %s: %s",
dest->buf, strerror(errno));
if (!option_no_hardlinks) {
if (!link(src->buf, dest->buf))
continue;

View File

@@ -825,7 +825,7 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
fd = hold_lock_file_for_update(&lock, shallow,
LOCK_DIE_ON_ERROR);
if (!write_shallow_commits(fd, 0)) {
unlink(shallow);
unlink_or_warn(shallow);
rollback_lock_file(&lock);
} else {
commit_lock_file(&lock);

View File

@@ -197,7 +197,7 @@ static int update_local_ref(struct ref *ref,
struct commit *current = NULL, *updated;
enum object_type type;
struct branch *current_branch = branch_get(NULL);
const char *pretty_ref = prettify_ref(ref);
const char *pretty_ref = prettify_refname(ref->name);
*display = 0;
type = sha1_object_info(ref->new_sha1, NULL);
@@ -289,7 +289,7 @@ static int update_local_ref(struct ref *ref,
}
}
static int store_updated_refs(const char *url, const char *remote_name,
static int store_updated_refs(const char *raw_url, const char *remote_name,
struct ref *ref_map)
{
FILE *fp;
@@ -298,11 +298,13 @@ static int store_updated_refs(const char *url, const char *remote_name,
char note[1024];
const char *what, *kind;
struct ref *rm;
char *filename = git_path("FETCH_HEAD");
char *url, *filename = git_path("FETCH_HEAD");
fp = fopen(filename, "a");
if (!fp)
return error("cannot open %s: %s\n", filename, strerror(errno));
url = transport_anonymize_url(raw_url);
for (rm = ref_map; rm; rm = rm->next) {
struct ref *ref = NULL;
@@ -382,6 +384,7 @@ static int store_updated_refs(const char *url, const char *remote_name,
fprintf(stderr, " %s\n", note);
}
}
free(url);
fclose(fp);
if (rc & 2)
error("some local refs could not be updated; try running\n"

View File

@@ -339,8 +339,11 @@ static const char *copy_name(const char *buf)
static const char *copy_email(const char *buf)
{
const char *email = strchr(buf, '<');
const char *eoemail = strchr(email, '>');
if (!email || !eoemail)
const char *eoemail;
if (!email)
return "";
eoemail = strchr(email, '>');
if (!eoemail)
return "";
return xmemdupz(email, eoemail + 1 - email);
}

View File

@@ -10,6 +10,7 @@
#include "tag.h"
#include "tree-walk.h"
#include "builtin.h"
#include "parse-options.h"
#include "grep.h"
#ifndef NO_EXTERNAL_GREP
@@ -20,7 +21,10 @@
#endif
#endif
static int builtin_grep;
static char const * const grep_usage[] = {
"git grep [options] [-e] <pattern> [<rev>...] [[--] path...]",
NULL
};
static int grep_config(const char *var, const char *value, void *cb)
{
@@ -432,7 +436,8 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
}
#endif
static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
static int grep_cache(struct grep_opt *opt, const char **paths, int cached,
int external_grep_allowed)
{
int hit = 0;
int nr;
@@ -444,7 +449,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
* we grep through the checked-out files. It tends to
* be a lot more optimized
*/
if (!cached && !builtin_grep) {
if (!cached && external_grep_allowed) {
hit = external_grep(opt, paths, cached);
if (hit >= 0)
return hit;
@@ -560,25 +565,182 @@ static int grep_object(struct grep_opt *opt, const char **paths,
die("unable to grep from object of type %s", typename(obj->type));
}
static const char builtin_grep_usage[] =
"git grep <option>* [-e] <pattern> <rev>* [[--] <path>...]";
static int context_callback(const struct option *opt, const char *arg,
int unset)
{
struct grep_opt *grep_opt = opt->value;
int value;
const char *endp;
static const char emsg_invalid_context_len[] =
"%s: invalid context length argument";
static const char emsg_missing_context_len[] =
"missing context length argument";
static const char emsg_missing_argument[] =
"option requires an argument -%s";
if (unset) {
grep_opt->pre_context = grep_opt->post_context = 0;
return 0;
}
value = strtol(arg, (char **)&endp, 10);
if (*endp) {
return error("switch `%c' expects a numerical value",
opt->short_name);
}
grep_opt->pre_context = grep_opt->post_context = value;
return 0;
}
static int file_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
FILE *patterns;
int lno = 0;
struct strbuf sb;
patterns = fopen(arg, "r");
if (!patterns)
die("'%s': %s", arg, strerror(errno));
while (strbuf_getline(&sb, patterns, '\n') == 0) {
/* ignore empty line like grep does */
if (sb.len == 0)
continue;
append_grep_pattern(grep_opt, strbuf_detach(&sb, NULL), arg,
++lno, GREP_PATTERN);
}
fclose(patterns);
strbuf_release(&sb);
return 0;
}
static int not_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
append_grep_pattern(grep_opt, "--not", "command line", 0, GREP_NOT);
return 0;
}
static int and_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
append_grep_pattern(grep_opt, "--and", "command line", 0, GREP_AND);
return 0;
}
static int open_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
append_grep_pattern(grep_opt, "(", "command line", 0, GREP_OPEN_PAREN);
return 0;
}
static int close_callback(const struct option *opt, const char *arg, int unset)
{
struct grep_opt *grep_opt = opt->value;
append_grep_pattern(grep_opt, ")", "command line", 0, GREP_CLOSE_PAREN);
return 0;
}
static int pattern_callback(const struct option *opt, const char *arg,
int unset)
{
struct grep_opt *grep_opt = opt->value;
append_grep_pattern(grep_opt, arg, "-e option", 0, GREP_PATTERN);
return 0;
}
static int help_callback(const struct option *opt, const char *arg, int unset)
{
return -1;
}
int cmd_grep(int argc, const char **argv, const char *prefix)
{
int hit = 0;
int cached = 0;
int external_grep_allowed = 1;
int seen_dashdash = 0;
struct grep_opt opt;
struct object_array list = { 0, 0, NULL };
const char **paths = NULL;
int i;
int dummy;
struct option options[] = {
OPT_BOOLEAN(0, "cached", &cached,
"search in index instead of in the work tree"),
OPT_GROUP(""),
OPT_BOOLEAN('v', "invert-match", &opt.invert,
"show non-matching lines"),
OPT_BIT('i', "ignore-case", &opt.regflags,
"case insensitive matching", REG_ICASE),
OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp,
"match patterns only at word boundaries"),
OPT_SET_INT('a', "text", &opt.binary,
"process binary files as text", GREP_BINARY_TEXT),
OPT_SET_INT('I', NULL, &opt.binary,
"don't match patterns in binary files",
GREP_BINARY_NOMATCH),
OPT_GROUP(""),
OPT_BIT('E', "extended-regexp", &opt.regflags,
"use extended POSIX regular expressions", REG_EXTENDED),
OPT_NEGBIT('G', "basic-regexp", &opt.regflags,
"use basic POSIX regular expressions (default)",
REG_EXTENDED),
OPT_BOOLEAN('F', "fixed-strings", &opt.fixed,
"interpret patterns as fixed strings"),
OPT_GROUP(""),
OPT_BOOLEAN('n', NULL, &opt.linenum, "show line numbers"),
OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1),
OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1),
OPT_NEGBIT(0, "full-name", &opt.relative,
"show filenames relative to top directory", 1),
OPT_BOOLEAN('l', "files-with-matches", &opt.name_only,
"show only filenames instead of matching lines"),
OPT_BOOLEAN(0, "name-only", &opt.name_only,
"synonym for --files-with-matches"),
OPT_BOOLEAN('L', "files-without-match",
&opt.unmatch_name_only,
"show only the names of files without match"),
OPT_BOOLEAN('z', "null", &opt.null_following_name,
"print NUL after filenames"),
OPT_BOOLEAN('c', "count", &opt.count,
"show the number of matches instead of matching lines"),
OPT_SET_INT(0, "color", &opt.color, "highlight matches", 1),
OPT_GROUP(""),
OPT_CALLBACK('C', NULL, &opt, "n",
"show <n> context lines before and after matches",
context_callback),
OPT_INTEGER('B', NULL, &opt.pre_context,
"show <n> context lines before matches"),
OPT_INTEGER('A', NULL, &opt.post_context,
"show <n> context lines after matches"),
OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM",
context_callback),
OPT_GROUP(""),
OPT_CALLBACK('f', NULL, &opt, "file",
"read patterns from file", file_callback),
{ OPTION_CALLBACK, 'e', NULL, &opt, "pattern",
"match <pattern>", PARSE_OPT_NONEG, pattern_callback },
{ OPTION_CALLBACK, 0, "and", &opt, NULL,
"combine patterns specified with -e",
PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback },
OPT_BOOLEAN(0, "or", &dummy, ""),
{ OPTION_CALLBACK, 0, "not", &opt, NULL, "",
PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback },
{ OPTION_CALLBACK, '(', NULL, &opt, NULL, "",
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
open_callback },
{ OPTION_CALLBACK, ')', NULL, &opt, NULL, "",
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
close_callback },
OPT_BOOLEAN(0, "all-match", &opt.all_match,
"show only matches from files that match all patterns"),
OPT_GROUP(""),
#if NO_EXTERNAL_GREP
OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed,
"allow calling of grep(1) (ignored by this build)"),
#else
OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed,
"allow calling of grep(1) (default)"),
#endif
{ OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage",
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
OPT_END()
};
memset(&opt, 0, sizeof(opt));
opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
@@ -603,227 +765,21 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
* unrecognized non option is the beginning of the refs list
* that continues up to the -- (if exists), and then paths.
*/
argc = parse_options(argc, argv, options, grep_usage,
PARSE_OPT_KEEP_DASHDASH |
PARSE_OPT_STOP_AT_NON_OPTION |
PARSE_OPT_NO_INTERNAL_HELP);
while (1 < argc) {
const char *arg = argv[1];
argc--; argv++;
if (!strcmp("--cached", arg)) {
cached = 1;
continue;
}
if (!strcmp("--no-ext-grep", arg)) {
builtin_grep = 1;
continue;
}
if (!strcmp("-a", arg) ||
!strcmp("--text", arg)) {
opt.binary = GREP_BINARY_TEXT;
continue;
}
if (!strcmp("-i", arg) ||
!strcmp("--ignore-case", arg)) {
opt.regflags |= REG_ICASE;
continue;
}
if (!strcmp("-I", arg)) {
opt.binary = GREP_BINARY_NOMATCH;
continue;
}
if (!strcmp("-v", arg) ||
!strcmp("--invert-match", arg)) {
opt.invert = 1;
continue;
}
if (!strcmp("-E", arg) ||
!strcmp("--extended-regexp", arg)) {
opt.regflags |= REG_EXTENDED;
continue;
}
if (!strcmp("-F", arg) ||
!strcmp("--fixed-strings", arg)) {
opt.fixed = 1;
continue;
}
if (!strcmp("-G", arg) ||
!strcmp("--basic-regexp", arg)) {
opt.regflags &= ~REG_EXTENDED;
continue;
}
if (!strcmp("-n", arg)) {
opt.linenum = 1;
continue;
}
if (!strcmp("-h", arg)) {
opt.pathname = 0;
continue;
}
if (!strcmp("-H", arg)) {
opt.pathname = 1;
continue;
}
if (!strcmp("-l", arg) ||
!strcmp("--name-only", arg) ||
!strcmp("--files-with-matches", arg)) {
opt.name_only = 1;
continue;
}
if (!strcmp("-L", arg) ||
!strcmp("--files-without-match", arg)) {
opt.unmatch_name_only = 1;
continue;
}
if (!strcmp("-z", arg) ||
!strcmp("--null", arg)) {
opt.null_following_name = 1;
continue;
}
if (!strcmp("-c", arg) ||
!strcmp("--count", arg)) {
opt.count = 1;
continue;
}
if (!strcmp("-w", arg) ||
!strcmp("--word-regexp", arg)) {
opt.word_regexp = 1;
continue;
}
if (!prefixcmp(arg, "-A") ||
!prefixcmp(arg, "-B") ||
!prefixcmp(arg, "-C") ||
(arg[0] == '-' && '1' <= arg[1] && arg[1] <= '9')) {
unsigned num;
const char *scan;
switch (arg[1]) {
case 'A': case 'B': case 'C':
if (!arg[2]) {
if (argc <= 1)
die(emsg_missing_context_len);
scan = *++argv;
argc--;
}
else
scan = arg + 2;
break;
default:
scan = arg + 1;
break;
}
if (strtoul_ui(scan, 10, &num))
die(emsg_invalid_context_len, scan);
switch (arg[1]) {
case 'A':
opt.post_context = num;
break;
default:
case 'C':
opt.post_context = num;
case 'B':
opt.pre_context = num;
break;
}
continue;
}
if (!strcmp("-f", arg)) {
FILE *patterns;
int lno = 0;
char buf[1024];
if (argc <= 1)
die(emsg_missing_argument, arg);
patterns = fopen(argv[1], "r");
if (!patterns)
die("'%s': %s", argv[1], strerror(errno));
while (fgets(buf, sizeof(buf), patterns)) {
int len = strlen(buf);
if (len && buf[len-1] == '\n')
buf[len-1] = 0;
/* ignore empty line like grep does */
if (!buf[0])
continue;
append_grep_pattern(&opt, xstrdup(buf),
argv[1], ++lno,
GREP_PATTERN);
}
fclose(patterns);
argv++;
argc--;
continue;
}
if (!strcmp("--not", arg)) {
append_grep_pattern(&opt, arg, "command line", 0,
GREP_NOT);
continue;
}
if (!strcmp("--and", arg)) {
append_grep_pattern(&opt, arg, "command line", 0,
GREP_AND);
continue;
}
if (!strcmp("--or", arg))
continue; /* no-op */
if (!strcmp("(", arg)) {
append_grep_pattern(&opt, arg, "command line", 0,
GREP_OPEN_PAREN);
continue;
}
if (!strcmp(")", arg)) {
append_grep_pattern(&opt, arg, "command line", 0,
GREP_CLOSE_PAREN);
continue;
}
if (!strcmp("--all-match", arg)) {
opt.all_match = 1;
continue;
}
if (!strcmp("-e", arg)) {
if (1 < argc) {
append_grep_pattern(&opt, argv[1],
"-e option", 0,
GREP_PATTERN);
argv++;
argc--;
continue;
}
die(emsg_missing_argument, arg);
}
if (!strcmp("--full-name", arg)) {
opt.relative = 0;
continue;
}
if (!strcmp("--color", arg)) {
opt.color = 1;
continue;
}
if (!strcmp("--no-color", arg)) {
opt.color = 0;
continue;
}
if (!strcmp("--", arg)) {
/* later processing wants to have this at argv[1] */
argv--;
argc++;
break;
}
if (*arg == '-')
usage(builtin_grep_usage);
/* First unrecognized non-option token */
if (!opt.pattern_list) {
append_grep_pattern(&opt, arg, "command line", 0,
GREP_PATTERN);
break;
}
else {
/* We are looking at the first path or rev;
* it is found at argv[1] after leaving the
* loop.
*/
argc++; argv--;
break;
}
/* First unrecognized non-option token */
if (argc > 0 && !opt.pattern_list) {
append_grep_pattern(&opt, argv[0], "command line", 0,
GREP_PATTERN);
argv++;
argc--;
}
if (opt.color && !opt.color_external)
builtin_grep = 1;
external_grep_allowed = 0;
if (!opt.pattern_list)
die("no pattern given.");
if ((opt.regflags != REG_NEWLINE) && opt.fixed)
@@ -831,7 +787,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
compile_grep_patterns(&opt);
/* Check revs and then paths */
for (i = 1; i < argc; i++) {
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
unsigned char sha1[20];
/* Is it a rev? */
@@ -874,7 +830,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (!list.nr) {
if (!cached)
setup_work_tree();
return !grep_cache(&opt, paths, cached);
return !grep_cache(&opt, paths, cached, external_grep_allowed);
}
if (cached)

View File

@@ -755,6 +755,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
int cover_letter = 0;
int boundary_count = 0;
int no_binary_diff = 0;
int numbered_cmdline_opt = 0;
struct commit *origin = NULL, *head = NULL;
const char *in_reply_to = NULL;
struct patch_ids ids;
@@ -786,8 +787,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (!strcmp(argv[i], "--stdout"))
use_stdout = 1;
else if (!strcmp(argv[i], "-n") ||
!strcmp(argv[i], "--numbered"))
!strcmp(argv[i], "--numbered")) {
numbered = 1;
numbered_cmdline_opt = 1;
}
else if (!strcmp(argv[i], "-N") ||
!strcmp(argv[i], "--no-numbered")) {
numbered = 0;
@@ -918,6 +921,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (start_number < 0)
start_number = 1;
/*
* If numbered is set solely due to format.numbered in config,
* and it would conflict with --keep-subject (-k) from the
* command line, reset "numbered".
*/
if (numbered && keep_subject && !numbered_cmdline_opt)
numbered = 0;
if (numbered && keep_subject)
die ("-n and -k are mutually exclusive.");
if (keep_subject && subject_prefix)

View File

@@ -454,7 +454,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
OPT_BIT(0, "directory", &dir.flags,
"show 'other' directories' name only",
DIR_SHOW_OTHER_DIRECTORIES),
OPT_BIT(0, "no-empty-directory", &dir.flags,
OPT_NEGBIT(0, "empty-directory", &dir.flags,
"don't show empty directories",
DIR_HIDE_EMPTY_DIRECTORIES),
OPT_BOOLEAN('u', "unmerged", &show_unmerged,

View File

@@ -45,8 +45,9 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
bases[bases_count++] = sha;
}
else
warning("Cannot handle more than %zu bases. "
"Ignoring %s.", ARRAY_SIZE(bases)-1, argv[i]);
warning("Cannot handle more than %d bases. "
"Ignoring %s.",
(int)ARRAY_SIZE(bases)-1, argv[i]);
}
if (argc - i != 3) /* "--" "<head>" "<remote>" */
die("Not handling anything other than two heads merge.");

View File

@@ -28,8 +28,8 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts)
memcpy(pathname + len, de->d_name, 38);
if (opts & DRY_RUN)
printf("rm -f %s\n", pathname);
else if (unlink(pathname) < 0)
error("unable to unlink %s", pathname);
else
unlink_or_warn(pathname);
display_progress(progress, i + 1);
}
pathname[len] = 0;

View File

@@ -27,7 +27,7 @@ static int prune_tmp_object(const char *path, const char *filename)
}
printf("Removing stale temporary file %s\n", fullpath);
if (!show_only)
unlink(fullpath);
unlink_or_warn(fullpath);
return 0;
}
@@ -47,7 +47,7 @@ static int prune_object(char *path, const char *filename, const unsigned char *s
(type > 0) ? typename(type) : "unknown");
}
if (!show_only)
unlink(fullpath);
unlink_or_warn(fullpath);
return 0;
}

View File

@@ -27,10 +27,9 @@ static int receive_unpack_limit = -1;
static int transfer_unpack_limit = -1;
static int unpack_limit = 100;
static int report_status;
static int prefer_ofs_delta = 1;
static const char *head_name;
static char capabilities[] = " report-status delete-refs ";
static int capabilities_sent;
static char *capabilities_to_send;
static enum deny_action parse_deny_action(const char *var, const char *value)
{
@@ -84,24 +83,29 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
return 0;
}
if (strcmp(var, "repack.usedeltabaseoffset") == 0) {
prefer_ofs_delta = git_config_bool(var, value);
return 0;
}
return git_default_config(var, value, cb);
}
static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
{
if (capabilities_sent)
if (!capabilities_to_send)
packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
else
packet_write(1, "%s %s%c%s\n",
sha1_to_hex(sha1), path, 0, capabilities);
capabilities_sent = 1;
sha1_to_hex(sha1), path, 0, capabilities_to_send);
capabilities_to_send = NULL;
return 0;
}
static void write_head_info(void)
{
for_each_ref(show_ref, NULL);
if (!capabilities_sent)
if (capabilities_to_send)
show_ref("capabilities^{}", null_sha1, 0, NULL);
}
@@ -687,6 +691,10 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
else if (0 <= receive_unpack_limit)
unpack_limit = receive_unpack_limit;
capabilities_to_send = (prefer_ofs_delta) ?
" report-status delete-refs ofs-delta " :
" report-status delete-refs ";
add_alternate_refs();
write_head_info();
clear_extra_refs();
@@ -702,7 +710,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
unpack_status = unpack();
execute_commands(unpack_status);
if (pack_lockfile)
unlink(pack_lockfile);
unlink_or_warn(pack_lockfile);
if (report_status)
report(unpack_status);
run_receive_hook(post_receive_hook);

View File

@@ -525,8 +525,8 @@ static int migrate_file(struct remote *remote)
path = git_path("remotes/%s", remote->name);
else if (remote->origin == REMOTE_BRANCHES)
path = git_path("branches/%s", remote->name);
if (path && unlink(path))
warning("failed to remove '%s'", path);
if (path)
unlink_or_warn(path);
return 0;
}

View File

@@ -116,7 +116,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
if (!has_rerere_resolution(name))
unlink_rr_item(name);
}
unlink(git_path("rr-cache/MERGE_RR"));
unlink_or_warn(git_path("rr-cache/MERGE_RR"));
} else if (!strcmp(argv[1], "gc"))
garbage_collect(&merge_rr);
else if (!strcmp(argv[1], "status"))

View File

@@ -211,7 +211,7 @@ static inline int exp2i(int n)
*
* and P(2^n + x) < 0.5 means 2^n < 3x
*/
static int estimate_bisect_steps(int all)
int estimate_bisect_steps(int all)
{
int n, x, e;
@@ -225,20 +225,37 @@ static int estimate_bisect_steps(int all)
return (e < 3 * x) ? n : n - 1;
}
static void show_tried_revs(struct commit_list *tried, int stringed)
void print_commit_list(struct commit_list *list,
const char *format_cur,
const char *format_last)
{
for ( ; list; list = list->next) {
const char *format = list->next ? format_cur : format_last;
printf(format, sha1_to_hex(list->item->object.sha1));
}
}
static void show_tried_revs(struct commit_list *tried)
{
printf("bisect_tried='");
for (;tried; tried = tried->next) {
char *format = tried->next ? "%s|" : "%s";
printf(format, sha1_to_hex(tried->item->object.sha1));
}
printf(stringed ? "' &&\n" : "'\n");
print_commit_list(tried, "%s|", "%s");
printf("'\n");
}
static void print_var_str(const char *var, const char *val)
{
printf("%s='%s'\n", var, val);
}
static void print_var_int(const char *var, int val)
{
printf("%s=%d\n", var, val);
}
int show_bisect_vars(struct rev_list_info *info, int reaches, int all)
{
int cnt, flags = info->bisect_show_flags;
char hex[41] = "", *format;
char hex[41] = "";
struct commit_list *tried;
struct rev_info *revs = info->revs;
@@ -269,28 +286,14 @@ int show_bisect_vars(struct rev_list_info *info, int reaches, int all)
}
if (flags & BISECT_SHOW_TRIED)
show_tried_revs(tried, flags & BISECT_SHOW_STRINGED);
format = (flags & BISECT_SHOW_STRINGED) ?
"bisect_rev=%s &&\n"
"bisect_nr=%d &&\n"
"bisect_good=%d &&\n"
"bisect_bad=%d &&\n"
"bisect_all=%d &&\n"
"bisect_steps=%d\n"
:
"bisect_rev=%s\n"
"bisect_nr=%d\n"
"bisect_good=%d\n"
"bisect_bad=%d\n"
"bisect_all=%d\n"
"bisect_steps=%d\n";
printf(format,
hex,
cnt - 1,
all - reaches - 1,
reaches - 1,
all,
estimate_bisect_steps(all));
show_tried_revs(tried);
print_var_str("bisect_rev", hex);
print_var_int("bisect_nr", cnt - 1);
print_var_int("bisect_good", all - reaches - 1);
print_var_int("bisect_bad", reaches - 1);
print_var_int("bisect_all", all);
print_var_int("bisect_steps", estimate_bisect_steps(all));
return 0;
}

View File

@@ -402,6 +402,18 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
return 0;
}
static int cmd_sq_quote(int argc, const char **argv)
{
struct strbuf buf = STRBUF_INIT;
if (argc)
sq_quote_argv(&buf, argv, 0);
printf("%s\n", buf.buf);
strbuf_release(&buf);
return 0;
}
static void die_no_single_rev(int quiet)
{
if (quiet)
@@ -419,6 +431,9 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (argc > 1 && !strcmp("--parseopt", argv[1]))
return cmd_parseopt(argc - 1, argv + 1, prefix);
if (argc > 1 && !strcmp("--sq-quote", argv[1]))
return cmd_sq_quote(argc - 2, argv + 2);
prefix = setup_git_directory();
git_config(git_default_config, NULL);
for (i = 1; i < argc; i++) {

View File

@@ -43,12 +43,16 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
"--stdout",
NULL,
NULL,
NULL,
};
struct child_process po;
int i;
i = 4;
if (args->use_thin_pack)
argv[4] = "--thin";
argv[i++] = "--thin";
if (args->use_ofs_delta)
argv[i++] = "--delta-base-offset";
memset(&po, 0, sizeof(po));
po.argv = argv;
po.in = -1;
@@ -174,9 +178,9 @@ static void print_ref_status(char flag, const char *summary, struct ref *to, str
{
fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
if (from)
fprintf(stderr, "%s -> %s", prettify_ref(from), prettify_ref(to));
fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
else
fputs(prettify_ref(to), stderr);
fputs(prettify_refname(to->name), stderr);
if (msg) {
fputs(" (", stderr);
fputs(msg, stderr);
@@ -315,6 +319,8 @@ int send_pack(struct send_pack_args *args,
ask_for_status_report = 1;
if (server_supports("delete-refs"))
allow_deleting_refs = 1;
if (server_supports("ofs-delta"))
args->use_ofs_delta = 1;
if (!remote_refs) {
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"

View File

@@ -2,12 +2,25 @@
#include "commit.h"
#include "refs.h"
#include "builtin.h"
#include "color.h"
static const char show_branch_usage[] =
"git show-branch [--sparse] [--current] [--all] [--remotes] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...] | --reflog[=n[,b]] <branch>";
static const char show_branch_usage_reflog[] =
"--reflog is incompatible with --all, --remotes, --independent or --merge-base";
static int showbranch_use_color = -1;
static char column_colors[][COLOR_MAXLEN] = {
GIT_COLOR_RED,
GIT_COLOR_GREEN,
GIT_COLOR_YELLOW,
GIT_COLOR_BLUE,
GIT_COLOR_MAGENTA,
GIT_COLOR_CYAN,
};
#define COLUMN_COLORS_MAX (ARRAY_SIZE(column_colors))
static int default_num;
static int default_alloc;
static const char **default_arg;
@@ -19,6 +32,20 @@ static const char **default_arg;
#define DEFAULT_REFLOG 4
static const char *get_color_code(int idx)
{
if (showbranch_use_color)
return column_colors[idx];
return "";
}
static const char *get_color_reset_code(void)
{
if (showbranch_use_color)
return GIT_COLOR_RESET;
return "";
}
static struct commit *interesting(struct commit_list *list)
{
while (list) {
@@ -545,7 +572,12 @@ static int git_show_branch_config(const char *var, const char *value, void *cb)
return 0;
}
return git_default_config(var, value, cb);
if (!strcmp(var, "color.showbranch")) {
showbranch_use_color = git_config_colorbool(var, value, -1);
return 0;
}
return git_color_default_config(var, value, cb);
}
static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
@@ -576,7 +608,7 @@ static void parse_reflog_param(const char *arg, int *cnt, const char **base)
if (*ep == ',')
*base = ep + 1;
else if (*ep)
die("unrecognized reflog param '%s'", arg + 9);
die("unrecognized reflog param '%s'", arg);
else
*base = NULL;
if (*cnt <= 0)
@@ -611,6 +643,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
git_config(git_show_branch_config, NULL);
if (showbranch_use_color == -1)
showbranch_use_color = git_use_color_default;
/* If nothing is specified, try the default first */
if (ac == 1 && default_num) {
ac = default_num + 1;
@@ -658,6 +693,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
parse_reflog_param(arg + 9, &reflog, &reflog_base);
else if (!prefixcmp(arg, "-g="))
parse_reflog_param(arg + 3, &reflog, &reflog_base);
else if (!strcmp(arg, "--color"))
showbranch_use_color = 1;
else if (!strcmp(arg, "--no-color"))
showbranch_use_color = 0;
else
usage(show_branch_usage);
ac--; av++;
@@ -843,8 +882,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
else {
for (j = 0; j < i; j++)
putchar(' ');
printf("%c [%s] ",
is_head ? '*' : '!', ref_name[i]);
printf("%s%c%s [%s] ",
get_color_code(i % COLUMN_COLORS_MAX),
is_head ? '*' : '!',
get_color_reset_code(), ref_name[i]);
}
if (!reflog) {
@@ -903,7 +944,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
mark = '*';
else
mark = '+';
putchar(mark);
printf("%s%c%s",
get_color_code(i % COLUMN_COLORS_MAX),
mark, get_color_reset_code());
}
putchar(' ');
}

View File

@@ -338,7 +338,7 @@ static void create_tag(const unsigned char *object, const char *tag,
exit(128);
}
if (path) {
unlink(path);
unlink_or_warn(path);
free(path);
}
}

View File

@@ -55,7 +55,7 @@ static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
close(gpg.in);
ret = finish_command(&gpg);
unlink(path);
unlink_or_warn(path);
return ret;
}

View File

@@ -98,7 +98,7 @@ int verify_bundle(struct bundle_header *header, int verbose)
*/
struct ref_list *p = &header->prerequisites;
struct rev_info revs;
const char *argv[] = {NULL, "--all"};
const char *argv[] = {NULL, "--all", NULL};
struct object_array refs;
struct commit *commit;
int i, ret = 0, req_nr;

View File

@@ -525,8 +525,8 @@ static const char *parse_interpreter(const char *cmd)
if (buf[0] != '#' || buf[1] != '!')
return NULL;
buf[n] = '\0';
p = strchr(buf, '\n');
if (!p)
p = buf + strcspn(buf, "\r\n");
if (!*p)
return NULL;
*p = '\0';
@@ -1156,3 +1156,18 @@ int link(const char *oldpath, const char *newpath)
}
return 0;
}
char *getpass(const char *prompt)
{
struct strbuf buf = STRBUF_INIT;
fputs(prompt, stderr);
for (;;) {
char c = _getch();
if (c == '\r' || c == '\n')
break;
strbuf_addch(&buf, c);
}
fputs("\n", stderr);
return strbuf_detach(&buf, NULL);
}

View File

@@ -38,6 +38,8 @@ struct passwd {
char *pw_dir;
};
extern char *getpass(const char *prompt);
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
@@ -109,7 +111,7 @@ static inline int mingw_unlink(const char *pathname)
}
#define unlink mingw_unlink
static inline int waitpid(pid_t pid, unsigned *status, unsigned options)
static inline int waitpid(pid_t pid, int *status, unsigned options)
{
if (options == 0)
return _cwait(status, pid, 0);

View File

@@ -99,20 +99,32 @@ __git_ps1 ()
elif [ -d "$g/rebase-merge" ]; then
r="|REBASE-m"
b="$(cat "$g/rebase-merge/head-name")"
elif [ -f "$g/MERGE_HEAD" ]; then
r="|MERGING"
b="$(git symbolic-ref HEAD 2>/dev/null)"
else
if [ -f "$g/MERGE_HEAD" ]; then
r="|MERGING"
fi
if [ -f "$g/BISECT_LOG" ]; then
r="|BISECTING"
fi
if ! b="$(git symbolic-ref HEAD 2>/dev/null)"; then
if ! b="$(git describe --exact-match HEAD 2>/dev/null)"; then
if [ -r "$g/HEAD" ]; then
b="$(cut -c1-7 "$g/HEAD")..."
fi
fi
fi
b="$(git symbolic-ref HEAD 2>/dev/null)" || {
b="$(
case "${GIT_PS1_DESCRIBE_STYLE-}" in
(contains)
git describe --contains HEAD ;;
(branch)
git describe --contains --all HEAD ;;
(describe)
git describe HEAD ;;
(* | default)
git describe --exact-match HEAD ;;
esac 2>/dev/null)" ||
b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
b="unknown"
b="($b)"
}
fi
local w
@@ -120,7 +132,7 @@ __git_ps1 ()
local c
if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
if [ "true" = "$(git config --bool core.bare 2>/dev/null)" ]; then
if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
c="BARE:"
else
b="GIT_DIR!"
@@ -1382,7 +1394,8 @@ _git_config ()
__gitcomp "$(__git_merge_strategies)"
return
;;
color.branch|color.diff|color.interactive|color.status|color.ui)
color.branch|color.diff|color.interactive|\
color.showbranch|color.status|color.ui)
__gitcomp "always never auto"
return
;;
@@ -1531,6 +1544,7 @@ _git_config ()
color.interactive.help
color.interactive.prompt
color.pager
color.showbranch
color.status
color.status.added
color.status.changed
@@ -1825,7 +1839,7 @@ _git_show ()
return
;;
--*)
__gitcomp "--pretty= --format=
__gitcomp "--pretty= --format= --abbrev-commit --oneline
$__git_diff_common_options
"
return
@@ -1842,7 +1856,8 @@ _git_show_branch ()
__gitcomp "
--all --remotes --topo-order --current --more=
--list --independent --merge-base --no-name
--sha1-name --topics --reflog
--color --no-color
--sha1-name --sparse --topics --reflog
"
return
;;

4
contrib/hooks/post-receive-email Normal file → Executable file
View File

@@ -44,6 +44,10 @@
# --pretty %s", displaying the commit id, author, date and log
# message. To list full patches separated by a blank line, you
# could set this to "git show -C %s; echo".
# To list a gitweb/cgit URL *and* a full patch for each change set, use this:
# "t=%s; printf 'http://.../?id=%%s' \$t; echo;echo; git show -C \$t; echo"
# Be careful if "..." contains things that will be expanded by shell "eval"
# or printf.
#
# Notes
# -----

View File

@@ -8,7 +8,9 @@
static unsigned int hash_obj(const struct object *obj, unsigned int n)
{
unsigned int hash = *(unsigned int *)obj->sha1;
unsigned int hash;
memcpy(&hash, obj->sha1, sizeof(unsigned int));
return hash % n;
}
@@ -16,7 +18,7 @@ static void *insert_decoration(struct decoration *n, const struct object *base,
{
int size = n->size;
struct object_decoration *hash = n->hash;
int j = hash_obj(base, size);
unsigned int j = hash_obj(base, size);
while (hash[j].base) {
if (hash[j].base == base) {
@@ -68,7 +70,7 @@ void *add_decoration(struct decoration *n, const struct object *obj,
/* Lookup a decoration pointer */
void *lookup_decoration(struct decoration *n, const struct object *obj)
{
int j;
unsigned int j;
/* nothing to lookup */
if (!n->size)

View File

@@ -214,7 +214,7 @@ static int get_stat_data(struct cache_entry *ce,
const unsigned char *sha1 = ce->sha1;
unsigned int mode = ce->ce_mode;
if (!cached) {
if (!cached && !ce_uptodate(ce)) {
int changed;
struct stat st;
changed = check_removed(ce, &st);

17
diff.c
View File

@@ -189,7 +189,7 @@ static void remove_tempfile(void)
int i;
for (i = 0; i < ARRAY_SIZE(diff_temp); i++) {
if (diff_temp[i].name == diff_temp[i].tmp_path)
unlink(diff_temp[i].name);
unlink_or_warn(diff_temp[i].name);
diff_temp[i].name = NULL;
}
}
@@ -839,10 +839,9 @@ static int scale_linear(int it, int width, int max_change)
}
static void show_name(FILE *file,
const char *prefix, const char *name, int len,
const char *reset, const char *set)
const char *prefix, const char *name, int len)
{
fprintf(file, " %s%s%-*s%s |", set, prefix, len, name, reset);
fprintf(file, " %s%-*s |", prefix, len, name);
}
static void show_graph(FILE *file, char ch, int cnt, const char *set, const char *reset)
@@ -956,7 +955,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
}
if (data->files[i]->is_binary) {
show_name(options->file, prefix, name, len, reset, set);
show_name(options->file, prefix, name, len);
fprintf(options->file, " Bin ");
fprintf(options->file, "%s%d%s", del_c, deleted, reset);
fprintf(options->file, " -> ");
@@ -966,7 +965,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
continue;
}
else if (data->files[i]->is_unmerged) {
show_name(options->file, prefix, name, len, reset, set);
show_name(options->file, prefix, name, len);
fprintf(options->file, " Unmerged\n");
continue;
}
@@ -988,7 +987,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
add = scale_linear(add, width, max_change);
del = scale_linear(del, width, max_change);
}
show_name(options->file, prefix, name, len, reset, set);
show_name(options->file, prefix, name, len);
fprintf(options->file, "%5d%s", added + deleted,
added + deleted ? " " : "");
show_graph(options->file, '+', add, add_c, reset);
@@ -996,8 +995,8 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
fprintf(options->file, "\n");
}
fprintf(options->file,
"%s %d files changed, %d insertions(+), %d deletions(-)%s\n",
set, total_files, adds, dels, reset);
" %d files changed, %d insertions(+), %d deletions(-)\n",
total_files, adds, dels);
}
static void show_shortstats(struct diffstat_t* data, struct diff_options *options)

2
dir.c
View File

@@ -576,7 +576,7 @@ static int get_dtype(struct dirent *de, const char *path)
*/
static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only, const struct path_simplify *simplify)
{
DIR *fdir = opendir(path);
DIR *fdir = opendir(*path ? path : ".");
int contents = 0;
if (fdir) {

View File

@@ -35,7 +35,7 @@ static void create_directories(const char *path, int path_len,
*/
if (mkdir(buf, 0777)) {
if (errno == EEXIST && state->force &&
!unlink(buf) && !mkdir(buf, 0777))
!unlink_or_warn(buf) && !mkdir(buf, 0777))
continue;
die("cannot create directory at %s", buf);
}

View File

@@ -931,7 +931,7 @@ static void unkeep_all_packs(void)
struct packed_git *p = all_packs[k];
snprintf(name, sizeof(name), "%s/pack/pack-%s.keep",
get_object_directory(), sha1_to_hex(p->sha1));
unlink(name);
unlink_or_warn(name);
}
}
@@ -981,7 +981,7 @@ static void end_packfile(void)
}
else {
close(old_p->pack_fd);
unlink(old_p->pack_name);
unlink_or_warn(old_p->pack_name);
}
free(old_p);

View File

@@ -44,11 +44,7 @@ else
fi
sq () {
for sqarg
do
printf "%s" "$sqarg" |
sed -e 's/'\''/'\''\\'\'''\''/g' -e 's/.*/ '\''&'\''/'
done
git rev-parse --sq-quote "$@"
}
stop_here () {

View File

@@ -33,16 +33,6 @@ require_work_tree
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
sq() {
@@PERL@@ -e '
for (@ARGV) {
s/'\''/'\'\\\\\'\''/g;
print " '\''$_'\''";
}
print "\n";
' "$@"
}
bisect_autostart() {
test -s "$GIT_DIR/BISECT_START" || {
echo >&2 'You need to start by "git bisect start"'
@@ -107,7 +97,7 @@ bisect_start() {
for arg; do
case "$arg" in --) has_double_dash=1; break ;; esac
done
orig_args=$(sq "$@")
orig_args=$(git rev-parse --sq-quote "$@")
bad_seen=0
eval=''
while [ $# -gt 0 ]; do
@@ -147,7 +137,7 @@ bisect_start() {
# Write new start state.
#
echo "$start_head" >"$GIT_DIR/BISECT_START" &&
sq "$@" >"$GIT_DIR/BISECT_NAMES" &&
git rev-parse --sq-quote "$@" >"$GIT_DIR/BISECT_NAMES" &&
eval "$eval" &&
echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
#
@@ -177,10 +167,6 @@ is_expected_rev() {
test "$1" = $(cat "$GIT_DIR/BISECT_EXPECTED_REV")
}
mark_expected_rev() {
echo "$1" > "$GIT_DIR/BISECT_EXPECTED_REV"
}
check_expected_revs() {
for _rev in "$@"; do
if ! is_expected_rev "$_rev"; then
@@ -199,7 +185,7 @@ bisect_skip() {
*..*)
revs=$(git rev-list "$arg") || die "Bad rev input: $arg" ;;
*)
revs=$(sq "$arg") ;;
revs=$(git rev-parse --sq-quote "$arg") ;;
esac
all="$all $revs"
done
@@ -279,162 +265,22 @@ bisect_auto_next() {
bisect_next_check && bisect_next || :
}
exit_if_skipped_commits () {
_tried=$1
_bad=$2
if test -n "$_tried" ; then
echo "There are only 'skip'ped commit left to test."
echo "The first bad commit could be any of:"
echo "$_tried" | tr '[|]' '[\012]'
test -n "$_bad" && echo "$_bad"
echo "We cannot bisect more!"
exit 2
fi
}
bisect_checkout() {
_rev="$1"
_msg="$2"
echo "Bisecting: $_msg"
mark_expected_rev "$_rev"
git checkout -q "$_rev" -- || exit
git show-branch "$_rev"
}
is_among() {
_rev="$1"
_list="$2"
case "$_list" in *$_rev*) return 0 ;; esac
return 1
}
handle_bad_merge_base() {
_badmb="$1"
_good="$2"
if is_expected_rev "$_badmb"; then
cat >&2 <<EOF
The merge base $_badmb is bad.
This means the bug has been fixed between $_badmb and [$_good].
EOF
exit 3
else
cat >&2 <<EOF
Some good revs are not ancestor of the bad rev.
git bisect cannot work properly in this case.
Maybe you mistake good and bad revs?
EOF
exit 1
fi
}
handle_skipped_merge_base() {
_mb="$1"
_bad="$2"
_good="$3"
cat >&2 <<EOF
Warning: the merge base between $_bad and [$_good] must be skipped.
So we cannot be sure the first bad commit is between $_mb and $_bad.
We continue anyway.
EOF
}
#
# "check_merge_bases" checks that merge bases are not "bad".
#
# - If one is "good", that's good, we have nothing to do.
# - If one is "bad", it means the user assumed something wrong
# and we must exit.
# - If one is "skipped", we can't know but we should warn.
# - If we don't know, we should check it out and ask the user to test.
#
# In the last case we will return 1, and otherwise 0.
#
check_merge_bases() {
_bad="$1"
_good="$2"
_skip="$3"
for _mb in $(git merge-base --all $_bad $_good)
do
if is_among "$_mb" "$_good"; then
continue
elif test "$_mb" = "$_bad"; then
handle_bad_merge_base "$_bad" "$_good"
elif is_among "$_mb" "$_skip"; then
handle_skipped_merge_base "$_mb" "$_bad" "$_good"
else
bisect_checkout "$_mb" "a merge base must be tested"
return 1
fi
done
return 0
}
#
# "check_good_are_ancestors_of_bad" checks that all "good" revs are
# ancestor of the "bad" rev.
#
# If that's not the case, we need to check the merge bases.
# If a merge base must be tested by the user we return 1 and
# otherwise 0.
#
check_good_are_ancestors_of_bad() {
test -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
return
_bad="$1"
_good=$(echo $2 | sed -e 's/\^//g')
_skip="$3"
# Bisecting with no good rev is ok
test -z "$_good" && return
_side=$(git rev-list $_good ^$_bad)
if test -n "$_side"; then
# Return if a checkout was done
check_merge_bases "$_bad" "$_good" "$_skip" || return
fi
: > "$GIT_DIR/BISECT_ANCESTORS_OK"
return 0
}
bisect_next() {
case "$#" in 0) ;; *) usage ;; esac
bisect_autostart
bisect_next_check good
# Get bad, good and skipped revs
bad=$(git rev-parse --verify refs/bisect/bad) &&
good=$(git for-each-ref --format='^%(objectname)' \
"refs/bisect/good-*" | tr '\012' ' ') &&
skip=$(git for-each-ref --format='%(objectname)' \
"refs/bisect/skip-*" | tr '\012' ' ') || exit
# Perform all bisection computation, display and checkout
git bisect--helper --next-all
res=$?
# Maybe some merge bases must be tested first
check_good_are_ancestors_of_bad "$bad" "$good" "$skip"
# Return now if a checkout has already been done
test "$?" -eq "1" && return
# Check if we should exit because bisection is finished
test $res -eq 10 && exit 0
# Get bisection information
eval=$(eval "git bisect--helper --next-vars") &&
eval "$eval" || exit
# Check for an error in the bisection process
test $res -ne 0 && exit $res
if [ -z "$bisect_rev" ]; then
# We should exit here only if the "bad"
# commit is also a "skip" commit (see above).
exit_if_skipped_commits "$bisect_tried"
echo "$bad was both good and bad"
exit 1
fi
if [ "$bisect_rev" = "$bad" ]; then
exit_if_skipped_commits "$bisect_tried" "$bad"
echo "$bisect_rev is first bad commit"
git diff-tree --pretty $bisect_rev
exit 0
fi
bisect_checkout "$bisect_rev" "$bisect_nr revisions left to test after this (roughly $bisect_steps steps)"
return 0
}
bisect_visualize() {

View File

@@ -415,4 +415,10 @@ void git_qsort(void *base, size_t nmemb, size_t size,
#define fstat_is_reliable() 1
#endif
/*
* Preserves errno, prints a message, but gives no warning for ENOENT.
* Always returns the return value of unlink(2).
*/
int unlink_or_warn(const char *path);
#endif

View File

@@ -228,8 +228,8 @@ run_merge_tool () {
fi
check_unchanged
else
"$merge_tool_path" "$LOCAL" "$REMOTE" \
--default --mode=merge2 --to="$MERGED"
"$merge_tool_path" --default --mode=diff2 \
"$LOCAL" "$REMOTE"
fi
;;
emerge)
@@ -248,7 +248,7 @@ run_merge_tool () {
status=$?
else
"$merge_tool_path" -f emerge-files-command \
"$LOCAL" "$REMOTE" "$(basename "$MERGED")"
"$LOCAL" "$REMOTE"
fi
;;
tortoisemerge)

View File

@@ -210,6 +210,7 @@ my %config_settings = (
"envelopesender" => \$envelope_sender,
"multiedit" => \$multiedit,
"confirm" => \$confirm,
"from" => \$sender,
);
# Handle Uncouth Termination
@@ -409,7 +410,7 @@ my %parse_alias = (
mailrc => sub { my $fh = shift; while (<$fh>) {
if (/^alias\s+(\S+)\s+(.*)$/) {
# spaces delimit multiple addresses
$aliases{$1} = [ split(/\s+/, $2) ];
$aliases{$1} = [ quotewords('\s+', 0, $2) ];
}}},
pine => sub { my $fh = shift; my $f='\t[^\t]*';
for (my $x = ''; defined($x); $x = $_) {

View File

@@ -15,6 +15,7 @@ require_work_tree
command=
branch=
quiet=
reference=
cached=
nofetch=
@@ -91,6 +92,7 @@ module_clone()
{
path=$1
url=$2
reference="$3"
# If there already is a directory at the submodule path,
# expect it to be empty (since that is the default checkout
@@ -106,7 +108,12 @@ module_clone()
test -e "$path" &&
die "A file already exist at path '$path'"
git-clone -n "$url" "$path" ||
if test -n "$reference"
then
git-clone "$reference" -n "$url" "$path"
else
git-clone -n "$url" "$path"
fi ||
die "Clone of '$url' into submodule path '$path' failed"
}
@@ -131,6 +138,15 @@ cmd_add()
-q|--quiet)
quiet=1
;;
--reference)
case "$2" in '') usage ;; esac
reference="--reference=$2"
shift
;;
--reference=*)
reference="$1"
shift
;;
--)
shift
break
@@ -203,7 +219,7 @@ cmd_add()
git config submodule."$path".url "$url"
else
module_clone "$path" "$realrepo" || exit
module_clone "$path" "$realrepo" "$reference" || exit
(
unset GIT_DIR
cd "$path" &&
@@ -314,13 +330,22 @@ cmd_update()
quiet=1
;;
-i|--init)
init=1
shift
cmd_init "$@" || return
;;
-N|--no-fetch)
shift
nofetch=1
;;
--reference)
case "$2" in '') usage ;; esac
reference="--reference=$2"
shift 2
;;
--reference=*)
reference="$1"
shift
;;
--)
shift
break
@@ -334,6 +359,11 @@ cmd_update()
esac
done
if test -n "$init"
then
cmd_init "--" "$@" || return
fi
module_list "$@" |
while read mode sha1 stage path
do
@@ -351,7 +381,7 @@ cmd_update()
if ! test -d "$path"/.git -o -f "$path"/.git
then
module_clone "$path" "$url" || exit
module_clone "$path" "$url" "$reference"|| exit
subsha1=
else
subsha1=$(unset GIT_DIR; cd "$path" &&

View File

@@ -5,7 +5,7 @@ use warnings;
use strict;
use vars qw/ $AUTHOR $VERSION
$sha1 $sha1_short $_revision $_repository
$_q $_authors %users/;
$_q $_authors $_authors_prog %users/;
$AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
$VERSION = '@@GIT_VERSION@@';
@@ -39,6 +39,7 @@ use Digest::MD5;
use IO::File qw//;
use File::Basename qw/dirname basename/;
use File::Path qw/mkpath/;
use File::Spec;
use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
use IPC::Open3;
use Git;
@@ -76,6 +77,7 @@ my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
'ignore-paths=s' => \$SVN::Git::Fetcher::_ignore_regex );
my %fc_opts = ( 'follow-parent|follow!' => \$Git::SVN::_follow_parent,
'authors-file|A=s' => \$_authors,
'authors-prog=s' => \$_authors_prog,
'repack:i' => \$Git::SVN::_repack,
'noMetadata' => \$Git::SVN::_no_metadata,
'useSvmProps' => \$Git::SVN::_use_svm_props,
@@ -263,6 +265,9 @@ usage(0) if $_help;
version() if $_version;
usage(1) unless defined $cmd;
load_authors() if $_authors;
if (defined $_authors_prog) {
$_authors_prog = "'" . File::Spec->rel2abs($_authors_prog) . "'";
}
unless ($cmd =~ /^(?:clone|init|multi-init|commit-diff)$/) {
Git::SVN::Migration::migration_check();
@@ -361,6 +366,7 @@ sub cmd_clone {
$path = basename($url) if !defined $path || !length $path;
cmd_init($url, $path);
Git::SVN::fetch_all($Git::SVN::default_repo_id);
command_oneline('config', 'svn.authorsfile', $_authors) if $_authors;
}
sub cmd_init {
@@ -2663,12 +2669,33 @@ sub other_gs {
$gs
}
sub call_authors_prog {
my ($orig_author) = @_;
my $author = `$::_authors_prog $orig_author`;
if ($? != 0) {
die "$::_authors_prog failed with exit code $?\n"
}
if ($author =~ /^\s*(.+?)\s*<(.*)>\s*$/) {
my ($name, $email) = ($1, $2);
$email = undef if length $2 == 0;
return [$name, $email];
} else {
die "Author: $orig_author: $::_authors_prog returned "
. "invalid author format: $author\n";
}
}
sub check_author {
my ($author) = @_;
if (!defined $author || length $author == 0) {
$author = '(no author)';
} elsif (defined $::_authors && ! defined $::users{$author}) {
die "Author: $author not defined in $::_authors file\n";
}
if (!defined $::users{$author}) {
if (defined $::_authors_prog) {
$::users{$author} = call_authors_prog($author);
} elsif (defined $::_authors) {
die "Author: $author not defined in $::_authors file\n";
}
}
$author;
}
@@ -4438,6 +4465,7 @@ sub gs_fetch_loop_common {
my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc);
my $longest_path = longest_common_path($gsv, $globs);
my $ra_url = $self->{url};
my $find_trailing_edge;
while (1) {
my %revs;
my $err;
@@ -4455,8 +4483,10 @@ sub gs_fetch_loop_common {
sub { $revs{$_[1]} = _cb(@_) });
if ($err) {
print "Checked through r$max\r";
} else {
$find_trailing_edge = 1;
}
if ($err && $max >= $head) {
if ($err and $find_trailing_edge) {
print STDERR "Path '$longest_path' ",
"was probably deleted:\n",
$err->expanded_message,
@@ -4468,13 +4498,14 @@ sub gs_fetch_loop_common {
my $ok;
$self->get_log([$longest_path], $min, $hi,
0, 1, 1, sub {
$ok ||= $_[1];
$ok = $_[1];
$revs{$_[1]} = _cb(@_) });
if ($ok) {
print STDERR "r$min .. r$ok OK\n";
last;
}
}
$find_trailing_edge = 0;
}
$SVN::Error::handler = $err_handler;

View File

@@ -458,8 +458,8 @@ sub filter_snapshot_fmts {
@fmts = map {
exists $known_snapshot_format_aliases{$_} ?
$known_snapshot_format_aliases{$_} : $_} @fmts;
@fmts = grep(exists $known_snapshot_formats{$_}, @fmts);
@fmts = grep {
exists $known_snapshot_formats{$_} } @fmts;
}
our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
@@ -690,9 +690,10 @@ sub evaluate_path_info {
# format key itself, with a prepended dot
while (my ($fmt, $opt) = each %known_snapshot_formats) {
my $hash = $refname;
my $sfx;
$hash =~ s/(\Q$opt->{'suffix'}\E|\Q.$fmt\E)$//;
next unless $sfx = $1;
unless ($hash =~ s/(\Q$opt->{'suffix'}\E|\Q.$fmt\E)$//) {
next;
}
my $sfx = $1;
# a valid suffix was found, so set the snapshot format
# and reset the hash parameter
$input_params{'snapshot_format'} = $fmt;
@@ -828,7 +829,7 @@ if (!defined $action) {
if (!defined($actions{$action})) {
die_error(400, "Unknown action");
}
if ($action !~ m/^(opml|project_list|project_index)$/ &&
if ($action !~ m/^(?:opml|project_list|project_index)$/ &&
!$project) {
die_error(400, "Project needed");
}
@@ -1235,7 +1236,7 @@ sub chop_and_escape_str {
if ($chopped eq $str) {
return esc_html($chopped);
} else {
$str =~ s/([[:cntrl:]])/?/g;
$str =~ s/[[:cntrl:]]/?/g;
return $cgi->span({-title=>$str}, esc_html($chopped));
}
}
@@ -1458,6 +1459,7 @@ sub format_subject_html {
$extra = '' unless defined($extra);
if (length($short) < length($long)) {
$long =~ s/[[:cntrl:]]/?/g;
return $cgi->a({-href => $href, -class => "list subject",
-title => to_utf8($long)},
esc_html($short) . $extra);
@@ -1838,7 +1840,7 @@ sub git_cmd {
# Try to avoid using this function wherever possible.
sub quote_command {
return join(' ',
map( { my $a = $_; $a =~ s/(['!])/'\\$1'/g; "'$a'" } @_ ));
map { my $a = $_; $a =~ s/(['!])/'\\$1'/g; "'$a'" } @_ );
}
# get HEAD ref of given project as hash
@@ -2050,7 +2052,7 @@ sub git_get_project_description {
my $path = shift;
$git_dir = "$projectroot/$path";
open my $fd, "$git_dir/description"
open my $fd, '<', "$git_dir/description"
or return git_get_project_config('description');
my $descr = <$fd>;
close $fd;
@@ -2065,18 +2067,17 @@ sub git_get_project_ctags {
my $ctags = {};
$git_dir = "$projectroot/$path";
unless (opendir D, "$git_dir/ctags") {
return $ctags;
}
foreach (grep { -f $_ } map { "$git_dir/ctags/$_" } readdir(D)) {
open CT, $_ or next;
my $val = <CT>;
opendir my $dh, "$git_dir/ctags"
or return $ctags;
foreach (grep { -f $_ } map { "$git_dir/ctags/$_" } readdir($dh)) {
open my $ct, '<', $_ or next;
my $val = <$ct>;
chomp $val;
close CT;
close $ct;
my $ctag = $_; $ctag =~ s#.*/##;
$ctags->{$ctag} = $val;
}
closedir D;
closedir $dh;
$ctags;
}
@@ -2129,7 +2130,7 @@ sub git_get_project_url_list {
my $path = shift;
$git_dir = "$projectroot/$path";
open my $fd, "$git_dir/cloneurl"
open my $fd, '<', "$git_dir/cloneurl"
or return wantarray ?
@{ config_to_multi(git_get_project_config('url')) } :
config_to_multi(git_get_project_config('url'));
@@ -2187,7 +2188,7 @@ sub git_get_projects_list {
# 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
# 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
my %paths;
open my ($fd), $projects_list or return;
open my $fd, '<', $projects_list or return;
PROJECT:
while (my $line = <$fd>) {
chomp $line;
@@ -2250,7 +2251,7 @@ sub git_get_project_list_from_file {
# 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
# 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
if (-f $projects_list) {
open (my $fd , $projects_list);
open(my $fd, '<', $projects_list);
while (my $line = <$fd>) {
chomp $line;
my ($pr, $ow) = split ' ', $line;
@@ -2804,18 +2805,18 @@ sub mimetype_guess_file {
-r $mimemap or return undef;
my %mimemap;
open(MIME, $mimemap) or return undef;
while (<MIME>) {
open(my $mh, '<', $mimemap) or return undef;
while (<$mh>) {
next if m/^#/; # skip comments
my ($mime, $exts) = split(/\t+/);
my ($mimetype, $exts) = split(/\t+/);
if (defined $exts) {
my @exts = split(/\s+/, $exts);
foreach my $ext (@exts) {
$mimemap{$ext} = $mime;
$mimemap{$ext} = $mimetype;
}
}
}
close(MIME);
close($mh);
$filename =~ /\.([^.]*)$/;
return $mimemap{$1};
@@ -3326,7 +3327,7 @@ sub git_get_link_target {
open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
or return;
{
local $/;
local $/ = undef;
$link_target = <$fd>;
}
close $fd
@@ -3339,10 +3340,7 @@ sub git_get_link_target {
# return target of link relative to top directory (top tree);
# return undef if it is not possible (including absolute links).
sub normalize_link_target {
my ($link_target, $basedir, $hash_base) = @_;
# we can normalize symlink target only if $hash_base is provided
return unless $hash_base;
my ($link_target, $basedir) = @_;
# absolute symlinks (beginning with '/') cannot be normalized
return if (substr($link_target, 0, 1) eq '/');
@@ -3398,7 +3396,7 @@ sub git_print_tree_entry {
if (S_ISLNK(oct $t->{'mode'})) {
my $link_target = git_get_link_target($t->{'hash'});
if ($link_target) {
my $norm_target = normalize_link_target($link_target, $basedir, $hash_base);
my $norm_target = normalize_link_target($link_target, $basedir);
if (defined $norm_target) {
print " -> " .
$cgi->a({-href => href(action=>"object", hash_base=>$hash_base,
@@ -3991,7 +3989,7 @@ sub fill_project_list_info {
($pname !~ /\/$/) &&
(-d "$projectroot/$pname")) {
$pr->{'forks'} = "-d $projectroot/$pname";
} else {
} else {
$pr->{'forks'} = 0;
}
}
@@ -4801,11 +4799,10 @@ sub git_blob_plain {
-content_disposition =>
($sandbox ? 'attachment' : 'inline')
. '; filename="' . $save_as . '"');
undef $/;
local $/ = undef;
binmode STDOUT, ':raw';
print <$fd>;
binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
$/ = "\n";
close $fd;
}
@@ -4907,12 +4904,16 @@ sub git_tree {
}
}
die_error(404, "No such tree") unless defined($hash);
$/ = "\0";
open my $fd, "-|", git_cmd(), "ls-tree", '-z', $hash
or die_error(500, "Open git-ls-tree failed");
my @entries = map { chomp; $_ } <$fd>;
close $fd or die_error(404, "Reading tree failed");
$/ = "\n";
my @entries = ();
{
local $/ = "\0";
open my $fd, "-|", git_cmd(), "ls-tree", '-z', $hash
or die_error(500, "Open git-ls-tree failed");
@entries = map { chomp; $_ } <$fd>;
close $fd
or die_error(404, "Reading tree failed");
}
my $refs = git_get_references();
my $ref = format_ref_marker($refs, $hash_base);
@@ -5807,7 +5808,7 @@ sub git_search {
print "<table class=\"pickaxe search\">\n";
my $alternate = 1;
$/ = "\n";
local $/ = "\n";
open my $fd, '-|', git_cmd(), '--no-pager', 'log', @diff_opts,
'--pretty=format:%H', '--no-abbrev', '--raw', "-S$searchtext",
($search_use_regexp ? '--pickaxe-regex' : ());
@@ -5877,7 +5878,7 @@ sub git_search {
print "<table class=\"grep_search\">\n";
my $alternate = 1;
my $matches = 0;
$/ = "\n";
local $/ = "\n";
open my $fd, "-|", git_cmd(), 'grep', '-n',
$search_use_regexp ? ('-E', '-i') : '-F',
$searchtext, $co{'tree'};
@@ -6280,7 +6281,7 @@ XML
# end of feed
if ($format eq 'rss') {
print "</channel>\n</rss>\n";
} elsif ($format eq 'atom') {
} elsif ($format eq 'atom') {
print "</feed>\n";
}
}

62
graph.c
View File

@@ -47,20 +47,6 @@ static void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb);
* - Limit the number of columns, similar to the way gitk does.
* If we reach more than a specified number of columns, omit
* sections of some columns.
*
* - The output during the GRAPH_PRE_COMMIT and GRAPH_COLLAPSING states
* could be made more compact by printing horizontal lines, instead of
* long diagonal lines. For example, during collapsing, something like
* this: instead of this:
* | | | | | | | | | |
* | |_|_|/ | | | |/
* |/| | | | | |/|
* | | | | | |/| |
* |/| | |
* | | | |
*
* If there are several parallel diagonal lines, they will need to be
* replaced with horizontal lines on subsequent rows.
*/
struct column {
@@ -982,6 +968,9 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
{
int i;
int *tmp_mapping;
short used_horizontal = 0;
int horizontal_edge = -1;
int horizontal_edge_target = -1;
/*
* Clear out the new_mapping array
@@ -1019,6 +1008,23 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
* Move to the left by one
*/
graph->new_mapping[i - 1] = target;
/*
* If there isn't already an edge moving horizontally
* select this one.
*/
if (horizontal_edge == -1) {
int j;
horizontal_edge = i;
horizontal_edge_target = target;
/*
* The variable target is the index of the graph
* column, and therefore target*2+3 is the
* actual screen column of the first horizontal
* line.
*/
for (j = (target * 2)+3; j < (i - 2); j += 2)
graph->new_mapping[j] = target;
}
} else if (graph->new_mapping[i - 1] == target) {
/*
* There is a branch line to our left
@@ -1039,10 +1045,21 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
*
* The space just to the left of this
* branch should always be empty.
*
* The branch to the left of that space
* should be our eventual target.
*/
assert(graph->new_mapping[i - 1] > target);
assert(graph->new_mapping[i - 2] < 0);
assert(graph->new_mapping[i - 3] == target);
graph->new_mapping[i - 2] = target;
/*
* Mark this branch as the horizontal edge to
* prevent any other edges from moving
* horizontally.
*/
if (horizontal_edge == -1)
horizontal_edge = i;
}
}
@@ -1061,8 +1078,23 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf
strbuf_addch(sb, ' ');
else if (target * 2 == i)
strbuf_write_column(sb, &graph->new_columns[target], '|');
else
else if (target == horizontal_edge_target &&
i != horizontal_edge - 1) {
/*
* Set the mappings for all but the
* first segment to -1 so that they
* won't continue into the next line.
*/
if (i != (target * 2)+3)
graph->new_mapping[i] = -1;
used_horizontal = 1;
strbuf_write_column(sb, &graph->new_columns[target], '_');
} else {
if (used_horizontal && i < horizontal_edge)
graph->new_mapping[i] = -1;
strbuf_write_column(sb, &graph->new_columns[target], '/');
}
}
graph_pad_horizontally(graph, sb, graph->mapping_size);

5
grep.c
View File

@@ -305,6 +305,7 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
{
int hit = 0;
int saved_ch = 0;
const char *start = bol;
if ((p->token != GREP_PATTERN) &&
((p->token == GREP_PATTERN_HEAD) != (ctx == GREP_CONTEXT_HEAD)))
@@ -365,6 +366,10 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
}
if (p->token == GREP_PATTERN_HEAD && saved_ch)
*eol = saved_ch;
if (hit) {
pmatch[0].rm_so += bol - start;
pmatch[0].rm_eo += bol - start;
}
return hit;
}

28
grep.h
View File

@@ -61,23 +61,23 @@ struct grep_opt {
struct grep_expr *pattern_expression;
int prefix_length;
regex_t regexp;
unsigned linenum:1;
unsigned invert:1;
unsigned status_only:1;
unsigned name_only:1;
unsigned unmatch_name_only:1;
unsigned count:1;
unsigned word_regexp:1;
unsigned fixed:1;
unsigned all_match:1;
int linenum;
int invert;
int status_only;
int name_only;
int unmatch_name_only;
int count;
int word_regexp;
int fixed;
int all_match;
#define GREP_BINARY_DEFAULT 0
#define GREP_BINARY_NOMATCH 1
#define GREP_BINARY_TEXT 2
unsigned binary:2;
unsigned extended:1;
unsigned relative:1;
unsigned pathname:1;
unsigned null_following_name:1;
int binary;
int extended;
int relative;
int pathname;
int null_following_name;
int color;
char color_match[COLOR_MAXLEN];
const char *color_external;

View File

@@ -315,9 +315,9 @@ static void start_fetch_loose(struct transfer_request *request)
"%s.temp", filename);
snprintf(prevfile, sizeof(prevfile), "%s.prev", request->filename);
unlink(prevfile);
unlink_or_warn(prevfile);
rename(request->tmpfile, prevfile);
unlink(request->tmpfile);
unlink_or_warn(request->tmpfile);
if (request->local_fileno != -1)
error("fd leakage in start: %d", request->local_fileno);
@@ -372,7 +372,7 @@ static void start_fetch_loose(struct transfer_request *request)
} while (prev_read > 0);
close(prevlocal);
}
unlink(prevfile);
unlink_or_warn(prevfile);
/* Reset inflate/SHA1 if there was an error reading the previous temp
file; also rewind to the beginning of the local file. */
@@ -784,7 +784,7 @@ static void finish_request(struct transfer_request *request)
request->http_code != 416) {
if (stat(request->tmpfile, &st) == 0) {
if (st.st_size == 0)
unlink(request->tmpfile);
unlink_or_warn(request->tmpfile);
}
} else {
if (request->http_code == 416)
@@ -793,9 +793,9 @@ static void finish_request(struct transfer_request *request)
git_inflate_end(&request->stream);
git_SHA1_Final(request->real_sha1, &request->c);
if (request->zret != Z_STREAM_END) {
unlink(request->tmpfile);
unlink_or_warn(request->tmpfile);
} else if (hashcmp(request->obj->sha1, request->real_sha1)) {
unlink(request->tmpfile);
unlink_or_warn(request->tmpfile);
} else {
request->rename =
move_temp_to_file(
@@ -1415,8 +1415,9 @@ static void remove_locks(void)
fprintf(stderr, "Removing remote locks...\n");
while (lock) {
struct remote_lock *next = lock->next;
unlock_remote(lock);
lock = lock->next;
lock = next;
}
}
@@ -2326,7 +2327,7 @@ int main(int argc, char **argv)
new_refs = 0;
for (ref = remote_refs; ref; ref = ref->next) {
char old_hex[60], *new_hex;
const char *commit_argv[4];
const char *commit_argv[5];
int commit_argc;
char *new_sha1_hex, *old_sha1_hex;
@@ -2406,6 +2407,7 @@ int main(int argc, char **argv)
commit_argv[3] = old_sha1_hex;
commit_argc++;
}
commit_argv[commit_argc] = NULL;
init_revisions(&revs, setup_git_directory());
setup_revisions(commit_argc, commit_argv, &revs, NULL);
revs.edge_hint = 0; /* just in case */

View File

@@ -111,9 +111,9 @@ static void start_object_request(struct walker *walker,
struct walker_data *data = walker->data;
snprintf(prevfile, sizeof(prevfile), "%s.prev", obj_req->filename);
unlink(prevfile);
unlink_or_warn(prevfile);
rename(obj_req->tmpfile, prevfile);
unlink(obj_req->tmpfile);
unlink_or_warn(obj_req->tmpfile);
if (obj_req->local != -1)
error("fd leakage in start: %d", obj_req->local);
@@ -177,7 +177,7 @@ static void start_object_request(struct walker *walker,
} while (prev_read > 0);
close(prevlocal);
}
unlink(prevfile);
unlink_or_warn(prevfile);
/* Reset inflate/SHA1 if there was an error reading the previous temp
file; also rewind to the beginning of the local file. */
@@ -238,18 +238,18 @@ static void finish_object_request(struct object_request *obj_req)
} else if (obj_req->curl_result != CURLE_OK) {
if (stat(obj_req->tmpfile, &st) == 0)
if (st.st_size == 0)
unlink(obj_req->tmpfile);
unlink_or_warn(obj_req->tmpfile);
return;
}
git_inflate_end(&obj_req->stream);
git_SHA1_Final(obj_req->real_sha1, &obj_req->c);
if (obj_req->zret != Z_STREAM_END) {
unlink(obj_req->tmpfile);
unlink_or_warn(obj_req->tmpfile);
return;
}
if (hashcmp(obj_req->sha1, obj_req->real_sha1)) {
unlink(obj_req->tmpfile);
unlink_or_warn(obj_req->tmpfile);
return;
}
obj_req->rename =
@@ -809,7 +809,7 @@ static void abort_object_request(struct object_request *obj_req)
close(obj_req->local);
obj_req->local = -1;
}
unlink(obj_req->tmpfile);
unlink_or_warn(obj_req->tmpfile);
if (obj_req->slot) {
release_active_slot(obj_req->slot);
obj_req->slot = NULL;

View File

@@ -219,7 +219,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,
close(fd);
bad:
for (i = 0; i < 3; i++)
unlink(temp[i]);
unlink_or_warn(temp[i]);
strbuf_release(&cmd);
return status;
}

View File

@@ -16,7 +16,7 @@ static void remove_lock_file(void)
lock_file_list->filename[0]) {
if (lock_file_list->fd >= 0)
close(lock_file_list->fd);
unlink(lock_file_list->filename);
unlink_or_warn(lock_file_list->filename);
}
lock_file_list = lock_file_list->next;
}
@@ -259,7 +259,7 @@ void rollback_lock_file(struct lock_file *lk)
if (lk->filename[0]) {
if (lk->fd >= 0)
close(lk->fd);
unlink(lk->filename);
unlink_or_warn(lk->filename);
}
lk->filename[0] = 0;
}

View File

@@ -25,6 +25,7 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in
struct object *obj = parse_object(sha1);
if (!obj)
return 0;
refname = prettify_refname(refname);
add_name_decoration("", refname, obj);
while (obj->type == OBJ_TAG) {
obj = ((struct tag *)obj)->tagged;

View File

@@ -933,11 +933,12 @@ static int process_renames(struct merge_options *o,
ren1_src, ren1_dst, branch1,
branch2);
update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst);
update_stages(ren1_dst, NULL,
branch1 == o->branch1 ?
ren1->pair->two : NULL,
branch1 == o->branch1 ?
NULL : ren1->pair->two, 1);
if (!o->call_depth)
update_stages(ren1_dst, NULL,
branch1 == o->branch1 ?
ren1->pair->two : NULL,
branch1 == o->branch1 ?
NULL : ren1->pair->two, 1);
} else if (!sha_eq(dst_other.sha1, null_sha1)) {
const char *new_path;
clean_merge = 0;

View File

@@ -45,13 +45,14 @@ int type_from_string(const char *str)
static unsigned int hash_obj(struct object *obj, unsigned int n)
{
unsigned int hash = *(unsigned int *)obj->sha1;
unsigned int hash;
memcpy(&hash, obj->sha1, sizeof(unsigned int));
return hash % n;
}
static void insert_obj_hash(struct object *obj, struct object **hash, unsigned int size)
{
int j = hash_obj(obj, size);
unsigned int j = hash_obj(obj, size);
while (hash[j]) {
j++;
@@ -61,16 +62,16 @@ static void insert_obj_hash(struct object *obj, struct object **hash, unsigned i
hash[j] = obj;
}
static int hashtable_index(const unsigned char *sha1)
static unsigned int hashtable_index(const unsigned char *sha1)
{
unsigned int i;
memcpy(&i, sha1, sizeof(unsigned int));
return (int)(i % obj_hash_size);
return i % obj_hash_size;
}
struct object *lookup_object(const unsigned char *sha1)
{
int i;
unsigned int i;
struct object *obj;
if (!obj_hash)

View File

@@ -66,7 +66,7 @@ static void prune_ref(struct ref_to_prune *r)
struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1);
if (lock) {
unlink(git_path("%s", r->name));
unlink_or_warn(git_path("%s", r->name));
unlock_ref(lock);
}
}

View File

@@ -50,6 +50,7 @@ static int get_value(struct parse_opt_ctx_t *p,
/* FALLTHROUGH */
case OPTION_BOOLEAN:
case OPTION_BIT:
case OPTION_NEGBIT:
case OPTION_SET_INT:
case OPTION_SET_PTR:
return opterror(opt, "takes no value", flags);
@@ -66,6 +67,13 @@ static int get_value(struct parse_opt_ctx_t *p,
*(int *)opt->value |= opt->defval;
return 0;
case OPTION_NEGBIT:
if (unset)
*(int *)opt->value |= opt->defval;
else
*(int *)opt->value &= ~opt->defval;
return 0;
case OPTION_BOOLEAN:
*(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
return 0;
@@ -121,11 +129,33 @@ static int get_value(struct parse_opt_ctx_t *p,
static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
{
const struct option *numopt = NULL;
for (; options->type != OPTION_END; options++) {
if (options->short_name == *p->opt) {
p->opt = p->opt[1] ? p->opt + 1 : NULL;
return get_value(p, options, OPT_SHORT);
}
/*
* Handle the numerical option later, explicit one-digit
* options take precedence over it.
*/
if (options->type == OPTION_NUMBER)
numopt = options;
}
if (numopt && isdigit(*p->opt)) {
size_t len = 1;
char *arg;
int rc;
while (isdigit(p->opt[len]))
len++;
arg = xmemdupz(p->opt, len);
p->opt = p->opt[len] ? p->opt + len : NULL;
rc = (*numopt->callback)(numopt, arg, 0) ? (-1) : 0;
free(arg);
return rc;
}
return -2;
}
@@ -215,6 +245,25 @@ is_abbreviated:
return -2;
}
static int parse_nodash_opt(struct parse_opt_ctx_t *p, const char *arg,
const struct option *options)
{
for (; options->type != OPTION_END; options++) {
if (!(options->flags & PARSE_OPT_NODASH))
continue;
if ((options->flags & PARSE_OPT_OPTARG) ||
!(options->flags & PARSE_OPT_NOARG))
die("BUG: dashless options don't support arguments");
if (!(options->flags & PARSE_OPT_NONEG))
die("BUG: dashless options don't support negation");
if (options->long_name)
die("BUG: dashless options can't be long");
if (options->short_name == arg[0] && arg[1] == '\0')
return get_value(p, options, OPT_SHORT);
}
return -2;
}
static void check_typos(const char *arg, const struct option *options)
{
if (strlen(arg) < 3)
@@ -265,6 +314,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
const char *arg = ctx->argv[0];
if (*arg != '-' || !arg[1]) {
if (parse_nodash_opt(ctx, arg, options) == 0)
continue;
if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
break;
ctx->out[ctx->cpidx++] = ctx->argv[0];
@@ -397,12 +448,18 @@ int usage_with_options_internal(const char * const *usagestr,
continue;
pos = fprintf(stderr, " ");
if (opts->short_name)
pos += fprintf(stderr, "-%c", opts->short_name);
if (opts->short_name) {
if (opts->flags & PARSE_OPT_NODASH)
pos += fprintf(stderr, "%c", opts->short_name);
else
pos += fprintf(stderr, "-%c", opts->short_name);
}
if (opts->long_name && opts->short_name)
pos += fprintf(stderr, ", ");
if (opts->long_name)
pos += fprintf(stderr, "--%s", opts->long_name);
if (opts->type == OPTION_NUMBER)
pos += fprintf(stderr, "-NUM");
switch (opts->type) {
case OPTION_ARGUMENT:
@@ -439,7 +496,7 @@ int usage_with_options_internal(const char * const *usagestr,
pos += fprintf(stderr, " ...");
}
break;
default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */
default: /* OPTION_{BIT,BOOLEAN,NUMBER,SET_INT,SET_PTR} */
break;
}

View File

@@ -6,8 +6,10 @@ enum parse_opt_type {
OPTION_END,
OPTION_ARGUMENT,
OPTION_GROUP,
OPTION_NUMBER,
/* options with no arguments */
OPTION_BIT,
OPTION_NEGBIT,
OPTION_BOOLEAN, /* _INCR would have been a better name */
OPTION_SET_INT,
OPTION_SET_PTR,
@@ -31,6 +33,7 @@ enum parse_opt_option_flags {
PARSE_OPT_NONEG = 4,
PARSE_OPT_HIDDEN = 8,
PARSE_OPT_LASTARG_DEFAULT = 16,
PARSE_OPT_NODASH = 32,
};
struct option;
@@ -64,8 +67,11 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
* PARSE_OPT_OPTARG: says that the argument is optional (not for BOOLEANs)
* PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs
* PARSE_OPT_NONEG: says that this option cannot be negated
* PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in
* the long one.
* PARSE_OPT_HIDDEN: this option is skipped in the default usage, and
* shown only in the full usage.
* PARSE_OPT_LASTARG_DEFAULT: if no argument is given, the default value
* is used.
* PARSE_OPT_NODASH: this option doesn't start with a dash.
*
* `callback`::
* pointer to the callback to use for OPTION_CALLBACK.
@@ -93,6 +99,7 @@ struct option {
#define OPT_ARGUMENT(l, h) { OPTION_ARGUMENT, 0, (l), NULL, NULL, (h) }
#define OPT_GROUP(h) { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
#define OPT_BIT(s, l, v, h, b) { OPTION_BIT, (s), (l), (v), NULL, (h), 0, NULL, (b) }
#define OPT_NEGBIT(s, l, v, h, b) { OPTION_NEGBIT, (s), (l), (v), NULL, (h), 0, NULL, (b) }
#define OPT_BOOLEAN(s, l, v, h) { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) }
#define OPT_SET_INT(s, l, v, h, i) { OPTION_SET_INT, (s), (l), (v), NULL, (h), 0, NULL, (i) }
#define OPT_SET_PTR(s, l, v, h, p) { OPTION_SET_PTR, (s), (l), (v), NULL, (h), 0, NULL, (p) }
@@ -103,6 +110,9 @@ struct option {
parse_opt_approxidate_cb }
#define OPT_CALLBACK(s, l, v, a, h, f) \
{ OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
#define OPT_NUMBER_CALLBACK(v, h, f) \
{ OPTION_NUMBER, 0, NULL, (v), NULL, (h), \
PARSE_OPT_NOARG | PARSE_OPT_NONEG, (f) }
/* parse_options() will filter out the processed options and leave the
* non-option arguments in argv[].

View File

@@ -185,7 +185,7 @@ sub repository {
if ($dir) {
$dir =~ m#^/# or $dir = $opts{Directory} . '/' . $dir;
$opts{Repository} = $dir;
$opts{Repository} = abs_path($dir);
# If --git-dir went ok, this shouldn't die either.
my $prefix = $search->command_oneline('rev-parse', '--show-prefix');
@@ -1280,6 +1280,8 @@ sub _cmd_exec {
my ($self, @args) = @_;
if ($self) {
$self->repo_path() and $ENV{'GIT_DIR'} = $self->repo_path();
$self->repo_path() and $self->wc_path()
and $ENV{'GIT_WORK_TREE'} = $self->wc_path();
$self->wc_path() and chdir($self->wc_path());
$self->wc_subdir() and chdir($self->wc_subdir());
}

21
refs.c
View File

@@ -682,12 +682,13 @@ int for_each_rawref(each_ref_fn fn, void *cb_data)
* - it has ASCII control character, "~", "^", ":" or SP, anywhere, or
* - it ends with a "/".
* - it ends with ".lock"
* - it contains a "\" (backslash)
*/
static inline int bad_ref_char(int ch)
{
if (((unsigned) ch) <= ' ' ||
ch == '~' || ch == '^' || ch == ':')
ch == '~' || ch == '^' || ch == ':' || ch == '\\')
return 1;
/* 2.13 Pattern Matching Notation */
if (ch == '?' || ch == '[') /* Unsupported */
@@ -750,9 +751,8 @@ int check_ref_format(const char *ref)
}
}
const char *prettify_ref(const struct ref *ref)
const char *prettify_refname(const char *name)
{
const char *name = ref->name;
return name + (
!prefixcmp(name, "refs/heads/") ? 11 :
!prefixcmp(name, "refs/tags/") ? 10 :
@@ -1002,12 +1002,10 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
} else {
path = git_path("%s", refname);
}
err = unlink(path);
if (err && errno != ENOENT) {
err = unlink_or_warn(path);
if (err && errno != ENOENT)
ret = 1;
error("unlink(%s) failed: %s",
path, strerror(errno));
}
if (!(delopt & REF_NODEREF))
lock->lk->filename[i] = '.';
}
@@ -1017,10 +1015,7 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
*/
ret |= repack_without_ref(refname);
err = unlink(git_path("logs/%s", lock->ref_name));
if (err && errno != ENOENT)
warning("unlink(%s) failed: %s",
git_path("logs/%s", lock->ref_name), strerror(errno));
unlink_or_warn(git_path("logs/%s", lock->ref_name));
invalidate_cached_refs();
unlock_ref(lock);
return ret;
@@ -1381,7 +1376,7 @@ int create_symref(const char *ref_target, const char *refs_heads_master,
if (adjust_shared_perm(git_HEAD)) {
error("Unable to fix permissions on %s", lockpath);
error_unlink_return:
unlink(lockpath);
unlink_or_warn(lockpath);
error_free_return:
free(git_HEAD);
return -1;

2
refs.h
View File

@@ -80,7 +80,7 @@ extern int for_each_reflog(each_ref_fn, void *);
#define CHECK_REF_FORMAT_WILDCARD (-3)
extern int check_ref_format(const char *target);
extern const char *prettify_ref(const struct ref *ref);
extern const char *prettify_refname(const char *refname);
extern char *shorten_unambiguous_ref(const char *ref, int strict);
/** rename ref, return 0 on success **/

View File

@@ -1399,13 +1399,13 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
base = branch->merge[0]->dst;
if (!resolve_ref(base, sha1, 1, NULL))
return 0;
theirs = lookup_commit(sha1);
theirs = lookup_commit_reference(sha1);
if (!theirs)
return 0;
if (!resolve_ref(branch->refname, sha1, 1, NULL))
return 0;
ours = lookup_commit(sha1);
ours = lookup_commit_reference(sha1);
if (!ours)
return 0;

View File

@@ -173,7 +173,7 @@ static int handle_file(const char *path,
git_SHA1_Final(sha1, &ctx);
if (hunk != RR_CONTEXT) {
if (output)
unlink(output);
unlink_or_warn(output);
return error("Could not parse conflict hunks in %s", path);
}
if (wrerror)

View File

@@ -6,6 +6,7 @@ struct send_pack_args {
send_mirror:1,
force_update:1,
use_thin_pack:1,
use_ofs_delta:1,
dry_run:1;
};

View File

@@ -246,7 +246,7 @@ int update_server_info(int force)
errs = errs | update_info_packs(force);
/* remove leftover rev-cache file if there is any */
unlink(git_path("info/rev-cache"));
unlink_or_warn(git_path("info/rev-cache"));
return errs;
}

View File

@@ -720,6 +720,8 @@ static int open_packed_git_1(struct packed_git *p)
return error("packfile %s index unavailable", p->pack_name);
p->pack_fd = open(p->pack_name, O_RDONLY);
while (p->pack_fd < 0 && errno == EMFILE && unuse_one_window(p, -1))
p->pack_fd = open(p->pack_name, O_RDONLY);
if (p->pack_fd < 0 || fstat(p->pack_fd, &st))
return -1;
@@ -937,6 +939,8 @@ static void prepare_packed_git_one(char *objdir, int local)
sprintf(path, "%s/pack", objdir);
len = strlen(path);
dir = opendir(path);
while (!dir && errno == EMFILE && unuse_one_window(packed_git, -1))
dir = opendir(path);
if (!dir) {
if (errno != ENOENT)
error("unable to open object pack directory: %s: %s",
@@ -2247,7 +2251,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
goto out;
ret = errno;
}
unlink(tmpfile);
unlink_or_warn(tmpfile);
if (ret) {
if (ret != EEXIST) {
return error("unable to write sha1 filename %s: %s\n", filename, strerror(ret));
@@ -2339,6 +2343,8 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
filename = sha1_file_name(sha1);
fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
while (fd < 0 && errno == EMFILE && unuse_one_window(packed_git, -1))
fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
if (fd < 0) {
if (errno == EACCES)
return error("insufficient permission for adding an object to repository database %s\n", get_object_directory());

View File

@@ -26,6 +26,8 @@ fi
svnrepo=$PWD/svnrepo
export svnrepo
svnconf=$PWD/svnconf
export svnconf
perl -w -e "
use SVN::Core;
@@ -54,6 +56,19 @@ poke() {
test-chmtime +1 "$1"
}
# We need this, because we should pass empty configuration directory to
# the 'svn commit' to avoid automated property changes and other stuff
# that could be set from user's configuration files in ~/.subversion.
svn_cmd () {
[ -d "$svnconf" ] || mkdir "$svnconf"
orig_svncmd="$1"; shift
if [ -z "$orig_svncmd" ]; then
svn
return
fi
svn "$orig_svncmd" --config-dir "$svnconf" "$@"
}
for d in \
"$SVN_HTTPD_PATH" \
/usr/sbin/apache2 \

View File

@@ -12,6 +12,7 @@ usage: test-parse-options <options>
-b, --boolean get a boolean
-4, --or4 bitwise-or boolean with ...0100
--neg-or4 same as --no-or4
-i, --integer <n> get a integer
-j <n> get a integer, too
@@ -29,6 +30,8 @@ String options
Magic arguments
--quux means --quux
-NUM set integer to NUM
+ same as -b
Standard options
--abbrev[=<n>] use <n> digits to display SHA-1s
@@ -245,7 +248,56 @@ test_expect_success 'OPT_BIT() and OPT_SET_INT() work' '
test_cmp expect output
'
# --or4
# --no-or4
test_expect_success 'OPT_NEGBIT() and OPT_SET_INT() work' '
test-parse-options --set23 -bbbbb --neg-or4 > output 2> output.err &&
test ! -s output.err &&
test_cmp expect output
'
cat > expect <<EOF
boolean: 6
integer: 0
timestamp: 0
string: (not set)
abbrev: 7
verbose: 0
quiet: no
dry run: no
EOF
test_expect_success 'OPT_BIT() works' '
test-parse-options -bb --or4 > output 2> output.err &&
test ! -s output.err &&
test_cmp expect output
'
test_expect_success 'OPT_NEGBIT() works' '
test-parse-options -bb --no-neg-or4 > output 2> output.err &&
test ! -s output.err &&
test_cmp expect output
'
test_expect_success 'OPT_BOOLEAN() with PARSE_OPT_NODASH works' '
test-parse-options + + + + + + > output 2> output.err &&
test ! -s output.err &&
test_cmp expect output
'
cat > expect <<EOF
boolean: 0
integer: 12345
timestamp: 0
string: (not set)
abbrev: 7
verbose: 0
quiet: no
dry run: no
EOF
test_expect_success 'OPT_NUMBER_CALLBACK() works' '
test-parse-options -12345 > output 2> output.err &&
test ! -s output.err &&
test_cmp expect output
'
test_done

95
t/t3031-merge-criscross.sh Executable file
View File

@@ -0,0 +1,95 @@
#!/bin/sh
test_description='merge-recursive backend test'
. ./test-lib.sh
# A <- create some files
# / \
# B C <- cause rename/delete conflicts between B and C
# / \
# |\ /|
# | D E |
# | \ / |
# | X |
# | / \ |
# | / \ |
# |/ \|
# F G <- merge E into B, D into C
# \ /
# \ /
# \ /
# H <- recursive merge crashes
#
# initialize
test_expect_success 'setup repo with criss-cross history' '
mkdir data &&
# create a bunch of files
n=1 &&
while test $n -le 10
do
echo $n > data/$n &&
n=$(($n+1)) ||
break
done &&
# check them in
git add data &&
git commit -m A &&
git branch A &&
# a file in one branch
git checkout -b B A &&
git rm data/9 &&
git add data &&
git commit -m B &&
# with a branch off of it
git branch D &&
# put some commits on D
git checkout D &&
echo testD > data/testD &&
git add data &&
git commit -m D &&
# back up to the top, create another branch and cause
# a rename conflict with the file we deleted earlier
git checkout -b C A &&
git mv data/9 data/new-9 &&
git add data &&
git commit -m C &&
# with a branch off of it
git branch E &&
# put a commit on E
git checkout E &&
echo testE > data/testE &&
git add data &&
git commit -m E &&
# now, merge E into B
git checkout B &&
test_must_fail git merge E &&
# force-resolve
git add data &&
git commit -m F &&
git branch F &&
# and merge D into C
git checkout C &&
test_must_fail git merge D &&
# force-resolve
git add data &&
git commit -m G &&
git branch G
'
test_expect_success 'recursive merge between F and G, causes segfault' '
git merge F
'
test_done

View File

@@ -41,9 +41,40 @@ test_expect_success \
git tag topic
'
test_expect_success 'rebase on dirty worktree' '
echo dirty >> A &&
test_must_fail git rebase master'
test_expect_success 'rebase on dirty cache' '
git add A &&
test_must_fail git rebase master'
test_expect_success 'rebase against master' '
git reset --hard HEAD &&
git rebase master'
test_expect_success 'rebase against master twice' '
git rebase master 2>err &&
grep "Current branch my-topic-branch is up to date" err
'
test_expect_success 'rebase against master twice with --force' '
git rebase --force-rebase master >out &&
grep "Current branch my-topic-branch is up to date, rebase forced" out
'
test_expect_success 'rebase against master twice from another branch' '
git checkout my-topic-branch^ &&
git rebase master my-topic-branch 2>err &&
grep "Current branch my-topic-branch is up to date" err
'
test_expect_success 'rebase fast-forward to master' '
git checkout my-topic-branch^ &&
git rebase my-topic-branch 2>err &&
grep "Fast-forwarded HEAD to my-topic-branch" err
'
test_expect_success \
'the rebase operation should not have destroyed author information' \
'! (git log | grep "Author:" | grep "<>")'

121
t/t3702-add-edit.sh Executable file
View File

@@ -0,0 +1,121 @@
#!/bin/sh
#
# Copyright (c) 2007 Johannes E. Schindelin
#
test_description='add -e basic tests'
. ./test-lib.sh
cat > file << EOF
LO, praise of the prowess of people-kings
of spear-armed Danes, in days long sped,
we have heard, and what honor the athelings won!
Oft Scyld the Scefing from squadroned foes,
from many a tribe, the mead-bench tore,
awing the earls. Since erst he lay
friendless, a foundling, fate repaid him:
for he waxed under welkin, in wealth he throve,
till before him the folk, both far and near,
who house by the whale-path, heard his mandate,
gave him gifts: a good king he!
EOF
cat > second-part << EOF
To him an heir was afterward born,
a son in his halls, whom heaven sent
to favor the folk, feeling their woe
that erst they had lacked an earl for leader
so long a while; the Lord endowed him,
the Wielder of Wonder, with world's renown.
EOF
test_expect_success 'setup' '
git add file &&
test_tick &&
git commit -m initial file
'
cat > expected-patch << EOF
diff --git a/file b/file
index b9834b5..9020acb 100644
--- a/file
+++ b/file
@@ -1,11 +1,6 @@
-LO, praise of the prowess of people-kings
-of spear-armed Danes, in days long sped,
-we have heard, and what honor the athelings won!
-Oft Scyld the Scefing from squadroned foes,
-from many a tribe, the mead-bench tore,
-awing the earls. Since erst he lay
-friendless, a foundling, fate repaid him:
-for he waxed under welkin, in wealth he throve,
-till before him the folk, both far and near,
-who house by the whale-path, heard his mandate,
-gave him gifts: a good king he!
+To him an heir was afterward born,
+a son in his halls, whom heaven sent
+to favor the folk, feeling their woe
+that erst they had lacked an earl for leader
+so long a while; the Lord endowed him,
+the Wielder of Wonder, with world's renown.
EOF
cat > patch << EOF
diff --git a/file b/file
index b9834b5..ef6e94c 100644
--- a/file
+++ b/file
@@ -3,1 +3,333 @@ of spear-armed Danes, in days long sped,
we have heard, and what honor the athelings won!
+
Oft Scyld the Scefing from squadroned foes,
@@ -2,7 +1,5 @@ awing the earls. Since erst he lay
friendless, a foundling, fate repaid him:
+
for he waxed under welkin, in wealth he throve,
EOF
cat > expected << EOF
diff --git a/file b/file
index b9834b5..ef6e94c 100644
--- a/file
+++ b/file
@@ -1,10 +1,12 @@
LO, praise of the prowess of people-kings
of spear-armed Danes, in days long sped,
we have heard, and what honor the athelings won!
+
Oft Scyld the Scefing from squadroned foes,
from many a tribe, the mead-bench tore,
awing the earls. Since erst he lay
friendless, a foundling, fate repaid him:
+
for he waxed under welkin, in wealth he throve,
till before him the folk, both far and near,
who house by the whale-path, heard his mandate,
EOF
echo "#!$SHELL_PATH" >fake-editor.sh
cat >> fake-editor.sh <<\EOF
mv -f "$1" orig-patch &&
mv -f patch "$1"
EOF
test_set_editor "$(pwd)/fake-editor.sh"
chmod a+x fake-editor.sh
test_expect_success 'add -e' '
cp second-part file &&
git add -e &&
test_cmp second-part file &&
test_cmp orig-patch expected-patch &&
git diff --cached > out &&
test_cmp out expected
'
test_done

View File

@@ -13,8 +13,8 @@ compare_with () {
'')
test_cmp "$2" current ;;
?*)
iconv -f "$3" -t utf8 >current.utf8 <current &&
iconv -f "$3" -t utf8 >expect.utf8 <"$2" &&
iconv -f "$3" -t UTF-8 >current.utf8 <current &&
iconv -f "$3" -t UTF-8 >expect.utf8 <"$2" &&
test_cmp expect.utf8 current.utf8
;;
esac

View File

@@ -1,12 +1,12 @@
$ git log --decorate --all
commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (refs/heads/master)
commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (master)
Merge: 9a6d494 c7a2ab9
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:04:00 2006 +0000
Merge branch 'side'
commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (refs/heads/side)
commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (side)
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:03:00 2006 +0000
@@ -26,7 +26,7 @@ Date: Mon Jun 26 00:01:00 2006 +0000
This is the second commit.
commit 444ac553ac7612cc88969031b02b3767fb8a353a (refs/heads/initial)
commit 444ac553ac7612cc88969031b02b3767fb8a353a (initial)
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:00:00 2006 +0000

View File

@@ -505,4 +505,15 @@ test_expect_success 'format-patch from a subdirectory (3)' '
test -f "$basename"
'
test_expect_success 'format-patch --in-reply-to' '
git format-patch -1 --stdout --in-reply-to "baz@foo.bar" > patch8 &&
grep "^In-Reply-To: <baz@foo.bar>" patch8 &&
grep "^References: <baz@foo.bar>" patch8
'
test_expect_success 'format-patch --signoff' '
git format-patch -1 --signoff --stdout |
grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
'
test_done

View File

@@ -86,6 +86,13 @@ test_expect_success 'format.numbered && --no-numbered' '
'
test_expect_success 'format.numbered && --keep-subject' '
git format-patch --keep-subject --stdout HEAD^ >patch4a &&
grep "^Subject: Third" patch4a
'
test_expect_success 'format.numbered = auto' '
git config format.numbered auto
@@ -108,4 +115,10 @@ test_expect_success 'format.numbered = auto && --no-numbered' '
'
test_expect_success '--start-number && --numbered' '
git format-patch --start-number 3 --numbered --stdout HEAD~1 > patch8 &&
grep "^Subject: \[PATCH 3/3\]" patch8
'
test_done

View File

@@ -324,14 +324,12 @@ cat > expect <<\EOF
* | | | Merge branch 'side'
|\ \ \ \
| * | | | side-2
| | | |/
| | |/|
| | |_|/
| |/| |
| * | | side-1
* | | | Second
* | | | sixth
| | |/
| |/|
| |_|/
|/| |
* | | fifth
* | | fourth

View File

@@ -74,5 +74,19 @@ test_expect_success 'status' '
grep "have 1 and 1 different" actual
'
test_expect_success 'status when tracking lightweight tags' '
git checkout master &&
git tag light &&
git branch --track lighttrack light >actual &&
grep "set up to track" actual &&
git checkout lighttrack
'
test_expect_success 'status when tracking annotated tags' '
git checkout master &&
git tag -m heavy heavy &&
git branch --track heavytrack heavy >actual &&
grep "set up to track" actual &&
git checkout heavytrack
'
test_done

View File

@@ -534,4 +534,12 @@ test_expect_success 'failing checkout -b should not break working tree' '
'
test_expect_success 'switch out of non-branch' '
git reset --hard master &&
git checkout master^0 &&
echo modified >one &&
test_must_fail git checkout renamer 2>error.log &&
! grep "^Previous HEAD" error.log
'
test_done

81
t/t7406-submodule-reference.sh Executable file
View File

@@ -0,0 +1,81 @@
#!/bin/sh
#
# Copyright (c) 2009, Red Hat Inc, Author: Michael S. Tsirkin (mst@redhat.com)
#
test_description='test clone --reference'
. ./test-lib.sh
base_dir=`pwd`
U=$base_dir/UPLOAD_LOG
test_expect_success 'preparing first repository' \
'test_create_repo A && cd A &&
echo first > file1 &&
git add file1 &&
git commit -m A-initial'
cd "$base_dir"
test_expect_success 'preparing second repository' \
'git clone A B && cd B &&
echo second > file2 &&
git add file2 &&
git commit -m B-addition &&
git repack -a -d &&
git prune'
cd "$base_dir"
test_expect_success 'preparing supermodule' \
'test_create_repo super && cd super &&
echo file > file &&
git add file &&
git commit -m B-super-initial'
cd "$base_dir"
test_expect_success 'submodule add --reference' \
'cd super && git submodule add --reference ../B "file://$base_dir/A" sub &&
git commit -m B-super-added'
cd "$base_dir"
test_expect_success 'after add: existence of info/alternates' \
'test `wc -l <super/sub/.git/objects/info/alternates` = 1'
cd "$base_dir"
test_expect_success 'that reference gets used with add' \
'cd super/sub &&
echo "0 objects, 0 kilobytes" > expected &&
git count-objects > current &&
diff expected current'
cd "$base_dir"
test_expect_success 'cloning supermodule' \
'git clone super super-clone'
cd "$base_dir"
test_expect_success 'update with reference' \
'cd super-clone && git submodule update --init --reference ../B'
cd "$base_dir"
test_expect_success 'after update: existence of info/alternates' \
'test `wc -l <super-clone/sub/.git/objects/info/alternates` = 1'
cd "$base_dir"
test_expect_success 'that reference gets used with update' \
'cd super-clone/sub &&
echo "0 objects, 0 kilobytes" > expected &&
git count-objects > current &&
diff expected current'
cd "$base_dir"
test_done

View File

@@ -31,7 +31,7 @@ test_expect_success \
echo "zzz" > bar/zzz &&
echo "#!/bin/sh" > exec.sh &&
chmod +x exec.sh &&
svn import -m "import for git svn" . "$svnrepo" >/dev/null &&
svn_cmd import -m "import for git svn" . "$svnrepo" >/dev/null &&
cd .. &&
rm -rf import &&
git svn init "$svnrepo"'
@@ -51,7 +51,7 @@ test_expect_success "$name" '
git commit -m "$name" &&
git svn set-tree --find-copies-harder --rmdir \
${remotes_git_svn}..mybranch &&
svn up "$SVN_TREE" &&
svn_cmd up "$SVN_TREE" &&
test -d "$SVN_TREE"/dir && test ! -d "$SVN_TREE"/dir/a'
@@ -118,7 +118,7 @@ test_expect_success "$name" '
git commit -m "$name" &&
git svn set-tree --find-copies-harder --rmdir \
${remotes_git_svn}..mybranch5 &&
svn up "$SVN_TREE" &&
svn_cmd up "$SVN_TREE" &&
test ! -x "$SVN_TREE"/exec.sh'
@@ -129,7 +129,7 @@ test_expect_success "$name" '
git commit -m "$name" &&
git svn set-tree --find-copies-harder --rmdir \
${remotes_git_svn}..mybranch5 &&
svn up "$SVN_TREE" &&
svn_cmd up "$SVN_TREE" &&
test -x "$SVN_TREE"/exec.sh'
@@ -141,7 +141,7 @@ test_expect_success "$name" '
git commit -m "$name" &&
git svn set-tree --find-copies-harder --rmdir \
${remotes_git_svn}..mybranch5 &&
svn up "$SVN_TREE" &&
svn_cmd up "$SVN_TREE" &&
test -L "$SVN_TREE"/exec.sh'
name='new symlink is added to a file that was also just made executable'
@@ -153,7 +153,7 @@ test_expect_success "$name" '
git commit -m "$name" &&
git svn set-tree --find-copies-harder --rmdir \
${remotes_git_svn}..mybranch5 &&
svn up "$SVN_TREE" &&
svn_cmd up "$SVN_TREE" &&
test -x "$SVN_TREE"/bar/zzz &&
test -L "$SVN_TREE"/exec-2.sh'
@@ -166,7 +166,7 @@ test_expect_success "$name" '
git commit -m "$name" &&
git svn set-tree --find-copies-harder --rmdir \
${remotes_git_svn}..mybranch5 &&
svn up "$SVN_TREE" &&
svn_cmd up "$SVN_TREE" &&
test -f "$SVN_TREE"/exec-2.sh &&
test ! -L "$SVN_TREE"/exec-2.sh &&
test_cmp help "$SVN_TREE"/exec-2.sh'

View File

@@ -48,7 +48,7 @@ EOF
printf "\r\n" > empty_crlf
a_empty_crlf=`git hash-object -w empty_crlf`
svn import --no-auto-props -m 'import for git svn' . "$svnrepo" >/dev/null
svn_cmd import --no-auto-props -m 'import for git svn' . "$svnrepo" >/dev/null
cd ..
rm -rf import
@@ -57,13 +57,13 @@ test_expect_success 'setup some commits to svn' \
'cd test_wc &&
echo Greetings >> kw.c &&
poke kw.c &&
svn commit -m "Not yet an Id" &&
svn_cmd commit -m "Not yet an Id" &&
echo Hello world >> kw.c &&
poke kw.c &&
svn commit -m "Modified file, but still not yet an Id" &&
svn propset svn:keywords Id kw.c &&
svn_cmd commit -m "Modified file, but still not yet an Id" &&
svn_cmd propset svn:keywords Id kw.c &&
poke kw.c &&
svn commit -m "Propset Id" &&
svn_cmd commit -m "Propset Id" &&
cd ..'
test_expect_success 'initialize git svn' 'git svn init "$svnrepo"'
@@ -83,16 +83,16 @@ test_expect_success 'raw $Id$ found in kw.c' "test '$expect' = '$got'"
test_expect_success "propset CR on crlf files" \
'cd test_wc &&
svn propset svn:eol-style CR empty &&
svn propset svn:eol-style CR crlf &&
svn propset svn:eol-style CR ne_crlf &&
svn commit -m "propset CR on crlf files" &&
svn_cmd propset svn:eol-style CR empty &&
svn_cmd propset svn:eol-style CR crlf &&
svn_cmd propset svn:eol-style CR ne_crlf &&
svn_cmd commit -m "propset CR on crlf files" &&
cd ..'
test_expect_success 'fetch and pull latest from svn and checkout a new wc' \
'git svn fetch &&
git pull . ${remotes_git_svn} &&
svn co "$svnrepo" new_wc'
svn_cmd co "$svnrepo" new_wc'
for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf
do
@@ -106,11 +106,11 @@ cd test_wc
a_cr=`printf '$Id$\r\nHello\r\nWorld\r\n' | git hash-object --stdin`
a_ne_cr=`printf '$Id$\r\nHello\r\nWorld' | git hash-object --stdin`
test_expect_success 'Set CRLF on cr files' \
'svn propset svn:eol-style CRLF cr &&
svn propset svn:eol-style CRLF ne_cr &&
svn propset svn:keywords Id cr &&
svn propset svn:keywords Id ne_cr &&
svn commit -m "propset CRLF on cr files"'
'svn_cmd propset svn:eol-style CRLF cr &&
svn_cmd propset svn:eol-style CRLF ne_cr &&
svn_cmd propset svn:keywords Id cr &&
svn_cmd propset svn:keywords Id ne_cr &&
svn_cmd commit -m "propset CRLF on cr files"'
cd ..
test_expect_success 'fetch and pull latest from svn' \
'git svn fetch && git pull . ${remotes_git_svn}'
@@ -140,10 +140,10 @@ test_expect_success 'test show-ignore' "
cd test_wc &&
mkdir -p deeply/nested/directory &&
touch deeply/nested/directory/.keep &&
svn add deeply &&
svn up &&
svn propset -R svn:ignore 'no-such-file*' .
svn commit -m 'propset svn:ignore'
svn_cmd add deeply &&
svn_cmd up &&
svn_cmd propset -R svn:ignore 'no-such-file*' .
svn_cmd commit -m 'propset svn:ignore'
cd .. &&
git svn show-ignore > show-ignore.got &&
cmp show-ignore.expect show-ignore.got

View File

@@ -9,7 +9,7 @@ test_expect_success 'initialize repo' '
mkdir -p deeply/nested/directory/number/2 &&
echo foo > deeply/nested/directory/number/1/file &&
echo foo > deeply/nested/directory/number/2/another &&
svn import -m "import for git svn" . "$svnrepo" &&
svn_cmd import -m "import for git svn" . "$svnrepo" &&
cd ..
'
@@ -23,7 +23,7 @@ test_expect_success 'Try a commit on rmdir' '
git rm -f deeply/nested/directory/number/2/another &&
git commit -a -m "remove another" &&
git svn set-tree --rmdir HEAD &&
svn ls -R "$svnrepo" | grep ^deeply/nested/directory/number/1
svn_cmd ls -R "$svnrepo" | grep ^deeply/nested/directory/number/1
'

View File

@@ -10,15 +10,15 @@ test_expect_success 'make history for tracking' '
mkdir import &&
mkdir import/trunk &&
echo hello >> import/trunk/README &&
svn import -m initial import "$svnrepo" &&
svn_cmd import -m initial import "$svnrepo" &&
rm -rf import &&
svn co "$svnrepo"/trunk trunk &&
svn_cmd co "$svnrepo"/trunk trunk &&
echo bye bye >> trunk/README &&
svn rm -m "gone" "$svnrepo"/trunk &&
svn_cmd rm -m "gone" "$svnrepo"/trunk &&
rm -rf trunk &&
mkdir trunk &&
echo "new" > trunk/FOLLOWME &&
svn import -m "new trunk" trunk "$svnrepo"/trunk
svn_cmd import -m "new trunk" trunk "$svnrepo"/trunk
'
test_expect_success 'clone repo with git' '

View File

@@ -11,18 +11,18 @@ test_expect_success 'initialize repo' '
cd import &&
mkdir -p trunk &&
echo hello > trunk/readme &&
svn import -m "initial" . "$svnrepo" &&
svn_cmd import -m "initial" . "$svnrepo" &&
cd .. &&
svn co "$svnrepo" wc &&
svn_cmd co "$svnrepo" wc &&
cd wc &&
echo world >> trunk/readme &&
poke trunk/readme &&
svn commit -m "another commit" &&
svn up &&
svn mv trunk thunk &&
svn_cmd commit -m "another commit" &&
svn_cmd up &&
svn_cmd mv trunk thunk &&
echo goodbye >> thunk/readme &&
poke thunk/readme &&
svn commit -m "bye now" &&
svn_cmd commit -m "bye now" &&
cd ..
'
@@ -51,7 +51,7 @@ test_expect_success 'init and fetch from one svn-remote' '
'
test_expect_success 'follow deleted parent' '
(svn cp -m "resurrecting trunk as junk" \
(svn_cmd cp -m "resurrecting trunk as junk" \
"$svnrepo"/trunk@2 "$svnrepo"/junk ||
svn cp -m "resurrecting trunk as junk" \
-r2 "$svnrepo"/trunk "$svnrepo"/junk) &&
@@ -97,8 +97,8 @@ test_expect_success 'follow higher-level parent' '
'
test_expect_success 'follow deleted directory' '
svn mv -m "bye!" "$svnrepo"/glob/blob/hi "$svnrepo"/glob/blob/bye &&
svn rm -m "remove glob" "$svnrepo"/glob &&
svn_cmd mv -m "bye!" "$svnrepo"/glob/blob/hi "$svnrepo"/glob/blob/bye &&
svn_cmd rm -m "remove glob" "$svnrepo"/glob &&
git svn init --minimize-url -i glob "$svnrepo"/glob &&
git svn fetch -i glob &&
test "`git cat-file blob refs/remotes/glob:blob/bye`" = hi &&
@@ -120,7 +120,7 @@ test_expect_success 'follow-parent avoids deleting relevant info' '
cd import &&
svn import -m "r9270 test" . "$svnrepo"/r9270 &&
cd .. &&
svn co "$svnrepo"/r9270/trunk/subversion/bindings/swig/perl r9270 &&
svn_cmd co "$svnrepo"/r9270/trunk/subversion/bindings/swig/perl r9270 &&
cd r9270 &&
svn mkdir native &&
svn mv t native/t &&
@@ -138,7 +138,7 @@ test_expect_success 'follow-parent avoids deleting relevant info' '
'
test_expect_success "track initial change if it was only made to parent" '
svn cp -m "wheee!" "$svnrepo"/r9270/trunk "$svnrepo"/r9270/drunk &&
svn_cmd cp -m "wheee!" "$svnrepo"/r9270/trunk "$svnrepo"/r9270/drunk &&
git svn init --minimize-url -i r9270-d \
"$svnrepo"/r9270/drunk/subversion/bindings/swig/perl/native/t &&
git svn fetch -i r9270-d &&
@@ -152,20 +152,20 @@ test_expect_success "track initial change if it was only made to parent" '
test_expect_success "follow-parent is atomic" '
(
cd wc &&
svn up &&
svn mkdir stunk &&
svn_cmd up &&
svn_cmd mkdir stunk &&
echo "trunk stunk" > stunk/readme &&
svn add stunk/readme &&
svn ci -m "trunk stunk" &&
svn_cmd add stunk/readme &&
svn_cmd ci -m "trunk stunk" &&
echo "stunk like junk" >> stunk/readme &&
svn ci -m "really stunk" &&
svn_cmd ci -m "really stunk" &&
echo "stink stank stunk" >> stunk/readme &&
svn ci -m "even the grinch agrees"
svn_cmd ci -m "even the grinch agrees"
) &&
svn copy -m "stunk flunked" "$svnrepo"/stunk "$svnrepo"/flunk &&
svn_cmd copy -m "stunk flunked" "$svnrepo"/stunk "$svnrepo"/flunk &&
{ svn cp -m "early stunk flunked too" \
"$svnrepo"/stunk@17 "$svnrepo"/flunked ||
svn cp -m "early stunk flunked too" \
svn_cmd cp -m "early stunk flunked too" \
-r17 "$svnrepo"/stunk "$svnrepo"/flunked; } &&
git svn init --minimize-url -i stunk "$svnrepo"/stunk &&
git svn fetch -i stunk &&
@@ -192,7 +192,7 @@ test_expect_success "follow-parent is atomic" '
'
test_expect_success "track multi-parent paths" '
svn cp -m "resurrect /glob" "$svnrepo"/r9270 "$svnrepo"/glob &&
svn_cmd cp -m "resurrect /glob" "$svnrepo"/r9270 "$svnrepo"/glob &&
git svn multi-fetch &&
test `git cat-file commit refs/remotes/glob | \
grep "^parent " | wc -l` -eq 2

View File

@@ -8,7 +8,7 @@ test_expect_success 'initialize repo' '
mkdir import &&
cd import &&
echo hello > readme &&
svn import -m "initial" . "$svnrepo" &&
svn_cmd import -m "initial" . "$svnrepo" &&
cd .. &&
echo hello > readme &&
git update-index --add readme &&
@@ -27,16 +27,16 @@ prev=`git rev-parse --verify HEAD^1`
test_expect_success 'test the commit-diff command' '
test -n "$prev" && test -n "$head" &&
git svn commit-diff -r1 "$prev" "$head" "$svnrepo" &&
svn co "$svnrepo" wc &&
svn_cmd co "$svnrepo" wc &&
cmp readme wc/readme
'
test_expect_success 'commit-diff to a sub-directory (with git svn config)' '
svn import -m "sub-directory" import "$svnrepo"/subdir &&
svn_cmd import -m "sub-directory" import "$svnrepo"/subdir &&
git svn init --minimize-url "$svnrepo"/subdir &&
git svn fetch &&
git svn commit-diff -r3 "$prev" "$head" &&
svn cat "$svnrepo"/subdir/readme > readme.2 &&
svn_cmd cat "$svnrepo"/subdir/readme > readme.2 &&
cmp readme readme.2
'

View File

@@ -8,18 +8,18 @@ test_expect_success 'initialize repo' '
mkdir import &&
cd import &&
echo initial > file &&
svn import -m "initial" . "$svnrepo" &&
svn_cmd import -m "initial" . "$svnrepo" &&
cd .. &&
echo initial > file &&
git update-index --add file &&
git commit -a -m "initial"
'
test_expect_success 'commit change from svn side' '
svn co "$svnrepo" t.svn &&
svn_cmd co "$svnrepo" t.svn &&
cd t.svn &&
echo second line from svn >> file &&
poke file &&
svn commit -m "second line from svn" &&
svn_cmd commit -m "second line from svn" &&
cd .. &&
rm -rf t.svn
'
@@ -43,11 +43,11 @@ test_expect_success 'dcommit fails to commit because of conflict' '
git svn init "$svnrepo" &&
git svn fetch &&
git reset --hard refs/${remotes_git_svn} &&
svn co "$svnrepo" t.svn &&
svn_cmd co "$svnrepo" t.svn &&
cd t.svn &&
echo fourth line from svn >> file &&
poke file &&
svn commit -m "fourth line from svn" &&
svn_cmd commit -m "fourth line from svn" &&
cd .. &&
rm -rf t.svn &&
echo "fourth line from git" >> file &&
@@ -67,11 +67,11 @@ test_expect_success 'dcommit does the svn equivalent of an index merge' "
"
test_expect_success 'commit another change from svn side' '
svn co "$svnrepo" t.svn &&
svn_cmd co "$svnrepo" t.svn &&
cd t.svn &&
echo third line from svn >> file &&
poke file &&
svn commit -m "third line from svn" &&
svn_cmd commit -m "third line from svn" &&
cd .. &&
rm -rf t.svn
'

View File

@@ -12,7 +12,7 @@ test_expect_success 'setup old-looking metadata' '
mkdir -p $i && \
echo hello >> $i/README || exit 1
done && \
svn import -m test . "$svnrepo"
svn_cmd import -m test . "$svnrepo"
cd .. &&
git svn init "$svnrepo" &&
git svn fetch &&

View File

@@ -14,30 +14,30 @@ test_expect_success 'test refspec globbing' '
mkdir -p trunk/src/a trunk/src/b trunk/doc &&
echo "hello world" > trunk/src/a/readme &&
echo "goodbye world" > trunk/src/b/readme &&
svn import -m "initial" trunk "$svnrepo"/trunk &&
svn co "$svnrepo" tmp &&
svn_cmd import -m "initial" trunk "$svnrepo"/trunk &&
svn_cmd co "$svnrepo" tmp &&
(
cd tmp &&
mkdir branches tags &&
svn add branches tags &&
svn cp trunk branches/start &&
svn commit -m "start a new branch" &&
svn up &&
svn_cmd add branches tags &&
svn_cmd cp trunk branches/start &&
svn_cmd commit -m "start a new branch" &&
svn_cmd up &&
echo "hi" >> branches/start/src/b/readme &&
poke branches/start/src/b/readme &&
echo "hey" >> branches/start/src/a/readme &&
poke branches/start/src/a/readme &&
svn commit -m "hi" &&
svn up &&
svn cp branches/start tags/end &&
svn_cmd commit -m "hi" &&
svn_cmd up &&
svn_cmd cp branches/start tags/end &&
echo "bye" >> tags/end/src/b/readme &&
poke tags/end/src/b/readme &&
echo "aye" >> tags/end/src/a/readme &&
poke tags/end/src/a/readme &&
svn commit -m "the end" &&
svn_cmd commit -m "the end" &&
echo "byebye" >> tags/end/src/b/readme &&
poke tags/end/src/b/readme &&
svn commit -m "nothing to see here"
svn_cmd commit -m "nothing to see here"
) &&
git config --add svn-remote.svn.url "$svnrepo" &&
git config --add svn-remote.svn.fetch \
@@ -72,7 +72,7 @@ test_expect_success 'test left-hand-side only globbing' '
cd tmp &&
echo "try try" >> tags/end/src/b/readme &&
poke tags/end/src/b/readme &&
svn commit -m "try to try"
svn_cmd commit -m "try to try"
) &&
git svn fetch two &&
test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 &&
@@ -102,7 +102,7 @@ test_expect_success 'test disallow multi-globs' '
cd tmp &&
echo "try try" >> tags/end/src/b/readme &&
poke tags/end/src/b/readme &&
svn commit -m "try to try"
svn_cmd commit -m "try to try"
) &&
test_must_fail git svn fetch three 2> stderr.three &&
test_cmp expect.three stderr.three

Some files were not shown because too many files have changed in this diff Show More