mirror of
https://github.com/git/git.git
synced 2026-04-02 04:50:12 +02:00
Merge branch 'master' of git://repo.or.cz/alt-git
This commit is contained in:
@@ -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`,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
--------
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()`.
|
||||
|
||||
6
Makefile
6
Makefile
@@ -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 \
|
||||
|
||||
8
alias.c
8
alias.c
@@ -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
456
bisect.c
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
9
bisect.h
9
bisect.h
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
416
builtin-grep.c
416
builtin-grep.c
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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(' ');
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
2
bundle.c
2
bundle.c
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
4
contrib/hooks/post-receive-email
Normal file → Executable 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
|
||||
# -----
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
17
diff.c
@@ -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
2
dir.c
@@ -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) {
|
||||
|
||||
2
entry.c
2
entry.c
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 () {
|
||||
|
||||
176
git-bisect.sh
176
git-bisect.sh
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 = $_) {
|
||||
|
||||
@@ -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" &&
|
||||
|
||||
41
git-svn.perl
41
git-svn.perl
@@ -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;
|
||||
|
||||
|
||||
@@ -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
62
graph.c
@@ -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
5
grep.c
@@ -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
28
grep.h
@@ -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;
|
||||
|
||||
18
http-push.c
18
http-push.c
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
11
object.c
11
object.c
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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[].
|
||||
|
||||
@@ -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
21
refs.c
@@ -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
2
refs.h
@@ -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 **/
|
||||
|
||||
4
remote.c
4
remote.c
@@ -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;
|
||||
|
||||
|
||||
2
rerere.c
2
rerere.c
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
95
t/t3031-merge-criscross.sh
Executable 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
|
||||
@@ -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
121
t/t3702-add-edit.sh
Executable 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -324,14 +324,12 @@ cat > expect <<\EOF
|
||||
* | | | Merge branch 'side'
|
||||
|\ \ \ \
|
||||
| * | | | side-2
|
||||
| | | |/
|
||||
| | |/|
|
||||
| | |_|/
|
||||
| |/| |
|
||||
| * | | side-1
|
||||
* | | | Second
|
||||
* | | | sixth
|
||||
| | |/
|
||||
| |/|
|
||||
| |_|/
|
||||
|/| |
|
||||
* | | fifth
|
||||
* | | fourth
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
81
t/t7406-submodule-reference.sh
Executable 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
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
'
|
||||
|
||||
|
||||
|
||||
@@ -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' '
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
'
|
||||
|
||||
|
||||
@@ -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
|
||||
'
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user