Merge branch 'jc/symref'
authorJunio C Hamano <junkio@cox.net>
Thu, 4 May 2006 06:54:55 +0000 (23:54 -0700)
committerJunio C Hamano <junkio@cox.net>
Thu, 4 May 2006 06:54:55 +0000 (23:54 -0700)
* jc/symref:
  core.prefersymlinkrefs: use symlinks for .git/HEAD

26 files changed:
Documentation/git-count-objects.txt
Documentation/git-diff-tree.txt
Documentation/git-repo-config.txt
Documentation/git-update-index.txt
Documentation/glossary.txt
Documentation/sort_glossary.pl
Makefile
blame.c
builtin-count.c [new file with mode: 0644]
builtin-diff.c [new file with mode: 0644]
builtin-push.c [new file with mode: 0644]
builtin.h
combine-diff.c
diff.c
diff.h
git-count-objects.sh [deleted file]
git-cvsserver.perl
git-diff.sh [deleted file]
git.c
log-tree.c
merge-tree.c
repo-config.c
revision.c
sha1_file.c
t/t1300-repo-config.sh
update-index.c

index 47216f4..198ce77 100644 (file)
@@ -7,13 +7,23 @@ git-count-objects - Reports on unpacked objects
 
 SYNOPSIS
 --------
-'git-count-objects'
+'git-count-objects' [-v]
 
 DESCRIPTION
 -----------
 This counts the number of unpacked object files and disk space consumed by
 them, to help you decide when it is a good time to repack.
 
+
+OPTIONS
+-------
+-v::
+       In addition to the number of loose objects and disk
+       space consumed, it reports the number of in-pack
+       objects, and number of objects that can be removed by
+       running `git-prune-packed`.
+
+
 Author
 ------
 Written by Junio C Hamano <junkio@cox.net>
index 2169169..906830d 100644 (file)
@@ -92,7 +92,7 @@ separated with a single space are given.
        Furthermore, it lists only files which were modified
        from all parents.
 
--cc::
+--cc::
        This flag changes the way a merge commit patch is displayed,
        in a similar way to the '-c' option. It implies the '-c'
        and '-p' options and further compresses the patch output
index 566cfa1..ddcf523 100644 (file)
@@ -49,7 +49,7 @@ OPTIONS
 
 --replace-all::
        Default behaviour is to replace at most one line. This replaces
-       all lines matching the key (and optionally the value_regex)
+       all lines matching the key (and optionally the value_regex).
 
 --get::
        Get the value for a given key (optionally filtered by a regex
@@ -59,6 +59,9 @@ OPTIONS
        Like get, but does not fail if the number of values for the key
        is not exactly one.
 
+--get-regexp::
+       Like --get-all, but interprets the name as a regular expression.
+
 --unset::
        Remove the line matching the key from .git/config.
 
index d4137fc..23f2b6f 100644 (file)
@@ -10,12 +10,12 @@ SYNOPSIS
 --------
 [verse]
 'git-update-index'
-            [--add] [--remove | --force-remove] [--replace] 
-            [--refresh [-q] [--unmerged] [--ignore-missing]]
+            [--add] [--remove | --force-remove] [--replace]
+            [--refresh] [-q] [--unmerged] [--ignore-missing]
             [--cacheinfo <mode> <object> <file>]\*
             [--chmod=(+|-)x]
             [--assume-unchanged | --no-assume-unchanged]
-            [--really-refresh]
+            [--really-refresh] [--unresolve]
             [--info-only] [--index-info]
             [-z] [--stdin]
             [--verbose]
@@ -80,6 +80,10 @@ OPTIONS
        filesystem that has very slow lstat(2) system call
        (e.g. cifs).
 
+--unresolve::
+       Restores the 'unmerged' or 'needs updating' state of a
+       file during a merge if it was cleared by accident.
+
 --info-only::
        Do not create objects in the object database for all
        <file> arguments that follow this flag; just insert
index 02a9d9c..39c90ad 100644 (file)
@@ -1,79 +1,57 @@
-object::
-       The unit of storage in git. It is uniquely identified by
-       the SHA1 of its contents. Consequently, an object can not
-       be changed.
-
-object name::
-       The unique identifier of an object. The hash of the object's contents
-       using the Secure Hash Algorithm 1 and usually represented by the 40
-       character hexadecimal encoding of the hash of the object (possibly
-       followed by a white space).
-
-SHA1::
-       Synonym for object name.
-
-object identifier::
-       Synonym for object name.
-
-hash::
-       In git's context, synonym to object name.
+alternate object database::
+       Via the alternates mechanism, a repository can inherit part of its
+       object database from another object database, which is called
+       "alternate".
 
-object database::
-       Stores a set of "objects", and an individual object is identified
-       by its object name. The objects usually live in `$GIT_DIR/objects/`.
+bare repository::
+       A bare repository is normally an appropriately named
+       directory with a `.git` suffix that does not have a
+       locally checked-out copy of any of the files under revision
+       control.  That is, all of the `git` administrative and
+       control files that would normally be present in the
+       hidden `.git` sub-directory are directly present in
+       the `repository.git` directory instead, and no other files
+       are present and checked out.  Usually publishers of public
+       repositories make bare repositories available.
 
 blob object::
        Untyped object, e.g. the contents of a file.
 
-tree object::
-       An object containing a list of file names and modes along with refs
-       to the associated blob and/or tree objects. A tree is equivalent
-       to a directory.
-
-tree::
-       Either a working tree, or a tree object together with the
-       dependent blob and tree objects (i.e. a stored representation
-       of a working tree).
-
-DAG::
-       Directed acyclic graph. The commit objects form a directed acyclic
-       graph, because they have parents (directed), and the graph of commit
-       objects is acyclic (there is no chain which begins and ends with the
-       same object).
-
-index::
-       A collection of files with stat information, whose contents are
-       stored as objects. The index is a stored version of your working
-       tree. Truth be told, it can also contain a second, and even a third
-       version of a working tree, which are used when merging.
-
-index entry::
-       The information regarding a particular file, stored in the index.
-       An index entry can be unmerged, if a merge was started, but not
-       yet finished (i.e. if the index contains multiple versions of
-       that file).
-
-unmerged index:
-       An index which contains unmerged index entries.
+branch::
+       A non-cyclical graph of revisions, i.e. the complete history of
+       a particular revision, which is called the branch head. The
+       branch heads are stored in `$GIT_DIR/refs/heads/`.
 
 cache::
        Obsolete for: index.
 
-working tree::
-       The set of files and directories currently being worked on,
-       i.e. you can work in your working tree without using git at all.
-
-directory::
-       The list you get with "ls" :-)
+chain::
+       A list of objects, where each object in the list contains a
+       reference to its successor (for example, the successor of a commit
+       could be one of its parents).
 
-revision::
-       A particular state of files and directories which was stored in
-       the object database. It is referenced by a commit object.
+changeset::
+       BitKeeper/cvsps speak for "commit". Since git does not store
+       changes, but states, it really does not make sense to use
+       the term "changesets" with git.
 
 checkout::
        The action of updating the working tree to a revision which was
        stored in the object database.
 
+cherry-picking::
+       In SCM jargon, "cherry pick" means to choose a subset of
+       changes out of a series of changes (typically commits)
+       and record them as a new series of changes on top of
+       different codebase.  In GIT, this is performed by
+       "git cherry-pick" command to extract the change
+       introduced by an existing commit and to record it based
+       on the tip of the current branch as a new commit.
+
+clean::
+       A working tree is clean, if it corresponds to the revision
+       referenced by the current head.  Also see "dirty".
+
 commit::
        As a verb: The action of storing the current state of the index in the
        object database. The result is a revision.
@@ -85,73 +63,90 @@ commit object::
        tree object which corresponds to the top directory of the
        stored revision.
 
-parent::
-       A commit object contains a (possibly empty) list of the logical
-       predecessor(s) in the line of development, i.e. its parents.
+core git::
+       Fundamental data structures and utilities of git. Exposes only
+       limited source code management tools.
 
-changeset::
-       BitKeeper/cvsps speak for "commit". Since git does not store
-       changes, but states, it really does not make sense to use
-       the term "changesets" with git.
+DAG::
+       Directed acyclic graph. The commit objects form a directed acyclic
+       graph, because they have parents (directed), and the graph of commit
+       objects is acyclic (there is no chain which begins and ends with the
+       same object).
 
-clean::
-       A working tree is clean, if it corresponds to the revision
-       referenced by the current head.
+dircache::
+       You are *waaaaay* behind.
 
 dirty::
        A working tree is said to be dirty if it contains modifications
        which have not been committed to the current branch.
 
