GIT 0.99.9j aka 1.0rc3

Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
Junio C Hamano 2005-11-16 21:32:44 -08:00
parent 60d64db461
commit 27dedf0c3b
46 changed files with 894 additions and 256 deletions

View File

@ -81,7 +81,7 @@ The "diff" formatting options can be customized via the
environment variable 'GIT_DIFF_OPTS'. For example, if you
prefer context diff:
GIT_DIFF_OPTS=-c git-diff-index -p $(cat .git/HEAD)
GIT_DIFF_OPTS=-c git-diff-index -p HEAD
2. When the environment variable 'GIT_EXTERNAL_DIFF' is set, the

View File

@ -13,6 +13,11 @@
--name-status::
Show only names and status of changed files.
--full-index::
Instead of the first handful characters, show full
object name of pre- and post-image blob on the "index"
line when generating a patch format output.
-B::
Break complete rewrite changes into pairs of delete and create.

View File

@ -8,7 +8,7 @@ git-apply - Apply patch on a git index file and a work tree
SYNOPSIS
--------
'git-apply' [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [-z] [<patch>...]
'git-apply' [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [<patch>...]
DESCRIPTION
-----------
@ -79,6 +79,17 @@ OPTIONS
the result with this option, which would apply the
deletion part but not addition part.
--allow-binary-replacement::
When applying a patch, which is a git-enhanced patch
that was prepared to record the pre- and post-image object
name in full, and the path being patched exactly matches
the object the patch applies to (i.e. "index" line's
pre-image object name is what is in the working tree),
and the post-image object is available in the object
database, use the post-image object as the patch
result. This allows binary files to be patched in a
very limited way.
Author
------
Written by Linus Torvalds <torvalds@osdl.org>

View File

@ -26,8 +26,9 @@ to get there.
Normally a commit would identify a new "HEAD" state, and while git
doesn't care where you save the note about that state, in practice we
tend to just write the result to the file `.git/HEAD`, so that we can
always see what the last committed state was.
tend to just write the result to the file that is pointed at by
`.git/HEAD`, so that we can always see what the last committed
state was.
OPTIONS
-------

View File

@ -35,7 +35,7 @@ OPTIONS
do not have the 'git-daemon-export-ok' file.
--inetd::
Have the server run as an inetd service.
Have the server run as an inetd service. Implies --syslog.
--port::
Listen on an alternative port.

View File

@ -57,14 +57,14 @@ some files in the index and are ready to commit. You want to see eactly
*what* you are going to commit is without having to write a new tree
object and compare it that way, and to do that, you just do
git-diff-index --cached $(cat .git/HEAD)
git-diff-index --cached HEAD
Example: let's say I had renamed `commit.c` to `git-commit.c`, and I had
done an "git-update-index" to make that effective in the index file.
"git-diff-files" wouldn't show anything at all, since the index file
matches my working directory. But doing a "git-diff-index" does:
torvalds@ppc970:~/git> git-diff-index --cached $(cat .git/HEAD)
torvalds@ppc970:~/git> git-diff-index --cached HEAD
-100644 blob 4161aecc6700a2eb579e842af0b7f22b98443f74 commit.c
+100644 blob 4161aecc6700a2eb579e842af0b7f22b98443f74 git-commit.c
@ -98,7 +98,7 @@ show that. So let's say that you have edited `kernel/sched.c`, but
have not actually done a "git-update-index" on it yet - there is no
"object" associated with the new state, and you get:
torvalds@ppc970:~/v2.6/linux> git-diff-index $(cat .git/HEAD )
torvalds@ppc970:~/v2.6/linux> git-diff-index HEAD
*100644->100664 blob 7476bb......->000000...... kernel/sched.c
ie it shows that the tree has changed, and that `kernel/sched.c` has is

View File

@ -68,7 +68,7 @@ that aren't readable from any of the specified head nodes.
So for example
git-fsck-objects --unreachable $(cat .git/HEAD .git/refs/heads/*)
git-fsck-objects --unreachable HEAD $(cat .git/refs/heads/*)
will do quite a _lot_ of verification on the tree. There are a few
extra validity tests to be added (make sure that tree objects are

View File

@ -20,7 +20,7 @@ This manual page describes only the most frequently used options.
OPTIONS
-------
--pretty=<format>:
--pretty=<format>::
Controls the way the commit log is formatted.
--max-count=<n>::

View File

@ -237,7 +237,7 @@ This is done to prevent you from losing your work-in-progress
changes. To illustrate, suppose you start from what has been
commited last to your repository:
$ JC=`cat .git/HEAD`
$ JC=`git-rev-parse --verify "HEAD^0"`
$ git-checkout-index -f -u -a $JC
You do random edits, without running git-update-index. And then

View File

@ -24,8 +24,8 @@ Traditionally, `.git/HEAD` is a symlink pointing at
we did `ln -sf refs/heads/newbranch .git/HEAD`, and when we want
to find out which branch we are on, we did `readlink .git/HEAD`.
This was fine, and internally that is what still happens by
default, but on platforms that does not have working symlinks,
or that does not have the `readlink(1)` command, this was a bit
default, but on platforms that do not have working symlinks,
or that do not have the `readlink(1)` command, this was a bit
cumbersome. On some platforms, `ln -sf` does not even work as
advertised (horrors).

View File

@ -8,13 +8,33 @@ git - the stupid content tracker
SYNOPSIS
--------
'git-<command>' <args>
'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ARGS]
DESCRIPTION
-----------
'git' is both a program and a directory content tracker system.
The program 'git' is just a wrapper to reach the core git programs
(or a potty if you like, as it's not exactly porcelain but still
brings your stuff to the plumbing).
This is reference information for the core git commands.
OPTIONS
-------
--version::
prints the git suite version that the 'git' program came from.
--help::
prints the synopsis and a list of available commands.
If a git command is named this option will bring up the
man-page for that command.
--exec-path::
path to wherever your core git programs are installed.
This can also be controlled by setting the GIT_EXEC_PATH
environment variable. If no path is given 'git' will print
the current setting and then exit.
CORE GIT COMMANDS
-----------------
Before reading this cover to cover, you may want to take a look
at the link:tutorial.html[tutorial] document.
@ -67,7 +87,7 @@ gitlink:git-commit-tree[1]::
gitlink:git-hash-object[1]::
Computes the object ID from a file.
gitlink:git-index-pack.html[1]::
gitlink:git-index-pack[1]::
Build pack index file for an existing packed archive.
gitlink:git-init-db[1]::
@ -533,9 +553,12 @@ Discussion[[Discussion]]
------------------------
include::../README[]
Author
------
Written by Linus Torvalds <torvalds@osdl.org> and the git-list <git@vger.kernel.org>.
Authors
-------
git's founding father is Linus Torvalds <torvalds@osdl.org>.
The current git nurse is Junio C. Hamano <junkio@cox.net>.
The git potty was written by Andres Ericsson <ae@op5.se>.
General upbringing is handled by the git-list <git@vger.kernel.org>.
Documentation
--------------

View File

@ -50,7 +50,7 @@
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-cache perspective.
GIT_VERSION = 0.99.9i
GIT_VERSION = 0.99.9j
# CFLAGS and LDFLAGS are for the users to override from the command line.
@ -88,7 +88,7 @@ SCRIPT_SH = \
git-prune.sh git-pull.sh git-push.sh git-rebase.sh \
git-repack.sh git-request-pull.sh git-reset.sh \
git-resolve.sh git-revert.sh git-sh-setup.sh git-status.sh \
git-tag.sh git-verify-tag.sh git-whatchanged.sh git.sh \
git-tag.sh git-verify-tag.sh git-whatchanged.sh \
git-applymbox.sh git-applypatch.sh git-am.sh \
git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
git-merge-resolve.sh git-merge-ours.sh git-grep.sh \
@ -105,7 +105,7 @@ SCRIPT_PYTHON = \
# The ones that do not have to link with lcrypto nor lz.
SIMPLE_PROGRAMS = \
git-get-tar-commit-id$X git-mailinfo$X git-mailsplit$X \
git-stripspace$X git-var$X git-daemon$X
git-stripspace$X git-daemon$X
# ... and all the rest
PROGRAMS = \
@ -125,7 +125,7 @@ PROGRAMS = \
git-unpack-objects$X git-update-index$X git-update-server-info$X \
git-upload-pack$X git-verify-pack$X git-write-tree$X \
git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \
git-name-rev$X git-pack-redundant$X $(SIMPLE_PROGRAMS)
git-name-rev$X git-pack-redundant$X git-var$X $(SIMPLE_PROGRAMS)
# Backward compatibility -- to be removed after 1.0
PROGRAMS += git-ssh-pull$X git-ssh-push$X
@ -334,19 +334,15 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
### Build rules
all: $(PROGRAMS) $(SCRIPTS)
all: $(PROGRAMS) $(SCRIPTS) git
all:
$(MAKE) -C templates
git: git.sh Makefile
rm -f $@+ $@
sed -e '1s|#!.*/sh|#!$(call shq,$(SHELL_PATH))|' \
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
-e 's/@@X@@/$(X)/g' \
$(GIT_LIST_TWEAK) <$@.sh >$@+
chmod +x $@+
mv $@+ $@
# Only use $(CFLAGS). We don't need anything else.
git: git.c Makefile
$(CC) -DGIT_EXEC_PATH='"$(bindir)"' -DGIT_VERSION='"$(GIT_VERSION)"' \
$(CFLAGS) $@.c -o $@
$(filter-out git,$(patsubst %.sh,%,$(SCRIPT_SH))) : % : %.sh
rm -f $@
@ -431,9 +427,9 @@ check:
### Installation rules
install: $(PROGRAMS) $(SCRIPTS)
install: $(PROGRAMS) $(SCRIPTS) git
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(bindir))
$(INSTALL) $(PROGRAMS) $(SCRIPTS) $(call shellquote,$(DESTDIR)$(bindir))
$(INSTALL) git $(PROGRAMS) $(SCRIPTS) $(call shellquote,$(DESTDIR)$(bindir))
$(MAKE) -C templates install
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
$(INSTALL) $(PYMODULES) $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
@ -446,20 +442,20 @@ install-doc:
### Maintainer's dist rules
git-core.spec: git-core.spec.in Makefile
git.spec: git.spec.in Makefile
sed -e 's/@@VERSION@@/$(GIT_VERSION)/g' < $< > $@
GIT_TARNAME=git-core-$(GIT_VERSION)
dist: git-core.spec git-tar-tree
GIT_TARNAME=git-$(GIT_VERSION)
dist: git.spec git-tar-tree
./git-tar-tree HEAD $(GIT_TARNAME) > $(GIT_TARNAME).tar
@mkdir -p $(GIT_TARNAME)
@cp git-core.spec $(GIT_TARNAME)
$(TAR) rf $(GIT_TARNAME).tar $(GIT_TARNAME)/git-core.spec
@cp git.spec $(GIT_TARNAME)
$(TAR) rf $(GIT_TARNAME).tar $(GIT_TARNAME)/git.spec
@rm -rf $(GIT_TARNAME)
gzip -f -9 $(GIT_TARNAME).tar
rpm: dist
$(RPMBUILD) -ta git-core-$(GIT_VERSION).tar.gz
$(RPMBUILD) -ta $(GIT_TARNAME).tar.gz
deb: dist
rm -rf $(GIT_TARNAME)
@ -472,7 +468,7 @@ deb: dist
clean:
rm -f *.o mozilla-sha1/*.o ppc/*.o compat/*.o $(PROGRAMS) $(LIB_FILE)
rm -f $(filter-out gitk,$(SCRIPTS))
rm -f git-core.spec *.pyc *.pyo
rm -f *.spec *.pyc *.pyo
rm -rf $(GIT_TARNAME)
rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
rm -f git-core_$(GIT_VERSION)-*.dsc

6
README
View File

@ -396,8 +396,8 @@ git-commit-tree will return the name of the object that represents
that commit, and you should save it away for later use. Normally,
you'd commit a new `HEAD` state, and while git doesn't care where you
save the note about that state, in practice we tend to just write the
result to the file `.git/HEAD`, so that we can always see what the
last committed state was.
result to the file pointed at by `.git/HEAD`, so that we can always see
what the last committed state was.
Here is an ASCII art by Jon Loeliger that illustrates how
various pieces fit together.
@ -464,7 +464,7 @@ tend to be small and fairly self-explanatory. In particular, if you
follow the convention of having the top commit name in `.git/HEAD`,
you can do
git-cat-file commit $(cat .git/HEAD)
git-cat-file commit HEAD
to see what the top commit was.

92
apply.c
View File

@ -16,6 +16,7 @@
// --numstat does numeric diffstat, and doesn't actually apply
// --index-info shows the old and new index info for paths if available.
//
static int allow_binary_replacement = 0;
static int check_index = 0;
static int write_index = 0;
static int diffstat = 0;
@ -27,7 +28,7 @@ static int no_add = 0;
static int show_index_info = 0;
static int line_termination = '\n';
static const char apply_usage[] =
"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [-z] <patch>...";
"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] <patch>...";
/*
* For "diff-stat" like behaviour, we keep track of the biggest change
@ -891,7 +892,7 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
patchsize = parse_single_patch(buffer + offset + hdrsize, size - offset - hdrsize, patch);
if (!patchsize && !metadata_changes(patch)) {
if (!patchsize) {
static const char binhdr[] = "Binary files ";
if (sizeof(binhdr) - 1 < size - offset - hdrsize &&
@ -899,9 +900,14 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
sizeof(binhdr)-1))
patch->is_binary = 1;
if (patch->is_binary && !apply && !check)
;
else
/* Empty patch cannot be applied if:
* - it is a binary patch and we do not do binary_replace, or
* - text patch without metadata change
*/
if ((apply || check) &&
(patch->is_binary
? !allow_binary_replacement
: !metadata_changes(patch)))
die("patch with only garbage at line %d", linenr);
}
@ -1155,10 +1161,77 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag)
static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
{
struct fragment *frag = patch->fragments;
const char *name = patch->old_name ? patch->old_name : patch->new_name;
if (patch->is_binary) {
unsigned char sha1[20];
if (!allow_binary_replacement)
return error("cannot apply binary patch to '%s' "
"without --allow-binary-replacement",
name);
/* For safety, we require patch index line to contain
* full 40-byte textual SHA1 for old and new, at least for now.
*/
if (strlen(patch->old_sha1_prefix) != 40 ||
strlen(patch->new_sha1_prefix) != 40 ||
get_sha1_hex(patch->old_sha1_prefix, sha1) ||
get_sha1_hex(patch->new_sha1_prefix, sha1))
return error("cannot apply binary patch to '%s' "
"without full index line", name);
if (patch->old_name) {
unsigned char hdr[50];
int hdrlen;
/* See if the old one matches what the patch
* applies to.
*/
write_sha1_file_prepare(desc->buffer, desc->size,
"blob", sha1, hdr, &hdrlen);
if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
return error("the patch applies to '%s' (%s), "
"which does not match the "
"current contents.",
name, sha1_to_hex(sha1));
}
else {
/* Otherwise, the old one must be empty. */
if (desc->size)
return error("the patch applies to an empty "
"'%s' but it is not empty", name);
}
/* For now, we do not record post-image data in the patch,
* and require the object already present in the recipient's
* object database.
*/
if (desc->buffer) {
free(desc->buffer);
desc->alloc = desc->size = 0;
}
get_sha1_hex(patch->new_sha1_prefix, sha1);
if (memcmp(sha1, null_sha1, 20)) {
char type[10];
unsigned long size;
desc->buffer = read_sha1_file(sha1, type, &size);
if (!desc->buffer)
return error("the necessary postimage %s for "
"'%s' does not exist",
patch->new_sha1_prefix, name);
desc->alloc = desc->size = size;
}
return 0;
}
while (frag) {
if (apply_one_fragment(desc, frag) < 0)
return error("patch failed: %s:%ld", patch->old_name, frag->oldpos);
return error("patch failed: %s:%ld",
name, frag->oldpos);
frag = frag->next;
}
return 0;
@ -1200,6 +1273,7 @@ static int check_patch(struct patch *patch)
struct stat st;
const char *old_name = patch->old_name;
const char *new_name = patch->new_name;
const char *name = old_name ? old_name : new_name;
if (old_name) {
int changed;
@ -1274,7 +1348,7 @@ static int check_patch(struct patch *patch)
}
if (apply_data(patch, &st) < 0)
return error("%s: patch does not apply", old_name);
return error("%s: patch does not apply", name);
return 0;
}
@ -1723,6 +1797,10 @@ int main(int argc, char **argv)
diffstat = 1;
continue;
}
if (!strcmp(arg, "--allow-binary-replacement")) {
allow_binary_replacement = 1;
continue;
}
if (!strcmp(arg, "--numstat")) {
apply = 0;
numstat = 1;

View File

@ -179,6 +179,8 @@ extern int commit_index_file(struct cache_file *);
extern void rollback_index_file(struct cache_file *);
extern int trust_executable_bit;
extern int only_use_symrefs;
extern int diff_rename_limit_default;
#define MTIME_CHANGED 0x0001
#define CTIME_CHANGED 0x0002

View File

@ -204,6 +204,7 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
unsigned char parent[20];
struct commit_list **pptr;
struct commit_graft *graft;
unsigned n_refs = 0;
if (item->object.parsed)
return 0;
@ -214,7 +215,7 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
return error("bad tree pointer in commit %s\n", sha1_to_hex(item->object.sha1));
item->tree = lookup_tree(parent);
if (item->tree)
add_ref(&item->object, &item->tree->object);
n_refs++;
bufptr += 46; /* "tree " + "hex sha1" + "\n" */
pptr = &item->parents;
@ -230,7 +231,7 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
new_parent = lookup_commit(parent);
if (new_parent) {
pptr = &commit_list_insert(new_parent, pptr)->next;
add_ref(&item->object, &new_parent->object);
n_refs++;
}
}
if (graft) {
@ -241,10 +242,22 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
if (!new_parent)
continue;
pptr = &commit_list_insert(new_parent, pptr)->next;
add_ref(&item->object, &new_parent->object);
n_refs++;
}
}
item->date = parse_commit_date(bufptr);
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;
}

