LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
tag.o date.o index.o diff-delta.o patch-delta.o entry.o path.o \
refs.o csum-file.o pack-check.o pkt-line.o connect.o ident.o \
- sha1_name.o
+ sha1_name.o setup.o
LIB_H += rev-cache.h
LIB_OBJS += rev-cache.o
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
+extern const char **get_pathspec(const char *prefix, char **pathspec);
+extern const char *setup_git_directory(void);
+
#define alloc_nr(x) (((x)+16)*3/2)
/* Initialize and use the cache information */
"[<common diff options>] <tree-ish> [<path>...]"
COMMON_DIFF_OPTIONS_HELP;
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
{
const char *tree_name = NULL;
unsigned char sha1[20];
+ const char *prefix = setup_git_directory();
const char **pathspec = NULL;
void *tree;
unsigned long size;
int allow_options = 1;
int i;
- read_cache();
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!allow_options || *arg != '-') {
- if (tree_name) {
- pathspec = argv + i;
+ if (tree_name)
break;
- }
tree_name = arg;
continue;
}
usage(diff_cache_usage);
}
+ pathspec = get_pathspec(prefix, argv + i);
+
if (find_copies_harder && detect_rename != DIFF_DETECT_COPY)
usage(diff_cache_usage);
if (!tree_name || get_sha1(tree_name, sha1))
usage(diff_cache_usage);
+ read_cache();
+
/* The rest is for paths restriction. */
diff_setup(diff_setup_opt);
diff_change(oldmode, mode, old_sha1, sha1, path, NULL);
}
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
{
static const unsigned char null_sha1[20] = { 0, };
const char **pathspec;
- int entries = read_cache();
- int i;
+ const char *prefix = setup_git_directory();
+ int entries, i;
while (1 < argc && argv[1][0] == '-') {
if (!strcmp(argv[1], "-p") || !strcmp(argv[1], "-u"))
argv++; argc--;
}
- /* Do we have a pathspec? */
- pathspec = (argc > 1) ? argv + 1 : NULL;
+ /* Find the directory, and set up the pathspec */
+ pathspec = get_pathspec(prefix, argv + 1);
+ entries = read_cache();
if (find_copies_harder && detect_rename != DIFF_DETECT_COPY)
usage(diff_files_usage);
return diff_tree_commit(commit, line);
}
+static int count_paths(const char **paths)
+{
+ int i = 0;
+ while (*paths++)
+ i++;
+ return i;
+}
+
static const char diff_tree_usage[] =
"git-diff-tree [--stdin] [-m] [-s] [-v] [--pretty] [-t] "
"[<common diff options>] <tree-ish> <tree-ish>"
COMMON_DIFF_OPTIONS_HELP;
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
{
int nr_sha1;
char line[1000];
unsigned char sha1[2][20];
+ const char *prefix = setup_git_directory();
nr_sha1 = 0;
for (;;) {
if (find_copies_harder && detect_rename != DIFF_DETECT_COPY)
usage(diff_tree_usage);
- if (argc > 0) {
+ paths = get_pathspec(prefix, argv);
+ if (paths) {
int i;
- paths = argv;
- nr_paths = argc;
+ nr_paths = count_paths(paths);
pathlens = xmalloc(nr_paths * sizeof(int));
for (i=0; i<nr_paths; i++)
pathlens[i] = strlen(paths[i]);
name[len] == 0 ||
name[len] == '/')
return 1;
+ if (!len)
+ return 1;
}
return 0;
}
#!/bin/sh
-. git-sh-setup-script || die "Not a git archive"
-
-rev=($(git-rev-parse --revs-only "$@"))
+rev=($(git-rev-parse --revs-only "$@")) || exit
flags=($(git-rev-parse --no-revs --flags "$@"))
files=($(git-rev-parse --no-revs --no-flags "$@"))
case "${#rev[*]}" in
. git-sh-setup-script || die "Not a git archive."
usage () {
- echo >&2 "usage: $0"' [-n] [-o dir] [--mbox] [--check] [--signoff] [-<diff options>...] upstream [ our-head ]
+ echo >&2 "usage: $0"' [-n] [-o dir] [--keep-subject] [--mbox] [--check] [--signoff] [-<diff options>...] upstream [ our-head ]
Prepare each commit with its patch since our-head forked from upstream,
one file per patch, for e-mail submission. Each output file is
date=t ;;
-m|--m|--mb|--mbo|--mbox)
date=t author=t mbox=t ;;
+ -k|--k|--ke|--kee|--keep|--keep-|--keep-s|--keep-su|--keep-sub|\
+ --keep-subj|--keep-subje|--keep-subjec|--keep-subject)
+ keep_subject=t ;;
-n|--n|--nu|--num|--numb|--numbe|--number|--numbere|--numbered)
numbered=t ;;
-s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
shift
done
+case "$keep_subject$numbered" in
+tt)
+ die '--keep-subject and --numbered are incompatible.' ;;
+esac
+
revpair=
case "$#" in
2)
{
mailScript='
/./d
- /^$/n
- s|^\[PATCH[^]]*\] *||'
-
- case "$mbox" in
- t)
- echo 'From nobody Mon Sep 17 00:00:00 2001' ;# UNIX "From" line
- mailScript="$mailScript"'
- s|^|Subject: [PATCH'"$num"'] |'
- ;;
+ /^$/n'
+ case "$keep_subject" in
+ t) ;;
*)
mailScript="$mailScript"'
+ s|^\[PATCH[^]]*\] *||
s|^|[PATCH'"$num"'] |'
;;
esac
-
+ mailScript="$mailScript"'
+ s|^|Subject: |'
+ case "$mbox" in
+ t)
+ echo 'From nobody Mon Sep 17 00:00:00 2001' ;# UNIX "From" line
+ ;;
+ esac
eval "$(sed -ne "$whosepatchScript" $commsg)"
test "$author,$au" = ",$me" || {
mailScript="$mailScript"'
return 1;
if (name[matchlen] == '/' || !name[matchlen])
return 1;
+ if (!matchlen)
+ return 1;
}
return 0;
}
{
int i, as_is = 0;
unsigned char sha1[20];
-
+ const char *prefix = setup_git_directory();
+
for (i = 1; i < argc; i++) {
char *arg = argv[i];
char *dotdot;
for_each_ref(show_reference);
continue;
}
+ if (!strcmp(arg, "--show-prefix")) {
+ puts(prefix);
+ continue;
+ }
show_arg(arg);
continue;
}
--- /dev/null
+#include "cache.h"
+
+static char *prefix_path(const char *prefix, int len, char *path)
+{
+ char *orig = path;
+ for (;;) {
+ char c;
+ if (*path != '.')
+ break;
+ c = path[1];
+ /* "." */
+ if (!c) {
+ path++;
+ break;
+ }
+ /* "./" */
+ if (c == '/') {
+ path += 2;
+ continue;
+ }
+ if (c != '.')
+ break;
+ c = path[2];
+ if (!c)
+ path += 2;
+ else if (c == '/')
+ path += 3;
+ else
+ break;
+ /* ".." and "../" */
+ /* Remove last component of the prefix */
+ do {
+ if (!len)
+ die("'%s' is outside repository", orig);
+ len--;
+ } while (len && prefix[len-1] != '/');
+ continue;
+ }
+ if (len) {
+ int speclen = strlen(path);
+ char *n = xmalloc(speclen + len + 1);
+
+ memcpy(n, prefix, len);
+ memcpy(n + len, path, speclen+1);
+ path = n;
+ }
+ return path;
+}
+
+const char **get_pathspec(const char *prefix, char **pathspec)
+{
+ char *entry = *pathspec;
+ char **p;
+ int prefixlen;
+
+ if (!prefix && !entry)
+ return NULL;
+
+ if (!entry) {
+ static const char *spec[2];
+ spec[0] = prefix;
+ spec[1] = NULL;
+ return spec;
+ }
+
+ /* Otherwise we have to re-write the entries.. */
+ p = pathspec;
+ prefixlen = prefix ? strlen(prefix) : 0;
+ do {
+ *p = prefix_path(prefix, prefixlen, entry);
+ } while ((entry = *++p) != NULL);
+ return (const char **) pathspec;
+}
+
+const char *setup_git_directory(void)
+{
+ static char cwd[PATH_MAX+1];
+ int len, offset;
+
+ /*
+ * If GIT_DIR is set explicitly, we're not going
+ * to do any discovery
+ */
+ if (gitenv(GIT_DIR_ENVIRONMENT))
+ return NULL;
+
+ if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
+ die("Unable to read current working directory");
+
+ offset = len = strlen(cwd);
+ for (;;) {
+ /*
+ * We always want to see a .git/refs/ subdirectory
+ */
+ if (!access(".git/refs/", X_OK)) {
+ /*
+ * Then we need either a GIT_OBJECT_DIRECTORY define
+ * or a .git/objects/ directory
+ */
+ if (gitenv(DB_ENVIRONMENT) || !access(".git/objects/", X_OK))
+ break;
+ }
+ chdir("..");
+ do {
+ if (!offset)
+ die("Not a git repository");
+ } while (cwd[--offset] != '/');
+ }
+
+ if (offset == len)
+ return NULL;
+
+ /* Make "offset" point to past the '/', and add a '/' at the end */
+ offset++;
+ cwd[len++] = '/';
+ cwd[len] = 0;
+ return cwd + offset;
+}
* SHA1, an extra slash for the first level indirection, and the
* terminating NUL.
*/
-static void link_alt_odb_entries(const char *alt, const char *ep)
+static void link_alt_odb_entries(const char *alt, const char *ep, int sep)
{
const char *cp, *last;
struct alternate_object_database *ent;
last = alt;
- do {
- for (cp = last; cp < ep && *cp != ':'; cp++)
+ while (last < ep) {
+ cp = last;
+ if (cp < ep && *cp == '#') {
+ while (cp < ep && *cp != sep)
+ cp++;
+ last = cp + 1;
+ continue;
+ }
+ for ( ; cp < ep && *cp != sep; cp++)
;
if (last != cp) {
/* 43 = 40-byte + 2 '/' + terminating NUL */
ent->base[pfxlen] = ent->base[pfxlen + 3] = '/';
ent->base[entlen-1] = 0;
}
- while (cp < ep && *cp == ':')
+ while (cp < ep && *cp == sep)
cp++;
last = cp;
- } while (cp < ep);
+ }
}
void prepare_alt_odb(void)
{
char path[PATH_MAX];
- char *map, *ep;
+ char *map;
int fd;
struct stat st;
char *alt = gitenv(ALTERNATE_DB_ENVIRONMENT) ? : "";
if (alt_odb_tail)
return;
alt_odb_tail = &alt_odb_list;
- link_alt_odb_entries(alt, alt + strlen(alt));
+ link_alt_odb_entries(alt, alt + strlen(alt), ':');
fd = open(path, O_RDONLY);
if (fd < 0)
if (map == MAP_FAILED)
return;
- /* Remove the trailing newline */
- for (ep = map + st.st_size - 1; map < ep && ep[-1] == '\n'; ep--)
- ;
- link_alt_odb_entries(map, ep);
+ link_alt_odb_entries(map, map + st.st_size, '\n');
munmap(map, st.st_size);
}
## You give it a mbox-format collection of emails, and it will try to
## apply them to the kernel using "applypatch"
##
-## applymbox [ -q ] (-c .dotest/msg-number | mail_archive) [Signoff_file]"
+## applymbox [ -k ] [ -q ] (-c .dotest/msg-number | mail_archive) [Signoff_file]"
##
## The patch application may fail in the middle. In which case:
## (1) look at .dotest/patch and fix it up to apply
## use a Signoff_file, because applypatch wants to append the sign-off
## message to msg-clean every time it is run.
-query_apply= continue= resume=t
+keep_subject= query_apply= continue= resume=t
while case "$#" in 0) break ;; esac
do
case "$1" in
+ -k) keep_subject=-k ;;
-q) query_apply=t ;;
-c) continue="$2"; resume=f; shift ;;
-*) usage ;;
case "$query_apply" in
t) touch .dotest/.query_apply
esac
+case "$keep_subject" in
+-k) : >.dotest/.keep_subject
+esac
signoff="$1"
set x .dotest/0*
f,$i) resume=t;;
f,*) continue;;
*)
- git-mailinfo .dotest/msg .dotest/patch <$i >.dotest/info || exit 1
+ git-mailinfo $keep_subject \
+ .dotest/msg .dotest/patch <$i >.dotest/info || exit 1
git-stripspace < .dotest/msg > .dotest/msg-clean
;;
esac
## If this file exists, we ask before applying
##
query_apply=.dotest/.query_apply
+keep_subject=.dotest/.keep_subject
MSGFILE=$1
PATCHFILE=$2
INFO=$3
if [ -n "$signoff" -a -f "$signoff" ]; then
cat $signoff >> $MSGFILE
fi
+patch_header=
+test -f "$keep_subject" || patch_header='[PATCH] '
-(echo "[PATCH] $SUBJECT" ; if [ -s $MSGFILE ]; then echo ; cat $MSGFILE; fi ) > $final
+(echo "$patch_header$SUBJECT" ; if [ -s $MSGFILE ]; then echo ; cat $MSGFILE; fi ) > $final
f=0
[ -f $query_apply ] || f=1
static FILE *cmitmsg, *patchfile;
+static int keep_subject = 0;
static char line[1000];
static char date[1000];
static char name[1000];
static char * cleanup_subject(char *subject)
{
+ if (keep_subject)
+ return subject;
for (;;) {
char *p;
int len, remove;
exit(1);
}
+static const char mailinfo_usage[] =
+"git-mailinfo [-k] msg patch <mail >info";
int main(int argc, char ** argv)
{
+ while (1 < argc && argv[1][0] == '-') {
+ if (!strcmp(argv[1], "-k"))
+ keep_subject = 1;
+ else {
+ fprintf(stderr, "usage: %s\n", mailinfo_usage);
+ exit(1);
+ }
+ argc--; argv++;
+ }
+
if (argc != 3)
usage();
cmitmsg = fopen(argv[1], "w");