-head::
-       The top of a branch. It contains a ref to the corresponding
-       commit object.
+directory::
+       The list you get with "ls" :-)
 
-branch::
-       A non-cyclical graph of revisions, i.e. the complete history of
-       a particular revision, which is called the branch head. The
-       branch heads are stored in `$GIT_DIR/refs/heads/`.
+ent::
+       Favorite synonym to "tree-ish" by some total geeks. See
+       `http://en.wikipedia.org/wiki/Ent_(Middle-earth)` for an in-depth
+       explanation.
 
-master::
-       The default branch. Whenever you create a git repository, a branch
-       named "master" is created, and becomes the active branch. In most
-       cases, this contains the local development.
+fast forward::
+       A fast-forward is a special type of merge where you have
+       a revision and you are "merging" another branch's changes
+       that happen to be a descendant of what you have.
+       In such these cases, you do not make a new merge commit but
+       instead just update to his revision. This will happen
+       frequently on a tracking branch of a remote repository.
 
-origin::
-       The default upstream branch. Most projects have one upstream
-       project which they track, and by default 'origin' is used for
-       that purpose.  New updates from upstream will be fetched into
-       this branch; you should never commit to it yourself.
+fetch::
+       Fetching a branch means to get the branch's head ref from a
+       remote repository, to find out which objects are missing from
+       the local object database, and to get them, too.
 
-ref::
-       A 40-byte hex representation of a SHA1 pointing to a particular
-       object. These may be stored in `$GIT_DIR/refs/`.
+file system::
+       Linus Torvalds originally designed git to be a user space file
+       system, i.e. the infrastructure to hold files and directories.
+       That ensured the efficiency and speed of git.
+
+git archive::
+       Synonym for repository (for arch people).
+
+hash::
+       In git's context, synonym to object name.
+
+head::
+       The top of a branch. It contains a ref to the corresponding
+       commit object.
 
 head ref::
        A ref pointing to a head. Often, this is abbreviated to "head".
        Head refs are stored in `$GIT_DIR/refs/heads/`.
 
-tree-ish::
-       A ref pointing to either a commit object, a tree object, or a
-       tag object pointing to a tag or commit or tree object.
+hook::
+       During the normal execution of several git commands,
+       call-outs are made to optional scripts that allow
+       a developer to add functionality or checking.
+       Typically, the hooks allow for a command to be pre-verified
+       and potentially aborted, and allow for a post-notification
+       after the operation is done.
+       The hook scripts are found in the `$GIT_DIR/hooks/` directory,
+       and are enabled by simply making them executable.
 
-ent::
-       Favorite synonym to "tree-ish" by some total geeks. See
-       `http://en.wikipedia.org/wiki/Ent_(Middle-earth)` for an in-depth
-       explanation.
+index::
+       A collection of files with stat information, whose contents are
+       stored as objects. The index is a stored version of your working
+       tree. Truth be told, it can also contain a second, and even a third
+       version of a working tree, which are used when merging.
 
-tag object::
-       An object containing a ref pointing to another object, which can
-       contain a message just like a commit object. It can also
-       contain a (PGP) signature, in which case it is called a "signed
-       tag object".
+index entry::
+       The information regarding a particular file, stored in the index.
+       An index entry can be unmerged, if a merge was started, but not
+       yet finished (i.e. if the index contains multiple versions of
+       that file).
 
