aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-repo-config.txt12
-rw-r--r--Makefile40
-rw-r--r--blame.c4
-rw-r--r--builtin-mailinfo.c (renamed from mailinfo.c)85
-rw-r--r--builtin-mailsplit.c (renamed from mailsplit.c)71
-rw-r--r--builtin-read-tree.c3
-rw-r--r--builtin-stripspace.c (renamed from stripspace.c)16
-rw-r--r--builtin-update-index.c (renamed from update-index.c)19
-rw-r--r--builtin-update-ref.c (renamed from update-ref.c)5
-rw-r--r--builtin-write-tree.c (renamed from write-tree.c)68
-rw-r--r--builtin.h15
-rw-r--r--config.c43
-rw-r--r--diff-delta.c3
-rw-r--r--diff-lib.c41
-rw-r--r--diff.c79
-rw-r--r--diff.h3
-rw-r--r--git.c8
-rw-r--r--http-fetch.c13
-rw-r--r--http-push.c13
-rw-r--r--imap-send.c2
-rw-r--r--pager.c2
-rw-r--r--quote.c9
-rw-r--r--repo-config.c39
-rw-r--r--t/Makefile2
-rwxr-xr-xt/t1300-repo-config.sh24
25 files changed, 432 insertions, 187 deletions
diff --git a/Documentation/git-repo-config.txt b/Documentation/git-repo-config.txt
index d5142e0dc..803c0d5ca 100644
--- a/Documentation/git-repo-config.txt
+++ b/Documentation/git-repo-config.txt
@@ -73,6 +73,18 @@ OPTIONS
List all variables set in .git/config.
+ENVIRONMENT
+-----------
+
+GIT_CONFIG::
+ Take the configuration from the given file instead of .git/config.
+
+GIT_CONFIG_LOCAL::
+ Currently the same as $GIT_CONFIG; when Git will support global
+ configuration files, this will cause it to take the configuration
+ from the global configuration file in addition to the given file.
+
+
EXAMPLE
-------
diff --git a/Makefile b/Makefile
index ea8cd283e..99c9ec205 100644
--- a/Makefile
+++ b/Makefile
@@ -144,34 +144,33 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
# The ones that do not have to link with lcrypto, lz nor xdiff.
SIMPLE_PROGRAMS = \
- git-mailsplit$X \
- git-stripspace$X git-daemon$X
+ git-daemon$X
# ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS = \
git-checkout-index$X git-clone-pack$X \
git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \
git-hash-object$X git-index-pack$X git-local-fetch$X \
- git-mailinfo$X git-merge-base$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-receive-pack$X \
git-send-pack$X git-shell$X \
git-show-index$X git-ssh-fetch$X \
git-ssh-upload$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-unpack-objects$X git-update-server-info$X \
+ git-upload-pack$X git-verify-pack$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-grep$X git-add$X git-rm$X git-rev-list$X \
- git-check-ref-format$X git-rev-parse$X \
+BUILT_INS = git-log$X git-whatchanged$X git-show$X git-update-ref$X \
+ git-count-objects$X git-diff$X git-push$X git-mailsplit$X \
+ git-grep$X git-add$X git-rm$X git-rev-list$X git-stripspace$X \
+ git-check-ref-format$X git-rev-parse$X git-mailinfo$X \
git-init-db$X git-tar-tree$X git-upload-tar$X git-format-patch$X \
git-ls-files$X git-ls-tree$X git-get-tar-commit-id$X \
- git-read-tree$X git-commit-tree$X \
- git-apply$X git-show-branch$X git-diff-files$X \
+ git-read-tree$X git-commit-tree$X git-write-tree$X \
+ git-apply$X git-show-branch$X git-diff-files$X git-update-index$X \
git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X
# what 'all' will build and 'install' will install, in gitexecdir
@@ -222,12 +221,13 @@ BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-add.o builtin-rev-list.o builtin-check-ref-format.o \
builtin-rm.o builtin-init-db.o builtin-rev-parse.o \
- builtin-tar-tree.o builtin-upload-tar.o \
- builtin-ls-files.o builtin-ls-tree.o \
- builtin-read-tree.o builtin-commit-tree.o \
+ builtin-tar-tree.o builtin-upload-tar.o builtin-update-index.o \
+ builtin-ls-files.o builtin-ls-tree.o builtin-write-tree.o \
+ builtin-read-tree.o builtin-commit-tree.o builtin-mailinfo.o \
builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
- builtin-cat-file.o
+ builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \
+ builtin-update-ref.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
@@ -380,9 +380,7 @@ ifdef NEEDS_LIBICONV
else
ICONV_LINK =
endif
- LIB_4_ICONV = $(ICONV_LINK) -liconv
-else
- LIB_4_ICONV =
+ LIBS += $(ICONV_LINK) -liconv
endif
ifdef NEEDS_SOCKET
LIBS += -lsocket
@@ -565,10 +563,6 @@ $(SIMPLE_PROGRAMS) : git-%$X : %.o
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIB_FILE) $(SIMPLE_LIB)
-git-mailinfo$X: mailinfo.o $(LIB_FILE)
- $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
- $(LIB_FILE) $(SIMPLE_LIB) $(LIB_4_ICONV)
-
git-local-fetch$X: fetch.o
git-ssh-fetch$X: rsh.o fetch.o
git-ssh-upload$X: rsh.o
diff --git a/blame.c b/blame.c
index 7c0b62cf3..c86e2fd4b 100644
--- a/blame.c
+++ b/blame.c
@@ -301,9 +301,9 @@ static void fill_line_map(struct commit *commit, struct commit *other,
if (DEBUG)
printf("map: i1: %d %d %p i2: %d %d %p\n",
i1, map[i1],
- i1 != -1 ? blame_lines[map[i1]] : NULL,
+ (void *) (i1 != -1 ? blame_lines[map[i1]] : NULL),
i2, map2[i2],
- i2 != -1 ? blame_lines[map2[i2]] : NULL);
+ (void *) (i2 != -1 ? blame_lines[map2[i2]] : NULL));
if (map2[i2] != -1 &&
blame_lines[map[i1]] &&
!blame_lines[map2[i2]])
diff --git a/mailinfo.c b/builtin-mailinfo.c
index d9b74f30d..821642a7a 100644
--- a/mailinfo.c
+++ b/builtin-mailinfo.c
@@ -12,11 +12,12 @@
#endif
#include "git-compat-util.h"
#include "cache.h"
+#include "builtin.h"
-static FILE *cmitmsg, *patchfile;
+static FILE *cmitmsg, *patchfile, *fin, *fout;
static int keep_subject = 0;
-static char *metainfo_charset = NULL;
+static const char *metainfo_charset = NULL;
static char line[1000];
static char date[1000];
static char name[1000];
@@ -49,7 +50,7 @@ static int bogus_from(char *line)
/* This is fallback, so do not bother if we already have an
* e-mail address.
- */
+ */
if (*email)
return 0;
@@ -322,13 +323,13 @@ static char *cleanup_subject(char *subject)
if (remove <= len *2) {
subject = p+1;
continue;
- }
+ }
break;
}
eatspace(subject);
return subject;
}
-}
+}
static void cleanup_space(char *buf)
{
@@ -648,7 +649,7 @@ static void handle_info(void)
cleanup_space(email);
cleanup_space(sub);
- printf("Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n",
+ fprintf(fout, "Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n",
name, email, sub, date);
}
@@ -685,7 +686,7 @@ static int handle_commit_msg(int *seen)
continue;
fputs(line, cmitmsg);
- } while (fgets(line, sizeof(line), stdin) != NULL);
+ } while (fgets(line, sizeof(line), fin) != NULL);
fclose(cmitmsg);
cmitmsg = NULL;
return 0;
@@ -706,7 +707,7 @@ static void handle_patch(void)
decode_transfer_encoding(line);
fputs(line, patchfile);
patch_lines++;
- } while (fgets(line, sizeof(line), stdin) != NULL);
+ } while (fgets(line, sizeof(line), fin) != NULL);
}
/* multipart boundary and transfer encoding are set up for us, and we
@@ -719,7 +720,7 @@ static int handle_multipart_one_part(int *seen)
{
int n = 0;
- while (fgets(line, sizeof(line), stdin) != NULL) {
+ while (fgets(line, sizeof(line), fin) != NULL) {
again:
n++;
if (is_multipart_boundary(line))
@@ -740,7 +741,7 @@ static void handle_multipart_body(void)
int part_num = 0;
/* Skip up to the first boundary */
- while (fgets(line, sizeof(line), stdin) != NULL)
+ while (fgets(line, sizeof(line), fin) != NULL)
if (is_multipart_boundary(line)) {
part_num = 1;
break;
@@ -749,7 +750,7 @@ static void handle_multipart_body(void)
return;
/* We are on boundary line. Start slurping the subhead. */
while (1) {
- int hdr = read_one_header_line(line, sizeof(line), stdin);
+ int hdr = read_one_header_line(line, sizeof(line), fin);
if (!hdr) {
if (handle_multipart_one_part(&seen) < 0)
return;
@@ -781,10 +782,45 @@ static void handle_body(void)
}
}
+int mailinfo(FILE *in, FILE *out, int ks, const char *encoding,
+ const char *msg, const char *patch)
+{
+ keep_subject = ks;
+ metainfo_charset = encoding;
+ fin = in;
+ fout = out;
+
+ cmitmsg = fopen(msg, "w");
+ if (!cmitmsg) {
+ perror(msg);
+ return -1;
+ }
+ patchfile = fopen(patch, "w");
+ if (!patchfile) {
+ perror(patch);
+ fclose(cmitmsg);
+ return -1;
+ }
+ while (1) {
+ int hdr = read_one_header_line(line, sizeof(line), fin);
+ if (!hdr) {
+ if (multipart_boundary[0])
+ handle_multipart_body();
+ else
+ handle_body();
+ handle_info();
+ break;
+ }
+ check_header_line(line);
+ }
+
+ return 0;
+}
+
static const char mailinfo_usage[] =
"git-mailinfo [-k] [-u | --encoding=<encoding>] msg patch <mail >info";
-int main(int argc, char **argv)
+int cmd_mailinfo(int argc, const char **argv, char **envp)
{
/* NEEDSWORK: might want to do the optional .git/ directory
* discovery
@@ -805,27 +841,6 @@ int main(int argc, char **argv)
if (argc != 3)
usage(mailinfo_usage);
- cmitmsg = fopen(argv[1], "w");
- if (!cmitmsg) {
- perror(argv[1]);
- exit(1);
- }
- patchfile = fopen(argv[2], "w");
- if (!patchfile) {
- perror(argv[2]);
- exit(1);
- }
- while (1) {
- int hdr = read_one_header_line(line, sizeof(line), stdin);
- if (!hdr) {
- if (multipart_boundary[0])
- handle_multipart_body();
- else
- handle_body();
- handle_info();
- break;
- }
- check_header_line(line);
- }
- return 0;
+
+ return !!mailinfo(stdin, stdout, keep_subject, metainfo_charset, argv[1], argv[2]);
}
diff --git a/mailsplit.c b/builtin-mailsplit.c
index 70a569c12..e2a005843 100644
--- a/mailsplit.c
+++ b/builtin-mailsplit.c
@@ -12,6 +12,7 @@
#include <string.h>
#include <stdio.h>
#include "cache.h"
+#include "builtin.h"
static const char git_mailsplit_usage[] =
"git-mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> <mbox>...";
@@ -102,14 +103,48 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)
exit(1);
}
-int main(int argc, const char **argv)
+int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip)
{
- int nr = 0, nr_prec = 4;
+ char *name = xmalloc(strlen(dir) + 2 + 3 * sizeof(skip));
+ int ret = -1;
+
+ while (*mbox) {
+ const char *file = *mbox++;
+ FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
+ int file_done = 0;
+
+ if ( !f ) {
+ error("cannot open mbox %s", file);
+ goto out;
+ }
+
+ if (fgets(buf, sizeof(buf), f) == NULL) {
+ if (f == stdin)
+ break; /* empty stdin is OK */
+ error("cannot read mbox %s", file);
+ goto out;
+ }
+
+ while (!file_done) {
+ sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+ file_done = split_one(f, name, allow_bare);
+ }
+
+ if (f != stdin)
+ fclose(f);
+ }
+ ret = skip;
+out:
+ free(name);
+ return ret;
+}
+int cmd_mailsplit(int argc, const char **argv, char **envp)
+{
+ int nr = 0, nr_prec = 4, ret;
int allow_bare = 0;
const char *dir = NULL;
const char **argp;
static const char *stdin_only[] = { "-", NULL };
- char *name;
for (argp = argv+1; *argp; argp++) {
const char *arg = *argp;
@@ -158,31 +193,9 @@ int main(int argc, const char **argv)
argp = stdin_only;
}
- name = xmalloc(strlen(dir) + 2 + 3 * sizeof(nr));
-
- while (*argp) {
- const char *file = *argp++;
- FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
- int file_done = 0;
-
- if ( !f )
- die ("cannot open mbox %s", file);
-
- if (fgets(buf, sizeof(buf), f) == NULL) {
- if (f == stdin)
- break; /* empty stdin is OK */
- die("cannot read mbox %s", file);
- }
-
- while (!file_done) {
- sprintf(name, "%s/%0*d", dir, nr_prec, ++nr);
- file_done = split_one(f, name, allow_bare);
- }
-
- if (f != stdin)
- fclose(f);
- }
+ ret = split_mbox(argp, dir, allow_bare, nr_prec, nr);
+ if (ret != -1)
+ printf("%d\n", ret);
- printf("%d\n", nr);
- return 0;
+ return ret == -1;
}
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index 04506da89..9a2099d73 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -31,8 +31,7 @@ static int merge_size = 0;
static struct object_list *trees = NULL;
-static struct cache_entry df_conflict_entry = {
-};
+static struct cache_entry df_conflict_entry;
struct tree_entry_list {
struct tree_entry_list *next;
diff --git a/stripspace.c b/builtin-stripspace.c
index 65a634645..2ce1264f7 100644
--- a/stripspace.c
+++ b/builtin-stripspace.c
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <string.h>
#include <ctype.h>
+#include "builtin.h"
/*
* Remove empty lines from the beginning and end.
@@ -28,21 +29,21 @@ static int cleanup(char *line)
return 1;
}
-int main(int argc, char **argv)
+void stripspace(FILE *in, FILE *out)
{
int empties = -1;
int incomplete = 0;
char line[1024];
- while (fgets(line, sizeof(line), stdin)) {
+ while (fgets(line, sizeof(line), in)) {
incomplete = cleanup(line);
/* Not just an empty line? */
if (line[0] != '\n') {
if (empties > 0)
- putchar('\n');
+ fputc('\n', out);
empties = 0;
- fputs(line, stdout);
+ fputs(line, out);
continue;
}
if (empties < 0)
@@ -50,6 +51,11 @@ int main(int argc, char **argv)
empties++;
}
if (incomplete)
- putchar('\n');
+ fputc('\n', out);
+}
+
+int cmd_stripspace(int argc, const char **argv, char **envp)
+{
+ stripspace(stdin, stdout);
return 0;
}
diff --git a/update-index.c b/builtin-update-index.c
index fbccc4a67..ef5024345 100644
--- a/update-index.c
+++ b/builtin-update-index.c
@@ -8,6 +8,7 @@
#include "quote.h"
#include "cache-tree.h"
#include "tree-walk.h"
+#include "builtin.h"
/*
* Default to not allowing changes to the list of files. The
@@ -186,8 +187,6 @@ static void chmod_path(int flip, const char *path)
die("git-update-index: cannot chmod %cx '%s'", flip, path);
}
-static struct lock_file lock_file;
-
static void update_one(const char *path, const char *prefix, int prefix_length)
{
const char *p = prefix_path(prefix, prefix_length, path);
@@ -238,7 +237,7 @@ static void read_index_info(int line_termination)
* (2) mode SP type SP sha1 TAB path
* The second format is to stuff git-ls-tree output
* into the index file.
- *
+ *
* (3) mode SP sha1 SP stage TAB path
* This format is to put higher order stages into the
* index file and matches git-ls-files --stage output.
@@ -477,7 +476,7 @@ static int do_reupdate(int ac, const char **av,
return 0;
}
-int main(int argc, const char **argv)
+int cmd_update_index(int argc, const char **argv, char **envp)
{
int i, newfd, entries, has_errors = 0, line_termination = '\n';
int allow_options = 1;
@@ -486,12 +485,16 @@ int main(int argc, const char **argv)
int prefix_length = prefix ? strlen(prefix) : 0;
char set_executable_bit = 0;
unsigned int refresh_flags = 0;
+ struct lock_file *lock_file;
git_config(git_default_config);
- newfd = hold_lock_file_for_update(&lock_file, get_index_file());
+ /* We can't free this memory, it becomes part of a linked list parsed atexit() */
+ lock_file = xcalloc(1, sizeof(struct lock_file));
+
+ newfd = hold_lock_file_for_update(lock_file, get_index_file());
if (newfd < 0)
- die("unable to create new index file");
+ die("unable to create new cachefile");
entries = read_cache();
if (entries < 0)
@@ -645,9 +648,11 @@ int main(int argc, const char **argv)
finish:
if (active_cache_changed) {
if (write_cache(newfd, active_cache, active_nr) ||
- commit_lock_file(&lock_file))
+ commit_lock_file(lock_file))
die("Unable to write new index file");
}
+ rollback_lock_file(lock_file);
+
return has_errors ? 1 : 0;
}
diff --git a/update-ref.c b/builtin-update-ref.c
index a1e6bb90f..00333c7e7 100644
--- a/update-ref.c
+++ b/builtin-update-ref.c
@@ -1,10 +1,11 @@
#include "cache.h"
#include "refs.h"
+#include "builtin.h"
static const char git_update_ref_usage[] =
"git-update-ref <refname> <value> [<oldval>] [-m <reason>]";
-int main(int argc, char **argv)
+int cmd_update_ref(int argc, const char **argv, char **envp)
{
const char *refname=NULL, *value=NULL, *oldval=NULL, *msg=NULL;
struct ref_lock *lock;
@@ -52,5 +53,7 @@ int main(int argc, char **argv)
return 1;
if (write_ref_sha1(lock, sha1, msg) < 0)
return 1;
+
+ /* write_ref_sha1 always unlocks the ref, no need to do it explicitly */
return 0;
}
diff --git a/write-tree.c b/builtin-write-tree.c
index bd07da618..70e9b6fcc 100644
--- a/write-tree.c
+++ b/builtin-write-tree.c
@@ -3,41 +3,24 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
+#include "builtin.h"
#include "cache.h"
#include "tree.h"
#include "cache-tree.h"
-static int missing_ok = 0;
-static char *prefix = NULL;
-
static const char write_tree_usage[] =
"git-write-tree [--missing-ok] [--prefix=<prefix>/]";
-static struct lock_file lock_file;
-
-int main(int argc, char **argv)
+int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
{
int entries, was_valid, newfd;
- setup_git_directory();
+ /* We can't free this memory, it becomes part of a linked list parsed atexit() */
+ struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
- newfd = hold_lock_file_for_update(&lock_file, get_index_file());
- entries = read_cache();
-
- while (1 < argc) {
- char *arg = argv[1];
- if (!strcmp(arg, "--missing-ok"))
- missing_ok = 1;
- else if (!strncmp(arg, "--prefix=", 9))
- prefix = arg + 9;
- else
- die(write_tree_usage);
- argc--; argv++;
- }
-
- if (argc > 2)
- die("too many options");
+ newfd = hold_lock_file_for_update(lock_file, get_index_file());
+ entries = read_cache();
if (entries < 0)
die("git-write-tree: error reading cache");
@@ -45,6 +28,7 @@ int main(int argc, char **argv)
active_cache_tree = cache_tree();
was_valid = cache_tree_fully_valid(active_cache_tree);
+
if (!was_valid) {
if (cache_tree_update(active_cache_tree,
active_cache, active_nr,
@@ -52,7 +36,7 @@ int main(int argc, char **argv)
die("git-write-tree: error building trees");
if (0 <= newfd) {
if (!write_cache(newfd, active_cache, active_nr))
- commit_lock_file(&lock_file);
+ commit_lock_file(lock_file);
}
/* Not being able to write is fine -- we are only interested
* in updating the cache-tree part, and if the next caller
@@ -61,12 +45,44 @@ int main(int argc, char **argv)
* performance penalty and not a big deal.
*/
}
+
if (prefix) {
struct cache_tree *subtree =
cache_tree_find(active_cache_tree, prefix);
- printf("%s\n", sha1_to_hex(subtree->sha1));
+ memcpy(sha1, subtree->sha1, 20);
}
else
- printf("%s\n", sha1_to_hex(active_cache_tree->sha1));
+ memcpy(sha1, active_cache_tree->sha1, 20);
+
+ rollback_lock_file(lock_file);
+
return 0;
}
+
+int cmd_write_tree(int argc, const char **argv, char **envp)
+{
+ int missing_ok = 0, ret;
+ const char *prefix = NULL;
+ unsigned char sha1[20];
+
+ setup_git_directory();
+
+ while (1 < argc) {
+ const char *arg = argv[1];
+ if (!strcmp(arg, "--missing-ok"))
+ missing_ok = 1;
+ else if (!strncmp(arg, "--prefix=", 9))
+ prefix = arg + 9;
+ else
+ die(write_tree_usage);
+ argc--; argv++;
+ }
+
+ if (argc > 2)
+ die("too many options");
+
+ ret = write_tree(sha1, missing_ok, prefix);
+ printf("%s\n", sha1_to_hex(sha1));
+
+ return ret;
+}
diff --git a/builtin.h b/builtin.h
index b9f36beb6..f12d5e68f 100644
--- a/builtin.h
+++ b/builtin.h
@@ -1,6 +1,8 @@
#ifndef BUILTIN_H
#define BUILTIN_H
+#include <stdio.h>
+
#ifndef PATH_MAX
# define PATH_MAX 4096
#endif
@@ -45,5 +47,18 @@ extern int cmd_diff_stages(int argc, const char **argv, char **envp);
extern int cmd_diff_tree(int argc, const char **argv, char **envp);
extern int cmd_cat_file(int argc, const char **argv, char **envp);
extern int cmd_rev_parse(int argc, const char **argv, char **envp);
+extern int cmd_update_index(int argc, const char **argv, char **envp);
+extern int cmd_update_ref(int argc, const char **argv, char **envp);
+
+extern int cmd_write_tree(int argc, const char **argv, char **envp);
+extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
+
+extern int cmd_mailsplit(int argc, const char **argv, char **envp);
+extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
+
+extern int cmd_mailinfo(int argc, const char **argv, char **envp);
+extern int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, const char *msg, const char *patch);
+extern int cmd_stripspace(int argc, const char **argv, char **envp);
+extern void stripspace(FILE *in, FILE *out);
#endif
diff --git a/config.c b/config.c
index 984c75f5d..d064f429c 100644
--- a/config.c
+++ b/config.c
@@ -317,7 +317,33 @@ int git_config_from_file(config_fn_t fn, const char *filename)
int git_config(config_fn_t fn)
{
- return git_config_from_file(fn, git_path("config"));
+ int ret = 0;
+ char *repo_config = NULL;
+ const char *home = NULL, *filename;
+
+ /* $GIT_CONFIG makes git read _only_ the given config file,
+ * $GIT_CONFIG_LOCAL will make it process it in addition to the
+ * global config file, the same way it would the per-repository
+ * config file otherwise. */
+ filename = getenv("GIT_CONFIG");
+ if (!filename) {
+ home = getenv("HOME");
+ filename = getenv("GIT_CONFIG_LOCAL");
+ if (!filename)
+ filename = repo_config = strdup(git_path("config"));
+ }
+
+ if (home) {
+ char *user_config = strdup(mkpath("%s/.gitconfig", home));
+ if (access(user_config, R_OK) > 0)
+ ret = git_config_from_file(fn, user_config);
+ free(user_config);
+ }
+
+ ret += git_config_from_file(fn, filename);
+ if (repo_config)
+ free(repo_config);
+ return ret;
}
/*
@@ -490,10 +516,19 @@ int git_config_set_multivar(const char* key, const char* value,
int i, dot;
int fd = -1, in_fd;
int ret;
- char* config_filename = strdup(git_path("config"));
- char* lock_file = strdup(git_path("config.lock"));
+ char* config_filename;
+ char* lock_file;
const char* last_dot = strrchr(key, '.');
+ config_filename = getenv("GIT_CONFIG");
+ if (!config_filename) {
+ config_filename = getenv("GIT_CONFIG_LOCAL");
+ if (!config_filename)
+ config_filename = git_path("config");
+ }
+ config_filename = strdup(config_filename);
+ lock_file = strdup(mkpath("%s.lock", config_filename));
+
/*
* Since "key" actually contains the section name and the real
* key name separated by a dot, we have to know where the dot is.
@@ -600,7 +635,7 @@ int git_config_set_multivar(const char* key, const char* value,
* As a side effect, we make sure to transform only a valid
* existing config file.
*/
- if (git_config(store_aux)) {
+ if (git_config_from_file(store_aux, config_filename)) {
fprintf(stderr, "invalid config file\n");
free(store.key);
if (store.value_regex != NULL) {
diff --git a/diff-delta.c b/diff-delta.c
index 25a798d05..74486b1b8 100644
--- a/diff-delta.c
+++ b/diff-delta.c
@@ -22,6 +22,7 @@
#include <string.h>
#include "delta.h"
+#include "git-compat-util.h"
/* maximum hash entry list for the same hash bucket */
#define HASH_LIMIT 64
@@ -131,7 +132,7 @@ struct delta_index {
const void *src_buf;
unsigned long src_size;
unsigned int hash_mask;
- struct index_entry *hash[0];
+ struct index_entry *hash[FLEX_ARRAY];
};
struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)
diff --git a/diff-lib.c b/diff-lib.c
index 2183b41b0..fdc11732d 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -34,21 +34,23 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
continue;
if (ce_stage(ce)) {
- struct {
- struct combine_diff_path p;
- struct combine_diff_parent filler[5];
- } combine;
+ struct combine_diff_path *dpath;
int num_compare_stages = 0;
+ size_t path_len;
- combine.p.next = NULL;
- combine.p.len = ce_namelen(ce);
- combine.p.path = xmalloc(combine.p.len + 1);
- memcpy(combine.p.path, ce->name, combine.p.len);
- combine.p.path[combine.p.len] = 0;
- combine.p.mode = 0;
- memset(combine.p.sha1, 0, 20);
- memset(&combine.p.parent[0], 0,
- sizeof(combine.filler));
+ path_len = ce_namelen(ce);
+
+ dpath = xmalloc (combine_diff_path_size (5, path_len));
+ dpath->path = (char *) &(dpath->parent[5]);
+
+ dpath->next = NULL;
+ dpath->len = path_len;
+ memcpy(dpath->path, ce->name, path_len);
+ dpath->path[path_len] = '\0';
+ dpath->mode = 0;
+ memset(dpath->sha1, 0, 20);
+ memset(&(dpath->parent[0]), 0,
+ sizeof(struct combine_diff_parent)*5);
while (i < entries) {
struct cache_entry *nce = active_cache[i];
@@ -64,11 +66,11 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
if (2 <= stage) {
int mode = ntohl(nce->ce_mode);
num_compare_stages++;
- memcpy(combine.p.parent[stage-2].sha1,
+ memcpy(dpath->parent[stage-2].sha1,
nce->sha1, 20);
- combine.p.parent[stage-2].mode =
+ dpath->parent[stage-2].mode =
canon_mode(mode);
- combine.p.parent[stage-2].status =
+ dpath->parent[stage-2].status =
DIFF_STATUS_MODIFIED;
}
@@ -83,13 +85,14 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
i--;
if (revs->combine_merges && num_compare_stages == 2) {
- show_combined_diff(&combine.p, 2,
+ show_combined_diff(dpath, 2,
revs->dense_combined_merges,
revs);
- free(combine.p.path);
+ free(dpath);
continue;
}
- free(combine.p.path);
+ free(dpath);
+ dpath = NULL;
/*
* Show the diff for the 'ce' if we found the one
diff --git a/diff.c b/diff.c
index 9e9cfc8b7..bc32a4aa2 100644
--- a/diff.c
+++ b/diff.c
@@ -25,6 +25,20 @@ int git_diff_config(const char *var, const char *value)
return git_default_config(var, value);
}
+enum color_diff {
+ DIFF_PLAIN = 0,
+ DIFF_METAINFO = 1,
+ DIFF_FILE_OLD = 2,
+ DIFF_FILE_NEW = 3,
+};
+
+static const char *diff_colors[] = {
+ "\033[0;0m",
+ "\033[1;35m",
+ "\033[1;31m",
+ "\033[1;34m",
+};
+
static char *quote_one(const char *str)
{
int needlen;
@@ -177,23 +191,54 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
}
struct emit_callback {
+ struct xdiff_emit_state xm;
+ int nparents, color_diff;
const char **label_path;
};
-static int fn_out(void *priv, mmbuffer_t *mb, int nbuf)
+static inline void color_diff(int diff_use_color, enum color_diff ix)
+{
+ if (diff_use_color)
+ fputs(diff_colors[ix], stdout);
+}
+
+static void fn_out_consume(void *priv, char *line, unsigned long len)
{
int i;
struct emit_callback *ecbdata = priv;
if (ecbdata->label_path[0]) {
+ color_diff(ecbdata->color_diff, DIFF_METAINFO);
printf("--- %s\n", ecbdata->label_path[0]);
+ color_diff(ecbdata->color_diff, DIFF_METAINFO);
printf("+++ %s\n", ecbdata->label_path[1]);
ecbdata->label_path[0] = ecbdata->label_path[1] = NULL;
}
- for (i = 0; i < nbuf; i++)
- if (!fwrite(mb[i].ptr, mb[i].size, 1, stdout))
- return -1;
- return 0;
+
+ /* This is not really necessary for now because
+ * this codepath only deals with two-way diffs.
+ */
+ for (i = 0; i < len && line[i] == '@'; i++)
+ ;
+ if (2 <= i && i < len && line[i] == ' ') {
+ ecbdata->nparents = i - 1;
+ color_diff(ecbdata->color_diff, DIFF_METAINFO);
+ }
+ else if (len < ecbdata->nparents)
+ color_diff(ecbdata->color_diff, DIFF_PLAIN);
+ else {
+ int nparents = ecbdata->nparents;
+ int color = DIFF_PLAIN;
+ for (i = 0; i < nparents && len; i++) {
+ if (line[i] == '-')
+ color = DIFF_FILE_OLD;
+ else if (line[i] == '+')
+ color = DIFF_FILE_NEW;
+ }
+ color_diff(ecbdata->color_diff, color);
+ }
+ fwrite(line, len, 1, stdout);
+ color_diff(ecbdata->color_diff, DIFF_PLAIN);
}
static char *pprint_rename(const char *a, const char *b)
@@ -549,25 +594,35 @@ static void builtin_diff(const char *name_a,
b_two = quote_two("b/", name_b);
lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null";
+ color_diff(o->color_diff, DIFF_METAINFO);
printf("diff --git %s %s\n", a_one, b_two);
if (lbl[0][0] == '/') {
/* /dev/null */
+ color_diff(o->color_diff, DIFF_METAINFO);
printf("new file mode %06o\n", two->mode);
- if (xfrm_msg && xfrm_msg[0])
+ if (xfrm_msg && xfrm_msg[0]) {
+ color_diff(o->color_diff, DIFF_METAINFO);
puts(xfrm_msg);
+ }
}
else if (lbl[1][0] == '/') {
printf("deleted file mode %06o\n", one->mode);
- if (xfrm_msg && xfrm_msg[0])
+ if (xfrm_msg && xfrm_msg[0]) {
+ color_diff(o->color_diff, DIFF_METAINFO);
puts(xfrm_msg);
+ }
}
else {
if (one->mode != two->mode) {
+ color_diff(o->color_diff, DIFF_METAINFO);
printf("old mode %06o\n", one->mode);
+ color_diff(o->color_diff, DIFF_METAINFO);
printf("new mode %06o\n", two->mode);
}
- if (xfrm_msg && xfrm_msg[0])
+ if (xfrm_msg && xfrm_msg[0]) {
+ color_diff(o->color_diff, DIFF_METAINFO);
puts(xfrm_msg);
+ }
/*
* we do not run diff between different kind
* of objects.
@@ -575,6 +630,7 @@ static void builtin_diff(const char *name_a,
if ((one->mode ^ two->mode) & S_IFMT)
goto free_ab_and_return;
if (complete_rewrite) {
+ color_diff(o->color_diff, DIFF_PLAIN);
emit_rewrite_diff(name_a, name_b, one, two);
goto free_ab_and_return;
}
@@ -602,7 +658,9 @@ static void builtin_diff(const char *name_a,
xdemitcb_t ecb;
struct emit_callback ecbdata;
+ memset(&ecbdata, 0, sizeof(ecbdata));
ecbdata.label_path = lbl;
+ ecbdata.color_diff = o->color_diff;
xpp.flags = XDF_NEED_MINIMAL;
xecfg.ctxlen = o->context;
xecfg.flags = XDL_EMIT_FUNCNAMES;
@@ -612,8 +670,9 @@ static void builtin_diff(const char *name_a,
xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10);
else if (!strncmp(diffopts, "-u", 2))
xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10);
- ecb.outf = fn_out;
+ ecb.outf = xdiff_outf;
ecb.priv = &ecbdata;
+ ecbdata.xm.consume = fn_out_consume;
xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
}
@@ -1456,6 +1515,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
else if (40 < options->abbrev)
options->abbrev = 40;
}
+ else if (!strcmp(arg, "--color"))
+ options->color_diff = 1;
else
return 0;
return 1;
diff --git a/diff.h b/diff.h
index 4fc597c59..de9de574e 100644
--- a/diff.h
+++ b/diff.h
@@ -32,7 +32,8 @@ struct diff_options {
full_index:1,
silent_on_remove:1,
find_copies_harder:1,
- summary:1;
+ summary:1,
+ color_diff:1;
int context;
int break_opt;
int detect_rename;
diff --git a/git.c b/git.c
index 329ebec78..94e9a4a4b 100644
--- a/git.c
+++ b/git.c
@@ -178,7 +178,13 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
{ "diff-stages", cmd_diff_stages },
{ "diff-tree", cmd_diff_tree },
{ "cat-file", cmd_cat_file },
- { "rev-parse", cmd_rev_parse }
+ { "rev-parse", cmd_rev_parse },
+ { "write-tree", cmd_write_tree },
+ { "mailsplit", cmd_mailsplit },
+ { "mailinfo", cmd_mailinfo },
+ { "stripspace", cmd_stripspace },
+ { "update-index", cmd_update_index },
+ { "update-ref", cmd_update_ref }
};
int i;
diff --git a/http-fetch.c b/http-fetch.c
index da1a7f541..3a2cb5e1f 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -1136,13 +1136,14 @@ int fetch(unsigned char *sha1)
static inline int needs_quote(int ch)
{
- switch (ch) {
- case '/': case '-': case '.':
- case 'A'...'Z': case 'a'...'z': case '0'...'9':
+ if (((ch >= 'A') && (ch <= 'Z'))
+ || ((ch >= 'a') && (ch <= 'z'))
+ || ((ch >= '0') && (ch <= '9'))
+ || (ch == '/')
+ || (ch == '-')
+ || (ch == '.'))
return 0;
- default:
- return 1;
- }
+ return 1;
}
static inline int hex(int v)
diff --git a/http-push.c b/http-push.c
index ba64f8fff..aaf155c5b 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1077,13 +1077,14 @@ static int fetch_indices(void)
static inline int needs_quote(int ch)
{
- switch (ch) {
- case '/': case '-': case '.':
- case 'A'...'Z': case 'a'...'z': case '0'...'9':
+ if (((ch >= 'A') && (ch <= 'Z'))
+ || ((ch >= 'a') && (ch <= 'z'))
+ || ((ch >= '0') && (ch <= '9'))
+ || (ch == '/')
+ || (ch == '-')
+ || (ch == '.'))
return 0;
- default:
- return 1;
- }
+ return 1;
}
static inline int hex(int v)
diff --git a/imap-send.c b/imap-send.c
index 285ad29af..94e39cd94 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -93,7 +93,7 @@ typedef struct {
char *data;
int len;
unsigned char flags;
- unsigned char crlf:1;
+ unsigned int crlf:1;
} msg_data_t;
#define DRV_OK 0
diff --git a/pager.c b/pager.c
index 9a3093901..2d186e8bd 100644
--- a/pager.c
+++ b/pager.c
@@ -46,7 +46,7 @@ void setup_pager(void)
close(fd[0]);
close(fd[1]);
- setenv("LESS", "-S", 0);
+ setenv("LESS", "-RS", 0);
run_pager(pager);
die("unable to execute pager '%s'", pager);
exit(255);
diff --git a/quote.c b/quote.c
index 06792d47c..dcc232661 100644
--- a/quote.c
+++ b/quote.c
@@ -206,7 +206,14 @@ char *unquote_c_style(const char *quoted, const char **endp)
case '\\': case '"':
break; /* verbatim */
- case '0'...'7':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
/* octal */
ac = ((ch - '0') << 6);
if ((ch = *sp++) < '0' || '7' < ch)
diff --git a/repo-config.c b/repo-config.c
index 08fc4cc57..03f108fe2 100644
--- a/repo-config.c
+++ b/repo-config.c
@@ -64,7 +64,22 @@ static int show_config(const char* key_, const char* value_)
static int get_value(const char* key_, const char* regex_)
{
+ int ret = -1;
char *tl;
+ char *global = NULL, *repo_config = NULL;
+ const char *local;
+
+ local = getenv("GIT_CONFIG");
+ if (!local) {
+ const char *home = getenv("HOME");
+ local = getenv("GIT_CONFIG_LOCAL");
+ if (!local)
+ local = repo_config;
+ else
+ local = repo_config = strdup(git_path("config"));
+ if (home)
+ global = strdup(mkpath("%s/.gitconfig", home));
+ }
key = strdup(key_);
for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl)
@@ -76,7 +91,7 @@ static int get_value(const char* key_, const char* regex_)
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;
+ goto free_strings;
}
}
@@ -89,11 +104,16 @@ static int get_value(const char* key_, const char* regex_)
regexp = (regex_t*)malloc(sizeof(regex_t));
if (regcomp(regexp, regex_, REG_EXTENDED)) {
fprintf(stderr, "Invalid pattern: %s\n", regex_);
- return -1;
+ goto free_strings;
}
}
- git_config(show_config);
+ if (do_all && global)
+ git_config_from_file(show_config, global);
+ git_config_from_file(show_config, local);
+ if (!do_all && !seen && global)
+ git_config_from_file(show_config, global);
+
free(key);
if (regexp) {
regfree(regexp);
@@ -101,9 +121,16 @@ static int get_value(const char* key_, const char* regex_)
}
if (do_all)
- return !seen;
-
- return (seen == 1) ? 0 : 1;
+ ret = !seen;
+ else
+ ret = (seen == 1) ? 0 : 1;
+
+free_strings:
+ if (repo_config)
+ free(repo_config);
+ if (global)
+ free(global);
+ return ret;
}
int main(int argc, const char **argv)
diff --git a/t/Makefile b/t/Makefile
index 549598575..632c55f6d 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -19,7 +19,7 @@ endif
all: $(T) clean
$(T):
- @echo "*** $@ ***"; '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS)
+ @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS)
clean:
rm -fr trash
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 8260d57b6..0de249774 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -309,5 +309,29 @@ EOF
test_expect_success 'new variable inserts into proper section' 'cmp .git/config expect'
+cat > other-config << EOF
+[ein]
+ bahn = strasse
+EOF
+
+cat > expect << EOF
+ein.bahn=strasse
+EOF
+
+GIT_CONFIG=other-config git-repo-config -l > output
+
+test_expect_success 'alternative GIT_CONFIG' 'cmp output expect'
+
+GIT_CONFIG=other-config git-repo-config anwohner.park ausweis
+
+cat > expect << EOF
+[ein]
+ bahn = strasse
+[anwohner]
+ park = ausweis
+EOF
+
+test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect'
+
test_done