* [POC PATCH 1/5] Turn grep's use_threads into a global flag
From: Thomas Rast @ 2011-12-09 8:39 UTC (permalink / raw)
To: git; +Cc: René Scharfe, Junio C Hamano, Eric Herman
In-Reply-To: <cover.1323419666.git.trast@student.ethz.ch>
In preparation for further work on this, turn use_threads into a flag
shared across the whole code base. The supporting (un)lock_if_threaded()
functions are to be used for locking; they return immediately when not
threading.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
builtin/grep.c | 20 ++++++++------------
thread-utils.c | 16 ++++++++++++++++
thread-utils.h | 16 ++++++++++++++++
3 files changed, 40 insertions(+), 12 deletions(-)
diff --git a/builtin/grep.c b/builtin/grep.c
index 988ea1d..76f2c4f 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -24,8 +24,6 @@
NULL
};
-static int use_threads = 1;
-
#ifndef NO_PTHREADS
#define THREADS 8
static pthread_t threads[THREADS];
@@ -76,14 +74,12 @@ struct work_item {
static inline void grep_lock(void)
{
- if (use_threads)
- pthread_mutex_lock(&grep_mutex);
+ lock_if_threaded(&grep_mutex);
}
static inline void grep_unlock(void)
{
- if (use_threads)
- pthread_mutex_unlock(&grep_mutex);
+ unlock_if_threaded(&grep_mutex);
}
/* Used to serialize calls to read_sha1_file. */
@@ -91,14 +87,12 @@ static inline void grep_unlock(void)
static inline void read_sha1_lock(void)
{
- if (use_threads)
- pthread_mutex_lock(&read_sha1_mutex);
+ lock_if_threaded(&read_sha1_mutex);
}
static inline void read_sha1_unlock(void)
{
- if (use_threads)
- pthread_mutex_unlock(&read_sha1_mutex);
+ unlock_if_threaded(&read_sha1_mutex);
}
/* Signalled when a new work_item is added to todo. */
@@ -984,6 +978,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
argc--;
}
+#ifndef NO_PTHREADS
+ use_threads = 1;
+#endif
+
if (show_in_pager == default_pager)
show_in_pager = git_pager(1);
if (show_in_pager) {
@@ -1011,8 +1009,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
skip_first_line = 1;
start_threads(&opt);
}
-#else
- use_threads = 0;
#endif
compile_grep_patterns(&opt);
diff --git a/thread-utils.c b/thread-utils.c
index 7f4b76a..fb75a29 100644
--- a/thread-utils.c
+++ b/thread-utils.c
@@ -1,6 +1,8 @@
#include "cache.h"
#include "thread-utils.h"
+int use_threads;
+
#if defined(hpux) || defined(__hpux) || defined(_hpux)
# include <sys/pstat.h>
#endif
@@ -59,3 +61,17 @@ int init_recursive_mutex(pthread_mutex_t *m)
}
return ret;
}
+
+#ifndef NO_PTHREADS
+void lock_if_threaded(pthread_mutex_t *m)
+{
+ if (use_threads)
+ pthread_mutex_lock(m);
+}
+
+void unlock_if_threaded(pthread_mutex_t *m)
+{
+ if (use_threads)
+ pthread_mutex_unlock(m);
+}
+#endif
diff --git a/thread-utils.h b/thread-utils.h
index 6fb98c3..9a780a2 100644
--- a/thread-utils.h
+++ b/thread-utils.h
@@ -1,11 +1,27 @@
#ifndef THREAD_COMPAT_H
#define THREAD_COMPAT_H
+/*
+ * This variable is used by commands to globally tell affected
+ * subsystems that they must use thread-safe mechanisms.
+ */
+extern int use_threads;
+
#ifndef NO_PTHREADS
#include <pthread.h>
extern int online_cpus(void);
extern int init_recursive_mutex(pthread_mutex_t*);
+/* These functions do nothing if use_threads==0 or NO_PTHREADS */
+extern void lock_if_threaded(pthread_mutex_t*);
+extern void unlock_if_threaded(pthread_mutex_t*);
+
+#else
+
+#define lock_if_threaded(lock)
+#define unlock_if_threaded(lock)
+
#endif
+
#endif /* THREAD_COMPAT_H */
--
1.7.8.431.g2abf2
^ permalink raw reply related
* [POC PATCH 0/5] Threaded loose object and pack access
From: Thomas Rast @ 2011-12-09 8:39 UTC (permalink / raw)
To: git; +Cc: René Scharfe, Junio C Hamano, Eric Herman
Well, just to make sure we're all left in a confused mess of partly
conflicting patches, here's another angle on the same thing:
Jeff King wrote:
> Wow, that's horrible. Leaving aside the parallelism, it's just terrible
> that reading from the cache is 20 times slower than the worktree. I get
> similar results on my quad-core machine.
By poking around in sha1_file.c I got that down to about 10. It's not
great yet, but it seems a start.
The goal would be to improve it to the point where a patch lookup that
already has all relevant packs open and windows mapped can proceed
without locking. I'm not sure that's doable short of duplicating the
whole pack state (including fds and windows) across threads, but I'll
give it some more thought before going that route.
Thomas Rast (5):
Turn grep's use_threads into a global flag
grep: push locking into read_sha1_*
sha1_file_name_buf(): sha1_file_name in caller's buffer
sha1_file: stuff various pack reading variables into a struct
sha1_file: make the pack machinery thread-safe
builtin/grep.c | 60 +++++-----------
cache.h | 1 +
replace_object.c | 5 +-
sha1_file.c | 213 +++++++++++++++++++++++++++++++++++++++++-------------
thread-utils.c | 30 ++++++++
thread-utils.h | 23 ++++++
6 files changed, 240 insertions(+), 92 deletions(-)
--
1.7.8.431.g2abf2
^ permalink raw reply
* [POC PATCH 3/5] sha1_file_name_buf(): sha1_file_name in caller's buffer
From: Thomas Rast @ 2011-12-09 8:39 UTC (permalink / raw)
To: git; +Cc: René Scharfe, Junio C Hamano, Eric Herman
In-Reply-To: <cover.1323419666.git.trast@student.ethz.ch>
sha1_file_name is non-reentrant because of its use of a static buffer.
Split it into just the buffer writing (which can be called even from
threads as long as the buffer is stack'd) and a small wrapper that
uses the static buffer as before.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
sha1_file.c | 29 +++++++++++++++++++----------
1 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/sha1_file.c b/sha1_file.c
index c3595b3..18648c3 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -153,18 +153,11 @@ static void fill_sha1_path(char *pathbuf, const unsigned char *sha1)
}
/*
- * NOTE! This returns a statically allocated buffer, so you have to be
- * careful about using it. Do an "xstrdup()" if you need to save the
- * filename.
- *
- * Also note that this returns the location for creating. Reading
- * SHA1 file can happen from any alternate directory listed in the
- * DB_ENVIRONMENT environment variable if it is not found in
- * the primary object database.
+ * Similar to sha1_file_name but you provide a buffer of size at least
+ * PATH_MAX.
*/
-char *sha1_file_name(const unsigned char *sha1)
+void sha1_file_name_buf(char *buf, const unsigned char *sha1)
{
- static char buf[PATH_MAX];
const char *objdir;
int len;
@@ -179,6 +172,22 @@ char *sha1_file_name(const unsigned char *sha1)
buf[len+3] = '/';
buf[len+42] = '\0';
fill_sha1_path(buf + len + 1, sha1);
+}
+
+/*
+ * NOTE! This returns a statically allocated buffer, so you have to be
+ * careful about using it. Do an "xstrdup()" if you need to save the
+ * filename.
+ *
+ * Also note that this returns the location for creating. Reading
+ * SHA1 file can happen from any alternate directory listed in the
+ * DB_ENVIRONMENT environment variable if it is not found in
+ * the primary object database.
+ */
+char *sha1_file_name(const unsigned char *sha1)
+{
+ static char buf[PATH_MAX];
+ sha1_file_name_buf(buf, sha1);
return buf;
}
--
1.7.8.431.g2abf2
^ permalink raw reply related
* [POC PATCH 5/5] sha1_file: make the pack machinery thread-safe
From: Thomas Rast @ 2011-12-09 8:39 UTC (permalink / raw)
To: git; +Cc: René Scharfe, Junio C Hamano, Eric Herman
In-Reply-To: <cover.1323419666.git.trast@student.ethz.ch>
More precisely speaking, this pushes the locking down from
read_object() into bits of the pack machinery that cannot (yet) run in
parallel.
There are several hacks here:
a) prepare_packed_git() must be called before any parallel accesses
happen. It now unconditionally opens and maps all index files.
b) similarly, prepare_replace_object() must be called before any
parallel read_sha1_file() happens
This simplification lets us avoid locking outright to guard the index
accesses; locking is then mainly required for open_packed_git(),
[un]use_pack(), and such.
The ultimate goal would of course be to let at least _some_ pack
accesses happen without any locking whatsoever. But grep already
benefits from it with a nice speed boost on non-worktree greps.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
builtin/grep.c | 9 ++++++
cache.h | 1 +
replace_object.c | 5 ++-
sha1_file.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++------
thread-utils.c | 9 ++++--
thread-utils.h | 3 +-
6 files changed, 93 insertions(+), 15 deletions(-)
diff --git a/builtin/grep.c b/builtin/grep.c
index 6c5bdfa..212497d 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -980,6 +980,15 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (opt.pre_context || opt.post_context || opt.file_break ||
opt.funcbody)
skip_first_line = 1;
+ /*
+ * This does the non-threadsafe work early. FIXME:
+ * grep shouldn't have to know about this mess.
+ */
+ use_threads = 0;
+ prepare_replace_object();
+ prepare_packed_git();
+ use_threads = 1;
+
start_threads(&opt);
}
#endif
diff --git a/cache.h b/cache.h
index 8c98d05..379dd44 100644
--- a/cache.h
+++ b/cache.h
@@ -764,6 +764,7 @@ static inline const unsigned char *lookup_replace_object(const unsigned char *sh
return sha1;
return do_lookup_replace_object(sha1);
}
+extern void prepare_replace_object(void);
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
extern int sha1_object_info(const unsigned char *, unsigned long *);
diff --git a/replace_object.c b/replace_object.c
index d0b1548..b303392 100644
--- a/replace_object.c
+++ b/replace_object.c
@@ -2,6 +2,7 @@
#include "sha1-lookup.h"
#include "refs.h"
#include "commit.h"
+#include "thread-utils.h"
static struct replace_object {
unsigned char sha1[2][20];
@@ -76,13 +77,15 @@ static int register_replace_ref(const char *refname,
return 0;
}
-static void prepare_replace_object(void)
+void prepare_replace_object(void)
{
static int replace_object_prepared;
if (replace_object_prepared)
return;
+ assert(!use_threads);
+
for_each_replace_ref(register_replace_ref, NULL);
replace_object_prepared = 1;
if (!replace_object_nr)
diff --git a/sha1_file.c b/sha1_file.c
index 7c367f9..b61692e 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -429,7 +429,8 @@ void prepare_alt_odb(void)
static int has_loose_object_local(const unsigned char *sha1)
{
- char *name = sha1_file_name(sha1);
+ char name[PATH_MAX];
+ sha1_file_name_buf(name, sha1);
return !access(name, F_OK);
}
@@ -650,9 +651,12 @@ static int unuse_one_window(struct packed_git *current, int keep_fd)
void release_pack_memory(size_t need, int fd)
{
- size_t cur = pack_mapped;
+ size_t cur;
+ lock_if_threaded(&pack_access_mutex);
+ cur = pack_mapped;
while (need >= (cur - pack_mapped) && unuse_one_window(NULL, fd))
; /* nothing */
+ unlock_if_threaded(&pack_access_mutex);
}
void *xmmap(void *start, size_t length,
@@ -689,9 +693,12 @@ void close_pack_windows(struct packed_git *p)
void unuse_pack(struct pack_window **w_cursor)
{
struct pack_window *w = *w_cursor;
+
if (w) {
+ lock_if_threaded(&pack_access_mutex);
w->inuse_cnt--;
*w_cursor = NULL;
+ unlock_if_threaded(&pack_access_mutex);
}
}
@@ -712,10 +719,13 @@ void close_pack_index(struct packed_git *p)
* must subsist at this point. If ever objects from this pack are requested
* again, the new version of the pack will be reinitialized through
* reprepare_packed_git().
+ *
+ * NOT THREAD-SAFE
*/
void free_pack_by_name(const char *pack_name)
{
struct packed_git *p, **pp = &packed_git;
+ assert(!use_threads);
while (*pp) {
p = *pp;
@@ -821,13 +831,33 @@ static int open_packed_git_1(struct packed_git *p)
static int open_packed_git(struct packed_git *p)
{
- if (!open_packed_git_1(p))
+ lock_if_threaded(&pack_access_mutex);
+ /*
+ * is_pack_valid() took the easy route and did not
+ * lock. This is probably okay; if the pack was
+ * *ever* open, it was valid unless another process is
+ * actively trying to corrupt it, in which case:
+ * meh.
+ *
+ * However, a concurrent open_packed_git() may already have
+ * opened it before we get here. So we test again in a locked
+ * section. If it beat us to it, then we have no work left to
+ * do.
+ */
+ if (p->pack_fd != -1) {
+ unlock_if_threaded(&pack_access_mutex);
return 0;
+ }
+ if (!open_packed_git_1(p)) {
+ unlock_if_threaded(&pack_access_mutex);
+ return 0;
+ }
if (p->pack_fd != -1) {
close(p->pack_fd);
pack_open_fds--;
p->pack_fd = -1;
}
+ unlock_if_threaded(&pack_access_mutex);
return -1;
}
@@ -858,6 +888,9 @@ unsigned char *use_pack(struct packed_git *p,
*/
if (!p->pack_size && p->pack_fd == -1 && open_packed_git(p))
die("packfile %s cannot be accessed", p->pack_name);
+
+ lock_if_threaded(&pack_access_mutex);
+
if (offset > (p->pack_size - 20))
die("offset beyond end of packfile (truncated pack?)");
@@ -916,6 +949,9 @@ unsigned char *use_pack(struct packed_git *p,
offset -= win->offset;
if (left)
*left = win->len - xsize_t(offset);
+
+ unlock_if_threaded(&pack_access_mutex);
+
return win->base + offset;
}
@@ -1044,6 +1080,7 @@ static void prepare_packed_git_one(char *objdir, int local)
if (!p)
continue;
install_packed_git(p);
+ open_pack_index(p);
}
closedir(dir);
}
@@ -1102,6 +1139,12 @@ static void rearrange_packed_git(void)
free(ary);
}
+/*
+ * NOT THREAD-SAFE
+ *
+ * However, it's ok if you run this early, before starting threads,
+ * and then use the pack machinery from threads.
+ */
static int prepare_packed_git_run_once = 0;
void prepare_packed_git(void)
{
@@ -1109,6 +1152,7 @@ void prepare_packed_git(void)
if (prepare_packed_git_run_once)
return;
+ assert (!use_threads);
prepare_packed_git_one(get_object_directory(), 1);
prepare_alt_odb();
for (alt = alt_odb_list; alt; alt = alt->next) {
@@ -1180,8 +1224,10 @@ static int git_open_noatime(const char *name)
static int open_sha1_file(const unsigned char *sha1)
{
int fd;
- char *name = sha1_file_name(sha1);
+ char namebuf[PATH_MAX];
+ char *name = namebuf;
struct alternate_object_database *alt;
+ sha1_file_name_buf(name, sha1);
fd = git_open_noatime(name);
if (fd >= 0)
@@ -1698,7 +1744,22 @@ static struct pack_context *pack_context_alloc(void)
return ctx;
}
+#ifdef NO_PTHREADS
#define get_thread_pack_context() (&main_pack_context)
+#else
+static struct pack_context *get_thread_pack_context(void)
+{
+ struct pack_context *ctx;
+ if (!use_threads)
+ return &main_pack_context;
+ ctx = pthread_getspecific(pack_context_key);
+ if (ctx)
+ return ctx;
+ ctx = pack_context_alloc();
+ pthread_setspecific(pack_context_key, ctx);
+ return ctx;
+}
+#endif
static unsigned long pack_entry_hash(struct packed_git *p, off_t base_offset)
{
@@ -2219,6 +2280,10 @@ static void *read_packed_sha1(const unsigned char *sha1,
return data;
}
+/*
+ * WARNING: must never be called concurrently with read_sha1_file and
+ * friends! They do lookups in the cached_objects without locking.
+ */
int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
unsigned char *sha1)
{
@@ -2280,19 +2345,15 @@ void *read_sha1_file_extended(const unsigned char *sha1,
unsigned flag)
{
void *data;
- char *path;
const struct packed_git *p;
const unsigned char *repl;
- lock_if_threaded(&read_sha1_mutex);
-
repl = (flag & READ_SHA1_FILE_REPLACE)
? lookup_replace_object(sha1) : sha1;
errno = 0;
data = read_object(repl, type, size);
if (data) {
- unlock_if_threaded(&read_sha1_mutex);
return data;
}
@@ -2305,7 +2366,8 @@ void *read_sha1_file_extended(const unsigned char *sha1,
sha1_to_hex(repl), sha1_to_hex(sha1));
if (has_loose_object(repl)) {
- path = sha1_file_name(sha1);
+ char path[PATH_MAX];
+ sha1_file_name_buf(path, sha1);
die("loose object %s (stored in %s) is corrupt",
sha1_to_hex(repl), path);
}
@@ -2314,7 +2376,6 @@ void *read_sha1_file_extended(const unsigned char *sha1,
die("packed object %s (stored in %s) is corrupt",
sha1_to_hex(repl), p->pack_name);
- unlock_if_threaded(&read_sha1_mutex);
return NULL;
}
diff --git a/thread-utils.c b/thread-utils.c
index 70af3f9..0da2b65 100644
--- a/thread-utils.c
+++ b/thread-utils.c
@@ -62,15 +62,18 @@ int init_recursive_mutex(pthread_mutex_t *m)
return ret;
}
-pthread_mutex_t read_sha1_mutex;
+pthread_mutex_t pack_access_mutex;
+pthread_key_t pack_context_key;
void init_subsystem_locks(void)
{
- pthread_mutex_init(&read_sha1_mutex, NULL);
+ init_recursive_mutex(&pack_access_mutex);
+ pthread_key_create(&pack_context_key, NULL);
}
void destroy_subsystem_locks(void)
{
- pthread_mutex_destroy(&read_sha1_mutex);
+ pthread_mutex_destroy(&pack_access_mutex);
+ pthread_key_delete(pack_context_key);
}
#ifndef NO_PTHREADS
diff --git a/thread-utils.h b/thread-utils.h
index 3906753..7d3cc0a 100644
--- a/thread-utils.h
+++ b/thread-utils.h
@@ -17,7 +17,8 @@
extern void lock_if_threaded(pthread_mutex_t*);
extern void unlock_if_threaded(pthread_mutex_t*);
-extern pthread_mutex_t read_sha1_mutex;
+extern pthread_mutex_t pack_access_mutex;
+extern pthread_key_t pack_context_key;
extern void init_subsystem_locks(void);
extern void destroy_subsystem_locks(void);
--
1.7.8.431.g2abf2
^ permalink raw reply related
* [POC PATCH 4/5] sha1_file: stuff various pack reading variables into a struct
From: Thomas Rast @ 2011-12-09 8:39 UTC (permalink / raw)
To: git; +Cc: René Scharfe, Junio C Hamano, Eric Herman
In-Reply-To: <cover.1323419666.git.trast@student.ethz.ch>
In preparation for making these variables thread-local, put various
delta-cache related bits of pack reading state into a struct. For now
the accessor function is a dummy that always returns a static instance
of this struct.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
sha1_file.c | 99 ++++++++++++++++++++++++++++++++++++++++-------------------
1 files changed, 67 insertions(+), 32 deletions(-)
diff --git a/sha1_file.c b/sha1_file.c
index 18648c3..7c367f9 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1655,21 +1655,50 @@ static void *unpack_compressed_entry(struct packed_git *p,
#define MAX_DELTA_CACHE (256)
-static size_t delta_base_cached;
-
-static struct delta_base_cache_lru_list {
+struct delta_base_cache_lru_list {
struct delta_base_cache_lru_list *prev;
struct delta_base_cache_lru_list *next;
-} delta_base_cache_lru = { &delta_base_cache_lru, &delta_base_cache_lru };
+};
+
+static struct delta_base_cache_lru_list main_delta_base_cache_lru = {
+ &main_delta_base_cache_lru, &main_delta_base_cache_lru
+};
-static struct delta_base_cache_entry {
+struct delta_base_cache_entry {
struct delta_base_cache_lru_list lru;
void *data;
struct packed_git *p;
off_t base_offset;
unsigned long size;
enum object_type type;
-} delta_base_cache[MAX_DELTA_CACHE];
+};
+
+static struct delta_base_cache_entry main_delta_base_cache[MAX_DELTA_CACHE];
+
+struct pack_context {
+ size_t delta_base_cached;
+ struct delta_base_cache_entry *delta_base_cache;
+ struct delta_base_cache_lru_list *delta_base_cache_lru;
+ struct packed_git *last_found;
+};
+
+static struct pack_context main_pack_context = {
+ 0, main_delta_base_cache, &main_delta_base_cache_lru, (void*)1
+};
+
+static struct pack_context *pack_context_alloc(void)
+{
+ struct pack_context *ctx = xmalloc(sizeof(struct pack_context));
+ ctx->delta_base_cached = 0;
+ ctx->delta_base_cache_lru = xmalloc(sizeof(struct delta_base_cache_lru_list));
+ ctx->delta_base_cache_lru->prev = ctx->delta_base_cache_lru;
+ ctx->delta_base_cache_lru->next = ctx->delta_base_cache_lru;
+ ctx->delta_base_cache = xcalloc(MAX_DELTA_CACHE, sizeof(struct delta_base_cache_entry));
+ ctx->last_found = (void*)1;
+ return ctx;
+}
+
+#define get_thread_pack_context() (&main_pack_context)
static unsigned long pack_entry_hash(struct packed_git *p, off_t base_offset)
{
@@ -1683,7 +1712,8 @@ static unsigned long pack_entry_hash(struct packed_git *p, off_t base_offset)
static int in_delta_base_cache(struct packed_git *p, off_t base_offset)
{
unsigned long hash = pack_entry_hash(p, base_offset);
- struct delta_base_cache_entry *ent = delta_base_cache + hash;
+ struct delta_base_cache_entry *ent
+ = get_thread_pack_context()->delta_base_cache + hash;
return (ent->data && ent->p == p && ent->base_offset == base_offset);
}
@@ -1692,7 +1722,8 @@ static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset,
{
void *ret;
unsigned long hash = pack_entry_hash(p, base_offset);
- struct delta_base_cache_entry *ent = delta_base_cache + hash;
+ struct pack_context *ctx = get_thread_pack_context();
+ struct delta_base_cache_entry *ent = ctx->delta_base_cache + hash;
ret = ent->data;
if (!ret || ent->p != p || ent->base_offset != base_offset)
@@ -1702,7 +1733,7 @@ static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset,
ent->data = NULL;
ent->lru.next->prev = ent->lru.prev;
ent->lru.prev->next = ent->lru.next;
- delta_base_cached -= ent->size;
+ ctx->delta_base_cached -= ent->size;
} else {
ret = xmemdupz(ent->data, ent->size);
}
@@ -1711,48 +1742,52 @@ static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset,
return ret;
}
-static inline void release_delta_base_cache(struct delta_base_cache_entry *ent)
+static inline void release_delta_base_cache(struct pack_context *ctx,
+ struct delta_base_cache_entry *ent)
{
if (ent->data) {
free(ent->data);
ent->data = NULL;
ent->lru.next->prev = ent->lru.prev;
ent->lru.prev->next = ent->lru.next;
- delta_base_cached -= ent->size;
+ ctx->delta_base_cached -= ent->size;
}
}
void clear_delta_base_cache(void)
{
unsigned long p;
+ struct pack_context *ctx = get_thread_pack_context();
+ struct delta_base_cache_entry *delta_base_cache = ctx->delta_base_cache;
for (p = 0; p < MAX_DELTA_CACHE; p++)
- release_delta_base_cache(&delta_base_cache[p]);
+ release_delta_base_cache(ctx, &delta_base_cache[p]);
}
static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
void *base, unsigned long base_size, enum object_type type)
{
unsigned long hash = pack_entry_hash(p, base_offset);
- struct delta_base_cache_entry *ent = delta_base_cache + hash;
+ struct pack_context *ctx = get_thread_pack_context();
+ struct delta_base_cache_entry *ent = ctx->delta_base_cache + hash;
struct delta_base_cache_lru_list *lru;
- release_delta_base_cache(ent);
- delta_base_cached += base_size;
+ release_delta_base_cache(ctx, ent);
+ ctx->delta_base_cached += base_size;
- for (lru = delta_base_cache_lru.next;
- delta_base_cached > delta_base_cache_limit
- && lru != &delta_base_cache_lru;
+ for (lru = ctx->delta_base_cache_lru->next;
+ ctx->delta_base_cached > delta_base_cache_limit
+ && lru != ctx->delta_base_cache_lru;
lru = lru->next) {
struct delta_base_cache_entry *f = (void *)lru;
if (f->type == OBJ_BLOB)
- release_delta_base_cache(f);
+ release_delta_base_cache(ctx, f);
}
- for (lru = delta_base_cache_lru.next;
- delta_base_cached > delta_base_cache_limit
- && lru != &delta_base_cache_lru;
+ for (lru = ctx->delta_base_cache_lru->next;
+ ctx->delta_base_cached > delta_base_cache_limit
+ && lru != ctx->delta_base_cache_lru;
lru = lru->next) {
struct delta_base_cache_entry *f = (void *)lru;
- release_delta_base_cache(f);
+ release_delta_base_cache(ctx, f);
}
ent->p = p;
@@ -1760,10 +1795,10 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
ent->type = type;
ent->data = base;
ent->size = base_size;
- ent->lru.next = &delta_base_cache_lru;
- ent->lru.prev = delta_base_cache_lru.prev;
- delta_base_cache_lru.prev->next = &ent->lru;
- delta_base_cache_lru.prev = &ent->lru;
+ ent->lru.next = ctx->delta_base_cache_lru;
+ ent->lru.prev = ctx->delta_base_cache_lru->prev;
+ ctx->delta_base_cache_lru->prev->next = &ent->lru;
+ ctx->delta_base_cache_lru->prev = &ent->lru;
}
static void *read_object(const unsigned char *sha1, enum object_type *type,
@@ -2021,14 +2056,14 @@ int is_pack_valid(struct packed_git *p)
static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
{
- static struct packed_git *last_found = (void *)1;
struct packed_git *p;
off_t offset;
+ struct pack_context *ctx = get_thread_pack_context();
prepare_packed_git();
if (!packed_git)
return 0;
- p = (last_found == (void *)1) ? packed_git : last_found;
+ p = (ctx->last_found == (void *)1) ? packed_git : ctx->last_found;
do {
if (p->num_bad_objects) {
@@ -2055,16 +2090,16 @@ static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
e->offset = offset;
e->p = p;
hashcpy(e->sha1, sha1);
- last_found = p;
+ ctx->last_found = p;
return 1;
}
next:
- if (p == last_found)
+ if (p == ctx->last_found)
p = packed_git;
else
p = p->next;
- if (p == last_found)
+ if (p == ctx->last_found)
p = p->next;
} while (p);
return 0;
--
1.7.8.431.g2abf2
^ permalink raw reply related
* [POC PATCH 2/5] grep: push locking into read_sha1_*
From: Thomas Rast @ 2011-12-09 8:39 UTC (permalink / raw)
To: git; +Cc: René Scharfe, Junio C Hamano, Eric Herman
In-Reply-To: <cover.1323419666.git.trast@student.ethz.ch>
Move the locking away from grep (the user) and into read_sha1_* and
read_object_* (the subsystem). This will allow future work on the
locking granularity there.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
builtin/grep.c | 35 ++++-------------------------------
sha1_file.c | 12 ++++++++++--
thread-utils.c | 11 +++++++++++
thread-utils.h | 6 ++++++
4 files changed, 31 insertions(+), 33 deletions(-)
diff --git a/builtin/grep.c b/builtin/grep.c
index 76f2c4f..6c5bdfa 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -82,19 +82,6 @@ static inline void grep_unlock(void)
unlock_if_threaded(&grep_mutex);
}
-/* Used to serialize calls to read_sha1_file. */
-static pthread_mutex_t read_sha1_mutex;
-
-static inline void read_sha1_lock(void)
-{
- lock_if_threaded(&read_sha1_mutex);
-}
-
-static inline void read_sha1_unlock(void)
-{
- unlock_if_threaded(&read_sha1_mutex);
-}
-
/* Signalled when a new work_item is added to todo. */
static pthread_cond_t cond_add;
@@ -248,8 +235,8 @@ static void start_threads(struct grep_opt *opt)
{
int i;
+ init_subsystem_locks();
pthread_mutex_init(&grep_mutex, NULL);
- pthread_mutex_init(&read_sha1_mutex, NULL);
pthread_cond_init(&cond_add, NULL);
pthread_cond_init(&cond_write, NULL);
pthread_cond_init(&cond_result, NULL);
@@ -296,16 +283,14 @@ static int wait_all(void)
}
pthread_mutex_destroy(&grep_mutex);
- pthread_mutex_destroy(&read_sha1_mutex);
pthread_cond_destroy(&cond_add);
pthread_cond_destroy(&cond_write);
pthread_cond_destroy(&cond_result);
+ destroy_subsystem_locks();
return hit;
}
#else /* !NO_PTHREADS */
-#define read_sha1_lock()
-#define read_sha1_unlock()
static int wait_all(void)
{
@@ -363,21 +348,11 @@ static int grep_config(const char *var, const char *value, void *cb)
return 0;
}
-static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
-{
- void *data;
-
- read_sha1_lock();
- data = read_sha1_file(sha1, type, size);
- read_sha1_unlock();
- return data;
-}
-
static void *load_sha1(const unsigned char *sha1, unsigned long *size,
const char *name)
{
enum object_type type;
- void *data = lock_and_read_sha1_file(sha1, &type, size);
+ void *data = read_sha1_file(sha1, &type, size);
if (!data)
error(_("'%s': unable to read %s"), name, sha1_to_hex(sha1));
@@ -578,7 +553,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
void *data;
unsigned long size;
- data = lock_and_read_sha1_file(entry.sha1, &type, &size);
+ data = read_sha1_file(entry.sha1, &type, &size);
if (!data)
die(_("unable to read tree (%s)"),
sha1_to_hex(entry.sha1));
@@ -608,10 +583,8 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
struct strbuf base;
int hit, len;
- read_sha1_lock();
data = read_object_with_reference(obj->sha1, tree_type,
&size, NULL);
- read_sha1_unlock();
if (!data)
die(_("unable to read tree (%s)"), sha1_to_hex(obj->sha1));
diff --git a/sha1_file.c b/sha1_file.c
index 956422b..c3595b3 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -18,6 +18,7 @@
#include "refs.h"
#include "pack-revindex.h"
#include "sha1-lookup.h"
+#include "thread-utils.h"
#ifndef O_NOATIME
#if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
@@ -2237,13 +2238,19 @@ void *read_sha1_file_extended(const unsigned char *sha1,
void *data;
char *path;
const struct packed_git *p;
- const unsigned char *repl = (flag & READ_SHA1_FILE_REPLACE)
+ const unsigned char *repl;
+
+ lock_if_threaded(&read_sha1_mutex);
+
+ repl = (flag & READ_SHA1_FILE_REPLACE)
? lookup_replace_object(sha1) : sha1;
errno = 0;
data = read_object(repl, type, size);
- if (data)
+ if (data) {
+ unlock_if_threaded(&read_sha1_mutex);
return data;
+ }
if (errno && errno != ENOENT)
die_errno("failed to read object %s", sha1_to_hex(sha1));
@@ -2263,6 +2270,7 @@ void *read_sha1_file_extended(const unsigned char *sha1,
die("packed object %s (stored in %s) is corrupt",
sha1_to_hex(repl), p->pack_name);
+ unlock_if_threaded(&read_sha1_mutex);
return NULL;
}
diff --git a/thread-utils.c b/thread-utils.c
index fb75a29..70af3f9 100644
--- a/thread-utils.c
+++ b/thread-utils.c
@@ -62,6 +62,17 @@ int init_recursive_mutex(pthread_mutex_t *m)
return ret;
}
+pthread_mutex_t read_sha1_mutex;
+void init_subsystem_locks(void)
+{
+ pthread_mutex_init(&read_sha1_mutex, NULL);
+}
+
+void destroy_subsystem_locks(void)
+{
+ pthread_mutex_destroy(&read_sha1_mutex);
+}
+
#ifndef NO_PTHREADS
void lock_if_threaded(pthread_mutex_t *m)
{
diff --git a/thread-utils.h b/thread-utils.h
index 9a780a2..3906753 100644
--- a/thread-utils.h
+++ b/thread-utils.h
@@ -17,10 +17,16 @@
extern void lock_if_threaded(pthread_mutex_t*);
extern void unlock_if_threaded(pthread_mutex_t*);
+extern pthread_mutex_t read_sha1_mutex;
+extern void init_subsystem_locks(void);
+extern void destroy_subsystem_locks(void);
+
#else
#define lock_if_threaded(lock)
#define unlock_if_threaded(lock)
+#define init_subsystem_locks()
+#define destroy_subsystem_locks()
#endif
--
1.7.8.431.g2abf2
^ permalink raw reply related
* Re: [POC PATCH 0/5] Threaded loose object and pack access
From: Thomas Rast @ 2011-12-09 8:45 UTC (permalink / raw)
To: git; +Cc: René Scharfe, Junio C Hamano, Eric Herman, Jeff King
In-Reply-To: <cover.1323419666.git.trast@student.ethz.ch>
Thomas Rast wrote:
> Well, just to make sure we're all left in a confused mess of partly
> conflicting patches, here's another angle on the same thing:
Bleh, obviously that was intended to be a reply to
http://thread.gmane.org/gmane.comp.version-control.git/185932/focus=186231
and CC'd to Peff.
Sorry for the mess. I'll go sulking with a few cups of coffee.
--
Thomas Rast
trast@{inf,student}.ethz.ch
^ permalink raw reply
* [PATCH] tag deletions not rejected with receive.denyDeletes= true
From: Jerome DE VIVIE @ 2011-12-09 8:51 UTC (permalink / raw)
To: git
In-Reply-To: <18285669.571323420520289.JavaMail.root@promailix.prometil.com>
Hello,
I have try to deny tag deletion over push using denyDeletes parameter:
git config --system receive.denyDeletes true
git daemon --reuseaddr --base-path=.. --export-all --verbose --enable=receive-pack
I can push tag deletions despite what the internet says (http://progit.org/book/ch7-1.html#receivedenydeletes). I don't know if it is a bug. Could you have a look, pls ? Thank you
BR
Jérôme
Signed-off-by: Jérôme de Vivie <j.edevivie@prometil.com>
---
builtin/receive-pack.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 7ec68a1..bf91042 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -432,7 +432,7 @@ static const char *update(struct command *cmd)
}
if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) {
- if (deny_deletes && !prefixcmp(name, "refs/heads/")) {
+ if (deny_deletes && (!prefixcmp(name, "refs/heads/") || !prefixcmp(name, "refs/tags/"))) {
rp_error("denying ref deletion for %s", name);
return "deletion prohibited";
}
--
1.7.6.msysgit.0
^ permalink raw reply related
* [PATCH v3 0/6] Fix '&&' chaining in tests
From: Ramkumar Ramachandra @ 2011-12-09 11:29 UTC (permalink / raw)
To: Jonathan Nieder; +Cc: Junio C Hamano, Matthieu Moy, Git List
In-Reply-To: <1323349817-15737-1-git-send-email-artagnon@gmail.com>
This replaces the previous iteration of the series at $gmane/186553.
Thanks to Jonathan for reviewing.
-- Ram
Ramkumar Ramachandra (6):
t3040 (subprojects-basic): fix '&&' chaining, modernize style
t3030 (merge-recursive): use test_expect_code
t1006 (cat-file): use test_cmp
t3200 (branch): fix '&&' chaining
t1510 (worktree): fix '&&' chaining
tests: fix '&&' chaining
t/t1006-cat-file.sh | 119 +++++++++++++--------------
t/t1007-hash-object.sh | 2 +-
t/t1013-loose-object-format.sh | 2 +-
t/t1300-repo-config.sh | 2 +-
t/t1412-reflog-loop.sh | 2 +-
t/t1501-worktree.sh | 6 +-
t/t1510-repo-setup.sh | 4 +-
t/t1511-rev-parse-caret.sh | 2 +-
t/t3030-merge-recursive.sh | 72 ++---------------
t/t3040-subprojects-basic.sh | 144 ++++++++++++++++----------------
t/t3200-branch.sh | 4 +-
t/t3310-notes-merge-manual-resolve.sh | 10 +-
t/t3400-rebase.sh | 4 +-
t/t3418-rebase-continue.sh | 4 +-
t/t3419-rebase-patch-id.sh | 2 +-
15 files changed, 156 insertions(+), 223 deletions(-)
--
1.7.7.3
^ permalink raw reply
* [PATCH 1/6] t3040 (subprojects-basic): fix '&&' chaining, modernize style
From: Ramkumar Ramachandra @ 2011-12-09 11:29 UTC (permalink / raw)
To: Jonathan Nieder; +Cc: Junio C Hamano, Matthieu Moy, Git List
In-Reply-To: <1323430158-14885-1-git-send-email-artagnon@gmail.com>
Breaks in a test assertion's && chain can potentially hide failures
from earlier commands in the chain. Fix instances of this. While at
it, clean up the style to fit the prevailing style. This means:
- Put the opening quote starting each test on the same line as the
test_expect_* invocation.
- Indent the file with tabs, not spaces.
- Use test_expect_code() in preference to checking the exit status of
various statements by hand.
- Guard commands that prepare test input for individual tests in the
same test_expect_success, so that their scope is clearer and errors
at that stage can be caught.
- Use <<-\EOF in preference to <<EOF to save readers the trouble of
looking for variable interpolations.
- Include "setup" in the titles of test assertions that prepare for
later ones to make it more obvious which tests can be skipped.
Helped-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
t/t3040-subprojects-basic.sh | 144 +++++++++++++++++++++---------------------
1 files changed, 72 insertions(+), 72 deletions(-)
diff --git a/t/t3040-subprojects-basic.sh b/t/t3040-subprojects-basic.sh
index f6973e9..0a4ff6d 100755
--- a/t/t3040-subprojects-basic.sh
+++ b/t/t3040-subprojects-basic.sh
@@ -3,81 +3,81 @@
test_description='Basic subproject functionality'
. ./test-lib.sh
-test_expect_success 'Super project creation' \
- ': >Makefile &&
- git add Makefile &&
- git commit -m "Superproject created"'
-
-
-cat >expected <<EOF
-:000000 160000 00000... A sub1
-:000000 160000 00000... A sub2
-EOF
-test_expect_success 'create subprojects' \
- 'mkdir sub1 &&
- ( cd sub1 && git init && : >Makefile && git add * &&
- git commit -q -m "subproject 1" ) &&
- mkdir sub2 &&
- ( cd sub2 && git init && : >Makefile && git add * &&
- git commit -q -m "subproject 2" ) &&
- git update-index --add sub1 &&
- git add sub2 &&
- git commit -q -m "subprojects added" &&
- git diff-tree --abbrev=5 HEAD^ HEAD |cut -d" " -f-3,5- >current &&
- test_cmp expected current'
-
-git branch save HEAD
-
-test_expect_success 'check if fsck ignores the subprojects' \
- 'git fsck --full'
-
-test_expect_success 'check if commit in a subproject detected' \
- '( cd sub1 &&
- echo "all:" >>Makefile &&
- echo " true" >>Makefile &&
- git commit -q -a -m "make all" ) && {
- git diff-files --exit-code
- test $? = 1
- }'
-
-test_expect_success 'check if a changed subproject HEAD can be committed' \
- 'git commit -q -a -m "sub1 changed" && {
- git diff-tree --exit-code HEAD^ HEAD
- test $? = 1
- }'
-
-test_expect_success 'check if diff-index works for subproject elements' \
- 'git diff-index --exit-code --cached save -- sub1
- test $? = 1'
-
-test_expect_success 'check if diff-tree works for subproject elements' \
- 'git diff-tree --exit-code HEAD^ HEAD -- sub1
- test $? = 1'
-
-test_expect_success 'check if git diff works for subproject elements' \
- 'git diff --exit-code HEAD^ HEAD
- test $? = 1'
-
-test_expect_success 'check if clone works' \
- 'git ls-files -s >expected &&
- git clone -l -s . cloned &&
- ( cd cloned && git ls-files -s ) >current &&
- test_cmp expected current'
-
-test_expect_success 'removing and adding subproject' \
- 'git update-index --force-remove -- sub2 &&
- mv sub2 sub3 &&
- git add sub3 &&
- git commit -q -m "renaming a subproject" && {
- git diff -M --name-status --exit-code HEAD^ HEAD
- test $? = 1
- }'
+test_expect_success 'setup: create superproject' '
+ : >Makefile &&
+ git add Makefile &&
+ git commit -m "Superproject created"
+'
+
+test_expect_success 'setup: create subprojects' '
+ mkdir sub1 &&
+ ( cd sub1 && git init && : >Makefile && git add * &&
+ git commit -q -m "subproject 1" ) &&
+ mkdir sub2 &&
+ ( cd sub2 && git init && : >Makefile && git add * &&
+ git commit -q -m "subproject 2" ) &&
+ git update-index --add sub1 &&
+ git add sub2 &&
+ git commit -q -m "subprojects added" &&
+ git diff-tree --abbrev=5 HEAD^ HEAD |cut -d" " -f-3,5- >current &&
+ git branch save HEAD &&
+ cat >expected <<-\EOF &&
+ :000000 160000 00000... A sub1
+ :000000 160000 00000... A sub2
+ EOF
+ test_cmp expected current
+'
+
+test_expect_success 'check if fsck ignores the subprojects' '
+ git fsck --full
+'
+
+test_expect_success 'check if commit in a subproject detected' '
+ ( cd sub1 &&
+ echo "all:" >>Makefile &&
+ echo " true" >>Makefile &&
+ git commit -q -a -m "make all" ) &&
+ test_expect_code 1 git diff-files --exit-code
+'
+
+test_expect_success 'check if a changed subproject HEAD can be committed' '
+ git commit -q -a -m "sub1 changed" &&
+ test_expect_code 1 git diff-tree --exit-code HEAD^ HEAD
+'
+
+test_expect_success 'check if diff-index works for subproject elements' '
+ test_expect_code 1 git diff-index --exit-code --cached save -- sub1
+'
+
+test_expect_success 'check if diff-tree works for subproject elements' '
+ test_expect_code 1 git diff-tree --exit-code HEAD^ HEAD -- sub1
+'
+
+test_expect_success 'check if git diff works for subproject elements' '
+ test_expect_code 1 git diff --exit-code HEAD^ HEAD
+'
+
+test_expect_success 'check if clone works' '
+ git ls-files -s >expected &&
+ git clone -l -s . cloned &&
+ ( cd cloned && git ls-files -s ) >current &&
+ test_cmp expected current
+'
+
+test_expect_success 'removing and adding subproject' '
+ git update-index --force-remove -- sub2 &&
+ mv sub2 sub3 &&
+ git add sub3 &&
+ git commit -q -m "renaming a subproject" &&
+ test_expect_code 1 git diff -M --name-status --exit-code HEAD^ HEAD
+'
# the index must contain the object name the HEAD of the
# subproject sub1 was at the point "save"
-test_expect_success 'checkout in superproject' \
- 'git checkout save &&
- git diff-index --exit-code --raw --cached save -- sub1'
+test_expect_success 'checkout in superproject' '
+ git checkout save &&
+ git diff-index --exit-code --raw --cached save -- sub1
+'
# just interesting what happened...
# git diff --name-status -M save master
--
1.7.7.3
^ permalink raw reply related
* [PATCH 2/6] t3030 (merge-recursive): use test_expect_code
From: Ramkumar Ramachandra @ 2011-12-09 11:29 UTC (permalink / raw)
To: Jonathan Nieder; +Cc: Junio C Hamano, Matthieu Moy, Git List
In-Reply-To: <1323430158-14885-1-git-send-email-artagnon@gmail.com>
Use test_expect_code in preference to repeatedly checking exit codes
by hand.
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
t/t3030-merge-recursive.sh | 72 ++++----------------------------------------
1 files changed, 6 insertions(+), 66 deletions(-)
diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh
index 55ef189..a5e3da7 100755
--- a/t/t3030-merge-recursive.sh
+++ b/t/t3030-merge-recursive.sh
@@ -285,17 +285,7 @@ test_expect_success 'merge-recursive simple' '
rm -fr [abcd] &&
git checkout -f "$c2" &&
- git merge-recursive "$c0" -- "$c2" "$c1"
- status=$?
- case "$status" in
- 1)
- : happy
- ;;
- *)
- echo >&2 "why status $status!!!"
- false
- ;;
- esac
+ test_expect_code 1 git merge-recursive "$c0" -- "$c2" "$c1"
'
test_expect_success 'merge-recursive result' '
@@ -334,17 +324,7 @@ test_expect_success 'merge-recursive remove conflict' '
rm -fr [abcd] &&
git checkout -f "$c1" &&
- git merge-recursive "$c0" -- "$c1" "$c5"
- status=$?
- case "$status" in
- 1)
- : happy
- ;;
- *)
- echo >&2 "why status $status!!!"
- false
- ;;
- esac
+ test_expect_code 1 git merge-recursive "$c0" -- "$c1" "$c5"
'
test_expect_success 'merge-recursive remove conflict' '
@@ -388,17 +368,7 @@ test_expect_success 'merge-recursive d/f conflict' '
git reset --hard &&
git checkout -f "$c1" &&
- git merge-recursive "$c0" -- "$c1" "$c4"
- status=$?
- case "$status" in
- 1)
- : happy
- ;;
- *)
- echo >&2 "why status $status!!!"
- false
- ;;
- esac
+ test_expect_code 1 git merge-recursive "$c0" -- "$c1" "$c4"
'
test_expect_success 'merge-recursive d/f conflict result' '
@@ -422,17 +392,7 @@ test_expect_success 'merge-recursive d/f conflict the other way' '
git reset --hard &&
git checkout -f "$c4" &&
- git merge-recursive "$c0" -- "$c4" "$c1"
- status=$?
- case "$status" in
- 1)
- : happy
- ;;
- *)
- echo >&2 "why status $status!!!"
- false
- ;;
- esac
+ test_expect_code 1 git merge-recursive "$c0" -- "$c4" "$c1"
'
test_expect_success 'merge-recursive d/f conflict result the other way' '
@@ -456,17 +416,7 @@ test_expect_success 'merge-recursive d/f conflict' '
git reset --hard &&
git checkout -f "$c1" &&
- git merge-recursive "$c0" -- "$c1" "$c6"
- status=$?
- case "$status" in
- 1)
- : happy
- ;;
- *)
- echo >&2 "why status $status!!!"
- false
- ;;
- esac
+ test_expect_code 1 git merge-recursive "$c0" -- "$c1" "$c6"
'
test_expect_success 'merge-recursive d/f conflict result' '
@@ -490,17 +440,7 @@ test_expect_success 'merge-recursive d/f conflict' '
git reset --hard &&
git checkout -f "$c6" &&
- git merge-recursive "$c0" -- "$c6" "$c1"
- status=$?
- case "$status" in
- 1)
- : happy
- ;;
- *)
- echo >&2 "why status $status!!!"
- false
- ;;
- esac
+ test_expect_code 1 git merge-recursive "$c0" -- "$c6" "$c1"
'
test_expect_success 'merge-recursive d/f conflict result' '
--
1.7.7.3
^ permalink raw reply related
* [PATCH 3/6] t1006 (cat-file): use test_cmp
From: Ramkumar Ramachandra @ 2011-12-09 11:29 UTC (permalink / raw)
To: Jonathan Nieder; +Cc: Junio C Hamano, Matthieu Moy, Git List
In-Reply-To: <1323430158-14885-1-git-send-email-artagnon@gmail.com>
In testing, a common paradigm involves checking the expected output
with the actual output: test-lib provides a test_cmp to show the diff
between the two outputs. So, use this function in preference to
calling a human over to compare command outputs by eye.
Helped-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
t/t1006-cat-file.sh | 119 ++++++++++++++++++++++++---------------------------
1 files changed, 56 insertions(+), 63 deletions(-)
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index d8b7f2f..5be3ce9 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -36,66 +36,41 @@ $content"
'
test_expect_success "Type of $type is correct" '
- test $type = "$(git cat-file -t $sha1)"
+ echo $type >expect &&
+ git cat-file -t $sha1 >actual &&
+ test_cmp expect actual
'
test_expect_success "Size of $type is correct" '
- test $size = "$(git cat-file -s $sha1)"
+ echo $size >expect &&
+ git cat-file -s $sha1 >actual &&
+ test_cmp expect actual
'
test -z "$content" ||
test_expect_success "Content of $type is correct" '
- expect="$(maybe_remove_timestamp "$content" $no_ts)"
- actual="$(maybe_remove_timestamp "$(git cat-file $type $sha1)" $no_ts)"
-
- if test "z$expect" = "z$actual"
- then
- : happy
- else
- echo "Oops: expected $expect"
- echo "but got $actual"
- false
- fi
+ maybe_remove_timestamp "$content" $no_ts >expect &&
+ maybe_remove_timestamp "$(git cat-file $type $sha1)" $no_ts >actual &&
+ test_cmp expect actual
'
test_expect_success "Pretty content of $type is correct" '
- expect="$(maybe_remove_timestamp "$pretty_content" $no_ts)"
- actual="$(maybe_remove_timestamp "$(git cat-file -p $sha1)" $no_ts)"
- if test "z$expect" = "z$actual"
- then
- : happy
- else
- echo "Oops: expected $expect"
- echo "but got $actual"
- false
- fi
+ maybe_remove_timestamp "$pretty_content" $no_ts >expect &&
+ maybe_remove_timestamp "$(git cat-file -p $sha1)" $no_ts >actual &&
+ test_cmp expect actual
'
test -z "$content" ||
test_expect_success "--batch output of $type is correct" '
- expect="$(maybe_remove_timestamp "$batch_output" $no_ts)"
- actual="$(maybe_remove_timestamp "$(echo $sha1 | git cat-file --batch)" $no_ts)"
- if test "z$expect" = "z$actual"
- then
- : happy
- else
- echo "Oops: expected $expect"
- echo "but got $actual"
- false
- fi
+ maybe_remove_timestamp "$batch_output" $no_ts >expect &&
+ maybe_remove_timestamp "$(echo $sha1 | git cat-file --batch)" $no_ts >actual &&
+ test_cmp expect actual
'
test_expect_success "--batch-check output of $type is correct" '
- expect="$sha1 $type $size"
- actual="$(echo_without_newline $sha1 | git cat-file --batch-check)"
- if test "z$expect" = "z$actual"
- then
- : happy
- else
- echo "Oops: expected $expect"
- echo "but got $actual"
- false
- fi
+ echo "$sha1 $type $size" >expect &&
+ echo_without_newline $sha1 | git cat-file --batch-check >actual &&
+ test_cmp expect actual
'
}
@@ -144,10 +119,13 @@ tag_size=$(strlen "$tag_content")
run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_pretty_content" 1
-test_expect_success \
- "Reach a blob from a tag pointing to it" \
- "test '$hello_content' = \"\$(git cat-file blob $tag_sha1)\""
+test_expect_success "Reach a blob from a tag pointing to it" '
+ echo_without_newline "$hello_content" >expect &&
+ git cat-file blob "$tag_sha1" >actual &&
+ test_cmp expect actual
+'
+test_done
for batch in batch batch-check
do
for opt in t s e p
@@ -175,30 +153,41 @@ do
done
test_expect_success "--batch-check for a non-existent named object" '
- test "foobar42 missing
-foobar84 missing" = \
- "$( ( echo foobar42; echo_without_newline foobar84; ) | git cat-file --batch-check)"
+ cat >expect <<\-EOF &&
+foobar42 missing
+foobar84 missing
+EOF
+ echo foobar42; echo_without_newline foobar84 | \
+ git cat-file --batch-check >actual &&
+ test_cmp expect actual
'
test_expect_success "--batch-check for a non-existent hash" '
- test "0000000000000000000000000000000000000042 missing
-0000000000000000000000000000000000000084 missing" = \
- "$( ( echo 0000000000000000000000000000000000000042;
- echo_without_newline 0000000000000000000000000000000000000084; ) \
- | git cat-file --batch-check)"
+ cat >expect <<\-EOF &&
+0000000000000000000000000000000000000042 missing
+0000000000000000000000000000000000000084 missing
+EOF
+ echo 0000000000000000000000000000000000000042;
+ echo_without_newline 0000000000000000000000000000000000000084 | \
+ git cat-file --batch-check >actual &&
+ test_cmp expect actual
'
test_expect_success "--batch for an existent and a non-existent hash" '
- test "$tag_sha1 tag $tag_size
+ cat >expect <<\-EOF &&
+tag_sha1 tag $tag_size
$tag_content
-0000000000000000000000000000000000000000 missing" = \
- "$( ( echo $tag_sha1;
- echo_without_newline 0000000000000000000000000000000000000000; ) \
- | git cat-file --batch)"
+0000000000000000000000000000000000000000 missing
+EOF
+ echo $tag_sha1; echo_without_newline 0000000000000000000000000000000000000000 | \
+ git cat-file --batch >actual &&
+ test_cmp expect_actual
'
test_expect_success "--batch-check for an emtpy line" '
- test " missing" = "$(echo | git cat-file --batch-check)"
+ echo " missing" >expect &&
+ echo | git cat-file --batch-check >actual &&
+ test_cmp expect actual
'
batch_input="$hello_sha1
@@ -218,7 +207,10 @@ deadbeef missing
missing"
test_expect_success '--batch with multiple sha1s gives correct format' '
- test "$(maybe_remove_timestamp "$batch_output" 1)" = "$(maybe_remove_timestamp "$(echo_without_newline "$batch_input" | git cat-file --batch)" 1)"
+ maybe_remove_timestamp "$batch_output" 1 >expect &&
+ maybe_remove_timestamp "echo_without_newline "$batch_input" | \
+ git cat-file --batch" 1 >actual &&
+ test_cmp expect actual
'
batch_check_input="$hello_sha1
@@ -237,8 +229,9 @@ deadbeef missing
missing"
test_expect_success "--batch-check with multiple sha1s gives correct format" '
- test "$batch_check_output" = \
- "$(echo_without_newline "$batch_check_input" | git cat-file --batch-check)"
+ echo "$batch_check_output" >expect &&
+ echo_without_newline "$batch_check_input" | git cat-file --batch-check >actual &&
+ test_cmp expect actual
'
test_done
--
1.7.7.3
^ permalink raw reply related
* [PATCH 4/6] t3200 (branch): fix '&&' chaining
From: Ramkumar Ramachandra @ 2011-12-09 11:29 UTC (permalink / raw)
To: Jonathan Nieder; +Cc: Junio C Hamano, Matthieu Moy, Git List
In-Reply-To: <1323430158-14885-1-git-send-email-artagnon@gmail.com>
Breaks in a test assertion's && chain can potentially hide failures
from earlier commands in the chain. Fix these breaks.
'git branch --help' will fail when git manpages aren't already
installed; now that its status is tested, guard these instances with
'test_might_fail'.
Acked-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
t/t3200-branch.sh | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index bc73c20..95066d0 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -22,7 +22,7 @@ test_expect_success \
test_expect_success \
'git branch --help should not have created a bogus branch' '
- git branch --help </dev/null >/dev/null 2>/dev/null;
+ test_might_fail git branch --help </dev/null >/dev/null 2>/dev/null &&
test_path_is_missing .git/refs/heads/--help
'
@@ -88,7 +88,7 @@ test_expect_success \
test_expect_success \
'git branch -m n/n n should work' \
'git branch -l n/n &&
- git branch -m n/n n
+ git branch -m n/n n &&
test_path_is_file .git/logs/refs/heads/n'
test_expect_success 'git branch -m o/o o should fail when o/p exists' '
--
1.7.7.3
^ permalink raw reply related
* [PATCH 5/6] t1510 (worktree): fix '&&' chaining
From: Ramkumar Ramachandra @ 2011-12-09 11:29 UTC (permalink / raw)
To: Jonathan Nieder; +Cc: Junio C Hamano, Matthieu Moy, Git List
In-Reply-To: <1323430158-14885-1-git-send-email-artagnon@gmail.com>
Breaks in a test assertion's && chain can potentially hide failures
from earlier commands in the chain. Fix these breaks.
'unset' returns non-zero status when the variable passed was already
unset on some shells; now that its status is tested, change these
instances to 'sane_unset'.
Acked-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
t/t1501-worktree.sh | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index 6384983..e661147 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -48,7 +48,7 @@ test_expect_success 'setup: helper for testing rev-parse' '
'
test_expect_success 'setup: core.worktree = relative path' '
- unset GIT_WORK_TREE;
+ sane_unset GIT_WORK_TREE &&
GIT_DIR=repo.git &&
GIT_CONFIG="$(pwd)"/$GIT_DIR/config &&
export GIT_DIR GIT_CONFIG &&
@@ -89,7 +89,7 @@ test_expect_success 'subdir of work tree' '
'
test_expect_success 'setup: core.worktree = absolute path' '
- unset GIT_WORK_TREE;
+ sane_unset GIT_WORK_TREE &&
GIT_DIR=$(pwd)/repo.git &&
GIT_CONFIG=$GIT_DIR/config &&
export GIT_DIR GIT_CONFIG &&
@@ -334,7 +334,7 @@ test_expect_success 'absolute pathspec should fail gracefully' '
'
test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
- >dummy_file
+ >dummy_file &&
echo git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file &&
git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
'
--
1.7.7.3
^ permalink raw reply related
* [PATCH 6/6] tests: fix '&&' chaining
From: Ramkumar Ramachandra @ 2011-12-09 11:29 UTC (permalink / raw)
To: Jonathan Nieder; +Cc: Junio C Hamano, Matthieu Moy, Git List
In-Reply-To: <1323430158-14885-1-git-send-email-artagnon@gmail.com>
Breaks in a test assertion's && chain can potentially hide failures
from earlier commands in the chain. Fix instances of this by adding
'&&' at the end of lines where they're missing; this patch doesn't
intend to make any other changes.
Acked-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
t/t1007-hash-object.sh | 2 +-
t/t1013-loose-object-format.sh | 2 +-
t/t1300-repo-config.sh | 2 +-
t/t1412-reflog-loop.sh | 2 +-
t/t1510-repo-setup.sh | 4 ++--
t/t1511-rev-parse-caret.sh | 2 +-
t/t3310-notes-merge-manual-resolve.sh | 10 +++++-----
t/t3400-rebase.sh | 4 ++--
t/t3418-rebase-continue.sh | 4 ++--
t/t3419-rebase-patch-id.sh | 2 +-
10 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh
index 6d52b82..f83df8e 100755
--- a/t/t1007-hash-object.sh
+++ b/t/t1007-hash-object.sh
@@ -189,7 +189,7 @@ for args in "-w --stdin-paths" "--stdin-paths -w"; do
done
test_expect_success 'corrupt tree' '
- echo abc >malformed-tree
+ echo abc >malformed-tree &&
test_must_fail git hash-object -t tree malformed-tree
'
diff --git a/t/t1013-loose-object-format.sh b/t/t1013-loose-object-format.sh
index 0a9cedd..fbf5f2f 100755
--- a/t/t1013-loose-object-format.sh
+++ b/t/t1013-loose-object-format.sh
@@ -34,7 +34,7 @@ assert_blob_equals() {
}
test_expect_success setup '
- cp -R "$TEST_DIRECTORY/t1013/objects" .git/
+ cp -R "$TEST_DIRECTORY/t1013/objects" .git/ &&
git --version
'
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 51caff0..0690e0e 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -38,7 +38,7 @@ cat > expect << EOF
WhatEver = Second
EOF
test_expect_success 'similar section' '
- git config Cores.WhatEver Second
+ git config Cores.WhatEver Second &&
test_cmp expect .git/config
'
diff --git a/t/t1412-reflog-loop.sh b/t/t1412-reflog-loop.sh
index 647d888..3acd895 100755
--- a/t/t1412-reflog-loop.sh
+++ b/t/t1412-reflog-loop.sh
@@ -20,7 +20,7 @@ test_expect_success 'setup reflog with alternating commits' '
'
test_expect_success 'reflog shows all entries' '
- cat >expect <<-\EOF
+ cat >expect <<-\EOF &&
topic@{0} reset: moving to two
topic@{1} reset: moving to one
topic@{2} reset: moving to two
diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh
index ec50a9a..80aedfc 100755
--- a/t/t1510-repo-setup.sh
+++ b/t/t1510-repo-setup.sh
@@ -603,7 +603,7 @@ test_expect_success '#22a: core.worktree = GIT_DIR = .git dir' '
# like case #6.
setup_repo 22a "$here/22a/.git" "" unset &&
- setup_repo 22ab . "" unset
+ setup_repo 22ab . "" unset &&
mkdir -p 22a/.git/sub 22a/sub &&
mkdir -p 22ab/.git/sub 22ab/sub &&
try_case 22a/.git unset . \
@@ -742,7 +742,7 @@ test_expect_success '#28: core.worktree and core.bare conflict (gitfile case)' '
# Case #29: GIT_WORK_TREE(+core.worktree) overrides core.bare (gitfile case).
test_expect_success '#29: setup' '
setup_repo 29 non-existent gitfile true &&
- mkdir -p 29/sub/sub 29/wt/sub
+ mkdir -p 29/sub/sub 29/wt/sub &&
(
cd 29 &&
GIT_WORK_TREE="$here/29" &&
diff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh
index e043cb7..eaefc77 100755
--- a/t/t1511-rev-parse-caret.sh
+++ b/t/t1511-rev-parse-caret.sh
@@ -6,7 +6,7 @@ test_description='tests for ref^{stuff}'
test_expect_success 'setup' '
echo blob >a-blob &&
- git tag -a -m blob blob-tag `git hash-object -w a-blob`
+ git tag -a -m blob blob-tag `git hash-object -w a-blob` &&
mkdir a-tree &&
echo moreblobs >a-tree/another-blob &&
git add . &&
diff --git a/t/t3310-notes-merge-manual-resolve.sh b/t/t3310-notes-merge-manual-resolve.sh
index 4ec4d11..4367197 100755
--- a/t/t3310-notes-merge-manual-resolve.sh
+++ b/t/t3310-notes-merge-manual-resolve.sh
@@ -389,7 +389,7 @@ test_expect_success 'abort notes merge' '
test_must_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
test_cmp /dev/null output &&
# m has not moved (still == y)
- test "$(git rev-parse refs/notes/m)" = "$(cat pre_merge_y)"
+ test "$(git rev-parse refs/notes/m)" = "$(cat pre_merge_y)" &&
# Verify that other notes refs has not changed (w, x, y and z)
verify_notes w &&
verify_notes x &&
@@ -525,9 +525,9 @@ EOF
test -f .git/NOTES_MERGE_WORKTREE/$commit_sha3 &&
test -f .git/NOTES_MERGE_WORKTREE/$commit_sha4 &&
# Refs are unchanged
- test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/w)"
- test "$(git rev-parse refs/notes/y)" = "$(git rev-parse NOTES_MERGE_PARTIAL^1)"
- test "$(git rev-parse refs/notes/m)" != "$(git rev-parse NOTES_MERGE_PARTIAL^1)"
+ test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/w)" &&
+ test "$(git rev-parse refs/notes/y)" = "$(git rev-parse NOTES_MERGE_PARTIAL^1)" &&
+ test "$(git rev-parse refs/notes/m)" != "$(git rev-parse NOTES_MERGE_PARTIAL^1)" &&
# Mention refs/notes/m, and its current and expected value in output
grep -q "refs/notes/m" output &&
grep -q "$(git rev-parse refs/notes/m)" output &&
@@ -545,7 +545,7 @@ test_expect_success 'resolve situation by aborting the notes merge' '
test_must_fail ls .git/NOTES_MERGE_* >output 2>/dev/null &&
test_cmp /dev/null output &&
# m has not moved (still == w)
- test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/w)"
+ test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/w)" &&
# Verify that other notes refs has not changed (w, x, y and z)
verify_notes w &&
verify_notes x &&
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 6eaecec..c355533 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -172,8 +172,8 @@ test_expect_success 'fail when upstream arg is missing and not configured' '
test_expect_success 'default to @{upstream} when upstream arg is missing' '
git checkout -b default topic &&
- git config branch.default.remote .
- git config branch.default.merge refs/heads/master
+ git config branch.default.remote . &&
+ git config branch.default.merge refs/heads/master &&
git rebase &&
test "$(git rev-parse default~1)" = "$(git rev-parse master)"
'
diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh
index 1e855cd..2680375 100755
--- a/t/t3418-rebase-continue.sh
+++ b/t/t3418-rebase-continue.sh
@@ -51,7 +51,7 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '
test_commit "commit-new-file-F3-on-topic-branch" F3 32 &&
test_when_finished "rm -fr test-bin funny.was.run" &&
mkdir test-bin &&
- cat >test-bin/git-merge-funny <<-EOF
+ cat >test-bin/git-merge-funny <<-EOF &&
#!$SHELL_PATH
case "\$1" in --opt) ;; *) exit 2 ;; esac
shift &&
@@ -77,7 +77,7 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '
test_expect_success 'rebase --continue remembers --rerere-autoupdate' '
rm -fr .git/rebase-* &&
git reset --hard commit-new-file-F3-on-topic-branch &&
- git checkout master
+ git checkout master &&
test_commit "commit-new-file-F3" F3 3 &&
git config rerere.enabled true &&
test_must_fail git rebase -m master topic &&
diff --git a/t/t3419-rebase-patch-id.sh b/t/t3419-rebase-patch-id.sh
index bd8efaf..e70ac10 100755
--- a/t/t3419-rebase-patch-id.sh
+++ b/t/t3419-rebase-patch-id.sh
@@ -39,7 +39,7 @@ run()
}
test_expect_success 'setup' '
- git commit --allow-empty -m initial
+ git commit --allow-empty -m initial &&
git tag root
'
--
1.7.7.3
^ permalink raw reply related
* git-svn clone repositotory without files from codeplex
From: Arkadiy Shapkin @ 2011-12-09 12:28 UTC (permalink / raw)
To: git
Hi
I can't clone svn repository from codeplex
https://vld.svn.codeplex.com/svn/vld . Repository generated by git-svn
doesn't contain files, only log messages.
WBR,
Arkadiy Shapkin*
*
^ permalink raw reply
* Re: [PATCH 2/2] bundle: rewrite builtin to use parse-options
From: Jakub Narebski @ 2011-12-09 13:33 UTC (permalink / raw)
To: Junio C Hamano
Cc: Ramkumar Ramachandra, Jonathan Nieder, Matthieu Moy, Git List
In-Reply-To: <7viplqhbgs.fsf@alter.siamese.dyndns.org>
Junio C Hamano <gitster@pobox.com> writes:
> Ramkumar Ramachandra <artagnon@gmail.com> writes:
>
> > That being said, do you see value in lifting the restriction on
> > opts->long_name and PARSE_OPTS_NODASH not allowed together? The
> > restriction seems quite arbitrary, but I can't justify lifting it
> > unless I can show some valid usecase.
>
> True and true.
>
> As to the first "true", it is because the nodash was introduced only to
> parse "find ... \( ... \)" style parentheses as if they are part of option
> sequence, and that use case only needed a single letter.
>
> As to the second "true", it is because so far we didn't need anything
> longer.
>
> I do not think the name of a subcommand is not a good use case example for
> it, by the way. Unlike parentheses on the command line of "find" that can
> come anywhere and there can be more than one, the subcommand must be the
> first thing on the command line and only one subcommand is given at one
> command invocation.
Well, I think it doesn't have to be true: there can be some options
like e.g. '-n' / '--dry-run' that are common to all subcommands, and
in my opinion they could come before subcommand name.
But if restriction that subcommand name must be first simplifies code,
then let's do it this way.
I agree that subcommands are and must be mutually exclusive --
otherwise they better be implemented as options, not subcommands.
--
Jakub Narębski
^ permalink raw reply
* gittornado: A tornado-based implementation of the git-http-backend in Python
From: Manuel Stocker @ 2011-12-09 13:34 UTC (permalink / raw)
To: git
Hi,
I decided to implement the smart HTTP protocol on top of tornado for
our codehosting platform. It is built as a library but also includes
an example of a simple server.
At the moment, it's in a stage where it is in daily use for accessing
git repositories by a diverse set of different git client
versions/flavours. I have not done any load testing or performance
benchmarking yet, but it should basically scale relatively well due to
it's event-driven nature.
You can find the code at https://github.com/mensi/gittornado
Feedback / patches are highly appreciated.
--
Manuel
^ permalink raw reply
* Re: Question about commit message wrapping
From: Jakub Narebski @ 2011-12-09 13:41 UTC (permalink / raw)
To: Sidney San Martín; +Cc: git
In-Reply-To: <35A5A513-91FD-4EF9-B890-AB3D1550D63F@sidneysm.com>
Sidney San Martín <s@sidneysm.com> writes:
> *Nothing else* in my everyday life works this way anymore. Line
> wrapping gets done on the display end in my email client, my web
> browser, my ebook reader entirely automatically, and it adapts to
> the size of the window.
The problem with automatic wrapping on the display is that there could
be parts of commit message that *shouldn't* be wrapped, like code
sample, or URL... and in plain text you don't have a way to separate
flowed from non-flowed part.
Also with long non-breakable identifiers you sometimes need to wrap by
hand (or use linebreaking algorithm from TeX) or go bit over the limit
to make it look nice.
BTW. proper editor used to create commit message can wrap it for you
;-).
--
Jakub Narębski
^ permalink raw reply
* configure git to not push all remote tracking branches
From: Justin Johnson @ 2011-12-09 15:00 UTC (permalink / raw)
To: git
Hi, I'm looking for some help with pushing to remote repositories.
I accidentally left out the refspec from my git push command and git
pushed all branches that are set up to track the remote repo that I
specified. I would like to disable this, and enforce specifying a
refspec. Is there a way to do this?
e.g.
git push alternateorigin
should not do anything, but
git push alternateorigin mybranch
should push just mybranch.
--
Justin Johnson
^ permalink raw reply
* Re: configure git to not push all remote tracking branches
From: Ramkumar Ramachandra @ 2011-12-09 15:03 UTC (permalink / raw)
To: Justin Johnson; +Cc: git
In-Reply-To: <CAPD5EOjsu-9=CCUJut_bGqv=asp8FeGqL2GhKewgw3SQsArk_A@mail.gmail.com>
Hi Justin,
Justin Johnson wrote:
> git push alternateorigin
> should not do anything, but
> git push alternateorigin mybranch
> should push just mybranch.
$ git config push.default nothing
Note: push.default defaults to "matching"
Cheers.
-- Ram
^ permalink raw reply
* Re: configure git to not push all remote tracking branches
From: Justin Johnson @ 2011-12-09 15:07 UTC (permalink / raw)
To: Ramkumar Ramachandra; +Cc: git
In-Reply-To: <CALkWK0m0f-AGLwKqiKx9Aozwr5oN6FrH5ehG03mmEpB7Di8PWQ@mail.gmail.com>
On Fri, Dec 9, 2011 at 10:03 AM, Ramkumar Ramachandra
<artagnon@gmail.com> wrote:
> Hi Justin,
>
> Justin Johnson wrote:
>> git push alternateorigin
>> should not do anything, but
>> git push alternateorigin mybranch
>> should push just mybranch.
>
> $ git config push.default nothing
> Note: push.default defaults to "matching"
>
> Cheers.
>
> -- Ram
Thank you, that's exactly it. I saw it in the docs for git-config but
wasn't positive that's what I needed.
--Justin
^ permalink raw reply
* [PATCH 0/9] Re-roll rr/revert-cherry-pick v2
From: Ramkumar Ramachandra @ 2011-12-09 15:41 UTC (permalink / raw)
To: Git List; +Cc: Junio C Hamano, Jonathan Nieder
Hi,
The previous iteration had 5 parts ($gmane/186425), and this one has
9. So, I have to explain where the four new patches came from:
- "revert: report fine-grained error messages from insn parser" arises
from Jonathan's request to split "revert: allow mixed pick and
revert instructions".
- "revert: tolerate extra spaces, tabs in insn sheet" comes from
Junio's request to be considerate towards people with fat fingers.
- I put in the other two patches on my own, because I realized that
the tests needed some tightening, lest they hide underlying bugs
(it's happened before).
Apart from that, I've just made changes in response to reviews. I'm
not yet sure what to do about $gmane/186433.
Thanks for reading.
-- Ram
Jonathan Nieder (1):
revert: simplify communicating command-line arguments
Ramkumar Ramachandra (8):
revert: free msg in format_todo()
revert: make commit subjects in insn sheet optional
revert: tolerate extra spaces, tabs in insn sheet
revert: simplify getting commit subject in format_todo()
t3510 (cherry-pick-sequencer): use exit status
t3510 (cherry-pick-sequencer): remove malformed sheet 2
revert: allow mixed pick and revert instructions
revert: report fine-grained error messages from insn parser
builtin/revert.c | 237 ++++++++++++++++++++------------------
t/t3510-cherry-pick-sequence.sh | 157 +++++++++++++++++++++-----
2 files changed, 252 insertions(+), 142 deletions(-)
--
1.7.7.3
^ permalink raw reply
* [PATCH 1/9] revert: free msg in format_todo()
From: Ramkumar Ramachandra @ 2011-12-09 15:41 UTC (permalink / raw)
To: Git List; +Cc: Junio C Hamano, Jonathan Nieder
In-Reply-To: <1323445326-24637-1-git-send-email-artagnon@gmail.com>
Memory allocated to the fields of msg by get_message() isn't freed.
This is potentially a big leak, because fresh memory is allocated to
store the commit message for each commit. Fix this using
free_message().
Reported-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/revert.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/builtin/revert.c b/builtin/revert.c
index 1ea525c..0c6d3d8 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -706,6 +706,7 @@ static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
if (get_message(cur->item, &msg))
return error(_("Cannot get commit message for %s"), sha1_abbrev);
strbuf_addf(buf, "%s %s %s\n", action_str, sha1_abbrev, msg.subject);
+ free_message(&msg);
}
return 0;
}
--
1.7.7.3
^ permalink raw reply related
* [PATCH 2/9] revert: make commit subjects in insn sheet optional
From: Ramkumar Ramachandra @ 2011-12-09 15:41 UTC (permalink / raw)
To: Git List; +Cc: Junio C Hamano, Jonathan Nieder
In-Reply-To: <1323445326-24637-1-git-send-email-artagnon@gmail.com>
Change the instruction sheet format subtly so that the subject of the
commit message that follows the object name is optional. As a result,
an instruction sheet like this is now perfectly valid:
pick 35b0426
pick fbd5bbcbc2e
pick 7362160f
While at it, also fix a bug: currently, we use a commit-id-shaped
buffer to store the word after "pick" in '.git/sequencer/todo'. This
is both wasteful and wrong because it places an artificial limit on
the line length. In addition to literal SHA-1 hexes, expressions like
the following are valid object names in the instruction sheet:
featurebranch~4
rr/revert-cherry-pick-continue^2~12@{12 days ago}
So, eliminate the need for the buffer to keep the object name
altogether, and add a test demonstrating this.
[jc: simplify parsing]
Suggested-by: Jonathan Nieder <jrnieder@gmail.com>
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
builtin/revert.c | 37 ++++++++++++++++---------------------
t/t3510-cherry-pick-sequence.sh | 28 ++++++++++++++++++++++++++++
2 files changed, 44 insertions(+), 21 deletions(-)
diff --git a/builtin/revert.c b/builtin/revert.c
index 0c6d3d8..70055e5 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -711,31 +711,27 @@ static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
return 0;
}
-static struct commit *parse_insn_line(char *start, struct replay_opts *opts)
+static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)
{
unsigned char commit_sha1[20];
- char sha1_abbrev[40];
enum replay_action action;
- int insn_len = 0;
- char *p, *q;
+ char *end_of_object_name;
+ int saved, status;
- if (!prefixcmp(start, "pick ")) {
+ if (!prefixcmp(bol, "pick ")) {
action = CHERRY_PICK;
- insn_len = strlen("pick");
- p = start + insn_len + 1;
- } else if (!prefixcmp(start, "revert ")) {
+ bol += strlen("pick ");
+ } else if (!prefixcmp(bol, "revert ")) {
action = REVERT;
- insn_len = strlen("revert");
- p = start + insn_len + 1;
+ bol += strlen("revert ");
} else
return NULL;
- q = strchr(p, ' ');
- if (!q)
- return NULL;
- q++;
-
- strlcpy(sha1_abbrev, p, q - p);
+ end_of_object_name = bol + strcspn(bol, " \n");
+ saved = *end_of_object_name;
+ *end_of_object_name = '\0';
+ status = get_sha1(bol, commit_sha1);
+ *end_of_object_name = saved;
/*
* Verify that the action matches up with the one in
@@ -748,7 +744,7 @@ static struct commit *parse_insn_line(char *start, struct replay_opts *opts)
return NULL;
}
- if (get_sha1(sha1_abbrev, commit_sha1) < 0)
+ if (status < 0)
return NULL;
return lookup_commit_reference(commit_sha1);
@@ -763,13 +759,12 @@ static int parse_insn_buffer(char *buf, struct commit_list **todo_list,
int i;
for (i = 1; *p; i++) {
- commit = parse_insn_line(p, opts);
+ char *eol = strchrnul(p, '\n');
+ commit = parse_insn_line(p, eol, opts);
if (!commit)
return error(_("Could not parse line %d."), i);
next = commit_list_append(commit, next);
- p = strchrnul(p, '\n');
- if (*p)
- p++;
+ p = *eol ? eol + 1 : eol;
}
if (!*todo_list)
return error(_("No commits parsed."));
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 2c4c1c8..6390f2a 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -13,6 +13,9 @@ test_description='Test cherry-pick continuation features
. ./test-lib.sh
+# Repeat first match 10 times
+_r10='\1\1\1\1\1\1\1\1\1\1'
+
pristine_detach () {
git cherry-pick --quit &&
git checkout -f "$1^0" &&
@@ -328,4 +331,29 @@ test_expect_success 'malformed instruction sheet 2' '
test_must_fail git cherry-pick --continue
'
+test_expect_success 'malformed instruction sheet 3' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick base..anotherpick &&
+ echo "resolved" >foo &&
+ git add foo &&
+ git commit &&
+ sed "s/pick \([0-9a-f]*\)/pick $_r10/" .git/sequencer/todo >new_sheet &&
+ cp new_sheet .git/sequencer/todo &&
+ test_must_fail git cherry-pick --continue
+'
+
+test_expect_success 'commit descriptions in insn sheet are optional' '
+ pristine_detach initial &&
+ test_must_fail git cherry-pick base..anotherpick &&
+ echo "c" >foo &&
+ git add foo &&
+ git commit &&
+ cut -d" " -f1,2 .git/sequencer/todo >new_sheet &&
+ cp new_sheet .git/sequencer/todo &&
+ git cherry-pick --continue &&
+ test_path_is_missing .git/sequencer &&
+ git rev-list HEAD >commits &&
+ test_line_count = 4 commits
+'
+
test_done
--
1.7.7.3
^ permalink raw reply related
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