-tag::
-       A ref pointing to a tag or commit object. In contrast to a head,
-       a tag is not changed by a commit. Tags (not tag objects) are
-       stored in `$GIT_DIR/refs/tags/`. A git tag has nothing to do with
-       a Lisp tag (which is called object type in git's context).
-       A tag is most typically used to mark a particular point in the
-       commit ancestry chain.
+master::
+       The default development branch. Whenever you create a git
+       repository, a branch named "master" is created, and becomes
+       the active branch. In most cases, this contains the local
+       development, though that is purely conventional and not required.
 
 merge::
        To merge branches means to try to accumulate the changes since a
@@ -159,55 +154,65 @@ merge::
        merge uses heuristics to accomplish that. Evidently, an automatic
        merge can fail.
 
-octopus::
-       To merge more than two branches. Also denotes an intelligent
-       predator.
+object::
+       The unit of storage in git. It is uniquely identified by
+       the SHA1 of its contents. Consequently, an object can not
+       be changed.
 
-resolve::
-       The action of fixing up manually what a failed automatic merge
-       left behind.
+object database::
+       Stores a set of "objects", and an individual object is identified
+       by its object name. The objects usually live in `$GIT_DIR/objects/`.
 
-rewind::
-       To throw away part of the development, i.e. to assign the head to
-       an earlier revision.
+object identifier::
+       Synonym for object name.
 
-rebase::
-       To clean a branch by starting from the head of the main line of
-       development ("master"), and reapply the (possibly cherry-picked)
-       changes from that branch.
+object name::
+       The unique identifier of an object. The hash of the object's contents
+       using the Secure Hash Algorithm 1 and usually represented by the 40
+       character hexadecimal encoding of the hash of the object (possibly
+       followed by a white space).
 
-repository::
-       A collection of refs together with an object database containing
-       all objects, which are reachable from the refs, possibly accompanied
-       by meta data from one or more porcelains. A repository can
-       share an object database with other repositories.
+object type:
+       One of the identifiers "commit","tree","tag" and "blob" describing
+       the type of an object.
 
-git archive::
-       Synonym for repository (for arch people).
+octopus::
+       To merge more than two branches. Also denotes an intelligent
+       predator.
 
-file system::
-       Linus Torvalds originally designed git to be a user space file
-       system, i.e. the infrastructure to hold files and directories.
-       That ensured the efficiency and speed of git.
+origin::
+       The default upstream tracking branch. Most projects have at
+       least one upstream project which they track. By default
+       'origin' is used for that purpose.  New upstream updates
+       will be fetched into this branch; you should never commit
+       to it yourself.
 
-alternate object database::
-       Via the alternates mechanism, a repository can inherit part of its
-       object database from another object database, which is called
-       "alternate".
+pack::
+       A set of objects which have been compressed into one file (to save
+       space or to transmit them efficiently).
 
-reachable::
-       An object is reachable from a ref/commit/tree/tag, if there is a
-       chain leading from the latter to the former.
+pack index::
+       The list of identifiers, and other information, of the objects in a
+       pack, to assist in efficiently accessing the contents of a pack.
 
-chain::
-       A list of objects, where each object in the list contains a
-       reference to its successor (for example, the successor of a commit
-       could be one of its parents).
+parent::
+       A commit object contains a (possibly empty) list of the logical
+       predecessor(s) in the line of development, i.e. its parents.
 
-fetch::
-       Fetching a branch means to get the branch's head ref from a
-       remote repository, to find out which objects are missing from
-       the local object database, and to get them, too.
+pickaxe::
+       The term pickaxe refers to an option to the diffcore routines
+       that help select changes that add or delete a given text string.
+       With the --pickaxe-all option, it can be used to view the
+       full changeset that introduced or removed, say, a particular
+       line of text.  See gitlink:git-diff[1].
+
+plumbing::
+       Cute name for core git.
+
+porcelain::
+       Cute name for programs and program suites depending on core git,
+       presenting a high level access to core git. Porcelains expose
+       more of a SCM interface than the plumbing.
 
 pull::
        Pulling a branch means to fetch it and merge it.
@@ -221,33 +226,101 @@ push::
        the remote head ref. If the remote head is not an ancestor to the
        local head, the push fails.
 
-pack::
-       A set of objects which have been compressed into one file (to save
-       space or to transmit them efficiently).
+reachable::
+       An object is reachable from a ref/commit/tree/tag, if there is a
+       chain leading from the latter to the former.
 
-pack index::
-       The list of identifiers, and other information, of the objects in a
-       pack, to assist in efficiently accessing the contents of a pack. 
+rebase::
+       To clean a branch by starting from the head of the main line of
+       development ("master"), and reapply the (possibly cherry-picked)
+       changes from that branch.
 
-core git::
-       Fundamental data structures and utilities of git. Exposes only
-       limited source code management tools.
+ref::
+       A 40-byte hex representation of a SHA1 or a name that denotes
+       a particular object. These may be stored in `$GIT_DIR/refs/`.
+
+refspec::
+       A refspec is used by fetch and push to describe the mapping
+       between remote ref and local ref.  They are combined with
+       a colon in the format <src>:<dst>, preceded by an optional
+       plus sign, +.  For example:
+       `git fetch $URL refs/heads/master:refs/heads/origin`
+       means "grab the master branch head from the $URL and store
+       it as my origin branch head".
+       And `git push $URL refs/heads/master:refs/heads/to-upstream`
+       means "publish my master branch head as to-upstream master head
+       at $URL".   See also gitlink:git-push[1]
 
-plumbing::
-       Cute name for core git.
+repository::
+       A collection of refs together with an object database containing
+       all objects, which are reachable from the refs, possibly accompanied
+       by meta data from one or more porcelains. A repository can
+       share an object database with other repositories.
 
-porcelain::
-       Cute name for programs and program suites depending on core git,
-       presenting a high level access to core git. Porcelains expose
-       more of a SCM interface than the plumbing.
+resolve::
+       The action of fixing up manually what a failed automatic merge
+       left behind.
 
-object type:
-       One of the identifiers "commit","tree","tag" and "blob" describing
-       the type of an object.
+revision::
+       A particular state of files and directories which was stored in
+       the object database. It is referenced by a commit object.
+
+rewind::
+       To throw away part of the development, i.e. to assign the head to
+       an earlier revision.
 
 SCM::
        Source code management (tool).
 
-dircache::
-       You are *waaaaay* behind.
+SHA1::
+       Synonym for object name.
+
+topic branch::
+       A regular git branch that is used by a developer to
+       identify a conceptual line of development.  Since branches
+       are very easy and inexpensive, it is often desirable to
+       have several small branches that each contain very well
+       defined concepts or small incremental yet related changes.
+
+tracking branch::
+       A regular git branch that is used to follow changes from
+       another repository.  A tracking branch should not contain
+       direct modifications or have local commits made to it.
+       A tracking branch can usually be identified as the
+       right-hand-side ref in a Pull: refspec.
+
+tree object::
+       An object containing a list of file names and modes along with refs
+       to the associated blob and/or tree objects. A tree is equivalent
+       to a directory.
+
+tree::
+       Either a working tree, or a tree object together with the
+       dependent blob and tree objects (i.e. a stored representation
+       of a working tree).
+
+tree-ish::
+       A ref pointing to either a commit object, a tree object, or a
+       tag object pointing to a tag or commit or tree object.
+
+tag object::
+       An object containing a ref pointing to another object, which can
+       contain a message just like a commit object. It can also
+       contain a (PGP) signature, in which case it is called a "signed
+       tag object".
+
+tag::
+       A ref pointing to a tag or commit object. In contrast to a head,
+       a tag is not changed by a commit. Tags (not tag objects) are
+       stored in `$GIT_DIR/refs/tags/`. A git tag has nothing to do with
+       a Lisp tag (which is called object type in git's context).
+       A tag is most typically used to mark a particular point in the
+       commit ancestry chain.
+
+unmerged index:
+       An index which contains unmerged index entries.
+
+working tree::
+       The set of files and directories currently being worked on,
+       i.e. you can work in your working tree without using git at all.
 
index e57dc78..e0bc552 100644 (file)
@@ -48,7 +48,7 @@ This list is sorted alphabetically:
 ';
 
 @keys=sort {uc($a) cmp uc($b)} keys %terms;
-$pattern='(\b'.join('\b|\b',reverse @keys).'\b)';
+$pattern='(\b(?<!link:git-)'.join('\b|\b(?<!link:git-)',reverse @keys).'\b)';
 foreach $key (@keys) {
        $terms{$key}=~s/$pattern/sprintf "<<ref_".no_spaces($1).",$1>>";/eg;
        print '[[ref_'.no_spaces($key).']]'.$key."::\n"
index cb6bb72..fea20cc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -115,10 +115,10 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
 SCRIPT_SH = \
        git-add.sh git-bisect.sh git-branch.sh git-checkout.sh \
        git-cherry.sh git-clean.sh git-clone.sh git-commit.sh \
-       git-count-objects.sh git-diff.sh git-fetch.sh \
+       git-fetch.sh \
        git-format-patch.sh git-ls-remote.sh \
        git-merge-one-file.sh git-parse-remote.sh \
-       git-prune.sh git-pull.sh git-push.sh git-rebase.sh \
+       git-prune.sh git-pull.sh git-rebase.sh \
        git-repack.sh git-request-pull.sh git-reset.sh \
        git-resolve.sh git-revert.sh git-rm.sh git-sh-setup.sh \
        git-tag.sh git-verify-tag.sh git-whatchanged.sh \
@@ -167,7 +167,8 @@ PROGRAMS = \
        git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \
        git-describe$X git-merge-tree$X git-blame$X git-imap-send$X
 
-BUILT_INS = git-log$X
+BUILT_INS = git-log$X \
+       git-count-objects$X git-diff$X git-push$X
 
 # what 'all' will build and 'install' will install, in gitexecdir
 ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -214,7 +215,7 @@ LIB_OBJS = \
        $(DIFF_OBJS)
 
 BUILTIN_OBJS = \
-       builtin-log.o builtin-help.o
+       builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o
 
 GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
 LIBS = $(GITLIBS) -lz
diff --git a/blame.c b/blame.c
index 07d2d27..99ceea8 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -515,9 +515,9 @@ static int compare_tree_path(struct rev_info* revs,
        paths[1] = NULL;
 
        diff_tree_setup_paths(get_pathspec(revs->prefix, paths),
-                             &revs->diffopt);
+                             &revs->pruning);
        ret = rev_compare_tree(revs, c1->tree, c2->tree);
-       diff_tree_release_paths(&revs->diffopt);
+       diff_tree_release_paths(&revs->pruning);
        return ret;
 }
 
@@ -531,9 +531,9 @@ static int same_tree_as_empty_path(struct rev_info *revs, struct tree* t1,
        paths[1] = NULL;
 
        diff_tree_setup_paths(get_pathspec(revs->prefix, paths),
-                             &revs->diffopt);
+                             &revs->pruning);
        ret = rev_same_tree_as_empty(revs, t1);
-       diff_tree_release_paths(&revs->diffopt);
+       diff_tree_release_paths(&revs->pruning);
        return ret;
 }
 
@@ -834,7 +834,7 @@ int main(int argc, const char **argv)
 
        args[0] = filename;
        args[1] = NULL;
-       diff_tree_setup_paths(args, &rev.diffopt);
+       diff_tree_setup_paths(args, &rev.pruning);
        prepare_revision_walk(&rev);
        process_commits(&rev, filename, &initial);
 
diff --git a/builtin-count.c b/builtin-count.c
new file mode 100644 (file)
index 0000000..5ee72df
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Builtin "git count-objects".
+ *
+ * Copyright (c) 2006 Junio C Hamano
+ */
+
+#include "cache.h"
+#include "builtin.h"
+
+static const char count_objects_usage[] = "git-count-objects [-v]";
+
+static void count_objects(DIR *d, char *path, int len, int verbose,
+                         unsigned long *loose,
+                         unsigned long *loose_size,
+                         unsigned long *packed_loose,
+                         unsigned long *garbage)
+{
+       struct dirent *ent;
+       while ((ent = readdir(d)) != NULL) {
+               char hex[41];
+               unsigned char sha1[20];
+               const char *cp;
+               int bad = 0;
+
+               if ((ent->d_name[0] == '.') &&
+                   (ent->d_name[1] == 0 ||
+                    ((ent->d_name[1] == '.') && (ent->d_name[2] == 0))))
+                       continue;
+               for (cp = ent->d_name; *cp; cp++) {
+                       int ch = *cp;
+                       if (('0' <= ch && ch <= '9') ||
+                           ('a' <= ch && ch <= 'f'))
+                               continue;
+                       bad = 1;
+                       break;
+               }
+               if (cp - ent->d_name != 38)
+                       bad = 1;
+               else {
+                       struct stat st;
+                       memcpy(path + len + 3, ent->d_name, 38);
+                       path[len + 2] = '/';
+                       path[len + 41] = 0;
+                       if (lstat(path, &st) || !S_ISREG(st.st_mode))
+                               bad = 1;
+                       else
+                               (*loose_size) += st.st_blocks;
+               }
+               if (bad) {
+                       if (verbose) {
+                               error("garbage found: %.*s/%s",
+                                     len + 2, path, ent->d_name);
+                               (*garbage)++;
+                       }
+                       continue;
+               }
+               (*loose)++;
+               if (!verbose)
+                       continue;
+               memcpy(hex, path+len, 2);
+               memcpy(hex+2, ent->d_name, 38);
+               hex[40] = 0;
+               if (get_sha1_hex(hex, sha1))
+                       die("internal error");
+               if (has_sha1_pack(sha1))
+                       (*packed_loose)++;
+       }
+}
+
+int cmd_count_objects(int ac, const char **av, char **ep)
+{
+       int i;
+       int verbose = 0;
+       const char *objdir = get_object_directory();
+       int len = strlen(objdir);
+       char *path = xmalloc(len + 50);
+       unsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0;
+       unsigned long loose_size = 0;
+
+       for (i = 1; i < ac; i++) {
+               const char *arg = av[i];
+               if (*arg != '-')
+                       break;
+               else if (!strcmp(arg, "-v"))
+                       verbose = 1;
+               else
+                       usage(count_objects_usage);
+       }
+
+       /* we do not take arguments other than flags for now */
+       if (i < ac)
+               usage(count_objects_usage);
+       memcpy(path, objdir, len);
+       if (len && objdir[len-1] != '/')
+               path[len++] = '/';
+       for (i = 0; i < 256; i++) {
+               DIR *d;
+               sprintf(path + len, "%02x", i);
+               d = opendir(path);
+               if (!d)
+                       continue;
+               count_objects(d, path, len, verbose,
+                             &loose, &loose_size, &packed_loose, &garbage);
+               closedir(d);
+       }
+       if (verbose) {
+               struct packed_git *p;
+               if (!packed_git)
+                       prepare_packed_git();
+               for (p = packed_git; p; p = p->next) {
+                       if (!p->pack_local)
+                               continue;
+                       packed += num_packed_objects(p);
+               }
+               printf("count: %lu\n", loose);
+               printf("size: %lu\n", loose_size / 2);
+               printf("in-pack: %lu\n", packed);
+               printf("prune-packable: %lu\n", packed_loose);
+               printf("garbage: %lu\n", garbage);
+       }
+       else
+               printf("%lu objects, %lu kilobytes\n",
+                      loose, loose_size / 2);
+       return 0;
+}
diff --git a/builtin-diff.c b/builtin-diff.c
new file mode 100644 (file)
index 0000000..636edbf
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * Builtin "git diff"
+ *
+ * Copyright (c) 2006 Junio C Hamano
+ */
+#include "cache.h"
+#include "commit.h"
+#include "blob.h"
+#include "tag.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "revision.h"
+#include "log-tree.h"
+#include "builtin.h"
+
+/* NEEDSWORK: struct object has place for name but we _do_
+ * know mode when we extracted the blob out of a tree, which
+ * we currently lose.
+ */
+struct blobinfo {
+       unsigned char sha1[20];
+       const char *name;
+};
+
+static const char builtin_diff_usage[] =
+"diff <options> <rev>{0,2} -- <path>*";
+
+static int builtin_diff_files(struct rev_info *revs,
+                             int argc, const char **argv)
+{
+       int silent = 0;
+       while (1 < argc) {
+               const char *arg = argv[1];
+               if (!strcmp(arg, "--base"))
+                       revs->max_count = 1;
+               else if (!strcmp(arg, "--ours"))
+                       revs->max_count = 2;
+               else if (!strcmp(arg, "--theirs"))
+                       revs->max_count = 3;
+               else if (!strcmp(arg, "-q"))
+                       silent = 1;
+               else if (!strcmp(arg, "--raw"))
+                       revs->diffopt.output_format = DIFF_FORMAT_RAW;
+               else
+                       usage(builtin_diff_usage);
+               argv++; argc--;
+       }
+       /*
+        * Make sure there are NO revision (i.e. pending object) parameter,
+        * specified rev.max_count is reasonable (0 <= n <= 3), and
+        * there is no other revision filtering parameter.
+        */
+       if (revs->pending_objects ||
+           revs->min_age != -1 ||
+           revs->max_age != -1 ||
+           3 < revs->max_count)
+               usage(builtin_diff_usage);
+       if (revs->max_count < 0 &&
+           (revs->diffopt.output_format == DIFF_FORMAT_PATCH))
+               revs->combine_merges = revs->dense_combined_merges = 1;
+       /*
+        * Backward compatibility wart - "diff-files -s" used to
+        * defeat the common diff option "-s" which asked for
+        * DIFF_FORMAT_NO_OUTPUT.
+        */
+       if (revs->diffopt.output_format == DIFF_FORMAT_NO_OUTPUT)
+               revs->diffopt.output_format = DIFF_FORMAT_RAW;
+       return run_diff_files(revs, silent);
+}
+
+static void stuff_change(struct diff_options *opt,
+                        unsigned old_mode, unsigned new_mode,
+                        const unsigned char *old_sha1,
+                        const unsigned char *new_sha1,
+                        const char *old_name,
+                        const char *new_name)
+{
+       struct diff_filespec *one, *two;
+
+       if (memcmp(null_sha1, old_sha1, 20) &&
+           memcmp(null_sha1, new_sha1, 20) &&
+           !memcmp(old_sha1, new_sha1, 20))
+               return;
+
+       if (opt->reverse_diff) {
+               unsigned tmp;
+               const
+                       const unsigned char *tmp_u;
+               const char *tmp_c;
+               tmp = old_mode; old_mode = new_mode; new_mode = tmp;
+               tmp_u = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_u;
+               tmp_c = old_name; old_name = new_name; new_name = tmp_c;
+       }
+       one = alloc_filespec(old_name);
+       two = alloc_filespec(new_name);
+       fill_filespec(one, old_sha1, old_mode);
+       fill_filespec(two, new_sha1, new_mode);
+
+       /* NEEDSWORK: shouldn't this part of diffopt??? */
+       diff_queue(&diff_queued_diff, one, two);
+}
+
+static int builtin_diff_b_f(struct rev_info *revs,
+                           int argc, const char **argv,
+                           struct blobinfo *blob,
+                           const char *path)
+{
+       /* Blob vs file in the working tree*/
+       struct stat st;
+
+       while (1 < argc) {
+               const char *arg = argv[1];
+               if (!strcmp(arg, "--raw"))
+                       revs->diffopt.output_format = DIFF_FORMAT_RAW;
+               else
+                       usage(builtin_diff_usage);
+               argv++; argc--;
+       }
+       if (lstat(path, &st))
+               die("'%s': %s", path, strerror(errno));
+       if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
+               die("'%s': not a regular file or symlink", path);
+       stuff_change(&revs->diffopt,
+                    canon_mode(st.st_mode), canon_mode(st.st_mode),
+                    blob[0].sha1, null_sha1,
+                    blob[0].name, path);
+       diffcore_std(&revs->diffopt);
+       diff_flush(&revs->diffopt);
+       return 0;
+}
+
+static int builtin_diff_blobs(struct rev_info *revs,
+                             int argc, const char **argv,
+                             struct blobinfo *blob)
+{
+       /* Blobs */
+       unsigned mode = canon_mode(S_IFREG | 0644);
+
+       while (1 < argc) {
+               const char *arg = argv[1];
+               if (!strcmp(arg, "--raw"))
+                       revs->diffopt.output_format = DIFF_FORMAT_RAW;
+               else
+                       usage(builtin_diff_usage);
+               argv++; argc--;
+       }
+       stuff_change(&revs->diffopt,
+                    mode, mode,
+                    blob[0].sha1, blob[1].sha1,
+                    blob[1].name, blob[1].name);
+       diffcore_std(&revs->diffopt);
+       diff_flush(&revs->diffopt);
+       return 0;
+}
+
+static int builtin_diff_index(struct rev_info *revs,
+                             int argc, const char **argv)
+{
+       int cached = 0;
+       while (1 < argc) {
+               const char *arg = argv[1];
+               if (!strcmp(arg, "--cached"))
+                       cached = 1;
+               else if (!strcmp(arg, "--raw"))
+                       revs->diffopt.output_format = DIFF_FORMAT_RAW;
+               else
+                       usage(builtin_diff_usage);
+               argv++; argc--;
+       }
+       /*
+        * Make sure there is one revision (i.e. pending object),
+        * and there is no revision filtering parameters.
+        */
+       if (!revs->pending_objects || revs->pending_objects->next ||
+           revs->max_count != -1 || revs->min_age != -1 ||
+           revs->max_age != -1)
+               usage(builtin_diff_usage);
+       return run_diff_index(revs, cached);
+}
+
+static int builtin_diff_tree(struct rev_info *revs,
+                            int argc, const char **argv,
+                            struct object_list *ent)
+{
+       const unsigned char *(sha1[2]);
+       int swap = 1;
+       while (1 < argc) {
+               const char *arg = argv[1];
+               if (!strcmp(arg, "--raw"))
+                       revs->diffopt.output_format = DIFF_FORMAT_RAW;
+               else
+                       usage(builtin_diff_usage);
+               argv++; argc--;
+       }
+
+       /* We saw two trees, ent[0] and ent[1].
+        * unless ent[0] is unintesting, they are swapped
+        */
+       if (ent[0].item->flags & UNINTERESTING)
+               swap = 0;
+       sha1[swap] = ent[0].item->sha1;
+       sha1[1-swap] = ent[1].item->sha1;
+       diff_tree_sha1(sha1[0], sha1[1], "", &revs->diffopt);
+       log_tree_diff_flush(revs);
+       return 0;
+}
+
+static int builtin_diff_combined(struct rev_info *revs,
+                                int argc, const char **argv,
+                                struct object_list *ent,
+                                int ents)
+{
+       const unsigned char (*parent)[20];
+       int i;
+
+       while (1 < argc) {
+               const char *arg = argv[1];
+               if (!strcmp(arg, "--raw"))
+                       revs->diffopt.output_format = DIFF_FORMAT_RAW;
+               else
+                       usage(builtin_diff_usage);
+               argv++; argc--;
+       }
+       if (!revs->dense_combined_merges && !revs->combine_merges)
+               revs->dense_combined_merges = revs->combine_merges = 1;
+       parent = xmalloc(ents * sizeof(*parent));
+       /* Again, the revs are all reverse */
+       for (i = 0; i < ents; i++)
+               memcpy(parent + i, ent[ents - 1 - i].item->sha1, 20);
+       diff_tree_combined(parent[0], parent + 1, ents - 1,
+                          revs->dense_combined_merges, revs);
+       return 0;
+}
+
+static void add_head(struct rev_info *revs)
+{
+       unsigned char sha1[20];
+       struct object *obj;
+       if (get_sha1("HEAD", sha1))
+               return;
+       obj = parse_object(sha1);
+       if (!obj)
+               return;
+       add_object(obj, &revs->pending_objects, NULL, "HEAD");
+}
+
+int cmd_diff(int argc, const char **argv, char **envp)
+{
+       struct rev_info rev;
+       struct object_list *list, ent[100];
+       int ents = 0, blobs = 0, paths = 0;
+       const char *path = NULL;
+       struct blobinfo blob[2];
+
+       /*
+        * We could get N tree-ish in the rev.pending_objects list.
+        * Also there could be M blobs there, and P pathspecs.
+        *
+        * N=0, M=0:
+        *      cache vs files (diff-files)
+        * N=0, M=2:
+        *      compare two random blobs.  P must be zero.
+        * N=0, M=1, P=1:
+        *      compare a blob with a working tree file.
+        *
+        * N=1, M=0:
+        *      tree vs cache (diff-index --cached)
+        *
+        * N=2, M=0:
+        *      tree vs tree (diff-tree)
+        *
+        * Other cases are errors.
+        */
+
+       git_config(git_diff_config);
+       init_revisions(&rev);
+       rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+
+       argc = setup_revisions(argc, argv, &rev, NULL);
+       /* Do we have --cached and not have a pending object, then
+        * default to HEAD by hand.  Eek.
+        */
+       if (!rev.pending_objects) {
+               int i;
+               for (i = 1; i < argc; i++) {
+                       const char *arg = argv[i];
+                       if (!strcmp(arg, "--"))
+                               break;
+                       else if (!strcmp(arg, "--cached")) {
+                               add_head(&rev);
+                               break;
+                       }
+               }
+       }
+
+       for (list = rev.pending_objects; list; list = list->next) {
+               struct object *obj = list->item;
+               const char *name = list->name;
+               int flags = (obj->flags & UNINTERESTING);
+               if (!obj->parsed)
+                       obj = parse_object(obj->sha1);
+               obj = deref_tag(obj, NULL, 0);
+               if (!obj)
+                       die("invalid object '%s' given.", name);
+               if (!strcmp(obj->type, commit_type))
+                       obj = &((struct commit *)obj)->tree->object;
+               if (!strcmp(obj->type, tree_type)) {
+                       if (ARRAY_SIZE(ent) <= ents)
+                               die("more than %d trees given: '%s'",
+                                   (int) ARRAY_SIZE(ent), name);
+                       obj->flags |= flags;
+                       ent[ents].item = obj;
+                       ent[ents].name = name;
+                       ents++;
+                       continue;
+               }
+               if (!strcmp(obj->type, blob_type)) {
+                       if (2 <= blobs)
+                               die("more than two blobs given: '%s'", name);
+                       memcpy(blob[blobs].sha1, obj->sha1, 20);
+                       blob[blobs].name = name;
+                       blobs++;
+                       continue;
+
+               }
+               die("unhandled object '%s' given.", name);
+       }
+       if (rev.prune_data) {
+               const char **pathspec = rev.prune_data;
+               while (*pathspec) {
+                       if (!path)
+                               path = *pathspec;
+                       paths++;
+                       pathspec++;
+               }
+       }
+
+       /*
+        * Now, do the arguments look reasonable?
+        */
+       if (!ents) {
+               switch (blobs) {
+               case 0:
+                       return builtin_diff_files(&rev, argc, argv);
+                       break;
+               case 1:
+                       if (paths != 1)
+                               usage(builtin_diff_usage);
+                       return builtin_diff_b_f(&rev, argc, argv, blob, path);
+                       break;
+               case 2:
+                       if (paths)
+                               usage(builtin_diff_usage);
+                       return builtin_diff_blobs(&rev, argc, argv, blob);
+                       break;
+               default:
+                       usage(builtin_diff_usage);
+               }
+       }
+       else if (blobs)
+               usage(builtin_diff_usage);
+       else if (ents == 1)
+               return builtin_diff_index(&rev, argc, argv);
+       else if (ents == 2)
+               return builtin_diff_tree(&rev, argc, argv, ent);
+       else
+               return builtin_diff_combined(&rev, argc, argv, ent, ents);
+       usage(builtin_diff_usage);
+}
diff --git a/builtin-push.c b/builtin-push.c
new file mode 100644 (file)
index 0000000..06d06ff
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * "git push"
+ */
+#include "cache.h"
+#include "refs.h"
+#include "run-command.h"
+#include "builtin.h"
+
+#define MAX_URI (16)
+
+static const char push_usage[] = "git push [--all] [--tags] [--force] <repository> [<refspec>...]";
+
+static int all = 0, tags = 0, force = 0, thin = 1;
+static const char *execute = NULL;
+
+#define BUF_SIZE (2084)
+static char buffer[BUF_SIZE];
+
+static const char **refspec = NULL;
+static int refspec_nr = 0;
+
+static void add_refspec(const char *ref)
+{
+       int nr = refspec_nr + 1;
+       refspec = xrealloc(refspec, nr * sizeof(char *));
+       refspec[nr-1] = ref;
+       refspec_nr = nr;
+}
+
+static int expand_one_ref(const char *ref, const unsigned char *sha1)
+{
+       /* Ignore the "refs/" at the beginning of the refname */
+       ref += 5;
+
+       if (strncmp(ref, "tags/", 5))
+               return 0;
+
+       add_refspec(strdup(ref));
+       return 0;
+}
+
+static void expand_refspecs(void)
+{
+       if (all) {
+               if (refspec_nr)
+                       die("cannot mix '--all' and a refspec");
+
+               /*
+                * No need to expand "--all" - we'll just use
+                * the "--all" flag to send-pack
+                */
+               return;
+       }
+       if (!tags)
+               return;
+       for_each_ref(expand_one_ref);
+}
+
+static void set_refspecs(const char **refs, int nr)
+{
+       if (nr) {
+               size_t bytes = nr * sizeof(char *);
+
+               refspec = xrealloc(refspec, bytes);
+               memcpy(refspec, refs, bytes);
+               refspec_nr = nr;
+       }
+       expand_refspecs();
+}
+
+static int get_remotes_uri(const char *repo, const char *uri[MAX_URI])
+{
+       int n = 0;
+       FILE *f = fopen(git_path("remotes/%s", repo), "r");
+       int has_explicit_refspec = refspec_nr;
+
+       if (!f)
+               return -1;
+       while (fgets(buffer, BUF_SIZE, f)) {
+               int is_refspec;
+               char *s, *p;
+
+               if (!strncmp("URL: ", buffer, 5)) {
+                       is_refspec = 0;
+                       s = buffer + 5;
+               } else if (!strncmp("Push: ", buffer, 6)) {
+                       is_refspec = 1;
+                       s = buffer + 6;
+               } else
+                       continue;
+
+               /* Remove whitespace at the head.. */
+               while (isspace(*s))
+                       s++;
+               if (!*s)
+                       continue;
+
+               /* ..and at the end */
+               p = s + strlen(s);
+               while (isspace(p[-1]))
+                       *--p = 0;
+
+               if (!is_refspec) {
+                       if (n < MAX_URI)
+                               uri[n++] = strdup(s);
+                       else
+                               error("more than %d URL's specified, ignoreing the rest", MAX_URI);
+               }
+               else if (is_refspec && !has_explicit_refspec)
+                       add_refspec(strdup(s));
+       }
+       fclose(f);
+       if (!n)
+               die("remote '%s' has no URL", repo);
+       return n;
+}
+
+static const char **config_uri;
+static const char *config_repo;
+static int config_repo_len;
+static int config_current_uri;
+static int config_get_refspecs;
+
+static int get_remote_config(const char* key, const char* value)
+{
+       if (!strncmp(key, "remote.", 7) &&
+           !strncmp(key + 7, config_repo, config_repo_len)) {
+               if (!strcmp(key + 7 + config_repo_len, ".url")) {
+                       if (config_current_uri < MAX_URI)
+                               config_uri[config_current_uri++] = strdup(value);
+                       else
+                               error("more than %d URL's specified, ignoring the rest", MAX_URI);
+               }
+               else if (config_get_refspecs &&
+                        !strcmp(key + 7 + config_repo_len, ".push"))
+                       add_refspec(strdup(value));
+       }
+       return 0;
+}
+
+static int get_config_remotes_uri(const char *repo, const char *uri[MAX_URI])
+{
+       config_repo_len = strlen(repo);
+       config_repo = repo;
+       config_current_uri = 0;
+       config_uri = uri;
+       config_get_refspecs = !refspec_nr;
+
+       git_config(get_remote_config);
+       return config_current_uri;
+}
+
+static int get_branches_uri(const char *repo, const char *uri[MAX_URI])
+{
+       const char *slash = strchr(repo, '/');
+       int n = slash ? slash - repo : 1000;
+       FILE *f = fopen(git_path("branches/%.*s", n, repo), "r");
+       char *s, *p;
+       int len;
+
+       if (!f)
+               return 0;
+       s = fgets(buffer, BUF_SIZE, f);
+       fclose(f);
+       if (!s)
+               return 0;
+       while (isspace(*s))
+               s++;
+       if (!*s)
+               return 0;
+       p = s + strlen(s);
+       while (isspace(p[-1]))
+               *--p = 0;
+       len = p - s;
+       if (slash)
+               len += strlen(slash);
+       p = xmalloc(len + 1);
+       strcpy(p, s);
+       if (slash)
+               strcat(p, slash);
+       uri[0] = p;
+       return 1;
+}
+
+/*
+ * Read remotes and branches file, fill the push target URI
+ * list.  If there is no command line refspecs, read Push: lines
+ * to set up the *refspec list as well.
+ * return the number of push target URIs
+ */
+static int read_config(const char *repo, const char *uri[MAX_URI])
+{
+       int n;
+
+       if (*repo != '/') {
+               n = get_remotes_uri(repo, uri);
+               if (n > 0)
+                       return n;
+
+               n = get_config_remotes_uri(repo, uri);
+               if (n > 0)
+                       return n;
+
+               n = get_branches_uri(repo, uri);
+               if (n > 0)
+                       return n;
+       }
+
+       uri[0] = repo;
+       return 1;
+}
+
+static int do_push(const char *repo)
+{
+       const char *uri[MAX_URI];
+       int i, n;
+       int remote;
+       const char **argv;
+       int argc;
+
+       n = read_config(repo, uri);
+       if (n <= 0)
+               die("bad repository '%s'", repo);
+
+       argv = xmalloc((refspec_nr + 10) * sizeof(char *));
+       argv[0] = "dummy-send-pack";
+       argc = 1;
+       if (all)
+               argv[argc++] = "--all";
+       if (force)
+               argv[argc++] = "--force";
+       if (execute)
+               argv[argc++] = execute;
+       if (thin)
+               argv[argc++] = "--thin";
+       remote = argc;
+       argv[argc++] = "dummy-remote";
+       while (refspec_nr--)
+               argv[argc++] = *refspec++;
+       argv[argc] = NULL;
+
+       for (i = 0; i < n; i++) {
+               int error;
+               const char *dest = uri[i];
+               const char *sender = "git-send-pack";
+               if (!strncmp(dest, "http://", 7) ||
+                   !strncmp(dest, "https://", 8))
+                       sender = "git-http-push";
+               argv[0] = sender;
+               argv[remote] = dest;
+               error = run_command_v(argc, argv);
+               if (!error)
+                       continue;
+               switch (error) {
+               case -ERR_RUN_COMMAND_FORK:
+                       die("unable to fork for %s", sender);
+               case -ERR_RUN_COMMAND_EXEC:
+                       die("unable to exec %s", sender);
+               case -ERR_RUN_COMMAND_WAITPID:
+               case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
+               case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
+               case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
+                       die("%s died with strange error", sender);
+               default:
+                       return -error;
+               }
+       }
+       return 0;
+}
+
+int cmd_push(int argc, const char **argv, char **envp)
+{
+       int i;
+       const char *repo = "origin";    // default repository
+
+       for (i = 1; i < argc; i++) {
+               const char *arg = argv[i];
+
+               if (arg[0] != '-') {
+                       repo = arg;
+                       i++;
+                       break;
+               }
+               if (!strcmp(arg, "--all")) {
+                       all = 1;
+                       continue;
+               }
+               if (!strcmp(arg, "--tags")) {
+                       tags = 1;
+                       continue;
+               }
+               if (!strcmp(arg, "--force")) {
+                       force = 1;
+                       continue;
+               }
+               if (!strcmp(arg, "--thin")) {
+                       thin = 1;
+                       continue;
+               }
+               if (!strcmp(arg, "--no-thin")) {
+                       thin = 0;
+                       continue;
+               }
+               if (!strncmp(arg, "--exec=", 7)) {
+                       execute = arg;
+                       continue;
+               }
+               usage(push_usage);
+       }
+       set_refspecs(argv + i, argc - i);
+       return do_push(repo);
+}
index 47408a0..bb63f07 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -19,5 +19,9 @@ extern int cmd_version(int argc, const char **argv, char **envp);
 extern int cmd_whatchanged(int argc, const char **argv, char **envp);
 extern int cmd_show(int argc, const char **argv, char **envp);
 extern int cmd_log(int argc, const char **argv, char **envp);
+extern int cmd_diff(int argc, const char **argv, char **envp);
+extern int cmd_count_objects(int argc, const char **argv, char **envp);
+
+extern int cmd_push(int argc, const char **argv, char **envp);
 
 #endif
index ca36f5d..8a8fe38 100644 (file)
@@ -831,15 +831,16 @@ void show_combined_diff(struct combine_diff_path *p,
        }
 }
 
