diff options
-rw-r--r-- | Documentation/git-count-objects.txt | 12 | ||||
-rw-r--r-- | Documentation/git-diff-tree.txt | 2 | ||||
-rw-r--r-- | Documentation/git-repo-config.txt | 5 | ||||
-rw-r--r-- | Documentation/git-update-index.txt | 10 | ||||
-rw-r--r-- | Documentation/glossary.txt | 409 | ||||
-rw-r--r-- | Documentation/sort_glossary.pl | 2 | ||||
-rw-r--r-- | Makefile | 9 | ||||
-rw-r--r-- | blame.c | 10 | ||||
-rw-r--r-- | builtin-count.c | 125 | ||||
-rw-r--r-- | builtin-diff.c | 369 | ||||
-rw-r--r-- | builtin-push.c | 312 | ||||
-rw-r--r-- | builtin.h | 4 | ||||
-rw-r--r-- | combine-diff.c | 47 | ||||
-rw-r--r-- | diff.c | 6 | ||||
-rw-r--r-- | diff.h | 2 | ||||
-rwxr-xr-x | git-count-objects.sh | 31 | ||||
-rwxr-xr-x | git-cvsserver.perl | 5 | ||||
-rwxr-xr-x | git-diff.sh | 74 | ||||
-rw-r--r-- | git.c | 3 | ||||
-rw-r--r-- | log-tree.c | 18 | ||||
-rw-r--r-- | merge-tree.c | 6 | ||||
-rw-r--r-- | repo-config.c | 82 | ||||
-rw-r--r-- | revision.c | 3 | ||||
-rw-r--r-- | sha1_file.c | 5 | ||||
-rwxr-xr-x | t/t1300-repo-config.sh | 23 | ||||
-rw-r--r-- | update-index.c | 2 |
26 files changed, 1224 insertions, 352 deletions
diff --git a/Documentation/git-count-objects.txt b/Documentation/git-count-objects.txt index 47216f488b..198ce77a8a 100644 --- a/Documentation/git-count-objects.txt +++ b/Documentation/git-count-objects.txt @@ -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> diff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.txt index 2169169850..906830d4bf 100644 --- a/Documentation/git-diff-tree.txt +++ b/Documentation/git-diff-tree.txt @@ -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 diff --git a/Documentation/git-repo-config.txt b/Documentation/git-repo-config.txt index 566cfa1836..ddcf52364c 100644 --- a/Documentation/git-repo-config.txt +++ b/Documentation/git-repo-config.txt @@ -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. diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt index d4137fc87e..23f2b6f1a5 100644 --- a/Documentation/git-update-index.txt +++ b/Documentation/git-update-index.txt @@ -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 diff --git a/Documentation/glossary.txt b/Documentation/glossary.txt index 02a9d9c18a..39c90ad7a6 100644 --- a/Documentation/glossary.txt +++ b/Documentation/glossary.txt @@ -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. diff --git a/Documentation/sort_glossary.pl b/Documentation/sort_glossary.pl index e57dc78e0e..e0bc552a64 100644 --- a/Documentation/sort_glossary.pl +++ b/Documentation/sort_glossary.pl @@ -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" @@ -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 @@ -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 index 0000000000..5ee72df247 --- /dev/null +++ b/builtin-count.c @@ -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 index 0000000000..636edbf2a7 --- /dev/null +++ b/builtin-diff.c @@ -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 index 0000000000..06d06ff310 --- /dev/null +++ b/builtin-push.c @@ -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); +} @@ -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 diff --git a/combine-diff.c b/combine-diff.c index ca36f5d5e7..8a8fe3863a 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -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); +} @@ -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); @@ -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 index 40c58efe08..0000000000 --- a/git-count-objects.sh +++ /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 diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 11d153c4cd..ffd9c66f94 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -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 index 0fe6770749..0000000000 --- a/git-diff.sh +++ /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" @@ -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; diff --git a/log-tree.c b/log-tree.c index 9634c4677f..b90ba6762a 100644 --- a/log-tree.c +++ b/log-tree.c @@ -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'); diff --git a/merge-tree.c b/merge-tree.c index 50528d5e43..cc7b5bd891 100644 --- a/merge-tree.c +++ b/merge-tree.c @@ -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); } diff --git a/repo-config.c b/repo-config.c index e35063034f..63eda1bb78 100644 --- a/repo-config.c +++ b/repo-config.c @@ -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); diff --git a/revision.c b/revision.c index ad78efda51..f8ee38e54d 100644 --- a/revision.c +++ b/revision.c @@ -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; } diff --git a/sha1_file.c b/sha1_file.c index f2d33afb27..5464828259 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -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++) { diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index ab4dd5c4ce..1bf728fb06 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -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 diff --git a/update-index.c b/update-index.c index facec8d915..9fa3d2bb96 100644 --- a/update-index.c +++ b/update-index.c @@ -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]; |