mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge branch 'master' of git://repo.or.cz/alt-git
This commit is contained in:
@@ -53,6 +53,18 @@ For shell scripts specifically (not exhaustive):
|
||||
- We do not write the noiseword "function" in front of shell
|
||||
functions.
|
||||
|
||||
- As to use of grep, stick to a subset of BRE (namely, no \{m,n\},
|
||||
[::], [==], nor [..]) for portability.
|
||||
|
||||
- We do not use \{m,n\};
|
||||
|
||||
- We do not use -E;
|
||||
|
||||
- We do not use ? nor + (which are \{0,1\} and \{1,\}
|
||||
respectively in BRE) but that goes without saying as these
|
||||
are ERE elements not BRE (note that \? and \+ are not even part
|
||||
of BRE -- making them accessible from BRE is a GNU extension).
|
||||
|
||||
For C programs:
|
||||
|
||||
- We use tabs to indent, and interpret tabs as taking up to
|
||||
|
||||
@@ -4,6 +4,10 @@ GIT v1.5.4.4 Release Notes
|
||||
Fixes since v1.5.4.3
|
||||
--------------------
|
||||
|
||||
* Building and installing with an overtight umask such as 077 made
|
||||
installed templates unreadable by others, while the rest of the install
|
||||
are done in a way that is friendly to umask 022.
|
||||
|
||||
* "git cvsexportcommit -w $cvsdir" misbehaved when GIT_DIR is set to a
|
||||
relative directory.
|
||||
|
||||
@@ -17,10 +21,26 @@ Fixes since v1.5.4.3
|
||||
|
||||
* "git send-email" in 1.5.4.3 issued a bogus empty In-Reply-To: header.
|
||||
|
||||
* "git bisect" showed mysterious "won't bisect on seeked tree" error message.
|
||||
This was leftover from Cogito days to prevent "bisect" starting from a
|
||||
cg-seeked state. We still keep the Cogito safety, but running "git bisect
|
||||
start" when another bisect was in effect will clean up and start over.
|
||||
|
||||
* "git push" with an explicit PATH to receive-pack did not quite work if
|
||||
receive-pack was not on usual PATH. We earlier fixed the same issue
|
||||
with "git fetch" and upload-pack, but somehow forgot to do so in the
|
||||
other direction.
|
||||
|
||||
* git-gui's info dialog was not displayed correctly when the user tries
|
||||
to commit nothing (i.e. without staging anything).
|
||||
|
||||
* "git revert" did not properly fail when attempting to run with a
|
||||
dirty index.
|
||||
|
||||
Also included are a handful documentation updates.
|
||||
|
||||
---
|
||||
exec >/var/tmp/1
|
||||
echo O=$(git describe maint)
|
||||
O=v1.5.4.3
|
||||
O=v1.5.4.3-32-g0f2d447
|
||||
git shortlog --no-merges $O..maint
|
||||
|
||||
@@ -4,6 +4,10 @@ GIT v1.5.5 Release Notes
|
||||
Updates since v1.5.4
|
||||
--------------------
|
||||
|
||||
(subsystems)
|
||||
|
||||
* Comes with git-gui 0.9.3
|
||||
|
||||
(performance)
|
||||
|
||||
* On platforms with suboptimal qsort(3) implementation, there
|
||||
@@ -57,6 +61,8 @@ Updates since v1.5.4
|
||||
|
||||
* "git add -i" behaves better even before you make an initial commit.
|
||||
|
||||
* "git am" refused to run from a subdirectory without a good reason.
|
||||
|
||||
* After "git apply --whitespace=fix" fixes whitespace errors in a patch,
|
||||
a line before the fix can appear as a context or preimage line in a
|
||||
later patch, causing the patch not to apply. The command now knows to
|
||||
@@ -81,6 +87,8 @@ Updates since v1.5.4
|
||||
inspect what is going to be committed and prepare the commit
|
||||
log message template to be edited.
|
||||
|
||||
* "git cvsimport" can now take more than one -M options.
|
||||
|
||||
* "git describe" learned to limit the tags to be used for
|
||||
naming with --match option.
|
||||
|
||||
@@ -89,6 +97,12 @@ Updates since v1.5.4
|
||||
|
||||
* "git describe --exact-match" describes only commits that are tagged.
|
||||
|
||||
* "git describe --long" describes a tagged commit as $tag-0-$sha1,
|
||||
instead of just showing the exact tagname.
|
||||
|
||||
* "git describe" warns when using a tag whose name and path contradict
|
||||
with each other.
|
||||
|
||||
* "git diff" learned "--relative" option to limit and output paths
|
||||
relative to the current directory when working in a subdirectory.
|
||||
|
||||
@@ -98,6 +112,8 @@ Updates since v1.5.4
|
||||
* "git format-patch" learned --cover-letter option to generate a cover
|
||||
letter template.
|
||||
|
||||
* "git gc" learned --quiet option.
|
||||
|
||||
* "git grep" now knows "--name-only" is a synonym for the "-l" option.
|
||||
|
||||
* "git help <alias>" now reports "'git <alias>' is alias to <what>",
|
||||
@@ -144,8 +160,18 @@ Fixes since v1.5.4
|
||||
All of the fixes in v1.5.4 maintenance series are included in
|
||||
this release, unless otherwise noted.
|
||||
|
||||
* "git-daemon" did not send early errors to syslog.
|
||||
|
||||
* "git-http-push" did not allow deletion of remote ref with the usual
|
||||
"push <remote> :<branch>" syntax.
|
||||
|
||||
* "git-log --merge" did not well work with --left-right option.
|
||||
|
||||
* "git-rebase --abort" did not go back to the right location if
|
||||
"git-reset" was run during the "git-rebase" session.
|
||||
|
||||
---
|
||||
exec >/var/tmp/1
|
||||
O=v1.5.4.3-339-g7cf7f54
|
||||
O=v1.5.4.3-428-g6b48990
|
||||
echo O=`git describe refs/heads/master`
|
||||
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
|
||||
|
||||
@@ -939,6 +939,12 @@ imap::
|
||||
The configuration variables in the 'imap' section are described
|
||||
in linkgit:git-imap-send[1].
|
||||
|
||||
receive.fsckObjects::
|
||||
If it is set to true, git-receive-pack will check all received
|
||||
objects. It will abort in the case of a malformed object or a
|
||||
broken link. The result of an abort are only dangling objects.
|
||||
The default value is true.
|
||||
|
||||
receive.unpackLimit::
|
||||
If the number of objects received in a push is below this
|
||||
limit then the objects will be unpacked into loose object
|
||||
|
||||
@@ -102,13 +102,17 @@ If you need to pass multiple options, separate them with a comma.
|
||||
|
||||
-m::
|
||||
Attempt to detect merges based on the commit message. This option
|
||||
will enable default regexes that try to capture the name source
|
||||
will enable default regexes that try to capture the source
|
||||
branch name from the commit message.
|
||||
|
||||
-M <regex>::
|
||||
Attempt to detect merges based on the commit message with a custom
|
||||
regex. It can be used with '-m' to enable the default regexes
|
||||
as well. You must escape forward slashes.
|
||||
+
|
||||
The regex must capture the source branch name in $1.
|
||||
+
|
||||
This option can be used several times to provide several detection regexes.
|
||||
|
||||
-S <regex>::
|
||||
Skip paths matching the regex.
|
||||
|
||||
@@ -56,6 +56,15 @@ OPTIONS
|
||||
being employed to standard error. The tag name will still
|
||||
be printed to standard out.
|
||||
|
||||
--long::
|
||||
Always output the long format (the tag, the number of commits
|
||||
and the abbreviated commit name) even when it matches a tag.
|
||||
This is useful when you want to see parts of the commit object name
|
||||
in "describe" output, even when the commit in question happens to be
|
||||
a tagged version. Instead of just emitting the tag name, it will
|
||||
describe such a commit as v1.2-0-deadbeef (0th commit since tag v1.2
|
||||
that points at object deadbeef....).
|
||||
|
||||
--match <pattern>::
|
||||
Only consider tags matching the given pattern (can be used to avoid
|
||||
leaking private tags made from the repository).
|
||||
|
||||
@@ -78,7 +78,7 @@ OPTIONS
|
||||
-l | --files-with-matches | --name-only | -L | --files-without-match::
|
||||
Instead of showing every matched line, show only the
|
||||
names of files that contain (or do not contain) matches.
|
||||
For better compatability with git-diff, --name-only is a
|
||||
For better compatibility with git-diff, --name-only is a
|
||||
synonym for --files-with-matches.
|
||||
|
||||
-c | --count::
|
||||
|
||||
@@ -75,6 +75,9 @@ OPTIONS
|
||||
to force the version for the generated pack index, and to force
|
||||
64-bit index entries on objects located above the given offset.
|
||||
|
||||
--strict::
|
||||
Die, if the pack contains broken objects or links.
|
||||
|
||||
|
||||
Note
|
||||
----
|
||||
|
||||
@@ -9,6 +9,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-rebase' [-i | --interactive] [-v | --verbose] [-m | --merge]
|
||||
[-s <strategy> | --strategy=<strategy>]
|
||||
[-C<n>] [ --whitespace=<option>] [-p | --preserve-merges]
|
||||
[--onto <newbase>] <upstream> [<branch>]
|
||||
'git-rebase' --continue | --skip | --abort
|
||||
|
||||
@@ -40,6 +40,9 @@ OPTIONS
|
||||
and make the best effort to recover as many objects as
|
||||
possible.
|
||||
|
||||
--strict::
|
||||
Don't write objects with broken content or links.
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
@@ -32,11 +32,11 @@ OUTPUT FORMAT
|
||||
-------------
|
||||
When specifying the -v option the format used is:
|
||||
|
||||
SHA1 type size offset-in-packfile
|
||||
SHA1 type size size-in-pack-file offset-in-packfile
|
||||
|
||||
for objects that are not deltified in the pack, and
|
||||
|
||||
SHA1 type size offset-in-packfile depth base-SHA1
|
||||
SHA1 type size size-in-packfile offset-in-packfile depth base-SHA1
|
||||
|
||||
for objects that are deltified.
|
||||
|
||||
|
||||
@@ -130,9 +130,11 @@ limiting may be applied.
|
||||
|
||||
Show commits older than a specific date.
|
||||
|
||||
ifdef::git-rev-list[]
|
||||
--max-age='timestamp', --min-age='timestamp'::
|
||||
|
||||
Limit the commits output to specified time range.
|
||||
endif::git-rev-list[]
|
||||
|
||||
--author='pattern', --committer='pattern'::
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ Functions
|
||||
|
||||
`finish_async`::
|
||||
|
||||
Wait for the completeion of an asynchronous function that was
|
||||
Wait for the completion of an asynchronous function that was
|
||||
started with start_async().
|
||||
|
||||
|
||||
@@ -121,8 +121,8 @@ string pointers (NULL terminated) in .env:
|
||||
. If the string is of the form "VAR=value", i.e. it contains '='
|
||||
the variable is added to the child process's environment.
|
||||
|
||||
. If the string does not contain '=', it names an environement
|
||||
variable that will be removed from the child process's envionment.
|
||||
. If the string does not contain '=', it names an environment
|
||||
variable that will be removed from the child process's environment.
|
||||
|
||||
To specify a new initial working directory for the sub-process,
|
||||
specify it in the .dir member.
|
||||
|
||||
7
Makefile
7
Makefile
@@ -303,7 +303,8 @@ LIB_H = \
|
||||
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
|
||||
tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
|
||||
utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \
|
||||
mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h
|
||||
mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h fsck.h \
|
||||
pack-revindex.h
|
||||
|
||||
DIFF_OBJS = \
|
||||
diff.o diff-lib.o diffcore-break.o diffcore-order.o \
|
||||
@@ -318,7 +319,7 @@ LIB_OBJS = \
|
||||
patch-ids.o \
|
||||
object.o pack-check.o pack-write.o patch-delta.o path.o pkt-line.o \
|
||||
sideband.o reachable.o reflog-walk.o \
|
||||
quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \
|
||||
quote.o read-cache.o refs.o run-command.o dir.o \
|
||||
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
|
||||
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
|
||||
revision.o pager.o tree-walk.o xdiff-interface.o \
|
||||
@@ -327,7 +328,7 @@ LIB_OBJS = \
|
||||
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
|
||||
convert.o attr.o decorate.o progress.o mailmap.o symlinks.o remote.o \
|
||||
transport.o bundle.o walker.o parse-options.o ws.o archive.o branch.o \
|
||||
alias.o
|
||||
alias.o fsck.o pack-revindex.o
|
||||
|
||||
BUILTIN_OBJS = \
|
||||
builtin-add.o \
|
||||
|
||||
@@ -484,11 +484,6 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
|
||||
return post_checkout_hook(old.commit, new->commit, 1);
|
||||
}
|
||||
|
||||
static int git_checkout_config(const char *var, const char *value)
|
||||
{
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
int cmd_checkout(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct checkout_opts opts;
|
||||
@@ -510,7 +505,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
memset(&new, 0, sizeof(new));
|
||||
|
||||
git_config(git_checkout_config);
|
||||
git_config(git_default_config);
|
||||
|
||||
opts.track = git_branch_track;
|
||||
|
||||
|
||||
@@ -17,12 +17,15 @@ static const char * const describe_usage[] = {
|
||||
static int debug; /* Display lots of verbose info */
|
||||
static int all; /* Default to annotated tags only */
|
||||
static int tags; /* But allow any tags if --tags is specified */
|
||||
static int longformat;
|
||||
static int abbrev = DEFAULT_ABBREV;
|
||||
static int max_candidates = 10;
|
||||
const char *pattern = NULL;
|
||||
|
||||
struct commit_name {
|
||||
struct tag *tag;
|
||||
int prio; /* annotated tag = 2, tag = 1, head = 0 */
|
||||
unsigned char sha1[20];
|
||||
char path[FLEX_ARRAY]; /* more */
|
||||
};
|
||||
static const char *prio_names[] = {
|
||||
@@ -31,14 +34,17 @@ static const char *prio_names[] = {
|
||||
|
||||
static void add_to_known_names(const char *path,
|
||||
struct commit *commit,
|
||||
int prio)
|
||||
int prio,
|
||||
const unsigned char *sha1)
|
||||
{
|
||||
struct commit_name *e = commit->util;
|
||||
if (!e || e->prio < prio) {
|
||||
size_t len = strlen(path)+1;
|
||||
free(e);
|
||||
e = xmalloc(sizeof(struct commit_name) + len);
|
||||
e->tag = NULL;
|
||||
e->prio = prio;
|
||||
hashcpy(e->sha1, sha1);
|
||||
memcpy(e->path, path, len);
|
||||
commit->util = e;
|
||||
}
|
||||
@@ -89,7 +95,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
|
||||
if (!tags && prio < 2)
|
||||
return 0;
|
||||
}
|
||||
add_to_known_names(all ? path + 5 : path + 10, commit, prio);
|
||||
add_to_known_names(all ? path + 5 : path + 10, commit, prio, sha1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -146,6 +152,25 @@ static unsigned long finish_depth_computation(
|
||||
return seen_commits;
|
||||
}
|
||||
|
||||
static void display_name(struct commit_name *n)
|
||||
{
|
||||
if (n->prio == 2 && !n->tag) {
|
||||
n->tag = lookup_tag(n->sha1);
|
||||
if (parse_tag(n->tag) || !n->tag || !n->tag->tag)
|
||||
die("annotated tag %s not available", n->path);
|
||||
if (strcmp(n->tag->tag, n->path))
|
||||
warning("tag '%s' is really '%s' here", n->tag->tag, n->path);
|
||||
}
|
||||
|
||||
if (n->tag)
|
||||
printf("%s", n->tag->tag);
|
||||
else
|
||||
printf("%s", n->path);
|
||||
if (longformat)
|
||||
printf("-0-g%s",
|
||||
find_unique_abbrev(n->tag->tagged->sha1, abbrev));
|
||||
}
|
||||
|
||||
static void describe(const char *arg, int last_one)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
@@ -170,7 +195,8 @@ static void describe(const char *arg, int last_one)
|
||||
|
||||
n = cmit->util;
|
||||
if (n) {
|
||||
printf("%s\n", n->path);
|
||||
display_name(n);
|
||||
printf("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -252,12 +278,12 @@ static void describe(const char *arg, int last_one)
|
||||
sha1_to_hex(gave_up_on->object.sha1));
|
||||
}
|
||||
}
|
||||
if (abbrev == 0)
|
||||
printf("%s\n", all_matches[0].name->path );
|
||||
else
|
||||
printf("%s-%d-g%s\n", all_matches[0].name->path,
|
||||
all_matches[0].depth,
|
||||
|
||||
display_name(all_matches[0].name);
|
||||
if (abbrev)
|
||||
printf("-%d-g%s", all_matches[0].depth,
|
||||
find_unique_abbrev(cmit->object.sha1, abbrev));
|
||||
printf("\n");
|
||||
|
||||
if (!last_one)
|
||||
clear_commit_marks(cmit, -1);
|
||||
@@ -271,6 +297,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
|
||||
OPT_BOOLEAN(0, "debug", &debug, "debug search strategy on stderr"),
|
||||
OPT_BOOLEAN(0, "all", &all, "use any ref in .git/refs"),
|
||||
OPT_BOOLEAN(0, "tags", &tags, "use any tag in .git/refs/tags"),
|
||||
OPT_BOOLEAN(0, "long", &longformat, "always use long format"),
|
||||
OPT__ABBREV(&abbrev),
|
||||
OPT_SET_INT(0, "exact-match", &max_candidates,
|
||||
"only output exact matches", 0),
|
||||
@@ -289,6 +316,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
|
||||
|
||||
save_commit_buffer = 0;
|
||||
|
||||
if (longformat && abbrev == 0)
|
||||
die("--long is incompatible with --abbrev=0");
|
||||
|
||||
if (contains) {
|
||||
const char **args = xmalloc((6 + argc) * sizeof(char*));
|
||||
int i = 0;
|
||||
|
||||
@@ -41,7 +41,8 @@ static void rev_list_push(struct commit *commit, int mark)
|
||||
commit->object.flags |= mark;
|
||||
|
||||
if (!(commit->object.parsed))
|
||||
parse_commit(commit);
|
||||
if (parse_commit(commit))
|
||||
return;
|
||||
|
||||
insert_by_date(commit, &rev_list);
|
||||
|
||||
@@ -83,7 +84,8 @@ static void mark_common(struct commit *commit,
|
||||
if (!ancestors_only && !(o->flags & POPPED))
|
||||
non_common_revs--;
|
||||
if (!o->parsed && !dont_parse)
|
||||
parse_commit(commit);
|
||||
if (parse_commit(commit))
|
||||
return;
|
||||
|
||||
for (parents = commit->parents;
|
||||
parents;
|
||||
@@ -103,20 +105,20 @@ static const unsigned char* get_rev(void)
|
||||
|
||||
while (commit == NULL) {
|
||||
unsigned int mark;
|
||||
struct commit_list* parents;
|
||||
struct commit_list *parents = NULL;
|
||||
|
||||
if (rev_list == NULL || non_common_revs == 0)
|
||||
return NULL;
|
||||
|
||||
commit = rev_list->item;
|
||||
if (!(commit->object.parsed))
|
||||
parse_commit(commit);
|
||||
if (!parse_commit(commit))
|
||||
parents = commit->parents;
|
||||
|
||||
commit->object.flags |= POPPED;
|
||||
if (!(commit->object.flags & COMMON))
|
||||
non_common_revs--;
|
||||
|
||||
parents = commit->parents;
|
||||
|
||||
if (commit->object.flags & COMMON) {
|
||||
/* do not send "have", and ignore ancestors */
|
||||
commit = NULL;
|
||||
@@ -212,7 +214,8 @@ static int find_common(int fd[2], unsigned char *result_sha1,
|
||||
if (!lookup_object(sha1))
|
||||
die("object not found: %s", line);
|
||||
/* make sure that it is parsed as shallow */
|
||||
parse_object(sha1);
|
||||
if (!parse_object(sha1))
|
||||
die("error in object: %s", line);
|
||||
if (unregister_shallow(sha1))
|
||||
die("no shallow found: %s", line);
|
||||
continue;
|
||||
@@ -386,7 +389,6 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
|
||||
int retval;
|
||||
unsigned long cutoff = 0;
|
||||
|
||||
track_object_refs = 0;
|
||||
save_commit_buffer = 0;
|
||||
|
||||
for (ref = *refs; ref; ref = ref->next) {
|
||||
|
||||
349
builtin-fsck.c
349
builtin-fsck.c
@@ -8,6 +8,7 @@
|
||||
#include "pack.h"
|
||||
#include "cache-tree.h"
|
||||
#include "tree-walk.h"
|
||||
#include "fsck.h"
|
||||
#include "parse-options.h"
|
||||
|
||||
#define REACHABLE 0x0001
|
||||
@@ -54,13 +55,75 @@ static int objerror(struct object *obj, const char *err, ...)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int objwarning(struct object *obj, const char *err, ...)
|
||||
static int fsck_error_func(struct object *obj, int type, const char *err, ...)
|
||||
{
|
||||
va_list params;
|
||||
va_start(params, err);
|
||||
objreport(obj, "warning", err, params);
|
||||
objreport(obj, (type == FSCK_WARN) ? "warning" : "error", err, params);
|
||||
va_end(params);
|
||||
return -1;
|
||||
return (type == FSCK_WARN) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int mark_object(struct object *obj, int type, void *data)
|
||||
{
|
||||
struct tree *tree = NULL;
|
||||
struct object *parent = data;
|
||||
int result;
|
||||
|
||||
if (!obj) {
|
||||
printf("broken link from %7s %s\n",
|
||||
typename(parent->type), sha1_to_hex(parent->sha1));
|
||||
printf("broken link from %7s %s\n",
|
||||
(type == OBJ_ANY ? "unknown" : typename(type)), "unknown");
|
||||
errors_found |= ERROR_REACHABLE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (type != OBJ_ANY && obj->type != type)
|
||||
objerror(parent, "wrong object type in link");
|
||||
|
||||
if (obj->flags & REACHABLE)
|
||||
return 0;
|
||||
obj->flags |= REACHABLE;
|
||||
if (!obj->parsed) {
|
||||
if (parent && !has_sha1_file(obj->sha1)) {
|
||||
printf("broken link from %7s %s\n",
|
||||
typename(parent->type), sha1_to_hex(parent->sha1));
|
||||
printf(" to %7s %s\n",
|
||||
typename(obj->type), sha1_to_hex(obj->sha1));
|
||||
errors_found |= ERROR_REACHABLE;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (obj->type == OBJ_TREE) {
|
||||
obj->parsed = 0;
|
||||
tree = (struct tree *)obj;
|
||||
if (parse_tree(tree) < 0)
|
||||
return 1; /* error already displayed */
|
||||
}
|
||||
result = fsck_walk(obj, mark_object, obj);
|
||||
if (tree) {
|
||||
free(tree->buffer);
|
||||
tree->buffer = NULL;
|
||||
}
|
||||
if (result < 0)
|
||||
result = 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void mark_object_reachable(struct object *obj)
|
||||
{
|
||||
mark_object(obj, OBJ_ANY, 0);
|
||||
}
|
||||
|
||||
static int mark_used(struct object *obj, int type, void *data)
|
||||
{
|
||||
if (!obj)
|
||||
return 1;
|
||||
obj->used = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -68,8 +131,6 @@ static int objwarning(struct object *obj, const char *err, ...)
|
||||
*/
|
||||
static void check_reachable_object(struct object *obj)
|
||||
{
|
||||
const struct object_refs *refs;
|
||||
|
||||
/*
|
||||
* We obviously want the object to be parsed,
|
||||
* except if it was in a pack-file and we didn't
|
||||
@@ -82,25 +143,6 @@ static void check_reachable_object(struct object *obj)
|
||||
errors_found |= ERROR_REACHABLE;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that everything that we try to reference is also good.
|
||||
*/
|
||||
refs = lookup_object_refs(obj);
|
||||
if (refs) {
|
||||
unsigned j;
|
||||
for (j = 0; j < refs->count; j++) {
|
||||
struct object *ref = refs->ref[j];
|
||||
if (ref->parsed ||
|
||||
(has_sha1_file(ref->sha1)))
|
||||
continue;
|
||||
printf("broken link from %7s %s\n",
|
||||
typename(obj->type), sha1_to_hex(obj->sha1));
|
||||
printf(" to %7s %s\n",
|
||||
typename(ref->type), sha1_to_hex(ref->sha1));
|
||||
errors_found |= ERROR_REACHABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -204,205 +246,6 @@ static void check_connectivity(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The entries in a tree are ordered in the _path_ order,
|
||||
* which means that a directory entry is ordered by adding
|
||||
* a slash to the end of it.
|
||||
*
|
||||
* So a directory called "a" is ordered _after_ a file
|
||||
* called "a.c", because "a/" sorts after "a.c".
|
||||
*/
|
||||
#define TREE_UNORDERED (-1)
|
||||
#define TREE_HAS_DUPS (-2)
|
||||
|
||||
static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2)
|
||||
{
|
||||
int len1 = strlen(name1);
|
||||
int len2 = strlen(name2);
|
||||
int len = len1 < len2 ? len1 : len2;
|
||||
unsigned char c1, c2;
|
||||
int cmp;
|
||||
|
||||
cmp = memcmp(name1, name2, len);
|
||||
if (cmp < 0)
|
||||
return 0;
|
||||
if (cmp > 0)
|
||||
return TREE_UNORDERED;
|
||||
|
||||
/*
|
||||
* Ok, the first <len> characters are the same.
|
||||
* Now we need to order the next one, but turn
|
||||
* a '\0' into a '/' for a directory entry.
|
||||
*/
|
||||
c1 = name1[len];
|
||||
c2 = name2[len];
|
||||
if (!c1 && !c2)
|
||||
/*
|
||||
* git-write-tree used to write out a nonsense tree that has
|
||||
* entries with the same name, one blob and one tree. Make
|
||||
* sure we do not have duplicate entries.
|
||||
*/
|
||||
return TREE_HAS_DUPS;
|
||||
if (!c1 && S_ISDIR(mode1))
|
||||
c1 = '/';
|
||||
if (!c2 && S_ISDIR(mode2))
|
||||
c2 = '/';
|
||||
return c1 < c2 ? 0 : TREE_UNORDERED;
|
||||
}
|
||||
|
||||
static int fsck_tree(struct tree *item)
|
||||
{
|
||||
int retval;
|
||||
int has_full_path = 0;
|
||||
int has_empty_name = 0;
|
||||
int has_zero_pad = 0;
|
||||
int has_bad_modes = 0;
|
||||
int has_dup_entries = 0;
|
||||
int not_properly_sorted = 0;
|
||||
struct tree_desc desc;
|
||||
unsigned o_mode;
|
||||
const char *o_name;
|
||||
const unsigned char *o_sha1;
|
||||
|
||||
if (verbose)
|
||||
fprintf(stderr, "Checking tree %s\n",
|
||||
sha1_to_hex(item->object.sha1));
|
||||
|
||||
init_tree_desc(&desc, item->buffer, item->size);
|
||||
|
||||
o_mode = 0;
|
||||
o_name = NULL;
|
||||
o_sha1 = NULL;
|
||||
while (desc.size) {
|
||||
unsigned mode;
|
||||
const char *name;
|
||||
const unsigned char *sha1;
|
||||
|
||||
sha1 = tree_entry_extract(&desc, &name, &mode);
|
||||
|
||||
if (strchr(name, '/'))
|
||||
has_full_path = 1;
|
||||
if (!*name)
|
||||
has_empty_name = 1;
|
||||
has_zero_pad |= *(char *)desc.buffer == '0';
|
||||
update_tree_entry(&desc);
|
||||
|
||||
switch (mode) {
|
||||
/*
|
||||
* Standard modes..
|
||||
*/
|
||||
case S_IFREG | 0755:
|
||||
case S_IFREG | 0644:
|
||||
case S_IFLNK:
|
||||
case S_IFDIR:
|
||||
case S_IFGITLINK:
|
||||
break;
|
||||
/*
|
||||
* This is nonstandard, but we had a few of these
|
||||
* early on when we honored the full set of mode
|
||||
* bits..
|
||||
*/
|
||||
case S_IFREG | 0664:
|
||||
if (!check_strict)
|
||||
break;
|
||||
default:
|
||||
has_bad_modes = 1;
|
||||
}
|
||||
|
||||
if (o_name) {
|
||||
switch (verify_ordered(o_mode, o_name, mode, name)) {
|
||||
case TREE_UNORDERED:
|
||||
not_properly_sorted = 1;
|
||||
break;
|
||||
case TREE_HAS_DUPS:
|
||||
has_dup_entries = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
o_mode = mode;
|
||||
o_name = name;
|
||||
o_sha1 = sha1;
|
||||
}
|
||||
free(item->buffer);
|
||||
item->buffer = NULL;
|
||||
|
||||
retval = 0;
|
||||
if (has_full_path) {
|
||||
objwarning(&item->object, "contains full pathnames");
|
||||
}
|
||||
if (has_empty_name) {
|
||||
objwarning(&item->object, "contains empty pathname");
|
||||
}
|
||||
if (has_zero_pad) {
|
||||
objwarning(&item->object, "contains zero-padded file modes");
|
||||
}
|
||||
if (has_bad_modes) {
|
||||
objwarning(&item->object, "contains bad file modes");
|
||||
}
|
||||
if (has_dup_entries) {
|
||||
retval = objerror(&item->object, "contains duplicate file entries");
|
||||
}
|
||||
if (not_properly_sorted) {
|
||||
retval = objerror(&item->object, "not properly sorted");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int fsck_commit(struct commit *commit)
|
||||
{
|
||||
char *buffer = commit->buffer;
|
||||
unsigned char tree_sha1[20], sha1[20];
|
||||
|
||||
if (verbose)
|
||||
fprintf(stderr, "Checking commit %s\n",
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
|
||||
if (!commit->date)
|
||||
return objerror(&commit->object, "invalid author/committer line");
|
||||
|
||||
if (memcmp(buffer, "tree ", 5))
|
||||
return objerror(&commit->object, "invalid format - expected 'tree' line");
|
||||
if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n')
|
||||
return objerror(&commit->object, "invalid 'tree' line format - bad sha1");
|
||||
buffer += 46;
|
||||
while (!memcmp(buffer, "parent ", 7)) {
|
||||
if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n')
|
||||
return objerror(&commit->object, "invalid 'parent' line format - bad sha1");
|
||||
buffer += 48;
|
||||
}
|
||||
if (memcmp(buffer, "author ", 7))
|
||||
return objerror(&commit->object, "invalid format - expected 'author' line");
|
||||
free(commit->buffer);
|
||||
commit->buffer = NULL;
|
||||
if (!commit->tree)
|
||||
return objerror(&commit->object, "could not load commit's tree %s", tree_sha1);
|
||||
if (!commit->parents && show_root)
|
||||
printf("root %s\n", sha1_to_hex(commit->object.sha1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsck_tag(struct tag *tag)
|
||||
{
|
||||
struct object *tagged = tag->tagged;
|
||||
|
||||
if (verbose)
|
||||
fprintf(stderr, "Checking tag %s\n",
|
||||
sha1_to_hex(tag->object.sha1));
|
||||
|
||||
if (!tagged) {
|
||||
return objerror(&tag->object, "could not load tagged object");
|
||||
}
|
||||
if (!show_tags)
|
||||
return 0;
|
||||
|
||||
printf("tagged %s %s", typename(tagged->type), sha1_to_hex(tagged->sha1));
|
||||
printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsck_sha1(const unsigned char *sha1)
|
||||
{
|
||||
struct object *obj = parse_object(sha1);
|
||||
@@ -414,18 +257,43 @@ static int fsck_sha1(const unsigned char *sha1)
|
||||
if (obj->flags & SEEN)
|
||||
return 0;
|
||||
obj->flags |= SEEN;
|
||||
if (obj->type == OBJ_BLOB)
|
||||
return 0;
|
||||
if (obj->type == OBJ_TREE)
|
||||
return fsck_tree((struct tree *) obj);
|
||||
if (obj->type == OBJ_COMMIT)
|
||||
return fsck_commit((struct commit *) obj);
|
||||
if (obj->type == OBJ_TAG)
|
||||
return fsck_tag((struct tag *) obj);
|
||||
|
||||
/* By now, parse_object() would've returned NULL instead. */
|
||||
return objerror(obj, "unknown type '%d' (internal fsck error)",
|
||||
obj->type);
|
||||
if (verbose)
|
||||
fprintf(stderr, "Checking %s %s\n",
|
||||
typename(obj->type), sha1_to_hex(obj->sha1));
|
||||
|
||||
if (fsck_walk(obj, mark_used, 0))
|
||||
objerror(obj, "broken links");
|
||||
if (fsck_object(obj, check_strict, fsck_error_func))
|
||||
return -1;
|
||||
|
||||
if (obj->type == OBJ_TREE) {
|
||||
struct tree *item = (struct tree *) obj;
|
||||
|
||||
free(item->buffer);
|
||||
item->buffer = NULL;
|
||||
}
|
||||
|
||||
if (obj->type == OBJ_COMMIT) {
|
||||
struct commit *commit = (struct commit *) obj;
|
||||
|
||||
free(commit->buffer);
|
||||
commit->buffer = NULL;
|
||||
|
||||
if (!commit->parents && show_root)
|
||||
printf("root %s\n", sha1_to_hex(commit->object.sha1));
|
||||
}
|
||||
|
||||
if (obj->type == OBJ_TAG) {
|
||||
struct tag *tag = (struct tag *) obj;
|
||||
|
||||
if (show_tags && tag->tagged) {
|
||||
printf("tagged %s %s", typename(tag->tagged->type), sha1_to_hex(tag->tagged->sha1));
|
||||
printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -538,13 +406,13 @@ static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
|
||||
obj = lookup_object(osha1);
|
||||
if (obj) {
|
||||
obj->used = 1;
|
||||
mark_reachable(obj, REACHABLE);
|
||||
mark_object_reachable(obj);
|
||||
}
|
||||
}
|
||||
obj = lookup_object(nsha1);
|
||||
if (obj) {
|
||||
obj->used = 1;
|
||||
mark_reachable(obj, REACHABLE);
|
||||
mark_object_reachable(obj);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -574,7 +442,7 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int f
|
||||
error("%s: not a commit", refname);
|
||||
default_refs++;
|
||||
obj->used = 1;
|
||||
mark_reachable(obj, REACHABLE);
|
||||
mark_object_reachable(obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -660,7 +528,7 @@ static int fsck_cache_tree(struct cache_tree *it)
|
||||
sha1_to_hex(it->sha1));
|
||||
return 1;
|
||||
}
|
||||
mark_reachable(obj, REACHABLE);
|
||||
mark_object_reachable(obj);
|
||||
obj->used = 1;
|
||||
if (obj->type != OBJ_TREE)
|
||||
err |= objerror(obj, "non-tree in cache-tree");
|
||||
@@ -693,7 +561,6 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, heads;
|
||||
|
||||
track_object_refs = 1;
|
||||
errors_found = 0;
|
||||
|
||||
argc = parse_options(argc, argv, fsck_opts, fsck_usage, 0);
|
||||
@@ -741,7 +608,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
||||
continue;
|
||||
|
||||
obj->used = 1;
|
||||
mark_reachable(obj, REACHABLE);
|
||||
mark_object_reachable(obj);
|
||||
heads++;
|
||||
continue;
|
||||
}
|
||||
@@ -773,7 +640,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
|
||||
continue;
|
||||
obj = &blob->object;
|
||||
obj->used = 1;
|
||||
mark_reachable(obj, REACHABLE);
|
||||
mark_object_reachable(obj);
|
||||
}
|
||||
if (active_cache_tree)
|
||||
fsck_cache_tree(active_cache_tree);
|
||||
|
||||
@@ -59,7 +59,7 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix)
|
||||
url = rewritten_url;
|
||||
}
|
||||
|
||||
walker = get_http_walker(url);
|
||||
walker = get_http_walker(url, NULL);
|
||||
walker->get_tree = get_tree;
|
||||
walker->get_history = get_history;
|
||||
walker->get_all = get_all;
|
||||
|
||||
@@ -683,6 +683,10 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
|
||||
strbuf_release(&sb);
|
||||
|
||||
shortlog_init(&log);
|
||||
log.wrap_lines = 1;
|
||||
log.wrap = 72;
|
||||
log.in1 = 2;
|
||||
log.in2 = 4;
|
||||
for (i = 0; i < nr; i++)
|
||||
shortlog_add_commit(&log, list[i]);
|
||||
|
||||
@@ -694,8 +698,8 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
|
||||
if (!origin)
|
||||
return;
|
||||
|
||||
diff_setup(&opts);
|
||||
opts.output_format |= DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
|
||||
memcpy(&opts, &rev->diffopt, sizeof(opts));
|
||||
opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
|
||||
|
||||
diff_setup_done(&opts);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "tree.h"
|
||||
#include "delta.h"
|
||||
#include "pack.h"
|
||||
#include "pack-revindex.h"
|
||||
#include "csum-file.h"
|
||||
#include "tree-walk.h"
|
||||
#include "diff.h"
|
||||
@@ -92,158 +93,12 @@ static unsigned long window_memory_limit = 0;
|
||||
static int *object_ix;
|
||||
static int object_ix_hashsz;
|
||||
|
||||
/*
|
||||
* Pack index for existing packs give us easy access to the offsets into
|
||||
* corresponding pack file where each object's data starts, but the entries
|
||||
* do not store the size of the compressed representation (uncompressed
|
||||
* size is easily available by examining the pack entry header). It is
|
||||
* also rather expensive to find the sha1 for an object given its offset.
|
||||
*
|
||||
* We build a hashtable of existing packs (pack_revindex), and keep reverse
|
||||
* index here -- pack index file is sorted by object name mapping to offset;
|
||||
* this pack_revindex[].revindex array is a list of offset/index_nr pairs
|
||||
* ordered by offset, so if you know the offset of an object, next offset
|
||||
* is where its packed representation ends and the index_nr can be used to
|
||||
* get the object sha1 from the main index.
|
||||
*/
|
||||
struct revindex_entry {
|
||||
off_t offset;
|
||||
unsigned int nr;
|
||||
};
|
||||
struct pack_revindex {
|
||||
struct packed_git *p;
|
||||
struct revindex_entry *revindex;
|
||||
};
|
||||
static struct pack_revindex *pack_revindex;
|
||||
static int pack_revindex_hashsz;
|
||||
|
||||
/*
|
||||
* stats
|
||||
*/
|
||||
static uint32_t written, written_delta;
|
||||
static uint32_t reused, reused_delta;
|
||||
|
||||
static int pack_revindex_ix(struct packed_git *p)
|
||||
{
|
||||
unsigned long ui = (unsigned long)p;
|
||||
int i;
|
||||
|
||||
ui = ui ^ (ui >> 16); /* defeat structure alignment */
|
||||
i = (int)(ui % pack_revindex_hashsz);
|
||||
while (pack_revindex[i].p) {
|
||||
if (pack_revindex[i].p == p)
|
||||
return i;
|
||||
if (++i == pack_revindex_hashsz)
|
||||
i = 0;
|
||||
}
|
||||
return -1 - i;
|
||||
}
|
||||
|
||||
static void prepare_pack_ix(void)
|
||||
{
|
||||
int num;
|
||||
struct packed_git *p;
|
||||
for (num = 0, p = packed_git; p; p = p->next)
|
||||
num++;
|
||||
if (!num)
|
||||
return;
|
||||
pack_revindex_hashsz = num * 11;
|
||||
pack_revindex = xcalloc(sizeof(*pack_revindex), pack_revindex_hashsz);
|
||||
for (p = packed_git; p; p = p->next) {
|
||||
num = pack_revindex_ix(p);
|
||||
num = - 1 - num;
|
||||
pack_revindex[num].p = p;
|
||||
}
|
||||
/* revindex elements are lazily initialized */
|
||||
}
|
||||
|
||||
static int cmp_offset(const void *a_, const void *b_)
|
||||
{
|
||||
const struct revindex_entry *a = a_;
|
||||
const struct revindex_entry *b = b_;
|
||||
return (a->offset < b->offset) ? -1 : (a->offset > b->offset) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ordered list of offsets of objects in the pack.
|
||||
*/
|
||||
static void prepare_pack_revindex(struct pack_revindex *rix)
|
||||
{
|
||||
struct packed_git *p = rix->p;
|
||||
int num_ent = p->num_objects;
|
||||
int i;
|
||||
const char *index = p->index_data;
|
||||
|
||||
rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1));
|
||||
index += 4 * 256;
|
||||
|
||||
if (p->index_version > 1) {
|
||||
const uint32_t *off_32 =
|
||||
(uint32_t *)(index + 8 + p->num_objects * (20 + 4));
|
||||
const uint32_t *off_64 = off_32 + p->num_objects;
|
||||
for (i = 0; i < num_ent; i++) {
|
||||
uint32_t off = ntohl(*off_32++);
|
||||
if (!(off & 0x80000000)) {
|
||||
rix->revindex[i].offset = off;
|
||||
} else {
|
||||
rix->revindex[i].offset =
|
||||
((uint64_t)ntohl(*off_64++)) << 32;
|
||||
rix->revindex[i].offset |=
|
||||
ntohl(*off_64++);
|
||||
}
|
||||
rix->revindex[i].nr = i;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < num_ent; i++) {
|
||||
uint32_t hl = *((uint32_t *)(index + 24 * i));
|
||||
rix->revindex[i].offset = ntohl(hl);
|
||||
rix->revindex[i].nr = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* This knows the pack format -- the 20-byte trailer
|
||||
* follows immediately after the last object data.
|
||||
*/
|
||||
rix->revindex[num_ent].offset = p->pack_size - 20;
|
||||
rix->revindex[num_ent].nr = -1;
|
||||
qsort(rix->revindex, num_ent, sizeof(*rix->revindex), cmp_offset);
|
||||
}
|
||||
|
||||
static struct revindex_entry * find_packed_object(struct packed_git *p,
|
||||
off_t ofs)
|
||||
{
|
||||
int num;
|
||||
int lo, hi;
|
||||
struct pack_revindex *rix;
|
||||
struct revindex_entry *revindex;
|
||||
num = pack_revindex_ix(p);
|
||||
if (num < 0)
|
||||
die("internal error: pack revindex uninitialized");
|
||||
rix = &pack_revindex[num];
|
||||
if (!rix->revindex)
|
||||
prepare_pack_revindex(rix);
|
||||
revindex = rix->revindex;
|
||||
lo = 0;
|
||||
hi = p->num_objects + 1;
|
||||
do {
|
||||
int mi = (lo + hi) / 2;
|
||||
if (revindex[mi].offset == ofs) {
|
||||
return revindex + mi;
|
||||
}
|
||||
else if (ofs < revindex[mi].offset)
|
||||
hi = mi;
|
||||
else
|
||||
lo = mi + 1;
|
||||
} while (lo < hi);
|
||||
die("internal error: pack revindex corrupt");
|
||||
}
|
||||
|
||||
static const unsigned char *find_packed_object_name(struct packed_git *p,
|
||||
off_t ofs)
|
||||
{
|
||||
struct revindex_entry *entry = find_packed_object(p, ofs);
|
||||
return nth_packed_object_sha1(p, entry->nr);
|
||||
}
|
||||
|
||||
static void *delta_against(void *buf, unsigned long size, struct object_entry *entry)
|
||||
{
|
||||
@@ -510,7 +365,7 @@ static unsigned long write_object(struct sha1file *f,
|
||||
}
|
||||
hdrlen = encode_header(obj_type, entry->size, header);
|
||||
offset = entry->in_pack_offset;
|
||||
revidx = find_packed_object(p, offset);
|
||||
revidx = find_pack_revindex(p, offset);
|
||||
datalen = revidx[1].offset - offset;
|
||||
if (!pack_to_stdout && p->index_version > 1 &&
|
||||
check_pack_crc(p, &w_curs, offset, datalen, revidx->nr))
|
||||
@@ -1162,8 +1017,11 @@ static void check_object(struct object_entry *entry)
|
||||
die("delta base offset out of bound for %s",
|
||||
sha1_to_hex(entry->idx.sha1));
|
||||
ofs = entry->in_pack_offset - ofs;
|
||||
if (!no_reuse_delta && !entry->preferred_base)
|
||||
base_ref = find_packed_object_name(p, ofs);
|
||||
if (!no_reuse_delta && !entry->preferred_base) {
|
||||
struct revindex_entry *revidx;
|
||||
revidx = find_pack_revindex(p, ofs);
|
||||
base_ref = nth_packed_object_sha1(p, revidx->nr);
|
||||
}
|
||||
entry->in_pack_header_size = used + used_0;
|
||||
break;
|
||||
}
|
||||
@@ -1240,9 +1098,11 @@ static void get_object_details(void)
|
||||
sorted_by_offset[i] = objects + i;
|
||||
qsort(sorted_by_offset, nr_objects, sizeof(*sorted_by_offset), pack_offset_sort);
|
||||
|
||||
prepare_pack_ix();
|
||||
init_pack_revindex();
|
||||
|
||||
for (i = 0; i < nr_objects; i++)
|
||||
check_object(sorted_by_offset[i]);
|
||||
|
||||
free(sorted_by_offset);
|
||||
}
|
||||
|
||||
@@ -2013,7 +1873,6 @@ static void get_object_list(int ac, const char **av)
|
||||
|
||||
init_revisions(&revs, NULL);
|
||||
save_commit_buffer = 0;
|
||||
track_object_refs = 0;
|
||||
setup_revisions(ac, av, &revs, NULL);
|
||||
|
||||
while (fgets(line, sizeof(line), stdin) != NULL) {
|
||||
|
||||
@@ -63,14 +63,10 @@ static int reset_index_file(const unsigned char *sha1, int is_hard_reset)
|
||||
|
||||
static void print_new_head_line(struct commit *commit)
|
||||
{
|
||||
const char *hex, *dots = "...", *body;
|
||||
const char *hex, *body;
|
||||
|
||||
hex = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
|
||||
if (!hex) {
|
||||
hex = sha1_to_hex(commit->object.sha1);
|
||||
dots = "";
|
||||
}
|
||||
printf("HEAD is now at %s%s", hex, dots);
|
||||
printf("HEAD is now at %s", hex);
|
||||
body = strstr(commit->buffer, "\n\n");
|
||||
if (body) {
|
||||
const char *eol;
|
||||
|
||||
@@ -610,7 +610,6 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
||||
usage(rev_list_usage);
|
||||
|
||||
save_commit_buffer = revs.verbose_header || revs.grep_filter;
|
||||
track_object_refs = 0;
|
||||
if (bisect_list)
|
||||
revs.limited = 1;
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "utf8.h"
|
||||
#include "parse-options.h"
|
||||
#include "cache-tree.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
|
||||
/*
|
||||
* This implements the builtins revert and cherry-pick.
|
||||
@@ -246,6 +248,17 @@ static char *help_msg(const unsigned char *sha1)
|
||||
return helpbuf;
|
||||
}
|
||||
|
||||
static int index_is_dirty(void)
|
||||
{
|
||||
struct rev_info rev;
|
||||
init_revisions(&rev, NULL);
|
||||
setup_revisions(0, NULL, &rev, "HEAD");
|
||||
DIFF_OPT_SET(&rev.diffopt, QUIET);
|
||||
DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
|
||||
run_diff_index(&rev, 1);
|
||||
return !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES);
|
||||
}
|
||||
|
||||
static int revert_or_cherry_pick(int argc, const char **argv)
|
||||
{
|
||||
unsigned char head[20];
|
||||
@@ -274,12 +287,11 @@ static int revert_or_cherry_pick(int argc, const char **argv)
|
||||
if (write_cache_as_tree(head, 0, NULL))
|
||||
die ("Your index file is unmerged.");
|
||||
} else {
|
||||
struct wt_status s;
|
||||
|
||||
if (get_sha1("HEAD", head))
|
||||
die ("You do not have a valid HEAD");
|
||||
wt_status_prepare(&s);
|
||||
if (s.commitable)
|
||||
if (read_cache() < 0)
|
||||
die("could not read the index");
|
||||
if (index_is_dirty())
|
||||
die ("Dirty index: cannot %s", me);
|
||||
discard_cache();
|
||||
}
|
||||
|
||||
@@ -264,9 +264,7 @@ static void print_ref_status(char flag, const char *summary, struct ref *to, str
|
||||
|
||||
static const char *status_abbrev(unsigned char sha1[20])
|
||||
{
|
||||
const char *abbrev;
|
||||
abbrev = find_unique_abbrev(sha1, DEFAULT_ABBREV);
|
||||
return abbrev ? abbrev : sha1_to_hex(sha1);
|
||||
return find_unique_abbrev(sha1, DEFAULT_ABBREV);
|
||||
}
|
||||
|
||||
static void print_ok_ref_status(struct ref *ref)
|
||||
|
||||
@@ -7,10 +7,13 @@
|
||||
#include "commit.h"
|
||||
#include "tag.h"
|
||||
#include "tree.h"
|
||||
#include "tree-walk.h"
|
||||
#include "progress.h"
|
||||
#include "decorate.h"
|
||||
#include "fsck.h"
|
||||
|
||||
static int dry_run, quiet, recover, has_errors;
|
||||
static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] < pack-file";
|
||||
static int dry_run, quiet, recover, has_errors, strict;
|
||||
static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
|
||||
|
||||
/* We always read in 4kB chunks. */
|
||||
static unsigned char buffer[4096];
|
||||
@@ -18,6 +21,28 @@ static unsigned int offset, len;
|
||||
static off_t consumed_bytes;
|
||||
static SHA_CTX ctx;
|
||||
|
||||
struct obj_buffer {
|
||||
char *buffer;
|
||||
unsigned long size;
|
||||
};
|
||||
|
||||
static struct decoration obj_decorate;
|
||||
|
||||
static struct obj_buffer *lookup_object_buffer(struct object *base)
|
||||
{
|
||||
return lookup_decoration(&obj_decorate, base);
|
||||
}
|
||||
|
||||
static void add_object_buffer(struct object *object, char *buffer, unsigned long size)
|
||||
{
|
||||
struct obj_buffer *obj;
|
||||
obj = xcalloc(1, sizeof(struct obj_buffer));
|
||||
obj->buffer = buffer;
|
||||
obj->size = size;
|
||||
if (add_decoration(&obj_decorate, object, obj))
|
||||
die("object %s tried to add buffer twice!", sha1_to_hex(object->sha1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure at least "min" bytes are available in the buffer, and
|
||||
* return the pointer to the buffer.
|
||||
@@ -121,9 +146,58 @@ static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1,
|
||||
struct obj_info {
|
||||
off_t offset;
|
||||
unsigned char sha1[20];
|
||||
struct object *obj;
|
||||
};
|
||||
|
||||
#define FLAG_OPEN (1u<<20)
|
||||
#define FLAG_WRITTEN (1u<<21)
|
||||
|
||||
static struct obj_info *obj_list;
|
||||
unsigned nr_objects;
|
||||
|
||||
static void write_cached_object(struct object *obj)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
struct obj_buffer *obj_buf = lookup_object_buffer(obj);
|
||||
if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), sha1) < 0)
|
||||
die("failed to write object %s", sha1_to_hex(obj->sha1));
|
||||
obj->flags |= FLAG_WRITTEN;
|
||||
}
|
||||
|
||||
static int check_object(struct object *obj, int type, void *data)
|
||||
{
|
||||
if (!obj)
|
||||
return 0;
|
||||
|
||||
if (obj->flags & FLAG_WRITTEN)
|
||||
return 1;
|
||||
|
||||
if (type != OBJ_ANY && obj->type != type)
|
||||
die("object type mismatch");
|
||||
|
||||
if (!(obj->flags & FLAG_OPEN)) {
|
||||
unsigned long size;
|
||||
int type = sha1_object_info(obj->sha1, &size);
|
||||
if (type != obj->type || type <= 0)
|
||||
die("object of unexpected type");
|
||||
obj->flags |= FLAG_WRITTEN;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fsck_object(obj, 1, fsck_error_function))
|
||||
die("Error in object");
|
||||
if (!fsck_walk(obj, check_object, 0))
|
||||
die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
|
||||
write_cached_object(obj);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void write_rest(void)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < nr_objects; i++)
|
||||
check_object(obj_list[i].obj, OBJ_ANY, 0);
|
||||
}
|
||||
|
||||
static void added_object(unsigned nr, enum object_type type,
|
||||
void *data, unsigned long size);
|
||||
@@ -131,9 +205,36 @@ static void added_object(unsigned nr, enum object_type type,
|
||||
static void write_object(unsigned nr, enum object_type type,
|
||||
void *buf, unsigned long size)
|
||||
{
|
||||
if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
|
||||
die("failed to write object");
|
||||
added_object(nr, type, buf, size);
|
||||
if (!strict) {
|
||||
if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
|
||||
die("failed to write object");
|
||||
free(buf);
|
||||
obj_list[nr].obj = 0;
|
||||
} else if (type == OBJ_BLOB) {
|
||||
struct blob *blob;
|
||||
if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
|
||||
die("failed to write object");
|
||||
free(buf);
|
||||
|
||||
blob = lookup_blob(obj_list[nr].sha1);
|
||||
if (blob)
|
||||
blob->object.flags |= FLAG_WRITTEN;
|
||||
else
|
||||
die("invalid blob object");
|
||||
obj_list[nr].obj = 0;
|
||||
} else {
|
||||
struct object *obj;
|
||||
int eaten;
|
||||
hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1);
|
||||
obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten);
|
||||
if (!obj)
|
||||
die("invalid %s", typename(type));
|
||||
/* buf is stored via add_object_buffer and in obj, if its a tree or commit */
|
||||
add_object_buffer(obj, buf, size);
|
||||
obj->flags |= FLAG_OPEN;
|
||||
obj_list[nr].obj = obj;
|
||||
}
|
||||
}
|
||||
|
||||
static void resolve_delta(unsigned nr, enum object_type type,
|
||||
@@ -150,7 +251,6 @@ static void resolve_delta(unsigned nr, enum object_type type,
|
||||
die("failed to apply delta");
|
||||
free(delta);
|
||||
write_object(nr, type, result, result_size);
|
||||
free(result);
|
||||
}
|
||||
|
||||
static void added_object(unsigned nr, enum object_type type,
|
||||
@@ -180,7 +280,8 @@ static void unpack_non_delta_entry(enum object_type type, unsigned long size,
|
||||
|
||||
if (!dry_run && buf)
|
||||
write_object(nr, type, buf, size);
|
||||
free(buf);
|
||||
else
|
||||
free(buf);
|
||||
}
|
||||
|
||||
static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
||||
@@ -189,6 +290,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
||||
void *delta_data, *base;
|
||||
unsigned long base_size;
|
||||
unsigned char base_sha1[20];
|
||||
struct object *obj;
|
||||
|
||||
if (type == OBJ_REF_DELTA) {
|
||||
hashcpy(base_sha1, fill(20));
|
||||
@@ -252,6 +354,15 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
|
||||
}
|
||||
}
|
||||
|
||||
obj = lookup_object(base_sha1);
|
||||
if (obj) {
|
||||
struct obj_buffer *obj_buf = lookup_object_buffer(obj);
|
||||
if (obj_buf) {
|
||||
resolve_delta(nr, obj->type, obj_buf->buffer, obj_buf->size, delta_data, delta_size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
base = read_sha1_file(base_sha1, &type, &base_size);
|
||||
if (!base) {
|
||||
error("failed to read delta-pack base object %s",
|
||||
@@ -313,7 +424,8 @@ static void unpack_all(void)
|
||||
int i;
|
||||
struct progress *progress = NULL;
|
||||
struct pack_header *hdr = fill(sizeof(struct pack_header));
|
||||
unsigned nr_objects = ntohl(hdr->hdr_entries);
|
||||
|
||||
nr_objects = ntohl(hdr->hdr_entries);
|
||||
|
||||
if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE)
|
||||
die("bad pack file");
|
||||
@@ -324,6 +436,7 @@ static void unpack_all(void)
|
||||
if (!quiet)
|
||||
progress = start_progress("Unpacking objects", nr_objects);
|
||||
obj_list = xmalloc(nr_objects * sizeof(*obj_list));
|
||||
memset(obj_list, 0, nr_objects * sizeof(*obj_list));
|
||||
for (i = 0; i < nr_objects; i++) {
|
||||
unpack_one(i);
|
||||
display_progress(progress, i + 1);
|
||||
@@ -359,6 +472,10 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
|
||||
recover = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--strict")) {
|
||||
strict = 1;
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--pack_header=")) {
|
||||
struct pack_header *hdr;
|
||||
char *c;
|
||||
@@ -384,6 +501,8 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
|
||||
unpack_all();
|
||||
SHA1_Update(&ctx, buffer, offset);
|
||||
SHA1_Final(sha1, &ctx);
|
||||
if (strict)
|
||||
write_rest();
|
||||
if (hashcmp(fill(20), sha1))
|
||||
die("final sha1 did not match");
|
||||
use(20);
|
||||
|
||||
@@ -40,8 +40,8 @@ static int verify_one_pack(const char *path, int verbose)
|
||||
if (!pack)
|
||||
return error("packfile %s not found.", arg);
|
||||
|
||||
install_packed_git(pack);
|
||||
err = verify_pack(pack, verbose);
|
||||
free(pack);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
1
cache.h
1
cache.h
@@ -274,6 +274,7 @@ enum object_type {
|
||||
/* 5 for future expansion */
|
||||
OBJ_OFS_DELTA = 6,
|
||||
OBJ_REF_DELTA = 7,
|
||||
OBJ_ANY,
|
||||
OBJ_MAX,
|
||||
};
|
||||
|
||||
|
||||
13
commit.c
13
commit.c
@@ -193,7 +193,7 @@ static void prepare_commit_graft(void)
|
||||
commit_graft_prepared = 1;
|
||||
}
|
||||
|
||||
static struct commit_graft *lookup_commit_graft(const unsigned char *sha1)
|
||||
struct commit_graft *lookup_commit_graft(const unsigned char *sha1)
|
||||
{
|
||||
int pos;
|
||||
prepare_commit_graft();
|
||||
@@ -290,17 +290,6 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
|
||||
}
|
||||
item->date = parse_commit_date(bufptr, tail);
|
||||
|
||||
if (track_object_refs) {
|
||||
unsigned i = 0;
|
||||
struct commit_list *p;
|
||||
struct object_refs *refs = alloc_object_refs(n_refs);
|
||||
if (item->tree)
|
||||
refs->ref[i++] = &item->tree->object;
|
||||
for (p = item->parents; p; p = p->next)
|
||||
refs->ref[i++] = &p->item->object;
|
||||
set_object_refs(&item->object, refs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
1
commit.h
1
commit.h
@@ -116,6 +116,7 @@ struct commit_graft {
|
||||
struct commit_graft *read_graft_line(char *buf, int len);
|
||||
int register_commit_graft(struct commit_graft *, int);
|
||||
int read_graft_file(const char *graft_file);
|
||||
struct commit_graft *lookup_commit_graft(const unsigned char *sha1);
|
||||
|
||||
extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ my %depths;
|
||||
my @depths;
|
||||
|
||||
while (<STDIN>) {
|
||||
my ($sha1, $type, $size, $offset, $depth, $parent) = split(/\s+/, $_);
|
||||
my ($sha1, $type, $size, $space, $offset, $depth, $parent) = split(/\s+/, $_);
|
||||
next unless ($sha1 =~ /^[0-9a-f]{40}$/);
|
||||
$depths{$sha1} = $depth || 0;
|
||||
push(@depths, $depth || 0);
|
||||
|
||||
18
daemon.c
18
daemon.c
@@ -1149,6 +1149,11 @@ int main(int argc, char **argv)
|
||||
usage(daemon_usage);
|
||||
}
|
||||
|
||||
if (log_syslog) {
|
||||
openlog("git-daemon", 0, LOG_DAEMON);
|
||||
set_die_routine(daemon_die);
|
||||
}
|
||||
|
||||
if (inetd_mode && (group_name || user_name))
|
||||
die("--user and --group are incompatible with --inetd");
|
||||
|
||||
@@ -1176,14 +1181,17 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (log_syslog) {
|
||||
openlog("git-daemon", 0, LOG_DAEMON);
|
||||
set_die_routine(daemon_die);
|
||||
}
|
||||
|
||||
if (strict_paths && (!ok_paths || !*ok_paths))
|
||||
die("option --strict-paths requires a whitelist");
|
||||
|
||||
if (base_path) {
|
||||
struct stat st;
|
||||
|
||||
if (stat(base_path, &st) || !S_ISDIR(st.st_mode))
|
||||
die("base-path '%s' does not exist or "
|
||||
"is not a directory", base_path);
|
||||
}
|
||||
|
||||
if (inetd_mode) {
|
||||
struct sockaddr_storage ss;
|
||||
struct sockaddr *peer = (struct sockaddr *)&ss;
|
||||
|
||||
13
diff-lib.c
13
diff-lib.c
@@ -472,22 +472,21 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
|
||||
static void diff_index_show_file(struct rev_info *revs,
|
||||
const char *prefix,
|
||||
struct cache_entry *ce,
|
||||
unsigned char *sha1, unsigned int mode)
|
||||
const unsigned char *sha1, unsigned int mode)
|
||||
{
|
||||
diff_addremove(&revs->diffopt, prefix[0], mode,
|
||||
sha1, ce->name, NULL);
|
||||
}
|
||||
|
||||
static int get_stat_data(struct cache_entry *ce,
|
||||
unsigned char **sha1p,
|
||||
const unsigned char **sha1p,
|
||||
unsigned int *modep,
|
||||
int cached, int match_missing)
|
||||
{
|
||||
unsigned char *sha1 = ce->sha1;
|
||||
const unsigned char *sha1 = ce->sha1;
|
||||
unsigned int mode = ce->ce_mode;
|
||||
|
||||
if (!cached) {
|
||||
static unsigned char no_sha1[20];
|
||||
int changed;
|
||||
struct stat st;
|
||||
if (lstat(ce->name, &st) < 0) {
|
||||
@@ -501,7 +500,7 @@ static int get_stat_data(struct cache_entry *ce,
|
||||
changed = ce_match_stat(ce, &st, 0);
|
||||
if (changed) {
|
||||
mode = ce_mode_from_stat(ce, st.st_mode);
|
||||
sha1 = no_sha1;
|
||||
sha1 = null_sha1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,7 +513,7 @@ static void show_new_file(struct rev_info *revs,
|
||||
struct cache_entry *new,
|
||||
int cached, int match_missing)
|
||||
{
|
||||
unsigned char *sha1;
|
||||
const unsigned char *sha1;
|
||||
unsigned int mode;
|
||||
|
||||
/* New file in the index: it might actually be different in
|
||||
@@ -533,7 +532,7 @@ static int show_modified(struct rev_info *revs,
|
||||
int cached, int match_missing)
|
||||
{
|
||||
unsigned int mode, oldmode;
|
||||
unsigned char *sha1;
|
||||
const unsigned char *sha1;
|
||||
|
||||
if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0) {
|
||||
if (report_missing)
|
||||
|
||||
9
diff.c
9
diff.c
@@ -2581,8 +2581,6 @@ const char *diff_unique_abbrev(const unsigned char *sha1, int len)
|
||||
return sha1_to_hex(sha1);
|
||||
|
||||
abbrev = find_unique_abbrev(sha1, len);
|
||||
if (!abbrev)
|
||||
return sha1_to_hex(sha1);
|
||||
abblen = strlen(abbrev);
|
||||
if (abblen < 37) {
|
||||
static char hex[41];
|
||||
@@ -3189,11 +3187,8 @@ static void diffcore_apply_filter(const char *filter)
|
||||
static int diff_filespec_is_identical(struct diff_filespec *one,
|
||||
struct diff_filespec *two)
|
||||
{
|
||||
if (S_ISGITLINK(one->mode)) {
|
||||
diff_fill_sha1_info(one);
|
||||
diff_fill_sha1_info(two);
|
||||
return !hashcmp(one->sha1, two->sha1);
|
||||
}
|
||||
if (S_ISGITLINK(one->mode))
|
||||
return 0;
|
||||
if (diff_populate_filespec(one, 0))
|
||||
return 0;
|
||||
if (diff_populate_filespec(two, 0))
|
||||
|
||||
@@ -2377,6 +2377,7 @@ int main(int argc, const char **argv)
|
||||
{
|
||||
unsigned int i, show_stats = 1;
|
||||
|
||||
setup_git_directory();
|
||||
git_config(git_pack_config);
|
||||
if (!pack_compression_seen && core_compression_seen)
|
||||
pack_compression_level = core_compression_level;
|
||||
|
||||
335
fsck.c
Normal file
335
fsck.c
Normal file
@@ -0,0 +1,335 @@
|
||||
#include "cache.h"
|
||||
#include "object.h"
|
||||
#include "blob.h"
|
||||
#include "tree.h"
|
||||
#include "tree-walk.h"
|
||||
#include "commit.h"
|
||||
#include "tag.h"
|
||||
#include "fsck.h"
|
||||
|
||||
static int fsck_walk_tree(struct tree *tree, fsck_walk_func walk, void *data)
|
||||
{
|
||||
struct tree_desc desc;
|
||||
struct name_entry entry;
|
||||
int res = 0;
|
||||
|
||||
if (parse_tree(tree))
|
||||
return -1;
|
||||
|
||||
init_tree_desc(&desc, tree->buffer, tree->size);
|
||||
while (tree_entry(&desc, &entry)) {
|
||||
int result;
|
||||
|
||||
if (S_ISGITLINK(entry.mode))
|
||||
continue;
|
||||
if (S_ISDIR(entry.mode))
|
||||
result = walk(&lookup_tree(entry.sha1)->object, OBJ_TREE, data);
|
||||
else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode))
|
||||
result = walk(&lookup_blob(entry.sha1)->object, OBJ_BLOB, data);
|
||||
else {
|
||||
result = error("in tree %s: entry %s has bad mode %.6o\n",
|
||||
sha1_to_hex(tree->object.sha1), entry.path, entry.mode);
|
||||
}
|
||||
if (result < 0)
|
||||
return result;
|
||||
if (!res)
|
||||
res = result;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int fsck_walk_commit(struct commit *commit, fsck_walk_func walk, void *data)
|
||||
{
|
||||
struct commit_list *parents;
|
||||
int res;
|
||||
int result;
|
||||
|
||||
if (parse_commit(commit))
|
||||
return -1;
|
||||
|
||||
result = walk((struct object *)commit->tree, OBJ_TREE, data);
|
||||
if (result < 0)
|
||||
return result;
|
||||
res = result;
|
||||
|
||||
parents = commit->parents;
|
||||
while (parents) {
|
||||
result = walk((struct object *)parents->item, OBJ_COMMIT, data);
|
||||
if (result < 0)
|
||||
return result;
|
||||
if (!res)
|
||||
res = result;
|
||||
parents = parents->next;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int fsck_walk_tag(struct tag *tag, fsck_walk_func walk, void *data)
|
||||
{
|
||||
if (parse_tag(tag))
|
||||
return -1;
|
||||
return walk(tag->tagged, OBJ_ANY, data);
|
||||
}
|
||||
|
||||
int fsck_walk(struct object *obj, fsck_walk_func walk, void *data)
|
||||
{
|
||||
if (!obj)
|
||||
return -1;
|
||||
switch (obj->type) {
|
||||
case OBJ_BLOB:
|
||||
return 0;
|
||||
case OBJ_TREE:
|
||||
return fsck_walk_tree((struct tree *)obj, walk, data);
|
||||
case OBJ_COMMIT:
|
||||
return fsck_walk_commit((struct commit *)obj, walk, data);
|
||||
case OBJ_TAG:
|
||||
return fsck_walk_tag((struct tag *)obj, walk, data);
|
||||
default:
|
||||
error("Unknown object type for %s", sha1_to_hex(obj->sha1));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The entries in a tree are ordered in the _path_ order,
|
||||
* which means that a directory entry is ordered by adding
|
||||
* a slash to the end of it.
|
||||
*
|
||||
* So a directory called "a" is ordered _after_ a file
|
||||
* called "a.c", because "a/" sorts after "a.c".
|
||||
*/
|
||||
#define TREE_UNORDERED (-1)
|
||||
#define TREE_HAS_DUPS (-2)
|
||||
|
||||
static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2)
|
||||
{
|
||||
int len1 = strlen(name1);
|
||||
int len2 = strlen(name2);
|
||||
int len = len1 < len2 ? len1 : len2;
|
||||
unsigned char c1, c2;
|
||||
int cmp;
|
||||
|
||||
cmp = memcmp(name1, name2, len);
|
||||
if (cmp < 0)
|
||||
return 0;
|
||||
if (cmp > 0)
|
||||
return TREE_UNORDERED;
|
||||
|
||||
/*
|
||||
* Ok, the first <len> characters are the same.
|
||||
* Now we need to order the next one, but turn
|
||||
* a '\0' into a '/' for a directory entry.
|
||||
*/
|
||||
c1 = name1[len];
|
||||
c2 = name2[len];
|
||||
if (!c1 && !c2)
|
||||
/*
|
||||
* git-write-tree used to write out a nonsense tree that has
|
||||
* entries with the same name, one blob and one tree. Make
|
||||
* sure we do not have duplicate entries.
|
||||
*/
|
||||
return TREE_HAS_DUPS;
|
||||
if (!c1 && S_ISDIR(mode1))
|
||||
c1 = '/';
|
||||
if (!c2 && S_ISDIR(mode2))
|
||||
c2 = '/';
|
||||
return c1 < c2 ? 0 : TREE_UNORDERED;
|
||||
}
|
||||
|
||||
static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
|
||||
{
|
||||
int retval;
|
||||
int has_full_path = 0;
|
||||
int has_empty_name = 0;
|
||||
int has_zero_pad = 0;
|
||||
int has_bad_modes = 0;
|
||||
int has_dup_entries = 0;
|
||||
int not_properly_sorted = 0;
|
||||
struct tree_desc desc;
|
||||
unsigned o_mode;
|
||||
const char *o_name;
|
||||
const unsigned char *o_sha1;
|
||||
|
||||
init_tree_desc(&desc, item->buffer, item->size);
|
||||
|
||||
o_mode = 0;
|
||||
o_name = NULL;
|
||||
o_sha1 = NULL;
|
||||
if (!desc.size)
|
||||
return error_func(&item->object, FSCK_ERROR, "empty tree");
|
||||
|
||||
while (desc.size) {
|
||||
unsigned mode;
|
||||
const char *name;
|
||||
const unsigned char *sha1;
|
||||
|
||||
sha1 = tree_entry_extract(&desc, &name, &mode);
|
||||
|
||||
if (strchr(name, '/'))
|
||||
has_full_path = 1;
|
||||
if (!*name)
|
||||
has_empty_name = 1;
|
||||
has_zero_pad |= *(char *)desc.buffer == '0';
|
||||
update_tree_entry(&desc);
|
||||
|
||||
switch (mode) {
|
||||
/*
|
||||
* Standard modes..
|
||||
*/
|
||||
case S_IFREG | 0755:
|
||||
case S_IFREG | 0644:
|
||||
case S_IFLNK:
|
||||
case S_IFDIR:
|
||||
case S_IFGITLINK:
|
||||
break;
|
||||
/*
|
||||
* This is nonstandard, but we had a few of these
|
||||
* early on when we honored the full set of mode
|
||||
* bits..
|
||||
*/
|
||||
case S_IFREG | 0664:
|
||||
if (!strict)
|
||||
break;
|
||||
default:
|
||||
has_bad_modes = 1;
|
||||
}
|
||||
|
||||
if (o_name) {
|
||||
switch (verify_ordered(o_mode, o_name, mode, name)) {
|
||||
case TREE_UNORDERED:
|
||||
not_properly_sorted = 1;
|
||||
break;
|
||||
case TREE_HAS_DUPS:
|
||||
has_dup_entries = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
o_mode = mode;
|
||||
o_name = name;
|
||||
o_sha1 = sha1;
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
if (has_full_path)
|
||||
retval += error_func(&item->object, FSCK_WARN, "contains full pathnames");
|
||||
if (has_empty_name)
|
||||
retval += error_func(&item->object, FSCK_WARN, "contains empty pathname");
|
||||
if (has_zero_pad)
|
||||
retval += error_func(&item->object, FSCK_WARN, "contains zero-padded file modes");
|
||||
if (has_bad_modes)
|
||||
retval += error_func(&item->object, FSCK_WARN, "contains bad file modes");
|
||||
if (has_dup_entries)
|
||||
retval += error_func(&item->object, FSCK_ERROR, "contains duplicate file entries");
|
||||
if (not_properly_sorted)
|
||||
retval += error_func(&item->object, FSCK_ERROR, "not properly sorted");
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int fsck_commit(struct commit *commit, fsck_error error_func)
|
||||
{
|
||||
char *buffer = commit->buffer;
|
||||
unsigned char tree_sha1[20], sha1[20];
|
||||
struct commit_graft *graft;
|
||||
int parents = 0;
|
||||
|
||||
if (!commit->date)
|
||||
return error_func(&commit->object, FSCK_ERROR, "invalid author/committer line");
|
||||
|
||||
if (memcmp(buffer, "tree ", 5))
|
||||
return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'tree' line");
|
||||
if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n')
|
||||
return error_func(&commit->object, FSCK_ERROR, "invalid 'tree' line format - bad sha1");
|
||||
buffer += 46;
|
||||
while (!memcmp(buffer, "parent ", 7)) {
|
||||
if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n')
|
||||
return error_func(&commit->object, FSCK_ERROR, "invalid 'parent' line format - bad sha1");
|
||||
buffer += 48;
|
||||
parents++;
|
||||
}
|
||||
graft = lookup_commit_graft(commit->object.sha1);
|
||||
if (graft) {
|
||||
struct commit_list *p = commit->parents;
|
||||
parents = 0;
|
||||
while (p) {
|
||||
p = p->next;
|
||||
parents++;
|
||||
}
|
||||
if (graft->nr_parent == -1 && !parents)
|
||||
; /* shallow commit */
|
||||
else if (graft->nr_parent != parents)
|
||||
return error_func(&commit->object, FSCK_ERROR, "graft objects missing");
|
||||
} else {
|
||||
struct commit_list *p = commit->parents;
|
||||
while (p && parents) {
|
||||
p = p->next;
|
||||
parents--;
|
||||
}
|
||||
if (p || parents)
|
||||
return error_func(&commit->object, FSCK_ERROR, "parent objects missing");
|
||||
}
|
||||
if (memcmp(buffer, "author ", 7))
|
||||
return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'author' line");
|
||||
if (!commit->tree)
|
||||
return error_func(&commit->object, FSCK_ERROR, "could not load commit's tree %s", sha1_to_hex(tree_sha1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsck_tag(struct tag *tag, fsck_error error_func)
|
||||
{
|
||||
struct object *tagged = tag->tagged;
|
||||
|
||||
if (!tagged)
|
||||
return error_func(&tag->object, FSCK_ERROR, "could not load tagged object");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fsck_object(struct object *obj, int strict, fsck_error error_func)
|
||||
{
|
||||
if (!obj)
|
||||
return error_func(obj, FSCK_ERROR, "no valid object to fsck");
|
||||
|
||||
if (obj->type == OBJ_BLOB)
|
||||
return 0;
|
||||
if (obj->type == OBJ_TREE)
|
||||
return fsck_tree((struct tree *) obj, strict, error_func);
|
||||
if (obj->type == OBJ_COMMIT)
|
||||
return fsck_commit((struct commit *) obj, error_func);
|
||||
if (obj->type == OBJ_TAG)
|
||||
return fsck_tag((struct tag *) obj, error_func);
|
||||
|
||||
return error_func(obj, FSCK_ERROR, "unknown type '%d' (internal fsck error)",
|
||||
obj->type);
|
||||
}
|
||||
|
||||
int fsck_error_function(struct object *obj, int type, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int len;
|
||||
struct strbuf sb;
|
||||
|
||||
strbuf_init(&sb, 0);
|
||||
strbuf_addf(&sb, "object %s:", obj->sha1?sha1_to_hex(obj->sha1):"(null)");
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(sb.buf + sb.len, strbuf_avail(&sb), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (len < 0)
|
||||
len = 0;
|
||||
if (len >= strbuf_avail(&sb)) {
|
||||
strbuf_grow(&sb, len + 2);
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(sb.buf + sb.len, strbuf_avail(&sb), fmt, ap);
|
||||
va_end(ap);
|
||||
if (len >= strbuf_avail(&sb))
|
||||
die("this should not happen, your snprintf is broken");
|
||||
}
|
||||
|
||||
error(sb.buf);
|
||||
strbuf_release(&sb);
|
||||
return 1;
|
||||
}
|
||||
32
fsck.h
Normal file
32
fsck.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef GIT_FSCK_H
|
||||
#define GIT_FSCK_H
|
||||
|
||||
#define FSCK_ERROR 1
|
||||
#define FSCK_WARN 2
|
||||
|
||||
/*
|
||||
* callback function for fsck_walk
|
||||
* type is the expected type of the object or OBJ_ANY
|
||||
* the return value is:
|
||||
* 0 everything OK
|
||||
* <0 error signaled and abort
|
||||
* >0 error signaled and do not abort
|
||||
*/
|
||||
typedef int (*fsck_walk_func)(struct object *obj, int type, void *data);
|
||||
|
||||
/* callback for fsck_object, type is FSCK_ERROR or FSCK_WARN */
|
||||
typedef int (*fsck_error)(struct object *obj, int type, const char *err, ...);
|
||||
|
||||
int fsck_error_function(struct object *obj, int type, const char *fmt, ...);
|
||||
|
||||
/* descend in all linked child objects
|
||||
* the return value is:
|
||||
* -1 error in processing the object
|
||||
* <0 return value of the callback, which lead to an abort
|
||||
* >0 return value of the first sigaled error >0 (in the case of no other errors)
|
||||
* 0 everything OK
|
||||
*/
|
||||
int fsck_walk(struct object *obj, fsck_walk_func walk, void *data);
|
||||
int fsck_object(struct object *obj, int strict, fsck_error error_func);
|
||||
|
||||
#endif
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Getopt::Std;
|
||||
use Getopt::Long;
|
||||
use File::Spec;
|
||||
use File::Temp qw(tempfile tmpnam);
|
||||
use File::Path qw(mkpath);
|
||||
@@ -29,7 +29,7 @@ use IPC::Open2;
|
||||
$SIG{'PIPE'}="IGNORE";
|
||||
$ENV{'TZ'}="UTC";
|
||||
|
||||
our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,$opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r);
|
||||
our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,@opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r);
|
||||
my (%conv_author_name, %conv_author_email);
|
||||
|
||||
sub usage(;$) {
|
||||
@@ -112,7 +112,12 @@ sub read_repo_config {
|
||||
|
||||
my $opts = "haivmkuo:d:p:r:C:z:s:M:P:A:S:L:";
|
||||
read_repo_config($opts);
|
||||
getopts($opts) or usage();
|
||||
Getopt::Long::Configure( 'no_ignore_case', 'bundling' );
|
||||
|
||||
# turn the Getopt::Std specification in a Getopt::Long one,
|
||||
# with support for multiple -M options
|
||||
GetOptions( map { s/:/=s/; /M/ ? "$_\@" : $_ } split( /(?!:)/, $opts ) )
|
||||
or usage();
|
||||
usage if $opt_h;
|
||||
|
||||
if (@ARGV == 0) {
|
||||
@@ -164,10 +169,10 @@ if ($#ARGV == 0) {
|
||||
|
||||
our @mergerx = ();
|
||||
if ($opt_m) {
|
||||
@mergerx = ( qr/\b(?:from|of|merge|merging|merged) (\w+)/i );
|
||||
@mergerx = ( qr/\b(?:from|of|merge|merging|merged) ([-\w]+)/i );
|
||||
}
|
||||
if ($opt_M) {
|
||||
push (@mergerx, qr/$opt_M/);
|
||||
if (@opt_M) {
|
||||
push (@mergerx, map { qr/$_/ } @opt_M);
|
||||
}
|
||||
|
||||
# Remember UTC of our starting time
|
||||
|
||||
@@ -208,16 +208,15 @@ do
|
||||
if test -d "$dotest"
|
||||
then
|
||||
move_to_original_branch
|
||||
rm -r "$dotest"
|
||||
elif test -d .dotest
|
||||
then
|
||||
dotest=.dotest
|
||||
move_to_original_branch
|
||||
rm -r .dotest
|
||||
else
|
||||
die "No rebase in progress?"
|
||||
fi
|
||||
git reset --hard ORIG_HEAD
|
||||
git reset --hard $(cat $dotest/orig-head)
|
||||
rm -r "$dotest"
|
||||
exit
|
||||
;;
|
||||
--onto)
|
||||
|
||||
@@ -7,10 +7,10 @@ my $git = Git->repository();
|
||||
sub add_remote_config {
|
||||
my ($hash, $name, $what, $value) = @_;
|
||||
if ($what eq 'url') {
|
||||
if (exists $hash->{$name}{'URL'}) {
|
||||
print STDERR "Warning: more than one remote.$name.url\n";
|
||||
# Having more than one is Ok -- it is used for push.
|
||||
if (! exists $hash->{'URL'}) {
|
||||
$hash->{$name}{'URL'} = $value;
|
||||
}
|
||||
$hash->{$name}{'URL'} = $value;
|
||||
}
|
||||
elsif ($what eq 'fetch') {
|
||||
$hash->{$name}{'FETCH'} ||= [];
|
||||
|
||||
@@ -362,7 +362,7 @@ cmd_status()
|
||||
do
|
||||
name=$(module_name "$path") || exit
|
||||
url=$(git config submodule."$name".url)
|
||||
if test -z "url" || ! test -d "$path"/.git
|
||||
if test -z "$url" || ! test -d "$path"/.git
|
||||
then
|
||||
say "-$sha1 $path"
|
||||
continue;
|
||||
|
||||
@@ -472,13 +472,15 @@ if (defined $searchtype) {
|
||||
}
|
||||
}
|
||||
|
||||
our $search_use_regexp = $cgi->param('sr');
|
||||
|
||||
our $searchtext = $cgi->param('s');
|
||||
our $search_regexp;
|
||||
if (defined $searchtext) {
|
||||
if (length($searchtext) < 2) {
|
||||
die_error(undef, "At least two characters are required for search parameter");
|
||||
}
|
||||
$search_regexp = quotemeta $searchtext;
|
||||
$search_regexp = $search_use_regexp ? $searchtext : quotemeta $searchtext;
|
||||
}
|
||||
|
||||
# now read PATH_INFO and use it as alternative to parameters
|
||||
@@ -608,6 +610,7 @@ sub href(%) {
|
||||
searchtype => "st",
|
||||
snapshot_format => "sf",
|
||||
extra_options => "opt",
|
||||
search_use_regexp => "sr",
|
||||
);
|
||||
my %mapping = @mapping;
|
||||
|
||||
@@ -2079,7 +2082,7 @@ sub parse_commit {
|
||||
}
|
||||
|
||||
sub parse_commits {
|
||||
my ($commit_id, $maxcount, $skip, $arg, $filename) = @_;
|
||||
my ($commit_id, $maxcount, $skip, $filename, @args) = @_;
|
||||
my @cos;
|
||||
|
||||
$maxcount ||= 1;
|
||||
@@ -2089,7 +2092,7 @@ sub parse_commits {
|
||||
|
||||
open my $fd, "-|", git_cmd(), "rev-list",
|
||||
"--header",
|
||||
($arg ? ($arg) : ()),
|
||||
@args,
|
||||
("--max-count=" . $maxcount),
|
||||
("--skip=" . $skip),
|
||||
@extra_options,
|
||||
@@ -2584,6 +2587,10 @@ EOF
|
||||
$cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) .
|
||||
" search:\n",
|
||||
$cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
|
||||
"<span title=\"Extended regular expression\">" .
|
||||
$cgi->checkbox(-name => 'sr', -value => 1, -label => 're',
|
||||
-checked => $search_use_regexp) .
|
||||
"</span>" .
|
||||
"</div>" .
|
||||
$cgi->end_form() . "\n";
|
||||
}
|
||||
@@ -3830,7 +3837,7 @@ sub git_search_grep_body {
|
||||
chop_and_escape_str($co{'title'}, 50) . "<br/>");
|
||||
my $comment = $co{'comment'};
|
||||
foreach my $line (@$comment) {
|
||||
if ($line =~ m/^(.*)($search_regexp)(.*)$/i) {
|
||||
if ($line =~ m/^(.*?)($search_regexp)(.*)$/i) {
|
||||
my ($lead, $match, $trail) = ($1, $2, $3);
|
||||
$match = chop_str($match, 70, 5, 'center');
|
||||
my $contextlen = int((80 - length($match))/2);
|
||||
@@ -5172,7 +5179,7 @@ sub git_history {
|
||||
$ftype = git_get_type($hash);
|
||||
}
|
||||
|
||||
my @commitlist = parse_commits($hash_base, 101, (100 * $page), "--full-history", $file_name);
|
||||
my @commitlist = parse_commits($hash_base, 101, (100 * $page), $file_name, "--full-history");
|
||||
|
||||
my $paging_nav = '';
|
||||
if ($page > 0) {
|
||||
@@ -5254,14 +5261,17 @@ sub git_search {
|
||||
} elsif ($searchtype eq 'committer') {
|
||||
$greptype = "--committer=";
|
||||
}
|
||||
$greptype .= $search_regexp;
|
||||
my @commitlist = parse_commits($hash, 101, (100 * $page), $greptype);
|
||||
$greptype .= $searchtext;
|
||||
my @commitlist = parse_commits($hash, 101, (100 * $page), undef,
|
||||
$greptype, '--regexp-ignore-case',
|
||||
$search_use_regexp ? '--extended-regexp' : '--fixed-strings');
|
||||
|
||||
my $paging_nav = '';
|
||||
if ($page > 0) {
|
||||
$paging_nav .=
|
||||
$cgi->a({-href => href(action=>"search", hash=>$hash,
|
||||
searchtext=>$searchtext, searchtype=>$searchtype)},
|
||||
searchtext=>$searchtext,
|
||||
searchtype=>$searchtype)},
|
||||
"first");
|
||||
$paging_nav .= " ⋅ " .
|
||||
$cgi->a({-href => href(-replay=>1, page=>$page-1),
|
||||
@@ -5298,8 +5308,9 @@ sub git_search {
|
||||
my $git_command = git_cmd_str();
|
||||
my $searchqtext = $searchtext;
|
||||
$searchqtext =~ s/'/'\\''/;
|
||||
my $pickaxe_flags = $search_use_regexp ? '--pickaxe-regex' : '';
|
||||
open my $fd, "-|", "$git_command rev-list $hash | " .
|
||||
"$git_command diff-tree -r --stdin -S\'$searchqtext\'";
|
||||
"$git_command diff-tree -r --stdin -S\'$searchqtext\' $pickaxe_flags";
|
||||
undef %co;
|
||||
my @files;
|
||||
while (my $line = <$fd>) {
|
||||
@@ -5363,7 +5374,9 @@ sub git_search {
|
||||
my $alternate = 1;
|
||||
my $matches = 0;
|
||||
$/ = "\n";
|
||||
open my $fd, "-|", git_cmd(), 'grep', '-n', '-i', '-E', $searchtext, $co{'tree'};
|
||||
open my $fd, "-|", git_cmd(), 'grep', '-n',
|
||||
$search_use_regexp ? ('-E', '-i') : '-F',
|
||||
$searchtext, $co{'tree'};
|
||||
my $lastfile = '';
|
||||
while (my $line = <$fd>) {
|
||||
chomp $line;
|
||||
@@ -5393,7 +5406,7 @@ sub git_search {
|
||||
print "<div class=\"binary\">Binary file</div>\n";
|
||||
} else {
|
||||
$ltext = untabify($ltext);
|
||||
if ($ltext =~ m/^(.*)($searchtext)(.*)$/i) {
|
||||
if ($ltext =~ m/^(.*)($search_regexp)(.*)$/i) {
|
||||
$ltext = esc_html($1, -nbsp=>1);
|
||||
$ltext .= '<span class="match">';
|
||||
$ltext .= esc_html($2, -nbsp=>1);
|
||||
@@ -5428,27 +5441,31 @@ sub git_search_help {
|
||||
git_header_html();
|
||||
git_print_page_nav('','', $hash,$hash,$hash);
|
||||
print <<EOT;
|
||||
<p><strong>Pattern</strong> is by default a normal string that is matched precisely (but without
|
||||
regard to case, except in the case of pickaxe). However, when you check the <em>re</em> checkbox,
|
||||
the pattern entered is recognized as the POSIX extended
|
||||
<a href="http://en.wikipedia.org/wiki/Regular_expression">regular expression</a> (also case
|
||||
insensitive).</p>
|
||||
<dl>
|
||||
<dt><b>commit</b></dt>
|
||||
<dd>The commit messages and authorship information will be scanned for the given string.</dd>
|
||||
<dd>The commit messages and authorship information will be scanned for the given pattern.</dd>
|
||||
EOT
|
||||
my ($have_grep) = gitweb_check_feature('grep');
|
||||
if ($have_grep) {
|
||||
print <<EOT;
|
||||
<dt><b>grep</b></dt>
|
||||
<dd>All files in the currently selected tree (HEAD unless you are explicitly browsing
|
||||
a different one) are searched for the given
|
||||
<a href="http://en.wikipedia.org/wiki/Regular_expression">regular expression</a>
|
||||
(POSIX extended) and the matches are listed. On large
|
||||
trees, this search can take a while and put some strain on the server, so please use it with
|
||||
some consideration.</dd>
|
||||
a different one) are searched for the given pattern. On large trees, this search can take
|
||||
a while and put some strain on the server, so please use it with some consideration. Note that
|
||||
due to git-grep peculiarity, currently if regexp mode is turned off, the matches are
|
||||
case-sensitive.</dd>
|
||||
EOT
|
||||
}
|
||||
print <<EOT;
|
||||
<dt><b>author</b></dt>
|
||||
<dd>Name and e-mail of the change author and date of birth of the patch will be scanned for the given string.</dd>
|
||||
<dd>Name and e-mail of the change author and date of birth of the patch will be scanned for the given pattern.</dd>
|
||||
<dt><b>committer</b></dt>
|
||||
<dd>Name and e-mail of the committer and date of commit will be scanned for the given string.</dd>
|
||||
<dd>Name and e-mail of the committer and date of commit will be scanned for the given pattern.</dd>
|
||||
EOT
|
||||
my ($have_pickaxe) = gitweb_check_feature('pickaxe');
|
||||
if ($have_pickaxe) {
|
||||
@@ -5456,7 +5473,8 @@ EOT
|
||||
<dt><b>pickaxe</b></dt>
|
||||
<dd>All commits that caused the string to appear or disappear from any file (changes that
|
||||
added, removed or "modified" the string) will be listed. This search can take a while and
|
||||
takes a lot of strain on the server, so please use it wisely.</dd>
|
||||
takes a lot of strain on the server, so please use it wisely. Note that since you may be
|
||||
interested even in changes just changing the case as well, this search is case sensitive.</dd>
|
||||
EOT
|
||||
}
|
||||
print "</dl>\n";
|
||||
@@ -5507,7 +5525,7 @@ sub git_feed {
|
||||
|
||||
# log/feed of current (HEAD) branch, log of given branch, history of file/directory
|
||||
my $head = $hash || 'HEAD';
|
||||
my @commitlist = parse_commits($head, 150, 0, undef, $file_name);
|
||||
my @commitlist = parse_commits($head, 150, 0, $file_name);
|
||||
|
||||
my %latest_commit;
|
||||
my %latest_date;
|
||||
|
||||
19
http-push.c
19
http-push.c
@@ -2133,6 +2133,8 @@ static int delete_remote_branch(char *pattern, int force)
|
||||
|
||||
/* Send delete request */
|
||||
fprintf(stderr, "Removing remote branch '%s'\n", remote_ref->name);
|
||||
if (dry_run)
|
||||
return 0;
|
||||
url = xmalloc(strlen(remote->url) + strlen(remote_ref->name) + 1);
|
||||
sprintf(url, "%s%s", remote->url, remote_ref->name);
|
||||
slot = get_active_slot();
|
||||
@@ -2235,7 +2237,7 @@ int main(int argc, char **argv)
|
||||
|
||||
memset(remote_dir_exists, -1, 256);
|
||||
|
||||
http_init();
|
||||
http_init(NULL);
|
||||
|
||||
no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
|
||||
|
||||
@@ -2306,6 +2308,16 @@ int main(int argc, char **argv)
|
||||
|
||||
if (!ref->peer_ref)
|
||||
continue;
|
||||
|
||||
if (is_zero_sha1(ref->peer_ref->new_sha1)) {
|
||||
if (delete_remote_branch(ref->name, 1) == -1) {
|
||||
error("Could not remove %s", ref->name);
|
||||
rc = -4;
|
||||
}
|
||||
new_refs++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
|
||||
if (push_verbosely || 1)
|
||||
fprintf(stderr, "'%s': up-to-date\n", ref->name);
|
||||
@@ -2337,11 +2349,6 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
|
||||
if (is_zero_sha1(ref->new_sha1)) {
|
||||
error("cannot happen anymore");
|
||||
rc = -3;
|
||||
continue;
|
||||
}
|
||||
new_refs++;
|
||||
strcpy(old_hex, sha1_to_hex(ref->old_sha1));
|
||||
new_hex = sha1_to_hex(ref->new_sha1);
|
||||
|
||||
@@ -902,13 +902,13 @@ static void cleanup(struct walker *walker)
|
||||
curl_slist_free_all(data->no_pragma_header);
|
||||
}
|
||||
|
||||
struct walker *get_http_walker(const char *url)
|
||||
struct walker *get_http_walker(const char *url, struct remote *remote)
|
||||
{
|
||||
char *s;
|
||||
struct walker_data *data = xmalloc(sizeof(struct walker_data));
|
||||
struct walker *walker = xmalloc(sizeof(struct walker));
|
||||
|
||||
http_init();
|
||||
http_init(remote);
|
||||
|
||||
data->no_pragma_header = curl_slist_append(NULL, "Pragma:");
|
||||
|
||||
|
||||
10
http.c
10
http.c
@@ -218,13 +218,16 @@ static CURL* get_curl_handle(void)
|
||||
return result;
|
||||
}
|
||||
|
||||
void http_init(void)
|
||||
void http_init(struct remote *remote)
|
||||
{
|
||||
char *low_speed_limit;
|
||||
char *low_speed_time;
|
||||
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
|
||||
if (remote && remote->http_proxy)
|
||||
curl_http_proxy = xstrdup(remote->http_proxy);
|
||||
|
||||
pragma_header = curl_slist_append(pragma_header, "Pragma: no-cache");
|
||||
|
||||
#ifdef USE_CURL_MULTI
|
||||
@@ -314,6 +317,11 @@ void http_cleanup(void)
|
||||
|
||||
curl_slist_free_all(pragma_header);
|
||||
pragma_header = NULL;
|
||||
|
||||
if (curl_http_proxy) {
|
||||
free(curl_http_proxy);
|
||||
curl_http_proxy = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct active_request_slot *get_active_slot(void)
|
||||
|
||||
3
http.h
3
http.h
@@ -7,6 +7,7 @@
|
||||
#include <curl/easy.h>
|
||||
|
||||
#include "strbuf.h"
|
||||
#include "remote.h"
|
||||
|
||||
/*
|
||||
* We detect based on the cURL version if multi-transfer is
|
||||
@@ -83,7 +84,7 @@ extern void add_fill_function(void *data, int (*fill)(void *));
|
||||
extern void step_active_slots(void);
|
||||
#endif
|
||||
|
||||
extern void http_init(void);
|
||||
extern void http_init(struct remote *remote);
|
||||
extern void http_cleanup(void);
|
||||
|
||||
extern int data_received;
|
||||
|
||||
88
index-pack.c
88
index-pack.c
@@ -7,9 +7,10 @@
|
||||
#include "tag.h"
|
||||
#include "tree.h"
|
||||
#include "progress.h"
|
||||
#include "fsck.h"
|
||||
|
||||
static const char index_pack_usage[] =
|
||||
"git-index-pack [-v] [-o <index-file>] [{ ---keep | --keep=<msg> }] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
|
||||
"git-index-pack [-v] [-o <index-file>] [{ ---keep | --keep=<msg> }] [--strict] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
|
||||
|
||||
struct object_entry
|
||||
{
|
||||
@@ -31,6 +32,9 @@ union delta_base {
|
||||
*/
|
||||
#define UNION_BASE_SZ 20
|
||||
|
||||
#define FLAG_LINK (1u<<20)
|
||||
#define FLAG_CHECKED (1u<<21)
|
||||
|
||||
struct delta_entry
|
||||
{
|
||||
union delta_base base;
|
||||
@@ -44,6 +48,7 @@ static int nr_deltas;
|
||||
static int nr_resolved_deltas;
|
||||
|
||||
static int from_stdin;
|
||||
static int strict;
|
||||
static int verbose;
|
||||
|
||||
static struct progress *progress;
|
||||
@@ -56,6 +61,48 @@ static SHA_CTX input_ctx;
|
||||
static uint32_t input_crc32;
|
||||
static int input_fd, output_fd, pack_fd;
|
||||
|
||||
static int mark_link(struct object *obj, int type, void *data)
|
||||
{
|
||||
if (!obj)
|
||||
return -1;
|
||||
|
||||
if (type != OBJ_ANY && obj->type != type)
|
||||
die("object type mismatch at %s", sha1_to_hex(obj->sha1));
|
||||
|
||||
obj->flags |= FLAG_LINK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The content of each linked object must have been checked
|
||||
or it must be already present in the object database */
|
||||
static void check_object(struct object *obj)
|
||||
{
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
if (!(obj->flags & FLAG_LINK))
|
||||
return;
|
||||
|
||||
if (!(obj->flags & FLAG_CHECKED)) {
|
||||
unsigned long size;
|
||||
int type = sha1_object_info(obj->sha1, &size);
|
||||
if (type != obj->type || type <= 0)
|
||||
die("object of unexpected type");
|
||||
obj->flags |= FLAG_CHECKED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void check_objects(void)
|
||||
{
|
||||
unsigned i, max;
|
||||
|
||||
max = get_max_object_index();
|
||||
for (i = 0; i < max; i++)
|
||||
check_object(get_indexed_object(i));
|
||||
}
|
||||
|
||||
|
||||
/* Discard current buffer used content. */
|
||||
static void flush(void)
|
||||
{
|
||||
@@ -341,6 +388,41 @@ static void sha1_object(const void *data, unsigned long size,
|
||||
die("SHA1 COLLISION FOUND WITH %s !", sha1_to_hex(sha1));
|
||||
free(has_data);
|
||||
}
|
||||
if (strict) {
|
||||
if (type == OBJ_BLOB) {
|
||||
struct blob *blob = lookup_blob(sha1);
|
||||
if (blob)
|
||||
blob->object.flags |= FLAG_CHECKED;
|
||||
else
|
||||
die("invalid blob object %s", sha1_to_hex(sha1));
|
||||
} else {
|
||||
struct object *obj;
|
||||
int eaten;
|
||||
void *buf = (void *) data;
|
||||
|
||||
/*
|
||||
* we do not need to free the memory here, as the
|
||||
* buf is deleted by the caller.
|
||||
*/
|
||||
obj = parse_object_buffer(sha1, type, size, buf, &eaten);
|
||||
if (!obj)
|
||||
die("invalid %s", typename(type));
|
||||
if (fsck_object(obj, 1, fsck_error_function))
|
||||
die("Error in object");
|
||||
if (fsck_walk(obj, mark_link, 0))
|
||||
die("Not all child objects of %s are reachable", sha1_to_hex(obj->sha1));
|
||||
|
||||
if (obj->type == OBJ_TREE) {
|
||||
struct tree *item = (struct tree *) obj;
|
||||
item->buffer = NULL;
|
||||
}
|
||||
if (obj->type == OBJ_COMMIT) {
|
||||
struct commit *commit = (struct commit *) obj;
|
||||
commit->buffer = NULL;
|
||||
}
|
||||
obj->flags |= FLAG_CHECKED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void resolve_delta(struct object_entry *delta_obj, void *base_data,
|
||||
@@ -714,6 +796,8 @@ int main(int argc, char **argv)
|
||||
from_stdin = 1;
|
||||
} else if (!strcmp(arg, "--fix-thin")) {
|
||||
fix_thin_pack = 1;
|
||||
} else if (!strcmp(arg, "--strict")) {
|
||||
strict = 1;
|
||||
} else if (!strcmp(arg, "--keep")) {
|
||||
keep_msg = "";
|
||||
} else if (!prefixcmp(arg, "--keep=")) {
|
||||
@@ -812,6 +896,8 @@ int main(int argc, char **argv)
|
||||
nr_deltas - nr_resolved_deltas);
|
||||
}
|
||||
free(deltas);
|
||||
if (strict)
|
||||
check_objects();
|
||||
|
||||
idx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *));
|
||||
for (i = 0; i < nr_objects; i++)
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
#include "cache.h"
|
||||
#include "object.h"
|
||||
#include "decorate.h"
|
||||
|
||||
int track_object_refs = 0;
|
||||
|
||||
static struct decoration ref_decorate;
|
||||
|
||||
struct object_refs *lookup_object_refs(struct object *base)
|
||||
{
|
||||
return lookup_decoration(&ref_decorate, base);
|
||||
}
|
||||
|
||||
static void add_object_refs(struct object *obj, struct object_refs *refs)
|
||||
{
|
||||
if (add_decoration(&ref_decorate, obj, refs))
|
||||
die("object %s tried to add refs twice!", sha1_to_hex(obj->sha1));
|
||||
}
|
||||
|
||||
struct object_refs *alloc_object_refs(unsigned count)
|
||||
{
|
||||
struct object_refs *refs;
|
||||
size_t size = sizeof(*refs) + count*sizeof(struct object *);
|
||||
|
||||
refs = xcalloc(1, size);
|
||||
refs->count = count;
|
||||
return refs;
|
||||
}
|
||||
|
||||
static int compare_object_pointers(const void *a, const void *b)
|
||||
{
|
||||
const struct object * const *pa = a;
|
||||
const struct object * const *pb = b;
|
||||
if (*pa == *pb)
|
||||
return 0;
|
||||
else if (*pa < *pb)
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
void set_object_refs(struct object *obj, struct object_refs *refs)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
/* Do not install empty list of references */
|
||||
if (refs->count < 1) {
|
||||
free(refs);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Sort the list and filter out duplicates */
|
||||
qsort(refs->ref, refs->count, sizeof(refs->ref[0]),
|
||||
compare_object_pointers);
|
||||
for (i = j = 1; i < refs->count; i++) {
|
||||
if (refs->ref[i] != refs->ref[i - 1])
|
||||
refs->ref[j++] = refs->ref[i];
|
||||
}
|
||||
if (j < refs->count) {
|
||||
/* Duplicates were found - reallocate list */
|
||||
size_t size = sizeof(*refs) + j*sizeof(struct object *);
|
||||
refs->count = j;
|
||||
refs = xrealloc(refs, size);
|
||||
}
|
||||
|
||||
for (i = 0; i < refs->count; i++)
|
||||
refs->ref[i]->used = 1;
|
||||
add_object_refs(obj, refs);
|
||||
}
|
||||
|
||||
void mark_reachable(struct object *obj, unsigned int mask)
|
||||
{
|
||||
const struct object_refs *refs;
|
||||
|
||||
if (!track_object_refs)
|
||||
die("cannot do reachability with object refs turned off");
|
||||
/* If we've been here already, don't bother */
|
||||
if (obj->flags & mask)
|
||||
return;
|
||||
obj->flags |= mask;
|
||||
refs = lookup_object_refs(obj);
|
||||
if (refs) {
|
||||
unsigned i;
|
||||
for (i = 0; i < refs->count; i++)
|
||||
mark_reachable(refs->ref[i], mask);
|
||||
}
|
||||
}
|
||||
8
object.h
8
object.h
@@ -35,14 +35,11 @@ struct object {
|
||||
unsigned char sha1[20];
|
||||
};
|
||||
|
||||
extern int track_object_refs;
|
||||
|
||||
extern const char *typename(unsigned int type);
|
||||
extern int type_from_string(const char *str);
|
||||
|
||||
extern unsigned int get_max_object_index(void);
|
||||
extern struct object *get_indexed_object(unsigned int);
|
||||
extern struct object_refs *lookup_object_refs(struct object *);
|
||||
|
||||
/** Internal only **/
|
||||
struct object *lookup_object(const unsigned char *sha1);
|
||||
@@ -61,11 +58,6 @@ struct object *parse_object_buffer(const unsigned char *sha1, enum object_type t
|
||||
/** Returns the object, with potentially excess memory allocated. **/
|
||||
struct object *lookup_unknown_object(const unsigned char *sha1);
|
||||
|
||||
struct object_refs *alloc_object_refs(unsigned count);
|
||||
void set_object_refs(struct object *obj, struct object_refs *refs);
|
||||
|
||||
void mark_reachable(struct object *obj, unsigned int mask);
|
||||
|
||||
struct object_list *object_list_insert(struct object *item,
|
||||
struct object_list **list_p);
|
||||
|
||||
|
||||
11
pack-check.c
11
pack-check.c
@@ -1,5 +1,6 @@
|
||||
#include "cache.h"
|
||||
#include "pack.h"
|
||||
#include "pack-revindex.h"
|
||||
|
||||
struct idx_entry
|
||||
{
|
||||
@@ -101,8 +102,10 @@ static int verify_packfile(struct packed_git *p,
|
||||
static void show_pack_info(struct packed_git *p)
|
||||
{
|
||||
uint32_t nr_objects, i, chain_histogram[MAX_CHAIN+1];
|
||||
|
||||
nr_objects = p->num_objects;
|
||||
memset(chain_histogram, 0, sizeof(chain_histogram));
|
||||
init_pack_revindex();
|
||||
|
||||
for (i = 0; i < nr_objects; i++) {
|
||||
const unsigned char *sha1;
|
||||
@@ -125,11 +128,11 @@ static void show_pack_info(struct packed_git *p)
|
||||
base_sha1);
|
||||
printf("%s ", sha1_to_hex(sha1));
|
||||
if (!delta_chain_length)
|
||||
printf("%-6s %lu %"PRIuMAX"\n",
|
||||
type, size, (uintmax_t)offset);
|
||||
printf("%-6s %lu %lu %"PRIuMAX"\n",
|
||||
type, size, store_size, (uintmax_t)offset);
|
||||
else {
|
||||
printf("%-6s %lu %"PRIuMAX" %u %s\n",
|
||||
type, size, (uintmax_t)offset,
|
||||
printf("%-6s %lu %lu %"PRIuMAX" %u %s\n",
|
||||
type, size, store_size, (uintmax_t)offset,
|
||||
delta_chain_length, sha1_to_hex(base_sha1));
|
||||
if (delta_chain_length <= MAX_CHAIN)
|
||||
chain_histogram[delta_chain_length]++;
|
||||
|
||||
142
pack-revindex.c
Normal file
142
pack-revindex.c
Normal file
@@ -0,0 +1,142 @@
|
||||
#include "cache.h"
|
||||
#include "pack-revindex.h"
|
||||
|
||||
/*
|
||||
* Pack index for existing packs give us easy access to the offsets into
|
||||
* corresponding pack file where each object's data starts, but the entries
|
||||
* do not store the size of the compressed representation (uncompressed
|
||||
* size is easily available by examining the pack entry header). It is
|
||||
* also rather expensive to find the sha1 for an object given its offset.
|
||||
*
|
||||
* We build a hashtable of existing packs (pack_revindex), and keep reverse
|
||||
* index here -- pack index file is sorted by object name mapping to offset;
|
||||
* this pack_revindex[].revindex array is a list of offset/index_nr pairs
|
||||
* ordered by offset, so if you know the offset of an object, next offset
|
||||
* is where its packed representation ends and the index_nr can be used to
|
||||
* get the object sha1 from the main index.
|
||||
*/
|
||||
|
||||
struct pack_revindex {
|
||||
struct packed_git *p;
|
||||
struct revindex_entry *revindex;
|
||||
};
|
||||
|
||||
static struct pack_revindex *pack_revindex;
|
||||
static int pack_revindex_hashsz;
|
||||
|
||||
static int pack_revindex_ix(struct packed_git *p)
|
||||
{
|
||||
unsigned long ui = (unsigned long)p;
|
||||
int i;
|
||||
|
||||
ui = ui ^ (ui >> 16); /* defeat structure alignment */
|
||||
i = (int)(ui % pack_revindex_hashsz);
|
||||
while (pack_revindex[i].p) {
|
||||
if (pack_revindex[i].p == p)
|
||||
return i;
|
||||
if (++i == pack_revindex_hashsz)
|
||||
i = 0;
|
||||
}
|
||||
return -1 - i;
|
||||
}
|
||||
|
||||
void init_pack_revindex(void)
|
||||
{
|
||||
int num;
|
||||
struct packed_git *p;
|
||||
|
||||
for (num = 0, p = packed_git; p; p = p->next)
|
||||
num++;
|
||||
if (!num)
|
||||
return;
|
||||
pack_revindex_hashsz = num * 11;
|
||||
pack_revindex = xcalloc(sizeof(*pack_revindex), pack_revindex_hashsz);
|
||||
for (p = packed_git; p; p = p->next) {
|
||||
num = pack_revindex_ix(p);
|
||||
num = - 1 - num;
|
||||
pack_revindex[num].p = p;
|
||||
}
|
||||
/* revindex elements are lazily initialized */
|
||||
}
|
||||
|
||||
static int cmp_offset(const void *a_, const void *b_)
|
||||
{
|
||||
const struct revindex_entry *a = a_;
|
||||
const struct revindex_entry *b = b_;
|
||||
return (a->offset < b->offset) ? -1 : (a->offset > b->offset) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ordered list of offsets of objects in the pack.
|
||||
*/
|
||||
static void create_pack_revindex(struct pack_revindex *rix)
|
||||
{
|
||||
struct packed_git *p = rix->p;
|
||||
int num_ent = p->num_objects;
|
||||
int i;
|
||||
const char *index = p->index_data;
|
||||
|
||||
rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1));
|
||||
index += 4 * 256;
|
||||
|
||||
if (p->index_version > 1) {
|
||||
const uint32_t *off_32 =
|
||||
(uint32_t *)(index + 8 + p->num_objects * (20 + 4));
|
||||
const uint32_t *off_64 = off_32 + p->num_objects;
|
||||
for (i = 0; i < num_ent; i++) {
|
||||
uint32_t off = ntohl(*off_32++);
|
||||
if (!(off & 0x80000000)) {
|
||||
rix->revindex[i].offset = off;
|
||||
} else {
|
||||
rix->revindex[i].offset =
|
||||
((uint64_t)ntohl(*off_64++)) << 32;
|
||||
rix->revindex[i].offset |=
|
||||
ntohl(*off_64++);
|
||||
}
|
||||
rix->revindex[i].nr = i;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < num_ent; i++) {
|
||||
uint32_t hl = *((uint32_t *)(index + 24 * i));
|
||||
rix->revindex[i].offset = ntohl(hl);
|
||||
rix->revindex[i].nr = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* This knows the pack format -- the 20-byte trailer
|
||||
* follows immediately after the last object data.
|
||||
*/
|
||||
rix->revindex[num_ent].offset = p->pack_size - 20;
|
||||
rix->revindex[num_ent].nr = -1;
|
||||
qsort(rix->revindex, num_ent, sizeof(*rix->revindex), cmp_offset);
|
||||
}
|
||||
|
||||
struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs)
|
||||
{
|
||||
int num;
|
||||
int lo, hi;
|
||||
struct pack_revindex *rix;
|
||||
struct revindex_entry *revindex;
|
||||
|
||||
num = pack_revindex_ix(p);
|
||||
if (num < 0)
|
||||
die("internal error: pack revindex uninitialized");
|
||||
|
||||
rix = &pack_revindex[num];
|
||||
if (!rix->revindex)
|
||||
create_pack_revindex(rix);
|
||||
revindex = rix->revindex;
|
||||
|
||||
lo = 0;
|
||||
hi = p->num_objects + 1;
|
||||
do {
|
||||
int mi = (lo + hi) / 2;
|
||||
if (revindex[mi].offset == ofs) {
|
||||
return revindex + mi;
|
||||
} else if (ofs < revindex[mi].offset)
|
||||
hi = mi;
|
||||
else
|
||||
lo = mi + 1;
|
||||
} while (lo < hi);
|
||||
die("internal error: pack revindex corrupt");
|
||||
}
|
||||
12
pack-revindex.h
Normal file
12
pack-revindex.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef PACK_REVINDEX_H
|
||||
#define PACK_REVINDEX_H
|
||||
|
||||
struct revindex_entry {
|
||||
off_t offset;
|
||||
unsigned int nr;
|
||||
};
|
||||
|
||||
void init_pack_revindex(void);
|
||||
struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs);
|
||||
|
||||
#endif
|
||||
4
path.c
4
path.c
@@ -318,8 +318,10 @@ const char *make_absolute_path(const char *path)
|
||||
if (last_slash) {
|
||||
*last_slash = '\0';
|
||||
last_elem = xstrdup(last_slash + 1);
|
||||
} else
|
||||
} else {
|
||||
last_elem = xstrdup(buf);
|
||||
*buf = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (*buf) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
|
||||
|
||||
static int deny_non_fast_forwards = 0;
|
||||
static int receive_fsck_objects = 1;
|
||||
static int receive_unpack_limit = -1;
|
||||
static int transfer_unpack_limit = -1;
|
||||
static int unpack_limit = 100;
|
||||
@@ -35,6 +36,11 @@ static int receive_pack_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(var, "receive.fsckobjects") == 0) {
|
||||
receive_fsck_objects = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
@@ -368,11 +374,13 @@ static const char *unpack(void)
|
||||
ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
|
||||
|
||||
if (ntohl(hdr.hdr_entries) < unpack_limit) {
|
||||
int code;
|
||||
const char *unpacker[3];
|
||||
unpacker[0] = "unpack-objects";
|
||||
unpacker[1] = hdr_arg;
|
||||
unpacker[2] = NULL;
|
||||
int code, i = 0;
|
||||
const char *unpacker[4];
|
||||
unpacker[i++] = "unpack-objects";
|
||||
if (receive_fsck_objects)
|
||||
unpacker[i++] = "--strict";
|
||||
unpacker[i++] = hdr_arg;
|
||||
unpacker[i++] = NULL;
|
||||
code = run_command_v_opt(unpacker, RUN_GIT_CMD);
|
||||
switch (code) {
|
||||
case 0:
|
||||
@@ -393,8 +401,8 @@ static const char *unpack(void)
|
||||
return "unpacker exited with error code";
|
||||
}
|
||||
} else {
|
||||
const char *keeper[6];
|
||||
int s, status;
|
||||
const char *keeper[7];
|
||||
int s, status, i = 0;
|
||||
char keep_arg[256];
|
||||
struct child_process ip;
|
||||
|
||||
@@ -402,12 +410,14 @@ static const char *unpack(void)
|
||||
if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
|
||||
strcpy(keep_arg + s, "localhost");
|
||||
|
||||
keeper[0] = "index-pack";
|
||||
keeper[1] = "--stdin";
|
||||
keeper[2] = "--fix-thin";
|
||||
keeper[3] = hdr_arg;
|
||||
keeper[4] = keep_arg;
|
||||
keeper[5] = NULL;
|
||||
keeper[i++] = "index-pack";
|
||||
keeper[i++] = "--stdin";
|
||||
if (receive_fsck_objects)
|
||||
keeper[i++] = "--strict";
|
||||
keeper[i++] = "--fix-thin";
|
||||
keeper[i++] = hdr_arg;
|
||||
keeper[i++] = keep_arg;
|
||||
keeper[i++] = NULL;
|
||||
memset(&ip, 0, sizeof(ip));
|
||||
ip.argv = keeper;
|
||||
ip.out = -1;
|
||||
@@ -471,6 +481,8 @@ int main(int argc, char **argv)
|
||||
if (!dir)
|
||||
usage(receive_pack_usage);
|
||||
|
||||
setup_path(NULL);
|
||||
|
||||
if (!enter_repo(dir, 0))
|
||||
die("'%s': unable to chdir or not a git archive", dir);
|
||||
|
||||
|
||||
12
revision.c
12
revision.c
@@ -772,14 +772,9 @@ static void prepare_show_merge(struct rev_info *revs)
|
||||
add_pending_object(revs, &head->object, "HEAD");
|
||||
add_pending_object(revs, &other->object, "MERGE_HEAD");
|
||||
bases = get_merge_bases(head, other, 1);
|
||||
while (bases) {
|
||||
struct commit *it = bases->item;
|
||||
struct commit_list *n = bases->next;
|
||||
free(bases);
|
||||
bases = n;
|
||||
it->object.flags |= UNINTERESTING;
|
||||
add_pending_object(revs, &it->object, "(merge-base)");
|
||||
}
|
||||
add_pending_commit_list(revs, bases, UNINTERESTING);
|
||||
free_commit_list(bases);
|
||||
head->object.flags |= SYMMETRIC_LEFT;
|
||||
|
||||
if (!active_nr)
|
||||
read_cache();
|
||||
@@ -798,6 +793,7 @@ static void prepare_show_merge(struct rev_info *revs)
|
||||
i++;
|
||||
}
|
||||
revs->prune_data = prune;
|
||||
revs->limited = 1;
|
||||
}
|
||||
|
||||
int handle_revision_arg(const char *arg, struct rev_info *revs,
|
||||
|
||||
10
sha1_file.c
10
sha1_file.c
@@ -14,6 +14,7 @@
|
||||
#include "tag.h"
|
||||
#include "tree.h"
|
||||
#include "refs.h"
|
||||
#include "pack-revindex.h"
|
||||
|
||||
#ifndef O_NOATIME
|
||||
#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
|
||||
@@ -1375,11 +1376,15 @@ const char *packed_object_info_detail(struct packed_git *p,
|
||||
unsigned long dummy;
|
||||
unsigned char *next_sha1;
|
||||
enum object_type type;
|
||||
struct revindex_entry *revidx;
|
||||
|
||||
*delta_chain_length = 0;
|
||||
curpos = obj_offset;
|
||||
type = unpack_object_header(p, &w_curs, &curpos, size);
|
||||
|
||||
revidx = find_pack_revindex(p, obj_offset);
|
||||
*store_size = revidx[1].offset - obj_offset;
|
||||
|
||||
for (;;) {
|
||||
switch (type) {
|
||||
default:
|
||||
@@ -1389,14 +1394,13 @@ const char *packed_object_info_detail(struct packed_git *p,
|
||||
case OBJ_TREE:
|
||||
case OBJ_BLOB:
|
||||
case OBJ_TAG:
|
||||
*store_size = 0; /* notyet */
|
||||
unuse_pack(&w_curs);
|
||||
return typename(type);
|
||||
case OBJ_OFS_DELTA:
|
||||
obj_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset);
|
||||
if (*delta_chain_length == 0) {
|
||||
/* TODO: find base_sha1 as pointed by curpos */
|
||||
hashclr(base_sha1);
|
||||
revidx = find_pack_revindex(p, obj_offset);
|
||||
hashcpy(base_sha1, nth_packed_object_sha1(p, revidx->nr));
|
||||
}
|
||||
break;
|
||||
case OBJ_REF_DELTA:
|
||||
|
||||
13
sha1_name.c
13
sha1_name.c
@@ -192,26 +192,25 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
|
||||
|
||||
const char *find_unique_abbrev(const unsigned char *sha1, int len)
|
||||
{
|
||||
int status, is_null;
|
||||
int status, exists;
|
||||
static char hex[41];
|
||||
|
||||
is_null = is_null_sha1(sha1);
|
||||
exists = has_sha1_file(sha1);
|
||||
memcpy(hex, sha1_to_hex(sha1), 40);
|
||||
if (len == 40 || !len)
|
||||
return hex;
|
||||
while (len < 40) {
|
||||
unsigned char sha1_ret[20];
|
||||
status = get_short_sha1(hex, len, sha1_ret, 1);
|
||||
if (!status ||
|
||||
(is_null && status != SHORT_NAME_AMBIGUOUS)) {
|
||||
if (exists
|
||||
? !status
|
||||
: status == SHORT_NAME_NOT_FOUND) {
|
||||
hex[len] = 0;
|
||||
return hex;
|
||||
}
|
||||
if (status != SHORT_NAME_AMBIGUOUS)
|
||||
return NULL;
|
||||
len++;
|
||||
}
|
||||
return NULL;
|
||||
return hex;
|
||||
}
|
||||
|
||||
static int ambiguous_path(const char *path, int len)
|
||||
|
||||
96
t/lib-httpd.sh
Normal file
96
t/lib-httpd.sh
Normal file
@@ -0,0 +1,96 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2008 Clemens Buchacher <drizzd@aon.at>
|
||||
#
|
||||
|
||||
if test -z "$GIT_TEST_HTTPD"
|
||||
then
|
||||
say "skipping test, network testing disabled by default"
|
||||
say "(define GIT_TEST_HTTPD to enable)"
|
||||
test_done
|
||||
exit
|
||||
fi
|
||||
|
||||
LIB_HTTPD_PATH=${LIB_HTTPD_PATH-'/usr/sbin/apache2'}
|
||||
LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'8111'}
|
||||
|
||||
TEST_PATH="$PWD"/../lib-httpd
|
||||
HTTPD_ROOT_PATH="$PWD"/httpd
|
||||
HTTPD_DOCUMENT_ROOT_PATH=$HTTPD_ROOT_PATH/www
|
||||
|
||||
if ! test -x "$LIB_HTTPD_PATH"
|
||||
then
|
||||
say "skipping test, no web server found at '$LIB_HTTPD_PATH'"
|
||||
test_done
|
||||
exit
|
||||
fi
|
||||
|
||||
HTTPD_VERSION=`$LIB_HTTPD_PATH -v | \
|
||||
sed -n 's/^Server version: Apache\/\([0-9]*\)\..*$/\1/p; q'`
|
||||
|
||||
if test -n "$HTTPD_VERSION"
|
||||
then
|
||||
if test -z "$LIB_HTTPD_MODULE_PATH"
|
||||
then
|
||||
if ! test $HTTPD_VERSION -ge 2
|
||||
then
|
||||
say "skipping test, at least Apache version 2 is required"
|
||||
test_done
|
||||
exit
|
||||
fi
|
||||
|
||||
LIB_HTTPD_MODULE_PATH='/usr/lib/apache2/modules'
|
||||
fi
|
||||
else
|
||||
error "Could not identify web server at '$LIB_HTTPD_PATH'"
|
||||
fi
|
||||
|
||||
HTTPD_PARA="-d $HTTPD_ROOT_PATH -f $TEST_PATH/apache.conf"
|
||||
|
||||
prepare_httpd() {
|
||||
mkdir -p $HTTPD_DOCUMENT_ROOT_PATH
|
||||
|
||||
ln -s $LIB_HTTPD_MODULE_PATH $HTTPD_ROOT_PATH/modules
|
||||
|
||||
if test -n "$LIB_HTTPD_SSL"
|
||||
then
|
||||
HTTPD_URL=https://127.0.0.1:$LIB_HTTPD_PORT
|
||||
|
||||
RANDFILE_PATH="$HTTPD_ROOT_PATH"/.rnd openssl req \
|
||||
-config $TEST_PATH/ssl.cnf \
|
||||
-new -x509 -nodes \
|
||||
-out $HTTPD_ROOT_PATH/httpd.pem \
|
||||
-keyout $HTTPD_ROOT_PATH/httpd.pem
|
||||
export GIT_SSL_NO_VERIFY=t
|
||||
HTTPD_PARA="$HTTPD_PARA -DSSL"
|
||||
else
|
||||
HTTPD_URL=http://127.0.0.1:$LIB_HTTPD_PORT
|
||||
fi
|
||||
|
||||
if test -n "$LIB_HTTPD_DAV" -o -n "$LIB_HTTPD_SVN"
|
||||
then
|
||||
HTTPD_PARA="$HTTPD_PARA -DDAV"
|
||||
|
||||
if test -n "$LIB_HTTPD_SVN"
|
||||
then
|
||||
HTTPD_PARA="$HTTPD_PARA -DSVN"
|
||||
rawsvnrepo="$HTTPD_ROOT_PATH/svnrepo"
|
||||
svnrepo="http://127.0.0.1:$LIB_HTTPD_PORT/svn"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
start_httpd() {
|
||||
prepare_httpd
|
||||
|
||||
trap 'stop_httpd; die' exit
|
||||
|
||||
"$LIB_HTTPD_PATH" $HTTPD_PARA \
|
||||
-c "Listen 127.0.0.1:$LIB_HTTPD_PORT" -k start
|
||||
}
|
||||
|
||||
stop_httpd() {
|
||||
trap 'die' exit
|
||||
|
||||
"$LIB_HTTPD_PATH" $HTTPD_PARA -k stop
|
||||
}
|
||||
34
t/lib-httpd/apache.conf
Normal file
34
t/lib-httpd/apache.conf
Normal file
@@ -0,0 +1,34 @@
|
||||
PidFile httpd.pid
|
||||
DocumentRoot www
|
||||
ErrorLog error.log
|
||||
|
||||
<IfDefine SSL>
|
||||
LoadModule ssl_module modules/mod_ssl.so
|
||||
|
||||
SSLCertificateFile httpd.pem
|
||||
SSLCertificateKeyFile httpd.pem
|
||||
SSLRandomSeed startup file:/dev/urandom 512
|
||||
SSLRandomSeed connect file:/dev/urandom 512
|
||||
SSLSessionCache none
|
||||
SSLMutex file:ssl_mutex
|
||||
SSLEngine On
|
||||
</IfDefine>
|
||||
|
||||
<IfDefine DAV>
|
||||
LoadModule dav_module modules/mod_dav.so
|
||||
LoadModule dav_fs_module modules/mod_dav_fs.so
|
||||
|
||||
DAVLockDB DAVLock
|
||||
<Location />
|
||||
Dav on
|
||||
</Location>
|
||||
</IfDefine>
|
||||
|
||||
<IfDefine SVN>
|
||||
LoadModule dav_svn_module modules/mod_dav_svn.so
|
||||
|
||||
<Location /svn>
|
||||
DAV svn
|
||||
SVNPath svnrepo
|
||||
</Location>
|
||||
</IfDefine>
|
||||
8
t/lib-httpd/ssl.cnf
Normal file
8
t/lib-httpd/ssl.cnf
Normal file
@@ -0,0 +1,8 @@
|
||||
RANDFILE = $ENV::RANDFILE_PATH
|
||||
|
||||
[ req ]
|
||||
default_bits = 1024
|
||||
distinguished_name = req_distinguished_name
|
||||
prompt = no
|
||||
[ req_distinguished_name ]
|
||||
commonName = 127.0.0.1
|
||||
@@ -329,6 +329,8 @@ test_expect_success 'absolute path works as expected' '
|
||||
test "$dir" = "$(test-absolute-path $dir2)" &&
|
||||
file="$dir"/index &&
|
||||
test "$file" = "$(test-absolute-path $dir2/index)" &&
|
||||
basename=blub &&
|
||||
test "$dir/$basename" = $(cd .git && test-absolute-path $basename) &&
|
||||
ln -s ../first/file .git/syml &&
|
||||
sym="$(cd first; pwd -P)"/file &&
|
||||
test "$sym" = "$(test-absolute-path $dir2/syml)"
|
||||
|
||||
@@ -29,7 +29,7 @@ test_expect_success 'rebase --abort' '
|
||||
test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase)
|
||||
'
|
||||
|
||||
test_expect_failure 'rebase --abort after --skip' '
|
||||
test_expect_success 'rebase --abort after --skip' '
|
||||
# Clean up the state from the previous one
|
||||
git reset --hard pre-rebase
|
||||
rm -rf .dotest
|
||||
|
||||
@@ -59,4 +59,13 @@ test_expect_success 'revert after renaming branch' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'revert forbidden on dirty working tree' '
|
||||
|
||||
echo content >extra_file &&
|
||||
git add extra_file &&
|
||||
test_must_fail git revert HEAD 2>errors &&
|
||||
grep "Dirty index" errors
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -7,8 +7,8 @@ Subject: [DIFFERENT_PREFIX 0/2] *** SUBJECT HERE ***
|
||||
*** BLURB HERE ***
|
||||
|
||||
A U Thor (2):
|
||||
Second
|
||||
Third
|
||||
Second
|
||||
Third
|
||||
|
||||
dir/sub | 4 ++++
|
||||
file0 | 3 +++
|
||||
|
||||
@@ -147,7 +147,7 @@ test_expect_success 'thread' '
|
||||
for i in patches/0002-* patches/0003-*
|
||||
do
|
||||
grep "References: $FIRST_MID" $i &&
|
||||
grep "In-Reply-To: $FIRST_MID" $i
|
||||
grep "In-Reply-To: $FIRST_MID" $i || break
|
||||
done
|
||||
'
|
||||
|
||||
@@ -160,7 +160,7 @@ test_expect_success 'thread in-reply-to' '
|
||||
for i in patches/*
|
||||
do
|
||||
grep "References: $FIRST_MID" $i &&
|
||||
grep "In-Reply-To: $FIRST_MID" $i
|
||||
grep "In-Reply-To: $FIRST_MID" $i || break
|
||||
done
|
||||
'
|
||||
|
||||
@@ -173,7 +173,7 @@ test_expect_success 'thread cover-letter' '
|
||||
for i in patches/0001-* patches/0002-* patches/0003-*
|
||||
do
|
||||
grep "References: $FIRST_MID" $i &&
|
||||
grep "In-Reply-To: $FIRST_MID" $i
|
||||
grep "In-Reply-To: $FIRST_MID" $i || break
|
||||
done
|
||||
'
|
||||
|
||||
@@ -186,7 +186,7 @@ test_expect_success 'thread cover-letter in-reply-to' '
|
||||
for i in patches/*
|
||||
do
|
||||
grep "References: $FIRST_MID" $i &&
|
||||
grep "In-Reply-To: $FIRST_MID" $i
|
||||
grep "In-Reply-To: $FIRST_MID" $i || break
|
||||
done
|
||||
'
|
||||
|
||||
@@ -201,4 +201,33 @@ test_expect_success 'excessive subject' '
|
||||
ls patches/0004-This-is-an-excessively-long-subject-line-for-a-messa.patch
|
||||
'
|
||||
|
||||
test_expect_success 'cover-letter inherits diff options' '
|
||||
|
||||
git mv file foo &&
|
||||
git commit -m foo &&
|
||||
git format-patch --cover-letter -1 &&
|
||||
! grep "file => foo .* 0 *$" 0000-cover-letter.patch &&
|
||||
git format-patch --cover-letter -1 -M &&
|
||||
grep "file => foo .* 0 *$" 0000-cover-letter.patch
|
||||
|
||||
'
|
||||
|
||||
cat > expect << EOF
|
||||
This is an excessively long subject line for a message due to the
|
||||
habit some projects have of not having a short, one-line subject at
|
||||
the start of the commit message, but rather sticking a whole
|
||||
paragraph right at the start as the only thing in the commit
|
||||
message. It had better not become the filename for the patch.
|
||||
foo
|
||||
|
||||
EOF
|
||||
|
||||
test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '
|
||||
|
||||
git format-patch --cover-letter -2 &&
|
||||
sed -e "1,/A U Thor/d" -e "/^$/q" < 0000-cover-letter.patch > output &&
|
||||
git diff expect output
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
53
t/t4027-diff-submodule.sh
Executable file
53
t/t4027-diff-submodule.sh
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='difference in submodules'
|
||||
|
||||
. ./test-lib.sh
|
||||
. ../diff-lib.sh
|
||||
|
||||
_z40=0000000000000000000000000000000000000000
|
||||
test_expect_success setup '
|
||||
test_tick &&
|
||||
test_create_repo sub &&
|
||||
(
|
||||
cd sub &&
|
||||
echo hello >world &&
|
||||
git add world &&
|
||||
git commit -m submodule
|
||||
) &&
|
||||
|
||||
test_tick &&
|
||||
echo frotz >nitfol &&
|
||||
git add nitfol sub &&
|
||||
git commit -m superproject &&
|
||||
|
||||
(
|
||||
cd sub &&
|
||||
echo goodbye >world &&
|
||||
git add world &&
|
||||
git commit -m "submodule #2"
|
||||
) &&
|
||||
|
||||
set x $(
|
||||
cd sub &&
|
||||
git rev-list HEAD
|
||||
) &&
|
||||
echo ":160000 160000 $3 $_z40 M sub" >expect
|
||||
'
|
||||
|
||||
test_expect_success 'git diff --raw HEAD' '
|
||||
git diff --raw --abbrev=40 HEAD >actual &&
|
||||
diff -u expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'git diff-index --raw HEAD' '
|
||||
git diff-index --raw HEAD >actual.index &&
|
||||
diff -u expect actual.index
|
||||
'
|
||||
|
||||
test_expect_success 'git diff-files --raw' '
|
||||
git diff-files --raw >actual.files &&
|
||||
diff -u expect actual.files
|
||||
'
|
||||
|
||||
test_done
|
||||
73
t/t5540-http-push.sh
Executable file
73
t/t5540-http-push.sh
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2008 Clemens Buchacher <drizzd@aon.at>
|
||||
#
|
||||
|
||||
test_description='test http-push
|
||||
|
||||
This test runs various sanity checks on http-push.'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
ROOT_PATH="$PWD"
|
||||
LIB_HTTPD_DAV=t
|
||||
|
||||
. ../lib-httpd.sh
|
||||
|
||||
if ! start_httpd >&3 2>&4
|
||||
then
|
||||
say "skipping test, web server setup failed"
|
||||
test_done
|
||||
exit
|
||||
fi
|
||||
|
||||
test_expect_success 'setup remote repository' '
|
||||
cd "$ROOT_PATH" &&
|
||||
mkdir test_repo &&
|
||||
cd test_repo &&
|
||||
git init &&
|
||||
: >path1 &&
|
||||
git add path1 &&
|
||||
test_tick &&
|
||||
git commit -m initial &&
|
||||
cd - &&
|
||||
git clone --bare test_repo test_repo.git &&
|
||||
cd test_repo.git &&
|
||||
git --bare update-server-info &&
|
||||
chmod +x hooks/post-update &&
|
||||
cd - &&
|
||||
mv test_repo.git $HTTPD_DOCUMENT_ROOT_PATH
|
||||
'
|
||||
|
||||
test_expect_success 'clone remote repository' '
|
||||
cd "$ROOT_PATH" &&
|
||||
git clone $HTTPD_URL/test_repo.git test_repo_clone
|
||||
'
|
||||
|
||||
test_expect_success 'push to remote repository' '
|
||||
cd "$ROOT_PATH"/test_repo_clone &&
|
||||
: >path2 &&
|
||||
git add path2 &&
|
||||
test_tick &&
|
||||
git commit -m path2 &&
|
||||
git push
|
||||
'
|
||||
|
||||
test_expect_success 'create and delete remote branch' '
|
||||
cd "$ROOT_PATH"/test_repo_clone &&
|
||||
git checkout -b dev &&
|
||||
: >path3 &&
|
||||
git add path3 &&
|
||||
test_tick &&
|
||||
git commit -m dev &&
|
||||
git push origin dev &&
|
||||
git fetch &&
|
||||
git push origin :dev &&
|
||||
git branch -d -r origin/dev &&
|
||||
git fetch &&
|
||||
! git show-ref --verify refs/remotes/origin/dev
|
||||
'
|
||||
|
||||
stop_httpd
|
||||
|
||||
test_done
|
||||
@@ -94,4 +94,6 @@ check_describe D-* --tags HEAD^^
|
||||
check_describe A-* --tags HEAD^^2
|
||||
check_describe B --tags HEAD^^2^
|
||||
|
||||
check_describe B-0-* --long HEAD^^2^
|
||||
|
||||
test_done
|
||||
|
||||
@@ -80,7 +80,7 @@ do
|
||||
-q|--q|--qu|--qui|--quie|--quiet)
|
||||
quiet=t; shift ;;
|
||||
--no-color)
|
||||
color=; shift ;;
|
||||
color=; shift ;;
|
||||
--no-python)
|
||||
# noop now...
|
||||
shift ;;
|
||||
@@ -142,7 +142,12 @@ test_count=0
|
||||
test_fixed=0
|
||||
test_broken=0
|
||||
|
||||
trap 'echo >&5 "FATAL: Unexpected exit with code $?"; exit 1' exit
|
||||
die () {
|
||||
echo >&5 "FATAL: Unexpected exit with code $?"
|
||||
exit 1
|
||||
}
|
||||
|
||||
trap 'die' exit
|
||||
|
||||
test_tick () {
|
||||
if test -z "${test_tick+set}"
|
||||
|
||||
6
tag.c
6
tag.c
@@ -87,12 +87,6 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
|
||||
item->tagged = NULL;
|
||||
}
|
||||
|
||||
if (item->tagged && track_object_refs) {
|
||||
struct object_refs *refs = alloc_object_refs(1);
|
||||
refs->ref[0] = item->tagged;
|
||||
set_object_refs(&item->object, refs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -442,7 +442,8 @@ static struct ref *get_refs_via_curl(struct transport *transport)
|
||||
struct ref *last_ref = NULL;
|
||||
|
||||
if (!transport->data)
|
||||
transport->data = get_http_walker(transport->url);
|
||||
transport->data = get_http_walker(transport->url,
|
||||
transport->remote);
|
||||
|
||||
refs_url = xmalloc(strlen(transport->url) + 11);
|
||||
sprintf(refs_url, "%s/info/refs", transport->url);
|
||||
@@ -453,9 +454,6 @@ static struct ref *get_refs_via_curl(struct transport *transport)
|
||||
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_URL, refs_url);
|
||||
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
|
||||
if (transport->remote->http_proxy)
|
||||
curl_easy_setopt(slot->curl, CURLOPT_PROXY,
|
||||
transport->remote->http_proxy);
|
||||
|
||||
if (start_active_slot(slot)) {
|
||||
run_active_slot(slot);
|
||||
@@ -509,7 +507,8 @@ static int fetch_objs_via_curl(struct transport *transport,
|
||||
int nr_objs, struct ref **to_fetch)
|
||||
{
|
||||
if (!transport->data)
|
||||
transport->data = get_http_walker(transport->url);
|
||||
transport->data = get_http_walker(transport->url,
|
||||
transport->remote);
|
||||
return fetch_objs_via_walker(transport, nr_objs, to_fetch);
|
||||
}
|
||||
|
||||
|
||||
48
tree.c
48
tree.c
@@ -202,52 +202,6 @@ struct tree *lookup_tree(const unsigned char *sha1)
|
||||
return (struct tree *) obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE! Tree refs to external git repositories
|
||||
* (ie gitlinks) do not count as real references.
|
||||
*
|
||||
* You don't have to have those repositories
|
||||
* available at all, much less have the objects
|
||||
* accessible from the current repository.
|
||||
*/
|
||||
static void track_tree_refs(struct tree *item)
|
||||
{
|
||||
int n_refs = 0, i;
|
||||
struct object_refs *refs;
|
||||
struct tree_desc desc;
|
||||
struct name_entry entry;
|
||||
|
||||
/* Count how many entries there are.. */
|
||||
init_tree_desc(&desc, item->buffer, item->size);
|
||||
while (tree_entry(&desc, &entry)) {
|
||||
if (S_ISGITLINK(entry.mode))
|
||||
continue;
|
||||
n_refs++;
|
||||
}
|
||||
|
||||
/* Allocate object refs and walk it again.. */
|
||||
i = 0;
|
||||
refs = alloc_object_refs(n_refs);
|
||||
init_tree_desc(&desc, item->buffer, item->size);
|
||||
while (tree_entry(&desc, &entry)) {
|
||||
struct object *obj;
|
||||
|
||||
if (S_ISGITLINK(entry.mode))
|
||||
continue;
|
||||
if (S_ISDIR(entry.mode))
|
||||
obj = &lookup_tree(entry.sha1)->object;
|
||||
else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode))
|
||||
obj = &lookup_blob(entry.sha1)->object;
|
||||
else {
|
||||
warning("in tree %s: entry %s has bad mode %.6o\n",
|
||||
sha1_to_hex(item->object.sha1), entry.path, entry.mode);
|
||||
obj = lookup_unknown_object(entry.sha1);
|
||||
}
|
||||
refs->ref[i++] = obj;
|
||||
}
|
||||
set_object_refs(&item->object, refs);
|
||||
}
|
||||
|
||||
int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
|
||||
{
|
||||
if (item->object.parsed)
|
||||
@@ -256,8 +210,6 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
|
||||
item->buffer = buffer;
|
||||
item->size = size;
|
||||
|
||||
if (track_object_refs)
|
||||
track_tree_refs(item);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -395,7 +395,6 @@ static int get_common_commits(void)
|
||||
char hex[41], last_hex[41];
|
||||
int len;
|
||||
|
||||
track_object_refs = 0;
|
||||
save_commit_buffer = 0;
|
||||
|
||||
for(;;) {
|
||||
|
||||
1
walker.c
1
walker.c
@@ -256,7 +256,6 @@ int walker_fetch(struct walker *walker, int targets, char **target,
|
||||
int i;
|
||||
|
||||
save_commit_buffer = 0;
|
||||
track_object_refs = 0;
|
||||
|
||||
for (i = 0; i < targets; i++) {
|
||||
if (!write_ref || !write_ref[i])
|
||||
|
||||
4
walker.h
4
walker.h
@@ -1,6 +1,8 @@
|
||||
#ifndef WALKER_H
|
||||
#define WALKER_H
|
||||
|
||||
#include "remote.h"
|
||||
|
||||
struct walker {
|
||||
void *data;
|
||||
int (*fetch_ref)(struct walker *, char *ref, unsigned char *sha1);
|
||||
@@ -32,6 +34,6 @@ int walker_fetch(struct walker *impl, int targets, char **target,
|
||||
|
||||
void walker_free(struct walker *walker);
|
||||
|
||||
struct walker *get_http_walker(const char *url);
|
||||
struct walker *get_http_walker(const char *url, struct remote *remote);
|
||||
|
||||
#endif /* WALKER_H */
|
||||
|
||||
Reference in New Issue
Block a user