-void diff_tree_combined_merge(const unsigned char *sha1,
-                            int dense, struct rev_info *rev)
+void diff_tree_combined(const unsigned char *sha1,
+                       const unsigned char parent[][20],
+                       int num_parent,
+                       int dense,
+                       struct rev_info *rev)
 {
        struct diff_options *opt = &rev->diffopt;
-       struct commit *commit = lookup_commit(sha1);
        struct diff_options diffopts;
-       struct commit_list *parents;
        struct combine_diff_path *p, *paths = NULL;
-       int num_parent, i, num_paths;
+       int i, num_paths;
        int do_diffstat;
 
        do_diffstat = (opt->output_format == DIFF_FORMAT_DIFFSTAT ||
@@ -849,17 +850,8 @@ void diff_tree_combined_merge(const unsigned char *sha1,
        diffopts.with_stat = 0;
        diffopts.recursive = 1;
 
-       /* count parents */
-       for (parents = commit->parents, num_parent = 0;
-            parents;
-            parents = parents->next, num_parent++)
-               ; /* nothing */
-
        /* find set of paths that everybody touches */
-       for (parents = commit->parents, i = 0;
-            parents;
-            parents = parents->next, i++) {
-               struct commit *parent = parents->item;
+       for (i = 0; i < num_parent; i++) {
                /* show stat against the first parent even
                 * when doing combined diff.
                 */
@@ -867,8 +859,7 @@ void diff_tree_combined_merge(const unsigned char *sha1,
                        diffopts.output_format = DIFF_FORMAT_DIFFSTAT;
                else
                        diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
-               diff_tree_sha1(parent->object.sha1, commit->object.sha1, "",
-                              &diffopts);
+               diff_tree_sha1(parent[i], sha1, "", &diffopts);
                diffcore_std(&diffopts);
                paths = intersect_paths(paths, i, num_parent);
 
@@ -907,3 +898,25 @@ void diff_tree_combined_merge(const unsigned char *sha1,
                free(tmp);
        }
 }
+
+void diff_tree_combined_merge(const unsigned char *sha1,
+                            int dense, struct rev_info *rev)
+{
+       int num_parent;
+       const unsigned char (*parent)[20];
+       struct commit *commit = lookup_commit(sha1);
+       struct commit_list *parents;
+
+       /* count parents */
+       for (parents = commit->parents, num_parent = 0;
+            parents;
+            parents = parents->next, num_parent++)
+               ; /* nothing */
+
+       parent = xmalloc(num_parent * sizeof(*parent));
+       for (parents = commit->parents, num_parent = 0;
+            parents;
+            parents = parents->next, num_parent++)
+               memcpy(parent + num_parent, parents->item->object.sha1, 20);
+       diff_tree_combined(sha1, parent, num_parent, dense, rev);
+}
diff --git a/diff.c b/diff.c
index 6762fce..c845c87 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -1018,14 +1018,12 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
        }
 
        if (memcmp(one->sha1, two->sha1, 20)) {
-               char one_sha1[41];
                int abbrev = o->full_index ? 40 : DEFAULT_ABBREV;
-               memcpy(one_sha1, sha1_to_hex(one->sha1), 41);
 
                len += snprintf(msg + len, sizeof(msg) - len,
                                "index %.*s..%.*s",
-                               abbrev, one_sha1, abbrev,
-                               sha1_to_hex(two->sha1));
+                               abbrev, sha1_to_hex(one->sha1),
+                               abbrev, sha1_to_hex(two->sha1));
                if (one->mode == two->mode)
                        len += snprintf(msg + len, sizeof(msg) - len,
                                        " %06o", one->mode);
diff --git a/diff.h b/diff.h
index 7150b90..b3b2c4d 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -75,6 +75,8 @@ struct combine_diff_path {
 extern void show_combined_diff(struct combine_diff_path *elem, int num_parent,
                              int dense, struct rev_info *);
 
+extern void diff_tree_combined(const unsigned char *sha1, const unsigned char parent[][20], int num_parent, int dense, struct rev_info *rev);
+
 extern void diff_tree_combined_merge(const unsigned char *sha1, int, struct rev_info *);
 
 extern void diff_addremove(struct diff_options *,
diff --git a/git-count-objects.sh b/git-count-objects.sh
deleted file mode 100755 (executable)
index 40c58ef..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Junio C Hamano
-#
-
-GIT_DIR=`git-rev-parse --git-dir` || exit $?
-
-dc </dev/null 2>/dev/null || {
-       # This is not a real DC at all -- it just knows how
-       # this script feeds DC and does the computation itself.
-       dc () {
-               while read a b
-               do
-                       case $a,$b in
-                       0,)     acc=0 ;;
-                       *,+)    acc=$(($acc + $a)) ;;
-                       p,)     echo "$acc" ;;
-                       esac
-               done
-       }
-}
-
-echo $(find "$GIT_DIR/objects"/?? -type f -print 2>/dev/null | wc -l) objects, \
-$({
-    echo 0
-    # "no-such" is to help Darwin folks by not using xargs -r.
-    find "$GIT_DIR/objects"/?? -type f -print 2>/dev/null |
-    xargs du -k "$GIT_DIR/objects/no-such" 2>/dev/null |
-    sed -e 's/[        ].*/ +/'
-    echo p
-} | dc) kilobytes
index 11d153c..ffd9c66 100755 (executable)
@@ -2076,14 +2076,15 @@ sub update
     # TODO: log processing is memory bound
     # if we can parse into a 2nd file that is in reverse order
     # we can probably do something really efficient
-    my @git_log_params = ('--parents', '--topo-order');
+    my @git_log_params = ('--pretty', '--parents', '--topo-order');
 
     if (defined $lastcommit) {
         push @git_log_params, "$lastcommit..$self->{module}";
     } else {
         push @git_log_params, $self->{module};
     }
-    open(GITLOG, '-|', 'git-log', @git_log_params) or die "Cannot call git-log: $!";
+    # git-rev-list is the backend / plumbing version of git-log
+    open(GITLOG, '-|', 'git-rev-list', @git_log_params) or die "Cannot call git-rev-list: $!";
 
     my @commits;
 
diff --git a/git-diff.sh b/git-diff.sh
deleted file mode 100755 (executable)
index 0fe6770..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Linus Torvalds
-# Copyright (c) 2005 Junio C Hamano
-
-USAGE='[ --diff-options ] <ent>{0,2} [<path>...]'
-SUBDIRECTORY_OK='Yes'
-. git-sh-setup
-
-rev=$(git-rev-parse --revs-only --no-flags --sq "$@") || exit
-flags=$(git-rev-parse --no-revs --flags --sq "$@")
-files=$(git-rev-parse --no-revs --no-flags --sq "$@")
-
-# I often say 'git diff --cached -p' and get scolded by git-diff-files, but
-# obviously I mean 'git diff --cached -p HEAD' in that case.
-case "$rev" in
-'')
-       case " $flags " in
-       *" '--cached' "*)
-               rev='HEAD '
-               ;;
-       esac
-esac
-
-# If we have -[123] --ours --theirs --base, don't do --cc by default.
-case " $flags " in
-*" '-"[123]"' "* | *" '--ours' "* | *" '--base' "* | *" '--theirs' "*)
-       cc_or_p=-p ;;
-*)
-       cc_or_p=--cc ;;
-esac
-
-# If we do not have --name-status, --name-only, -r, -c or --stat,
-# default to --cc.
-case " $flags " in
-*" '--name-status' "* | *" '--name-only' "* | *" '-r' "* | *" '-c' "* | \
-*" '--stat' "*)
-       ;;
-*)
-       flags="$flags'$cc_or_p' " ;;
-esac
-
-# If we do not have -B, -C, -r, nor -p, default to -M.
-case " $flags " in
-*" '-"[BCMrp]* | *" '--find-copies-harder' "*)
-       ;; # something like -M50.
-*)
-       flags="$flags'-M' " ;;
-esac
-
-case "$rev" in
-?*' '?*' '?*)
-       usage
-       ;;
-?*' '^?*)
-       begin=$(expr "$rev" : '.*^.\([0-9a-f]*\).*') &&
-       end=$(expr "$rev" : '.\([0-9a-f]*\). .*') || exit
-       cmd="git-diff-tree $flags $begin $end -- $files"
-       ;;
-?*' '?*)
-       cmd="git-diff-tree $flags $rev -- $files"
-       ;;
-?*' ')
-       cmd="git-diff-index $flags $rev -- $files"
-       ;;
-'')
-       cmd="git-diff-files $flags -- $files"
-       ;;
-*)
-       usage
-       ;;
-esac
-
-eval "$cmd"
diff --git a/git.c b/git.c
index 01b7e28..49ba518 100644 (file)
--- a/git.c
+++ b/git.c
@@ -46,6 +46,9 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                { "log", cmd_log },
                { "whatchanged", cmd_whatchanged },
                { "show", cmd_show },