View File

@ -214,6 +214,11 @@ int git_default_config(const char *var, const char *value)
return 0;
}
if (!strcmp(var, "core.symrefsonly")) {
only_use_symrefs = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "user.name")) {
strncpy(git_default_name, value, sizeof(git_default_name));
return 0;
@ -224,6 +229,11 @@ int git_default_config(const char *var, const char *value)
return 0;
}
if (!strcmp(var, "diff.renamelimit")) {
diff_rename_limit_default = git_config_int(var, value);
return 0;
}
/* Add other config variables here.. */
return 0;
}

View File

@ -594,6 +594,7 @@ int main(int argc, char **argv)
}
if (!strcmp(arg, "--inetd")) {
inetd_mode = 1;
log_syslog = 1;
continue;
}
if (!strcmp(arg, "--verbose")) {
@ -602,7 +603,6 @@ int main(int argc, char **argv)
}
if (!strcmp(arg, "--syslog")) {
log_syslog = 1;
openlog("git-daemon", 0, LOG_DAEMON);
continue;
}
if (!strcmp(arg, "--export-all")) {
@ -611,9 +611,11 @@ int main(int argc, char **argv)
}
if (!strncmp(arg, "--timeout=", 10)) {
timeout = atoi(arg+10);
continue;
}
if (!strncmp(arg, "--init-timeout=", 15)) {
init_timeout = atoi(arg+15);
continue;
}
if (!strcmp(arg, "--")) {
ok_paths = &argv[i+1];
@ -626,10 +628,13 @@ int main(int argc, char **argv)
usage(daemon_usage);
}
if (log_syslog)
openlog("git-daemon", 0, LOG_DAEMON);
if (inetd_mode) {
fclose(stderr); //FIXME: workaround
return execute();
} else {
return serve(port);
}
return serve(port);
}

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
git-core (0.99.9j-0) unstable; urgency=low
* GIT 0.99.9j aka 1.0rc3
-- Junio C Hamano <junkio@cox.net> Wed, 16 Nov 2005 20:39:55 -0800
git-core (0.99.9i-0) unstable; urgency=low
* GIT 0.99.9i aka 1.0rc2

