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 environment variable 'GIT_DIFF_OPTS'. For example, if you
prefer context diff: 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 2. When the environment variable 'GIT_EXTERNAL_DIFF' is set, the

View file

@ -13,6 +13,11 @@
--name-status:: --name-status::
Show only names and status of changed files. 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:: -B::
Break complete rewrite changes into pairs of delete and create. 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 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 DESCRIPTION
----------- -----------
@ -79,6 +79,17 @@ OPTIONS
the result with this option, which would apply the the result with this option, which would apply the
deletion part but not addition part. 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 Author
------ ------
Written by Linus Torvalds <torvalds@osdl.org> 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 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 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 tend to just write the result to the file that is pointed at by
always see what the last committed state was. `.git/HEAD`, so that we can always see what the last committed
state was.
OPTIONS OPTIONS
------- -------

View file

@ -35,7 +35,7 @@ OPTIONS
do not have the 'git-daemon-export-ok' file. do not have the 'git-daemon-export-ok' file.
--inetd:: --inetd::
Have the server run as an inetd service. Have the server run as an inetd service. Implies --syslog.
--port:: --port::
Listen on an alternative 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 *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 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 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. 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 "git-diff-files" wouldn't show anything at all, since the index file
matches my working directory. But doing a "git-diff-index" does: 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 commit.c
+100644 blob 4161aecc6700a2eb579e842af0b7f22b98443f74 git-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 have not actually done a "git-update-index" on it yet - there is no
"object" associated with the new state, and you get: "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 *100644->100664 blob 7476bb......->000000...... kernel/sched.c
ie it shows that the tree has changed, and that `kernel/sched.c` has is 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 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 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 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 OPTIONS
------- -------
--pretty=<format>: --pretty=<format>::
Controls the way the commit log is formatted. Controls the way the commit log is formatted.
--max-count=<n>:: --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 changes. To illustrate, suppose you start from what has been
commited last to your repository: commited last to your repository:
$ JC=`cat .git/HEAD` $ JC=`git-rev-parse --verify "HEAD^0"`
$ git-checkout-index -f -u -a $JC $ git-checkout-index -f -u -a $JC
You do random edits, without running git-update-index. And then 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 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`. to find out which branch we are on, we did `readlink .git/HEAD`.
This was fine, and internally that is what still happens by This was fine, and internally that is what still happens by
default, but on platforms that does not have working symlinks, default, but on platforms that do not have working symlinks,
or that does not have the `readlink(1)` command, this was a bit or that do not have the `readlink(1)` command, this was a bit
cumbersome. On some platforms, `ln -sf` does not even work as cumbersome. On some platforms, `ln -sf` does not even work as
advertised (horrors). advertised (horrors).

View file

@ -8,13 +8,33 @@ git - the stupid content tracker
SYNOPSIS SYNOPSIS
-------- --------
'git-<command>' <args> 'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ARGS]
DESCRIPTION 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 Before reading this cover to cover, you may want to take a look
at the link:tutorial.html[tutorial] document. at the link:tutorial.html[tutorial] document.
@ -67,7 +87,7 @@ gitlink:git-commit-tree[1]::
gitlink:git-hash-object[1]:: gitlink:git-hash-object[1]::
Computes the object ID from a file. 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. Build pack index file for an existing packed archive.
gitlink:git-init-db[1]:: gitlink:git-init-db[1]::
@ -533,9 +553,12 @@ Discussion[[Discussion]]
------------------------ ------------------------
include::../README[] include::../README[]
Author Authors
------ -------
Written by Linus Torvalds <torvalds@osdl.org> and the git-list <git@vger.kernel.org>. 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 Documentation
-------------- --------------

View file

@ -50,7 +50,7 @@
# Define USE_STDEV below if you want git to care about the underlying device # 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. # 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. # 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-prune.sh git-pull.sh git-push.sh git-rebase.sh \
git-repack.sh git-request-pull.sh git-reset.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-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-applymbox.sh git-applypatch.sh git-am.sh \
git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \ git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
git-merge-resolve.sh git-merge-ours.sh git-grep.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. # The ones that do not have to link with lcrypto nor lz.
SIMPLE_PROGRAMS = \ SIMPLE_PROGRAMS = \
git-get-tar-commit-id$X git-mailinfo$X git-mailsplit$X \ 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 # ... and all the rest
PROGRAMS = \ PROGRAMS = \
@ -125,7 +125,7 @@ PROGRAMS = \
git-unpack-objects$X git-update-index$X git-update-server-info$X \ 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-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-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 # Backward compatibility -- to be removed after 1.0
PROGRAMS += git-ssh-pull$X git-ssh-push$X 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 export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
### Build rules ### Build rules
all: $(PROGRAMS) $(SCRIPTS) all: $(PROGRAMS) $(SCRIPTS) git
all: all:
$(MAKE) -C templates $(MAKE) -C templates
git: git.sh Makefile # Only use $(CFLAGS). We don't need anything else.
rm -f $@+ $@ git: git.c Makefile
sed -e '1s|#!.*/sh|#!$(call shq,$(SHELL_PATH))|' \ $(CC) -DGIT_EXEC_PATH='"$(bindir)"' -DGIT_VERSION='"$(GIT_VERSION)"' \
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ $(CFLAGS) $@.c -o $@
-e 's/@@X@@/$(X)/g' \
$(GIT_LIST_TWEAK) <$@.sh >$@+
chmod +x $@+
mv $@+ $@
$(filter-out git,$(patsubst %.sh,%,$(SCRIPT_SH))) : % : %.sh $(filter-out git,$(patsubst %.sh,%,$(SCRIPT_SH))) : % : %.sh
rm -f $@ rm -f $@
@ -431,9 +427,9 @@ check:
### Installation rules ### Installation rules
install: $(PROGRAMS) $(SCRIPTS) install: $(PROGRAMS) $(SCRIPTS) git
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(bindir)) $(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 $(MAKE) -C templates install
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR)) $(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
$(INSTALL) $(PYMODULES) $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR)) $(INSTALL) $(PYMODULES) $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
@ -446,20 +442,20 @@ install-doc:
### Maintainer's dist rules ### 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' < $< > $@ sed -e 's/@@VERSION@@/$(GIT_VERSION)/g' < $< > $@
GIT_TARNAME=git-core-$(GIT_VERSION) GIT_TARNAME=git-$(GIT_VERSION)
dist: git-core.spec git-tar-tree dist: git.spec git-tar-tree
./git-tar-tree HEAD $(GIT_TARNAME) > $(GIT_TARNAME).tar ./git-tar-tree HEAD $(GIT_TARNAME) > $(GIT_TARNAME).tar
@mkdir -p $(GIT_TARNAME) @mkdir -p $(GIT_TARNAME)
@cp git-core.spec $(GIT_TARNAME) @cp git.spec $(GIT_TARNAME)
$(TAR) rf $(GIT_TARNAME).tar $(GIT_TARNAME)/git-core.spec $(TAR) rf $(GIT_TARNAME).tar $(GIT_TARNAME)/git.spec
@rm -rf $(GIT_TARNAME) @rm -rf $(GIT_TARNAME)
gzip -f -9 $(GIT_TARNAME).tar gzip -f -9 $(GIT_TARNAME).tar
rpm: dist rpm: dist
$(RPMBUILD) -ta git-core-$(GIT_VERSION).tar.gz $(RPMBUILD) -ta $(GIT_TARNAME).tar.gz
deb: dist deb: dist
rm -rf $(GIT_TARNAME) rm -rf $(GIT_TARNAME)
@ -472,7 +468,7 @@ deb: dist
clean: clean:
rm -f *.o mozilla-sha1/*.o ppc/*.o compat/*.o $(PROGRAMS) $(LIB_FILE) rm -f *.o mozilla-sha1/*.o ppc/*.o compat/*.o $(PROGRAMS) $(LIB_FILE)
rm -f $(filter-out gitk,$(SCRIPTS)) rm -f $(filter-out gitk,$(SCRIPTS))
rm -f git-core.spec *.pyc *.pyo rm -f *.spec *.pyc *.pyo
rm -rf $(GIT_TARNAME) rm -rf $(GIT_TARNAME)
rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
rm -f git-core_$(GIT_VERSION)-*.dsc 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, 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 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 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 result to the file pointed at by `.git/HEAD`, so that we can always see
last committed state was. what the last committed state was.
Here is an ASCII art by Jon Loeliger that illustrates how Here is an ASCII art by Jon Loeliger that illustrates how
various pieces fit together. 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`, follow the convention of having the top commit name in `.git/HEAD`,
you can do you can do
git-cat-file commit $(cat .git/HEAD) git-cat-file commit HEAD
to see what the top commit was. 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 // --numstat does numeric diffstat, and doesn't actually apply
// --index-info shows the old and new index info for paths if available. // --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 check_index = 0;
static int write_index = 0; static int write_index = 0;
static int diffstat = 0; static int diffstat = 0;
@ -27,7 +28,7 @@ static int no_add = 0;
static int show_index_info = 0; static int show_index_info = 0;
static int line_termination = '\n'; static int line_termination = '\n';
static const char apply_usage[] = 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 * 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); patchsize = parse_single_patch(buffer + offset + hdrsize, size - offset - hdrsize, patch);
if (!patchsize && !metadata_changes(patch)) { if (!patchsize) {
static const char binhdr[] = "Binary files "; static const char binhdr[] = "Binary files ";
if (sizeof(binhdr) - 1 < size - offset - hdrsize && 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)) sizeof(binhdr)-1))
patch->is_binary = 1; patch->is_binary = 1;
if (patch->is_binary && !apply && !check) /* Empty patch cannot be applied if:
; * - it is a binary patch and we do not do binary_replace, or
else * - 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); 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) static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
{ {
struct fragment *frag = patch->fragments; 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) { while (frag) {
if (apply_one_fragment(desc, frag) < 0) 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; frag = frag->next;
} }
return 0; return 0;
@ -1200,6 +1273,7 @@ static int check_patch(struct patch *patch)
struct stat st; struct stat st;
const char *old_name = patch->old_name; const char *old_name = patch->old_name;
const char *new_name = patch->new_name; const char *new_name = patch->new_name;
const char *name = old_name ? old_name : new_name;
if (old_name) { if (old_name) {
int changed; int changed;
@ -1274,7 +1348,7 @@ static int check_patch(struct patch *patch)
} }
if (apply_data(patch, &st) < 0) 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; return 0;
} }
@ -1723,6 +1797,10 @@ int main(int argc, char **argv)
diffstat = 1; diffstat = 1;
continue; continue;
} }
if (!strcmp(arg, "--allow-binary-replacement")) {
allow_binary_replacement = 1;
continue;
}
if (!strcmp(arg, "--numstat")) { if (!strcmp(arg, "--numstat")) {
apply = 0; apply = 0;
numstat = 1; 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 void rollback_index_file(struct cache_file *);
extern int trust_executable_bit; extern int trust_executable_bit;
extern int only_use_symrefs;
extern int diff_rename_limit_default;
#define MTIME_CHANGED 0x0001 #define MTIME_CHANGED 0x0001
#define CTIME_CHANGED 0x0002 #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]; unsigned char parent[20];
struct commit_list **pptr; struct commit_list **pptr;
struct commit_graft *graft; struct commit_graft *graft;
unsigned n_refs = 0;
if (item->object.parsed) if (item->object.parsed)
return 0; 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)); return error("bad tree pointer in commit %s\n", sha1_to_hex(item->object.sha1));
item->tree = lookup_tree(parent); item->tree = lookup_tree(parent);
if (item->tree) if (item->tree)
add_ref(&item->object, &item->tree->object); n_refs++;
bufptr += 46; /* "tree " + "hex sha1" + "\n" */ bufptr += 46; /* "tree " + "hex sha1" + "\n" */
pptr = &item->parents; pptr = &item->parents;
@ -230,7 +231,7 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
new_parent = lookup_commit(parent); new_parent = lookup_commit(parent);
if (new_parent) { if (new_parent) {
pptr = &commit_list_insert(new_parent, pptr)->next; pptr = &commit_list_insert(new_parent, pptr)->next;
add_ref(&item->object, &new_parent->object); n_refs++;
} }
} }
if (graft) { if (graft) {
@ -241,10 +242,22 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
if (!new_parent) if (!new_parent)
continue; continue;
pptr = &commit_list_insert(new_parent, pptr)->next; pptr = &commit_list_insert(new_parent, pptr)->next;
add_ref(&item->object, &new_parent->object); n_refs++;
} }
} }
item->date = parse_commit_date(bufptr); 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; return 0;
} }