+               { "push", cmd_push },
+               { "count-objects", cmd_count_objects },
+               { "diff", cmd_diff },
        };
        int i;
 
index 9634c46..b90ba67 100644 (file)
@@ -3,6 +3,15 @@
 #include "commit.h"
 #include "log-tree.h"
 
+static void show_parents(struct commit *commit, int abbrev)
+{
+       struct commit_list *p;
+       for (p = commit->parents; p ; p = p->next) {
+               struct commit *parent = p->item;
+               printf(" %s", diff_unique_abbrev(parent->object.sha1, abbrev));
+       }
+}
+
 void show_log(struct rev_info *opt, struct log_info *log, const char *sep)
 {
        static char this_header[16384];
@@ -14,7 +23,10 @@ void show_log(struct rev_info *opt, struct log_info *log, const char *sep)
 
        opt->loginfo = NULL;
        if (!opt->verbose_header) {
-               puts(sha1_to_hex(commit->object.sha1));
+               fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
+               if (opt->parents)
+                       show_parents(commit, abbrev_commit);
+               putchar('\n');
                return;
        }
 
@@ -40,7 +52,9 @@ void show_log(struct rev_info *opt, struct log_info *log, const char *sep)
        printf("%s%s",
                opt->commit_format == CMIT_FMT_ONELINE ? "" : "commit ",
                diff_unique_abbrev(commit->object.sha1, abbrev_commit));
-       if (parent) 
+       if (opt->parents)
+               show_parents(commit, abbrev_commit);
+       if (parent)
                printf(" (from %s)", diff_unique_abbrev(parent->object.sha1, abbrev_commit));
        putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n');
 
index 50528d5..cc7b5bd 100644 (file)
@@ -24,16 +24,14 @@ static const char *sha1_to_hex_zero(const unsigned char *sha1)
 
 static void resolve(const char *base, struct name_entry *branch1, struct name_entry *result)
 {
-       char branch1_sha1[50];
-
        /* If it's already branch1, don't bother showing it */
        if (!branch1)
                return;
-       memcpy(branch1_sha1, sha1_to_hex_zero(branch1->sha1), 41);
 
        printf("0 %06o->%06o %s->%s %s%s\n",
                branch1->mode, result->mode,
-               branch1_sha1, sha1_to_hex_zero(result->sha1),
+               sha1_to_hex_zero(branch1->sha1),
+               sha1_to_hex_zero(result->sha1),
                base, result->path);
 }
 
index e350630..63eda1b 100644 (file)
@@ -2,11 +2,13 @@
 #include <regex.h>
 
 static const char git_config_set_usage[] =
-"git-repo-config [ --bool | --int ] [--get | --get-all | --replace-all | --unset | --unset-all] name [value [value_regex]] | --list";
+"git-repo-config [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --unset | --unset-all] name [value [value_regex]] | --list";
 
 static char* key = NULL;
-static char* value = NULL;
+static regex_t* key_regexp = NULL;
 static regex_t* regexp = NULL;
+static int show_keys = 0;
+static int use_key_regexp = 0;
 static int do_all = 0;
 static int do_not_match = 0;
 static int seen = 0;
@@ -23,34 +25,40 @@ static int show_all_config(const char *key_, const char *value_)
 
 static int show_config(const char* key_, const char* value_)
 {
+       char value[256];
+       const char *vptr = value;
+       int dup_error = 0;
+
        if (value_ == NULL)
                value_ = "";
 
-       if (!strcmp(key_, key) &&
-                       (regexp == NULL ||
+       if (!use_key_regexp && strcmp(key_, key))
+               return 0;
+       if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
+               return 0;
+       if (regexp != NULL &&
                         (do_not_match ^
-                         !regexec(regexp, value_, 0, NULL, 0)))) {
-               if (do_all) {
-                       printf("%s\n", value_);
-                       return 0;
-               }
-               if (seen > 0) {
-                       fprintf(stderr, "More than one value: %s\n", value);
-                       free(value);
-               }
+                         regexec(regexp, value_, 0, NULL, 0)))
+               return 0;
 
-               if (type == T_INT) {
-                       value = malloc(256);
-                       sprintf(value, "%d", git_config_int(key_, value_));
-               } else if (type == T_BOOL) {
-                       value = malloc(256);
-                       sprintf(value, "%s", git_config_bool(key_, value_)
-                                            ? "true" : "false");
-               } else {
-                       value = strdup(value_);
-               }
-               seen++;
+       if (show_keys)
+               printf("%s ", key_);
+       if (seen && !do_all)
+               dup_error = 1;
+       if (type == T_INT)
+               sprintf(value, "%d", git_config_int(key_, value_));
+       else if (type == T_BOOL)
+               vptr = git_config_bool(key_, value_) ? "true" : "false";
+       else
+               vptr = value_;
+       seen++;
+       if (dup_error) {
+               error("More than one value for the key %s: %s",
+                               key_, vptr);
        }
+       else
+               printf("%s\n", vptr);
+
        return 0;
 }
 
@@ -63,6 +71,14 @@ static int get_value(const char* key_, const char* regex_)
                key[i] = tolower(key_[i]);
        key[i] = 0;
 
+       if (use_key_regexp) {
+               key_regexp = (regex_t*)malloc(sizeof(regex_t));
+               if (regcomp(key_regexp, key, REG_EXTENDED)) {
+                       fprintf(stderr, "Invalid key pattern: %s\n", key_);
+                       return -1;
+               }
+       }
+
        if (regex_) {
                if (regex_[0] == '!') {
                        do_not_match = 1;
@@ -77,10 +93,6 @@ static int get_value(const char* key_, const char* regex_)
        }
 
        git_config(show_config);
-       if (value) {
-               printf("%s\n", value);
-               free(value);
-       }
        free(key);
        if (regexp) {
                regfree(regexp);
@@ -88,9 +100,9 @@ static int get_value(const char* key_, const char* regex_)
        }
 
        if (do_all)
-               return 0;
+               return !seen;
 
-       return seen == 1 ? 0 : 1;
+       return (seen == 1) ? 0 : 1;
 }
 
 int main(int argc, const char **argv)
@@ -123,6 +135,11 @@ int main(int argc, const char **argv)
                else if (!strcmp(argv[1], "--get-all")) {
                        do_all = 1;
                        return get_value(argv[2], NULL);
+               } else if (!strcmp(argv[1], "--get-regexp")) {
+                       show_keys = 1;
+                       use_key_regexp = 1;
+                       do_all = 1;
+                       return get_value(argv[2], NULL);
                } else
 
                        return git_config_set(argv[1], argv[2]);
@@ -136,6 +153,11 @@ int main(int argc, const char **argv)
                else if (!strcmp(argv[1], "--get-all")) {
                        do_all = 1;
                        return get_value(argv[2], argv[3]);
+               } else if (!strcmp(argv[1], "--get-regexp")) {
+                       show_keys = 1;
+                       use_key_regexp = 1;
+                       do_all = 1;
+                       return get_value(argv[2], argv[3]);
                } else if (!strcmp(argv[1], "--replace-all"))
 
                        return git_config_set_multivar(argv[2], argv[3], NULL, 1);
index ad78efd..f8ee38e 100644 (file)
@@ -574,7 +574,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                                revs->max_count = atoi(arg + 12);
                                continue;
                        }