23
diff.c
View File

@ -13,6 +13,8 @@ static const char *diff_opts = "-pu";
static int use_size_cache;
int diff_rename_limit_default = -1;
static char *quote_one(const char *str)
{
int needlen;
@ -648,7 +650,7 @@ static void diff_fill_sha1_info(struct diff_filespec *one)
memset(one->sha1, 0, 20);
}
static void run_diff(struct diff_filepair *p)
static void run_diff(struct diff_filepair *p, struct diff_options *o)
{
const char *pgm = external_diff();
char msg[PATH_MAX*2+300], *xfrm_msg;
@ -711,11 +713,11 @@ static void run_diff(struct diff_filepair *p)
if (memcmp(one->sha1, two->sha1, 20)) {
char one_sha1[41];
const char *index_fmt = o->full_index ? "index %s..%s" : "index %.7s..%.7s";
memcpy(one_sha1, sha1_to_hex(one->sha1), 41);
len += snprintf(msg + len, sizeof(msg) - len,
"index %.7s..%.7s", one_sha1,
sha1_to_hex(two->sha1));
index_fmt, one_sha1, sha1_to_hex(two->sha1));
if (one->mode == two->mode)
len += snprintf(msg + len, sizeof(msg) - len,
" %06o", one->mode);
@ -761,9 +763,12 @@ void diff_setup(struct diff_options *options)
int diff_setup_done(struct diff_options *options)
{
if ((options->find_copies_harder || 0 <= options->rename_limit) &&
options->detect_rename != DIFF_DETECT_COPY)
if ((options->find_copies_harder &&
options->detect_rename != DIFF_DETECT_COPY) ||
(0 <= options->rename_limit && !options->detect_rename))
return -1;
if (options->detect_rename && options->rename_limit < 0)
options->rename_limit = diff_rename_limit_default;
if (options->setup & DIFF_SETUP_USE_CACHE) {
if (!active_cache)
/* read-cache does not die even when it fails
@ -789,6 +794,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
options->line_termination = 0;
else if (!strncmp(arg, "-l", 2))
options->rename_limit = strtoul(arg+2, NULL, 10);
else if (!strcmp(arg, "--full-index"))
options->full_index = 1;
else if (!strcmp(arg, "--name-only"))
options->output_format = DIFF_FORMAT_NAME;
else if (!strcmp(arg, "--name-status"))
@ -1017,7 +1024,7 @@ int diff_unmodified_pair(struct diff_filepair *p)
return 0;
}
static void diff_flush_patch(struct diff_filepair *p)
static void diff_flush_patch(struct diff_filepair *p, struct diff_options *o)
{
if (diff_unmodified_pair(p))
return;
@ -1026,7 +1033,7 @@ static void diff_flush_patch(struct diff_filepair *p)
(DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
return; /* no tree diffs in patch format */
run_diff(p);
run_diff(p, o);
}
int diff_queue_is_empty(void)
@ -1158,7 +1165,7 @@ void diff_flush(struct diff_options *options)
die("internal error in diff-resolve-rename-copy");
switch (diff_output_format) {
case DIFF_FORMAT_PATCH:
diff_flush_patch(p);
diff_flush_patch(p, options);
break;
case DIFF_FORMAT_RAW:
case DIFF_FORMAT_NAME_STATUS:

4
diff.h
View File

@ -32,7 +32,8 @@ struct diff_options {
const char *orderfile;
const char *pickaxe;
unsigned recursive:1,
tree_in_recursive:1;
tree_in_recursive:1,
full_index:1;
int break_opt;
int detect_rename;
int find_copies_harder;
@ -96,6 +97,7 @@ extern void diffcore_std_no_resolve(struct diff_options *);
" -u synonym for -p.\n" \
" --name-only show only names of changed files.\n" \
" --name-status show names and status of changed files.\n" \
" --full-index show full object name on index ines.\n" \
" -R swap input file pairs.\n" \
" -B detect complete rewrites.\n" \
" -M detect renames.\n" \

View File

@ -283,7 +283,7 @@ void diffcore_rename(struct diff_options *options)
register_rename_src(p->one, 1);
}
if (rename_dst_nr == 0 ||
(0 <= rename_limit && rename_limit < rename_dst_nr))
(0 < rename_limit && rename_limit < rename_dst_nr))
goto cleanup; /* nothing to do */
/* We really want to cull the candidates list early

View File

@ -12,6 +12,7 @@
char git_default_email[MAX_GITNAME];
char git_default_name[MAX_GITNAME];
int trust_executable_bit = 1;
int only_use_symrefs = 0;
static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
*git_graft_file;

View File

@ -56,7 +56,6 @@ static void check_connectivity(void)
/* Look up all the requirements, warn about missing objects.. */
for (i = 0; i < nr_objs; i++) {
struct object *obj = objs[i];
struct object_list *refs;
if (!obj->parsed) {
if (!standalone && has_sha1_file(obj->sha1))
@ -67,14 +66,19 @@ static void check_connectivity(void)
continue;
}
for (refs = obj->refs; refs; refs = refs->next) {
if (refs->item->parsed ||
(!standalone && has_sha1_file(refs->item->sha1)))
continue;
printf("broken link from %7s %s\n",
obj->type, sha1_to_hex(obj->sha1));
printf(" to %7s %s\n",
refs->item->type, sha1_to_hex(refs->item->sha1));
if (obj->refs) {
const struct object_refs *refs = obj->refs;
unsigned j;
for (j = 0; j < refs->count; j++) {
struct object *ref = refs->ref[j];
if (ref->parsed ||
(!standalone && has_sha1_file(ref->sha1)))
continue;
printf("broken link from %7s %s\n",
obj->type, sha1_to_hex(obj->sha1));
printf(" to %7s %s\n",
ref->type, sha1_to_hex(ref->sha1));
}
}
if (show_unreachable && !(obj->flags & REACHABLE)) {
@ -184,10 +188,17 @@ static int fsck_tree(struct tree *item)
default:
break;
}
free(last->name);
free(last);
}
last = entry;
}
if (last) {
free(last->name);
free(last);
}
item->entries = NULL;
retval = 0;
if (has_full_path) {

View File

@ -3,16 +3,10 @@
#
. git-sh-setup || die "Not a git archive"
files=$(git-diff-index --cached --name-only HEAD) || exit
if [ "$files" ]; then
echo "Dirty index: cannot apply patches (dirty: $files)" >&2
exit 1
fi
usage () {
echo >&2 "usage: $0 [--signoff] [--dotest=<dir>] [--utf8] [--3way] <mbox>"
echo >&2 " or, when resuming"
echo >&2 " $0 [--skip]"
echo >&2 " $0 [--skip | --resolved]"
exit 1;
}
@ -104,7 +98,7 @@ fall_back_3way () {
}
prec=4
dotest=.dotest sign= utf8= keep= skip= interactive=
dotest=.dotest sign= utf8= keep= skip= interactive= resolved=
while case "$#" in 0) break;; esac
do
@ -128,6 +122,9 @@ do
-k|--k|--ke|--kee|--keep)
keep=t; shift ;;
-r|--r|--re|--res|--reso|--resol|--resolv|--resolve|--resolved)
resolved=t; shift ;;
--sk|--ski|--skip)
skip=t; shift ;;
@ -140,6 +137,8 @@ do
esac
done
# If the dotest directory exists, but we have finished applying all the
# patches in them, clear it out.
if test -d "$dotest" &&
last=$(cat "$dotest/last") &&
next=$(cat "$dotest/next") &&
@ -155,9 +154,9 @@ then
die "previous dotest directory $dotest still exists but mbox given."
resume=yes
else
# Make sure we are not given --skip
test ",$skip," = ,, ||
die "we are not resuming."
# Make sure we are not given --skip nor --resolved
test ",$skip,$resolved," = ,,, ||
die "we are not resuming."
# Start afresh.
mkdir -p "$dotest" || exit
@ -170,12 +169,24 @@ else
exit 1
}
# -s, -u and -k flags are kept for the resuming session after
# a patch failure.
# -3 and -i can and must be given when resuming.
echo "$sign" >"$dotest/sign"
echo "$utf8" >"$dotest/utf8"
echo "$keep" >"$dotest/keep"
echo 1 >"$dotest/next"
fi
case "$resolved" in
'')
files=$(git-diff-index --cached --name-only HEAD) || exit
if [ "$files" ]; then
echo "Dirty index: cannot apply patches (dirty: $files)" >&2
exit 1
fi
esac
if test "$(cat "$dotest/utf8")" = t
then
utf8=-u
@ -216,6 +227,15 @@ do
go_next
continue
}
# If we are not resuming, parse and extract the patch information
# into separate files:
# - info records the authorship and title
# - msg is the rest of commit log message
# - patch is the patch body.
#
# When we are resuming, these files are either already prepared
# by the user, or the user can tell us to do so by --resolved flag.
case "$resume" in
'')
git-mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \
@ -263,6 +283,13 @@ do
fi
} >"$dotest/final-commit"
;;
*)
case "$resolved,$interactive" in
tt)
# This is used only for interactive view option.
git-diff-index -p --cached HEAD >"$dotest/patch"
;;
esac
esac
resume=
@ -310,7 +337,21 @@ do
echo "Applying '$SUBJECT'"
echo
git-apply --index "$dotest/patch"; apply_status=$?
case "$resolved" in
'')
git-apply --index "$dotest/patch"
apply_status=$?
;;
t)
# Resolved means the user did all the hard work, and
# we do not have to do any patch application. Just
# trust what the user has in the index file and the
# working tree.
resolved=
apply_status=0
;;
esac
if test $apply_status = 1 && test "$threeway" = t
then
if (fall_back_3way)

View File

@ -410,8 +410,7 @@ foreach my $ps (@psets) {
open HEAD, ">$git_dir/refs/heads/$ps->{branch}";
print HEAD $commitid;
close HEAD;
unlink ("$git_dir/HEAD");
symlink("refs/heads/$ps->{branch}","$git_dir/HEAD");
system('git-update-ref', 'HEAD', "$ps->{branch}");
# tag accordingly
ptag($ps->{id}, $commitid); # private tag

View File

@ -4,6 +4,7 @@ use strict;
use Getopt::Std;
use File::Temp qw(tempdir);
use Data::Dumper;
use File::Basename qw(basename);
unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){
die "GIT_DIR is not defined or is unreadable";
@ -11,7 +12,7 @@ unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){
our ($opt_h, $opt_p, $opt_v, $opt_c );
getopt('hpvc');
getopts('hpvc');
$opt_h && usage();
@ -77,7 +78,7 @@ $opt_v && print "Applying to CVS commit $commit from parent $parent\n";
# grab the commit message
`git-cat-file commit $commit | sed -e '1,/^\$/d' > .msg`;
$? && die "Error extraction the commit message";
$? && die "Error extracting the commit message";
my (@afiles, @dfiles, @mfiles);
my @files = `git-diff-tree -r $parent $commit`;
@ -187,9 +188,9 @@ my $cmd = "cvs commit -F .msg $commitfiles";
if ($dirtypatch) {
print "NOTE: One or more hunks failed to apply cleanly.\n";
print "Resolve the conflicts and then commit using:n";
print "Resolve the conflicts and then commit using:\n";
print "\n $cmd\n\n";
exit;
exit(1);
}
@ -206,8 +207,7 @@ if ($opt_c) {
}
sub usage {
print STDERR <<END;
Usage: GIT_DIR=/path/to/.gi ${\basename $0} # fetch/update GIT from CVS
[-h] [-p] [ parent ] commit
Usage: GIT_DIR=/path/to/.git ${\basename $0} [-h] [-p] [-v] [-c] [ parent ] commit
END
exit(1);
}

View File

@ -437,7 +437,11 @@ unless(-d $git_dir) {
"Either use the correct '-o branch' option,\n".
"or import to a new repository.\n";
$last_branch = basename(readlink("$git_dir/HEAD"));
open(F, "git-symbolic-ref HEAD |") or
die "Cannot run git-symbolic-ref: $!\n";
chomp ($last_branch = <F>);
$last_branch = basename($last_branch);
close(F);
unless($last_branch) {
warn "Cannot read the last branch name: $! -- assuming 'master'\n";
$last_branch = "master";
@ -829,8 +833,7 @@ if($orig_branch) {
print "DONE; creating $orig_branch branch\n" if $opt_v;
system("cp","$git_dir/refs/heads/$opt_o","$git_dir/refs/heads/master")
unless -f "$git_dir/refs/heads/master";
unlink("$git_dir/HEAD");
symlink("refs/heads/$orig_branch","$git_dir/HEAD");
system('git-update-ref', 'HEAD', "$orig_branch");
unless ($opt_i) {
system('git checkout');
die "checkout failed: $?\n" if $?;

View File

@ -39,5 +39,9 @@ while : ; do
esac
shift
done
[ "$pattern" ] || {
echo >&2 "usage: 'git grep <pattern> [pathspec*]'"
exit 1
}
git-ls-files -z "${git_flags[@]}" "$@" |
xargs -0 grep "${flags[@]}" -e "$pattern"

View File

@ -3,11 +3,13 @@
# Copyright (C) 2005 Fredrik Kuivinen
#
import sys, math, random, os, re, signal, tempfile, stat, errno, traceback
import sys
sys.path.append('''@@GIT_PYTHON_PATH@@''')
import math, random, os, re, signal, tempfile, stat, errno, traceback
from heapq import heappush, heappop
from sets import Set
sys.path.append('''@@GIT_PYTHON_PATH@@''')
from gitMergeCommon import *
outputIndent = 0

View File

@ -216,7 +216,11 @@ unless(-d $git_dir) {
-f "$git_dir/svn2git"
or die "'$git_dir/svn2git' does not exist.\n".
"You need that file for incremental imports.\n";
$last_branch = basename(readlink("$git_dir/HEAD"));
open(F, "git-symbolic-ref HEAD |") or
die "Cannot run git-symbolic-ref: $!\n";
chomp ($last_branch = <F>);
$last_branch = basename($last_branch);
close(F);
unless($last_branch) {
warn "Cannot read the last branch name: $! -- assuming 'master'\n";
$last_branch = "master";
@ -766,8 +770,7 @@ if($orig_branch) {
print "DONE; creating $orig_branch branch\n" if $opt_v and (not defined $opt_l or $opt_l > 0);
system("cp","$git_dir/refs/heads/$opt_o","$git_dir/refs/heads/master")
unless -f "$git_dir/refs/heads/master";
unlink("$git_dir/HEAD");
symlink("refs/heads/$orig_branch","$git_dir/HEAD");
system('git-update-ref', 'HEAD', "$orig_branch");
unless ($opt_i) {
system('git checkout');
die "checkout failed: $?\n" if $?;

295
git.c Normal file
View File

@ -0,0 +1,295 @@
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#ifndef PATH_MAX
# define PATH_MAX 4096
#endif
static const char git_usage[] =
"Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]";
/* most gui terms set COLUMNS (although some don't export it) */
static int term_columns(void)
{
char *col_string = getenv("COLUMNS");
int n_cols = 0;
if (col_string && (n_cols = atoi(col_string)) > 0)
return n_cols;
return 80;
}
static void oom(void)
{
fprintf(stderr, "git: out of memory\n");
exit(1);
}
static inline void mput_char(char c, unsigned int num)
{
while(num--)
putchar(c);
}
static struct cmdname {
size_t len;
char name[1];
} **cmdname;
static int cmdname_alloc, cmdname_cnt;
static void add_cmdname(const char *name, int len)
{
struct cmdname *ent;
if (cmdname_alloc <= cmdname_cnt) {
cmdname_alloc = cmdname_alloc + 200;
cmdname = realloc(cmdname, cmdname_alloc * sizeof(*cmdname));
if (!cmdname)
oom();
}
ent = malloc(sizeof(*ent) + len);
if (!ent)
oom();
ent->len = len;
memcpy(ent->name, name, len+1);
cmdname[cmdname_cnt++] = ent;
}
static int cmdname_compare(const void *a_, const void *b_)
{
struct cmdname *a = *(struct cmdname **)a_;
struct cmdname *b = *(struct cmdname **)b_;
return strcmp(a->name, b->name);
}
static void pretty_print_string_list(struct cmdname **cmdname, int longest)
{
int cols = 1;
int space = longest + 1; /* min 1 SP between words */
int max_cols = term_columns() - 1; /* don't print *on* the edge */
int i;
if (space < max_cols)
cols = max_cols / space;
qsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare);
for (i = 0; i < cmdname_cnt; ) {
int c;
printf(" ");
for (c = cols; c && i < cmdname_cnt; i++) {
printf("%s", cmdname[i]->name);
if (--c)
mput_char(' ', space - cmdname[i]->len);
}
putchar('\n');
}
}
static void list_commands(const char *exec_path, const char *pattern)
{
unsigned int longest = 0;
char path[PATH_MAX];
int dirlen;
DIR *dir = opendir(exec_path);
struct dirent *de;
if (!dir) {
fprintf(stderr, "git: '%s': %s\n", exec_path, strerror(errno));
exit(1);
}
dirlen = strlen(exec_path);
if (PATH_MAX - 20 < dirlen) {
fprintf(stderr, "git: insanely long exec-path '%s'\n",
exec_path);
exit(1);
}
memcpy(path, exec_path, dirlen);
path[dirlen++] = '/';
while ((de = readdir(dir)) != NULL) {
struct stat st;
int entlen;
if (strncmp(de->d_name, "git-", 4))
continue;
strcpy(path+dirlen, de->d_name);
if (stat(path, &st) || /* stat, not lstat */
!S_ISREG(st.st_mode) ||
!(st.st_mode & S_IXUSR))
continue;
entlen = strlen(de->d_name);
if (longest < entlen)
longest = entlen;
add_cmdname(de->d_name + 4, entlen-4);
}
closedir(dir);
printf("git commands available in '%s'\n", exec_path);
printf("----------------------------");
mput_char('-', strlen(exec_path));
putchar('\n');
pretty_print_string_list(cmdname, longest - 4);
putchar('\n');
}
#ifdef __GNUC__
static void usage(const char *exec_path, const char *fmt, ...)
__attribute__((__format__(__printf__, 2, 3), __noreturn__));
#endif
static void usage(const char *exec_path, const char *fmt, ...)
{
if (fmt) {
va_list ap;
va_start(ap, fmt);
printf("git: ");
vprintf(fmt, ap);
va_end(ap);
putchar('\n');
}
else
puts(git_usage);
putchar('\n');
if(exec_path)
list_commands(exec_path, "git-*");
exit(1);
}
static void prepend_to_path(const char *dir, int len)
{
char *path, *old_path = getenv("PATH");
int path_len = len;
if (!old_path)
old_path = "/usr/local/bin:/usr/bin:/bin";
path_len = len + strlen(old_path) + 1;
path = malloc(path_len + 1);
path[path_len + 1] = '\0';
memcpy(path, dir, len);
path[len] = ':';
memcpy(path + len + 1, old_path, path_len - len);
setenv("PATH", path, 1);
}
static void show_man_page(char *git_cmd)
{
char *page;
if (!strncmp(git_cmd, "git", 3))
page = git_cmd;
else {
int page_len = strlen(git_cmd) + 4;
page = malloc(page_len + 1);
strcpy(page, "git-");
strcpy(page + 4, git_cmd);
page[page_len] = 0;
}
execlp("man", "man", page, NULL);
}
int main(int argc, char **argv, char **envp)
{
char git_command[PATH_MAX + 1];
char wd[PATH_MAX + 1];
int i, len, show_help = 0;
char *exec_path = getenv("GIT_EXEC_PATH");
getcwd(wd, PATH_MAX);
if (!exec_path)
exec_path = GIT_EXEC_PATH;
for (i = 1; i < argc; i++) {
char *arg = argv[i];
if (strncmp(arg, "--", 2))
break;
arg += 2;
if (!strncmp(arg, "exec-path", 9)) {
arg += 9;
if (*arg == '=')
exec_path = arg + 1;
else {
puts(exec_path);
exit(0);
}
}
else if (!strcmp(arg, "version")) {
printf("git version %s\n", GIT_VERSION);
exit(0);
}
else if (!strcmp(arg, "help"))
show_help = 1;
else if (!show_help)
usage(NULL, NULL);
}
if (i >= argc || show_help) {
if (i >= argc)
usage(exec_path, NULL);
show_man_page(argv[i]);
}
if (*exec_path != '/') {
if (!getcwd(git_command, sizeof(git_command))) {
fprintf(stderr,
"git: cannot determine current directory");
exit(1);
}
len = strlen(git_command);
/* Trivial cleanup */
while (!strncmp(exec_path, "./", 2)) {
exec_path += 2;
while (*exec_path == '/')
*exec_path++;
}
snprintf(git_command + len, sizeof(git_command) - len,
"/%s", exec_path);
}
else
strcpy(git_command, exec_path);
len = strlen(git_command);
prepend_to_path(git_command, len);
strncat(&git_command[len], "/git-", sizeof(git_command) - len);
len += 5;
strncat(&git_command[len], argv[i], sizeof(git_command) - len);
if (access(git_command, X_OK))
usage(exec_path, "'%s' is not a git-command", argv[i]);
/* execve() can only ever return if it fails */
execve(git_command, &argv[i], envp);
printf("Failed to run command '%s': %s\n", git_command, strerror(errno));
return 1;
}

76
git.sh
View File

@ -1,76 +0,0 @@
#!/bin/sh
cmd=
path=$(dirname "$0")
case "$#" in
0) ;;
*) cmd="$1"
shift
case "$cmd" in
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "git version @@GIT_VERSION@@"
exit 0 ;;
esac
test -x "$path/git-$cmd" && exec "$path/git-$cmd" "$@"
case '@@X@@' in
'')
;;
*)
test -x "$path/git-$cmd@@X@@" &&
exec "$path/git-$cmd@@X@@" "$@"
;;
esac
;;
esac
echo "Usage: git COMMAND [OPTIONS] [TARGET]"
if [ -n "$cmd" ]; then
echo "git command '$cmd' not found."
fi
echo "git commands are:"
fmt <<\EOF | sed -e 's/^/ /'
add
apply
archimport
bisect
branch
checkout
cherry
clone
commit
count-objects
cvsimport
diff
fetch
format-patch
fsck-objects
get-tar-commit-id
init-db
log
ls-remote
octopus
pack-objects
parse-remote
patch-id
prune
pull
push
rebase
relink
rename
repack
request-pull
reset
resolve
revert
send-email
shortlog
show-branch
status
tag
verify-tag
whatchanged
EOF

View File

@ -1,5 +1,5 @@
# Pass --without docs to rpmbuild if you don't want the documentation
Name: git-core
Name: git
Version: @@VERSION@@
Release: 1%{?dist}
Summary: Git core and tools
@ -9,7 +9,7 @@ URL: http://kernel.org/pub/software/scm/git/
Source: http://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz
BuildRequires: zlib-devel >= 1.2, openssl-devel, curl-devel, expat-devel %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
Requires: zlib >= 1.2, rsync, rcs, curl, less, openssh-clients, python >= 2.3, expat
Requires: git-core, git-svn, git-cvs, git-arch, git-email, gitk
%description
This is a stupid (but extremely fast) directory content manager. It
@ -19,6 +19,22 @@ distributed source code management system. This package includes
rudimentary tools that can be used as a SCM, but you should look
elsewhere for tools for ordinary humans layered on top of this.
This is a dummy package which brings in all subpackages.
%package core
Summary: Core git tools
Group: Development/Tools
Requires: zlib >= 1.2, rsync, rcs, curl, less, openssh-clients, python >= 2.3, expat
%description core
This is a stupid (but extremely fast) directory content manager. It
doesn't do a whole lot, but what it _does_ do is track directory
contents efficiently. It is intended to be the base of an efficient,
distributed source code management system. This package includes
rudimentary tools that can be used as a SCM, but you should look
elsewhere for tools for ordinary humans layered on top of this.
These are the core tools with minimal dependencies.
%package svn
Summary: Git tools for importing Subversion repositories
Group: Development/Tools
@ -47,11 +63,11 @@ Requires: git-core = %{version}-%{release}
%description email
Git tools for sending email.
%package tk
%package -n gitk
Summary: Git revision tree visualiser ('gitk')
Group: Development/Tools
Requires: git-core = %{version}-%{release}, tk >= 8.4
%description tk
%description -n gitk
Git revision tree visualiser ('gitk')
%prep
@ -75,6 +91,9 @@ make %{_smp_mflags} DESTDIR=$RPM_BUILD_ROOT WITH_OWN_SUBPROCESS_PY=YesPlease WIT
%clean
rm -rf $RPM_BUILD_ROOT
%files
# These are no files in the root package
%files svn
%defattr(-,root,root)
%{_bindir}/*svn*
@ -103,20 +122,25 @@ rm -rf $RPM_BUILD_ROOT
%{!?_without_docs: %{_mandir}/man1/*email*.1*}
%{!?_without_docs: %doc Documentation/*email*.html }
%files tk
%files -n gitk
%defattr(-,root,root)
%doc Documentation/*gitk*.txt
%{_bindir}/*gitk*
%{!?_without_docs: %{_mandir}/man1/*gitk*.1*}
%{!?_without_docs: %doc Documentation/*gitk*.html }
%files -f bin-man-doc-files
%files core -f bin-man-doc-files
%defattr(-,root,root)
%{_datadir}/git-core/
%doc README COPYING Documentation/*.txt
%{!?_without_docs: %doc Documentation/*.html }
%changelog
* Mon Nov 14 2005 H. Peter Anvin <hpa@zytor.com> 0.99.9j-1
- Change subpackage names to git-<name> instead of git-core-<name>
- Create empty root package which brings in all subpackages
- Rename git-tk -> gitk
* Thu Nov 10 2005 Chris Wright <chrisw@osdl.org> 0.99.9g-1
- zlib dependency fix
- Minor cleanups from split

View File

@ -425,6 +425,8 @@ static void start_request(struct transfer_request *request)
rename(request->tmpfile, prevfile);
unlink(request->tmpfile);
if (request->local != -1)
error("fd leakage in start: %d", request->local);
request->local = open(request->tmpfile,
O_WRONLY | O_CREAT | O_EXCL, 0666);
/* This could have failed due to the "lazy directory creation";
@ -523,7 +525,7 @@ static void start_request(struct transfer_request *request)
/* Try to get the request started, abort the request on error */
if (!start_active_slot(slot)) {
request->state = ABORTED;
close(request->local);
close(request->local); request->local = -1;
free(request->url);
return;
}
@ -537,7 +539,7 @@ static void finish_request(struct transfer_request *request)
struct stat st;
fchmod(request->local, 0444);
close(request->local);
close(request->local); request->local = -1;
if (request->http_code == 416) {
fprintf(stderr, "Warning: requested range invalid; we may already have all the data.\n");
@ -569,6 +571,8 @@ static void release_request(struct transfer_request *request)
{
struct transfer_request *entry = request_queue_head;
if (request->local != -1)
error("fd leakage in release: %d", request->local);
if (request == request_queue_head) {
request_queue_head = request->next;
} else {
@ -631,6 +635,8 @@ static void process_curl_messages(void)
if (request->repo->next != NULL) {
request->repo =
request->repo->next;
close(request->local);
request->local = -1;
start_request(request);
} else {
finish_request(request);
@ -763,6 +769,7 @@ static int fetch_index(struct alt_base *repo, unsigned char *sha1)
curl_errorstr);
}
} else {
fclose(indexfile);
return error("Unable to start request");
}
@ -1083,6 +1090,7 @@ static int fetch_pack(struct alt_base *repo, unsigned char *sha1)
curl_errorstr);
}
} else {
fclose(packfile);
return error("Unable to start request");
}
@ -1145,6 +1153,7 @@ static int fetch_object(struct alt_base *repo, unsigned char *sha1)
fetch_alternates(alt->base);
if (request->repo->next != NULL) {
request->repo = request->repo->next;
close(request->local); request->local = -1;
start_request(request);
}
} else {
@ -1153,6 +1162,9 @@ static int fetch_object(struct alt_base *repo, unsigned char *sha1)
}
#endif
}
if (request->local != -1) {
close(request->local); request->local = -1;
}
if (request->state == ABORTED) {
release_request(request);

View File

@ -67,40 +67,66 @@ void created_object(const unsigned char *sha1, struct object *obj)
nr_objs++;
}
void add_ref(struct object *refer, struct object *target)
struct object_refs *alloc_object_refs(unsigned count)
{
struct object_list **pp, *p;
struct object_refs *refs;
size_t size = sizeof(*refs) + count*sizeof(struct object *);
if (!track_object_refs)
refs = xmalloc(size);
memset(refs, 0, 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;
return *pa - *pb;
}
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;
pp = &refer->refs;
while ((p = *pp) != NULL) {
if (p->item == target)
return;
pp = &p->next;
}
target->used = 1;
p = xmalloc(sizeof(*p));
p->item = target;
p->next = NULL;
*pp = p;
/* 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;
obj->refs = refs;
}
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;
obj->flags |= mask;
while (p) {
mark_reachable(p->item, mask);
p = p->next;
if (obj->refs) {
const struct object_refs *refs = obj->refs;
unsigned i;
for (i = 0; i < refs->count; i++)
mark_reachable(refs->ref[i], mask);
}
}

View File

@ -7,13 +7,18 @@ struct object_list {
const char *name;
};
struct object_refs {
unsigned count;
struct object *ref[0];
};
struct object {
unsigned parsed : 1;
unsigned used : 1;
unsigned int flags;
unsigned char sha1[20];
const char *type;
struct object_list *refs;
struct object_refs *refs;
void *util;
};
@ -35,7 +40,8 @@ struct object *parse_object(const unsigned char *sha1);
/** Returns the object, with potentially excess memory allocated. **/
struct object *lookup_unknown_object(const unsigned char *sha1);
void add_ref(struct object *refer, struct object *target);
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);

View File

@ -127,38 +127,6 @@ inline struct llist_item * llist_insert_sorted_unique(struct llist *list,
return llist_insert_back(list, sha1);
}
/* computes A\B */
void llist_sorted_difference_inplace(struct llist *A,
struct llist *B)
{
struct llist_item *prev, *a, *b, *x;
prev = a = A->front;
b = B->front;
while (a != NULL && b != NULL) {
int cmp = memcmp(a->sha1, b->sha1, 20);
if (!cmp) {
x = a;
if (a == A->front)
A->front = a->next;
a = prev->next = a->next;
if (a == NULL) /* end of list */
A->back = prev;
A->size--;
free(x);
b = b->next;
} else
if (cmp > 0)
b = b->next;
else {
prev = a;
a = a->next;
}
}
}
/* returns a pointer to an item in front of sha1 */
inline struct llist_item * llist_sorted_remove(struct llist *list, char *sha1,
struct llist_item *hint)
@ -194,6 +162,21 @@ redo_from_start:
return prev;
}
/* computes A\B */
void llist_sorted_difference_inplace(struct llist *A,
struct llist *B)
{
struct llist_item *hint, *b;
hint = NULL;
b = B->front;
while (b) {
hint = llist_sorted_remove(A, b->sha1, hint);
b = b->next;
}
}
inline struct pack_list * pack_list_insert(struct pack_list **pl,
struct pack_list *entry)
{

10
refs.c
View File

@ -121,10 +121,12 @@ int create_symref(const char *git_HEAD, const char *refs_heads_master)
int fd, len, written;
#if USE_SYMLINK_HEAD
unlink(git_HEAD);
if (!symlink(refs_heads_master, git_HEAD))
return 0;
fprintf(stderr, "no symlink - falling back to symbolic ref\n");
if (!only_use_symrefs) {
unlink(git_HEAD);
if (!symlink(refs_heads_master, git_HEAD))
return 0;
fprintf(stderr, "no symlink - falling back to symbolic ref\n");
}
#endif
len = snprintf(ref, sizeof(ref), "ref: %s\n", refs_heads_master);

View File

@ -424,7 +424,6 @@ static void find_pack_info_one(int pack_ix)
{
unsigned char sha1[20];
struct object *o;
struct object_list *ref;
int i;
struct packed_git *p = info[pack_ix]->p;
int num = num_packed_objects(p);
@ -437,8 +436,12 @@ static void find_pack_info_one(int pack_ix)
die("corrupt pack file %s?", p->pack_name);
if ((o = lookup_object(sha1)) == NULL)
die("cannot parse %s", sha1_to_hex(sha1));
for (ref = o->refs; ref; ref = ref->next)
ref->item->flags = 0;
if (o->refs) {
struct object_refs *refs = o->refs;
int j;
for (j = 0; j < refs->count; j++)
refs->ref[j]->flags = 0;
}
o->flags = 0;
}
@ -448,8 +451,12 @@ static void find_pack_info_one(int pack_ix)
die("corrupt pack file %s?", p->pack_name);
if ((o = lookup_object(sha1)) == NULL)
die("cannot find %s", sha1_to_hex(sha1));
for (ref = o->refs; ref; ref = ref->next)
ref->item->flags |= REFERENCED;
if (o->refs) {
struct object_refs *refs = o->refs;
int j;
for (j = 0; j < refs->count; j++)
refs->ref[j]->flags |= REFERENCED;
}
o->flags |= INTERNAL;
}
@ -460,8 +467,12 @@ static void find_pack_info_one(int pack_ix)
die("cannot find %s", sha1_to_hex(sha1));
show(o, pack_ix);
for (ref = o->refs; ref; ref = ref->next)
show(ref->item, pack_ix);
if (o->refs) {
struct object_refs *refs = o->refs;
int j;
for (j = 0; j < refs->count; j++)
show(refs->ref[j], pack_ix);
}
}
}

