* [PATCH/RFC 3/3] handle renames using similarity engine
From: Jeff King @ 2007-10-30 4:24 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Andy C, Junio C Hamano
In-Reply-To: <20071030042118.GA14729@sigill.intra.peff.net>
This changes diffcore-rename to use the engine in
similarity.c rather than doing an O(m*n) loop around
diffcore_count_changes.
Signed-off-by: Jeff King <peff@peff.net>
---
diffcore-rename.c | 215 +++++++++++++++++++----------------------------------
1 files changed, 76 insertions(+), 139 deletions(-)
diff --git a/diffcore-rename.c b/diffcore-rename.c
index ba038af..6c0d2d0 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -5,12 +5,21 @@
#include "diff.h"
#include "diffcore.h"
#include "hash.h"
+#include "similarity.h"
-/* Table of rename/copy destinations */
+/* Table of rename/copy src files */
+static struct diff_rename_src {
+ struct diff_filespec *one;
+ unsigned short score; /* to remember the break score */
+} *rename_src;
+static int rename_src_nr, rename_src_alloc;
+/* Table of rename/copy destinations */
static struct diff_rename_dst {
struct diff_filespec *two;
struct diff_filepair *pair;
+ struct diff_rename_src *best_match;
+ unsigned score;
} *rename_dst;
static int rename_dst_nr, rename_dst_alloc;
@@ -49,16 +58,11 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
rename_dst[first].two = alloc_filespec(two->path);
fill_filespec(rename_dst[first].two, two->sha1, two->mode);
rename_dst[first].pair = NULL;
+ rename_dst[first].best_match = NULL;
+ rename_dst[first].score = 0;
return &(rename_dst[first]);
}
-/* Table of rename/copy src files */
-static struct diff_rename_src {
- struct diff_filespec *one;
- unsigned short score; /* to remember the break score */
-} *rename_src;
-static int rename_src_nr, rename_src_alloc;
-
static struct diff_rename_src *register_rename_src(struct diff_filespec *one,
unsigned short score)
{
@@ -109,88 +113,6 @@ static int basename_same(struct diff_filespec *src, struct diff_filespec *dst)
(!dst_len || dst->path[dst_len - 1] == '/');
}
-struct diff_score {
- int src; /* index in rename_src */
- int dst; /* index in rename_dst */
- int score;
- int name_score;
-};
-
-static int estimate_similarity(struct diff_filespec *src,
- struct diff_filespec *dst,
- int minimum_score)
-{
- /* src points at a file that existed in the original tree (or
- * optionally a file in the destination tree) and dst points
- * at a newly created file. They may be quite similar, in which
- * case we want to say src is renamed to dst or src is copied into
- * dst, and then some edit has been applied to dst.
- *
- * Compare them and return how similar they are, representing
- * the score as an integer between 0 and MAX_SCORE.
- *
- * When there is an exact match, it is considered a better
- * match than anything else; the destination does not even
- * call into this function in that case.
- */
- unsigned long max_size, delta_size, base_size, src_copied, literal_added;
- unsigned long delta_limit;
- int score;
-
- /* We deal only with regular files. Symlink renames are handled
- * only when they are exact matches --- in other words, no edits
- * after renaming.
- */
- if (!S_ISREG(src->mode) || !S_ISREG(dst->mode))
- return 0;
-
- /*
- * Need to check that source and destination sizes are
- * filled in before comparing them.
- *
- * If we already have "cnt_data" filled in, we know it's
- * all good (avoid checking the size for zero, as that
- * is a possible size - we really should have a flag to
- * say whether the size is valid or not!)
- */
- if (!src->cnt_data && diff_populate_filespec(src, 0))
- return 0;
- if (!dst->cnt_data && diff_populate_filespec(dst, 0))
- return 0;
-
- max_size = ((src->size > dst->size) ? src->size : dst->size);
- base_size = ((src->size < dst->size) ? src->size : dst->size);
- delta_size = max_size - base_size;
-
- /* We would not consider edits that change the file size so
- * drastically. delta_size must be smaller than
- * (MAX_SCORE-minimum_score)/MAX_SCORE * min(src->size, dst->size).
- *
- * Note that base_size == 0 case is handled here already
- * and the final score computation below would not have a
- * divide-by-zero issue.
- */
- if (base_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE)
- return 0;
-
- delta_limit = (unsigned long)
- (base_size * (MAX_SCORE-minimum_score) / MAX_SCORE);
- if (diffcore_count_changes(src, dst,
- &src->cnt_data, &dst->cnt_data,
- delta_limit,
- &src_copied, &literal_added))
- return 0;
-
- /* How similar are they?
- * what percentage of material in dst are from source?
- */
- if (!dst->size)
- score = 0; /* should not happen */
- else
- score = (int)(src_copied * MAX_SCORE / max_size);
- return score;
-}
-
static void record_rename_pair(int dst_index, int src_index, int score)
{
struct diff_filespec *src, *dst;
@@ -215,20 +137,6 @@ static void record_rename_pair(int dst_index, int src_index, int score)
rename_dst[dst_index].pair = dp;
}
-/*
- * We sort the rename similarity matrix with the score, in descending
- * order (the most similar first).
- */
-static int score_compare(const void *a_, const void *b_)
-{
- const struct diff_score *a = a_, *b = b_;
-
- if (a->score == b->score)
- return b->name_score - a->name_score;
-
- return b->score - a->score;
-}
-
struct file_similarity {
int src_dst, index;
struct diff_filespec *filespec;
@@ -376,6 +284,67 @@ static int find_exact_renames(void)
return i;
}
+static void record_similarity(void *vsrc, void *vdst, unsigned score)
+{
+ struct diff_rename_src *src = vsrc;
+ struct diff_rename_dst *dst = vdst;
+ unsigned max_size = (src->one->size > dst->two->size) ?
+ src->one->size : dst->two->size;
+
+ score = (dst->two->size != 0) ? (score * MAX_SCORE / max_size) : 0;
+
+ /* Is there a match already that is better than we are? */
+ if (dst->best_match) {
+ if (score < dst->score)
+ return;
+ if (score == dst->score && !basename_same(src->one, dst->two))
+ return;
+ }
+
+ dst->best_match = src;
+ dst->score = score;
+}
+
+static void find_approximate_renames(int minimum_score)
+{
+ struct similarity sim;
+ int i;
+
+ similarity_init(&sim);
+
+ for (i = 0; i < rename_src_nr; i++) {
+ struct diff_rename_src *s = &rename_src[i];
+ diff_populate_filespec(s->one, 0);
+ similarity_add(&sim, SIMILARITY_SOURCE, s,
+ s->one->data, s->one->size,
+ diff_filespec_is_binary(s->one));
+ diff_free_filespec_data(s->one);
+ }
+
+ for (i = 0; i < rename_dst_nr; i++) {
+ struct diff_rename_dst *d = &rename_dst[i];
+ if (d->pair)
+ continue;
+ diff_populate_filespec(d->two, 0);
+ similarity_add(&sim, SIMILARITY_DEST, d,
+ d->two->data, d->two->size,
+ diff_filespec_is_binary(d->two));
+ diff_free_filespec_data(d->two);
+ }
+
+ similarity_score(&sim);
+ similarity_report(&sim, record_similarity);
+
+ for (i = 0 ; i < rename_dst_nr; i++) {
+ struct diff_rename_dst *d = &rename_dst[i];
+ if (d->pair)
+ continue;
+ if (d->score < minimum_score)
+ continue;
+ record_rename_pair(i, d->best_match - rename_src, d->score);
+ }
+}
+
void diffcore_rename(struct diff_options *options)
{
int detect_rename = options->detect_rename;
@@ -383,9 +352,8 @@ void diffcore_rename(struct diff_options *options)
int rename_limit = options->rename_limit;
struct diff_queue_struct *q = &diff_queued_diff;
struct diff_queue_struct outq;
- struct diff_score *mx;
- int i, j, rename_count;
- int num_create, num_src, dst_cnt;
+ int num_create, num_src;
+ int i, rename_count;
if (!minimum_score)
minimum_score = DEFAULT_RENAME_SCORE;
@@ -462,38 +430,7 @@ void diffcore_rename(struct diff_options *options)
if (num_create * num_src > rename_limit * rename_limit)
goto cleanup;
- mx = xmalloc(sizeof(*mx) * num_create * num_src);
- for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
- int base = dst_cnt * num_src;
- struct diff_filespec *two = rename_dst[i].two;
- if (rename_dst[i].pair)
- continue; /* dealt with exact match already. */
- for (j = 0; j < rename_src_nr; j++) {
- struct diff_filespec *one = rename_src[j].one;
- struct diff_score *m = &mx[base+j];
- m->src = j;
- m->dst = i;
- m->score = estimate_similarity(one, two,
- minimum_score);
- m->name_score = basename_same(one, two);
- diff_free_filespec_blob(one);
- }
- /* We do not need the text anymore */
- diff_free_filespec_blob(two);
- dst_cnt++;
- }
- /* cost matrix sorted by most to least similar pair */
- qsort(mx, num_create * num_src, sizeof(*mx), score_compare);
- for (i = 0; i < num_create * num_src; i++) {
- struct diff_rename_dst *dst = &rename_dst[mx[i].dst];
- if (dst->pair)
- continue; /* already done, either exact or fuzzy. */
- if (mx[i].score < minimum_score)
- break; /* there is no more usable pair. */
- record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
- rename_count++;
- }
- free(mx);
+ find_approximate_renames(minimum_score);
cleanup:
/* At this point, we have found some renames and copies and they
--
1.5.3.4
^ permalink raw reply related
* [PATCH/RFC 2/3] introduce generic similarity library
From: Jeff King @ 2007-10-30 4:24 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Andy C, Junio C Hamano
In-Reply-To: <20071030042118.GA14729@sigill.intra.peff.net>
This library attempts to find similarities among items
efficiently. It treats items as opaque pointers; callers are
responsible for providing an item along with its contents.
The algorithm is roughly:
1. for each item, create a set of fingerprints for each
chunk of the item (where each chunk is either delimited
by a newline or is 64 characters, whichever is smaller
-- this is the same fingerprint code from
diffcore-delta.c). A hash stores a mapping of
fingerprints to items, with each fingerprint having at
most one 'source' item and one 'dest' item.
2. for each fingerprint with a source and dest item,
find the entry with key (source, dest) in a hash table
and increment its value by the value of the fingerprint
3. for each (source, dest) pair that had non-zero
similarity, report the pair to the caller
The program test-similarity is a simple demonstration of the
code. It takes two list of files on stdin, with each file
separated by newlines and the two lists separated by a blank
line. It prints the similarity score of each non-zero pair
on stdout.
There are a few "interesting" design decisions, which should
probably be tweaked:
- we store only one source and dest for each fingerprint
item. We need to bound this list so that we don't get
O(n^2) behavior for common fingerprints. This means that
some files won't get "credit" for common fingerprints,
which is probably OK, since those fingerprints are
probably uninteresting. We could bound at some small
number greater than one; one was chosen for speed and
simplicity of implementation. We also don't store any
overflow bit, so commonly used fingerprints will get
assigned to whatever file is found with them last.
- the similarity engine hands back absolute,
non-normalized scores. That means that bigger items will
have bigger scores, and the caller is responsible for
normalizing. This also means that the engine cannot
adjust normalization to account for chunks which are
thrown out by the bounding mentioned above (i.e., if a
file is 80 bytes, 64 of which are ignored as "common",
then it can at most have 20% similarity (16/80) with
another file. This means our normalized rename values
(i.e., percentage similarity) will be lower than other
algorithms.
Signed-off-by: Jeff King <peff@peff.net>
---
.gitignore | 1 +
Makefile | 4 +-
similarity.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++
similarity.h | 24 ++++++++
test-similarity.c | 54 +++++++++++++++++++
5 files changed, 233 insertions(+), 2 deletions(-)
create mode 100644 similarity.c
create mode 100644 similarity.h
create mode 100644 test-similarity.c
diff --git a/.gitignore b/.gitignore
index 62afef2..8ce6026 100644
--- a/.gitignore
+++ b/.gitignore
@@ -155,6 +155,7 @@ test-dump-cache-tree
test-genrandom
test-match-trees
test-sha1
+test-similarity
common-cmds.h
*.tar.gz
*.dsc
diff --git a/Makefile b/Makefile
index 2e6fd8f..0568d0d 100644
--- a/Makefile
+++ b/Makefile
@@ -300,7 +300,7 @@ DIFF_OBJS = \
LIB_OBJS = \
blob.o commit.o connect.o csum-file.o cache-tree.o base85.o \
date.o diff-delta.o entry.o exec_cmd.o ident.o \
- interpolate.o hash.o \
+ interpolate.o hash.o similarity.o \
lockfile.o \
patch-ids.o \
object.o pack-check.o pack-write.o patch-delta.o path.o pkt-line.o \
@@ -975,7 +975,7 @@ endif
### Testing rules
-TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-absolute-path$X
+TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-absolute-path$X test-similarity$X
all:: $(TEST_PROGRAMS)
diff --git a/similarity.c b/similarity.c
new file mode 100644
index 0000000..0bd135c
--- /dev/null
+++ b/similarity.c
@@ -0,0 +1,152 @@
+#include "cache.h"
+#include "similarity.h"
+
+struct fingerprint_entry {
+ void *src;
+ void *dst;
+ unsigned weight;
+};
+
+struct score_entry {
+ void *src;
+ void *dst;
+ unsigned score;
+ struct score_entry *next;
+};
+
+void similarity_init(struct similarity *s)
+{
+ init_hash(&s->fingerprints);
+ init_hash(&s->scores);
+}
+
+static int free_one_fingerprint(void *ve, void *data)
+{
+ struct fingerprint_entry *e = ve;
+ free(e);
+ return 0;
+}
+
+static int free_one_score(void *ve, void *data)
+{
+ struct score_entry *e = ve;
+ while (e) {
+ struct score_entry *next = e->next;
+ free(e);
+ e = next;
+ }
+ return 0;
+}
+
+void similarity_free(struct similarity *s)
+{
+ for_each_hash(&s->fingerprints, free_one_fingerprint, NULL);
+ free_hash(&s->fingerprints);
+ for_each_hash(&s->scores, free_one_score, NULL);
+ free_hash(&s->scores);
+}
+
+static void add_fingerprint(struct hash_table *h, unsigned int fp,
+ int type, void *data, unsigned weight)
+{
+ void **pos;
+ struct fingerprint_entry *e;
+
+ pos = insert_hash(fp, h);
+ if (!*pos) {
+ e = xmalloc(sizeof(*e));
+ e->weight = weight;
+ e->src = e->dst = NULL;
+ *pos = e;
+ }
+ else
+ e = *pos;
+
+ if (type == SIMILARITY_SOURCE)
+ e->src = data;
+ else
+ e->dst = data;
+}
+
+void similarity_add(struct similarity *sim, int type, void *data,
+ const char *buf, unsigned long sz, int is_text)
+{
+ int n;
+ unsigned int accum1, accum2, hashval;
+
+ n = 0;
+ accum1 = accum2 = 0;
+ while (sz) {
+ unsigned int c = *buf++;
+ unsigned int old_1 = accum1;
+ sz--;
+
+ /* Ignore CR in CRLF sequence if text */
+ if (!is_text && c == '\r' && sz && *buf == '\n')
+ continue;
+
+ accum1 = (accum1 << 7) ^ (accum2 >> 25);
+ accum2 = (accum2 << 7) ^ (old_1 >> 25);
+ accum1 += c;
+ if (++n < 64 && c != '\n')
+ continue;
+ hashval = accum1 + accum2 * 0x61;
+ add_fingerprint(&sim->fingerprints, hashval, type, data, n);
+ n = 0;
+ accum1 = accum2 = 0;
+ }
+}
+
+static unsigned hash_void_pair(void *a, void *b)
+{
+ return (unsigned)a + (unsigned)b;
+}
+
+static int score_one_entry(void *vfp, void *vsim)
+{
+ struct fingerprint_entry *fp = vfp;
+ struct similarity *sim = vsim;
+ struct score_entry *score;
+ void **pos;
+
+ if (!fp->src || !fp->dst)
+ return 0;
+
+ pos = insert_hash(hash_void_pair(fp->src, fp->dst), &sim->scores);
+ for (score = *pos; score; score = score->next) {
+ if (score->src == fp->src && score->dst == fp->dst) {
+ score->score += fp->weight;
+ return 0;
+ }
+ }
+
+ score = xmalloc(sizeof(*score));
+ score->src = fp->src;
+ score->dst = fp->dst;
+ score->score = fp->weight;
+ score->next = *pos;
+ *pos = score;
+
+ return 0;
+}
+
+void similarity_score(struct similarity *s)
+{
+ for_each_hash(&s->fingerprints, score_one_entry, s);
+}
+
+static int report_one_score(void *ve, void *vdata)
+{
+ struct score_entry *e;
+ void (*fn)(void *, void *, unsigned) = vdata;
+
+ for (e = ve; e; e = e->next)
+ fn(e->src, e->dst, e->score);
+ return 1;
+}
+
+void similarity_report(struct similarity *s,
+ void (*fn)(void *, void *, unsigned))
+{
+ for_each_hash(&s->scores, report_one_score, fn);
+}
diff --git a/similarity.h b/similarity.h
new file mode 100644
index 0000000..6409ab8
--- /dev/null
+++ b/similarity.h
@@ -0,0 +1,24 @@
+#ifndef SIMILARITY_H
+#define SIMILARITY_H
+
+#include "hash.h"
+
+#define SIMILARITY_SOURCE 0
+#define SIMILARITY_DEST 1
+
+struct similarity {
+ struct hash_table fingerprints;
+ struct hash_table scores;
+};
+
+void similarity_init(struct similarity *s);
+void similarity_free(struct similarity *s);
+
+void similarity_add(struct similarity *s, int type, void *data,
+ const char *buf, unsigned long sz, int is_text);
+
+void similarity_score(struct similarity *s);
+void similarity_report(struct similarity *s,
+ void (*fn)(void *, void *, unsigned));
+
+#endif /* SIMILARITY_H */
diff --git a/test-similarity.c b/test-similarity.c
new file mode 100644
index 0000000..5947420
--- /dev/null
+++ b/test-similarity.c
@@ -0,0 +1,54 @@
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "git-compat-util.h"
+#include "similarity.h"
+#include "strbuf.h"
+#include "xdiff-interface.h"
+
+static void print_rename(void *vone, void *vtwo, unsigned score) {
+ const char *one = vone, *two = vtwo;
+ printf("%u %s -> %s\n", score, one, two);
+}
+
+static void add_file(struct similarity *sim, int type, const char *fn)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int len;
+
+ len = strbuf_read_file(&sb, fn, 0);
+ if (len < 0)
+ die("unable to read %s: %s\n", fn, strerror(errno));
+
+ similarity_add(sim, type, strdup(fn),
+ sb.buf, sb.len, buffer_is_binary(sb.buf, sb.len));
+
+ strbuf_release(&sb);
+}
+
+int main(int argc, char **argv)
+{
+ struct similarity sim;
+ struct strbuf line;
+
+ similarity_init(&sim);
+ strbuf_init(&line, 0);
+
+ while (strbuf_getline(&line, stdin, '\n') != EOF) {
+ if (!line.len)
+ break;
+ add_file(&sim, SIMILARITY_SOURCE, line.buf);
+ }
+ while (strbuf_getline(&line, stdin, '\n') != EOF)
+ add_file(&sim, SIMILARITY_DEST, line.buf);
+
+ strbuf_release(&line);
+
+ similarity_score(&sim);
+ similarity_report(&sim, print_rename);
+
+ similarity_free(&sim);
+
+ return 0;
+}
--
1.5.3.4
^ permalink raw reply related
* [PATCH/RFC 1/3] change hash table calling conventions
From: Jeff King @ 2007-10-30 4:23 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Andy C, Junio C Hamano
In-Reply-To: <20071030042118.GA14729@sigill.intra.peff.net>
The recent hash table code has two limitations in its
calling conventions that are addressed here:
1. Insertion either inserts a value, returning NULL, or
returns a pointer to the previously inserted value.
This is fine if you are making a linked list of the
colliding values, but is awkward if your goal is to:
a. modify the value if it already exists
b. otherwise, allocate and insert the value
With the old convention, you must either allocate the
structure (and throw it away in case a), or perform two
lookups (one to see if the entry exists, then another
to perform the insertion).
Instead, insertion no longer inserts any value; it
simply returns a pointer to where you _can_ insert a
value (which will be non-NULL if a value already
existed).
2. for_each_hash now allows a void 'data' pointer to be
passed to the callback function along with each hash
entry.
Signed-off-by: Jeff King <peff@peff.net>
---
The insertion feels kind of hack-ish. Suggestions are welcome.
diffcore-rename.c | 14 +++++---------
hash.c | 18 +++++++++---------
hash.h | 5 +++--
3 files changed, 17 insertions(+), 20 deletions(-)
diff --git a/diffcore-rename.c b/diffcore-rename.c
index f9ebea5..ba038af 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -288,7 +288,7 @@ static void free_similarity_list(struct file_similarity *p)
}
}
-static int find_same_files(void *ptr)
+static int find_same_files(void *ptr, void *data)
{
int ret;
struct file_similarity *p = ptr;
@@ -343,13 +343,9 @@ static void insert_file_table(struct hash_table *table, int src_dst, int index,
entry->next = NULL;
hash = hash_filespec(filespec);
- pos = insert_hash(hash, entry, table);
-
- /* We already had an entry there? */
- if (pos) {
- entry->next = *pos;
- *pos = entry;
- }
+ pos = insert_hash(hash, table);
+ entry->next = *pos;
+ *pos = entry;
}
/*
@@ -372,7 +368,7 @@ static int find_exact_renames(void)
insert_file_table(&file_table, 1, i, rename_dst[i].two);
/* Find the renames */
- i = for_each_hash(&file_table, find_same_files);
+ i = for_each_hash(&file_table, find_same_files, NULL);
/* .. and free the hash data structure */
free_hash(&file_table);
diff --git a/hash.c b/hash.c
index 7b492d4..dc5d20e 100644
--- a/hash.c
+++ b/hash.c
@@ -33,15 +33,13 @@ static struct hash_table_entry *lookup_hash_entry(unsigned int hash, struct hash
* pointers or do anything else). If it didn't exist, return
* NULL (and the caller knows the pointer has been inserted).
*/
-static void **insert_hash_entry(unsigned int hash, void *ptr, struct hash_table *table)
+static void **insert_hash_entry(unsigned int hash, struct hash_table *table)
{
struct hash_table_entry *entry = lookup_hash_entry(hash, table);
if (!entry->ptr) {
- entry->ptr = ptr;
entry->hash = hash;
table->nr++;
- return NULL;
}
return &entry->ptr;
}
@@ -60,8 +58,10 @@ static void grow_hash_table(struct hash_table *table)
for (i = 0; i < old_size; i++) {
unsigned int hash = old_array[i].hash;
void *ptr = old_array[i].ptr;
- if (ptr)
- insert_hash_entry(hash, ptr, table);
+ if (ptr) {
+ void **pos = insert_hash_entry(hash, table);
+ *pos = ptr;
+ }
}
free(old_array);
}
@@ -73,15 +73,15 @@ void *lookup_hash(unsigned int hash, struct hash_table *table)
return &lookup_hash_entry(hash, table)->ptr;
}
-void **insert_hash(unsigned int hash, void *ptr, struct hash_table *table)
+void **insert_hash(unsigned int hash, struct hash_table *table)
{
unsigned int nr = table->nr;
if (nr >= table->size/2)
grow_hash_table(table);
- return insert_hash_entry(hash, ptr, table);
+ return insert_hash_entry(hash, table);
}
-int for_each_hash(struct hash_table *table, int (*fn)(void *))
+int for_each_hash(struct hash_table *table, int (*fn)(void *, void *), void *d)
{
int sum = 0;
unsigned int i;
@@ -92,7 +92,7 @@ int for_each_hash(struct hash_table *table, int (*fn)(void *))
void *ptr = array->ptr;
array++;
if (ptr) {
- int val = fn(ptr);
+ int val = fn(ptr, d);
if (val < 0)
return val;
sum += val;
diff --git a/hash.h b/hash.h
index a8b0fbb..f9a50da 100644
--- a/hash.h
+++ b/hash.h
@@ -29,8 +29,9 @@ struct hash_table {
};
extern void *lookup_hash(unsigned int hash, struct hash_table *table);
-extern void **insert_hash(unsigned int hash, void *ptr, struct hash_table *table);
-extern int for_each_hash(struct hash_table *table, int (*fn)(void *));
+extern void **insert_hash(unsigned int hash, struct hash_table *table);
+extern int for_each_hash(struct hash_table *table, int (*fn)(void *, void*),
+ void *data);
extern void free_hash(struct hash_table *table);
static inline void init_hash(struct hash_table *table)
--
1.5.3.4
^ permalink raw reply related
* [PATCH/RFC 0/3] faster inexact rename handling
From: Jeff King @ 2007-10-30 4:21 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds, Andy C, Junio C Hamano
This is my first stab at faster rename handling based on Andy's code.
The patches are on top of next (to get Linus' recent work on exact
renames). Most of the interesting stuff is in 2/3.
1/3: extension of hash interface
2/3: similarity detection code
3/3: integrate similarity detection into diffcore-rename
The implementation is pretty basic, so I think there is room for
code optimization (50% of the time is spent in hash lookups, so we might
be able to micro-optimize that) as well as algorithmic improvements (like the
sampling Andy mentioned).
With these patches, I can get my monster binary diff down from about 2
minutes to 17 seconds. And comparing all of linux-2.4 to all of
linux-2.6 (similar to Andy's previous demo) takes about 10 seconds.
There are a few downsides:
- the current implementation tends to give lower similarity values
compared to the old code (see discussion in 2/3), but this should be
tweakable
- on large datasets, it's more memory hungry than the old code because
the hash grows very large. This can be helped by bumping up the
binary chunk size (actually, the 17 seconds quoted above is using
256-byte chunks rather than 64-byte -- with 64-byte chunks, it's
more like 24 seconds) as well as sampling.
- no improvement on smaller datasets. Running "git-whatchanged -M
--raw -l0" on the linux-2.6 repo takes about the same time with the
old and new code (presumably the algorithmic savings of the new code
are lost in a higher constant factor, so when n is small, it is a
wash).
-Peff
^ permalink raw reply
* Re: How to merge git://repo.or.cz/git-gui into git.git
From: Junio C Hamano @ 2007-10-30 3:46 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: Yin Ping, Peter Baumann, git
In-Reply-To: <20071030005217.GT14735@spearce.org>
"Shawn O. Pearce" <spearce@spearce.org> writes:
>> 2. pull with subtree strategy
>> ~/git-gui$ git-pull -s subtree git master:master
>
> You are merging in the wrong direction. You want to merge git-gui
> into git.git:
>
> git clone git://repo.or.cz/alt-git.git mygit
> cd mygit
> git pull -s subtree git://repo.or.cz/git-gui.git master
>
> So you are pulling git-gui into git, not the reverse.
Actually, subtree strategy was designed to allow merging back
and forth. But the result, as it _is_ a merge, will not omit
any commit from the history from both branches.
^ permalink raw reply
* Re: remote#branch
From: Junio C Hamano @ 2007-10-30 3:40 UTC (permalink / raw)
To: Theodore Tso
Cc: Linus Torvalds, Jan Hudec, Johannes Schindelin, Petr Baudis,
Paolo Ciarrocchi, git
In-Reply-To: <20071030030104.GK21133@thunk.org>
Theodore Tso <tytso@mit.edu> writes:
> It would probably also be a good idea to expurgate URL's from the
> documentations, because, well, they aren't URL's. Git doesn't treat
> them like URL's, and you've said you aren't interested in changing git
> to treat them like URL's, and finally git:// isn't a registered URL
> scheme name with the IANA registration authority. So let's not call
> them URL's, since they're clearly not.
Are you playing reverse psychology, encouraging us to switch to
RFC-conforming quoting?
^ permalink raw reply
* Re: remote#branch
From: Theodore Tso @ 2007-10-30 3:01 UTC (permalink / raw)
To: Linus Torvalds
Cc: Jan Hudec, Johannes Schindelin, Petr Baudis, Paolo Ciarrocchi,
git
In-Reply-To: <alpine.LFD.0.999.0710291545250.30120@woody.linux-foundation.org>
On Mon, Oct 29, 2007 at 03:57:41PM -0700, Linus Torvalds wrote:
> Sure, but "URL" in human-speak has nothing to do with an RFC.
>
> I dislike language-lawyerese. Why the hell do people think that human
> language should follow the RFC's?
>
> Git addresses look like URL's, and they act like URL's, but dammit, git
> isn't a web browser, and it's not interested in acting like one.
The quoting rules aren't specific to a web browser; the whole point of
URL's is that they are uniform so that programs know how to handle
them without needing information specific to the URL type. Hence the
quoting rules apply to all applications using URL's, whether it's CUPS
using a url such as: ipp://example.com/printer/tiger/bob or LDAP using
a url such as: ldap://ldap.example.com/dc=example,dc=com?postalAddress.
It's just git which is different here. Having a uniform set of
processing rules are *useful* for applications and libraries that are
parsing URL's, not just for language-lawyer wanking. Not that git
addresses that are layered on top of http is all that well supported
any more, but in that case we really are using an http-style URL ---
but yet git doesn't do URL quoting, because, well, it doesn't. Yet in
that case it's very clear the http address is really a URL, and it's
arguably a defect that git doesn't handle an http address the way all
other applications handle http URL's.
At the very least, if we aren't going to change git, we should hang a
big fat sign in the documentation saying that although git location
names that begin git:// look like URL's, and smell like URL's, they
aren't treated the same way that all other applications treat URL's,
and the user shouldn't be surprised by this. Furthermore, choosing
pathnames so that git:// and gitweb http:// addresses don't require
URL-style quoting, will probably save the user a fair amount of pain
and confusion because git refuses to treat git addresses as URL's.
It would probably also be a good idea to expurgate URL's from the
documentations, because, well, they aren't URL's. Git doesn't treat
them like URL's, and you've said you aren't interested in changing git
to treat them like URL's, and finally git:// isn't a registered URL
scheme name with the IANA registration authority. So let's not call
them URL's, since they're clearly not.
- Ted
^ permalink raw reply
* Re: [PATCH 6/7] include $PATH in generating list of commands for "help -a"
From: Scott Parish @ 2007-10-30 3:00 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vir4ptyc9.fsf@gitster.siamese.dyndns.org>
On Mon, Oct 29, 2007 at 02:17:26PM -0700, Junio C Hamano wrote:
> It's easier to read if you briefly describe the differences
> between the replacement patch and the previous version of the
> patch below the three-dash lines. See for example Lars Knoll's
> patch from today <200710290959.32538.lars@trolltech.com>.
Oh, that's useful information!
For the above patch, were basically what Johannes Schindelin suggested:
+ add_cmdname() now uses ALLOC_GROW and has its lines reordered to be
somewhat cleanre
+ uniq() has lost the curly brackets
+ s/subtract_cmds/exclude_cmds/
+ exclude_cmds() uses an arg name of "path" instead of "dir"
+ exclude_cmd() no longer renames "dir" to "dirp"
+ exclude_cmds() an earlier patch moved the "struct stat" declaration
for no-longer relevant reasons. change removed.
sRp
--
Scott Parish
http://srparish.net/
^ permalink raw reply
* Re: [PATCH] Correct handling of upload-pack in builtin-fetch-pack
From: Shawn O. Pearce @ 2007-10-30 2:41 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.64.0710292232330.7357@iabervon.org>
Daniel Barkalow <barkalow@iabervon.org> wrote:
> The field in the args was being ignored in favor of a static constant
>
> Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
> ---
> Found this while trying to figure out how builtin-fetch-pack was
> initializing the string in the args struct, and why it generally worked
> even though it wasn't.
Gahhh. Yes, obviously correct fix. Thanks! :-)
> -static struct fetch_pack_args args;
> +static struct fetch_pack_args args = {
> + /* .uploadpack = */ "git-upload-pack",
> +};
>
> static const char fetch_pack_usage[] =
> "git-fetch-pack [--all] [--quiet|-q] [--keep|-k] [--thin] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...]";
> -static const char *uploadpack = "git-upload-pack";
>
> #define COMPLETE (1U << 0)
> #define COMMON (1U << 1)
> @@ -773,7 +774,7 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
> st.st_mtime = 0;
> }
>
> - pid = git_connect(fd, (char *)dest, uploadpack,
> + pid = git_connect(fd, (char *)dest, args.uploadpack,
> args.verbose ? CONNECT_VERBOSE : 0);
> if (pid < 0)
> return NULL;
--
Shawn.
^ permalink raw reply
* [PATCH] Correct handling of upload-pack in builtin-fetch-pack
From: Daniel Barkalow @ 2007-10-30 2:35 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Shawn O. Pearce
The field in the args was being ignored in favor of a static constant
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
Found this while trying to figure out how builtin-fetch-pack was
initializing the string in the args struct, and why it generally worked
even though it wasn't.
builtin-fetch-pack.c | 7 ++++---
1 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c
index 8f25d50..8753840 100644
--- a/builtin-fetch-pack.c
+++ b/builtin-fetch-pack.c
@@ -11,11 +11,12 @@
static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1;
static int unpack_limit = 100;
-static struct fetch_pack_args args;
+static struct fetch_pack_args args = {
+ /* .uploadpack = */ "git-upload-pack",
+};
static const char fetch_pack_usage[] =
"git-fetch-pack [--all] [--quiet|-q] [--keep|-k] [--thin] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...]";
-static const char *uploadpack = "git-upload-pack";
#define COMPLETE (1U << 0)
#define COMMON (1U << 1)
@@ -773,7 +774,7 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
st.st_mtime = 0;
}
- pid = git_connect(fd, (char *)dest, uploadpack,
+ pid = git_connect(fd, (char *)dest, args.uploadpack,
args.verbose ? CONNECT_VERBOSE : 0);
if (pid < 0)
return NULL;
--
1.5.3.4.1206.g5f96
^ permalink raw reply related
* Re: How to merge git://repo.or.cz/git-gui into git.git
From: Yin Ping @ 2007-10-30 2:12 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: Peter Baumann, git
In-Reply-To: <20071030005217.GT14735@spearce.org>
> You are merging in the wrong direction. You want to merge git-gui
> into git.git:
>
> git clone git://repo.or.cz/alt-git.git mygit
> cd mygit
> git pull -s subtree git://repo.or.cz/git-gui.git master
>
> So you are pulling git-gui into git, not the reverse. But yes,
> when this happens the entire history of the pulled project (in the
> above case git-gui) suddenly appears in the history of the parent
> project (in this case git). If you don't want this to happen then
> you need to make git-gui into a submodule. That has been talked
> about being done, but hasn't happened yet in the main git repository.
> git-gui is currently still being subtree merged in.
>
> --
> Shawn.
>
Ok, I see. I'm just be interested in the subtree strategy and try a
few ways and different directions to merge. And also i'm trying to
figure out which one of subtree merge and submodule is more suitable
for my project. However, the conclusion havn't come.
--
franky
^ permalink raw reply
* [PATCH 4/4 v2] Use built-in send-pack.
From: Daniel Barkalow @ 2007-10-30 2:03 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
transport.c | 51 ++++++++++-----------------------------------------
1 files changed, 10 insertions(+), 41 deletions(-)
diff --git a/transport.c b/transport.c
index 89b73dc..6b1f419 100644
--- a/transport.c
+++ b/transport.c
@@ -6,6 +6,7 @@
#endif
#include "pkt-line.h"
#include "fetch-pack.h"
+#include "send-pack.h"
#include "walker.h"
#include "bundle.h"
#include "dir.h"
@@ -653,48 +654,16 @@ static int fetch_refs_via_pack(struct transport *transport,
static int git_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) {
struct git_transport_data *data = transport->data;
- const char **argv;
- char *rem;
- int argc;
- int err;
+ struct send_pack_args args;
- argv = xmalloc((refspec_nr + 11) * sizeof(char *));
- argv[0] = "send-pack";
- argc = 1;
- if (flags & TRANSPORT_PUSH_ALL)
- argv[argc++] = "--all";
- if (flags & TRANSPORT_PUSH_FORCE)
- argv[argc++] = "--force";
- if (flags & TRANSPORT_PUSH_DRY_RUN)
- argv[argc++] = "--dry-run";
- if (data->receivepack) {
- char *rp = xmalloc(strlen(data->receivepack) + 16);
- sprintf(rp, "--receive-pack=%s", data->receivepack);
- argv[argc++] = rp;
- }
- if (data->thin)
- argv[argc++] = "--thin";
- rem = xmalloc(strlen(transport->remote->name) + 10);
- sprintf(rem, "--remote=%s", transport->remote->name);
- argv[argc++] = rem;
- argv[argc++] = transport->url;
- while (refspec_nr--)
- argv[argc++] = *refspec++;
- argv[argc] = NULL;
- err = run_command_v_opt(argv, RUN_GIT_CMD);
- switch (err) {
- case -ERR_RUN_COMMAND_FORK:
- error("unable to fork for %s", argv[0]);
- case -ERR_RUN_COMMAND_EXEC:
- error("unable to exec %s", argv[0]);
- break;
- case -ERR_RUN_COMMAND_WAITPID:
- case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
- case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
- case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
- error("%s died with strange error", argv[0]);
- }
- return !!err;
+ args.receivepack = data->receivepack;
+ args.send_all = !!(flags & TRANSPORT_PUSH_ALL);
+ args.force_update = !!(flags & TRANSPORT_PUSH_FORCE);
+ args.use_thin_pack = data->thin;
+ args.verbose = transport->verbose;
+ args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
+
+ return send_pack(&args, transport->url, transport->remote, refspec_nr, refspec);
}
static int disconnect_git(struct transport *transport)
--
1.5.3.4.1206.g5f96
^ permalink raw reply related
* [PATCH 3/4 v2] Build-in send-pack, with an API for other programs to call.
From: Daniel Barkalow @ 2007-10-30 2:03 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Also marks some more things as const, as needed.
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
Makefile | 1 +
send-pack.c => builtin-send-pack.c | 81 +++++++++++++++++++----------------
builtin.h | 1 +
git.c | 1 +
send-pack.h | 17 ++++++++
5 files changed, 64 insertions(+), 37 deletions(-)
rename send-pack.c => builtin-send-pack.c (88%)
create mode 100644 send-pack.h
diff --git a/Makefile b/Makefile
index 64ad297..8b0c8cd 100644
--- a/Makefile
+++ b/Makefile
@@ -359,6 +359,7 @@ BUILTIN_OBJS = \
builtin-push.o \
builtin-read-tree.o \
builtin-reflog.o \
+ builtin-send-pack.o \
builtin-config.o \
builtin-rerere.o \
builtin-reset.o \
diff --git a/send-pack.c b/builtin-send-pack.c
similarity index 88%
rename from send-pack.c
rename to builtin-send-pack.c
index fe56617..60a12f7 100644
--- a/send-pack.c
+++ b/builtin-send-pack.c
@@ -5,16 +5,15 @@
#include "pkt-line.h"
#include "run-command.h"
#include "remote.h"
+#include "send-pack.h"
static const char send_pack_usage[] =
"git-send-pack [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
" --all and explicit <ref> specification are mutually exclusive.";
-static const char *receivepack = "git-receive-pack";
-static int verbose;
-static int send_all;
-static int force_update;
-static int use_thin_pack;
-static int dry_run;
+
+static struct send_pack_args args = {
+ /* .receivepack = */ "git-receive-pack",
+};
/*
* Make a pack stream and spit it out into file descriptor fd
@@ -26,7 +25,7 @@ static int pack_objects(int fd, struct ref *refs)
* the revision parameters to it via its stdin and
* let its stdout go back to the other end.
*/
- const char *args[] = {
+ const char *argv[] = {
"pack-objects",
"--all-progress",
"--revs",
@@ -36,10 +35,10 @@ static int pack_objects(int fd, struct ref *refs)
};
struct child_process po;
- if (use_thin_pack)
- args[4] = "--thin";
+ if (args.use_thin_pack)
+ argv[4] = "--thin";
memset(&po, 0, sizeof(po));
- po.argv = args;
+ po.argv = argv;
po.in = -1;
po.out = fd;
po.git_cmd = 1;
@@ -178,7 +177,7 @@ static int receive_status(int in)
return ret;
}
-static int send_pack(int in, int out, struct remote *remote, int nr_refspec, const char **refspec)
+static int do_send_pack(int in, int out, struct remote *remote, int nr_refspec, const char **refspec)
{
struct ref *ref;
int new_refs;
@@ -201,7 +200,7 @@ static int send_pack(int in, int out, struct remote *remote, int nr_refspec, con
if (!remote_tail)
remote_tail = &remote_refs;
if (match_refs(local_refs, remote_refs, &remote_tail,
- nr_refspec, refspec, send_all))
+ nr_refspec, refspec, args.send_all))
return -1;
if (!remote_refs) {
@@ -230,7 +229,7 @@ static int send_pack(int in, int out, struct remote *remote, int nr_refspec, con
}
if (!will_delete_ref &&
!hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
- if (verbose)
+ if (args.verbose)
fprintf(stderr, "'%s': up-to-date\n", ref->name);
continue;
}
@@ -254,7 +253,7 @@ static int send_pack(int in, int out, struct remote *remote, int nr_refspec, con
* always allowed.
*/
- if (!force_update &&
+ if (!args.force_update &&
!will_delete_ref &&
!is_null_sha1(ref->old_sha1) &&
!ref->force) {
@@ -284,7 +283,7 @@ static int send_pack(int in, int out, struct remote *remote, int nr_refspec, con
strcpy(old_hex, sha1_to_hex(ref->old_sha1));
new_hex = sha1_to_hex(ref->new_sha1);
- if (!dry_run) {
+ if (!args.dry_run) {
if (ask_for_status_report) {
packet_write(out, "%s %s %s%c%s",
old_hex, new_hex, ref->name, 0,
@@ -306,7 +305,7 @@ static int send_pack(int in, int out, struct remote *remote, int nr_refspec, con
fprintf(stderr, "\n from %s\n to %s\n",
old_hex, new_hex);
}
- if (remote && !dry_run) {
+ if (remote && !args.dry_run) {
struct refspec rs;
rs.src = ref->name;
rs.dst = NULL;
@@ -325,7 +324,7 @@ static int send_pack(int in, int out, struct remote *remote, int nr_refspec, con
}
packet_flush(out);
- if (new_refs && !dry_run)
+ if (new_refs && !args.dry_run)
ret = pack_objects(out, remote_refs);
close(out);
@@ -360,30 +359,25 @@ static void verify_remote_names(int nr_heads, const char **heads)
}
}
-int main(int argc, char **argv)
+int cmd_send_pack(int argc, const char **argv, const char *prefix)
{
int i, nr_heads = 0;
- char *dest = NULL;
const char **heads = NULL;
- int fd[2], ret;
- pid_t pid;
- char *remote_name = NULL;
+ const char *remote_name = NULL;
struct remote *remote = NULL;
-
- setup_git_directory();
- git_config(git_default_config);
+ const char *dest = NULL;
argv++;
for (i = 1; i < argc; i++, argv++) {
- char *arg = *argv;
+ const char *arg = *argv;
if (*arg == '-') {
if (!prefixcmp(arg, "--receive-pack=")) {
- receivepack = arg + 15;
+ args.receivepack = arg + 15;
continue;
}
if (!prefixcmp(arg, "--exec=")) {
- receivepack = arg + 7;
+ args.receivepack = arg + 7;
continue;
}
if (!prefixcmp(arg, "--remote=")) {
@@ -391,23 +385,23 @@ int main(int argc, char **argv)
continue;
}
if (!strcmp(arg, "--all")) {
- send_all = 1;
+ args.send_all = 1;
continue;
}
if (!strcmp(arg, "--dry-run")) {
- dry_run = 1;
+ args.dry_run = 1;
continue;
}
if (!strcmp(arg, "--force")) {
- force_update = 1;
+ args.force_update = 1;
continue;
}
if (!strcmp(arg, "--verbose")) {
- verbose = 1;
+ args.verbose = 1;
continue;
}
if (!strcmp(arg, "--thin")) {
- use_thin_pack = 1;
+ args.use_thin_pack = 1;
continue;
}
usage(send_pack_usage);
@@ -422,9 +416,8 @@ int main(int argc, char **argv)
}
if (!dest)
usage(send_pack_usage);
- if (heads && send_all)
+ if (heads && args.send_all)
usage(send_pack_usage);
- verify_remote_names(nr_heads, heads);
if (remote_name) {
remote = remote_get(remote_name);
@@ -434,10 +427,24 @@ int main(int argc, char **argv)
}
}
- pid = git_connect(fd, dest, receivepack, verbose ? CONNECT_VERBOSE : 0);
+ return send_pack(&args, dest, remote, nr_heads, heads);
+}
+
+int send_pack(struct send_pack_args *my_args,
+ const char *dest, struct remote *remote,
+ int nr_heads, const char **heads)
+{
+ int fd[2], ret;
+ pid_t pid;
+
+ memcpy(&args, my_args, sizeof(args));
+
+ verify_remote_names(nr_heads, heads);
+
+ pid = git_connect(fd, dest, args.receivepack, args.verbose ? CONNECT_VERBOSE : 0);
if (pid < 0)
return 1;
- ret = send_pack(fd[0], fd[1], remote, nr_heads, heads);
+ ret = do_send_pack(fd[0], fd[1], remote, nr_heads, heads);
close(fd[0]);
close(fd[1]);
ret |= finish_connect(pid);
diff --git a/builtin.h b/builtin.h
index ff84835..51747c7 100644
--- a/builtin.h
+++ b/builtin.h
@@ -69,6 +69,7 @@ extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
extern int cmd_revert(int argc, const char **argv, const char *prefix);
extern int cmd_rm(int argc, const char **argv, const char *prefix);
extern int cmd_runstatus(int argc, const char **argv, const char *prefix);
+extern int cmd_send_pack(int argc, const char **argv, const char *prefix);
extern int cmd_shortlog(int argc, const char **argv, const char *prefix);
extern int cmd_show(int argc, const char **argv, const char *prefix);
extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
diff --git a/git.c b/git.c
index 1b182e2..4893a85 100644
--- a/git.c
+++ b/git.c
@@ -370,6 +370,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
{ "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE },
{ "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
+ { "send-pack", cmd_send_pack, RUN_SETUP },
{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
{ "show-branch", cmd_show_branch, RUN_SETUP },
{ "show", cmd_show, RUN_SETUP | USE_PAGER },
diff --git a/send-pack.h b/send-pack.h
new file mode 100644
index 0000000..7a24f71
--- /dev/null
+++ b/send-pack.h
@@ -0,0 +1,17 @@
+#ifndef SEND_PACK_H
+#define SEND_PACK_H
+
+struct send_pack_args {
+ const char *receivepack;
+ unsigned verbose:1,
+ send_all:1,
+ force_update:1,
+ use_thin_pack:1,
+ dry_run:1;
+};
+
+int send_pack(struct send_pack_args *args,
+ const char *dest, struct remote *remote,
+ int nr_heads, const char **heads);
+
+#endif
--
1.5.3.4.1206.g5f96
^ permalink raw reply related
* Re: [PATCH 3/4] Build-in send-pack, with an API for other programs to call.
From: Daniel Barkalow @ 2007-10-30 1:19 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: Junio C Hamano, git
In-Reply-To: <20071030011401.GU14735@spearce.org>
On Mon, 29 Oct 2007, Shawn O. Pearce wrote:
> Daniel Barkalow <barkalow@iabervon.org> wrote:
> > -int main(int argc, char **argv)
> > +void setup_send_pack(struct send_pack_args *args)
> > +{
> > + receivepack = args->receivepack;
> > + verbose = args->verbose;
> > + send_all = args->send_all;
> > + force_update = args->force_update;
> > + use_thin_pack = args->use_thin_pack;
> > + dry_run = args->dry_run;
> > +}
> ...
> > +struct send_pack_args {
> > + const char *receivepack;
> > + int verbose;
> > + int send_all;
> > + int force_update;
> > + int use_thin_pack;
> > + int dry_run;
> > +};
> > +
>
> Ick. How about doing what I did with builtin-fetch-pack.c which
> was to copy the args into a global "static struct fetch_pack_args"
> and make the struct a bitfield with these boolean items as ":1"
> rather than a full int?
Yeah, that's better. I'll respin parts 3 and 4 that way.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: [PATCH 3/4] Build-in send-pack, with an API for other programs to call.
From: Shawn O. Pearce @ 2007-10-30 1:18 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: Junio C Hamano, git
In-Reply-To: <20071030011401.GU14735@spearce.org>
"Shawn O. Pearce" <spearce@spearce.org> wrote:
> Daniel Barkalow <barkalow@iabervon.org> wrote:
> > -int main(int argc, char **argv)
> > +void setup_send_pack(struct send_pack_args *args)
> > +{
> > + receivepack = args->receivepack;
> > + verbose = args->verbose;
> > + send_all = args->send_all;
> > + force_update = args->force_update;
> > + use_thin_pack = args->use_thin_pack;
> > + dry_run = args->dry_run;
> > +}
> ...
> > +struct send_pack_args {
> > + const char *receivepack;
> > + int verbose;
> > + int send_all;
> > + int force_update;
> > + int use_thin_pack;
> > + int dry_run;
> > +};
> > +
>
> Ick. How about doing what I did with builtin-fetch-pack.c [...]
To be more precise please refer to the following fetch-pack changes:
fa74052922: Always obtain fetch-pack arguments from struct fetch_pack_args
bbaf458428: Use 'unsigned:1' when we mean boolean options
--
Shawn.
^ permalink raw reply
* Re: [PATCH 3/4] Build-in send-pack, with an API for other programs to call.
From: Shawn O. Pearce @ 2007-10-30 1:14 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.64.0710292049350.7357@iabervon.org>
Daniel Barkalow <barkalow@iabervon.org> wrote:
> -int main(int argc, char **argv)
> +void setup_send_pack(struct send_pack_args *args)
> +{
> + receivepack = args->receivepack;
> + verbose = args->verbose;
> + send_all = args->send_all;
> + force_update = args->force_update;
> + use_thin_pack = args->use_thin_pack;
> + dry_run = args->dry_run;
> +}
...
> +struct send_pack_args {
> + const char *receivepack;
> + int verbose;
> + int send_all;
> + int force_update;
> + int use_thin_pack;
> + int dry_run;
> +};
> +
Ick. How about doing what I did with builtin-fetch-pack.c which
was to copy the args into a global "static struct fetch_pack_args"
and make the struct a bitfield with these boolean items as ":1"
rather than a full int?
--
Shawn.
^ permalink raw reply
* [PATCH 4/4] Use built-in send-pack.
From: Daniel Barkalow @ 2007-10-30 1:05 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
transport.c | 53 ++++++++++++-----------------------------------------
1 files changed, 12 insertions(+), 41 deletions(-)
diff --git a/transport.c b/transport.c
index 89b73dc..e4344b8 100644
--- a/transport.c
+++ b/transport.c
@@ -6,6 +6,7 @@
#endif
#include "pkt-line.h"
#include "fetch-pack.h"
+#include "send-pack.h"
#include "walker.h"
#include "bundle.h"
#include "dir.h"
@@ -653,48 +654,18 @@ static int fetch_refs_via_pack(struct transport *transport,
static int git_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) {
struct git_transport_data *data = transport->data;
- const char **argv;
- char *rem;
- int argc;
- int err;
+ struct send_pack_args args;
- argv = xmalloc((refspec_nr + 11) * sizeof(char *));
- argv[0] = "send-pack";
- argc = 1;
- if (flags & TRANSPORT_PUSH_ALL)
- argv[argc++] = "--all";
- if (flags & TRANSPORT_PUSH_FORCE)
- argv[argc++] = "--force";
- if (flags & TRANSPORT_PUSH_DRY_RUN)
- argv[argc++] = "--dry-run";
- if (data->receivepack) {
- char *rp = xmalloc(strlen(data->receivepack) + 16);
- sprintf(rp, "--receive-pack=%s", data->receivepack);
- argv[argc++] = rp;
- }
- if (data->thin)
- argv[argc++] = "--thin";
- rem = xmalloc(strlen(transport->remote->name) + 10);
- sprintf(rem, "--remote=%s", transport->remote->name);
- argv[argc++] = rem;
- argv[argc++] = transport->url;
- while (refspec_nr--)
- argv[argc++] = *refspec++;
- argv[argc] = NULL;
- err = run_command_v_opt(argv, RUN_GIT_CMD);
- switch (err) {
- case -ERR_RUN_COMMAND_FORK:
- error("unable to fork for %s", argv[0]);
- case -ERR_RUN_COMMAND_EXEC:
- error("unable to exec %s", argv[0]);
- break;
- case -ERR_RUN_COMMAND_WAITPID:
- case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
- case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
- case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
- error("%s died with strange error", argv[0]);
- }
- return !!err;
+ args.receivepack = data->receivepack;
+ args.send_all = !!(flags & TRANSPORT_PUSH_ALL);
+ args.force_update = !!(flags & TRANSPORT_PUSH_FORCE);
+ args.use_thin_pack = data->thin;
+ args.verbose = transport->verbose;
+ args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
+
+ setup_send_pack(&args);
+
+ return send_pack(transport->url, transport->remote, refspec_nr, refspec);
}
static int disconnect_git(struct transport *transport)
--
1.5.3.4.1206.g5f96
^ permalink raw reply related
* [PATCH 3/4] Build-in send-pack, with an API for other programs to call.
From: Daniel Barkalow @ 2007-10-30 1:05 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Also marks some more things as const, as needed.
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
Makefile | 1 +
send-pack.c => builtin-send-pack.c | 40 +++++++++++++++++++++++++----------
builtin.h | 1 +
git.c | 1 +
send-pack.h | 18 ++++++++++++++++
5 files changed, 49 insertions(+), 12 deletions(-)
rename send-pack.c => builtin-send-pack.c (93%)
create mode 100644 send-pack.h
diff --git a/Makefile b/Makefile
index 64ad297..8b0c8cd 100644
--- a/Makefile
+++ b/Makefile
@@ -359,6 +359,7 @@ BUILTIN_OBJS = \
builtin-push.o \
builtin-read-tree.o \
builtin-reflog.o \
+ builtin-send-pack.o \
builtin-config.o \
builtin-rerere.o \
builtin-reset.o \
diff --git a/send-pack.c b/builtin-send-pack.c
similarity index 93%
rename from send-pack.c
rename to builtin-send-pack.c
index fe56617..931f994 100644
--- a/send-pack.c
+++ b/builtin-send-pack.c
@@ -5,6 +5,7 @@
#include "pkt-line.h"
#include "run-command.h"
#include "remote.h"
+#include "send-pack.h"
static const char send_pack_usage[] =
"git-send-pack [--all] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
@@ -178,7 +179,7 @@ static int receive_status(int in)
return ret;
}
-static int send_pack(int in, int out, struct remote *remote, int nr_refspec, const char **refspec)
+static int do_send_pack(int in, int out, struct remote *remote, int nr_refspec, const char **refspec)
{
struct ref *ref;
int new_refs;
@@ -360,22 +361,27 @@ static void verify_remote_names(int nr_heads, const char **heads)
}
}
-int main(int argc, char **argv)
+void setup_send_pack(struct send_pack_args *args)
+{
+ receivepack = args->receivepack;
+ verbose = args->verbose;
+ send_all = args->send_all;
+ force_update = args->force_update;
+ use_thin_pack = args->use_thin_pack;
+ dry_run = args->dry_run;
+}
+
+int cmd_send_pack(int argc, const char **argv, const char *prefix)
{
int i, nr_heads = 0;
- char *dest = NULL;
const char **heads = NULL;
- int fd[2], ret;
- pid_t pid;
- char *remote_name = NULL;
+ const char *remote_name = NULL;
struct remote *remote = NULL;
-
- setup_git_directory();
- git_config(git_default_config);
+ const char *dest = NULL;
argv++;
for (i = 1; i < argc; i++, argv++) {
- char *arg = *argv;
+ const char *arg = *argv;
if (*arg == '-') {
if (!prefixcmp(arg, "--receive-pack=")) {
@@ -424,7 +430,6 @@ int main(int argc, char **argv)
usage(send_pack_usage);
if (heads && send_all)
usage(send_pack_usage);
- verify_remote_names(nr_heads, heads);
if (remote_name) {
remote = remote_get(remote_name);
@@ -434,10 +439,21 @@ int main(int argc, char **argv)
}
}
+ return send_pack(dest, remote, nr_heads, heads);
+}
+
+int send_pack(const char *dest, struct remote *remote,
+ int nr_heads, const char **heads)
+{
+ int fd[2], ret;
+ pid_t pid;
+
+ verify_remote_names(nr_heads, heads);
+
pid = git_connect(fd, dest, receivepack, verbose ? CONNECT_VERBOSE : 0);
if (pid < 0)
return 1;
- ret = send_pack(fd[0], fd[1], remote, nr_heads, heads);
+ ret = do_send_pack(fd[0], fd[1], remote, nr_heads, heads);
close(fd[0]);
close(fd[1]);
ret |= finish_connect(pid);
diff --git a/builtin.h b/builtin.h
index ff84835..51747c7 100644
--- a/builtin.h
+++ b/builtin.h
@@ -69,6 +69,7 @@ extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
extern int cmd_revert(int argc, const char **argv, const char *prefix);
extern int cmd_rm(int argc, const char **argv, const char *prefix);
extern int cmd_runstatus(int argc, const char **argv, const char *prefix);
+extern int cmd_send_pack(int argc, const char **argv, const char *prefix);
extern int cmd_shortlog(int argc, const char **argv, const char *prefix);
extern int cmd_show(int argc, const char **argv, const char *prefix);
extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
diff --git a/git.c b/git.c
index 1b182e2..4893a85 100644
--- a/git.c
+++ b/git.c
@@ -370,6 +370,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
{ "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE },
{ "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
+ { "send-pack", cmd_send_pack, RUN_SETUP },
{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
{ "show-branch", cmd_show_branch, RUN_SETUP },
{ "show", cmd_show, RUN_SETUP | USE_PAGER },
diff --git a/send-pack.h b/send-pack.h
new file mode 100644
index 0000000..22b0624
--- /dev/null
+++ b/send-pack.h
@@ -0,0 +1,18 @@
+#ifndef SEND_PACK_H
+#define SEND_PACK_H
+
+struct send_pack_args {
+ const char *receivepack;
+ int verbose;
+ int send_all;
+ int force_update;
+ int use_thin_pack;
+ int dry_run;
+};
+
+void setup_send_pack(struct send_pack_args *args);
+
+int send_pack(const char *dest, struct remote *remote,
+ int nr_heads, const char **heads);
+
+#endif
--
1.5.3.4.1206.g5f96
^ permalink raw reply related
* [PATCH 1/4] Miscellaneous const changes and utilities
From: Daniel Barkalow @ 2007-10-30 1:05 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
The list of remote refs in struct transport should be const, because
builtin-fetch will get confused if it changes.
The url in git_connect should be const (and work on a copy) instead of
requiring the caller to copy it.
match_refs doesn't modify the refspecs it gets.
get_fetch_map and get_remote_ref don't change the list they get.
Allow transport get_refs_list methods to modify the struct transport.
Add a function to copy a list of refs, when a function needs a mutable
copy of a const list.
Add a function to check the type of a ref, as per the code in connect.c
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
builtin-fetch.c | 10 +++++-----
cache.h | 2 +-
connect.c | 10 +++++++++-
http-push.c | 2 +-
remote.c | 32 ++++++++++++++++++++++----------
remote.h | 10 +++++++---
send-pack.c | 8 ++++----
transport.c | 10 +++++-----
transport.h | 6 +++---
9 files changed, 57 insertions(+), 33 deletions(-)
diff --git a/builtin-fetch.c b/builtin-fetch.c
index b9d2b0c..fb64353 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -29,7 +29,7 @@ static void unlock_pack_on_signal(int signo)
}
static void add_merge_config(struct ref **head,
- struct ref *remote_refs,
+ const struct ref *remote_refs,
struct branch *branch,
struct ref ***tail)
{
@@ -71,7 +71,7 @@ static struct ref *get_ref_map(struct transport *transport,
struct ref *ref_map = NULL;
struct ref **tail = &ref_map;
- struct ref *remote_refs = transport_get_remote_refs(transport);
+ const struct ref *remote_refs = transport_get_remote_refs(transport);
if (ref_count || tags) {
for (i = 0; i < ref_count; i++) {
@@ -337,12 +337,12 @@ static struct ref *find_non_local_tags(struct transport *transport,
struct path_list new_refs = { NULL, 0, 0, 1 };
char *ref_name;
int ref_name_len;
- unsigned char *ref_sha1;
- struct ref *tag_ref;
+ const unsigned char *ref_sha1;
+ const struct ref *tag_ref;
struct ref *rm = NULL;
struct ref *ref_map = NULL;
struct ref **tail = &ref_map;
- struct ref *ref;
+ const struct ref *ref;
for_each_ref(add_existing, &existing_refs);
for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) {
diff --git a/cache.h b/cache.h
index 27485d3..0e3848d 100644
--- a/cache.h
+++ b/cache.h
@@ -503,7 +503,7 @@ struct ref {
#define REF_TAGS (1u << 2)
#define CONNECT_VERBOSE (1u << 0)
-extern pid_t git_connect(int fd[2], char *url, const char *prog, int flags);
+extern pid_t git_connect(int fd[2], const char *url, const char *prog, int flags);
extern int finish_connect(pid_t pid);
extern int path_match(const char *path, int nr, char **match);
extern int get_ack(int fd, unsigned char *result_sha1);
diff --git a/connect.c b/connect.c
index 3d5c4ab..2d62ea9 100644
--- a/connect.c
+++ b/connect.c
@@ -36,6 +36,11 @@ static int check_ref(const char *name, int len, unsigned int flags)
return !(flags & ~REF_NORMAL);
}
+int check_ref_type(const struct ref *ref, int flags)
+{
+ return check_ref(ref->name, strlen(ref->name), flags);
+}
+
/*
* Read all the refs from the other end
*/
@@ -476,8 +481,9 @@ char *get_port(char *host)
*
* Does not return a negative value on error; it just dies.
*/
-pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
+pid_t git_connect(int fd[2], const char *url_orig, const char *prog, int flags)
{
+ char *url = xstrdup(url_orig);
char *host, *path = url;
char *end;
int c;
@@ -566,6 +572,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
prog, path, 0,
target_host, 0);
free(target_host);
+ free(url);
if (free_path)
free(path);
return 0;
@@ -623,6 +630,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
fd[1] = pipefd[1][1];
close(pipefd[0][1]);
close(pipefd[1][0]);
+ free(url);
if (free_path)
free(path);
return pid;
diff --git a/http-push.c b/http-push.c
index c02a3af..f461bb3 100644
--- a/http-push.c
+++ b/http-push.c
@@ -2389,7 +2389,7 @@ int main(int argc, char **argv)
if (!remote_tail)
remote_tail = &remote_refs;
if (match_refs(local_refs, remote_refs, &remote_tail,
- nr_refspec, refspec, push_all))
+ nr_refspec, (const char **) refspec, push_all))
return -1;
if (!remote_refs) {
fprintf(stderr, "No refs in common and none specified; doing nothing.\n");
diff --git a/remote.c b/remote.c
index 170015a..ec89c97 100644
--- a/remote.c
+++ b/remote.c
@@ -485,7 +485,7 @@ struct ref *alloc_ref(unsigned namelen)
return ret;
}
-static struct ref *copy_ref(struct ref *ref)
+static struct ref *copy_ref(const struct ref *ref)
{
struct ref *ret = xmalloc(sizeof(struct ref) + strlen(ref->name) + 1);
memcpy(ret, ref, sizeof(struct ref) + strlen(ref->name) + 1);
@@ -493,6 +493,18 @@ static struct ref *copy_ref(struct ref *ref)
return ret;
}
+struct ref *copy_ref_list(const struct ref *ref)
+{
+ struct ref *ret = NULL;
+ struct ref **tail = &ret;
+ while (ref) {
+ *tail = copy_ref(ref);
+ ref = ref->next;
+ tail = &((*tail)->next);
+ }
+ return ret;
+}
+
void free_refs(struct ref *ref)
{
struct ref *next;
@@ -710,7 +722,7 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
* without thinking.
*/
int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
- int nr_refspec, char **refspec, int all)
+ int nr_refspec, const char **refspec, int all)
{
struct refspec *rs =
parse_ref_spec(nr_refspec, (const char **) refspec);
@@ -810,10 +822,10 @@ int branch_merge_matches(struct branch *branch,
return ref_matches_abbrev(branch->merge[i]->src, refname);
}
-static struct ref *get_expanded_map(struct ref *remote_refs,
+static struct ref *get_expanded_map(const struct ref *remote_refs,
const struct refspec *refspec)
{
- struct ref *ref;
+ const struct ref *ref;
struct ref *ret = NULL;
struct ref **tail = &ret;
@@ -824,7 +836,7 @@ static struct ref *get_expanded_map(struct ref *remote_refs,
if (strchr(ref->name, '^'))
continue; /* a dereference item */
if (!prefixcmp(ref->name, refspec->src)) {
- char *match;
+ const char *match;
struct ref *cpy = copy_ref(ref);
match = ref->name + remote_prefix_len;
@@ -842,9 +854,9 @@ static struct ref *get_expanded_map(struct ref *remote_refs,
return ret;
}
-static struct ref *find_ref_by_name_abbrev(struct ref *refs, const char *name)
+static const struct ref *find_ref_by_name_abbrev(const struct ref *refs, const char *name)
{
- struct ref *ref;
+ const struct ref *ref;
for (ref = refs; ref; ref = ref->next) {
if (ref_matches_abbrev(name, ref->name))
return ref;
@@ -852,9 +864,9 @@ static struct ref *find_ref_by_name_abbrev(struct ref *refs, const char *name)
return NULL;
}
-struct ref *get_remote_ref(struct ref *remote_refs, const char *name)
+struct ref *get_remote_ref(const struct ref *remote_refs, const char *name)
{
- struct ref *ref = find_ref_by_name_abbrev(remote_refs, name);
+ const struct ref *ref = find_ref_by_name_abbrev(remote_refs, name);
if (!ref)
die("Couldn't find remote ref %s\n", name);
@@ -887,7 +899,7 @@ static struct ref *get_local_ref(const char *name)
return ret;
}
-int get_fetch_map(struct ref *remote_refs,
+int get_fetch_map(const struct ref *remote_refs,
const struct refspec *refspec,
struct ref ***tail)
{
diff --git a/remote.h b/remote.h
index c62636d..723c21a 100644
--- a/remote.h
+++ b/remote.h
@@ -44,6 +44,10 @@ struct refspec {
struct ref *alloc_ref(unsigned namelen);
+struct ref *copy_ref_list(const struct ref *ref);
+
+int check_ref_type(const struct ref *ref, int flags);
+
/*
* Frees the entire list and peers of elements.
*/
@@ -57,7 +61,7 @@ void ref_remove_duplicates(struct ref *ref_map);
struct refspec *parse_ref_spec(int nr_refspec, const char **refspec);
int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
- int nr_refspec, char **refspec, int all);
+ int nr_refspec, const char **refspec, int all);
/*
* Given a list of the remote refs and the specification of things to
@@ -68,10 +72,10 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
* beforehand, and will be set to the tail pointer of the list of
* results afterward.
*/
-int get_fetch_map(struct ref *remote_refs, const struct refspec *refspec,
+int get_fetch_map(const struct ref *remote_refs, const struct refspec *refspec,
struct ref ***tail);
-struct ref *get_remote_ref(struct ref *remote_refs, const char *name);
+struct ref *get_remote_ref(const struct ref *remote_refs, const char *name);
/*
* For the given remote, reads the refspec's src and sets the other fields.
diff --git a/send-pack.c b/send-pack.c
index e9b9a39..fe56617 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -178,7 +178,7 @@ static int receive_status(int in)
return ret;
}
-static int send_pack(int in, int out, struct remote *remote, int nr_refspec, char **refspec)
+static int send_pack(int in, int out, struct remote *remote, int nr_refspec, const char **refspec)
{
struct ref *ref;
int new_refs;
@@ -339,7 +339,7 @@ static int send_pack(int in, int out, struct remote *remote, int nr_refspec, cha
return ret;
}
-static void verify_remote_names(int nr_heads, char **heads)
+static void verify_remote_names(int nr_heads, const char **heads)
{
int i;
@@ -364,7 +364,7 @@ int main(int argc, char **argv)
{
int i, nr_heads = 0;
char *dest = NULL;
- char **heads = NULL;
+ const char **heads = NULL;
int fd[2], ret;
pid_t pid;
char *remote_name = NULL;
@@ -416,7 +416,7 @@ int main(int argc, char **argv)
dest = arg;
continue;
}
- heads = argv;
+ heads = (const char **) argv;
nr_heads = argc - i;
break;
}
diff --git a/transport.c b/transport.c
index 400af71..89b73dc 100644
--- a/transport.c
+++ b/transport.c
@@ -141,7 +141,7 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list)
}
}
-static struct ref *get_refs_via_rsync(const struct transport *transport)
+static struct ref *get_refs_via_rsync(struct transport *transport)
{
struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
struct ref dummy, *tail = &dummy;
@@ -427,7 +427,7 @@ static int missing__target(int code, int result)
#define missing_target(a) missing__target((a)->http_code, (a)->curl_result)
-static struct ref *get_refs_via_curl(const struct transport *transport)
+static struct ref *get_refs_via_curl(struct transport *transport)
{
struct buffer buffer;
char *data, *start, *mid;
@@ -524,7 +524,7 @@ struct bundle_transport_data {
struct bundle_header header;
};
-static struct ref *get_refs_from_bundle(const struct transport *transport)
+static struct ref *get_refs_from_bundle(struct transport *transport)
{
struct bundle_transport_data *data = transport->data;
struct ref *result = NULL;
@@ -596,7 +596,7 @@ static int set_git_option(struct transport *connection,
return 1;
}
-static struct ref *get_refs_via_connect(const struct transport *transport)
+static struct ref *get_refs_via_connect(struct transport *transport)
{
struct git_transport_data *data = transport->data;
struct ref *refs;
@@ -786,7 +786,7 @@ int transport_push(struct transport *transport,
return transport->push(transport, refspec_nr, refspec, flags);
}
-struct ref *transport_get_remote_refs(struct transport *transport)
+const struct ref *transport_get_remote_refs(struct transport *transport)
{
if (!transport->remote_refs)
transport->remote_refs = transport->get_refs_list(transport);
diff --git a/transport.h b/transport.h
index df12ea7..d27f562 100644
--- a/transport.h
+++ b/transport.h
@@ -8,7 +8,7 @@ struct transport {
struct remote *remote;
const char *url;
void *data;
- struct ref *remote_refs;
+ const struct ref *remote_refs;
/**
* Returns 0 if successful, positive if the option is not
@@ -18,7 +18,7 @@ struct transport {
int (*set_option)(struct transport *connection, const char *name,
const char *value);
- struct ref *(*get_refs_list)(const struct transport *transport);
+ struct ref *(*get_refs_list)(struct transport *transport);
int (*fetch)(struct transport *transport, int refs_nr, struct ref **refs);
int (*push)(struct transport *connection, int refspec_nr, const char **refspec, int flags);
@@ -61,7 +61,7 @@ int transport_set_option(struct transport *transport, const char *name,
int transport_push(struct transport *connection,
int refspec_nr, const char **refspec, int flags);
-struct ref *transport_get_remote_refs(struct transport *transport);
+const struct ref *transport_get_remote_refs(struct transport *transport);
int transport_fetch_refs(struct transport *transport, struct ref *refs);
void transport_unlock_pack(struct transport *transport);
--
1.5.3.4.1206.g5f96
^ permalink raw reply related
* [PATCH 2/4] Build-in peek-remote, using transport infrastructure.
From: Daniel Barkalow @ 2007-10-30 1:05 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
Makefile | 3 +-
peek-remote.c => builtin-peek-remote.c | 55 ++++++++++++++-----------------
builtin.h | 1 +
git.c | 1 +
4 files changed, 29 insertions(+), 31 deletions(-)
rename peek-remote.c => builtin-peek-remote.c (59%)
diff --git a/Makefile b/Makefile
index 72f5ef4..64ad297 100644
--- a/Makefile
+++ b/Makefile
@@ -240,7 +240,7 @@ PROGRAMS = \
git-fast-import$X \
git-daemon$X \
git-merge-index$X git-mktag$X git-mktree$X git-patch-id$X \
- git-peek-remote$X git-receive-pack$X \
+ git-receive-pack$X \
git-send-pack$X git-shell$X \
git-show-index$X \
git-unpack-file$X \
@@ -353,6 +353,7 @@ BUILTIN_OBJS = \
builtin-mv.o \
builtin-name-rev.o \
builtin-pack-objects.o \
+ builtin-peek-remote.o \
builtin-prune.o \
builtin-prune-packed.o \
builtin-push.o \
diff --git a/peek-remote.c b/builtin-peek-remote.c
similarity index 59%
rename from peek-remote.c
rename to builtin-peek-remote.c
index ceb7871..b4106f5 100644
--- a/peek-remote.c
+++ b/builtin-peek-remote.c
@@ -1,38 +1,26 @@
+#include "builtin.h"
#include "cache.h"
-#include "refs.h"
-#include "pkt-line.h"
+#include "transport.h"
+#include "remote.h"
static const char peek_remote_usage[] =
"git-peek-remote [--upload-pack=<git-upload-pack>] [<host>:]<directory>";
-static const char *uploadpack = "git-upload-pack";
-static int peek_remote(int fd[2], unsigned flags)
+int cmd_peek_remote(int argc, const char **argv, const char *prefix)
{
- struct ref *ref;
-
- get_remote_heads(fd[0], &ref, 0, NULL, flags);
- packet_flush(fd[1]);
-
- while (ref) {
- printf("%s %s\n", sha1_to_hex(ref->old_sha1), ref->name);
- ref = ref->next;
- }
- return 0;
-}
-
-int main(int argc, char **argv)
-{
- int i, ret;
- char *dest = NULL;
- int fd[2];
- pid_t pid;
+ int i;
+ const char *dest = NULL;
int nongit = 0;
unsigned flags = 0;
+ const char *uploadpack = NULL;
+
+ struct transport *transport;
+ const struct ref *ref;
setup_git_directory_gently(&nongit);
for (i = 1; i < argc; i++) {
- char *arg = argv[i];
+ const char *arg = argv[i];
if (*arg == '-') {
if (!prefixcmp(arg, "--upload-pack=")) {
@@ -64,12 +52,19 @@ int main(int argc, char **argv)
if (!dest || i != argc - 1)
usage(peek_remote_usage);
- pid = git_connect(fd, dest, uploadpack, 0);
- if (pid < 0)
+ transport = transport_get(NULL, dest);
+ if (uploadpack != NULL)
+ transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
+
+ ref = transport_get_remote_refs(transport);
+
+ if (!ref)
return 1;
- ret = peek_remote(fd, flags);
- close(fd[0]);
- close(fd[1]);
- ret |= finish_connect(pid);
- return !!ret;
+
+ while (ref) {
+ if (check_ref_type(ref, flags))
+ printf("%s %s\n", sha1_to_hex(ref->old_sha1), ref->name);
+ ref = ref->next;
+ }
+ return 0;
}
diff --git a/builtin.h b/builtin.h
index 65cc0fb..ff84835 100644
--- a/builtin.h
+++ b/builtin.h
@@ -54,6 +54,7 @@ extern int cmd_merge_file(int argc, const char **argv, const char *prefix);
extern int cmd_mv(int argc, const char **argv, const char *prefix);
extern int cmd_name_rev(int argc, const char **argv, const char *prefix);
extern int cmd_pack_objects(int argc, const char **argv, const char *prefix);
+extern int cmd_peek_remote(int argc, const char **argv, const char *prefix);
extern int cmd_pickaxe(int argc, const char **argv, const char *prefix);
extern int cmd_prune(int argc, const char **argv, const char *prefix);
extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
diff --git a/git.c b/git.c
index 23a430c..1b182e2 100644
--- a/git.c
+++ b/git.c
@@ -355,6 +355,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
{ "name-rev", cmd_name_rev, RUN_SETUP },
{ "pack-objects", cmd_pack_objects, RUN_SETUP },
+ { "peek-remote", cmd_peek_remote },
{ "pickaxe", cmd_blame, RUN_SETUP },
{ "prune", cmd_prune, RUN_SETUP },
{ "prune-packed", cmd_prune_packed, RUN_SETUP },
--
1.5.3.4.1206.g5f96
^ permalink raw reply related
* [PATCH 0/4] Build in some more things
From: Daniel Barkalow @ 2007-10-30 1:05 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
The main effect of this series is removing the fork/exec from pushing via
the git protocol (aside from the later fork/exec in connect.c of course).
It also heads off some tempting transport-related fetch bugs, which I will
not introduce in a later patch.
* Miscellaneous const changes and utilities
Adds two small utility functions, and marks a bunch of stuff as const;
the const stuff is to keep builtin-fetch from getting messed up without
a warning, because it wants some lists not to change.
* Build-in peek-remote, using transport infrastructure.
* Build-in send-pack, with an API for other programs to call.
* Use built-in send-pack.
Makefile | 4 ++-
builtin-fetch.c | 10 +++---
peek-remote.c => builtin-peek-remote.c | 55 +++++++++++++---------------
send-pack.c => builtin-send-pack.c | 46 ++++++++++++++++--------
builtin.h | 2 +
cache.h | 2 +-
connect.c | 10 +++++-
git.c | 2 +
http-push.c | 2 +-
remote.c | 32 +++++++++++-----
remote.h | 10 ++++--
send-pack.h | 18 +++++++++
transport.c | 63 +++++++++-----------------------
transport.h | 6 ++--
14 files changed, 146 insertions(+), 116 deletions(-)
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: How to merge git://repo.or.cz/git-gui into git.git
From: Shawn O. Pearce @ 2007-10-30 0:52 UTC (permalink / raw)
To: Yin Ping; +Cc: Peter Baumann, git
In-Reply-To: <46dff0320710282345r2922ac7dj9c7a4eb3e20fd011@mail.gmail.com>
Yin Ping <pkufranky@gmail.com> wrote:
> On 10/28/07, Peter Baumann <waste.manager@gmx.de> wrote:
> >
> > Have a look at the subtree merge strategy [1] and at the following
> > explanations how git-gui got initally merged.
> >
> > -Peter
> >
> > [1]: http://www.gelato.unsw.edu.au/archives/git/0702/40139.html
> > [2]: http://www.gelato.unsw.edu.au/archives/git/0702/39661.html
>
> When i merged git.git into git-gui with subtree strategy, I found all
> histories of git.git merged into histories of git-gui (from 584
> history entries to 11985). Is it possible that only histories related
> to git-gui subdirectory in git.git(i.e. histories displayed by git-log
> git-gui) are merged into?
>
> 2. pull with subtree strategy
> ~/git-gui$ git-pull -s subtree git master:master
You are merging in the wrong direction. You want to merge git-gui
into git.git:
git clone git://repo.or.cz/alt-git.git mygit
cd mygit
git pull -s subtree git://repo.or.cz/git-gui.git master
So you are pulling git-gui into git, not the reverse. But yes,
when this happens the entire history of the pulled project (in the
above case git-gui) suddenly appears in the history of the parent
project (in this case git). If you don't want this to happen then
you need to make git-gui into a submodule. That has been talked
about being done, but hasn't happened yet in the main git repository.
git-gui is currently still being subtree merged in.
--
Shawn.
^ permalink raw reply
* Re: backup or mirror a repository
From: Johannes Schindelin @ 2007-10-30 0:33 UTC (permalink / raw)
To: Dmitry Potapov; +Cc: Dan Farina, Junio C Hamano, git
In-Reply-To: <20071018053226.GA20588@dpotapov.dyndns.org>
Hi,
On Thu, 18 Oct 2007, Dmitry Potapov wrote:
> On Thu, Sep 27, 2007 at 11:27:06PM -0700, Junio C Hamano wrote:
> > The "git remote add --mirror" setup is about setting up the
> > local repository _AS_ the backup of the remote. In other words,
> > the contents come from the remote by fetching from it and safely
> > kept away from disaster on the local side. And for that,
> > "remote prune" is a perfect thing to do.
>
> I have tried to do that but I am getting a warning:
> $ git remote prune origin
> Warning: unrecognized mapping in remotes.origin.fetch: +refs/*:refs/*
> and no branch is removed.
>
> I suspect that the change that introduced --mirror option for the 'add'
> command did not adjust the prune procedure to handle the new situation
> properly. Or is just me doing something wrong?
No, you're right. I did not anticipate git-remote to be written the way
it is. After fiddling with it for several hours, I am giving up for now.
IMHO the script is too married to the idea that the remote branches live
in refs/remotes/<remote>/*. Probably it would be very easy by now to
implement it as a builtin, using remote.[ch].
Ciao,
Dscho
^ permalink raw reply
* [PATCH (resend)] gitweb: Fix and simplify "split patch" detection
From: Jakub Narebski @ 2007-10-30 0:35 UTC (permalink / raw)
To: git; +Cc: Jakub Narebski
There are some cases when one line from "raw" git-diff output (raw
format) corresponds to more than one patch in the patchset git-diff
output; we call this situation "split patch". Old code misdetected
subsequent patches (for different files) with the same pre-image and
post-image as fragments of "split patch", leading to mislabeled
from-file/to-file diff header etc.
Old code used pre-image and post-image SHA-1 identifier ('from_id' and
'to_id') to check if current patch corresponds to old raw diff format
line, to find if one difftree raw line coresponds to more than one
patch in the patch format. Now we use post-image filename for that.
This assumes that post-image filename alone can be used to identify
difftree raw line. In the case this changes (which is unlikely
considering current diff engine) we can add 'from_id' and 'to_id'
to detect "patch splitting" together with 'to_file'.
Because old code got pre-image and post-image SHA-1 identifier for the
patch from the "index" line in extended diff header, diff header had
to be buffered. New code takes post-image filename from "git diff"
header, which is first line of a patch; this allows to simplify
git_patchset_body code. A side effect of resigning diff header
buffering is that there is always "diff extended_header" div, even
if extended diff header is empty.
Alternate solution would be to check when git splits patches, and do
not check if parsed info from current patch corresponds to current or
next raw diff format output line. Git splits patches only for 'T'
(typechange) status filepair, and there always two patches
corresponding to one raw diff line. It was not used because it would
tie gitweb code to minute details of git diff output.
While at it, use newly introduced parsed_difftree_line wrapper
subroutine in git_difftree_body.
Noticed-by: Yann Dirson <ydirson@altern.org>
Diagnosed-by: Petr Baudis <pasky@suse.cz>
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
Junio has decided in
Message-ID: <7vmyw4ob7z.fsf@gitster.siamese.dyndns.org>
that tying gitweb to minute details of git diff output, namely that
we have "split patch" (two patches of patchset diff format for single
line of raw ditt format) only for typechange (status 'T') diffs.
We make other assumption instead, that post-image filename uniquely
defines line of raw git diff output. Currently diffcore is not
capable of producing other output; see Junio in
Message-ID: <7vtzqcj9ni.fsf@gitster.siamese.dyndns.org>
This assumption simplifies git_patchset_body, as we no longer need
to cache extended diff header for "split patch" detection.
gitweb/gitweb.perl | 152 +++++++++++++++++++++++-----------------------------
1 files changed, 67 insertions(+), 85 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 48e21da..1537b0e 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -2000,6 +2000,19 @@ sub parse_difftree_raw_line {
return wantarray ? %res : \%res;
}
+# wrapper: return parsed line of git-diff-tree "raw" output
+# (the argument might be raw line, or parsed info)
+sub parsed_difftree_line {
+ my $line_or_ref = shift;
+
+ if (ref($line_or_ref) eq "HASH") {
+ # pre-parsed (or generated by hand)
+ return $line_or_ref;
+ } else {
+ return parse_difftree_raw_line($line_or_ref);
+ }
+}
+
# parse line of git-ls-tree output
sub parse_ls_tree_line ($;%) {
my $line = shift;
@@ -2043,6 +2056,7 @@ sub parse_from_to_diffinfo {
}
}
} else {
+ # ordinary (not combined) diff
$from->{'file'} = $diffinfo->{'from_file'} || $diffinfo->{'file'};
if ($diffinfo->{'status'} ne "A") { # not new (added) file
$from->{'href'} = href(action=>"blob", hash_base=>$hash_parent,
@@ -2766,6 +2780,7 @@ sub git_print_tree_entry {
## ......................................................................
## functions printing large fragments of HTML
+# get pre-image filenames for merge (combined) diff
sub fill_from_file_info {
my ($diff, @parents) = @_;
@@ -2782,28 +2797,25 @@ sub fill_from_file_info {
return $diff;
}
-# parameters can be strings, or references to arrays of strings
-sub from_ids_eq {
- my ($a, $b) = @_;
-
- if (ref($a) eq "ARRAY" && ref($b) eq "ARRAY" && @$a == @$b) {
- for (my $i = 0; $i < @$a; ++$i) {
- return 0 unless ($a->[$i] eq $b->[$i]);
- }
- return 1;
- } elsif (!ref($a) && !ref($b)) {
- return $a eq $b;
- } else {
- return 0;
- }
-}
-
+# is current raw difftree line of file deletion
sub is_deleted {
my $diffinfo = shift;
return $diffinfo->{'to_id'} eq ('0' x 40);
}
+# does patch correspond to [previous] difftree raw line
+# $diffinfo - hashref of parsed raw diff format
+# $patchinfo - hashref of parsed patch diff format
+# (the same keys as in $diffinfo)
+sub is_patch_split {
+ my ($diffinfo, $patchinfo) = @_;
+
+ return defined $diffinfo && defined $patchinfo
+ && ($diffinfo->{'to_file'} || $diffinfo->{'file'}) eq $patchinfo->{'to_file'};
+}
+
+
sub git_difftree_body {
my ($difftree, $hash, @parents) = @_;
my ($parent) = $parents[0];
@@ -2840,13 +2852,7 @@ sub git_difftree_body {
my $alternate = 1;
my $patchno = 0;
foreach my $line (@{$difftree}) {
- my $diff;
- if (ref($line) eq "HASH") {
- # pre-parsed (or generated by hand)
- $diff = $line;
- } else {
- $diff = parse_difftree_raw_line($line);
- }
+ my $diff = parsed_difftree_line($line);
if ($alternate) {
print "<tr class=\"dark\">\n";
@@ -3117,10 +3123,12 @@ sub git_patchset_body {
my ($fd, $difftree, $hash, @hash_parents) = @_;
my ($hash_parent) = $hash_parents[0];
+ my $is_combined = (@hash_parents > 1);
my $patch_idx = 0;
my $patch_number = 0;
my $patch_line;
my $diffinfo;
+ my $to_name;
my (%from, %to);
print "<div class=\"patchset\">\n";
@@ -3134,73 +3142,46 @@ sub git_patchset_body {
PATCH:
while ($patch_line) {
- my @diff_header;
- my ($from_id, $to_id);
-
- # git diff header
- #assert($patch_line =~ m/^diff /) if DEBUG;
- #assert($patch_line !~ m!$/$!) if DEBUG; # is chomp-ed
- $patch_number++;
- push @diff_header, $patch_line;
-
- # extended diff header
- EXTENDED_HEADER:
- while ($patch_line = <$fd>) {
- chomp $patch_line;
- last EXTENDED_HEADER if ($patch_line =~ m/^--- |^diff /);
-
- if ($patch_line =~ m/^index ([0-9a-fA-F]{40})..([0-9a-fA-F]{40})/) {
- $from_id = $1;
- $to_id = $2;
- } elsif ($patch_line =~ m/^index ((?:[0-9a-fA-F]{40},)+[0-9a-fA-F]{40})..([0-9a-fA-F]{40})/) {
- $from_id = [ split(',', $1) ];
- $to_id = $2;
- }
-
- push @diff_header, $patch_line;
+ # parse "git diff" header line
+ if ($patch_line =~ m/^diff --git (\"(?:[^\\\"]*(?:\\.[^\\\"]*)*)\"|[^ "]*) (.*)$/) {
+ # $1 is from_name, which we do not use
+ $to_name = unquote($2);
+ $to_name =~ s!^b/!!;
+ } elsif ($patch_line =~ m/^diff --(cc|combined) ("?.*"?)$/) {
+ # $1 is 'cc' or 'combined', which we do not use
+ $to_name = unquote($2);
+ } else {
+ $to_name = undef;
}
- my $last_patch_line = $patch_line;
# check if current patch belong to current raw line
# and parse raw git-diff line if needed
- if (defined $diffinfo &&
- defined $from_id && defined $to_id &&
- from_ids_eq($diffinfo->{'from_id'}, $from_id) &&
- $diffinfo->{'to_id'} eq $to_id) {
+ if (is_patch_split($diffinfo, { 'to_file' => $to_name })) {
# this is continuation of a split patch
print "<div class=\"patch cont\">\n";
} else {
# advance raw git-diff output if needed
$patch_idx++ if defined $diffinfo;
- # compact combined diff output can have some patches skipped
- # find which patch (using pathname of result) we are at now
- my $to_name;
- if ($diff_header[0] =~ m!^diff --cc "?(.*)"?$!) {
- $to_name = $1;
- }
-
- do {
- # read and prepare patch information
- if (ref($difftree->[$patch_idx]) eq "HASH") {
- # pre-parsed (or generated by hand)
- $diffinfo = $difftree->[$patch_idx];
- } else {
- $diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]);
- }
+ # read and prepare patch information
+ $diffinfo = parsed_difftree_line($difftree->[$patch_idx]);
- # check if current raw line has no patch (it got simplified)
- if (defined $to_name && $to_name ne $diffinfo->{'to_file'}) {
+ # compact combined diff output can have some patches skipped
+ # find which patch (using pathname of result) we are at now;
+ if ($is_combined) {
+ while ($to_name ne $diffinfo->{'to_file'}) {
print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n" .
format_diff_cc_simplified($diffinfo, @hash_parents) .
"</div>\n"; # class="patch"
$patch_idx++;
$patch_number++;
+
+ last if $patch_idx > $#$difftree;
+ $diffinfo = parsed_difftree_line($difftree->[$patch_idx]);
}
- } until (!defined $to_name || $to_name eq $diffinfo->{'to_file'} ||
- $patch_idx > $#$difftree);
+ }
# modifies %from, %to hashes
parse_from_to_diffinfo($diffinfo, \%from, \%to, @hash_parents);
@@ -3210,30 +3191,36 @@ sub git_patchset_body {
print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n";
}
+ # git diff header
+ #assert($patch_line =~ m/^diff /) if DEBUG;
+ #assert($patch_line !~ m!$/$!) if DEBUG; # is chomp-ed
+ $patch_number++;
# print "git diff" header
- $patch_line = shift @diff_header;
print format_git_diff_header_line($patch_line, $diffinfo,
\%from, \%to);
# print extended diff header
- print "<div class=\"diff extended_header\">\n" if (@diff_header > 0);
+ print "<div class=\"diff extended_header\">\n";
EXTENDED_HEADER:
- foreach $patch_line (@diff_header) {
+ while ($patch_line = <$fd>) {
+ chomp $patch_line;
+
+ last EXTENDED_HEADER if ($patch_line =~ m/^--- |^diff /);
+
print format_extended_diff_header_line($patch_line, $diffinfo,
\%from, \%to);
}
- print "</div>\n" if (@diff_header > 0); # class="diff extended_header"
+ print "</div>\n"; # class="diff extended_header"
# from-file/to-file diff header
- $patch_line = $last_patch_line;
if (! $patch_line) {
print "</div>\n"; # class="patch"
last PATCH;
}
next PATCH if ($patch_line =~ m/^diff /);
#assert($patch_line =~ m/^---/) if DEBUG;
- #assert($patch_line eq $last_patch_line) if DEBUG;
+ my $last_patch_line = $patch_line;
$patch_line = <$fd>;
chomp $patch_line;
#assert($patch_line =~ m/^\+\+\+/) if DEBUG;
@@ -3258,16 +3245,11 @@ sub git_patchset_body {
# for compact combined (--cc) format, with chunk and patch simpliciaction
# patchset might be empty, but there might be unprocessed raw lines
- for ($patch_idx++ if $patch_number > 0;
+ for (++$patch_idx if $patch_number > 0;
$patch_idx < @$difftree;
- $patch_idx++) {
+ ++$patch_idx) {
# read and prepare patch information
- if (ref($difftree->[$patch_idx]) eq "HASH") {
- # pre-parsed (or generated by hand)
- $diffinfo = $difftree->[$patch_idx];
- } else {
- $diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]);
- }
+ $diffinfo = parsed_difftree_line($difftree->[$patch_idx]);
# generate anchor for "patch" links in difftree / whatchanged part
print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n" .
--
1.5.3
^ permalink raw reply related
* Re: [PATCH] Speedup scanning for excluded files.
From: Junio C Hamano @ 2007-10-30 0:00 UTC (permalink / raw)
To: Morten Welinder; +Cc: Lars Knoll, git, Pierre Habouzit, Junio C Hamano
In-Reply-To: <118833cc0710291559kbd874a8o8111b9495090ef27@mail.gmail.com>
"Morten Welinder" <mwelinder@gmail.com> writes:
>> + } else if (x->flags & EXC_FLAG_ENDSWITH) {
>> + if (!strcmp(exclude + 1, pathname + pathlen -x->patternlen + 1))
>
> Is there some guarantee that the result of that subtraction is still within
> the string?
Good eyes.
If pattern is "*.exe", patternlen is 5, and strcmp wants to
compare 4 chars, so pathlen is better be at least that long, and
we do allow that pattern to match a hidden file ".exe".
Like this?
if (x->patternlen - 1 <= pathlen &&
!strcmp(exclude + 1, pathname + pathlen - x->patternlen + 1))
return to_exclude;
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox