aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/SubmittingPatches4
-rw-r--r--Documentation/diff-options.txt4
-rw-r--r--Documentation/git-grep.txt85
-rw-r--r--Documentation/git-merge-base.txt18
-rw-r--r--Documentation/git-quiltimport.txt61
-rw-r--r--Documentation/git-rebase.txt11
-rw-r--r--Documentation/git-rev-parse.txt9
-rwxr-xr-xDocumentation/install-webdoc.sh8
-rw-r--r--Makefile49
-rw-r--r--builtin-check-ref-format.c14
-rw-r--r--builtin-diff.c10
-rw-r--r--builtin-grep.c902
-rw-r--r--builtin-init-db.c (renamed from init-db.c)12
-rw-r--r--builtin-log.c7
-rw-r--r--builtin-rev-list.c (renamed from rev-list.c)5
-rw-r--r--builtin.h4
-rw-r--r--cache.h6
-rw-r--r--check-ref-format.c17
-rw-r--r--combine-diff.c1
-rw-r--r--commit.c38
-rw-r--r--config.c94
-rw-r--r--delta.h2
-rw-r--r--diff-tree.c5
-rw-r--r--diff.c140
-rw-r--r--diff.h4
-rwxr-xr-xgit-am.sh11
-rwxr-xr-xgit-branch.sh3
-rwxr-xr-xgit-cvsimport.perl2
-rwxr-xr-xgit-format-patch.sh2
-rwxr-xr-xgit-grep.sh62
-rwxr-xr-xgit-merge.sh3
-rwxr-xr-xgit-quiltimport.sh118
-rwxr-xr-xgit-rebase.sh21
-rwxr-xr-xgit-request-pull.sh2
-rwxr-xr-xgit-reset.sh50
-rwxr-xr-xgit-send-email.perl75
-rwxr-xr-xgit-tag.sh8
-rw-r--r--git.c4
-rw-r--r--merge-base.c9
-rw-r--r--pack-objects.c30
-rw-r--r--read-cache.c117
-rw-r--r--read-tree.c15
-rw-r--r--refs.c28
-rw-r--r--refs.h3
-rw-r--r--repo-config.c11
-rw-r--r--rev-parse.c17
-rw-r--r--sha1_file.c3
-rwxr-xr-xt/t1300-repo-config.sh8
-rw-r--r--update-index.c128
49 files changed, 1819 insertions, 421 deletions
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 318b04fde..8601949e8 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -266,8 +266,8 @@ This recipe appears to work with the current [*1*] Thunderbird from Suse.
The following Thunderbird extensions are needed:
AboutConfig 0.5
http://aboutconfig.mozdev.org/
- External Editor 0.5.4
- http://extensionroom.mozdev.org/more-info/exteditor
+ External Editor 0.7.2
+ http://globs.org/articles.php?lng=en&pg=8
1) Prepare the patch as a text file using your method of choice.
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index c183dc9da..f523ec2fb 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -10,6 +10,10 @@
--stat::
Generate a diffstat instead of a patch.
+--summary::
+ Output a condensed summary of extended header information
+ such as creations, renames and mode changes.
+
--patch-with-stat::
Generate patch and prepend its diffstat.
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index d55456ae9..74102b794 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -8,43 +8,82 @@ git-grep - Print lines matching a pattern
SYNOPSIS
--------
-'git-grep' [<option>...] [-e] <pattern> [--] [<path>...]
+[verse]
+'git-grep' [--cached]
+ [-a | --text] [-I] [-i | --ignore-case] [-w | --word-regexp]
+ [-v | --invert-match]
+ [-E | --extended-regexp] [-G | --basic-regexp] [-F | --fixed-strings]
+ [-n] [-l | --files-with-matches] [-L | --files-without-match]
+ [-c | --count]
+ [-A <post-context>] [-B <pre-context>] [-C <context>]
+ [-f <file>] [-e <pattern>]
+ [<tree>...]
+ [--] [<path>...]
DESCRIPTION
-----------
-Searches list of files `git-ls-files` produces for lines
-containing a match to the given pattern.
+Look for specified patterns in the working tree files, blobs
+registered in the index file, or given tree objects.
OPTIONS
-------
-`--`::
- Signals the end of options; the rest of the parameters
- are <path> limiters.
+--cached::
+ Instead of searching in the working tree files, check
+ the blobs registerd in the index file.
+
+-a | --text::
+ Process binary files as if they were text.
+
+-i | --ignore-case::
+ Ignore case differences between the patterns and the
+ files.
+
+-w | --word-regexp::
+ Match the pattern only at word boundary (either begin at the
+ beginning of a line, or preceded by a non-word character; end at
+ the end of a line or followed by a non-word character).
+
+-v | --invert-match::
+ Select non-matching lines.
+
+-E | --extended-regexp | -G | --basic-regexp::
+ Use POSIX extended/basic regexp for patterns. Default
+ is to use basic regexp.
-<option>...::
- Either an option to pass to `grep` or `git-ls-files`.
-+
-The following are the specific `git-ls-files` options
-that may be given: `-o`, `--cached`, `--deleted`, `--others`,
-`--killed`, `--ignored`, `--modified`, `--exclude=\*`,
-`--exclude-from=\*`, and `--exclude-per-directory=\*`.
-+
-All other options will be passed to `grep`.
+-n::
+ Prefix the line number to matching lines.
-<pattern>::
- The pattern to look for. The first non option is taken
- as the pattern; if your pattern begins with a dash, use
- `-e <pattern>`.
+-l | --files-with-matches | -L | --files-without-match::
+ Instead of showing every matched line, show only the
+ names of files that contain (or do not contain) matches.
-<path>...::
- Optional paths to limit the set of files to be searched;
- passed to `git-ls-files`.
+-c | --count::
+ Instead of showing every matched line, show the number of
+ lines that match.
+
+-[ABC] <context>::
+ Show `context` trailing (`A` -- after), or leading (`B`
+ -- before), or both (`C` -- context) lines, and place a
+ line containing `--` between continguous groups of
+ matches.
+
+-f <file>::
+ Read patterns from <file>, one per line.
+
+`<tree>...`::
+ Search blobs in the trees for specified patterns.
+
+`--`::
+ Signals the end of options; the rest of the parameters
+ are <path> limiters.
Author
------
-Written by Linus Torvalds <torvalds@osdl.org>
+Originally written by Linus Torvalds <torvalds@osdl.org>, later
+revamped by Junio C Hamano.
+
Documentation
--------------
diff --git a/Documentation/git-merge-base.txt b/Documentation/git-merge-base.txt
index d1d56f194..6099be2ad 100644
--- a/Documentation/git-merge-base.txt
+++ b/Documentation/git-merge-base.txt
@@ -8,16 +8,26 @@ git-merge-base - Finds as good a common ancestor as possible for a merge
SYNOPSIS
--------
-'git-merge-base' <commit> <commit>
+'git-merge-base' [--all] <commit> <commit>
DESCRIPTION
-----------
-"git-merge-base" finds as good a common ancestor as possible. Given a
-selection of equally good common ancestors it should not be relied on
-to decide in any particular way.
+
+"git-merge-base" finds as good a common ancestor as possible between
+the two commits. That is, given two commits A and B 'git-merge-base A
+B' will output a commit which is reachable from both A and B through
+the parent relationship.
+
+Given a selection of equally good common ancestors it should not be
+relied on to decide in any particular way.
The "git-merge-base" algorithm is still in flux - use the source...
+OPTIONS
+-------
+--all::
+ Output all common ancestors for the two commits instead of
+ just one.
Author
------
diff --git a/Documentation/git-quiltimport.txt b/Documentation/git-quiltimport.txt
new file mode 100644
index 000000000..6e9a8c369
--- /dev/null
+++ b/Documentation/git-quiltimport.txt
@@ -0,0 +1,61 @@
+git-quiltimport(1)
+================
+
+NAME
+----
+git-quiltimport - Applies a quilt patchset onto the current branch
+
+
+SYNOPSIS
+--------
+[verse]
+'git-quiltimport' [--dry-run] [--author <author>] [--patches <dir>]
+
+
+DESCRIPTION
+-----------
+Applies a quilt patchset onto the current git branch, preserving
+the patch boundaries, patch order, and patch descriptions present
+in the quilt patchset.
+
+For each patch the code attempts to extract the author from the
+patch description. If that fails it falls back to the author
+specified with --author. If the --author flag was not given
+the patch description is displayed and the user is asked to
+interactively enter the author of the patch.
+
+If a subject is not found in the patch description the patch name is
+preserved as the 1 line subject in the git description.
+
+OPTIONS
+-------
+--dry-run::
+ Walk through the patches in the series and warn
+ if we cannot find all of the necessary information to commit
+ a patch. At the time of this writing only missing author
+ information is warned about.
+
+--author Author Name <Author Email>::
+ The author name and email address to use when no author
+ information can be found in the patch description.
+
+--patches <dir>::
+ The directory to find the quilt patches and the
+ quilt series file.
+
+ The default for the patch directory is patches
+ or the value of the $QUILT_PATCHES environment
+ variable.
+
+Author
+------
+Written by Eric Biederman <ebiederm@lnxi.com>
+
+Documentation
+--------------
+Documentation by Eric Biederman <ebiederm@lnxi.com>
+
+GIT
+---
+Part of the gitlink:git[7] suite
+
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 1b482abec..08ee4aaba 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -9,9 +9,7 @@ SYNOPSIS
--------
'git-rebase' [--onto <newbase>] <upstream> [<branch>]
-'git-rebase' --continue
-
-'git-rebase' --abort
+'git-rebase' --continue | --skip | --abort
DESCRIPTION
-----------
@@ -23,9 +21,10 @@ not exist in the <upstream> branch.
It is possible that a merge failure will prevent this process from being
completely automatic. You will have to resolve any such merge failure
-and run `git rebase --continue`. If you can not resolve the merge
-failure, running `git rebase --abort` will restore the original <branch>
-and remove the working files found in the .dotest directory.
+and run `git rebase --continue`. Another option is to bypass the commit
+that caused the merge failure with `git rebase --skip`. To restore the
+original <branch> and remove the .dotest working files, use the command
+`git rebase --abort` instead.
Note that if <branch> is not specified on the command line, the currently
checked out branch is used.
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 8b95df0c6..ab896fcf8 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -67,6 +67,15 @@ OPTIONS
--all::
Show all refs found in `$GIT_DIR/refs`.
+--branches::
+ Show branch refs found in `$GIT_DIR/refs/heads`.
+
+--tags::
+ Show tag refs found in `$GIT_DIR/refs/tags`.
+
+--remotes::
+ Show tag refs found in `$GIT_DIR/refs/remotes`.
+
--show-prefix::
When the command is invoked from a subdirectory, show the
path of the current directory relative to the top-level
diff --git a/Documentation/install-webdoc.sh b/Documentation/install-webdoc.sh
index 50638c78d..60211a505 100755
--- a/Documentation/install-webdoc.sh
+++ b/Documentation/install-webdoc.sh
@@ -4,12 +4,16 @@ T="$1"
for h in *.html *.txt howto/*.txt howto/*.html
do
- diff -u -I'Last updated [0-9][0-9]-[A-Z][a-z][a-z]-' "$T/$h" "$h" || {
+ if test -f "$T/$h" &&
+ diff -u -I'Last updated [0-9][0-9]-[A-Z][a-z][a-z]-' "$T/$h" "$h"
+ then
+ :; # up to date
+ else
echo >&2 "# install $h $T/$h"
rm -f "$T/$h"
mkdir -p `dirname "$T/$h"`
cp "$h" "$T/$h"
- }
+ fi
done
strip_leading=`echo "$T/" | sed -e 's|.|.|g'`
for th in "$T"/*.html "$T"/*.txt "$T"/howto/*.txt "$T"/howto/*.html
diff --git a/Makefile b/Makefile
index 93918a037..3a31ce015 100644
--- a/Makefile
+++ b/Makefile
@@ -124,8 +124,8 @@ SCRIPT_SH = \
git-tag.sh git-verify-tag.sh \
git-applymbox.sh git-applypatch.sh git-am.sh \
git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
- git-merge-resolve.sh git-merge-ours.sh git-grep.sh \
- git-lost-found.sh
+ git-merge-resolve.sh git-merge-ours.sh \
+ git-lost-found.sh git-quiltimport.sh
SCRIPT_PERL = \
git-archimport.perl git-cvsimport.perl git-relink.perl \
@@ -154,22 +154,24 @@ PROGRAMS = \
git-convert-objects$X git-diff-files$X \
git-diff-index$X git-diff-stages$X \
git-diff-tree$X git-fetch-pack$X git-fsck-objects$X \
- git-hash-object$X git-index-pack$X git-init-db$X git-local-fetch$X \
+ git-hash-object$X git-index-pack$X git-local-fetch$X \
git-ls-files$X git-ls-tree$X git-mailinfo$X git-merge-base$X \
git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
git-peek-remote$X git-prune-packed$X git-read-tree$X \
- git-receive-pack$X git-rev-list$X git-rev-parse$X \
+ git-receive-pack$X git-rev-parse$X \
git-send-pack$X git-show-branch$X git-shell$X \
git-show-index$X git-ssh-fetch$X \
git-ssh-upload$X git-tar-tree$X git-unpack-file$X \
git-unpack-objects$X git-update-index$X git-update-server-info$X \
git-upload-pack$X git-verify-pack$X git-write-tree$X \
- git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \
+ git-update-ref$X git-symbolic-ref$X \
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 git-whatchanged$X git-show$X \
- git-count-objects$X git-diff$X git-push$X
+ git-count-objects$X git-diff$X git-push$X \
+ git-grep$X git-rev-list$X git-check-ref-format$X \
+ git-init-db$X
# what 'all' will build and 'install' will install, in gitexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -216,7 +218,9 @@ LIB_OBJS = \
$(DIFF_OBJS)
BUILTIN_OBJS = \
- builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o
+ builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
+ builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
+ builtin-init-db.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
@@ -286,7 +290,9 @@ ifeq ($(uname_S),OpenBSD)
ALL_LDFLAGS += -L/usr/local/lib
endif
ifeq ($(uname_S),NetBSD)
- NEEDS_LIBICONV = YesPlease
+ ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)
+ NEEDS_LIBICONV = YesPlease
+ endif
ALL_CFLAGS += -I/usr/pkg/include
ALL_LDFLAGS += -L/usr/pkg/lib -Wl,-rpath,/usr/pkg/lib
endif
@@ -469,6 +475,7 @@ strip: $(PROGRAMS) git$X
git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS)
$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
+ -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' \
$(ALL_CFLAGS) -o $@ $(filter %.c,$^) \
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
@@ -561,10 +568,6 @@ git-http-push$X: revision.o http.o http-push.o $(LIB_FILE)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
-init-db.o: init-db.c
- $(CC) -c $(ALL_CFLAGS) \
- -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $*.c
-
$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
$(patsubst git-%$X,%.o,$(PROGRAMS)): $(GITLIBS)
$(DIFF_OBJS): diffcore.h
@@ -648,6 +651,25 @@ dist: git.spec git-tar-tree
rpm: dist
$(RPMBUILD) -ta $(GIT_TARNAME).tar.gz
+htmldocs = git-htmldocs-$(GIT_VERSION)
+manpages = git-manpages-$(GIT_VERSION)
+dist-doc:
+ rm -fr .doc-tmp-dir
+ mkdir .doc-tmp-dir
+ $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
+ cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar .
+ gzip -n -9 -f $(htmldocs).tar
+ :
+ rm -fr .doc-tmp-dir
+ mkdir .doc-tmp-dir .doc-tmp-dir/man1 .doc-tmp-dir/man7
+ $(MAKE) -C Documentation DESTDIR=. \
+ man1=../.doc-tmp-dir/man1 \
+ man7=../.doc-tmp-dir/man7 \
+ install
+ cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar .
+ gzip -n -9 -f $(manpages).tar
+ rm -fr .doc-tmp-dir
+
### Cleaning rules
clean:
@@ -655,8 +677,9 @@ clean:
$(LIB_FILE) $(XDIFF_LIB)
rm -f $(ALL_PROGRAMS) $(BUILT_INS) git$X
rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags
- rm -rf $(GIT_TARNAME)
+ rm -rf $(GIT_TARNAME) .doc-tmp-dir
rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
+ rm -f $(htmldocs).tar $(manpages).tar
$(MAKE) -C Documentation/ clean
$(MAKE) -C templates clean
$(MAKE) -C t/ clean
diff --git a/builtin-check-ref-format.c b/builtin-check-ref-format.c
new file mode 100644
index 000000000..4a23936af
--- /dev/null
+++ b/builtin-check-ref-format.c
@@ -0,0 +1,14 @@
+/*
+ * GIT - The information manager from hell
+ */
+
+#include "cache.h"
+#include "refs.h"
+#include "builtin.h"
+
+int cmd_check_ref_format(int argc, const char **argv, char **envp)
+{
+ if (argc != 2)
+ usage("git check-ref-format refname");
+ return !!check_ref_format(argv[1]);
+}
diff --git a/builtin-diff.c b/builtin-diff.c
index d3ac581f2..de81b05e3 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -122,7 +122,7 @@ static int builtin_diff_b_f(struct rev_info *revs,
stuff_change(&revs->diffopt,
canon_mode(st.st_mode), canon_mode(st.st_mode),
blob[0].sha1, null_sha1,
- blob[0].name, path);
+ path, path);
diffcore_std(&revs->diffopt);
diff_flush(&revs->diffopt);
return 0;
@@ -132,7 +132,9 @@ static int builtin_diff_blobs(struct rev_info *revs,
int argc, const char **argv,
struct blobinfo *blob)
{
- /* Blobs */
+ /* Blobs: the arguments are reversed when setup_revisions()
+ * picked them up.
+ */
unsigned mode = canon_mode(S_IFREG | 0644);
while (1 < argc) {
@@ -145,8 +147,8 @@ static int builtin_diff_blobs(struct rev_info *revs,
}
stuff_change(&revs->diffopt,
mode, mode,
- blob[0].sha1, blob[1].sha1,
- blob[1].name, blob[1].name);
+ blob[1].sha1, blob[0].sha1,
+ blob[0].name, blob[0].name);
diffcore_std(&revs->diffopt);
diff_flush(&revs->diffopt);
return 0;
diff --git a/builtin-grep.c b/builtin-grep.c
new file mode 100644
index 000000000..d09ddf048
--- /dev/null
+++ b/builtin-grep.c
@@ -0,0 +1,902 @@
+/*
+ * Builtin "git grep"
+ *
+ * Copyright (c) 2006 Junio C Hamano
+ */
+#include "cache.h"
+#include "blob.h"
+#include "tree.h"
+#include "commit.h"
+#include "tag.h"
+#include "tree-walk.h"
+#include "builtin.h"
+#include <regex.h>
+#include <fnmatch.h>
+#include <sys/wait.h>
+
+/*
+ * git grep pathspecs are somewhat different from diff-tree pathspecs;
+ * pathname wildcards are allowed.
+ */
+static int pathspec_matches(const char **paths, const char *name)
+{
+ int namelen, i;
+ if (!paths || !*paths)
+ return 1;
+ namelen = strlen(name);
+ for (i = 0; paths[i]; i++) {
+ const char *match = paths[i];
+ int matchlen = strlen(match);
+ const char *cp, *meta;
+
+ if ((matchlen <= namelen) &&
+ !strncmp(name, match, matchlen) &&
+ (match[matchlen-1] == '/' ||
+ name[matchlen] == '\0' || name[matchlen] == '/'))
+ return 1;
+ if (!fnmatch(match, name, 0))
+ return 1;
+ if (name[namelen-1] != '/')
+ continue;
+
+ /* We are being asked if the directory ("name") is worth
+ * descending into.
+ *
+ * Find the longest leading directory name that does
+ * not have metacharacter in the pathspec; the name
+ * we are looking at must overlap with that directory.
+ */
+ for (cp = match, meta = NULL; cp - match < matchlen; cp++) {
+ char ch = *cp;
+ if (ch == '*' || ch == '[' || ch == '?') {
+ meta = cp;
+ break;
+ }
+ }
+ if (!meta)
+ meta = cp; /* fully literal */
+
+ if (namelen <= meta - match) {
+ /* Looking at "Documentation/" and
+ * the pattern says "Documentation/howto/", or
+ * "Documentation/diff*.txt". The name we
+ * have should match prefix.
+ */
+ if (!memcmp(match, name, namelen))
+ return 1;
+ continue;
+ }
+
+ if (meta - match < namelen) {
+ /* Looking at "Documentation/howto/" and
+ * the pattern says "Documentation/h*";
+ * match up to "Do.../h"; this avoids descending
+ * into "Documentation/technical/".
+ */
+ if (!memcmp(match, name, meta - match))
+ return 1;
+ continue;
+ }
+ }
+ return 0;
+}
+
+struct grep_pat {
+ struct grep_pat *next;
+ const char *origin;
+ int no;
+ const char *pattern;
+ regex_t regexp;
+};
+
+struct grep_opt {
+ struct grep_pat *pattern_list;
+ struct grep_pat **pattern_tail;
+ regex_t regexp;
+ unsigned linenum:1;
+ unsigned invert:1;
+ unsigned name_only:1;
+ unsigned unmatch_name_only:1;
+ unsigned count:1;
+ unsigned word_regexp:1;
+ unsigned fixed:1;
+#define GREP_BINARY_DEFAULT 0
+#define GREP_BINARY_NOMATCH 1
+#define GREP_BINARY_TEXT 2
+ unsigned binary:2;
+ int regflags;
+ unsigned pre_context;
+ unsigned post_context;
+};
+
+static void add_pattern(struct grep_opt *opt, const char *pat,
+ const char *origin, int no)
+{
+ struct grep_pat *p = xcalloc(1, sizeof(*p));
+ p->pattern = pat;
+ p->origin = origin;
+ p->no = no;
+ *opt->pattern_tail = p;
+ opt->pattern_tail = &p->next;
+ p->next = NULL;
+}
+
+static void compile_patterns(struct grep_opt *opt)
+{
+ struct grep_pat *p;
+ for (p = opt->pattern_list; p; p = p->next) {
+ int err = regcomp(&p->regexp, p->pattern, opt->regflags);
+ if (err) {
+ char errbuf[1024];
+ char where[1024];
+ if (p->no)
+ sprintf(where, "In '%s' at %d, ",
+ p->origin, p->no);
+ else if (p->origin)
+ sprintf(where, "%s, ", p->origin);
+ else
+ where[0] = 0;
+ regerror(err, &p->regexp, errbuf, 1024);
+ regfree(&p->regexp);
+ die("%s'%s': %s", where, p->pattern, errbuf);
+ }
+ }
+}
+
+static char *end_of_line(char *cp, unsigned long *left)
+{
+ unsigned long l = *left;
+ while (l && *cp != '\n') {
+ l--;
+ cp++;
+ }
+ *left = l;
+ return cp;
+}
+
+static int word_char(char ch)
+{
+ return isalnum(ch) || ch == '_';
+}
+
+static void show_line(struct grep_opt *opt, const char *bol, const char *eol,
+ const char *name, unsigned lno, char sign)
+{
+ printf("%s%c", name, sign);
+ if (opt->linenum)
+ printf("%d%c", lno, sign);
+ printf("%.*s\n", (int)(eol-bol), bol);
+}
+
+/*
+ * NEEDSWORK: share code with diff.c
+ */
+#define FIRST_FEW_BYTES 8000
+static int buffer_is_binary(const char *ptr, unsigned long size)
+{
+ if (FIRST_FEW_BYTES < size)
+ size = FIRST_FEW_BYTES;
+ if (memchr(ptr, 0, size))
+ return 1;
+ return 0;
+}
+
+static int fixmatch(const char *pattern, char *line, regmatch_t *match)
+{
+ char *hit = strstr(line, pattern);
+ if (!hit) {
+ match->rm_so = match->rm_eo = -1;
+ return REG_NOMATCH;
+ }
+ else {
+ match->rm_so = hit - line;
+ match->rm_eo = match->rm_so + strlen(pattern);
+ return 0;
+ }
+}
+
+static int grep_buffer(struct grep_opt *opt, const char *name,
+ char *buf, unsigned long size)
+{
+ char *bol = buf;
+ unsigned long left = size;
+ unsigned lno = 1;
+ struct pre_context_line {
+ char *bol;
+ char *eol;
+ } *prev = NULL, *pcl;
+ unsigned last_hit = 0;
+ unsigned last_shown = 0;
+ int binary_match_only = 0;
+ const char *hunk_mark = "";
+ unsigned count = 0;
+
+ if (buffer_is_binary(buf, size)) {
+ switch (opt->binary) {
+ case GREP_BINARY_DEFAULT:
+ binary_match_only = 1;
+ break;
+ case GREP_BINARY_NOMATCH:
+ return 0; /* Assume unmatch */
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (opt->pre_context)
+ prev = xcalloc(opt->pre_context, sizeof(*prev));
+ if (opt->pre_context || opt->post_context)
+ hunk_mark = "--\n";
+
+ while (left) {
+ regmatch_t pmatch[10];
+ char *eol, ch;
+ int hit = 0;
+ struct grep_pat *p;
+
+ eol = end_of_line(bol, &left);
+ ch = *eol;
+ *eol = 0;
+
+ for (p = opt->pattern_list; p; p = p->next) {
+ if (!opt->fixed) {
+ regex_t *exp = &p->regexp;
+ hit = !regexec(exp, bol, ARRAY_SIZE(pmatch),
+ pmatch, 0);
+ }
+ else {
+ hit = !fixmatch(p->pattern, bol, pmatch);
+ }
+
+ if (hit && opt->word_regexp) {
+ /* Match beginning must be either
+ * beginning of the line, or at word
+ * boundary (i.e. the last char must
+ * not be alnum or underscore).
+ */
+ if ((pmatch[0].rm_so < 0) ||
+ (eol - bol) <= pmatch[0].rm_so ||
+ (pmatch[0].rm_eo < 0) ||
+ (eol - bol) < pmatch[0].rm_eo)
+ die("regexp returned nonsense");
+ if (pmatch[0].rm_so != 0 &&
+ word_char(bol[pmatch[0].rm_so-1]))
+ hit = 0;
+ if (pmatch[0].rm_eo != (eol-bol) &&
+ word_char(bol[pmatch[0].rm_eo]))
+ hit = 0;
+ }
+ if (hit)
+ break;
+ }
+ /* "grep -v -e foo -e bla" should list lines
+ * that do not have either, so inversion should
+ * be done outside.
+ */
+ if (opt->invert)
+ hit = !hit;
+ if (opt->unmatch_name_only) {
+ if (hit)
+ return 0;
+ goto next_line;
+ }
+ if (hit) {
+ count++;
+ if (binary_match_only) {
+ printf("Binary file %s matches\n", name);
+ return 1;
+ }
+ if (opt->name_only) {
+ printf("%s\n", name);
+ return 1;
+ }
+ /* Hit at this line. If we haven't shown the
+ * pre-context lines, we would need to show them.
+ * When asked to do "count", this still show
+ * the context which is nonsense, but the user
+ * deserves to get that ;-).
+ */
+ if (opt->pre_context) {
+ unsigned from;
+ if (opt->pre_context < lno)
+ from = lno - opt->pre_context;
+ else
+ from = 1;
+ if (from <= last_shown)
+ from = last_shown + 1;
+ if (last_shown && from != last_shown + 1)
+ printf(hunk_mark);
+ while (from < lno) {
+ pcl = &prev[lno-from-1];
+ show_line(opt, pcl->bol, pcl->eol,
+ name, from, '-');
+ from++;
+ }
+ last_shown = lno-1;
+ }
+ if (last_shown && lno != last_shown + 1)
+ printf(hunk_mark);
+ if (!opt->count)
+ show_line(opt, bol, eol, name, lno, ':');
+ last_shown = last_hit = lno;
+ }
+ else if (last_hit &&
+ lno <= last_hit + opt->post_context) {
+ /* If the last hit is within the post context,
+ * we need to show this line.
+ */
+ if (last_shown && lno != last_shown + 1)
+ printf(hunk_mark);
+ show_line(opt, bol, eol, name, lno, '-');
+ last_shown = lno;
+ }
+ if (opt->pre_context) {
+ memmove(prev+1, prev,
+ (opt->pre_context-1) * sizeof(*prev));
+ prev->bol = bol;
+ prev->eol = eol;
+ }
+
+ next_line:
+ *eol = ch;
+ bol = eol + 1;
+ if (!left)
+ break;
+ left--;
+ lno++;
+ }
+
+ if (opt->unmatch_name_only) {
+ /* We did not see any hit, so we want to show this */
+ printf("%s\n", name);
+ return 1;
+ }
+
+ /* NEEDSWORK:
+ * The real "grep -c foo *.c" gives many "bar.c:0" lines,
+ * which feels mostly useless but sometimes useful. Maybe
+ * make it another option? For now suppress them.
+ */
+ if (opt->count && count)
+ printf("%s:%u\n", name, count);
+ return !!last_hit;
+}
+
+static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char *name)
+{
+ unsigned long size;
+ char *data;
+ char type[20];
+ int hit;
+ data = read_sha1_file(sha1, type, &size);
+ if (!data) {
+ error("'%s': unable to read %s", name, sha1_to_hex(sha1));
+ return 0;
+ }
+ hit = grep_buffer(opt, name, data, size);
+ free(data);
+ return hit;
+}
+
+static int grep_file(struct grep_opt *opt, const char *filename)
+{
+ struct stat st;
+ int i;
+ char *data;
+ if (lstat(filename, &st) < 0) {
+ err_ret:
+ if (errno != ENOENT)
+ error("'%s': %s", filename, strerror(errno));
+ return 0;
+ }
+ if (!st.st_size)
+ return 0; /* empty file -- no grep hit */
+ if (!S_ISREG(st.st_mode))
+ return 0;
+ i = open(filename, O_RDONLY);
+ if (i < 0)
+ goto err_ret;
+ data = xmalloc(st.st_size + 1);
+ if (st.st_size != xread(i, data, st.st_size)) {
+ error("'%s': short read %s", filename, strerror(errno));
+ close(i);
+ free(data);
+ return 0;
+ }
+ close(i);
+ i = grep_buffer(opt, filename, data, st.st_size);
+ free(data);
+ return i;
+}
+
+static int exec_grep(int argc, const char **argv)
+{
+ pid_t pid;
+ int status;
+
+ argv[argc] = NULL;
+ pid = fork();
+ if (pid < 0)
+ return pid;
+ if (!pid) {
+ execvp("grep", (char **) argv);
+ exit(255);
+ }
+ while (waitpid(pid, &status, 0) < 0) {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+ if (WIFEXITED(status)) {
+ if (!WEXITSTATUS(status))
+ return 1;
+ return 0;
+ }
+ return -1;
+}
+
+#define MAXARGS 1000
+#define ARGBUF 4096
+#define push_arg(a) do { \
+ if (nr < MAXARGS) argv[nr++] = (a); \
+ else die("maximum number of args exceeded"); \
+ } while (0)
+
+static int external_grep(struct grep_opt *opt, const char **paths, int cached)
+{
+ int i, nr, argc, hit, len;
+ const char *argv[MAXARGS+1];
+ char randarg[ARGBUF];
+ char *argptr = randarg;
+ struct grep_pat *p;
+
+ len = nr = 0;
+ push_arg("grep");
+ if (opt->fixed)
+ push_arg("-F");
+ if (opt->linenum)
+ push_arg("-n");
+ if (opt->regflags & REG_EXTENDED)
+ push_arg("-E");
+ if (opt->word_regexp)
+ push_arg("-w");
+ if (opt->name_only)
+ push_arg("-l");
+ if (opt->unmatch_name_only)
+ push_arg("-L");
+ if (opt->count)
+ push_arg("-c");
+ if (opt->post_context || opt->pre_context) {
+ if (opt->post_context != opt->pre_context) {
+ if (opt->pre_context) {
+ push_arg("-B");
+ len += snprintf(argptr, sizeof(randarg)-len,
+ "%u", opt->pre_context);
+ if (sizeof(randarg) <= len)
+ die("maximum length of args exceeded");
+ push_arg(argptr);
+ argptr += len;
+ }
+ if (opt->post_context) {
+ push_arg("-A");
+ len += snprintf(argptr, sizeof(randarg)-len,
+ "%u", opt->post_context);
+ if (sizeof(randarg) <= len)
+ die("maximum length of args exceeded");
+ push_arg(argptr);
+ argptr += len;
+ }
+ }
+ else {
+ push_arg("-C");
+ len += snprintf(argptr, sizeof(randarg)-len,
+ "%u", opt->post_context);
+ if (sizeof(randarg) <= len)
+ die("maximum length of args exceeded");
+ push_arg(argptr);
+ argptr += len;
+ }
+ }
+ for (p = opt->pattern_list; p; p = p->next) {
+ push_arg("-e");
+ push_arg(p->pattern);
+ }
+
+ /*
+ * To make sure we get the header printed out when we want it,
+ * add /dev/null to the paths to grep. This is unnecessary
+ * (and wrong) with "-l" or "-L", which always print out the
+ * name anyway.
+ *
+ * GNU grep has "-H", but this is portable.
+ */
+ if (!opt->name_only && !opt->unmatch_name_only)
+ push_arg("/dev/null");
+
+ hit = 0;
+ argc = nr;
+ for (i = 0; i < active_nr; i++) {
+ struct cache_entry *ce = active_cache[i];
+ const char *name;
+ if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode)))
+ continue;
+ if (!pathspec_matches(paths, ce->name))
+ continue;
+ name = ce->name;
+ if (name[0] == '-') {
+ int len = ce_namelen(ce);
+ name = xmalloc(len + 3);
+ memcpy(name, "./", 2);
+ memcpy(name + 2, ce->name, len + 1);
+ }
+ argv[argc++] = name;
+ if (argc < MAXARGS)
+ continue;
+ hit += exec_grep(argc, argv);
+ argc = nr;
+ }
+ if (argc > nr)
+ hit += exec_grep(argc, argv);
+ return 0;
+}
+
+static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
+{
+ int hit = 0;
+ int nr;
+ read_cache();
+
+#ifdef __unix__
+ /*
+ * Use the external "grep" command for the case where
+ * we grep through the checked-out files. It tends to
+ * be a lot more optimized
+ */
+ if (!cached) {
+ hit = external_grep(opt, paths, cached);
+ if (hit >= 0)
+ return hit;
+ }
+#endif
+
+ for (nr = 0; nr < active_nr; nr++) {
+ struct cache_entry *ce = active_cache[nr];
+ if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode)))
+ continue;
+ if (!pathspec_matches(paths, ce->name))
+ continue;
+ if (cached)
+ hit |= grep_sha1(opt, ce->sha1, ce->name);
+ else
+ hit |= grep_file(opt, ce->name);
+ }
+ return hit;
+}
+
+static int grep_tree(struct grep_opt *opt, const char **paths,
+ struct tree_desc *tree,
+ const char *tree_name, const char *base)
+{
+ unsigned mode;
+ int len;
+ int hit = 0;
+ const char *path;
+ const unsigned char *sha1;
+ char *down;
+ char *path_buf = xmalloc(PATH_MAX + strlen(tree_name) + 100);
+
+ if (tree_name[0]) {
+ int offset = sprintf(path_buf, "%s:", tree_name);
+ down = path_buf + offset;
+ strcat(down, base);
+ }
+ else {
+ down = path_buf;
+ strcpy(down, base);
+ }
+ len = strlen(path_buf);
+
+ while (tree->size) {
+ int pathlen;
+ sha1 = tree_entry_extract(tree, &path, &mode);
+ pathlen = strlen(path);
+ strcpy(path_buf + len, path);
+
+ if (S_ISDIR(mode))
+ /* Match "abc/" against pathspec to
+ * decide if we want to descend into "abc"
+ * directory.
+ */
+ strcpy(path_buf + len + pathlen, "/");
+
+ if (!pathspec_matches(paths, down))
+ ;
+ else if (S_ISREG(mode))
+ hit |= grep_sha1(opt, sha1, path_buf);
+ else if (S_ISDIR(mode)) {
+ char type[20];
+ struct tree_desc sub;
+ void *data;
+ data = read_sha1_file(sha1, type, &sub.size);
+ if (!data)
+ die("unable to read tree (%s)",
+ sha1_to_hex(sha1));
+ sub.buf = data;
+ hit |= grep_tree(opt, paths, &sub, tree_name, down);
+ free(data);
+ }
+ update_tree_entry(tree);
+ }
+ return hit;
+}
+
+static int grep_object(struct grep_opt *opt, const char **paths,
+ struct object *obj, const char *name)
+{
+ if (!strcmp(obj->type, blob_type))
+ return grep_sha1(opt, obj->sha1, name);
+ if (!strcmp(obj->type, commit_type) ||
+ !strcmp(obj->type, tree_type)) {
+ struct tree_desc tree;
+ void *data;
+ int hit;
+ data = read_object_with_reference(obj->sha1, tree_type,
+ &tree.size, NULL);
+ if (!data)
+ die("unable to read tree (%s)", sha1_to_hex(obj->sha1));
+ tree.buf = data;
+ hit = grep_tree(opt, paths, &tree, name, "");
+ free(data);
+ return hit;
+ }
+ die("unable to grep from object of type %s", obj->type);
+}
+
+static const char builtin_grep_usage[] =
+"git-grep <option>* <rev>* [-e] <pattern> [<path>...]";
+
+int cmd_grep(int argc, const char **argv, char **envp)
+{
+ int hit = 0;
+ int cached = 0;
+ int seen_dashdash = 0;
+ struct grep_opt opt;
+ struct object_list *list, **tail, *object_list = NULL;
+ const char *prefix = setup_git_directory();
+ const char **paths = NULL;
+ int i;
+
+ memset(&opt, 0, sizeof(opt));
+ opt.pattern_tail = &opt.pattern_list;
+ opt.regflags = REG_NEWLINE;
+
+ /*
+ * If there is no -- then the paths must exist in the working
+ * tree. If there is no explicit pattern specified with -e or
+ * -f, we take the first unrecognized non option to be the
+ * pattern, but then what follows it must be zero or more
+ * valid refs up to the -- (if exists), and then existing
+ * paths. If there is an explicit pattern, then the first
+ * unrecocnized non option is the beginning of the refs list
+ * that continues up to the -- (if exists), and then paths.
+ */
+
+ tail = &object_list;
+ while (1 < argc) {
+ const char *arg = argv[1];
+ argc--; argv++;
+ if (!strcmp("--cached", arg)) {
+ cached = 1;
+ continue;
+ }
+ if (!strcmp("-a", arg) ||
+ !strcmp("--text", arg)) {
+ opt.binary = GREP_BINARY_TEXT;
+ continue;
+ }
+ if (!strcmp("-i", arg) ||
+ !strcmp("--ignore-case", arg)) {
+ opt.regflags |= REG_ICASE;
+ continue;
+ }
+ if (!strcmp("-I", arg)) {
+ opt.binary = GREP_BINARY_NOMATCH;
+ continue;
+ }
+ if (!strcmp("-v", arg) ||
+ !strcmp("--invert-match", arg)) {
+ opt.invert = 1;
+ continue;
+ }
+ if (!strcmp("-E", arg) ||
+ !strcmp("--extended-regexp", arg)) {
+ opt.regflags |= REG_EXTENDED;
+ continue;
+ }
+ if (!strcmp("-F", arg) ||
+ !strcmp("--fixed-strings", arg)) {
+ opt.fixed = 1;
+ continue;
+ }
+ if (!strcmp("-G", arg) ||
+ !strcmp("--basic-regexp", arg)) {
+ opt.regflags &= ~REG_EXTENDED;
+ continue;
+ }
+ if (!strcmp("-n", arg)) {
+ opt.linenum = 1;
+ continue;
+ }
+ if (!strcmp("-H", arg)) {
+ /* We always show the pathname, so this
+ * is a noop.
+ */
+ continue;
+ }
+ if (!strcmp("-l", arg) ||
+ !strcmp("--files-with-matches", arg)) {
+ opt.name_only = 1;
+ continue;
+ }
+ if (!strcmp("-L", arg) ||
+ !strcmp("--files-without-match", arg)) {
+ opt.unmatch_name_only = 1;
+ continue;
+ }
+ if (!strcmp("-c", arg) ||
+ !strcmp("--count", arg)) {
+ opt.count = 1;
+ continue;
+ }
+ if (!strcmp("-w", arg) ||
+ !strcmp("--word-regexp", arg)) {
+ opt.word_regexp = 1;
+ continue;
+ }
+ if (!strncmp("-A", arg, 2) ||
+ !strncmp("-B", arg, 2) ||
+ !strncmp("-C", arg, 2) ||
+ (arg[0] == '-' && '1' <= arg[1] && arg[1] <= '9')) {
+ unsigned num;
+ const char *scan;
+ switch (arg[1]) {
+ case 'A': case 'B': case 'C':
+ if (!arg[2]) {
+ if (argc <= 1)
+ usage(builtin_grep_usage);
+ scan = *++argv;
+ argc--;
+ }
+ else
+ scan = arg + 2;
+ break;
+ default:
+ scan = arg + 1;
+ break;
+ }
+ if (sscanf(scan, "%u", &num) != 1)
+ usage(builtin_grep_usage);
+ switch (arg[1]) {
+ case 'A':
+ opt.post_context = num;
+ break;
+ default:
+ case 'C':
+ opt.post_context = num;
+ case 'B':
+ opt.pre_context = num;
+ break;
+ }
+ continue;
+ }
+ if (!strcmp("-f", arg)) {
+ FILE *patterns;
+ int lno = 0;
+ char buf[1024];
+ if (argc <= 1)
+ usage(builtin_grep_usage);
+ patterns = fopen(argv[1], "r");
+ if (!patterns)
+ die("'%s': %s", argv[1], strerror(errno));
+ while (fgets(buf, sizeof(buf), patterns)) {
+ int len = strlen(buf);
+ if (buf[len-1] == '\n')
+ buf[len-1] = 0;
+ /* ignore empty line like grep does */
+ if (!buf[0])
+ continue;
+ add_pattern(&opt, strdup(buf), argv[1], ++lno);
+ }
+ fclose(patterns);
+ argv++;
+ argc--;
+ continue;
+ }
+ if (!strcmp("-e", arg)) {
+ if (1 < argc) {
+ add_pattern(&opt, argv[1], "-e option", 0);
+ argv++;
+ argc--;
+ continue;
+ }
+ usage(builtin_grep_usage);
+ }
+ if (!strcmp("--", arg))
+ break;
+ if (*arg == '-')
+ usage(builtin_grep_usage);
+
+ /* First unrecognized non-option token */
+ if (!opt.pattern_list) {
+ add_pattern(&opt, arg, "command line", 0);
+ break;
+ }
+ else {
+ /* We are looking at the first path or rev;
+ * it is found at argv[1] after leaving the
+ * loop.
+ */
+ argc++; argv--;
+ break;
+ }
+ }
+
+ if (!opt.pattern_list)
+ die("no pattern given.");
+ if ((opt.regflags != REG_NEWLINE) && opt.fixed)
+ die("cannot mix --fixed-strings and regexp");
+ if (!opt.fixed)
+ compile_patterns(&opt);
+
+ /* Check revs and then paths */
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+ unsigned char sha1[20];
+ /* Is it a rev? */
+ if (!get_sha1(arg, sha1)) {
+ struct object *object = parse_object(sha1);
+ struct object_list *elem;
+ if (!object)
+ die("bad object %s", arg);
+ elem = object_list_insert(object, tail);
+ elem->name = arg;
+ tail = &elem->next;
+ continue;
+ }
+ if (!strcmp(arg, "--")) {
+ i++;
+ seen_dashdash = 1;
+ }
+ break;
+ }
+
+ /* The rest are paths */
+ if (!seen_dashdash) {
+ int j;
+ for (j = i; j < argc; j++)
+ verify_filename(prefix, argv[j]);
+ }
+
+ if (i < argc)
+ paths = get_pathspec(prefix, argv + i);
+ else if (prefix) {
+ paths = xcalloc(2, sizeof(const char *));
+ paths[0] = prefix;
+ paths[1] = NULL;
+ }
+
+ if (!object_list)
+ return !grep_cache(&opt, paths, cached);
+
+ if (cached)
+ die("both --cached and trees are given.");
+
+ for (list = object_list; list; list = list->next) {
+ struct object *real_obj;
+ real_obj = deref_tag(list->item, NULL, 0);
+ if (grep_object(&opt, paths, real_obj, list->name))
+ hit = 1;
+ }
+ return !hit;
+}
diff --git a/init-db.c b/builtin-init-db.c
index ff294960f..2a1384ccb 100644
--- a/init-db.c
+++ b/builtin-init-db.c
@@ -4,6 +4,7 @@
* Copyright (C) Linus Torvalds, 2005
*/
#include "cache.h"
+#include "builtin.h"
#ifndef DEFAULT_GIT_TEMPLATE_DIR
#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/"
@@ -116,7 +117,7 @@ static void copy_templates_1(char *path, int baselen,
}
}
-static void copy_templates(const char *git_dir, int len, char *template_dir)
+static void copy_templates(const char *git_dir, int len, const char *template_dir)
{
char path[PATH_MAX];
char template_path[PATH_MAX];
@@ -163,7 +164,7 @@ static void copy_templates(const char *git_dir, int len, char *template_dir)
closedir(dir);
}
-static void create_default_files(const char *git_dir, char *template_path)
+static void create_default_files(const char *git_dir, const char *template_path)
{
unsigned len = strlen(git_dir);
static char path[PATH_MAX];
@@ -234,15 +235,16 @@ static const char init_db_usage[] =
* On the other hand, it might just make lookup slower and messier. You
* be the judge. The default case is to have one DB per managed directory.
*/
-int main(int argc, char **argv)
+int cmd_init_db(int argc, const char **argv, char **envp)
{
const char *git_dir;
const char *sha1_dir;
- char *path, *template_dir = NULL;
+ const char *template_dir = NULL;
+ char *path;
int len, i;
for (i = 1; i < argc; i++, argv++) {
- char *arg = argv[1];
+ const char *arg = argv[1];
if (!strncmp(arg, "--template=", 11))
template_dir = arg+11;
else if (!strcmp(arg, "--shared"))
diff --git a/builtin-log.c b/builtin-log.c
index 69f2911cb..c4ceee0f9 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -19,6 +19,13 @@ static int cmd_log_wc(int argc, const char **argv, char **envp,
rev->commit_format = CMIT_FMT_DEFAULT;
rev->verbose_header = 1;
argc = setup_revisions(argc, argv, rev, "HEAD");
+ if (rev->always_show_header) {
+ if (rev->diffopt.pickaxe || rev->diffopt.filter) {
+ rev->always_show_header = 0;
+ if (rev->diffopt.output_format == DIFF_FORMAT_RAW)
+ rev->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT;
+ }
+ }
if (argc > 1)
die("unrecognized argument: %s", argv[1]);
diff --git a/rev-list.c b/builtin-rev-list.c
index 8b0ec388f..446802d37 100644
--- a/rev-list.c
+++ b/builtin-rev-list.c
@@ -7,6 +7,7 @@
#include "tree-walk.h"
#include "diff.h"
#include "revision.h"
+#include "builtin.h"
/* bits #0-15 in revision.h */
@@ -36,7 +37,7 @@ static const char rev_list_usage[] =
" --bisect"
;
-struct rev_info revs;
+static struct rev_info revs;
static int bisect_list = 0;
static int show_timestamp = 0;
@@ -291,7 +292,7 @@ static void mark_edges_uninteresting(struct commit_list *list)
}
}
-int main(int argc, const char **argv)
+int cmd_rev_list(int argc, const char **argv, char **envp)
{
struct commit_list *list;
int i;
diff --git a/builtin.h b/builtin.h
index bb63f0729..60541262c 100644
--- a/builtin.h
+++ b/builtin.h
@@ -23,5 +23,9 @@ 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);
+extern int cmd_grep(int argc, const char **argv, char **envp);
+extern int cmd_rev_list(int argc, const char **argv, char **envp);
+extern int cmd_check_ref_format(int argc, const char **argv, char **envp);
+extern int cmd_init_db(int argc, const char **argv, char **envp);
#endif
diff --git a/cache.h b/cache.h
index 4b7a43925..afa8e4f0a 100644
--- a/cache.h
+++ b/cache.h
@@ -158,6 +158,12 @@ extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_o
extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
+#define REFRESH_REALLY 0x0001 /* ignore_valid */
+#define REFRESH_UNMERGED 0x0002 /* allow unmerged */
+#define REFRESH_QUIET 0x0004 /* be quiet about it */
+#define REFRESH_IGNORE_MISSING 0x0008 /* ignore non-existent */
+extern int refresh_cache(unsigned int flags);
+
struct cache_file {
struct cache_file *next;
char lockfile[PATH_MAX];
diff --git a/check-ref-format.c b/check-ref-format.c
deleted file mode 100644
index a0adb3dcb..000000000
--- a/check-ref-format.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * GIT - The information manager from hell
- */
-
-#include "cache.h"
-#include "refs.h"
-
-#include <stdio.h>
-
-int main(int ac, char **av)
-{
- if (ac != 2)
- usage("git-check-ref-format refname");
- if (check_ref_format(av[1]))
- exit(1);
- return 0;
-}
diff --git a/combine-diff.c b/combine-diff.c
index 8a8fe3863..64b20cce2 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -608,6 +608,7 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
int abbrev = opt->full_index ? 40 : DEFAULT_ABBREV;
mmfile_t result_file;
+ context = opt->context;
/* Read the result of merge first */
if (!working_tree_file)
result = grab_blob(elem->sha1, &result_size);
diff --git a/commit.c b/commit.c
index 2717dd81c..4a26070c1 100644
--- a/commit.c
+++ b/commit.c
@@ -22,23 +22,33 @@ struct sort_node
const char *commit_type = "commit";
+struct cmt_fmt_map {
+ const char *n;
+ size_t cmp_len;
+ enum cmit_fmt v;
+} cmt_fmts[] = {
+ { "raw", 1, CMIT_FMT_RAW },
+ { "medium", 1, CMIT_FMT_MEDIUM },
+ { "short", 1, CMIT_FMT_SHORT },
+ { "full", 5, CMIT_FMT_FULL },
+ { "fuller", 5, CMIT_FMT_FULLER },
+ { "oneline", 1, CMIT_FMT_ONELINE },
+};
+
enum cmit_fmt get_commit_format(const char *arg)
{
- if (!*arg)
+ int i;
+
+ if (!arg || !*arg)
return CMIT_FMT_DEFAULT;
- if (!strcmp(arg, "=raw"))
- return CMIT_FMT_RAW;
- if (!strcmp(arg, "=medium"))
- return CMIT_FMT_MEDIUM;
- if (!strcmp(arg, "=short"))
- return CMIT_FMT_SHORT;
- if (!strcmp(arg, "=full"))
- return CMIT_FMT_FULL;
- if (!strcmp(arg, "=fuller"))
- return CMIT_FMT_FULLER;
- if (!strcmp(arg, "=oneline"))
- return CMIT_FMT_ONELINE;
- die("invalid --pretty format");
+ if (*arg == '=')
+ arg++;
+ for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
+ if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len))
+ return cmt_fmts[i].v;
+ }
+
+ die("invalid --pretty format: %s", arg);
}
static struct commit *check_commit(struct object *obj,
diff --git a/config.c b/config.c
index 0f518c957..0248c6d8a 100644
--- a/config.c
+++ b/config.c
@@ -134,6 +134,41 @@ static int get_value(config_fn_t fn, char *name, unsigned int len)
return fn(name, value);
}
+static int get_extended_base_var(char *name, int baselen, int c)
+{
+ do {
+ if (c == '\n')
+ return -1;
+ c = get_next_char();
+ } while (isspace(c));
+
+ /* We require the format to be '[base "extension"]' */
+ if (c != '"')
+ return -1;
+ name[baselen++] = '.';
+
+ for (;;) {
+ int c = get_next_char();
+ if (c == '\n')
+ return -1;
+ if (c == '"')
+ break;
+ if (c == '\\') {
+ c = get_next_char();
+ if (c == '\n')
+ return -1;
+ }
+ name[baselen++] = c;
+ if (baselen > MAXNAME / 2)
+ return -1;
+ }
+
+ /* Final ']' */
+ if (get_next_char() != ']')
+ return -1;
+ return baselen;
+}
+
static int get_base_var(char *name)
{
int baselen = 0;
@@ -144,6 +179,8 @@ static int get_base_var(char *name)
return -1;
if (c == ']')
return baselen;
+ if (isspace(c))
+ return get_extended_base_var(name, baselen, c);
if (!isalnum(c) && c != '.')
return -1;
if (baselen > MAXNAME / 2)
@@ -335,10 +372,12 @@ static int store_aux(const char* key, const char* value)
store.offset[store.seen] = ftell(config_file);
store.state = KEY_SEEN;
store.seen++;
- } else if (strrchr(key, '.') - key == store.baselen &&
+ } else {
+ if (strrchr(key, '.') - key == store.baselen &&
!strncmp(key, store.key, store.baselen)) {
store.state = SECTION_SEEN;
store.offset[store.seen] = ftell(config_file);
+ }
}
}
return 0;
@@ -346,8 +385,30 @@ static int store_aux(const char* key, const char* value)
static void store_write_section(int fd, const char* key)
{
+ const char *dot = strchr(key, '.');
+ int len1 = store.baselen, len2 = -1;
+
+ dot = strchr(key, '.');
+ if (dot) {
+ int dotlen = dot - key;
+ if (dotlen < len1) {
+ len2 = len1 - dotlen - 1;
+ len1 = dotlen;
+ }
+ }
+
write(fd, "[", 1);
- write(fd, key, store.baselen);
+ write(fd, key, len1);
+ if (len2 >= 0) {
+ write(fd, " \"", 2);
+ while (--len2 >= 0) {
+ unsigned char c = *++dot;
+ if (c == '"')
+ write(fd, "\\", 1);
+ write(fd, &c, 1);
+ }
+ write(fd, "\"", 1);
+ }
write(fd, "]\n", 2);
}
@@ -421,7 +482,7 @@ int git_config_set(const char* key, const char* value)
int git_config_set_multivar(const char* key, const char* value,
const char* value_regex, int multi_replace)
{
- int i;
+ int i, dot;
int fd = -1, in_fd;
int ret;
char* config_filename = strdup(git_path("config"));
@@ -446,16 +507,23 @@ int git_config_set_multivar(const char* key, const char* value,
* Validate the key and while at it, lower case it for matching.
*/
store.key = (char*)malloc(strlen(key)+1);
- for (i = 0; key[i]; i++)
- if (i != store.baselen &&
- ((!isalnum(key[i]) && key[i] != '.') ||
- (i == store.baselen+1 && !isalpha(key[i])))) {
- fprintf(stderr, "invalid key: %s\n", key);
- free(store.key);
- ret = 1;
- goto out_free;
- } else
- store.key[i] = tolower(key[i]);
+ dot = 0;
+ for (i = 0; key[i]; i++) {
+ unsigned char c = key[i];
+ if (c == '.')
+ dot = 1;
+ /* Leave the extended basename untouched.. */
+ if (!dot || i > store.baselen) {
+ if (!isalnum(c) || (i == store.baselen+1 && !isalpha(c))) {
+ fprintf(stderr, "invalid key: %s\n", key);
+ free(store.key);
+ ret = 1;
+ goto out_free;
+ }
+ c = tolower(c);
+ }
+ store.key[i] = c;
+ }
store.key[i] = 0;
/*
diff --git a/delta.h b/delta.h
index 727ae30e9..7b3f86d85 100644
--- a/delta.h
+++ b/delta.h
@@ -18,6 +18,8 @@ create_delta_index(const void *buf, unsigned long bufsize);
/*
* free_delta_index: free the index created by create_delta_index()
+ *
+ * Given pointer must be what create_delta_index() returned, or NULL.
*/
extern void free_delta_index(struct delta_index *index);
diff --git a/diff-tree.c b/diff-tree.c
index 7207867a7..69bb74b31 100644
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -138,7 +138,10 @@ int main(int argc, const char **argv)
opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
DIFF_SETUP_USE_CACHE);
while (fgets(line, sizeof(line), stdin))
- diff_tree_stdin(line);
+ if (line[0] == '\n')
+ fflush(stdout);
+ else
+ diff_tree_stdin(line);
return 0;
}
diff --git a/diff.c b/diff.c
index 5285c0366..e16e0bfc0 100644
--- a/diff.c
+++ b/diff.c
@@ -563,7 +563,7 @@ static void builtin_diff(const char *name_a,
ecbdata.label_path = lbl;
xpp.flags = XDF_NEED_MINIMAL;
- xecfg.ctxlen = 3;
+ xecfg.ctxlen = o->context;
xecfg.flags = XDL_EMIT_FUNCNAMES;
if (!diffopts)
;
@@ -1187,6 +1187,7 @@ void diff_setup(struct diff_options *options)
options->line_termination = '\n';
options->break_opt = -1;
options->rename_limit = -1;
+ options->context = 3;
options->change = diff_change;
options->add_remove = diff_addremove;
@@ -1227,17 +1228,68 @@ int diff_setup_done(struct diff_options *options)
return 0;
}
+int opt_arg(const char *arg, int arg_short, const char *arg_long, int *val)
+{
+ char c, *eq;
+ int len;
+
+ if (*arg != '-')
+ return 0;
+ c = *++arg;
+ if (!c)
+ return 0;
+ if (c == arg_short) {
+ c = *++arg;
+ if (!c)
+ return 1;
+ if (val && isdigit(c)) {
+ char *end;
+ int n = strtoul(arg, &end, 10);
+ if (*end)
+ return 0;
+ *val = n;
+ return 1;
+ }
+ return 0;
+ }
+ if (c != '-')
+ return 0;
+ arg++;
+ eq = strchr(arg, '=');
+ if (eq)
+ len = eq - arg;
+ else
+ len = strlen(arg);
+ if (!len || strncmp(arg, arg_long, len))
+ return 0;
+ if (eq) {
+ int n;
+ char *end;
+ if (!isdigit(*++eq))
+ return 0;
+ n = strtoul(eq, &end, 10);
+ if (*end)
+ return 0;
+ *val = n;
+ }
+ return 1;
+}
+
int diff_opt_parse(struct diff_options *options, const char **av, int ac)
{
const char *arg = av[0];
if (!strcmp(arg, "-p") || !strcmp(arg, "-u"))
options->output_format = DIFF_FORMAT_PATCH;
+ else if (opt_arg(arg, 'U', "unified", &options->context))
+ options->output_format = DIFF_FORMAT_PATCH;
else if (!strcmp(arg, "--patch-with-raw")) {
options->output_format = DIFF_FORMAT_PATCH;
options->with_raw = 1;
}
else if (!strcmp(arg, "--stat"))
options->output_format = DIFF_FORMAT_DIFFSTAT;
+ else if (!strcmp(arg, "--summary"))
+ options->summary = 1;
else if (!strcmp(arg, "--patch-with-stat")) {
options->output_format = DIFF_FORMAT_PATCH;
options->with_stat = 1;
@@ -1708,6 +1760,85 @@ static void flush_one_pair(struct diff_filepair *p,
}
}
+static void show_file_mode_name(const char *newdelete, struct diff_filespec *fs)
+{
+ if (fs->mode)
+ printf(" %s mode %06o %s\n", newdelete, fs->mode, fs->path);
+ else
+ printf(" %s %s\n", newdelete, fs->path);
+}
+
+
+static void show_mode_change(struct diff_filepair *p, int show_name)
+{
+ if (p->one->mode && p->two->mode && p->one->mode != p->two->mode) {
+ if (show_name)
+ printf(" mode change %06o => %06o %s\n",
+ p->one->mode, p->two->mode, p->two->path);
+ else
+ printf(" mode change %06o => %06o\n",
+ p->one->mode, p->two->mode);
+ }
+}
+
+static void show_rename_copy(const char *renamecopy, struct diff_filepair *p)
+{
+ const char *old, *new;
+
+ /* Find common prefix */
+ old = p->one->path;
+ new = p->two->path;
+ while (1) {
+ const char *slash_old, *slash_new;
+ slash_old = strchr(old, '/');
+ slash_new = strchr(new, '/');
+ if (!slash_old ||
+ !slash_new ||
+ slash_old - old != slash_new - new ||
+ memcmp(old, new, slash_new - new))
+ break;
+ old = slash_old + 1;
+ new = slash_new + 1;
+ }
+ /* p->one->path thru old is the common prefix, and old and new
+ * through the end of names are renames
+ */
+ if (old != p->one->path)
+ printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
+ (int)(old - p->one->path), p->one->path,
+ old, new, (int)(0.5 + p->score * 100.0/MAX_SCORE));
+ else
+ printf(" %s %s => %s (%d%%)\n", renamecopy,
+ p->one->path, p->two->path,
+ (int)(0.5 + p->score * 100.0/MAX_SCORE));
+ show_mode_change(p, 0);
+}
+
+static void diff_summary(struct diff_filepair *p)
+{
+ switch(p->status) {
+ case DIFF_STATUS_DELETED:
+ show_file_mode_name("delete", p->one);
+ break;
+ case DIFF_STATUS_ADDED:
+ show_file_mode_name("create", p->two);
+ break;
+ case DIFF_STATUS_COPIED:
+ show_rename_copy("copy", p);
+ break;
+ case DIFF_STATUS_RENAMED:
+ show_rename_copy("rename", p);
+ break;
+ default:
+ if (p->score) {
+ printf(" rewrite %s (%d%%)\n", p->two->path,
+ (int)(0.5 + p->score * 100.0/MAX_SCORE));
+ show_mode_change(p, 0);
+ } else show_mode_change(p, 1);
+ break;
+ }
+}
+
void diff_flush(struct diff_options *options)
{
struct diff_queue_struct *q = &diff_queued_diff;
@@ -1741,7 +1872,6 @@ void diff_flush(struct diff_options *options)
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
flush_one_pair(p, diff_output_format, options, diffstat);
- diff_free_filepair(p);
}
if (diffstat) {
@@ -1749,6 +1879,12 @@ void diff_flush(struct diff_options *options)
free(diffstat);
}
+ for (i = 0; i < q->nr; i++) {
+ if (options->summary)
+ diff_summary(q->queue[i]);
+ diff_free_filepair(q->queue[i]);
+ }
+
free(q->queue);
q->queue = NULL;
q->nr = q->alloc = 0;
diff --git a/diff.h b/diff.h
index d05260840..3027974c1 100644
--- a/diff.h
+++ b/diff.h
@@ -31,7 +31,9 @@ struct diff_options {
binary:1,
full_index:1,
silent_on_remove:1,
- find_copies_harder:1;
+ find_copies_harder:1,
+ summary:1;
+ int context;
int break_opt;
int detect_rename;
int line_termination;
diff --git a/git-am.sh b/git-am.sh
index f50dff222..97ec2d0c7 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -15,6 +15,10 @@ stop_here () {
}
stop_here_user_resolve () {
+ if [ -n "$resolvemsg" ]; then
+ echo "$resolvemsg"
+ stop_here $1
+ fi
cmdline=$(basename $0)
if test '' != "$interactive"
then
@@ -87,7 +91,7 @@ fall_back_3way () {
}
prec=4
-dotest=.dotest sign= utf8= keep= skip= interactive= resolved= binary= ws=
+dotest=.dotest sign= utf8= keep= skip= interactive= resolved= binary= ws= resolvemsg=
while case "$#" in 0) break;; esac
do
@@ -123,6 +127,9 @@ do
--whitespace=*)
ws=$1; shift ;;
+ --resolvemsg=*)
+ resolvemsg=$(echo "$1" | sed -e "s/^--resolvemsg=//"); shift ;;
+
--)
shift; break ;;
-*)
@@ -151,7 +158,7 @@ then
else
# Make sure we are not given --skip nor --resolved
test ",$skip,$resolved," = ,,, ||
- die "we are not resuming."
+ die "Resolve operation not in progress, we are not resuming."
# Start afresh.
mkdir -p "$dotest" || exit
diff --git a/git-branch.sh b/git-branch.sh
index ebcc8989d..134e68cf7 100755
--- a/git-branch.sh
+++ b/git-branch.sh
@@ -82,8 +82,7 @@ done
case "$#" in
0)
- git-rev-parse --symbolic --all |
- sed -ne 's|^refs/heads/||p' |
+ git-rev-parse --symbolic --branches |
sort |
while read ref
do
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index c0ae00bda..8c707f2c6 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -350,7 +350,7 @@ sub _line {
return $res;
} elsif($line =~ s/^E //) {
# print STDERR "S: $line\n";
- } elsif($line =~ /^Remove-entry /i) {
+ } elsif($line =~ /^(Remove-entry|Removed) /i) {
$line = $self->readline(); # filename
$line = $self->readline(); # OK
chomp $line;
diff --git a/git-format-patch.sh b/git-format-patch.sh
index c077f44ca..8a16eadfb 100755
--- a/git-format-patch.sh
+++ b/git-format-patch.sh
@@ -274,7 +274,7 @@ print "\n---\n\n";
close FH or die "close $commsg pipe";
' "$keep_subject" "$num" "$signoff" "$headers" "$mimemagic" $commsg
- git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
+ git-diff-tree -p --stat --summary $diff_opts "$commit"
echo
case "$mimemagic" in
'');;
diff --git a/git-grep.sh b/git-grep.sh
deleted file mode 100755
index ad4f2fe81..000000000
--- a/git-grep.sh
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) Linus Torvalds, 2005
-#
-
-USAGE='[<option>...] [-e] <pattern> [<path>...]'
-SUBDIRECTORY_OK='Yes'
-. git-sh-setup
-
-got_pattern () {
- if [ -z "$no_more_patterns" ]
- then
- pattern="$1" no_more_patterns=yes
- else
- die "git-grep: do not specify more than one pattern"
- fi
-}
-
-no_more_patterns=
-pattern=
-flags=()
-git_flags=()
-while : ; do
- case "$1" in
- -o|--cached|--deleted|--others|--killed|\
- --ignored|--modified|--exclude=*|\
- --exclude-from=*|\--exclude-per-directory=*)
- git_flags=("${git_flags[@]}" "$1")
- ;;
- -e)
- got_pattern "$2"
- shift
- ;;
- -A|-B|-C|-D|-d|-f|-m)
- flags=("${flags[@]}" "$1" "$2")
- shift
- ;;
- --)
- # The rest are git-ls-files paths
- shift
- break
- ;;
- -*)
- flags=("${flags[@]}" "$1")
- ;;
- *)
- if [ -z "$no_more_patterns" ]
- then
- got_pattern "$1"
- shift
- fi
- [ "$1" = -- ] && shift
- break
- ;;
- esac
- shift
-done
-[ "$pattern" ] || {
- usage
-}
-git-ls-files -z "${git_flags[@]}" -- "$@" |
- xargs -0 grep "${flags[@]}" -e "$pattern" --
diff --git a/git-merge.sh b/git-merge.sh
index b834e79c9..af1f25b3c 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -55,8 +55,7 @@ finish () {
case "$no_summary" in
'')
- git-diff-tree -p -M "$head" "$1" |
- git-apply --stat --summary
+ git-diff-tree -p --stat --summary -M "$head" "$1"
;;
esac
}
diff --git a/git-quiltimport.sh b/git-quiltimport.sh
new file mode 100755
index 000000000..12d9d0cbc
--- /dev/null
+++ b/git-quiltimport.sh
@@ -0,0 +1,118 @@
+#!/bin/sh
+USAGE='--dry-run --author <author> --patches </path/to/quilt/patch/directory>'
+SUBDIRECTORY_ON=Yes
+. git-sh-setup
+
+dry_run=""
+quilt_author=""
+while case "$#" in 0) break;; esac
+do
+ case "$1" in
+ --au=*|--aut=*|--auth=*|--autho=*|--author=*)
+ quilt_author=$(expr "$1" : '-[^=]*\(.*\)')
+ shift
+ ;;
+
+ --au|--aut|--auth|--autho|--author)
+ case "$#" in 1) usage ;; esac
+ shift
+ quilt_author="$1"
+ shift
+ ;;
+
+ --dry-run)
+ shift
+ dry_run=1
+ ;;
+
+ --pa=*|--pat=*|--patc=*|--patch=*|--patche=*|--patches=*)
+ QUILT_PATCHES=$(expr "$1" : '-[^=]*\(.*\)')
+ shift
+ ;;
+
+ --pa|--pat|--patc|--patch|--patche|--patches)
+ case "$#" in 1) usage ;; esac
+ shift
+ QUILT_PATCHES="$1"
+ shift
+ ;;
+
+ *)
+ break
+ ;;
+ esac
+done
+
+# Quilt Author
+if [ -n "$quilt_author" ] ; then
+ quilt_author_name=$(expr "z$quilt_author" : 'z\(.*[^ ]\) *<.*') &&
+ quilt_author_email=$(expr "z$quilt_author" : '.*<\([^>]*\)') &&
+ test '' != "$quilt_author_name" &&
+ test '' != "$quilt_author_email" ||
+ die "malformatted --author parameter"
+fi
+
+# Quilt patch directory
+: ${QUILT_PATCHES:=patches}
+if ! [ -d "$QUILT_PATCHES" ] ; then
+ echo "The \"$QUILT_PATCHES\" directory does not exist."
+ exit 1
+fi
+
+# Temporay directories
+tmp_dir=.dotest
+tmp_msg="$tmp_dir/msg"
+tmp_patch="$tmp_dir/patch"
+tmp_info="$tmp_dir/info"
+
+
+# Find the intial commit
+commit=$(git-rev-parse HEAD)
+
+mkdir $tmp_dir || exit 2
+for patch_name in $(cat "$QUILT_PATCHES/series" | grep -v '^#'); do
+ echo $patch_name
+ (cat $QUILT_PATCHES/$patch_name | git-mailinfo "$tmp_msg" "$tmp_patch" > "$tmp_info") || exit 3
+
+ # Parse the author information
+ export GIT_AUTHOR_NAME=$(sed -ne 's/Author: //p' "$tmp_info")
+ export GIT_AUTHOR_EMAIL=$(sed -ne 's/Email: //p' "$tmp_info")
+ while test -z "$GIT_AUTHOR_EMAIL" && test -z "$GIT_AUTHOR_NAME" ; do
+ if [ -n "$quilt_author" ] ; then
+ GIT_AUTHOR_NAME="$quilt_author_name";
+ GIT_AUTHOR_EMAIL="$quilt_author_email";
+ elif [ -n "$dry_run" ]; then
+ echo "No author found in $patch_name" >&2;
+ GIT_AUTHOR_NAME="dry-run-not-found";
+ GIT_AUTHOR_EMAIL="dry-run-not-found";
+ else
+ echo "No author found in $patch_name" >&2;
+ echo "---"
+ cat $tmp_msg
+ echo -n "Author: ";
+ read patch_author
+
+ echo "$patch_author"
+
+ patch_author_name=$(expr "z$patch_author" : 'z\(.*[^ ]\) *<.*') &&
+ patch_author_email=$(expr "z$patch_author" : '.*<\([^>]*\)') &&
+ test '' != "$patch_author_name" &&
+ test '' != "$patch_author_email" &&
+ GIT_AUTHOR_NAME="$patch_author_name" &&
+ GIT_AUTHOR_EMAIL="$patch_author_email"
+ fi
+ done
+ export GIT_AUTHOR_DATE=$(sed -ne 's/Date: //p' "$tmp_info")
+ export SUBJECT=$(sed -ne 's/Subject: //p' "$tmp_info")
+ if [ -z "$SUBJECT" ] ; then
+ SUBJECT=$(echo $patch_name | sed -e 's/.patch$//')
+ fi
+
+ if [ -z "$dry_run" ] ; then
+ git-apply --index -C1 "$tmp_patch" &&
+ tree=$(git-write-tree) &&
+ commit=$((echo "$SUBJECT"; echo; cat "$tmp_msg") | git-commit-tree $tree -p $commit) &&
+ git-update-ref HEAD $commit || exit 4
+ fi
+done
+rm -rf $tmp_dir || exit 5
diff --git a/git-rebase.sh b/git-rebase.sh
index 9e259028e..6ff6088d1 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -12,9 +12,10 @@ It then attempts to create a new commit for each commit from the original
It is possible that a merge failure will prevent this process from being
completely automatic. You will have to resolve any such merge failure
-and run git-rebase --continue. If you can not resolve the merge failure,
-running git-rebase --abort will restore the original <branch> and remove
-the working files found in the .dotest directory.
+and run git rebase --continue. Another option is to bypass the commit
+that caused the merge failure with git rebase --skip. To restore the
+original <branch> and remove the .dotest working files, use the command
+git rebase --abort instead.
Note that if <branch> is not specified on the command line, the
currently checked out branch is used. You must be in the top
@@ -28,6 +29,11 @@ Example: git-rebase master~1 topic
'
. git-sh-setup
+RESOLVEMSG="
+When you have resolved this problem run \"git rebase --continue\".
+If you would prefer to skip this patch, instead run \"git rebase --skip\".
+To restore the original branch and stop rebasing run \"git rebase --abort\".
+"
unset newbase
while case "$#" in 0) break ;; esac
do
@@ -40,7 +46,11 @@ do
exit 1
;;
esac
- git am --resolved --3way
+ git am --resolved --3way --resolvemsg="$RESOLVEMSG"
+ exit
+ ;;
+ --skip)
+ git am -3 --skip --resolvemsg="$RESOLVEMSG"
exit
;;
--abort)
@@ -143,4 +153,5 @@ then
fi
git-format-patch -k --stdout --full-index "$upstream" ORIG_HEAD |
-git am --binary -3 -k
+git am --binary -3 -k --resolvemsg="$RESOLVEMSG"
+
diff --git a/git-request-pull.sh b/git-request-pull.sh
index 2c48bfb29..4319e35c6 100755
--- a/git-request-pull.sh
+++ b/git-request-pull.sh
@@ -30,4 +30,4 @@ echo " $url"
echo
git log $baserev..$headrev | git-shortlog ;
-git diff $baserev..$headrev | git-apply --stat --summary
+git diff --stat --summary $baserev..$headrev
diff --git a/git-reset.sh b/git-reset.sh
index 6cb073cb1..0ee3e3e15 100755
--- a/git-reset.sh
+++ b/git-reset.sh
@@ -6,6 +6,7 @@ USAGE='[--mixed | --soft | --hard] [<commit-ish>]'
tmp=${GIT_DIR}/reset.$$
trap 'rm -f $tmp-*' 0 1 2 3 15
+update=
reset_type=--mixed
case "$1" in
--mixed | --soft | --hard)
@@ -23,24 +24,7 @@ rev=$(git-rev-parse --verify $rev^0) || exit
# behind before a hard reset, so that we can remove them.
if test "$reset_type" = "--hard"
then
- {
- git-ls-files --stage -z
- git-rev-parse --verify HEAD 2>/dev/null &&
- git-ls-tree -r -z HEAD
- } | perl -e '
- use strict;
- my %seen;
- $/ = "\0";
- while (<>) {
- chomp;
- my ($info, $path) = split(/\t/, $_);
- next if ($info =~ / tree /);
- if (!$seen{$path}) {
- $seen{$path} = 1;
- print "$path\0";
- }
- }
- ' >$tmp-exists
+ update=-u
fi
# Soft reset does not touch the index file nor the working tree
@@ -54,7 +38,7 @@ then
die "Cannot do a soft reset in the middle of a merge."
fi
else
- git-read-tree --reset "$rev" || exit
+ git-read-tree --reset $update "$rev" || exit
fi
# Any resets update HEAD to the head being switched to.
@@ -68,33 +52,7 @@ git-update-ref HEAD "$rev"
case "$reset_type" in
--hard )
- # Hard reset matches the working tree to that of the tree
- # being switched to.
- git-checkout-index -f -u -q -a
- git-ls-files --cached -z |
- perl -e '
- use strict;
- my (%keep, $fh);
- $/ = "\0";
- while (<STDIN>) {
- chomp;
- $keep{$_} = 1;
- }
- open $fh, "<", $ARGV[0]
- or die "cannot open $ARGV[0]";
- while (<$fh>) {
- chomp;
- if (! exists $keep{$_}) {
- # it is ok if this fails -- it may already
- # have been culled by checkout-index.
- unlink $_;
- while (s|/[^/]*$||) {
- rmdir($_) or last;
- }
- }
- }
- ' $tmp-exists
- ;;
+ ;; # Nothing else to do
--soft )
;; # Nothing else to do
--mixed )
diff --git a/git-send-email.perl b/git-send-email.perl
index d8c4b1f89..312a4ea2a 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -40,7 +40,8 @@ my $compose_filename = ".msg.$$";
my (@to,@cc,@initial_cc,$initial_reply_to,$initial_subject,@files,$from,$compose,$time);
# Behavior modification variables
-my ($chain_reply_to, $smtp_server, $quiet, $suppress_from, $no_signed_off_cc) = (1, "localhost", 0, 0, 0);
+my ($chain_reply_to, $quiet, $suppress_from, $no_signed_off_cc) = (1, 0, 0, 0);
+my $smtp_server;
# Example reply to:
#$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
@@ -179,8 +180,14 @@ if (!defined $initial_reply_to && $prompting) {
$initial_reply_to =~ s/(^\s+|\s+$)//g;
}
-if (!defined $smtp_server) {
- $smtp_server = "localhost";
+if (!$smtp_server) {
+ foreach (qw( /usr/sbin/sendmail /usr/lib/sendmail )) {
+ if (-x $_) {
+ $smtp_server = $_;
+ last;
+ }
+ }
+ $smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*
}
if ($compose) {
@@ -300,6 +307,10 @@ our ($message_id, $cc, %mail, $subject, $reply_to, $message);
sub extract_valid_address {
my $address = shift;
+
+ # check for a local address:
+ return $address if ($address =~ /^([\w\-]+)$/);
+
if ($have_email_valid) {
return Email::Valid->address($address);
} else {
@@ -358,26 +369,39 @@ X-Mailer: git-send-email $gitversion
";
$header .= "In-Reply-To: $reply_to\n" if $reply_to;
- $smtp ||= Net::SMTP->new( $smtp_server );
- $smtp->mail( $from ) or die $smtp->message;
- $smtp->to( @recipients ) or die $smtp->message;
- $smtp->data or die $smtp->message;
- $smtp->datasend("$header\n$message") or die $smtp->message;
- $smtp->dataend() or die $smtp->message;
- $smtp->ok or die "Failed to send $subject\n".$smtp->message;
-
+ if ($smtp_server =~ m#^/#) {
+ my $pid = open my $sm, '|-';
+ defined $pid or die $!;
+ if (!$pid) {
+ exec($smtp_server,'-i',@recipients) or die $!;
+ }
+ print $sm "$header\n$message";
+ close $sm or die $?;
+ } else {
+ $smtp ||= Net::SMTP->new( $smtp_server );
+ $smtp->mail( $from ) or die $smtp->message;
+ $smtp->to( @recipients ) or die $smtp->message;
+ $smtp->data or die $smtp->message;
+ $smtp->datasend("$header\n$message") or die $smtp->message;
+ $smtp->dataend() or die $smtp->message;
+ $smtp->ok or die "Failed to send $subject\n".$smtp->message;
+ }
if ($quiet) {
printf "Sent %s\n", $subject;
} else {
- print "OK. Log says:
-Date: $date
-Server: $smtp_server Port: 25
-From: $from
-Subject: $subject
-Cc: $cc
-To: $to
-
-Result: ", $smtp->code, ' ', ($smtp->message =~ /\n([^\n]+\n)$/s), "\n";
+ print "OK. Log says:\nDate: $date\n";
+ if ($smtp) {
+ print "Server: $smtp_server\n";
+ } else {
+ print "Sendmail: $smtp_server\n";
+ }
+ print "From: $from\nSubject: $subject\nCc: $cc\nTo: $to\n\n";
+ if ($smtp) {
+ print "Result: ", $smtp->code, ' ',
+ ($smtp->message =~ /\n([^\n]+\n)$/s), "\n";
+ } else {
+ print "Result: OK\n";
+ }
}
}
@@ -478,9 +502,14 @@ sub unique_email_list(@) {
my @emails;
foreach my $entry (@_) {
- my $clean = extract_valid_address($entry);
- next if $seen{$clean}++;
- push @emails, $entry;
+ if (my $clean = extract_valid_address($entry)) {
+ $seen{$clean} ||= 0;
+ next if $seen{$clean}++;
+ push @emails, $entry;
+ } else {
+ print STDERR "W: unable to extract a valid address",
+ " from: $entry\n";
+ }
}
return @emails;
}
diff --git a/git-tag.sh b/git-tag.sh
index dc6aa9576..a0afa2582 100755
--- a/git-tag.sh
+++ b/git-tag.sh
@@ -25,14 +25,12 @@ do
force=1
;;
-l)
- cd "$GIT_DIR/refs" &&
case "$#" in
1)
- find tags -type f -print ;;
- *)
- shift
- find tags -type f -print | grep "$@" ;;
+ set x . ;;
esac
+ shift
+ git rev-parse --symbolic --tags | sort | grep "$@"
exit $?
;;
-m)
diff --git a/git.c b/git.c
index 49ba5189d..3216d311b 100644
--- a/git.c
+++ b/git.c
@@ -49,6 +49,10 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
{ "push", cmd_push },
{ "count-objects", cmd_count_objects },
{ "diff", cmd_diff },
+ { "grep", cmd_grep },
+ { "rev-list", cmd_rev_list },
+ { "init-db", cmd_init_db },
+ { "check-ref-format", cmd_check_ref_format }
};
int i;
diff --git a/merge-base.c b/merge-base.c
index f0dc06ef5..4856ca01c 100644
--- a/merge-base.c
+++ b/merge-base.c
@@ -82,8 +82,9 @@ static struct commit *interesting(struct commit_list *list)
* commit B.
*
*
- * Another pathological example how this thing can fail to mark an ancestor
- * of a merge base as UNINTERESTING without the postprocessing phase.
+ * Another pathological example how this thing used to fail to mark an
+ * ancestor of a merge base as UNINTERESTING before we introduced the
+ * postprocessing phase (mark_reachable_commits).
*
* 2
* H
@@ -118,7 +119,9 @@ static struct commit *interesting(struct commit_list *list)
* D7 2 3 7 7 3 2 1 2
* E7 2 3 7 7 7 2 1 2
*
- * and we end up showing E as an interesting merge base.
+ * and we ended up showing E as an interesting merge base.
+ * The postprocessing phase re-injects C and continues traversal
+ * to contaminate D and E.
*/
static int show_all = 0;
diff --git a/pack-objects.c b/pack-objects.c
index 5466b1516..77284cfdb 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -10,7 +10,6 @@
#include "tree-walk.h"
#include <sys/time.h>
#include <signal.h>
-#include <stdint.h>
static const char pack_usage[] = "git-pack-objects [-q] [--no-reuse-delta] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list";
@@ -157,7 +156,7 @@ static void prepare_pack_revindex(struct pack_revindex *rix)
rix->revindex = xmalloc(sizeof(unsigned long) * (num_ent + 1));
for (i = 0; i < num_ent; i++) {
- uint32_t hl = *((uint32_t *)(index + 24 * i));
+ unsigned int hl = *((unsigned int *)(index + 24 * i));
rix->revindex[i] = ntohl(hl);
}
/* This knows the pack format -- the 20-byte trailer
@@ -1037,10 +1036,13 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
if (src_entry->depth >= max_depth)
return 0;
- /* Now some size filtering euristics. */
+ /* Now some size filtering heuristics. */
size = trg_entry->size;
- max_size = size / 2 - 20;
- if (trg_entry->delta)
+ max_size = size/2 - 20;
+ max_size = max_size * (max_depth - src_entry->depth) / max_depth;
+ if (max_size == 0)
+ return 0;
+ if (trg_entry->delta && trg_entry->delta_size <= max_size)
max_size = trg_entry->delta_size-1;
src_size = src_entry->size;
sizediff = src_size < size ? size - src_size : 0;
@@ -1105,17 +1107,14 @@ static void find_deltas(struct object_entry **list, int window, int depth)
if (entry->size < 50)
continue;
- if (n->index)
- free_delta_index(n->index);
+ free_delta_index(n->index);
+ n->index = NULL;
free(n->data);
n->entry = entry;
n->data = read_sha1_file(entry->sha1, type, &size);
if (size != entry->size)
die("object %s inconsistent object length (%lu vs %lu)",
sha1_to_hex(entry->sha1), size, entry->size);
- n->index = create_delta_index(n->data, size);
- if (!n->index)
- die("out of memory");
j = window;
while (--j > 0) {
@@ -1129,15 +1128,17 @@ static void find_deltas(struct object_entry **list, int window, int depth)
if (try_delta(n, m, m->index, depth) < 0)
break;
}
-#if 0
/* if we made n a delta, and if n is already at max
* depth, leaving it in the window is pointless. we
* should evict it first.
- * ... in theory only; somehow this makes things worse.
*/
if (entry->delta && depth <= entry->depth)
continue;
-#endif
+
+ n->index = create_delta_index(n->data, size);
+ if (!n->index)
+ die("out of memory");
+
idx++;
if (idx >= window)
idx = 0;
@@ -1147,8 +1148,7 @@ static void find_deltas(struct object_entry **list, int window, int depth)
fputc('\n', stderr);
for (i = 0; i < window; ++i) {
- if (array[i].index)
- free_delta_index(array[i].index);
+ free_delta_index(array[i].index);
free(array[i].data);
}
free(array);
diff --git a/read-cache.c b/read-cache.c
index a917ab0cf..b95edcc14 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -496,6 +496,123 @@ int add_cache_entry(struct cache_entry *ce, int option)
return 0;
}
+/* Three functions to allow overloaded pointer return; see linux/err.h */
+static inline void *ERR_PTR(long error)
+{
+ return (void *) error;
+}
+
+static inline long PTR_ERR(const void *ptr)
+{
+ return (long) ptr;
+}
+
+static inline long IS_ERR(const void *ptr)
+{
+ return (unsigned long)ptr > (unsigned long)-1000L;
+}
+
+/*
+ * "refresh" does not calculate a new sha1 file or bring the
+ * cache up-to-date for mode/content changes. But what it
+ * _does_ do is to "re-match" the stat information of a file
+ * with the cache, so that you can refresh the cache for a
+ * file that hasn't been changed but where the stat entry is
+ * out of date.
+ *
+ * For example, you'd want to do this after doing a "git-read-tree",
+ * to link up the stat cache details with the proper files.
+ */
+static struct cache_entry *refresh_entry(struct cache_entry *ce, int really)
+{
+ struct stat st;
+ struct cache_entry *updated;
+ int changed, size;
+
+ if (lstat(ce->name, &st) < 0)
+ return ERR_PTR(-errno);
+
+ changed = ce_match_stat(ce, &st, really);
+ if (!changed) {
+ if (really && assume_unchanged &&
+ !(ce->ce_flags & htons(CE_VALID)))
+ ; /* mark this one VALID again */
+ else
+ return NULL;
+ }
+
+ if (ce_modified(ce, &st, really))
+ return ERR_PTR(-EINVAL);
+
+ size = ce_size(ce);
+ updated = xmalloc(size);
+ memcpy(updated, ce, size);
+ fill_stat_cache_info(updated, &st);
+
+ /* In this case, if really is not set, we should leave
+ * CE_VALID bit alone. Otherwise, paths marked with
+ * --no-assume-unchanged (i.e. things to be edited) will
+ * reacquire CE_VALID bit automatically, which is not
+ * really what we want.
+ */
+ if (!really && assume_unchanged && !(ce->ce_flags & htons(CE_VALID)))
+ updated->ce_flags &= ~htons(CE_VALID);
+
+ return updated;
+}
+
+int refresh_cache(unsigned int flags)
+{
+ int i;
+ int has_errors = 0;
+ int really = (flags & REFRESH_REALLY) != 0;
+ int allow_unmerged = (flags & REFRESH_UNMERGED) != 0;
+ int quiet = (flags & REFRESH_QUIET) != 0;
+ int not_new = (flags & REFRESH_IGNORE_MISSING) != 0;
+
+ for (i = 0; i < active_nr; i++) {
+ struct cache_entry *ce, *new;
+ ce = active_cache[i];
+ if (ce_stage(ce)) {
+ while ((i < active_nr) &&
+ ! strcmp(active_cache[i]->name, ce->name))
+ i++;
+ i--;
+ if (allow_unmerged)
+ continue;
+ printf("%s: needs merge\n", ce->name);
+ has_errors = 1;
+ continue;
+ }
+
+ new = refresh_entry(ce, really);
+ if (!new)
+ continue;
+ if (IS_ERR(new)) {
+ if (not_new && PTR_ERR(new) == -ENOENT)
+ continue;
+ if (really && PTR_ERR(new) == -EINVAL) {
+ /* If we are doing --really-refresh that
+ * means the index is not valid anymore.
+ */
+ ce->ce_flags &= ~htons(CE_VALID);
+ active_cache_changed = 1;
+ }
+ if (quiet)
+ continue;
+ printf("%s: needs update\n", ce->name);
+ has_errors = 1;
+ continue;
+ }
+ active_cache_changed = 1;
+ /* You can NOT just free active_cache[i] here, since it
+ * might not be necessarily malloc()ed but can also come
+ * from mmap(). */
+ active_cache[i] = new;
+ }
+ return has_errors;
+}
+
static int verify_hdr(struct cache_header *hdr, unsigned long size)
{
SHA_CTX c;
diff --git a/read-tree.c b/read-tree.c
index e926e4c88..e16e91b17 100644
--- a/read-tree.c
+++ b/read-tree.c
@@ -12,6 +12,7 @@
#include <sys/time.h>
#include <signal.h>
+static int reset = 0;
static int merge = 0;
static int update = 0;
static int index_only = 0;
@@ -416,6 +417,10 @@ static void verify_uptodate(struct cache_entry *ce)
return;
errno = 0;
}
+ if (reset) {
+ ce->ce_flags |= htons(CE_UPDATE);
+ return;
+ }
if (errno == ENOENT)
return;
die("Entry '%s' not uptodate. Cannot merge.", ce->name);
@@ -684,8 +689,14 @@ static int oneway_merge(struct cache_entry **src)
merge_size);
if (!a)
- return 0;
+ return deleted_entry(old, NULL);
if (old && same(old, a)) {
+ if (reset) {
+ struct stat st;
+ if (lstat(old->name, &st) ||
+ ce_match_stat(old, &st, 1))
+ old->ce_flags |= htons(CE_UPDATE);
+ }
return keep_entry(old);
}
return merged_entry(a, NULL);
@@ -719,7 +730,7 @@ static struct cache_file cache_file;
int main(int argc, char **argv)
{
- int i, newfd, reset, stage = 0;
+ int i, newfd, stage = 0;
unsigned char sha1[20];
merge_fn_t fn = NULL;
diff --git a/refs.c b/refs.c
index 275b914b2..0f3491f87 100644
--- a/refs.c
+++ b/refs.c
@@ -114,7 +114,7 @@ int read_ref(const char *filename, unsigned char *sha1)
return -1;
}
-static int do_for_each_ref(const char *base, int (*fn)(const char *path, const unsigned char *sha1))
+static int do_for_each_ref(const char *base, int (*fn)(const char *path, const unsigned char *sha1), int trim)
{
int retval = 0;
DIR *dir = opendir(git_path("%s", base));
@@ -146,7 +146,7 @@ static int do_for_each_ref(const char *base, int (*fn)(const char *path, const u
if (stat(git_path("%s", path), &st) < 0)
continue;
if (S_ISDIR(st.st_mode)) {
- retval = do_for_each_ref(path, fn);
+ retval = do_for_each_ref(path, fn, trim);
if (retval)
break;
continue;
@@ -160,7 +160,7 @@ static int do_for_each_ref(const char *base, int (*fn)(const char *path, const u
"commit object!", path);
continue;
}
- retval = fn(path, sha1);
+ retval = fn(path + trim, sha1);
if (retval)
break;
}
@@ -180,7 +180,22 @@ int head_ref(int (*fn)(const char *path, const unsigned char *sha1))
int for_each_ref(int (*fn)(const char *path, const unsigned char *sha1))
{
- return do_for_each_ref("refs", fn);
+ return do_for_each_ref("refs", fn, 0);
+}
+
+int for_each_tag_ref(int (*fn)(const char *path, const unsigned char *sha1))
+{
+ return do_for_each_ref("refs/tags", fn, 10);
+}
+
+int for_each_branch_ref(int (*fn)(const char *path, const unsigned char *sha1))
+{
+ return do_for_each_ref("refs/heads", fn, 11);
+}
+
+int for_each_remote_ref(int (*fn)(const char *path, const unsigned char *sha1))
+{
+ return do_for_each_ref("refs/remotes", fn, 13);
}
static char *ref_file_name(const char *ref)
@@ -205,12 +220,9 @@ static char *ref_lock_file_name(const char *ref)
int get_ref_sha1(const char *ref, unsigned char *sha1)
{
- const char *filename;
-
if (check_ref_format(ref))
return -1;
- filename = git_path("refs/%s", ref);
- return read_ref(filename, sha1);
+ return read_ref(git_path("refs/%s", ref), sha1);
}
static int lock_ref_file(const char *filename, const char *lock_filename,
diff --git a/refs.h b/refs.h
index 262559670..fa816c1e9 100644
--- a/refs.h
+++ b/refs.h
@@ -7,6 +7,9 @@
*/
extern int head_ref(int (*fn)(const char *path, const unsigned char *sha1));
extern int for_each_ref(int (*fn)(const char *path, const unsigned char *sha1));
+extern int for_each_tag_ref(int (*fn)(const char *path, const unsigned char *sha1));
+extern int for_each_branch_ref(int (*fn)(const char *path, const unsigned char *sha1));
+extern int for_each_remote_ref(int (*fn)(const char *path, const unsigned char *sha1));
/** Reads the refs file specified into sha1 **/
extern int get_ref_sha1(const char *ref, unsigned char *sha1);
diff --git a/repo-config.c b/repo-config.c
index 63eda1bb7..127afd784 100644
--- a/repo-config.c
+++ b/repo-config.c
@@ -64,12 +64,13 @@ static int show_config(const char* key_, const char* value_)
static int get_value(const char* key_, const char* regex_)
{
- int i;
+ char *tl;
- key = malloc(strlen(key_)+1);
- for (i = 0; key_[i]; i++)
- key[i] = tolower(key_[i]);
- key[i] = 0;
+ key = strdup(key_);
+ for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl)
+ *tl = tolower(*tl);
+ for (tl=key; *tl && *tl != '.'; ++tl)
+ *tl = tolower(*tl);
if (use_key_regexp) {
key_regexp = (regex_t*)malloc(sizeof(regex_t));
diff --git a/rev-parse.c b/rev-parse.c
index 62e16af33..4e2d9fbdf 100644
--- a/rev-parse.c
+++ b/rev-parse.c
@@ -36,6 +36,7 @@ static int is_rev_argument(const char *arg)
"--all",
"--bisect",
"--dense",
+ "--branches",
"--header",
"--max-age=",
"--max-count=",
@@ -45,7 +46,9 @@ static int is_rev_argument(const char *arg)
"--objects-edge",
"--parents",
"--pretty",
+ "--remotes",
"--sparse",
+ "--tags",
"--topo-order",
"--date-order",
"--unpacked",
@@ -165,7 +168,7 @@ int main(int argc, char **argv)
int i, as_is = 0, verify = 0;
unsigned char sha1[20];
const char *prefix = setup_git_directory();
-
+
git_config(git_default_config);
for (i = 1; i < argc; i++) {
@@ -255,6 +258,18 @@ int main(int argc, char **argv)
for_each_ref(show_reference);
continue;
}
+ if (!strcmp(arg, "--branches")) {
+ for_each_branch_ref(show_reference);
+ continue;
+ }
+ if (!strcmp(arg, "--tags")) {
+ for_each_tag_ref(show_reference);
+ continue;
+ }
+ if (!strcmp(arg, "--remotes")) {
+ for_each_remote_ref(show_reference);
+ continue;
+ }
if (!strcmp(arg, "--show-prefix")) {
if (prefix)
puts(prefix);
diff --git a/sha1_file.c b/sha1_file.c
index 3372ebcdc..223001033 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -13,7 +13,6 @@
#include "commit.h"
#include "tag.h"
#include "tree.h"
-#include <stdint.h>
#ifndef O_NOATIME
#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
@@ -1162,7 +1161,7 @@ int find_pack_entry_one(const unsigned char *sha1,
int mi = (lo + hi) / 2;
int cmp = memcmp(index + 24 * mi + 4, sha1, 20);
if (!cmp) {
- e->offset = ntohl(*((uint32_t *)(index + 24 * mi)));
+ e->offset = ntohl(*((unsigned int *)(index + 24 * mi)));
memcpy(e->sha1, sha1, 20);
e->p = p;
return 1;
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 7090ea92c..8260d57b6 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -229,7 +229,7 @@ test_expect_failure 'invalid key' 'git-repo-config inval.2key blabla'
test_expect_success 'correct key' 'git-repo-config 123456.a123 987'
test_expect_success 'hierarchical section' \
- 'git-repo-config 1.2.3.alpha beta'
+ 'git-repo-config Version.1.2.3eX.Alpha beta'
cat > expect << EOF
[beta] ; silly comment # another comment
@@ -241,8 +241,8 @@ noIndent= sillyValue ; 'nother silly comment
NoNewLine = wow2 for me
[123456]
a123 = 987
-[1.2.3]
- alpha = beta
+[Version "1.2.3eX"]
+ Alpha = beta
EOF
test_expect_success 'hierarchical section value' 'cmp .git/config expect'
@@ -251,7 +251,7 @@ cat > expect << EOF
beta.noindent=sillyValue
nextsection.nonewline=wow2 for me
123456.a123=987
-1.2.3.alpha=beta
+version.1.2.3eX.alpha=beta
EOF
test_expect_success 'working --list' \
diff --git a/update-index.c b/update-index.c
index 3d7e02db2..7d6de821e 100644
--- a/update-index.c
+++ b/update-index.c
@@ -18,9 +18,6 @@
static int allow_add;
static int allow_remove;
static int allow_replace;
-static int allow_unmerged; /* --refresh needing merge is not error */
-static int not_new; /* --refresh not having working tree files is not error */
-static int quiet; /* --refresh needing update is not error */
static int info_only;
static int force_remove;
static int verbose;
@@ -28,23 +25,6 @@ static int mark_valid_only = 0;
#define MARK_VALID 1
#define UNMARK_VALID 2
-
-/* Three functions to allow overloaded pointer return; see linux/err.h */
-static inline void *ERR_PTR(long error)
-{
- return (void *) error;
-}
-
-static inline long PTR_ERR(const void *ptr)
-{
- return (long) ptr;
-}
-
-static inline long IS_ERR(const void *ptr)
-{
- return (unsigned long)ptr > (unsigned long)-1000L;
-}
-
static void report(const char *fmt, ...)
{
va_list vp;
@@ -141,103 +121,6 @@ static int add_file_to_cache(const char *path)
}
/*
- * "refresh" does not calculate a new sha1 file or bring the
- * cache up-to-date for mode/content changes. But what it
- * _does_ do is to "re-match" the stat information of a file
- * with the cache, so that you can refresh the cache for a
- * file that hasn't been changed but where the stat entry is
- * out of date.
- *
- * For example, you'd want to do this after doing a "git-read-tree",
- * to link up the stat cache details with the proper files.
- */
-static struct cache_entry *refresh_entry(struct cache_entry *ce, int really)
-{
- struct stat st;
- struct cache_entry *updated;
- int changed, size;
-
- if (lstat(ce->name, &st) < 0)
- return ERR_PTR(-errno);
-
- changed = ce_match_stat(ce, &st, really);
- if (!changed) {
- if (really && assume_unchanged &&
- !(ce->ce_flags & htons(CE_VALID)))
- ; /* mark this one VALID again */
- else
- return NULL;
- }
-
- if (ce_modified(ce, &st, really))
- return ERR_PTR(-EINVAL);
-
- size = ce_size(ce);
- updated = xmalloc(size);
- memcpy(updated, ce, size);
- fill_stat_cache_info(updated, &st);
-
- /* In this case, if really is not set, we should leave
- * CE_VALID bit alone. Otherwise, paths marked with
- * --no-assume-unchanged (i.e. things to be edited) will
- * reacquire CE_VALID bit automatically, which is not
- * really what we want.
- */
- if (!really && assume_unchanged && !(ce->ce_flags & htons(CE_VALID)))
- updated->ce_flags &= ~htons(CE_VALID);
-
- return updated;
-}
-
-static int refresh_cache(int really)
-{
- int i;
- int has_errors = 0;
-
- for (i = 0; i < active_nr; i++) {
- struct cache_entry *ce, *new;
- ce = active_cache[i];
- if (ce_stage(ce)) {
- while ((i < active_nr) &&
- ! strcmp(active_cache[i]->name, ce->name))
- i++;
- i--;
- if (allow_unmerged)
- continue;
- printf("%s: needs merge\n", ce->name);
- has_errors = 1;
- continue;
- }
-
- new = refresh_entry(ce, really);
- if (!new)
- continue;
- if (IS_ERR(new)) {
- if (not_new && PTR_ERR(new) == -ENOENT)
- continue;
- if (really && PTR_ERR(new) == -EINVAL) {
- /* If we are doing --really-refresh that
- * means the index is not valid anymore.
- */
- ce->ce_flags &= ~htons(CE_VALID);
- active_cache_changed = 1;
- }
- if (quiet)
- continue;
- printf("%s: needs update\n", ce->name);
- has_errors = 1;
- continue;
- }
- active_cache_changed = 1;
- /* You can NOT just free active_cache[i] here, since it
- * might not be necessarily malloc()ed but can also come
- * from mmap(). */
- active_cache[i] = new;
- }
- return has_errors;
-}
-
-/*
* We fundamentally don't like some paths: we don't want
* dot or dot-dot anywhere, and for obvious reasons don't
* want to recurse into ".git" either.
@@ -653,6 +536,7 @@ int main(int argc, const char **argv)
const char *prefix = setup_git_directory();
int prefix_length = prefix ? strlen(prefix) : 0;
char set_executable_bit = 0;
+ unsigned int refresh_flags = 0;
git_config(git_default_config);
@@ -673,7 +557,7 @@ int main(int argc, const char **argv)
continue;
}
if (!strcmp(path, "-q")) {
- quiet = 1;
+ refresh_flags |= REFRESH_QUIET;
continue;
}
if (!strcmp(path, "--add")) {
@@ -689,15 +573,15 @@ int main(int argc, const char **argv)
continue;
}
if (!strcmp(path, "--unmerged")) {
- allow_unmerged = 1;
+ refresh_flags |= REFRESH_UNMERGED;
continue;
}
if (!strcmp(path, "--refresh")) {
- has_errors |= refresh_cache(0);
+ has_errors |= refresh_cache(refresh_flags);
continue;
}
if (!strcmp(path, "--really-refresh")) {
- has_errors |= refresh_cache(1);
+ has_errors |= refresh_cache(REFRESH_REALLY | refresh_flags);
continue;
}
if (!strcmp(path, "--cacheinfo")) {
@@ -770,7 +654,7 @@ int main(int argc, const char **argv)
goto finish;
}
if (!strcmp(path, "--ignore-missing")) {
- not_new = 1;
+ refresh_flags |= REFRESH_IGNORE_MISSING;
continue;
}
if (!strcmp(path, "--verbose")) {