View File

@ -424,7 +424,7 @@ struct packed_git *add_packed_git(char *path, int path_len, int local)
struct packed_git *p;
unsigned long idx_size;
void *idx_map;
char sha1[20];
unsigned char sha1[20];
if (check_packed_git_idx(path, &idx_size, &idx_map))
return NULL;

View File

@ -20,6 +20,7 @@ static void check_symref(const char *HEAD)
int main(int argc, const char **argv)
{
setup_git_directory();
git_config(git_default_config);
switch (argc) {
case 2:
check_symref(argv[1]);

115
t/t4103-apply-binary.sh Normal file
View File

@ -0,0 +1,115 @@
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#
test_description='git-apply handling binary patches
'
. ./test-lib.sh
# setup
cat >file1 <<EOF
A quick brown fox jumps over the lazy dog.
A tiny little penguin runs around in circles.
There is a flag with Linux written on it.
A slow black-and-white panda just sits there,
munching on his bamboo.
EOF
cat file1 >file2
cat file1 >file4
git-update-index --add --remove file1 file2 file4
git-commit -m 'Initial Version' 2>/dev/null
git-checkout -b binary
tr 'x' '\0' <file1 >file3
cat file3 >file4
git-add file2
tr '\0' 'v' <file3 >file1
rm -f file2
git-update-index --add --remove file1 file2 file3 file4
git-commit -m 'Second Version'
git-diff-tree -p master binary >B.diff
git-diff-tree -p -C master binary >C.diff
git-diff-tree -p --full-index master binary >BF.diff
git-diff-tree -p --full-index -C master binary >CF.diff
test_expect_success 'stat binary diff -- should not fail.' \
'git-checkout master
git-apply --stat --summary B.diff'
test_expect_success 'stat binary diff (copy) -- should not fail.' \
'git-checkout master
git-apply --stat --summary C.diff'
test_expect_failure 'check binary diff -- should fail.' \
'git-checkout master
git-apply --check B.diff'
test_expect_failure 'check binary diff (copy) -- should fail.' \
'git-checkout master
git-apply --check C.diff'
test_expect_failure 'check incomplete binary diff with replacement -- should fail.' \
'git-checkout master
git-apply --check --allow-binary-replacement B.diff'
test_expect_failure 'check incomplete binary diff with replacement (copy) -- should fail.' \
'git-checkout master
git-apply --check --allow-binary-replacement C.diff'
test_expect_success 'check binary diff with replacement.' \
'git-checkout master
git-apply --check --allow-binary-replacement BF.diff'
test_expect_success 'check binary diff with replacement (copy).' \
'git-checkout master
git-apply --check --allow-binary-replacement CF.diff'
# Now we start applying them.
do_reset () {
rm -f file?
git-reset --hard
git-checkout -f master
}
test_expect_failure 'apply binary diff -- should fail.' \
'do_reset
git-apply B.diff'
test_expect_failure 'apply binary diff -- should fail.' \
'do_reset
git-apply --index B.diff'
test_expect_failure 'apply binary diff (copy) -- should fail.' \
'do_reset
git-apply C.diff'
test_expect_failure 'apply binary diff (copy) -- should fail.' \
'do_reset
git-apply --index C.diff'
test_expect_failure 'apply binary diff without replacement -- should fail.' \
'do_reset
git-apply BF.diff'
test_expect_failure 'apply binary diff without replacement (copy) -- should fail.' \
'do_reset
git-apply CF.diff'
test_expect_success 'apply binary diff.' \
'do_reset
git-apply --allow-binary-replacement --index BF.diff &&
test -z "$(git-diff --name-status binary)"'
test_expect_success 'apply binary diff (copy).' \
'do_reset
git-apply --allow-binary-replacement --index CF.diff &&
test -z "$(git-diff --name-status binary)"'
test_done

View File

@ -158,6 +158,8 @@ test_done () {
# Test the binaries we have just built. The tests are kept in
# t/ subdirectory and are run in trash subdirectory.
PATH=$(pwd)/..:$PATH
GIT_EXEC_PATH=$(pwd)/..
export GIT_EXEC_PATH
# Test repository
test=trash

7
tag.c
View File

@ -75,8 +75,11 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
item->tag[taglen] = '\0';
item->tagged = lookup_object_type(object, type);
if (item->tagged)
add_ref(&item->object, item->tagged);
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;
}

13
tree.c
View File

@ -148,6 +148,7 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
{
void *bufptr = buffer;
struct tree_entry_list **list_p;
int n_refs = 0;
if (item->object.parsed)
return 0;
@ -184,11 +185,21 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
obj = &entry->item.blob->object;
}
if (obj)
add_ref(&item->object, obj);
n_refs++;
entry->parent = NULL; /* needs to be filled by the user */
*list_p = entry;
list_p = &entry->next;
}
if (track_object_refs) {
struct tree_entry_list *entry;
unsigned i = 0;
struct object_refs *refs = alloc_object_refs(n_refs);
for (entry = item->entries; entry; entry = entry->next)
refs->ref[i++] = entry->item.any;
set_object_refs(&item->object, refs);
}
return 0;
}