-                       /* accept -<digit>, like traditilnal "head" */
+                       /* accept -<digit>, like traditional "head" */
                        if ((*arg == '-') && isdigit(arg[1])) {
                                revs->max_count = atoi(arg + 1);
                                continue;
@@ -694,6 +694,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                        }
                        if (!strcmp(arg, "-c")) {
                                revs->diff = 1;
+                               revs->dense_combined_merges = 0;
                                revs->combine_merges = 1;
                                continue;
                        }
index f2d33af..5464828 100644 (file)
@@ -108,9 +108,10 @@ int safe_create_leading_directories(char *path)
 
 char * sha1_to_hex(const unsigned char *sha1)
 {
-       static char buffer[50];
+       static int bufno;
+       static char hexbuffer[4][50];
        static const char hex[] = "0123456789abcdef";
-       char *buf = buffer;
+       char *buffer = hexbuffer[3 & ++bufno], *buf = buffer;
        int i;
 
        for (i = 0; i < 20; i++) {
index ab4dd5c..1bf728f 100755 (executable)
@@ -247,6 +247,24 @@ EOF
 
 test_expect_success 'hierarchical section value' 'cmp .git/config expect'
 
+cat > expect << EOF
+beta.noindent=sillyValue
+nextsection.nonewline=wow2 for me
+123456.a123=987
+1.2.3.alpha=beta
+EOF
+
+test_expect_success 'working --list' \
+       'git-repo-config --list > output && cmp output expect'
+
+cat > expect << EOF
+beta.noindent sillyValue
+nextsection.nonewline wow2 for me
+EOF
+
+test_expect_success '--get-regexp' \
+       'git-repo-config --get-regexp in > output && cmp output expect'
+
 cat > .git/config << EOF
 [novalue]
        variable
@@ -255,5 +273,10 @@ EOF
 test_expect_success 'get variable with no value' \
        'git-repo-config --get novalue.variable ^$'
 
+git-repo-config > output 2>&1
+
+test_expect_success 'no arguments, but no crash' \
+       "test $? = 129 && grep usage output"
+
 test_done
 
index facec8d..9fa3d2b 100644 (file)
@@ -473,7 +473,7 @@ static void read_index_info(int line_termination)
 }
 
 static const char update_index_usage[] =
-"git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--cacheinfo] [--chmod=(+|-)x] [--info-only] [--force-remove] [--stdin] [--index-info] [--ignore-missing] [-z] [--verbose] [--] <file>...";
+"git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--ignore-missing] [-z] [--verbose] [--] <file>...";
 
 static unsigned char head_sha1[20];
 static unsigned char merge_head_sha1[20];