提交 8ac93bc9 编写于 作者: J Junio C Hamano

Merge branch 'master' of .

......@@ -6,7 +6,6 @@ git-applypatch
git-archimport
git-bisect
git-branch
git-build-rev-cache
git-cat-file
git-checkout
git-checkout-index
......@@ -73,13 +72,15 @@ git-rev-list
git-rev-parse
git-rev-tree
git-revert
git-send-email
git-send-pack
git-sh-setup
git-shortlog
git-show-branch
git-show-index
git-show-rev-cache
git-ssh-fetch
git-ssh-pull
git-ssh-push
git-ssh-upload
git-status
git-stripspace
......
......@@ -45,7 +45,7 @@ man1: $(DOC_MAN1)
man7: $(DOC_MAN7)
install:
$(INSTALL) -m755 -d $(DESTDIR)/$(man1) $(DESTDIR)/$(man7)
$(INSTALL) -d -m755 $(DESTDIR)/$(man1) $(DESTDIR)/$(man7)
$(INSTALL) $(DOC_MAN1) $(DESTDIR)/$(man1)
$(INSTALL) $(DOC_MAN7) $(DESTDIR)/$(man7)
......
git-build-rev-cache(1)
======================
NAME
----
git-build-rev-cache - Create or update a rev-cache file.
SYNOPSIS
--------
'git-build-rev-cache' [-v] <rev-cache-file> < list-of-heads
DESCRIPTION
-----------
Creates or updates a file that describes the commit ancestry reachable
from the list-of-head read from stdin. This file is in an append-only
binary format to make the server side friendly to rsync mirroring
scheme, and can be read by the git-show-rev-cache command.
OPTIONS
-------
-v::
Verbose.
<rev-cache-file>::
The rev-cache to operate on.
Author
------
Written by Junio C Hamano <junkio@cox.net>
Documentation
--------------
Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
GIT
---
Part of the link:git.html[git] suite
......@@ -26,6 +26,12 @@ OPTIONS
-------
include::pull-fetch-param.txt[]
-u, \--update-head-ok::
By default 'git-fetch' refuses to update the head which
corresponds to the current branch. This flag disables the
check. Note that fetching into the current branch will not
update the index and working directory, so use it with care.
Author
------
......
......@@ -32,8 +32,11 @@ I have the commit object 'bar', but not 'foo'".
The *--bisect* flag limits output to the one commit object which is
roughly halfway between the included and excluded commits. Thus,
if "git-rev-list --bisect foo ^bar ^baz" outputs 'midpoint', the output
of "git-rev-list foo ^midpoint" and "git-rev-list midpoint ^bar ^baz"
if 'git-rev-list --bisect foo ^bar
^baz' outputs 'midpoint', the output
of 'git-rev-list foo ^midpoint' and 'git-rev-list midpoint
^bar
^baz'
would be of roughly the same length. Finding the change which introduces
a regression is thus reduced to a binary search: repeatedly generate and
test new 'midpoint's until the commit chain is of length one.
......
git-show-rev-cache(1)
=====================
NAME
----
git-show-rev-cache - Show the contents of a rev-cache file.
SYNOPSIS
--------
'git-show-rev-cache' <rev-cache-file>
DESCRIPTION
-----------
Show the contents of <rev-cache-file>.
A rev-cache file describes the commit ancestry reachable from references
supplied as input to get-build-rev-cache. This file is in an
append-only binary format to make the server side friendly to rsync
mirroring scheme.
OPTIONS
-------
<rev-cache-file>::
Rev-cache file to display.
Author
------
Written by Junio C Hamano <junkio@cox.net>
Documentation
--------------
Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
GIT
---
Part of the link:git.html[git] suite
......@@ -38,8 +38,6 @@ of what they are for:
* info/refs
* info/rev-cache
BUGS
----
......
......@@ -359,9 +359,6 @@ link:git-tag.html[git-tag]::
Interrogators:
link:git-build-rev-cache.html[git-build-rev-cache]::
Create or update a rev-cache file.
link:git-cherry.html[git-cherry]::
Find commits not merged upstream.
......@@ -402,9 +399,6 @@ link:git-send-email.html[git-send-email]::
Send patch e-mails out of "format-patch --mbox" output.
Previously this command was known as git-send-email-script.
link:git-show-rev-cache.html[git-show-rev-cache]::
Show the contents of a rev-cache file.
link:git-stripspace.html[git-stripspace]::
Filter out empty lines.
......
......@@ -80,3 +80,14 @@
<ref>: when pulling/fetching, and <ref>:<ref> when
pushing. That is, do not store it locally if
fetching, and update the same name if pushing.
-a, \--append::
Append ref names and object names of fetched refs to the
existing contents of $GIT_DIR/FETCH_HEAD. Without this
option old data in $GIT_DIR/FETCH_HEAD will be overwritten.
-f, \--force::
Usually, the command refuses to update a local ref that is
not an ancestor of the remote ref used to overwrite it.
This flag disables the check. What this means is that the
local repository can lose commits; use it with care.
......@@ -117,13 +117,6 @@ info/grafts::
listing their 40-byte hexadecimal object names separated
by a space and terminated by a newline.
info/rev-cache::
No higher-level tool currently takes advantage of this
file, but it is generated when `git update-server-info`
is run. It records the commit ancestry information of
the commits in this repository in a concise binary
format, and can be read with `git-show-rev-cache`.
info/exclude::
This file, by convention among Porcelains, stores the
exclude pattern list. `git status` looks at it, but
......
......@@ -92,7 +92,7 @@ SIMPLE_PROGRAMS = \
# ... and all the rest
PROGRAMS = \
git-apply git-build-rev-cache git-cat-file \
git-apply git-cat-file \
git-checkout-index git-clone-pack git-commit-tree \
git-convert-objects git-diff-files \
git-diff-helper git-diff-index git-diff-stages \
......@@ -103,12 +103,15 @@ PROGRAMS = \
git-peek-remote git-prune-packed git-read-tree \
git-receive-pack git-rev-list git-rev-parse \
git-rev-tree git-send-pack git-show-branch \
git-show-index git-show-rev-cache git-ssh-fetch \
git-show-index git-ssh-fetch \
git-ssh-upload git-tar-tree git-unpack-file \
git-unpack-objects git-update-index git-update-server-info \
git-upload-pack git-verify-pack git-write-tree \
$(SIMPLE_PROGRAMS)
# Backward compatibility -- to be removed in 0.99.8
PROGRAMS += git-ssh-pull git-ssh-push
PYMODULES = \
gitMergeCommon.py
......@@ -125,7 +128,7 @@ LIB_FILE=libgit.a
LIB_H = \
blob.h cache.h commit.h count-delta.h csum-file.h delta.h \
diff.h epoch.h object.h pack.h pkt-line.h quote.h refs.h \
rev-cache.h run-command.h strbuf.h tag.h tree.h
run-command.h strbuf.h tag.h tree.h
DIFF_OBJS = \
diff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \
......@@ -135,7 +138,7 @@ LIB_OBJS = \
blob.o commit.o connect.o count-delta.o csum-file.o \
date.o diff-delta.o entry.o ident.o index.o \
object.o pack-check.o patch-delta.o path.o pkt-line.o \
quote.o read-cache.o refs.o rev-cache.o run-command.o \
quote.o read-cache.o refs.o run-command.o \
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
tag.o tree.o usage.o $(DIFF_OBJS)
......@@ -148,7 +151,8 @@ ifeq ($(shell uname -s),Darwin)
endif
ifeq ($(shell uname -s),SunOS)
NEEDS_SOCKET = YesPlease
PLATFORM_DEFINES += -DNO_GETDOMAINNAME=1
NEEDS_NSL = YesPlease
PLATFORM_DEFINES += -D__EXTENSIONS__
endif
ifndef SHELL_PATH
......@@ -195,6 +199,10 @@ ifdef NEEDS_SOCKET
LIBS += -lsocket
SIMPLE_LIB += -lsocket
endif
ifdef NEEDS_NSL
LIBS += -lnsl
SIMPLE_LIB += -lnsl
endif
DEFINES += '-DSHA1_HEADER=$(SHA1_HEADER)'
......@@ -250,6 +258,8 @@ git-http-fetch: fetch.o
git-local-fetch: fetch.o
git-ssh-fetch: rsh.o fetch.o
git-ssh-upload: rsh.o
git-ssh-pull: rsh.o fetch.o
git-ssh-push: rsh.o
git-http-fetch: LIBS += -lcurl
git-rev-list: LIBS += $(OPENSSL_LIBSSL)
......@@ -288,12 +298,12 @@ check:
### Installation rules
install: $(PROGRAMS) $(SCRIPTS)
$(INSTALL) -m755 -d $(DESTDIR)$(bindir)
$(INSTALL) -d -m755 $(DESTDIR)$(bindir)
$(INSTALL) $(PROGRAMS) $(SCRIPTS) $(DESTDIR)$(bindir)
$(INSTALL) git-revert $(DESTDIR)$(bindir)/git-cherry-pick
sh ./cmd-rename.sh $(DESTDIR)$(bindir)
$(MAKE) -C templates install
$(INSTALL) -m755 -d $(DESTDIR)$(GIT_PYTHON_DIR)
$(INSTALL) -d -m755 $(DESTDIR)$(GIT_PYTHON_DIR)
$(INSTALL) $(PYMODULES) $(DESTDIR)$(GIT_PYTHON_DIR)
install-doc:
......
#include "refs.h"
#include "cache.h"
#include "commit.h"
#include "rev-cache.h"
static void process_head_list(int verbose)
{
char buf[512];
while (fgets(buf, sizeof(buf), stdin)) {
unsigned char sha1[20];
struct commit *commit;
if (get_sha1_hex(buf, sha1)) {
error("ignoring: %s", buf);
continue;
}
if (!(commit = lookup_commit_reference(sha1))) {
error("not a commit: %s", sha1_to_hex(sha1));
continue;
}
record_rev_cache(commit->object.sha1, verbose ? stderr : NULL);
}
}
static const char *build_rev_cache_usage =
"git-build-rev-cache <rev-cache-file> < list-of-heads";
int main(int ac, char **av)
{
int verbose = 0;
const char *path;
while (1 < ac && av[1][0] == '-') {
if (!strcmp(av[1], "-v"))
verbose = 1;
else
usage(build_rev_cache_usage);
ac--; av++;
}
if (ac != 2)
usage(build_rev_cache_usage);
path = av[1];
/* read existing rev-cache */
read_rev_cache(path, NULL, 0);
process_head_list(verbose);
/* update the rev-cache database by appending newly found one to it */
write_rev_cache(path, path);
return 0;
}
......@@ -42,12 +42,14 @@ git-tag-script git-tag
git-verify-tag-script git-verify-tag
git-http-pull git-http-fetch
git-local-pull git-local-fetch
git-ssh-pull git-ssh-fetch
git-checkout-cache git-checkout-index
git-diff-cache git-diff-index
git-merge-cache git-merge-index
git-update-cache git-update-index
git-ssh-push git-ssh-upload
git-convert-cache git-convert-objects
git-fsck-cache git-fsck-objects
EOF
# These two are a bit more than symlinks now.
# git-ssh-push git-ssh-upload
# git-ssh-pull git-ssh-fetch
......@@ -3,6 +3,8 @@
#include "commit.h"
#include "cache.h"
int save_commit_buffer = 1;
struct sort_node
{
/*
......@@ -264,7 +266,7 @@ int parse_commit(struct commit *item)
sha1_to_hex(item->object.sha1));
}
ret = parse_commit_buffer(item, buffer, size);
if (!ret) {
if (save_commit_buffer && !ret) {
item->buffer = buffer;
return 0;
}
......
......@@ -17,6 +17,7 @@ struct commit {
char *buffer;
};
extern int save_commit_buffer;
extern const char *commit_type;
struct commit *lookup_commit(const unsigned char *sha1);
......
#define _XOPEN_SOURCE /* glibc2 needs this */
#define __EXTENSIONS__ /* solaris needs this */
#include <time.h>
#include <ctype.h>
#include "cache.h"
......
......@@ -2,13 +2,13 @@ Source: git-core
Section: devel
Priority: optional
Maintainer: Junio C Hamano <junkio@cox.net>
Build-Depends-Indep: libz-dev, libssl-dev, libcurl3-dev, asciidoc (>= 6.0.3), xmlto, debhelper (>= 4.0.0)
Build-Depends-Indep: libz-dev, libssl-dev, libcurl3-dev, asciidoc (>= 6.0.3), xmlto, debhelper (>= 4.0.0), bc
Standards-Version: 3.6.1
Package: git-core
Architecture: any
Depends: ${shlibs:Depends}, ${perl:Depends}, ${misc:Depends}, patch, rcs
Recommends: rsync, curl, ssh, libmail-sendmail-perl, libemail-valid-perl, python (>= 2.4.0)
Recommends: rsync, curl, ssh, libmail-sendmail-perl, libemail-valid-perl, python (>= 2.4.0), less
Suggests: cogito
Conflicts: git, cogito (<< 0.13)
Description: The git content addressable filesystem
......
......@@ -41,7 +41,7 @@ MAN_DESTDIR := $(DESTDIR)/$(MANDIR)
build: debian/build-stamp
debian/build-stamp:
dh_testdir
$(MAKE) prefix=$(PREFIX) PYTHON_PATH=/usr/bin/python2.4 all doc
$(MAKE) prefix=$(PREFIX) PYTHON_PATH=/usr/bin/python2.4 all doc test
touch debian/build-stamp
debian-clean:
......
......@@ -370,6 +370,7 @@ static int diff_tree_commit(const unsigned char *commit, const char *name)
}
offset += 48;
}
free(buf);
return 0;
}
......
......@@ -214,14 +214,10 @@ struct diff_filespec *alloc_filespec(const char *path)
{
int namelen = strlen(path);
struct diff_filespec *spec = xmalloc(sizeof(*spec) + namelen + 1);
memset(spec, 0, sizeof(*spec));
spec->path = (char *)(spec + 1);
strcpy(spec->path, path);
spec->should_free = spec->should_munmap = 0;
spec->xfrm_flags = 0;
spec->size = 0;
spec->data = NULL;
spec->mode = 0;
memset(spec->sha1, 0, 20);
memcpy(spec->path, path, namelen+1);
return spec;
}
......@@ -406,13 +402,14 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
return 0;
}
void diff_free_filespec(struct diff_filespec *s)
void diff_free_filespec_data(struct diff_filespec *s)
{
if (s->should_free)
free(s->data);
else if (s->should_munmap)
munmap(s->data, s->size);
free(s);
s->should_free = s->should_munmap = 0;
s->data = NULL;
}
static void prep_temp_blob(struct diff_tempfile *temp,
......@@ -765,14 +762,17 @@ struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
dp->status = 0;
dp->source_stays = 0;
dp->broken_pair = 0;
diff_q(queue, dp);
if (queue)
diff_q(queue, dp);
return dp;
}
void diff_free_filepair(struct diff_filepair *p)
{
diff_free_filespec(p->one);
diff_free_filespec(p->two);
diff_free_filespec_data(p->one);
diff_free_filespec_data(p->two);
free(p->one);
free(p->two);
free(p);
}
......
......@@ -231,8 +231,8 @@ static void merge_broken(struct diff_filepair *p,
dp = diff_queue(outq, d->one, c->two);
dp->score = p->score;
diff_free_filespec(d->two);
diff_free_filespec(c->one);
diff_free_filespec_data(d->two);
diff_free_filespec_data(c->one);
free(d);
free(c);
}
......
......@@ -47,7 +47,8 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
if (first < rename_dst_nr)
memmove(rename_dst + first + 1, rename_dst + first,
(rename_dst_nr - first - 1) * sizeof(*rename_dst));
rename_dst[first].two = two;
rename_dst[first].two = alloc_filespec(two->path);
fill_filespec(rename_dst[first].two, two->sha1, two->mode);
rename_dst[first].pair = NULL;
return &(rename_dst[first]);
}
......@@ -201,8 +202,7 @@ static int estimate_similarity(struct diff_filespec *src,
return score;
}
static void record_rename_pair(struct diff_queue_struct *renq,
int dst_index, int src_index, int score)
static void record_rename_pair(int dst_index, int src_index, int score)
{
struct diff_filespec *one, *two, *src, *dst;
struct diff_filepair *dp;
......@@ -218,7 +218,7 @@ static void record_rename_pair(struct diff_queue_struct *renq,
two = alloc_filespec(dst->path);
fill_filespec(two, dst->sha1, dst->mode);
dp = diff_queue(renq, one, two);
dp = diff_queue(NULL, one, two);
dp->score = score;
dp->source_stays = rename_src[src_index].src_path_left;
rename_dst[dst_index].pair = dp;
......@@ -252,15 +252,14 @@ static int compute_stays(struct diff_queue_struct *q,
void diffcore_rename(int detect_rename, int minimum_score)
{
struct diff_queue_struct *q = &diff_queued_diff;
struct diff_queue_struct renq, outq;
struct diff_queue_struct outq;
struct diff_score *mx;
int i, j;
int i, j, rename_count;
int num_create, num_src, dst_cnt;
if (!minimum_score)
minimum_score = DEFAULT_RENAME_SCORE;
renq.queue = NULL;
renq.nr = renq.alloc = 0;
rename_count = 0;
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
......@@ -292,19 +291,19 @@ void diffcore_rename(int detect_rename, int minimum_score)
struct diff_filespec *one = rename_src[j].one;
if (!is_exact_match(one, two))
continue;
record_rename_pair(&renq, i, j, MAX_SCORE);
record_rename_pair(i, j, MAX_SCORE);
rename_count++;
break; /* we are done with this entry */
}
}
diff_debug_queue("done detecting exact", &renq);
/* Have we run out the created file pool? If so we can avoid
* doing the delta matrix altogether.
*/
if (renq.nr == rename_dst_nr)
if (rename_count == rename_dst_nr)
goto cleanup;
num_create = (rename_dst_nr - renq.nr);
num_create = (rename_dst_nr - rename_count);
num_src = rename_src_nr;
mx = xmalloc(sizeof(*mx) * num_create * num_src);
for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
......@@ -330,14 +329,14 @@ void diffcore_rename(int detect_rename, int minimum_score)
continue; /* already done, either exact or fuzzy. */
if (mx[i].score < minimum_score)
break; /* there is no more usable pair. */
record_rename_pair(&renq, mx[i].dst, mx[i].src, mx[i].score);
record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
rename_count++;
}
free(mx);
diff_debug_queue("done detecting fuzzy", &renq);
cleanup:
/* At this point, we have found some renames and copies and they
* are kept in renq. The original list is still in *q.
* are recorded in rename_dst. The original list is still in *q.
*/
outq.queue = NULL;
outq.nr = outq.alloc = 0;
......@@ -372,9 +371,9 @@ void diffcore_rename(int detect_rename, int minimum_score)
*
* (1) this is a broken delete and the counterpart
* broken create remains in the output; or
* (2) this is not a broken delete, and renq does
* not have a rename/copy to move p->one->path
* out.
* (2) this is not a broken delete, and rename_dst
* does not have a rename/copy to move p->one->path
* out of existence.
*
* Otherwise, the counterpart broken create
* has been turned into a rename-edit; or
......@@ -390,11 +389,16 @@ void diffcore_rename(int detect_rename, int minimum_score)
pair_to_free = p;
}
else {
for (j = 0; j < renq.nr; j++)
if (!strcmp(renq.queue[j]->one->path,
p->one->path))
break;
if (j < renq.nr)
for (j = 0; j < rename_dst_nr; j++) {
if (!rename_dst[j].pair)
continue;
if (strcmp(rename_dst[j].pair->
one->path,
p->one->path))
continue;
break;
}
if (j < rename_dst_nr)
/* this path remains */
pair_to_free = p;
}
......@@ -416,7 +420,6 @@ void diffcore_rename(int detect_rename, int minimum_score)
}
diff_debug_queue("done copying original", &outq);
free(renq.queue);
free(q->queue);
*q = outq;
diff_debug_queue("done collapsing", q);
......@@ -438,6 +441,11 @@ void diffcore_rename(int detect_rename, int minimum_score)
}
}
for (i = 0; i < rename_dst_nr; i++) {
diff_free_filespec_data(rename_dst[i].two);
free(rename_dst[i].two);
}
free(rename_dst);
rename_dst = NULL;
rename_dst_nr = rename_dst_alloc = 0;
......
......@@ -43,7 +43,7 @@ extern void fill_filespec(struct diff_filespec *, const unsigned char *,
unsigned short);
extern int diff_populate_filespec(struct diff_filespec *, int);
extern void diff_free_filespec(struct diff_filespec *);
extern void diff_free_filespec_data(struct diff_filespec *);
struct diff_filepair {
struct diff_filespec *one;
......
......@@ -33,42 +33,51 @@ static void report_missing(const char *what, const unsigned char *missing)
what, missing_hex, sha1_to_hex(current_commit_sha1));
}
static int make_sure_we_have_it(const char *what, unsigned char *sha1)
{
int status = 0;
if (!has_sha1_file(sha1)) {
status = fetch(sha1);
if (status && what)
report_missing(what, sha1);
}
return status;
}
static int process(unsigned char *sha1, const char *type);
static int process_tree(struct tree *tree)
{
struct tree_entry_list *entries;
struct tree_entry_list *entry;
if (parse_tree(tree))
return -1;
for (entries = tree->entries; entries; entries = entries->next) {
if (process(entries->item.any->sha1,
entries->directory ? tree_type : blob_type))
entry = tree->entries;
tree->entries = NULL;
while (entry) {
struct tree_entry_list *next = entry->next;
if (process(entry->item.any->sha1,
entry->directory ? tree_type : blob_type))
return -1;
free(entry);
entry = next;
}
return 0;
}
#define COMPLETE 1U
#define TO_FETCH 2U
#define TO_SCAN 4U
#define SCANNED 8U
static struct commit_list *complete = NULL;
static int process_commit(struct commit *commit)
{
if (parse_commit(commit))
return -1;
while (complete && complete->item->date >= commit->date) {
pop_most_recent_commit(&complete, COMPLETE);
}
if (commit->object.flags & COMPLETE)
return 0;
memcpy(current_commit_sha1, commit->object.sha1, 20);
pull_say("walk %s\n", sha1_to_hex(commit->object.sha1));
if (get_tree) {
if (process(commit->tree->object.sha1, tree_type))
return -1;
......@@ -78,10 +87,7 @@ static int process_commit(struct commit *commit)
if (get_history) {
struct commit_list *parents = commit->parents;
for (; parents; parents = parents->next) {
if (has_sha1_file(parents->item->object.sha1))
continue;
if (process(parents->item->object.sha1,
commit_type))
if (process(parents->item->object.sha1, commit_type))
return -1;
}
}
......@@ -100,6 +106,10 @@ static struct object_list **process_queue_end = &process_queue;
static int process_object(struct object *obj)
{
if (obj->flags & SCANNED)
return 0;
obj->flags |= SCANNED;
if (obj->type == commit_type) {
if (process_commit((struct commit *)obj))
return -1;
......@@ -126,17 +136,23 @@ static int process_object(struct object *obj)
static int process(unsigned char *sha1, const char *type)
{
struct object *obj = lookup_object_type(sha1, type);
if (has_sha1_file(sha1)) {
parse_object(sha1);
/* We already have it, so we should scan it now. */
return process_object(obj);
if (obj->flags & (SCANNED | TO_SCAN))
return 0;
object_list_insert(obj, process_queue_end);
process_queue_end = &(*process_queue_end)->next;
obj->flags |= TO_SCAN;
return 0;
}
if (object_list_contains(process_queue, obj))
if (obj->flags & (COMPLETE | TO_FETCH))
return 0;
object_list_insert(obj, process_queue_end);
process_queue_end = &(*process_queue_end)->next;
obj->flags |= TO_FETCH;
//fprintf(stderr, "prefetch %s\n", sha1_to_hex(sha1));
prefetch(sha1);
return 0;
......@@ -144,21 +160,27 @@ static int process(unsigned char *sha1, const char *type)
static int loop(void)
{
struct object_list *elem;
while (process_queue) {
struct object *obj = process_queue->item;
/*
fprintf(stderr, "%d objects to pull\n",
object_list_length(process_queue));
*/
process_queue = process_queue->next;
elem = process_queue;
process_queue = elem->next;
free(elem);
if (!process_queue)
process_queue_end = &process_queue;
//fprintf(stderr, "fetch %s\n", sha1_to_hex(obj->sha1));
if (make_sure_we_have_it(obj->type ? obj->type : "object",
obj->sha1))
return -1;
/* If we are not scanning this object, we placed it in
* the queue because we needed to fetch it first.
*/
if (! (obj->flags & TO_SCAN)) {
if (fetch(obj->sha1)) {
report_missing(obj->type
? obj->type
: "object", obj->sha1);
return -1;
}
}
if (!obj->type)
parse_object(obj->sha1);
if (process_object(obj))
......@@ -179,18 +201,30 @@ static int interpret_target(char *target, unsigned char *sha1)
return -1;
}
static int mark_complete(const char *path, const unsigned char *sha1)
{
struct commit *commit = lookup_commit_reference_gently(sha1, 1);
if (commit) {
commit->object.flags |= COMPLETE;
insert_by_date(commit, &complete);
}
return 0;
}
int pull(char *target)
{
unsigned char sha1[20];
int fd = -1;
save_commit_buffer = 0;
if (write_ref && current_ref) {
fd = lock_ref_sha1(write_ref, current_ref);
if (fd < 0)
return -1;
}
for_each_ref(mark_complete);
if (interpret_target(target, sha1))
return error("Could not interpret %s as something to pull",
target);
......
......@@ -110,7 +110,7 @@ bisect_next_check() {
}
bisect_auto_next() {
bisect_next_check && bisect_next
bisect_next_check && bisect_next || :
}
bisect_next() {
......
......@@ -3,7 +3,7 @@
. git-sh-setup || die "Not a git archive"
usage () {
echo >&2 "usage: $(basename $0)"' [<branchname> [start-point]]
echo >&2 "usage: $(basename $0)"' [-d <branch>] | [<branch> [start-point]]
If no arguments, show available branches and mark current branch with a star.
If one argument, create a new branch <branchname> based off of current HEAD.
......@@ -12,6 +12,59 @@ If two arguments, create a new branch <branchname> based off of <start-point>.
exit 1
}
delete_branch () {
option="$1" branch_name="$2"
headref=$(readlink "$GIT_DIR/HEAD" | sed -e 's|^refs/heads/||')
case ",$headref," in
",$branch_name,")
die "Cannot delete the branch you are on." ;;
,,)
die "What branch are you on anyway?" ;;
esac
branch=$(cat "$GIT_DIR/refs/heads/$branch_name") &&
branch=$(git-rev-parse --verify "$branch^0") ||
die "Seriously, what branch are you talking about?"
case "$option" in
-D)
;;
*)
mbs=$(git-merge-base -a "$branch" HEAD | tr '\012' ' ')
case " $mbs " in
*' '$branch' '*)
# the merge base of branch and HEAD contains branch --
# which means that the HEAD contains everything in the HEAD.
;;
*)
echo >&2 "The branch '$branch_name' is not a strict subset of your current HEAD.
If you are sure you want to delete it, run 'git branch -D $branch_name'."
exit 1
;;
esac
;;
esac
rm -f "$GIT_DIR/refs/heads/$branch_name"
echo "Deleted branch $branch_name."
exit 0
}
while case "$#,$1" in 0,*) break ;; *,-*) ;; *) break ;; esac
do
case "$1" in
-d | -D)
delete_branch "$1" "$2"
exit
;;
--)
shift
break
;;
-*)
usage
;;
esac
shift
done
case "$#" in
0)
headref=$(readlink "$GIT_DIR/HEAD" | sed -e 's|^refs/heads/||')
......@@ -36,11 +89,6 @@ case "$#" in
esac
branchname="$1"
case "$branchname" in
-*)
usage;;
esac
rev=$(git-rev-parse --verify "$head") || exit
[ -e "$GIT_DIR/refs/heads/$branchname" ] && die "$branchname already exists"
......
......@@ -22,7 +22,8 @@ while [ "$#" != "0" ]; do
force=1
;;
*)
rev=$(git-rev-parse --verify "$arg^0") || exit
rev=$(git-rev-parse --verify "$arg^0" 2>/dev/null) ||
die "hey dummy, branch '$arg' doesn't exist."
if [ -z "$rev" ]; then
echo "unknown flag $arg"
exit 1
......
......@@ -144,8 +144,32 @@ yes,yes)
*)
case "$repo" in
rsync://*)
rsync $quiet -avz --ignore-existing "$repo/objects/" "$D/.git/objects/" &&
rsync $quiet -avz --ignore-existing "$repo/refs/" "$D/.git/refs/"
rsync $quiet -av --ignore-existing \
--exclude info "$repo/objects/" "$D/.git/objects/" &&
rsync $quiet -av --ignore-existing \
--exclude info "$repo/refs/" "$D/.git/refs/" || exit
# Look at objects/info/alternates for rsync -- http will
# support it natively and git native ones will do it on the
# remote end. Not having that file is not a crime.
rsync -q "$repo/objects/info/alternates" "$D/.git/TMP_ALT" ||
rm -f "$D/.git/TMP_ALT"
if test -f "$D/.git/TMP_ALT"
then
( cd $D &&
. git-parse-remote &&
resolve_alternates "$repo" <"./.git/TMP_ALT" ) |
while read alt
do
case "$alt" in 'bad alternate: '*) die "$alt";; esac
case "$quiet" in
'') echo >&2 "Getting alternate: $alt" ;;
esac
rsync $quiet -av --ignore-existing \
--exclude info "$alt" "$D/.git/objects" || exit
done
rm -f "$D/.git/TMP_ALT"
fi
;;
http://*)
clone_dumb_http "$repo" "$D"
......
# Pass --without docs to rpmbuild if you don't want the documetnation
Name: git-core
Version: @@VERSION@@
Release: 1
Vendor: Junio C Hamano <junkio@cox.net>
Release: 1%{?dist}
Summary: Git core and tools
License: GPL
Group: Development/Tools
URL: http://kernel.org/pub/software/scm/git/
Source: http://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz
BuildRequires: zlib-devel, openssl-devel, curl-devel %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
BuildRoot: %{_tmppath}/%{name}-%{version}-root
Requires: sh-utils, curl, diffutils, rsync, rcs, openssh-clients, perl, python >= 2.4, tk
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
Requires: rsync, rcs, curl, less, openssh-clients, python >= 2.4, tk
%description
This is a stupid (but extremely fast) directory content manager. It
......@@ -24,7 +23,7 @@ elsewhere for tools for ordinary humans layered on top of this.
%setup -q
%build
make prefix=%{_prefix} all %{!?_without_docs: doc}
make COPTS="$RPM_OPT_FLAGS" prefix=%{_prefix} all %{!?_without_docs: doc}
%install
rm -rf $RPM_BUILD_ROOT
......@@ -37,17 +36,35 @@ rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
%{_bindir}/*
%{_datadir}/git-core/templates/*
%{_datadir}/git-core/
%doc README COPYING Documentation/*.txt
%{!?_without_docs: %doc Documentation/*.html }
%{!?_without_docs: %{_mandir}/man1/*.1*}
%{!?_without_docs: %{_mandir}/man7/*.7*}
%changelog
* Fri Sep 16 2005 Chris Wright <chrisw@osdl.org> 0.99.6-1
- update to 0.99.6
* Fri Sep 16 2005 Horst H. von Brand <vonbrand@inf.utfsm.cl>
- Linus noticed that less is required, added to the dependencies
* Sun Sep 11 2005 Horst H. von Brand <vonbrand@inf.utfsm.cl>
- Updated dependencies
- Don't assume manpages are gzipped
* Thu Aug 18 2005 Chris Wright <chrisw@osdl.org> 0.99.4-4
- drop sh_utils, sh-utils, diffutils, mktemp, and openssl Requires
- use RPM_OPT_FLAGS in spec file, drop patch0
* Wed Aug 17 2005 Tom "spot" Callaway <tcallawa@redhat.com> 0.99.4-3
- use dist tag to differentiate between branches
- use rpm optflags by default (patch0)
- own %{_datadir}/git-core/
* Mon Aug 15 2005 Chris Wright <chrisw@osdl.org>
- update spec file to fix Buildroot, Requires, and drop Vendor
* Sun Aug 07 2005 Horst H. von Brand <vonbrand@inf.utfsm.cl>
- Redid the description
- Cut overlong make line, loosened changelog a bit
......
......@@ -183,12 +183,30 @@ do
;;
rsync://*)
TMP_HEAD="$GIT_DIR/TMP_HEAD"
rsync -L "$remote/$remote_name" "$TMP_HEAD" || exit 1
rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1
head=$(git-rev-parse TMP_HEAD)
rm -f "$TMP_HEAD"
test "$rsync_slurped_objects" || {
rsync -avz --ignore-existing "$remote/objects/" \
"$GIT_OBJECT_DIRECTORY/" || exit
rsync -av --ignore-existing --exclude info \
"$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit
# Look at objects/info/alternates for rsync -- http will
# support it natively and git native ones will do it on the remote
# end. Not having that file is not a crime.
rsync -q "$remote/objects/info/alternates" "$GIT_DIR/TMP_ALT" ||
rm -f "$GIT_DIR/TMP_ALT"
if test -f "$GIT_DIR/TMP_ALT"
then
resolve_alternates "$remote" <"$GIT_DIR/TMP_ALT" |
while read alt
do
case "$alt" in 'bad alternate: '*) die "$alt";; esac
echo >&2 "Getting alternate: $alt"
rsync -av --ignore-existing --exclude info \
"$alt" "$GIT_OBJECT_DIRECTORY/" || exit
done
rm -f "$GIT_DIR/TMP_ALT"
fi
rsync_slurped_objects=t
}
;;
......
......@@ -153,3 +153,24 @@ get_remote_refs_for_fetch () {
;;
esac
}
resolve_alternates () {
# original URL (xxx.git)
top_=`expr "$1" : '\([^:]*:/*[^/]*\)/'`
while read path
do
case "$path" in
\#* | '')
continue ;;
/*)
echo "$top_$path/" ;;
../*)
# relative -- ugly but seems to work.
echo "$1/objects/$path/" ;;
*)
# exit code may not be caught by the reader.
echo "bad alternate: $path"
exit 1 ;;
esac
done
}
......@@ -25,8 +25,10 @@ then
fi
merge_head=$(sed -e 's/ .*//' "$GIT_DIR"/FETCH_HEAD | tr '\012' ' ')
merge_name=$(sed -e 's/^[0-9a-f]* //' "$GIT_DIR"/FETCH_HEAD |
tr '\012' ' ')
merge_name=$(
perl -e 'print join("; ", map { chomp; s/^[0-9a-f]* //; $_ } <>)' \
"$GIT_DIR"/FETCH_HEAD
)
case "$merge_head" in
'')
......
......@@ -58,7 +58,15 @@ then
# all-into-one is used.
if test "$all_into_one" != '' && test "$existing" != ''
then
( cd "$PACKDIR" && rm -f $existing )
( cd "$PACKDIR" &&
for e in $existing
do
case "$e" in
./pack-$name.pack | ./pack-$name.idx) ;;
*) rm -f $e ;;
esac
done
)
fi
fi
......
......@@ -108,7 +108,7 @@ sub changelog_input {
if ($pstate == 1) {
my ($email);
next unless /^Author: (.*)<(.*)>.*$/;
next unless /^[Aa]uthor:? (.*)<(.*)>.*$/;
$n_records++;
......
......@@ -14,8 +14,19 @@
#endif
static CURL *curl;
static struct curl_slist *no_pragma_header;
static char *base;
static char *initial_base;
struct alt_base
{
char *base;
int got_indices;
struct packed_git *packs;
struct alt_base *next;
};
struct alt_base *alt = NULL;
static SHA_CTX c;
static z_stream stream;
......@@ -71,11 +82,9 @@ void prefetch(unsigned char *sha1)
{
}
static int got_indices = 0;
static struct packed_git *packs = NULL;
static int got_alternates = 0;
static int fetch_index(unsigned char *sha1)
static int fetch_index(struct alt_base *repo, unsigned char *sha1)
{
char *filename;
char *url;
......@@ -89,9 +98,9 @@ static int fetch_index(unsigned char *sha1)
fprintf(stderr, "Getting index for pack %s\n",
sha1_to_hex(sha1));
url = xmalloc(strlen(base) + 64);
url = xmalloc(strlen(repo->base) + 64);
sprintf(url, "%s/objects/pack/pack-%s.idx",
base, sha1_to_hex(sha1));
repo->base, sha1_to_hex(sha1));
filename = sha1_pack_index_name(sha1);
indexfile = fopen(filename, "w");
......@@ -102,6 +111,7 @@ static int fetch_index(unsigned char *sha1)
curl_easy_setopt(curl, CURLOPT_FILE, indexfile);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, no_pragma_header);
if (curl_easy_perform(curl)) {
fclose(indexfile);
......@@ -112,22 +122,92 @@ static int fetch_index(unsigned char *sha1)
return 0;
}
static int setup_index(unsigned char *sha1)
static int setup_index(struct alt_base *repo, unsigned char *sha1)
{
struct packed_git *new_pack;
if (has_pack_file(sha1))
return 0; // don't list this as something we can get
if (fetch_index(sha1))
if (fetch_index(repo, sha1))
return -1;
new_pack = parse_pack_index(sha1);
new_pack->next = packs;
packs = new_pack;
new_pack->next = repo->packs;
repo->packs = new_pack;
return 0;
}
static int fetch_indices(void)
static int fetch_alternates(char *base)
{
int ret = 0;
struct buffer buffer;
char *url;
char *data;
int i = 0;
if (got_alternates)
return 0;
data = xmalloc(4096);
buffer.size = 4096;
buffer.posn = 0;
buffer.buffer = data;
if (get_verbosely)
fprintf(stderr, "Getting alternates list\n");
url = xmalloc(strlen(base) + 31);
sprintf(url, "%s/objects/info/http-alternates", base);
curl_easy_setopt(curl, CURLOPT_FILE, &buffer);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
curl_easy_setopt(curl, CURLOPT_URL, url);
if (curl_easy_perform(curl) || !buffer.posn) {
sprintf(url, "%s/objects/info/alternates", base);
curl_easy_setopt(curl, CURLOPT_FILE, &buffer);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
curl_easy_setopt(curl, CURLOPT_URL, url);
if (curl_easy_perform(curl)) {
return 0;
}
}
while (i < buffer.posn) {
int posn = i;
while (posn < buffer.posn && data[posn] != '\n')
posn++;
if (data[posn] == '\n') {
if (data[i] == '/') {
int serverlen = strchr(base + 8, '/') - base;
// skip 'objects' at end
char *target =
xmalloc(serverlen + posn - i - 6);
struct alt_base *newalt;
strncpy(target, base, serverlen);
strncpy(target + serverlen, data + i,
posn - i - 7);
target[serverlen + posn - i - 7] = '\0';
if (get_verbosely)
fprintf(stderr,
"Also look at %s\n", target);
newalt = xmalloc(sizeof(*newalt));
newalt->next = alt;
newalt->base = target;
newalt->got_indices = 0;
newalt->packs = NULL;
alt = newalt;
ret++;
}
}
i = posn + 1;
}
got_alternates = 1;
return ret;
}
static int fetch_indices(struct alt_base *repo)
{
unsigned char sha1[20];
char *url;
......@@ -135,7 +215,7 @@ static int fetch_indices(void)
char *data;
int i = 0;
if (got_indices)
if (repo->got_indices)
return 0;
data = xmalloc(4096);
......@@ -146,18 +226,19 @@ static int fetch_indices(void)
if (get_verbosely)
fprintf(stderr, "Getting pack list\n");
url = xmalloc(strlen(base) + 21);
sprintf(url, "%s/objects/info/packs", base);
url = xmalloc(strlen(repo->base) + 21);
sprintf(url, "%s/objects/info/packs", repo->base);
curl_easy_setopt(curl, CURLOPT_FILE, &buffer);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL);
if (curl_easy_perform(curl)) {
return error("Unable to get pack index %s", url);
}
do {
while (i < buffer.posn) {
switch (data[i]) {
case 'P':
i++;
......@@ -165,7 +246,7 @@ static int fetch_indices(void)
!strncmp(data + i, " pack-", 6) &&
!strncmp(data + i + 46, ".pack\n", 6)) {
get_sha1_hex(data + i + 6, sha1);
setup_index(sha1);
setup_index(repo, sha1);
i += 51;
break;
}
......@@ -174,13 +255,13 @@ static int fetch_indices(void)
i++;
}
i++;
} while (i < buffer.posn);
}
got_indices = 1;
repo->got_indices = 1;
return 0;
}
static int fetch_pack(unsigned char *sha1)
static int fetch_pack(struct alt_base *repo, unsigned char *sha1)
{
char *url;
struct packed_git *target;
......@@ -188,12 +269,11 @@ static int fetch_pack(unsigned char *sha1)
FILE *packfile;
char *filename;
if (fetch_indices())
if (fetch_indices(repo))
return -1;
target = find_sha1_pack(sha1, packs);
target = find_sha1_pack(sha1, repo->packs);
if (!target)
return error("Couldn't get %s: not separate or in any pack",
sha1_to_hex(sha1));
return -1;
if (get_verbosely) {
fprintf(stderr, "Getting pack %s\n",
......@@ -202,9 +282,9 @@ static int fetch_pack(unsigned char *sha1)
sha1_to_hex(sha1));
}
url = xmalloc(strlen(base) + 65);
url = xmalloc(strlen(repo->base) + 65);
sprintf(url, "%s/objects/pack/pack-%s.pack",
base, sha1_to_hex(target->sha1));
repo->base, sha1_to_hex(target->sha1));
filename = sha1_pack_name(target->sha1);
packfile = fopen(filename, "w");
......@@ -215,6 +295,7 @@ static int fetch_pack(unsigned char *sha1)
curl_easy_setopt(curl, CURLOPT_FILE, packfile);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, no_pragma_header);
if (curl_easy_perform(curl)) {
fclose(packfile);
......@@ -223,7 +304,7 @@ static int fetch_pack(unsigned char *sha1)
fclose(packfile);
lst = &packs;
lst = &repo->packs;
while (*lst != target)
lst = &((*lst)->next);
*lst = (*lst)->next;
......@@ -233,7 +314,7 @@ static int fetch_pack(unsigned char *sha1)
return 0;
}
int fetch(unsigned char *sha1)
int fetch_object(struct alt_base *repo, unsigned char *sha1)
{
char *hex = sha1_to_hex(sha1);
char *filename = sha1_file_name(sha1);
......@@ -255,10 +336,11 @@ int fetch(unsigned char *sha1)
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
curl_easy_setopt(curl, CURLOPT_FILE, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, no_pragma_header);
url = xmalloc(strlen(base) + 50);
strcpy(url, base);
posn = url + strlen(base);
url = xmalloc(strlen(repo->base) + 50);
strcpy(url, repo->base);
posn = url + strlen(repo->base);
strcpy(posn, "objects/");
posn += 8;
memcpy(posn, hex, 2);
......@@ -270,9 +352,7 @@ int fetch(unsigned char *sha1)
if (curl_easy_perform(curl)) {
unlink(filename);
if (fetch_pack(sha1))
return error("Tried %s", url);
return 0;
return -1;
}
close(local);
......@@ -291,11 +371,30 @@ int fetch(unsigned char *sha1)
return 0;
}
int fetch(unsigned char *sha1)
{
struct alt_base *altbase = alt;
while (altbase) {
if (!fetch_object(altbase, sha1))
return 0;
if (!fetch_pack(altbase, sha1))
return 0;
if (fetch_alternates(altbase->base) > 0) {
altbase = alt;
continue;
}
altbase = altbase->next;
}
return error("Unable to find %s under %s\n", sha1_to_hex(sha1),
initial_base);
}
int fetch_ref(char *ref, unsigned char *sha1)
{
char *url, *posn;
char hex[42];
struct buffer buffer;
char *base = initial_base;
buffer.size = 41;
buffer.posn = 0;
buffer.buffer = hex;
......@@ -303,6 +402,7 @@ int fetch_ref(char *ref, unsigned char *sha1)
curl_easy_setopt(curl, CURLOPT_FILE, &buffer);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL);
url = xmalloc(strlen(base) + 6 + strlen(ref));
strcpy(url, base);
......@@ -354,6 +454,7 @@ int main(int argc, char **argv)
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
curl_ssl_verify = getenv("GIT_SSL_NO_VERIFY") ? 0 : 1;
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, curl_ssl_verify);
......@@ -361,11 +462,17 @@ int main(int argc, char **argv)
curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
#endif
base = url;
alt = xmalloc(sizeof(*alt));
alt->base = url;
alt->got_indices = 0;
alt->packs = NULL;
alt->next = NULL;
initial_base = url;
if (pull(commit_id))
return 1;
curl_slist_free_all(no_pragma_header);
curl_global_cleanup();
return 0;
}
......@@ -36,13 +36,11 @@ int setup_ident(void)
memcpy(real_email, pw->pw_name, len);
real_email[len++] = '@';
gethostname(real_email + len, sizeof(real_email) - len);
#ifndef NO_GETDOMAINNAME
if (!strchr(real_email+len, '.')) {
len = strlen(real_email);
real_email[len++] = '.';
getdomainname(real_email+len, sizeof(real_email)-len);
}
#endif
/* And set the default date */
datestamp(real_date, sizeof(real_date));
return 0;
......
......@@ -9,6 +9,8 @@ struct object **objs;
int nr_objs;
static int obj_allocs;
int track_object_refs = 1;
static int find_object(const unsigned char *sha1)
{
int first = 0, last = nr_objs;
......@@ -67,9 +69,12 @@ void created_object(const unsigned char *sha1, struct object *obj)
void add_ref(struct object *refer, struct object *target)
{
struct object_list **pp = &refer->refs;
struct object_list *p;
struct object_list **pp, *p;
if (!track_object_refs)
return;
pp = &refer->refs;
while ((p = *pp) != NULL) {
if (p->item == target)
return;
......@@ -87,6 +92,8 @@ void mark_reachable(struct object *obj, unsigned int mask)
{
struct object_list *p = obj->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;
......
......@@ -17,6 +17,7 @@ struct object {
void *util;
};
extern int track_object_refs;
extern int nr_objs;
extern struct object **objs;
......
#include "refs.h"
#include "cache.h"
#include "rev-cache.h"
struct rev_cache **rev_cache;
int nr_revs, alloc_revs;
static struct rev_list_elem *rle_free;
#define BATCH_SIZE 512
int find_rev_cache(const unsigned char *sha1)
{
int lo = 0, hi = nr_revs;
while (lo < hi) {
int mi = (lo + hi) / 2;
struct rev_cache *ri = rev_cache[mi];
int cmp = memcmp(sha1, ri->sha1, 20);
if (!cmp)
return mi;
if (cmp < 0)
hi = mi;
else
lo = mi + 1;
}
return -lo - 1;
}
static struct rev_list_elem *alloc_list_elem(void)
{
struct rev_list_elem *rle;
if (!rle_free) {
int i;
rle = xmalloc(sizeof(*rle) * BATCH_SIZE);
for (i = 0; i < BATCH_SIZE - 1; i++) {
rle[i].ri = NULL;
rle[i].next = &rle[i + 1];
}
rle[BATCH_SIZE - 1].ri = NULL;
rle[BATCH_SIZE - 1].next = NULL;
rle_free = rle;
}
rle = rle_free;
rle_free = rle->next;
return rle;
}
static struct rev_cache *create_rev_cache(const unsigned char *sha1)
{
struct rev_cache *ri;
int pos = find_rev_cache(sha1);
if (0 <= pos)
return rev_cache[pos];
pos = -pos - 1;
if (alloc_revs <= ++nr_revs) {
alloc_revs = alloc_nr(alloc_revs);
rev_cache = xrealloc(rev_cache, sizeof(ri) * alloc_revs);
}
if (pos < nr_revs)
memmove(rev_cache + pos + 1, rev_cache + pos,
(nr_revs - pos - 1) * sizeof(ri));
ri = xcalloc(1, sizeof(*ri));
memcpy(ri->sha1, sha1, 20);
rev_cache[pos] = ri;
return ri;
}
static unsigned char last_sha1[20];
static void write_one_rev_cache(FILE *rev_cache_file, struct rev_cache *ri)
{
unsigned char flag;
struct rev_list_elem *rle;
if (ri->written)
return;
if (ri->parsed) {
/* We use last_sha1 compression only for the first parent;
* otherwise the resulting rev-cache would lose the parent
* order information.
*/
if (ri->parents &&
!memcmp(ri->parents->ri->sha1, last_sha1, 20))
flag = (ri->num_parents - 1) | 0x80;
else
flag = ri->num_parents;
fwrite(ri->sha1, 20, 1, rev_cache_file);
fwrite(&flag, 1, 1, rev_cache_file);
for (rle = ri->parents; rle; rle = rle->next) {
if (flag & 0x80 && rle == ri->parents)
continue;
fwrite(rle->ri->sha1, 20, 1, rev_cache_file);
}
memcpy(last_sha1, ri->sha1, 20);
ri->written = 1;
}
/* recursively write children depth first */
for (rle = ri->children; rle; rle = rle->next)
write_one_rev_cache(rev_cache_file, rle->ri);
}
void write_rev_cache(const char *newpath, const char *oldpath)
{
/* write the following commit ancestry information in
* $GIT_DIR/info/rev-cache.
*
* The format is:
* 20-byte SHA1 (commit ID)
* 1-byte flag:
* - bit 0-6 records "number of parent commit SHA1s to
* follow" (i.e. up to 127 children can be listed).
* - when the bit 7 is on, then "the entry immediately
* before this entry is one of the parents of this
* commit".
* N x 20-byte SHA1 (parent commit IDs)
*/
FILE *rev_cache_file;
int i;
struct rev_cache *ri;
if (!strcmp(newpath, oldpath)) {
/* If we are doing it in place */
rev_cache_file = fopen(newpath, "a");
}
else {
char buf[8096];
size_t sz;
FILE *oldfp = fopen(oldpath, "r");
rev_cache_file = fopen(newpath, "w");
if (oldfp) {
while (1) {
sz = fread(buf, 1, sizeof(buf), oldfp);
if (sz == 0)
break;
fwrite(buf, 1, sz, rev_cache_file);
}
fclose(oldfp);
}
}
memset(last_sha1, 0, 20);
/* Go through available rev_cache structures, starting from
* parentless ones first, so that we would get most out of
* last_sha1 optimization by the depth first behaviour of
* write_one_rev_cache().
*/
for (i = 0; i < nr_revs; i++) {
ri = rev_cache[i];
if (ri->num_parents)
continue;
write_one_rev_cache(rev_cache_file, ri);
}
/* Then the rest */
for (i = 0; i < nr_revs; i++) {
ri = rev_cache[i];
write_one_rev_cache(rev_cache_file, ri);
}
fclose(rev_cache_file);
}
static void add_parent(struct rev_cache *child,
const unsigned char *parent_sha1)
{
struct rev_cache *parent = create_rev_cache(parent_sha1);
struct rev_list_elem *e = alloc_list_elem();
/* Keep the parent list ordered in the same way the commit
* object records them.
*/
e->ri = parent;
e->next = NULL;
if (!child->parents_tail)
child->parents = e;
else
child->parents_tail->next = e;
child->parents_tail = e;
child->num_parents++;
/* There is no inherent order of the children so we just
* LIFO them together.
*/
e = alloc_list_elem();
e->next = parent->children;
parent->children = e;
e->ri = child;
parent->num_children++;
}
int read_rev_cache(const char *path, FILE *dumpfile, int dry_run)
{
unsigned char *map;
int fd;
struct stat st;
unsigned long ofs, len;
struct rev_cache *ri = NULL;
fd = open(path, O_RDONLY);
if (fd < 0) {
if (dry_run)
return error("cannot open %s", path);
if (errno == ENOENT)
return 0;
return -1;
}
if (fstat(fd, &st)) {
close(fd);
return -1;
}
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
if (map == MAP_FAILED)
return -1;
memset(last_sha1, 0, 20);
ofs = 0;
len = st.st_size;
while (ofs < len) {
unsigned char sha1[20];
int flag, cnt, i;
if (len < ofs + 21)
die("rev-cache too short");
memcpy(sha1, map + ofs, 20);
flag = map[ofs + 20];
ofs += 21;
cnt = (flag & 0x7f) + ((flag & 0x80) != 0);
if (len < ofs + (flag & 0x7f) * 20)
die("rev-cache too short to have %d more parents",
(flag & 0x7f));
if (dumpfile)
fprintf(dumpfile, "%s", sha1_to_hex(sha1));
if (!dry_run) {
ri = create_rev_cache(sha1);
if (!ri)
die("cannot create rev-cache for %s",
sha1_to_hex(sha1));
ri->written = ri->parsed = 1;
}
i = 0;
if (flag & 0x80) {
if (!dry_run)
add_parent(ri, last_sha1);
if (dumpfile)
fprintf(dumpfile, " %s",
sha1_to_hex(last_sha1));
i++;
}
while (i++ < cnt) {
if (!dry_run)
add_parent(ri, map + ofs);
if (dumpfile)
fprintf(dumpfile, " %s",
sha1_to_hex(last_sha1));
ofs += 20;
}
if (dumpfile)
fprintf(dumpfile, "\n");
memcpy(last_sha1, sha1, 20);
}
if (ofs != len)
die("rev-cache truncated?");
munmap(map, len);
return 0;
}
int record_rev_cache(const unsigned char *sha1, FILE *dumpfile)
{
unsigned char parent[20];
char type[20];
unsigned long size, ofs;
unsigned int cnt, i;
void *buf;
struct rev_cache *ri;
buf = read_sha1_file(sha1, type, &size);
if (!buf)
return error("%s: not found", sha1_to_hex(sha1));
if (strcmp(type, "commit")) {
free(buf);
return error("%s: not a commit but a %s",
sha1_to_hex(sha1), type);
}
ri = create_rev_cache(sha1);
if (ri->parsed)
return 0;
if (dumpfile)
fprintf(dumpfile, "commit %s\n", sha1_to_hex(sha1));
cnt = 0;
ofs = 46; /* "tree " + hex-sha1 + "\n" */
while (!memcmp(buf + ofs, "parent ", 7) &&
!get_sha1_hex(buf + ofs + 7, parent)) {
ofs += 48;
cnt++;
}
if (cnt * 48 + 46 != ofs) {
free(buf);
die("internal error in record_rev_cache");
}
ri = create_rev_cache(sha1);
ri->parsed = 1;
for (i = 0; i < cnt; i++) {
unsigned char parent_sha1[20];
ofs = 46 + i * 48 + 7;
get_sha1_hex(buf + ofs, parent_sha1);
add_parent(ri, parent_sha1);
record_rev_cache(parent_sha1, dumpfile);
}
free(buf);
return 0;
}
#ifndef REV_CACHE_H
#define REV_CACHE_H
extern struct rev_cache {
struct rev_cache *head_list;
struct rev_list_elem *children;
struct rev_list_elem *parents;
struct rev_list_elem *parents_tail;
unsigned short num_parents;
unsigned short num_children;
unsigned int written : 1;
unsigned int parsed : 1;
unsigned int work : 30;
void *work_ptr;
unsigned char sha1[20];
} **rev_cache;
extern int nr_revs, alloc_revs;
struct rev_list_elem {
struct rev_list_elem *next;
struct rev_cache *ri;
};
extern int find_rev_cache(const unsigned char *);
extern int read_rev_cache(const char *, FILE *, int);
extern int record_rev_cache(const unsigned char *, FILE *);
extern void write_rev_cache(const char *new, const char *old);
#endif
......@@ -147,11 +147,16 @@ static struct object_list **process_tree(struct tree *tree, struct object_list *
die("bad tree object %s", sha1_to_hex(obj->sha1));
obj->flags |= SEEN;
p = add_object(obj, p, name);
for (entry = tree->entries ; entry ; entry = entry->next) {
entry = tree->entries;
tree->entries = NULL;
while (entry) {
struct tree_entry_list *next = entry->next;
if (entry->directory)
p = process_tree(entry->item.tree, p, entry->name);
else
p = process_blob(entry->item.blob, p, entry->name);
free(entry);
entry = next;
}
return p;
}
......@@ -218,12 +223,15 @@ static void mark_tree_uninteresting(struct tree *tree)
if (parse_tree(tree) < 0)
die("bad tree %s", sha1_to_hex(obj->sha1));
entry = tree->entries;
tree->entries = NULL;
while (entry) {
struct tree_entry_list *next = entry->next;
if (entry->directory)
mark_tree_uninteresting(entry->item.tree);
else
mark_blob_uninteresting(entry->item.blob);
entry = entry->next;
free(entry);
entry = next;
}
}
......@@ -231,8 +239,6 @@ static void mark_parents_uninteresting(struct commit *commit)
{
struct commit_list *parents = commit->parents;
if (tree_objects)
mark_tree_uninteresting(commit->tree);
while (parents) {
struct commit *commit = parents->item;
commit->object.flags |= UNINTERESTING;
......@@ -272,29 +278,6 @@ static int everybody_uninteresting(struct commit_list *orig)
continue;
return 0;
}
/*
* Ok, go back and mark all the edge trees uninteresting,
* since otherwise we can have situations where a parent
* that was marked uninteresting (and we never even had
* to look at) had lots of objects that we don't want to
* include.
*
* NOTE! This still doesn't mean that the object list is
* "correct", since we may end up listing objects that
* even older commits (that we don't list) do actually
* reference, but it gets us to a minimal list (or very
* close) in practice.
*/
if (!tree_objects)
return 1;
while (orig) {
struct commit *commit = orig->item;
if (!parse_commit(commit) && commit->tree)
mark_tree_uninteresting(commit->tree);
orig = orig->next;
}
return 1;
}
......@@ -370,6 +353,19 @@ static struct commit_list *find_bisection(struct commit_list *list)
return best;
}
static void mark_edges_uninteresting(struct commit_list *list)
{
for ( ; list; list = list->next) {
struct commit_list *parents = list->item->parents;
for ( ; parents; parents = parents->next) {
struct commit *commit = parents->item;
if (commit->object.flags & UNINTERESTING)
mark_tree_uninteresting(commit->tree);
}
}
}
static struct commit_list *limit_list(struct commit_list *list)
{
struct commit_list *newlist = NULL;
......@@ -388,6 +384,8 @@ static struct commit_list *limit_list(struct commit_list *list)
}
p = &commit_list_insert(commit, p)->next;
}
if (tree_objects)
mark_edges_uninteresting(newlist);
if (bisect_list)
newlist = find_bisection(newlist);
return newlist;
......@@ -563,6 +561,8 @@ int main(int argc, char **argv)
struct commit *exclude = NULL;
struct commit *include = NULL;
*dotdot = 0;
if (!*next)
next = "HEAD";
exclude = get_commit_reference(arg, UNINTERESTING);
include = get_commit_reference(next, 0);
if (exclude && include) {
......@@ -571,7 +571,7 @@ int main(int argc, char **argv)
handle_one_commit(include, &list);
continue;
}
*next = '.';
*dotdot = '.';
}
if (*arg == '^') {
flags = UNINTERESTING;
......@@ -582,6 +582,9 @@ int main(int argc, char **argv)
handle_one_commit(commit, &list);
}
save_commit_buffer = verbose_header;
track_object_refs = 0;
if (!merge_order) {
sort_by_date(&list);
if (limited)
......
......@@ -8,6 +8,71 @@
#define COMMAND_SIZE 4096
/*
* Write a shell-quoted version of a string into a buffer, and
* return bytes that ought to be output excluding final null.
*/
static int shell_quote(char *buf, int nmax, const char *str)
{
char ch;
int nq;
int oc = 0;
while ( (ch = *str++) ) {
nq = 0;
if ( strchr(" !\"#$%&\'()*;<=>?[\\]^`{|}", ch) )
nq = 1;
if ( nq ) {
if ( nmax > 1 ) {
*buf++ = '\\';
nmax--;
}
oc++;
}
if ( nmax > 1 ) {
*buf++ = ch;
nmax--;
}
oc++;
}
if ( nmax )
*buf = '\0';
return oc;
}
/*
* Append a string to a string buffer, with or without quoting. Return true
* if the buffer overflowed.
*/
static int add_to_string(char **ptrp, int *sizep, const char *str, int quote)
{
char *p = *ptrp;
int size = *sizep;
int oc;
if ( quote ) {
oc = shell_quote(p, size, str);
} else {
oc = strlen(str);
memcpy(p, str, (oc >= size) ? size-1 : oc);
}
if ( oc >= size ) {
p[size-1] = '\0';
*ptrp += size-1;
*sizep = 1;
return 1; /* Overflow, string unusable */
}
*ptrp += oc;
*sizep -= oc;
return 0;
}
int setup_connection(int *fd_in, int *fd_out, const char *remote_prog,
char *url, int rmt_argc, char **rmt_argv)
{
......@@ -16,6 +81,8 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog,
int sv[2];
char command[COMMAND_SIZE];
char *posn;
int sizen;
int of;
int i;
if (!strcmp(url, "-")) {
......@@ -37,24 +104,30 @@ int setup_connection(int *fd_in, int *fd_out, const char *remote_prog,
if (!path) {
return error("Bad URL: %s", url);
}
/* ssh <host> 'cd <path>; stdio-pull <arg...> <commit-id>' */
snprintf(command, COMMAND_SIZE,
"%s='%s' %s",
GIT_DIR_ENVIRONMENT, path, remote_prog);
*path = '\0';
posn = command + strlen(command);
for (i = 0; i < rmt_argc; i++) {
*(posn++) = ' ';
strncpy(posn, rmt_argv[i], COMMAND_SIZE - (posn - command));
posn += strlen(rmt_argv[i]);
if (posn - command + 4 >= COMMAND_SIZE) {
return error("Command line too long");
}
/* $GIT_RSH <host> "env GIR_DIR=<path> <remote_prog> <args...>" */
sizen = COMMAND_SIZE;
posn = command;
of = 0;
of |= add_to_string(&posn, &sizen, "env ", 0);
of |= add_to_string(&posn, &sizen, GIT_DIR_ENVIRONMENT, 0);
of |= add_to_string(&posn, &sizen, "=", 0);
of |= add_to_string(&posn, &sizen, path, 1);
of |= add_to_string(&posn, &sizen, " ", 0);
of |= add_to_string(&posn, &sizen, remote_prog, 1);
for ( i = 0 ; i < rmt_argc ; i++ ) {
of |= add_to_string(&posn, &sizen, " ", 0);
of |= add_to_string(&posn, &sizen, rmt_argv[i], 1);
}
strcpy(posn, " -");
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv)) {
of |= add_to_string(&posn, &sizen, " -", 0);
if ( of )
return error("Command line too long");
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv))
return error("Couldn't create socket");
}
if (!fork()) {
const char *ssh, *ssh_basename;
ssh = getenv("GIT_SSH");
......
......@@ -3,20 +3,9 @@
#include "object.h"
#include "commit.h"
#include "tag.h"
#include "rev-cache.h"
/* refs */
static FILE *info_ref_fp;
static unsigned long info_ref_time;
static int info_ref_is_stale = 0;
static int stat_ref(const char *path, const unsigned char *sha1)
{
struct stat st;
if (!stat(path, &st) && info_ref_time < st.st_mtime)
info_ref_is_stale = 1;
return 0;
}
static int add_info_ref(const char *path, const unsigned char *sha1)
{
......@@ -26,7 +15,6 @@ static int add_info_ref(const char *path, const unsigned char *sha1)
static int update_info_refs(int force)
{
struct stat st;
char *path0 = strdup(git_path("info/refs"));
int len = strlen(path0);
char *path1 = xmalloc(len + 2);
......@@ -34,21 +22,6 @@ static int update_info_refs(int force)
strcpy(path1, path0);
strcpy(path1 + len, "+");
if (!force) {
if (stat(path0, &st)) {
if (errno == ENOENT)
info_ref_is_stale = 1;
else
return error("cannot stat %s", path0);
}
else {
info_ref_time = st.st_mtime;
for_each_ref(stat_ref);
}
if (!info_ref_is_stale)
return 0;
}
safe_create_leading_directories(path0);
info_ref_fp = fopen(path1, "w");
if (!info_ref_fp)
......@@ -516,45 +489,6 @@ static int update_info_packs(int force)
return 0;
}
/* rev-cache */
static int record_rev_cache_ref(const char *path, const unsigned char *sha1)
{
struct object *obj = parse_object(sha1);
if (!obj)
return error("ref %s has bad sha %s", path, sha1_to_hex(sha1));
while (obj && obj->type == tag_type)
obj = parse_object(((struct tag *)obj)->tagged->sha1);
if (!obj || obj->type != commit_type)
/* tag pointing at a non-commit */
return 0;
return record_rev_cache(obj->sha1, NULL);
}
static int update_info_revs(int force)
{
char *path0 = strdup(git_path("info/rev-cache"));
int len = strlen(path0);
char *path1 = xmalloc(len + 2);
strcpy(path1, path0);
strcpy(path1 + len, "+");
/* read existing rev-cache */
if (!force)
read_rev_cache(path0, NULL, 0);
safe_create_leading_directories(path0);
for_each_ref(record_rev_cache_ref);
/* update the rev-cache database */
write_rev_cache(path1, force ? "/dev/null" : path0);
rename(path1, path0);
free(path1);
free(path0);
return 0;
}
/* public */
int update_server_info(int force)
{
......@@ -566,7 +500,6 @@ int update_server_info(int force)
errs = errs | update_info_refs(force);
errs = errs | update_info_packs(force);
errs = errs | update_info_revs(force);
return errs;
}
#include "cache.h"
#include "rev-cache.h"
static char *show_rev_cache_usage =
"git-show-rev-cache <rev-cache-file>";
int main(int ac, char **av)
{
while (1 < ac && av[0][1] == '-') {
/* do flags here */
break;
ac--; av++;
}
if (ac != 2)
usage(show_rev_cache_usage);
return read_rev_cache(av[1], stdout, 1);
}
#ifndef COUNTERPART_ENV_NAME
#define COUNTERPART_ENV_NAME "GIT_SSH_UPLOAD"
#endif
#ifndef COUNTERPART_PROGRAM_NAME
#define COUNTERPART_PROGRAM_NAME "git-ssh-upload"
#endif
#ifndef MY_PROGRAM_NAME
#define MY_PROGRAM_NAME "git-ssh-fetch"
#endif
#include "cache.h"
#include "commit.h"
#include "rsh.h"
......@@ -82,6 +92,9 @@ int fetch_ref(char *ref, unsigned char *sha1)
return 0;
}
static const char ssh_fetch_usage[] =
MY_PROGRAM_NAME
" [-c] [-t] [-a] [-v] [-d] [--recover] [-w ref] commit-id url";
int main(int argc, char **argv)
{
char *commit_id;
......@@ -110,7 +123,7 @@ int main(int argc, char **argv)
arg++;
}
if (argc < arg + 2) {
usage("git-ssh-fetch [-c] [-t] [-a] [-v] [-d] [--recover] [-w ref] commit-id url");
usage(ssh_fetch_usage);
return 1;
}
commit_id = argv[arg];
......
#define COUNTERPART_ENV_NAME "GIT_SSH_PUSH"
#define COUNTERPART_PROGRAM_NAME "git-ssh-push"
#define MY_PROGRAM_NAME "git-ssh-pull"
#include "ssh-fetch.c"
#define COUNTERPART_ENV_NAME "GIT_SSH_PULL"
#define COUNTERPART_PROGRAM_NAME "git-ssh-pull"
#define MY_PROGRAM_NAME "git-ssh-push"
#include "ssh-upload.c"
#ifndef COUNTERPART_ENV_NAME
#define COUNTERPART_ENV_NAME "GIT_SSH_FETCH"
#endif
#ifndef COUNTERPART_PROGRAM_NAME
#define COUNTERPART_PROGRAM_NAME "git-ssh-fetch"
#endif
#ifndef MY_PROGRAM_NAME
#define MY_PROGRAM_NAME "git-ssh-upload"
#endif
#include "cache.h"
#include "rsh.h"
#include "refs.h"
......@@ -97,7 +107,7 @@ static void service(int fd_in, int fd_out) {
}
static const char ssh_push_usage[] =
"git-ssh-upload [-c] [-t] [-a] [-w ref] commit-id url";
MY_PROGRAM_NAME " [-c] [-t] [-a] [-w ref] commit-id url";
int main(int argc, char **argv)
{
......@@ -109,8 +119,8 @@ int main(int argc, char **argv)
unsigned char sha1[20];
char hex[41];
prog = getenv("GIT_SSH_PULL");
if (!prog) prog = "git-ssh-fetch";
prog = getenv(COUNTERPART_ENV_NAME);
if (!prog) prog = COUNTERPART_PROGRAM_NAME;
while (arg < argc && argv[arg][0] == '-') {
if (argv[arg][1] == 'w')
arg++;
......
......@@ -11,7 +11,7 @@ There is the head (called H) and another commit (called M), which is
simply ahead of H. The index and the work tree contains a state that
is derived from H, but may also have local changes. This test checks
all the combinations described in the two-tree merge "carry forward"
rules, found in <Documentation/git-rev-tree.txt>.
rules, found in <Documentation/git-read-tree.txt>.
In the test, these paths are used:
bozbar - in H, stays in M, modified from bozbar to gnusto
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册