View file

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

View file

@ -594,6 +594,7 @@ int main(int argc, char **argv)
} }
if (!strcmp(arg, "--inetd")) { if (!strcmp(arg, "--inetd")) {
inetd_mode = 1; inetd_mode = 1;
log_syslog = 1;
continue; continue;
} }
if (!strcmp(arg, "--verbose")) { if (!strcmp(arg, "--verbose")) {
@ -602,7 +603,6 @@ int main(int argc, char **argv)
} }
if (!strcmp(arg, "--syslog")) { if (!strcmp(arg, "--syslog")) {
log_syslog = 1; log_syslog = 1;
openlog("git-daemon", 0, LOG_DAEMON);
continue; continue;
} }
if (!strcmp(arg, "--export-all")) { if (!strcmp(arg, "--export-all")) {
@ -611,9 +611,11 @@ int main(int argc, char **argv)
} }
if (!strncmp(arg, "--timeout=", 10)) { if (!strncmp(arg, "--timeout=", 10)) {
timeout = atoi(arg+10); timeout = atoi(arg+10);
continue;
} }
if (!strncmp(arg, "--init-timeout=", 15)) { if (!strncmp(arg, "--init-timeout=", 15)) {
init_timeout = atoi(arg+15); init_timeout = atoi(arg+15);
continue;
} }
if (!strcmp(arg, "--")) { if (!strcmp(arg, "--")) {
ok_paths = &argv[i+1]; ok_paths = &argv[i+1];
@ -626,10 +628,13 @@ int main(int argc, char **argv)
usage(daemon_usage); usage(daemon_usage);
} }
if (log_syslog)
openlog("git-daemon", 0, LOG_DAEMON);
if (inetd_mode) { if (inetd_mode) {
fclose(stderr); //FIXME: workaround fclose(stderr); //FIXME: workaround
return execute(); 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-core (0.99.9i-0) unstable; urgency=low
* GIT 0.99.9i aka 1.0rc2 * 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; static int use_size_cache;
int diff_rename_limit_default = -1;
static char *quote_one(const char *str) static char *quote_one(const char *str)
{ {
int needlen; int needlen;
@ -648,7 +650,7 @@ static void diff_fill_sha1_info(struct diff_filespec *one)
memset(one->sha1, 0, 20); 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(); const char *pgm = external_diff();
char msg[PATH_MAX*2+300], *xfrm_msg; 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)) { if (memcmp(one->sha1, two->sha1, 20)) {
char one_sha1[41]; 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); memcpy(one_sha1, sha1_to_hex(one->sha1), 41);
len += snprintf(msg + len, sizeof(msg) - len, len += snprintf(msg + len, sizeof(msg) - len,
"index %.7s..%.7s", one_sha1, index_fmt, one_sha1, sha1_to_hex(two->sha1));
sha1_to_hex(two->sha1));
if (one->mode == two->mode) if (one->mode == two->mode)
len += snprintf(msg + len, sizeof(msg) - len, len += snprintf(msg + len, sizeof(msg) - len,
" %06o", one->mode); " %06o", one->mode);
@ -761,9 +763,12 @@ void diff_setup(struct diff_options *options)
int diff_setup_done(struct diff_options *options) int diff_setup_done(struct diff_options *options)
{ {
if ((options->find_copies_harder || 0 <= options->rename_limit) && if ((options->find_copies_harder &&
options->detect_rename != DIFF_DETECT_COPY) options->detect_rename != DIFF_DETECT_COPY) ||
(0 <= options->rename_limit && !options->detect_rename))
return -1; 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 (options->setup & DIFF_SETUP_USE_CACHE) {
if (!active_cache) if (!active_cache)
/* read-cache does not die even when it fails /* 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; options->line_termination = 0;
else if (!strncmp(arg, "-l", 2)) else if (!strncmp(arg, "-l", 2))
options->rename_limit = strtoul(arg+2, NULL, 10); options->rename_limit = strtoul(arg+2, NULL, 10);
else if (!strcmp(arg, "--full-index"))
options->full_index = 1;
else if (!strcmp(arg, "--name-only")) else if (!strcmp(arg, "--name-only"))
options->output_format = DIFF_FORMAT_NAME; options->output_format = DIFF_FORMAT_NAME;
else if (!strcmp(arg, "--name-status")) else if (!strcmp(arg, "--name-status"))
@ -1017,7 +1024,7 @@ int diff_unmodified_pair(struct diff_filepair *p)
return 0; 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)) if (diff_unmodified_pair(p))
return; return;
@ -1026,7 +1033,7 @@ static void diff_flush_patch(struct diff_filepair *p)
(DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode))) (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
return; /* no tree diffs in patch format */ return; /* no tree diffs in patch format */
run_diff(p); run_diff(p, o);
} }
int diff_queue_is_empty(void) 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"); die("internal error in diff-resolve-rename-copy");
switch (diff_output_format) { switch (diff_output_format) {
case DIFF_FORMAT_PATCH: case DIFF_FORMAT_PATCH:
diff_flush_patch(p); diff_flush_patch(p, options);
break; break;
case DIFF_FORMAT_RAW: case DIFF_FORMAT_RAW:
case DIFF_FORMAT_NAME_STATUS: case DIFF_FORMAT_NAME_STATUS:

4
diff.h
View file

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

View file

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

View file

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

View file

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

View file

@ -3,16 +3,10 @@
# #
. git-sh-setup || die "Not a git archive" . 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 () { usage () {
echo >&2 "usage: $0 [--signoff] [--dotest=<dir>] [--utf8] [--3way] <mbox>" echo >&2 "usage: $0 [--signoff] [--dotest=<dir>] [--utf8] [--3way] <mbox>"
echo >&2 " or, when resuming" echo >&2 " or, when resuming"
echo >&2 " $0 [--skip]" echo >&2 " $0 [--skip | --resolved]"
exit 1; exit 1;
} }
@ -104,7 +98,7 @@ fall_back_3way () {
} }
prec=4 prec=4
dotest=.dotest sign= utf8= keep= skip= interactive= dotest=.dotest sign= utf8= keep= skip= interactive= resolved=
while case "$#" in 0) break;; esac while case "$#" in 0) break;; esac
do do
@ -128,6 +122,9 @@ do
-k|--k|--ke|--kee|--keep) -k|--k|--ke|--kee|--keep)
keep=t; shift ;; keep=t; shift ;;
-r|--r|--re|--res|--reso|--resol|--resolv|--resolve|--resolved)
resolved=t; shift ;;
--sk|--ski|--skip) --sk|--ski|--skip)
skip=t; shift ;; skip=t; shift ;;
@ -140,6 +137,8 @@ do
esac esac
done done
# If the dotest directory exists, but we have finished applying all the
# patches in them, clear it out.
if test -d "$dotest" && if test -d "$dotest" &&
last=$(cat "$dotest/last") && last=$(cat "$dotest/last") &&
next=$(cat "$dotest/next") && next=$(cat "$dotest/next") &&
@ -155,9 +154,9 @@ then
die "previous dotest directory $dotest still exists but mbox given." die "previous dotest directory $dotest still exists but mbox given."
resume=yes resume=yes
else else
# Make sure we are not given --skip # Make sure we are not given --skip nor --resolved
test ",$skip," = ,, || test ",$skip,$resolved," = ,,, ||
die "we are not resuming." die "we are not resuming."
# Start afresh. # Start afresh.
mkdir -p "$dotest" || exit mkdir -p "$dotest" || exit
@ -170,12 +169,24 @@ else
exit 1 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 "$sign" >"$dotest/sign"
echo "$utf8" >"$dotest/utf8" echo "$utf8" >"$dotest/utf8"
echo "$keep" >"$dotest/keep" echo "$keep" >"$dotest/keep"
echo 1 >"$dotest/next" echo 1 >"$dotest/next"
fi 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 if test "$(cat "$dotest/utf8")" = t
then then
utf8=-u utf8=-u
@ -216,6 +227,15 @@ do
go_next go_next
continue 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 case "$resume" in
'') '')
git-mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \ git-mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \
@ -263,6 +283,13 @@ do
fi fi
} >"$dotest/final-commit" } >"$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 esac
resume= resume=
@ -310,7 +337,21 @@ do
echo "Applying '$SUBJECT'" echo "Applying '$SUBJECT'"
echo 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 if test $apply_status = 1 && test "$threeway" = t
then then
if (fall_back_3way) if (fall_back_3way)

View file

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

View file

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

View file

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

View file

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

View file

@ -3,11 +3,13 @@
# Copyright (C) 2005 Fredrik Kuivinen # 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 heapq import heappush, heappop
from sets import Set from sets import Set
sys.path.append('''@@GIT_PYTHON_PATH@@''')
from gitMergeCommon import * from gitMergeCommon import *
outputIndent = 0 outputIndent = 0

View file

@ -216,7 +216,11 @@ ($$)
-f "$git_dir/svn2git" -f "$git_dir/svn2git"
or die "'$git_dir/svn2git' does not exist.\n". or die "'$git_dir/svn2git' does not exist.\n".
"You need that file for incremental imports.\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) { unless($last_branch) {
warn "Cannot read the last branch name: $! -- assuming 'master'\n"; warn "Cannot read the last branch name: $! -- assuming 'master'\n";
$last_branch = "master"; $last_branch = "master";
@ -766,8 +770,7 @@ sub commit_all {
print "DONE; creating $orig_branch branch\n" if $opt_v and (not defined $opt_l or $opt_l > 0); 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") system("cp","$git_dir/refs/heads/$opt_o","$git_dir/refs/heads/master")
unless -f "$git_dir/refs/heads/master"; unless -f "$git_dir/refs/heads/master";
unlink("$git_dir/HEAD"); system('git-update-ref', 'HEAD', "$orig_branch");
symlink("refs/heads/$orig_branch","$git_dir/HEAD");
unless ($opt_i) { unless ($opt_i) {
system('git checkout'); system('git checkout');
die "checkout failed: $?\n" if $?; 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 # Pass --without docs to rpmbuild if you don't want the documentation
Name: git-core Name: git
Version: @@VERSION@@ Version: @@VERSION@@
Release: 1%{?dist} Release: 1%{?dist}
Summary: Git core and tools 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 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} 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) 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 %description
This is a stupid (but extremely fast) directory content manager. It 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 rudimentary tools that can be used as a SCM, but you should look
elsewhere for tools for ordinary humans layered on top of this. 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 %package svn
Summary: Git tools for importing Subversion repositories Summary: Git tools for importing Subversion repositories
Group: Development/Tools Group: Development/Tools
@ -47,11 +63,11 @@ Requires: git-core = %{version}-%{release}
%description email %description email
Git tools for sending email. Git tools for sending email.
%package tk %package -n gitk
Summary: Git revision tree visualiser ('gitk') Summary: Git revision tree visualiser ('gitk')
Group: Development/Tools Group: Development/Tools
Requires: git-core = %{version}-%{release}, tk >= 8.4 Requires: git-core = %{version}-%{release}, tk >= 8.4
%description tk %description -n gitk
Git revision tree visualiser ('gitk') Git revision tree visualiser ('gitk')
%prep %prep
@ -75,6 +91,9 @@ make %{_smp_mflags} DESTDIR=$RPM_BUILD_ROOT WITH_OWN_SUBPROCESS_PY=YesPlease WIT
%clean %clean
rm -rf $RPM_BUILD_ROOT rm -rf $RPM_BUILD_ROOT
%files
# These are no files in the root package
%files svn %files svn
%defattr(-,root,root) %defattr(-,root,root)
%{_bindir}/*svn* %{_bindir}/*svn*
@ -103,20 +122,25 @@ rm -rf $RPM_BUILD_ROOT
%{!?_without_docs: %{_mandir}/man1/*email*.1*} %{!?_without_docs: %{_mandir}/man1/*email*.1*}
%{!?_without_docs: %doc Documentation/*email*.html } %{!?_without_docs: %doc Documentation/*email*.html }
%files tk %files -n gitk
%defattr(-,root,root) %defattr(-,root,root)
%doc Documentation/*gitk*.txt %doc Documentation/*gitk*.txt
%{_bindir}/*gitk* %{_bindir}/*gitk*
%{!?_without_docs: %{_mandir}/man1/*gitk*.1*} %{!?_without_docs: %{_mandir}/man1/*gitk*.1*}
%{!?_without_docs: %doc Documentation/*gitk*.html } %{!?_without_docs: %doc Documentation/*gitk*.html }
%files -f bin-man-doc-files %files core -f bin-man-doc-files
%defattr(-,root,root) %defattr(-,root,root)
%{_datadir}/git-core/ %{_datadir}/git-core/
%doc README COPYING Documentation/*.txt %doc README COPYING Documentation/*.txt
%{!?_without_docs: %doc Documentation/*.html } %{!?_without_docs: %doc Documentation/*.html }
%changelog %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 * Thu Nov 10 2005 Chris Wright <chrisw@osdl.org> 0.99.9g-1
- zlib dependency fix - zlib dependency fix
- Minor cleanups from split - Minor cleanups from split

View file

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

View file

@ -67,40 +67,66 @@ void created_object(const unsigned char *sha1, struct object *obj)
nr_objs++; 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; return;
pp = &refer->refs;
while ((p = *pp) != NULL) {
if (p->item == target)
return;
pp = &p->next;
} }
target->used = 1; /* Sort the list and filter out duplicates */
p = xmalloc(sizeof(*p)); qsort(refs->ref, refs->count, sizeof(refs->ref[0]),
p->item = target; compare_object_pointers);
p->next = NULL; for (i = j = 1; i < refs->count; i++) {
*pp = p; 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) void mark_reachable(struct object *obj, unsigned int mask)
{ {
struct object_list *p = obj->refs;
if (!track_object_refs) if (!track_object_refs)
die("cannot do reachability with object refs turned off"); die("cannot do reachability with object refs turned off");
/* If we've been here already, don't bother */ /* If we've been here already, don't bother */
if (obj->flags & mask) if (obj->flags & mask)
return; return;
obj->flags |= mask; obj->flags |= mask;
while (p) { if (obj->refs) {
mark_reachable(p->item, mask); const struct object_refs *refs = obj->refs;
p = p->next; 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; const char *name;
}; };
struct object_refs {
unsigned count;
struct object *ref[0];
};
struct object { struct object {
unsigned parsed : 1; unsigned parsed : 1;
unsigned used : 1; unsigned used : 1;
unsigned int flags; unsigned int flags;
unsigned char sha1[20]; unsigned char sha1[20];
const char *type; const char *type;
struct object_list *refs; struct object_refs *refs;
void *util; void *util;
}; };
@ -35,7 +40,8 @@ struct object *parse_object(const unsigned char *sha1);
/** Returns the object, with potentially excess memory allocated. **/ /** Returns the object, with potentially excess memory allocated. **/
struct object *lookup_unknown_object(const unsigned char *sha1); 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); 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); 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 */ /* returns a pointer to an item in front of sha1 */
inline struct llist_item * llist_sorted_remove(struct llist *list, char *sha1, inline struct llist_item * llist_sorted_remove(struct llist *list, char *sha1,
struct llist_item *hint) struct llist_item *hint)
@ -194,6 +162,21 @@ inline struct llist_item * llist_sorted_remove(struct llist *list, char *sha1,
return prev; 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, inline struct pack_list * pack_list_insert(struct pack_list **pl,
struct pack_list *entry) 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; int fd, len, written;
#if USE_SYMLINK_HEAD #if USE_SYMLINK_HEAD
unlink(git_HEAD); if (!only_use_symrefs) {
if (!symlink(refs_heads_master, git_HEAD)) unlink(git_HEAD);
return 0; if (!symlink(refs_heads_master, git_HEAD))
fprintf(stderr, "no symlink - falling back to symbolic ref\n"); return 0;
fprintf(stderr, "no symlink - falling back to symbolic ref\n");
}
#endif #endif
len = snprintf(ref, sizeof(ref), "ref: %s\n", refs_heads_master); 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]; unsigned char sha1[20];
struct object *o; struct object *o;
struct object_list *ref;
int i; int i;
struct packed_git *p = info[pack_ix]->p; struct packed_git *p = info[pack_ix]->p;
int num = num_packed_objects(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); die("corrupt pack file %s?", p->pack_name);
if ((o = lookup_object(sha1)) == NULL) if ((o = lookup_object(sha1)) == NULL)
die("cannot parse %s", sha1_to_hex(sha1)); die("cannot parse %s", sha1_to_hex(sha1));
for (ref = o->refs; ref; ref = ref->next) if (o->refs) {
ref->item->flags = 0; struct object_refs *refs = o->refs;
int j;
for (j = 0; j < refs->count; j++)
refs->ref[j]->flags = 0;
}
o->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); die("corrupt pack file %s?", p->pack_name);
if ((o = lookup_object(sha1)) == NULL) if ((o = lookup_object(sha1)) == NULL)
die("cannot find %s", sha1_to_hex(sha1)); die("cannot find %s", sha1_to_hex(sha1));
for (ref = o->refs; ref; ref = ref->next) if (o->refs) {
ref->item->flags |= REFERENCED; struct object_refs *refs = o->refs;
int j;
for (j = 0; j < refs->count; j++)
refs->ref[j]->flags |= REFERENCED;
}
o->flags |= INTERNAL; o->flags |= INTERNAL;
} }
@ -460,8 +467,12 @@ static void find_pack_info_one(int pack_ix)
die("cannot find %s", sha1_to_hex(sha1)); die("cannot find %s", sha1_to_hex(sha1));
show(o, pack_ix); show(o, pack_ix);
for (ref = o->refs; ref; ref = ref->next) if (o->refs) {
show(ref->item, pack_ix); 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; struct packed_git *p;
unsigned long idx_size; unsigned long idx_size;
void *idx_map; void *idx_map;
char sha1[20]; unsigned char sha1[20];
if (check_packed_git_idx(path, &idx_size, &idx_map)) if (check_packed_git_idx(path, &idx_size, &idx_map))
return NULL; return NULL;

View file

@ -20,6 +20,7 @@ static void check_symref(const char *HEAD)
int main(int argc, const char **argv) int main(int argc, const char **argv)
{ {
setup_git_directory(); setup_git_directory();
git_config(git_default_config);
switch (argc) { switch (argc) {
case 2: case 2:
check_symref(argv[1]); 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 # Test the binaries we have just built. The tests are kept in
# t/ subdirectory and are run in trash subdirectory. # t/ subdirectory and are run in trash subdirectory.
PATH=$(pwd)/..:$PATH PATH=$(pwd)/..:$PATH
GIT_EXEC_PATH=$(pwd)/..
export GIT_EXEC_PATH
# Test repository # Test repository
test=trash 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->tag[taglen] = '\0';
item->tagged = lookup_object_type(object, type); item->tagged = lookup_object_type(object, type);
if (item->tagged) if (item->tagged && track_object_refs) {
add_ref(&item->object, item->tagged); struct object_refs *refs = alloc_object_refs(1);
refs->ref[0] = item->tagged;
set_object_refs(&item->object, refs);
}
return 0; 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; void *bufptr = buffer;
struct tree_entry_list **list_p; struct tree_entry_list **list_p;
int n_refs = 0;
if (item->object.parsed) if (item->object.parsed)
return 0; return 0;
@ -184,11 +185,21 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
obj = &entry->item.blob->object; obj = &entry->item.blob->object;
} }
if (obj) if (obj)
add_ref(&item->object, obj); n_refs++;
entry->parent = NULL; /* needs to be filled by the user */ entry->parent = NULL; /* needs to be filled by the user */
*list_p = entry; *list_p = entry;
list_p = &entry->next; 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; return 0;
} }