Git development
 help / color / mirror / Atom feed
* [PATCH, take 2] Linear-time/space rename logic (exact renames only)
From: Linus Torvalds @ 2007-10-22 17:29 UTC (permalink / raw)
  To: Git Mailing List, Junio C Hamano, Shawn O. Pearce
  Cc: David Kastrup, Jeff King, Sven Verdoolaege
In-Reply-To: <alpine.LFD.0.999.0710220932150.10525@woody.linux-foundation.org>


Ok, as some people notices, there were a few bugs in the previous patch. I 
didn't free the hashes correctly (stupid) and the Makefile had "hash.o" 
instead of "hash.h".

But more importantly, my "testing" had been totally broken, because I had 
forgotten to actually move the rename limiting code to after the exact 
rename phase, so when I tested the 100,000 file rename, almost none of the 
new code triggered, so my performance testing was totally bogus.

When fixing that, I noticed that while my new exact rename detection was 
essentially instantaneous, there were some O(n*m) effects in the generic 
diff code from the extremely stupid way we handled the "was it a copy or a 
rename" issue.

To fix that, I just made the "was the path used by a rename" be a counter 
instead of a single "it was used"

With that in place, I could actually time the rename detection of 100,000 
files in my big-rename test repository. This is what it looks like when 
you rename a hundred thousand files:

	[torvalds@woody big-rename]$ time ~/git/git show -C | wc -l
	400006

	real    0m2.675s
	user    0m2.148s
	sys     0m0.540s

(each renamed file is 4 lines: they looks like

	diff --git a/really-big-dir/file-1-1-1-1-1 b/moved-big-dir/file-1-1-1-1-1
	similarity index 100%
	rename from really-big-dir/file-1-1-1-1-1
	rename to moved-big-dir/file-1-1-1-1-1

and the extra six lines is from a one-liner commit message and all the 
commit information and spacing).

So two seconds to do that exact rename detection.

Now, I can't really compare it to the "before" stage, because that is just 
so horrible. The rename detection limit triggers, so you never even get 
any renames, but if I were to move the limit check later (like I do in 
this patch) without my other fixes, it would take hours. Trying to do ten 
billion (100k x 100k) SHA1 and pathname compares simply isn't going to 
work.

But I *can* compare it to the old code *with* the rename limiting, which 
still wastes all the time on the whole "copy usage" crap. So here are the 
numbers on that repo without the patch:

	[torvalds@woody big-rename]$ time git show -C | wc -l
	1400006
	
	real    0m12.383s
	user    0m12.365s
	sys     0m0.160s

That's right: we used to take 12 seconds and not even do renames (now you 
see fourteen lines per file moved: seven lines each for the delete and the 
create of a one-liner file, and the same extra six lines of commit 
information).

So it not only makes the rename detection possible in the first place, it 
removes some stupid code that made it take a long time even when it 
failed!

Now, I'd still be careful with this patch, and I'd really like people to 
double-check all my logic, but I think it's worthy of some 'pu' love.

		Linus
---

 Makefile          |    4 +-
 diff.c            |   24 +----
 diffcore-rename.c |  275 ++++++++++++++++++++++++++++++----------------------
 diffcore.h        |    2 +-
 hash.c            |  110 +++++++++++++++++++++
 hash.h            |   43 ++++++++
 6 files changed, 321 insertions(+), 137 deletions(-)

diff --git a/Makefile b/Makefile
index 8db4dbe..b1ca186 100644
--- a/Makefile
+++ b/Makefile
@@ -291,7 +291,7 @@ LIB_H = \
 	run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
 	tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
 	utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \
-	mailmap.h remote.h
+	mailmap.h remote.h hash.h
 
 DIFF_OBJS = \
 	diff.o diff-lib.o diffcore-break.o diffcore-order.o \
@@ -301,7 +301,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 \
+	interpolate.o hash.o \
 	lockfile.o \
 	patch-ids.o \
 	object.o pack-check.o pack-write.o patch-delta.o path.o pkt-line.o \
diff --git a/diff.c b/diff.c
index 6648e01..e892030 100644
--- a/diff.c
+++ b/diff.c
@@ -2586,9 +2586,9 @@ void diff_debug_filepair(const struct diff_filepair *p, int i)
 {
 	diff_debug_filespec(p->one, i, "one");
 	diff_debug_filespec(p->two, i, "two");
-	fprintf(stderr, "score %d, status %c stays %d broken %d\n",
+	fprintf(stderr, "score %d, status %c rename_used %d broken %d\n",
 		p->score, p->status ? p->status : '?',
-		p->source_stays, p->broken_pair);
+		p->rename_used, p->broken_pair);
 }
 
 void diff_debug_queue(const char *msg, struct diff_queue_struct *q)
@@ -2606,8 +2606,8 @@ void diff_debug_queue(const char *msg, struct diff_queue_struct *q)
 
 static void diff_resolve_rename_copy(void)
 {
-	int i, j;
-	struct diff_filepair *p, *pp;
+	int i;
+	struct diff_filepair *p;
 	struct diff_queue_struct *q = &diff_queued_diff;
 
 	diff_debug_queue("resolve-rename-copy", q);
@@ -2629,27 +2629,15 @@ static void diff_resolve_rename_copy(void)
 		 * either in-place edit or rename/copy edit.
 		 */
 		else if (DIFF_PAIR_RENAME(p)) {
-			if (p->source_stays) {
-				p->status = DIFF_STATUS_COPIED;
-				continue;
-			}
 			/* See if there is some other filepair that
 			 * copies from the same source as us.  If so
 			 * we are a copy.  Otherwise we are either a
 			 * copy if the path stays, or a rename if it
 			 * does not, but we already handled "stays" case.
 			 */
-			for (j = i + 1; j < q->nr; j++) {
-				pp = q->queue[j];
-				if (strcmp(pp->one->path, p->one->path))
-					continue; /* not us */
-				if (!DIFF_PAIR_RENAME(pp))
-					continue; /* not a rename/copy */
-				/* pp is a rename/copy from the same source */
+			if (--p->one->rename_used > 0)
 				p->status = DIFF_STATUS_COPIED;
-				break;
-			}
-			if (!p->status)
+			else
 				p->status = DIFF_STATUS_RENAMED;
 		}
 		else if (hashcmp(p->one->sha1, p->two->sha1) ||
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 2077a9b..cc105db 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -4,6 +4,7 @@
 #include "cache.h"
 #include "diff.h"
 #include "diffcore.h"
+#include "hash.h"
 
 /* Table of rename/copy destinations */
 
@@ -55,12 +56,10 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
 static struct diff_rename_src {
 	struct diff_filespec *one;
 	unsigned short score; /* to remember the break score */
-	unsigned src_path_left : 1;
 } *rename_src;
 static int rename_src_nr, rename_src_alloc;
 
 static struct diff_rename_src *register_rename_src(struct diff_filespec *one,
-						   int src_path_left,
 						   unsigned short score)
 {
 	int first, last;
@@ -92,33 +91,9 @@ static struct diff_rename_src *register_rename_src(struct diff_filespec *one,
 			(rename_src_nr - first - 1) * sizeof(*rename_src));
 	rename_src[first].one = one;
 	rename_src[first].score = score;
-	rename_src[first].src_path_left = src_path_left;
 	return &(rename_src[first]);
 }
 
-static int is_exact_match(struct diff_filespec *src,
-			  struct diff_filespec *dst,
-			  int contents_too)
-{
-	if (src->sha1_valid && dst->sha1_valid &&
-	    !hashcmp(src->sha1, dst->sha1))
-		return 1;
-	if (!contents_too)
-		return 0;
-	if (diff_populate_filespec(src, 1) || diff_populate_filespec(dst, 1))
-		return 0;
-	if (src->size != dst->size)
-		return 0;
-	if (src->sha1_valid && dst->sha1_valid)
-	    return !hashcmp(src->sha1, dst->sha1);
-	if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0))
-		return 0;
-	if (src->size == dst->size &&
-	    !memcmp(src->data, dst->data, src->size))
-		return 1;
-	return 0;
-}
-
 static int basename_same(struct diff_filespec *src, struct diff_filespec *dst)
 {
 	int src_len = strlen(src->path), dst_len = strlen(dst->path);
@@ -216,6 +191,7 @@ static void record_rename_pair(int dst_index, int src_index, int score)
 		die("internal error: dst already matched.");
 
 	src = rename_src[src_index].one;
+	src->rename_used++;
 	one = alloc_filespec(src->path);
 	fill_filespec(one, src->sha1, src->mode);
 
@@ -229,7 +205,6 @@ static void record_rename_pair(int dst_index, int src_index, int score)
 		dp->score = rename_src[src_index].score;
 	else
 		dp->score = score;
-	dp->source_stays = rename_src[src_index].src_path_left;
 	rename_dst[dst_index].pair = dp;
 }
 
@@ -247,19 +222,127 @@ static int score_compare(const void *a_, const void *b_)
 	return b->score - a->score;
 }
 
-static int compute_stays(struct diff_queue_struct *q,
-			 struct diff_filespec *one)
+struct file_similarity {
+	int src_dst, index;
+	struct diff_filespec *filespec;
+	struct file_similarity *next;
+};
+
+static int find_identical_files(struct file_similarity *src,
+				struct file_similarity *dst)
 {
-	int i;
-	for (i = 0; i < q->nr; i++) {
-		struct diff_filepair *p = q->queue[i];
-		if (strcmp(one->path, p->two->path))
-			continue;
-		if (DIFF_PAIR_RENAME(p)) {
-			return 0; /* something else is renamed into this */
+	int renames = 0;
+	do {
+		struct diff_filespec *one = src->filespec;
+		struct file_similarity *p, *best;
+		int i = 100;
+
+		best = NULL;
+		for (p = dst; p; p = p->next) {
+			struct diff_filespec *two = p->filespec;
+
+			/* Already picked as a destination? */
+			if (!p->src_dst)
+				continue;
+			/* False hash collission? */
+			if (hashcmp(one->sha1, two->sha1))
+				continue;
+			best = p;
+			if (basename_same(one, two))
+				break;
+
+			/* Too many identical alternatives? Pick one */
+			if (!--i)
+				break;
 		}
+		if (best) {
+			best->src_dst = 0;
+			record_rename_pair(best->index, src->index, MAX_SCORE);
+			renames++;
+		}
+	} while ((src = src->next) != NULL);
+	return renames;
+}
+
+/*
+ * Note: the rest of the rename logic depends on this
+ * phase also populating all the filespecs for any
+ * entry that isn't matched up with an exact rename.
+ */
+static void free_similarity_list(struct file_similarity *p)
+{
+	while (p) {
+		struct file_similarity *entry = p;
+		p = p->next;
+
+		/* Stupid special case, see note above! */
+		diff_populate_filespec(entry->filespec, 0);
+		free(entry);
+	}
+}
+
+static int find_same_files(void *ptr)
+{
+	int ret;
+	struct file_similarity *p = ptr;
+	struct file_similarity *src = NULL, *dst = NULL;
+
+	/* Split the hash list up into sources and destinations */
+	do {
+		struct file_similarity *entry = p;
+		p = p->next;
+		if (entry->src_dst < 0) {
+			entry->next = src;
+			src = entry;
+		} else {
+			entry->next = dst;
+			dst = entry;
+		}
+	} while (p);
+
+	/*
+	 * If we have both sources *and* destinations, see if
+	 * we can match them up
+	 */
+	ret = (src && dst) ? find_identical_files(src, dst) : 0;
+
+	/* Free the hashes and return the number of renames found */
+	free_similarity_list(src);
+	free_similarity_list(dst);
+	return ret;
+}
+
+static unsigned int hash_filespec(struct diff_filespec *filespec)
+{
+	unsigned int hash;
+	if (!filespec->sha1_valid) {
+		if (diff_populate_filespec(filespec, 0))
+			return 0;
+		hash_sha1_file(filespec->data, filespec->size, "blob", filespec->sha1);
+	}
+	memcpy(&hash, filespec->sha1, sizeof(hash));
+	return hash;
+}
+
+static void insert_file_table(struct hash_table *table, int src_dst, int index, struct diff_filespec *filespec)
+{
+	void **pos;
+	unsigned int hash;
+	struct file_similarity *entry = xmalloc(sizeof(*entry));
+
+	entry->src_dst = src_dst;
+	entry->index = index;
+	entry->filespec = filespec;
+	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;
 	}
-	return 1;
 }
 
 /*
@@ -268,50 +351,26 @@ static int compute_stays(struct diff_queue_struct *q,
  * The first round matches up the up-to-date entries,
  * and then during the second round we try to match
  * cache-dirty entries as well.
- *
- * Note: the rest of the rename logic depends on this
- * phase also populating all the filespecs for any
- * entry that isn't matched up with an exact rename,
- * see "is_exact_match()".
  */
 static int find_exact_renames(void)
 {
-	int rename_count = 0;
-	int contents_too;
-
-	for (contents_too = 0; contents_too < 2; contents_too++) {
-		int i;
-
-		for (i = 0; i < rename_dst_nr; i++) {
-			struct diff_filespec *two = rename_dst[i].two;
-			int j;
-
-			if (rename_dst[i].pair)
-				continue; /* dealt with an earlier round */
-			for (j = 0; j < rename_src_nr; j++) {
-				int k;
-				struct diff_filespec *one = rename_src[j].one;
-				if (!is_exact_match(one, two, contents_too))
-					continue;
-
-				/* see if there is a basename match, too */
-				for (k = j; k < rename_src_nr; k++) {
-					one = rename_src[k].one;
-					if (basename_same(one, two) &&
-						is_exact_match(one, two,
-							contents_too)) {
-						j = k;
-						break;
-					}
-				}
-
-				record_rename_pair(i, j, (int)MAX_SCORE);
-				rename_count++;
-				break; /* we are done with this entry */
-			}
-		}
-	}
-	return rename_count;
+	int i;
+	struct hash_table file_table;
+
+	init_hash(&file_table);
+	for (i = 0; i < rename_src_nr; i++)
+		insert_file_table(&file_table, -1, i, rename_src[i].one);
+
+	for (i = 0; i < rename_dst_nr; i++)
+		insert_file_table(&file_table, 1, i, rename_dst[i].two);
+
+	/* Find the renames */
+	i = for_each_hash(&file_table, find_same_files);
+
+	/* .. and free the hash data structure */
+	free_hash(&file_table);
+
+	return i;
 }
 
 void diffcore_rename(struct diff_options *options)
@@ -340,20 +399,36 @@ void diffcore_rename(struct diff_options *options)
 				locate_rename_dst(p->two, 1);
 		}
 		else if (!DIFF_FILE_VALID(p->two)) {
-			/* If the source is a broken "delete", and
+			/*
+			 * If the source is a broken "delete", and
 			 * they did not really want to get broken,
 			 * that means the source actually stays.
+			 * So we increment the "rename_used" score
+			 * by one, to indicate ourselves as a user
 			 */
-			int stays = (p->broken_pair && !p->score);
-			register_rename_src(p->one, stays, p->score);
+			if (p->broken_pair && !p->score)
+				p->one->rename_used++;
+			register_rename_src(p->one, p->score);
+		}
+		else if (detect_rename == DIFF_DETECT_COPY) {
+			/*
+			 * Increment the "rename_used" score by
+			 * one, to indicate ourselves as a user.
+			 */
+			p->one->rename_used++;
+			register_rename_src(p->one, p->score);
 		}
-		else if (detect_rename == DIFF_DETECT_COPY)
-			register_rename_src(p->one, 1, p->score);
 	}
 	if (rename_dst_nr == 0 || rename_src_nr == 0)
 		goto cleanup; /* nothing to do */
 
 	/*
+	 * We really want to cull the candidates list early
+	 * with cheap tests in order to avoid doing deltas.
+	 */
+	rename_count = find_exact_renames();
+
+	/*
 	 * This basically does a test for the rename matrix not
 	 * growing larger than a "rename_limit" square matrix, ie:
 	 *
@@ -369,12 +444,6 @@ void diffcore_rename(struct diff_options *options)
 	if (rename_dst_nr * rename_src_nr > rename_limit * rename_limit)
 		goto cleanup;
 
-	/*
-	 * We really want to cull the candidates list early
-	 * with cheap tests in order to avoid doing deltas.
-	 */
-	rename_count = find_exact_renames();
-
 	/* Have we run out the created file pool?  If so we can avoid
 	 * doing the delta matrix altogether.
 	 */
@@ -474,16 +543,7 @@ void diffcore_rename(struct diff_options *options)
 					pair_to_free = p;
 			}
 			else {
-				for (j = 0; j < rename_dst_nr; j++) {
-					if (!rename_dst[j].pair)
-						continue;
-					if (strcmp(rename_dst[j].pair->
-						   one->path,
-						   p->one->path))
-						continue;
-					break;
-				}
-				if (j < rename_dst_nr)
+				if (p->one->rename_used)
 					/* this path remains */
 					pair_to_free = p;
 			}
@@ -509,23 +569,6 @@ void diffcore_rename(struct diff_options *options)
 	*q = outq;
 	diff_debug_queue("done collapsing", q);
 
-	/* We need to see which rename source really stays here;
-	 * earlier we only checked if the path is left in the result,
-	 * but even if a path remains in the result, if that is coming
-	 * from copying something else on top of it, then the original
-	 * source is lost and does not stay.
-	 */
-	for (i = 0; i < q->nr; i++) {
-		struct diff_filepair *p = q->queue[i];
-		if (DIFF_PAIR_RENAME(p) && p->source_stays) {
-			/* If one appears as the target of a rename-copy,
-			 * then mark p->source_stays = 0; otherwise
-			 * leave it as is.
-			 */
-			p->source_stays = compute_stays(q, p->one);
-		}
-	}
-
 	for (i = 0; i < rename_dst_nr; i++) {
 		diff_free_filespec_data(rename_dst[i].two);
 		free(rename_dst[i].two);
diff --git a/diffcore.h b/diffcore.h
index eb618b1..ceda932 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -30,6 +30,7 @@ struct diff_filespec {
 	const char *funcname_pattern_ident;
 	unsigned long size;
 	int xfrm_flags;		 /* for use by the xfrm */
+	int rename_used;         /* Count of rename users */
 	unsigned short mode;	 /* file mode */
 	unsigned sha1_valid : 1; /* if true, use sha1 and trust mode;
 				  * if false, use the name and read from
@@ -56,7 +57,6 @@ struct diff_filepair {
 	struct diff_filespec *two;
 	unsigned short int score;
 	char status; /* M C R N D U (see Documentation/diff-format.txt) */
-	unsigned source_stays : 1; /* all of R/C are copies */
 	unsigned broken_pair : 1;
 	unsigned renamed_pair : 1;
 	unsigned is_unmerged : 1;
diff --git a/hash.c b/hash.c
new file mode 100644
index 0000000..7b492d4
--- /dev/null
+++ b/hash.c
@@ -0,0 +1,110 @@
+/*
+ * Some generic hashing helpers.
+ */
+#include "cache.h"
+#include "hash.h"
+
+/*
+ * Look up a hash entry in the hash table. Return the pointer to
+ * the existing entry, or the empty slot if none existed. The caller
+ * can then look at the (*ptr) to see whether it existed or not.
+ */
+static struct hash_table_entry *lookup_hash_entry(unsigned int hash, struct hash_table *table)
+{
+	unsigned int size = table->size, nr = hash % size;
+	struct hash_table_entry *array = table->array;
+
+	while (array[nr].ptr) {
+		if (array[nr].hash == hash)
+			break;
+		nr++;
+		if (nr >= size)
+			nr = 0;
+	}
+	return array + nr;
+}
+
+
+/*
+ * Insert a new hash entry pointer into the table.
+ *
+ * If that hash entry already existed, return the pointer to
+ * the existing entry (and the caller can create a list of the
+ * 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)
+{
+	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;
+}
+
+static void grow_hash_table(struct hash_table *table)
+{
+	unsigned int i;
+	unsigned int old_size = table->size, new_size;
+	struct hash_table_entry *old_array = table->array, *new_array;
+
+	new_size = alloc_nr(old_size);
+	new_array = xcalloc(sizeof(struct hash_table_entry), new_size);
+	table->size = new_size;
+	table->array = new_array;
+	table->nr = 0;
+	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);
+	}
+	free(old_array);
+}
+
+void *lookup_hash(unsigned int hash, struct hash_table *table)
+{
+	if (!table->array)
+		return NULL;
+	return &lookup_hash_entry(hash, table)->ptr;
+}
+
+void **insert_hash(unsigned int hash, void *ptr, 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);
+}
+
+int for_each_hash(struct hash_table *table, int (*fn)(void *))
+{
+	int sum = 0;
+	unsigned int i;
+	unsigned int size = table->size;
+	struct hash_table_entry *array = table->array;
+
+	for (i = 0; i < size; i++) {
+		void *ptr = array->ptr;
+		array++;
+		if (ptr) {
+			int val = fn(ptr);
+			if (val < 0)
+				return val;
+			sum += val;
+		}
+	}
+	return sum;
+}
+
+void free_hash(struct hash_table *table)
+{
+	free(table->array);
+	table->array = NULL;
+	table->size = 0;
+	table->nr = 0;
+}
diff --git a/hash.h b/hash.h
new file mode 100644
index 0000000..5056c9a
--- /dev/null
+++ b/hash.h
@@ -0,0 +1,43 @@
+#ifndef HASH_H
+#define HASH_H
+
+/*
+ * These are some simple generic hash table helper functions.
+ * Not necessarily suitable for all users, but good for things
+ * where you want to just keep track of a list of things, and
+ * have a good hash to use on them.
+ *
+ * It keeps the hash table at roughly 50-75% free, so the memory
+ * cost of the hash table itself is roughly
+ *
+ *	3 * 2*sizeof(void *) * nr_of_objects
+ *
+ * bytes. 
+ *
+ * FIXME: on 64-bit architectures, we waste memory. It would be
+ * good to have just 32-bit pointers, requiring a special allocator
+ * for hashed entries or something.
+ */
+struct hash_table_entry {
+	unsigned int hash;
+	void *ptr;
+};
+
+struct hash_table {
+	unsigned int size, nr;
+	struct hash_table_entry *array;
+};
+
+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 free_hash(struct hash_table *table);
+
+static inline void init_hash(struct hash_table *table)
+{
+	table->size = 0;
+	table->nr = 0;
+	table->array = NULL;
+}
+
+#endif

^ permalink raw reply related

* Re: [PATCH] use only the PATH for exec'ing git commands
From: Johannes Schindelin @ 2007-10-22 17:44 UTC (permalink / raw)
  To: Scott R Parish; +Cc: git
In-Reply-To: <20071022170148.GB29642@srparish.net>

Hi,

On Mon, 22 Oct 2007, Scott R Parish wrote:

>  3 files changed, 61 insertions(+), 105 deletions(-)

Nice.

Ciao,
Dscho

^ permalink raw reply

* Re: best git practices, was Re: Git User's Survey 2007 unfinished summary continued
From: Steffen Prohaska @ 2007-10-22 15:42 UTC (permalink / raw)
  To: Andreas Ericsson
  Cc: Johannes Schindelin, Jakub Narebski, Federico Mena Quintero, git
In-Reply-To: <471CBEB1.2030008@op5.se>


On Oct 22, 2007, at 5:16 PM, Andreas Ericsson wrote:

> Johannes Schindelin wrote:
>> Hi,
>> On Mon, 22 Oct 2007, Andreas Ericsson wrote:
>>> Johannes Schindelin wrote:
>>>
>>>> On Mon, 22 Oct 2007, Andreas Ericsson wrote:
>>>>
>>>>> If I were to suggest any improvements, it'd be to change the  
>>>>> semantics of git-pull to always update the local branches set  
>>>>> up to be merged with the remote tracking branches when they,  
>>>>> prior to fetching, pointed to the same commit, such that when
>>>>>
>>>>> $ git show-ref master
>>>>> d4027a816dd0b416dc8c7b37e2c260e6905f11b6 refs/heads/master
>>>>> d4027a816dd0b416dc8c7b37e2c260e6905f11b6 refs/remotes/origin/ 
>>>>> master
>>>>>
>>>>> refs/heads/master gets set to refs/remotes/origin/master post- 
>>>>> fetch.
>>>> In general, this should fail.  Because you are expected to have  
>>>> local changes in the local branches.
>>>
>>> BS argument.
>> Aha.  So you want to make sure that the local branches are no  
>> longer "purely" local.  And you want to stop updating them when  
>> unpushed changes are in the local branches.
>
> To me, it's more along the lines of "let git help me not make the  
> mistake of hacking on a six-week old codebase when I've explicitly  
> asked it to merge these and those remote tracking branches into  
> these and those local branches". Not updating those branches when  
> there *are* changes on them is something users can understand and  
> will probably also appreciate, but the reason for not allowing even  
> fast-forwards escape me.

Here's also an interesting asymmetry. By default, git push
updates all remote branches matching a local branch. But git
pull "updates" only the current local branch to the state of
the remote head (by updating all local copies of the remote
branches, but merging only a single of these heads).

Maybe this asymmetry adds to the confusion. I see arguments
for both behaviours:
1) In both cases, update only the branch you're on
or
2) in both cases update all matching branches.
(btw, if I do not intend to merge at all, you can always use
"git fetch".)

	Steffen

^ permalink raw reply

* Re: best git practices, was Re: Git User's Survey 2007 unfinished summary continued
From: Robin Rosenberg @ 2007-10-22 17:48 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Wincent Colaiuta, Andreas Ericsson, Jakub Narebski,
	Steffen Prohaska, Federico Mena Quintero, git
In-Reply-To: <Pine.LNX.4.64.0710221428390.25221@racer.site>


My list

     61 show
     35 gitk
     31 diff
     23 fetch
     12 reset
     12 blame
     11 clone
     11 checkout
     10 remote
     10 rebase
      9 status
      5 commit
      4 branch
      3 clean
      2 revert
      2 merge
      2 ls-remote
      2 gui

-- robin

^ permalink raw reply

* Re: [PATCH] Dissociating a repository from its alternates
From: Michael Hendricks @ 2007-10-22 18:04 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Johannes Schindelin, git
In-Reply-To: <7v8xex50aa.fsf@assigned-by-dhcp.cox.net>

On Fri, Feb 16, 2007 at 12:13:01PM -0800, Junio C Hamano wrote:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > On Wed, 14 Feb 2007, Junio C Hamano wrote:
> >
> >> People often start out with "clone -l -s" (or --reference) and
> >> later wish to dissociate the repository from its alternates.
> >
> > Why not make a really dumb script which just _copies_ (or maybe 
> > optionally hard link) the objects from the alternate repo, and then kills 
> > the alternatives file? That should be easier. You always can repack after 
> > that.
> 
> I think that is much safer.

Was such a script ever incorporated into Git?

-- 
Michael

^ permalink raw reply

* Re: best git practices, was Re: Git User's Survey 2007 unfinished summary continued
From: Daniel Barkalow @ 2007-10-22 18:06 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Andreas Ericsson, Jakub Narebski, Steffen Prohaska,
	Federico Mena Quintero, git
In-Reply-To: <Pine.LNX.4.64.0710221445170.25221@racer.site>

On Mon, 22 Oct 2007, Johannes Schindelin wrote:

> Hi,
> 
> On Mon, 22 Oct 2007, Andreas Ericsson wrote:
> 
> > If I were to suggest any improvements, it'd be to change the semantics of
> > git-pull to always update the local branches set up to be merged with the
> > remote tracking branches when they, prior to fetching, pointed to the same
> > commit, such that when
> > 
> > $ git show-ref master
> > d4027a816dd0b416dc8c7b37e2c260e6905f11b6 refs/heads/master
> > d4027a816dd0b416dc8c7b37e2c260e6905f11b6 refs/remotes/origin/master
> > 
> > refs/heads/master gets set to refs/remotes/origin/master post-fetch.
> 
> In general, this should fail.  Because you are expected to have local 
> changes in the local branches.  What you describe suggests that you should 
> not use the branch name "master" at all, but "origin/master".

If you push your changes to the origin soon after making them, you'll only 
have local changes if somebody else changed something while you were 
working on a change. You're expected to create local changes in the local 
branches, but you shouldn't generally sit on them forever, and when you've 
pushed them, you no longer have any difference in content between local 
and remote.

If the project has multiple branches in the central repository, and you 
make changes for each of them at different times, but only one each day, 
the normal case will be to have local changes sitting in at most one of 
the branches, and, in particular, no local changes left in any branch 
other than HEAD.

	-Daniel
*This .sig left intentionally blank*

^ permalink raw reply

* Re: [PATCH] use only the PATH for exec'ing git commands
From: Alex Riesen @ 2007-10-22 19:01 UTC (permalink / raw)
  To: Scott R Parish; +Cc: git
In-Reply-To: <20071022170148.GB29642@srparish.net>

Scott R Parish, Mon, Oct 22, 2007 19:01:48 +0200:
> +static void add_path(struct strbuf *out, const char *path)
> +{
> +	if (path && strlen(path)) {
> +		if (is_absolute_path(path))
> +			strbuf_addstr(out, path);
> +		else
> +			strbuf_addstr(out, make_absolute_path(path));
> +
> +		strbuf_addch(out, ':');

Shouldn't it break MingW32 native port?

> +	}
> +}
> +
> +void setup_path(const char *cmd_path)
> +{
> +	const char *old_path = getenv("PATH");
> +	struct strbuf new_path;
> +
> +	strbuf_init(&new_path, 0);
> +
> +	add_path(&new_path, argv_exec_path);
> +	add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT));
> +	add_path(&new_path, builtin_exec_path);
> +	add_path(&new_path, cmd_path);
> +		

trailing space

> +	if (old_path)
> +		strbuf_addstr(&new_path, old_path);
> +	else 
> +		strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");

the default PATH is platform-dependent. Git is multi-platform.
You should consider putting the path list somewhere in Makefile,
config.mak or configure.

> +
> +	setenv("PATH", new_path.buf, 1);

^ permalink raw reply

* Re: [PATCH] Dissociating a repository from its alternates
From: Johannes Schindelin @ 2007-10-22 19:05 UTC (permalink / raw)
  To: Michael Hendricks; +Cc: Junio C Hamano, git
In-Reply-To: <20071022180424.GA17429@ginosko.local>

Hi,

On Mon, 22 Oct 2007, Michael Hendricks wrote:

> On Fri, Feb 16, 2007 at 12:13:01PM -0800, Junio C Hamano wrote:
> > Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> > 
> > > On Wed, 14 Feb 2007, Junio C Hamano wrote:
> > >
> > >> People often start out with "clone -l -s" (or --reference) and
> > >> later wish to dissociate the repository from its alternates.
> > >
> > > Why not make a really dumb script which just _copies_ (or maybe 
> > > optionally hard link) the objects from the alternate repo, and then kills 
> > > the alternatives file? That should be easier. You always can repack after 
> > > that.
> > 
> > I think that is much safer.
> 
> Was such a script ever incorporated into Git?

Not that I know of, but "git repack -a && rm .git/objects/info/alternates" 
should do what you want.  You can even make a script of it, add some 
documentation and a test case, and earn git fame by posting a patch ;-)

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH] use only the PATH for exec'ing git commands
From: Eric Merritt @ 2007-10-22 19:25 UTC (permalink / raw)
  To: Alex Riesen; +Cc: Scott R Parish, git
In-Reply-To: <20071022190102.GA23714@steel.home>

> the default PATH is platform-dependent. Git is multi-platform.
> You should consider putting the path list somewhere in Makefile,
> config.mak or configure.

This static configuration that you describe is one of the things this
patch is designed to strip out. Compile time configuration breaks down
completly if you don't deploy to the path defined when the system was
compiled. Thats a problem.

^ permalink raw reply

* Re: [PATCH, take 2] Linear-time/space rename logic (exact renames only)
From: Linus Torvalds @ 2007-10-22 19:31 UTC (permalink / raw)
  To: Git Mailing List, Junio C Hamano, Shawn O. Pearce
  Cc: David Kastrup, Jeff King, Sven Verdoolaege
In-Reply-To: <alpine.LFD.0.999.0710221009580.10525@woody.linux-foundation.org>



On Mon, 22 Oct 2007, Linus Torvalds wrote:
> 
> Ok, as some people notices, there were a few bugs in the previous patch. I 
> didn't free the hashes correctly (stupid) and the Makefile had "hash.o" 
> instead of "hash.h".

Ok, there were still more bugs, and before you get too involved with this 
last patch (not that I've seen any comments yet), apply this appended 
patch to actually fix things a bit more first!

Yes, I'm a moron. I hadn't even bothered to run the test-suite on it, and 
that showed several silly problems.

One of the problems was that since the rename detection copied the 
diffspecs around, the "rename_used" count couldn't work right, because 
things got copied around and the count stayed with one diffspec, but not 
the other..

In the kernel, we have a rule that says that any data structure that isn't 
ref-counted is basically a bug, and that was true here too. Instead of 
copying and splitting the diffspecs, just refcount them and keep track of 
how many users there are.

While the above bug was a somewhat subtle issue from me trying to be 
clever in avoiding the O(n*m) file copy/rename reuse issue, there were a 
few issues that were me just being totally braindead: the exact rename 
detection had lost the code that took file modes into account, so it would 
generate "renames" from regular files to symlinks, that the generic diff 
core layer would just split up again.

And even more stupidly, I had matched up the src/dst things when finding 
the rename, which just complicated things (added a totally unnecessary 
need to keep track of a destination being used more than once) and also 
broke the basename matching comparison. Duh.

So here's an incremental patch on top of the previous failed try. And if 
somebody is confused (and that might be me) and cannot get things to 
apply, just holler and I'll send the whole thing again. I might even try 
to clean up the series a bit and do it in stages.

This patch shouldn't change any performance behaviour (well, it might 
speed things up a bit to not allocate those diffspec structures, but it's 
unlikely that is even measurable). It just fixes stuff.

I'm sure there's more to come..

		Linus

---
 diff.c            |   17 ++++++++++++-----
 diffcore-rename.c |   40 ++++++++++++++++++++++------------------
 diffcore.h        |    2 ++
 3 files changed, 36 insertions(+), 23 deletions(-)

diff --git a/diff.c b/diff.c
index e892030..2e74cb3 100644
--- a/diff.c
+++ b/diff.c
@@ -1440,9 +1440,18 @@ struct diff_filespec *alloc_filespec(const char *path)
 	memset(spec, 0, sizeof(*spec));
 	spec->path = (char *)(spec + 1);
 	memcpy(spec->path, path, namelen+1);
+	spec->count = 1;
 	return spec;
 }
 
+void free_filespec(struct diff_filespec *spec)
+{
+	if (!--spec->count) {
+		diff_free_filespec_data(spec);
+		free(spec);
+	}
+}
+
 void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
 		   unsigned short mode)
 {
@@ -2431,10 +2440,8 @@ struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
 
 void diff_free_filepair(struct diff_filepair *p)
 {
-	diff_free_filespec_data(p->one);
-	diff_free_filespec_data(p->two);
-	free(p->one);
-	free(p->two);
+	free_filespec(p->one);
+	free_filespec(p->two);
 	free(p);
 }
 
@@ -2588,7 +2595,7 @@ void diff_debug_filepair(const struct diff_filepair *p, int i)
 	diff_debug_filespec(p->two, i, "two");
 	fprintf(stderr, "score %d, status %c rename_used %d broken %d\n",
 		p->score, p->status ? p->status : '?',
-		p->rename_used, p->broken_pair);
+		p->one->rename_used, p->broken_pair);
 }
 
 void diff_debug_queue(const char *msg, struct diff_queue_struct *q)
diff --git a/diffcore-rename.c b/diffcore-rename.c
index cc105db..3946932 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -184,7 +184,7 @@ static int estimate_similarity(struct diff_filespec *src,
 
 static void record_rename_pair(int dst_index, int src_index, int score)
 {
-	struct diff_filespec *one, *two, *src, *dst;
+	struct diff_filespec *src, *dst;
 	struct diff_filepair *dp;
 
 	if (rename_dst[dst_index].pair)
@@ -192,14 +192,12 @@ static void record_rename_pair(int dst_index, int src_index, int score)
 
 	src = rename_src[src_index].one;
 	src->rename_used++;
-	one = alloc_filespec(src->path);
-	fill_filespec(one, src->sha1, src->mode);
+	src->count++;
 
 	dst = rename_dst[dst_index].two;
-	two = alloc_filespec(dst->path);
-	fill_filespec(two, dst->sha1, dst->mode);
+	dst->count++;
 
-	dp = diff_queue(NULL, one, two);
+	dp = diff_queue(NULL, src, dst);
 	dp->renamed_pair = 1;
 	if (!strcmp(src->path, dst->path))
 		dp->score = rename_src[src_index].score;
@@ -232,21 +230,30 @@ static int find_identical_files(struct file_similarity *src,
 				struct file_similarity *dst)
 {
 	int renames = 0;
+
+	/*
+	 * Walk over all the destinations ...
+	 */
 	do {
-		struct diff_filespec *one = src->filespec;
+		struct diff_filespec *one = dst->filespec;
 		struct file_similarity *p, *best;
 		int i = 100;
 
+		/*
+		 * .. to find the best source match
+		 */
 		best = NULL;
-		for (p = dst; p; p = p->next) {
+		for (p = src; p; p = p->next) {
 			struct diff_filespec *two = p->filespec;
 
-			/* Already picked as a destination? */
-			if (!p->src_dst)
-				continue;
 			/* False hash collission? */
 			if (hashcmp(one->sha1, two->sha1))
 				continue;
+			/* Non-regular files? If so, the modes must match! */
+			if (!S_ISREG(one->mode) || !S_ISREG(two->mode)) {
+				if (one->mode != two->mode)
+					continue;
+			}
 			best = p;
 			if (basename_same(one, two))
 				break;
@@ -256,11 +263,10 @@ static int find_identical_files(struct file_similarity *src,
 				break;
 		}
 		if (best) {
-			best->src_dst = 0;
-			record_rename_pair(best->index, src->index, MAX_SCORE);
+			record_rename_pair(dst->index, best->index, MAX_SCORE);
 			renames++;
 		}
-	} while ((src = src->next) != NULL);
+	} while ((dst = dst->next) != NULL);
 	return renames;
 }
 
@@ -569,10 +575,8 @@ void diffcore_rename(struct diff_options *options)
 	*q = outq;
 	diff_debug_queue("done collapsing", q);
 
-	for (i = 0; i < rename_dst_nr; i++) {
-		diff_free_filespec_data(rename_dst[i].two);
-		free(rename_dst[i].two);
-	}
+	for (i = 0; i < rename_dst_nr; i++)
+		free_filespec(rename_dst[i].two);
 
 	free(rename_dst);
 	rename_dst = NULL;
diff --git a/diffcore.h b/diffcore.h
index ceda932..cc96c20 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -29,6 +29,7 @@ struct diff_filespec {
 	void *cnt_data;
 	const char *funcname_pattern_ident;
 	unsigned long size;
+	int count;               /* Reference count */
 	int xfrm_flags;		 /* for use by the xfrm */
 	int rename_used;         /* Count of rename users */
 	unsigned short mode;	 /* file mode */
@@ -44,6 +45,7 @@ struct diff_filespec {
 };
 
 extern struct diff_filespec *alloc_filespec(const char *);
+extern void free_filespec(struct diff_filespec *);
 extern void fill_filespec(struct diff_filespec *, const unsigned char *,
 			  unsigned short);
 

^ permalink raw reply related

* Re: best git practices, was Re: Git User's Survey 2007 unfinished summary continued
From: Federico Mena Quintero @ 2007-10-22 19:36 UTC (permalink / raw)
  To: Andreas Ericsson; +Cc: Johannes Schindelin, git
In-Reply-To: <471CBEB1.2030008@op5.se>

On Mon, 2007-10-22 at 17:16 +0200, Andreas Ericsson wrote:

> To me, it's more along the lines of "let git help me not make the 
> mistake of hacking on a six-week old codebase when I've explicitly asked 
> it to merge these and those remote tracking branches into these and 
> those local branches". Not updating those branches when there *are* 
> changes on them is something users can understand and will probably also 
> appreciate, but the reason for not allowing even fast-forwards escape me.

I'd love this behavior, FWIW.

The "branches should not track their origin by default" seems suited
only to Linux kernel maintainers who frequently pull from many different
people, not to "random hacker who wants to keep track of a project he
doesn't maintain" :)

  Federico

^ permalink raw reply

* Re: [PATCH, take 2] Linear-time/space rename logic (exact renames only)
From: Linus Torvalds @ 2007-10-22 19:44 UTC (permalink / raw)
  To: Git Mailing List, Junio C Hamano, Shawn O. Pearce
  Cc: David Kastrup, Jeff King, Sven Verdoolaege
In-Reply-To: <alpine.LFD.0.999.0710221207300.30120@woody.linux-foundation.org>



On Mon, 22 Oct 2007, Linus Torvalds wrote:
> 
> I'm sure there's more to come..

One more detail.. The updated comment explains the issue: if we broke a 
file apart, and rename detection joined it back together, the result is 
neither a rename nor a copy, it's a regular modification (and all 
remaining renames will be copies of the original, so don't bother 
decrementing the "rename_used" count).

		Linus

---
 diff.c |   18 ++++++++++++------
 1 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/diff.c b/diff.c
index 2e74cb3..e839f59 100644
--- a/diff.c
+++ b/diff.c
@@ -2636,13 +2636,19 @@ static void diff_resolve_rename_copy(void)
 		 * either in-place edit or rename/copy edit.
 		 */
 		else if (DIFF_PAIR_RENAME(p)) {
-			/* See if there is some other filepair that
-			 * copies from the same source as us.  If so
-			 * we are a copy.  Otherwise we are either a
-			 * copy if the path stays, or a rename if it
-			 * does not, but we already handled "stays" case.
+			/*
+			 * A rename might have re-connected a broken
+			 * pair up, causing the pathnames to be the
+			 * same again. If so, that's not a rename at
+			 * all, just a modification..
+			 *
+			 * Otherwise, see if this source was used for
+			 * multiple renames, in which case we decrement
+			 * the count, and call it a copy.
 			 */
-			if (--p->one->rename_used > 0)
+			if (!strcmp(p->one->path, p->two->path))
+				p->status = DIFF_STATUS_MODIFIED;
+			else if (--p->one->rename_used > 0)
 				p->status = DIFF_STATUS_COPIED;
 			else
 				p->status = DIFF_STATUS_RENAMED;

^ permalink raw reply related

* Re: odd behavior with concurrent fetch/checkout
From: J. Bruce Fields @ 2007-10-22 19:46 UTC (permalink / raw)
  To: git
In-Reply-To: <20071022165125.GG583@fieldses.org>

On Mon, Oct 22, 2007 at 12:51:25PM -0400, J. Bruce Fields wrote:
> Just now I checked out a topic branch in my working repo:
> 
> 	git checkout server-xprt-switch
> 
> and while waiting for it to complete (I just started work and caches
> were all cold), I ran a
> 
> 	git fetch origin
> 
> in another window to update from Linus.  The git fetch gave a warning:
> 
> 	remote: Generating pack...
> 	remote: Counting objects: 7550
> 	remote: Done counting 12885 objects.
> 	remote: Result has 8400 objects.
> 	remote: Deltifying 8400 objects...
> 	remote:  100% (8400/8400) done
> 	Indexing 8400 objects...
> 	remote: Total 8400 (delta 7257), reused 5696 (delta 4586)
> 	 100% (8400/8400) done
> 	Resolving 7257 deltas...
> 	 100% (7257/7257) done
> 	* refs/remotes/origin/master: fast forward to branch 'master' of
> 	* git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
> 	  old..new: d85714d..55b70a0
> 	Cannot fetch into the current branch.

By the way, I should have said--this is with git version
1.5.3.4.208.gc990.

--b.

> 
> Why the warning?  Also, afterwards I was left with server-xprt-switch
> pointing to the tip of the branch I'd just switched from (another
> miscellaneous topic branch).  The working directory was in some
> completely different state--thanks to a quick reset --hard I don't know
> what it was.  Also, in the reflog for the checked-out branch:
> 
> 	commit bac1e7977eb4781e62cee7f1c7c3d13a9e5d8d74
> 	Reflog: server-xprt-switch@{0} (J. Bruce Fields <bfields@citi.umich.edu>)
> 	Reflog message: fetch origin: Undoing incorrectly fetched HEAD.
> 	Author: J. Bruce Fields <bfields@citi.umich.edu>
> 	Date:   Mon Oct 22 12:32:37 2007 -0400
> 	...
> 
> Why was a fetch into the remote fooling with HEAD or anything under
> refs/heads/?
> 
> --b.
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] use only the PATH for exec'ing git commands
From: Scott R Parish @ 2007-10-22 19:59 UTC (permalink / raw)
  To: Alex Riesen, git


> Alex Reisen, Mon, Oct 22, 2007 12:01:
> > +                strbuf_addch(out, ':');
>
> Shouldn't it break MingW32 native port?
>

<snip>

> > +        if (old_path)
> > +                strbuf_addstr(&amp;new_path, old_path);
> > +        else
> > +                strbuf_addstr(&amp;new_path,
"/usr/local/bin:/usr/bin:/bin");
>
> the default PATH is platform-dependent. Git is multi-platform.
> You should consider putting the path list somewhere in Makefile,
> config.mak or configure.
>

The original code was already doing both of these things (see git.c's
prepend_to_path())

sRp

^ permalink raw reply

* Re: [PATCH] use only the PATH for exec'ing git commands
From: Scott R Parish @ 2007-10-22 19:59 UTC (permalink / raw)
  To: Alex Riesen, git


> Alex Reisen, Mon, Oct 22, 2007 12:01:
> > +                strbuf_addch(out, ':');
>
> Shouldn't it break MingW32 native port?
>

<snip>

> > +        if (old_path)
> > +                strbuf_addstr(&amp;new_path, old_path);
> > +        else
> > +                strbuf_addstr(&amp;new_path,
"/usr/local/bin:/usr/bin:/bin");
>
> the default PATH is platform-dependent. Git is multi-platform.
> You should consider putting the path list somewhere in Makefile,
> config.mak or configure.
>

The original code was already doing both of these things (see git.c's
prepend_to_path())

sRp

^ permalink raw reply

* [PATCH] More updates and corrections to the russian translation of git-gui
From: Alex Riesen @ 2007-10-22 20:28 UTC (permalink / raw)
  To: git; +Cc: Shawn O. Pearce, Kirill

In particular many screw-ups after po regeneration were fixed.

Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
---
 po/ru.po |  362 ++++++++++++++++++++++----------------------------------------
 1 files changed, 127 insertions(+), 235 deletions(-)

diff --git a/po/ru.po b/po/ru.po
index ed5b67a..b8e9447 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -8,8 +8,8 @@ msgstr ""
 "Project-Id-Version: git-gui\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2007-10-10 04:04-0400\n"
-"PO-Revision-Date: 2007-10-20 14:29-0500\n"
-"Last-Translator: Kirill <kirillathome@gmail.com>\n"
+"PO-Revision-Date: 2007-10-22 22:30-0200\n"
+"Last-Translator: Alex Riesen <raa.lkml@gmail.com>\n"
 "Language-Team: Russian Translation <git@vger.kernel.org>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -21,9 +21,9 @@ msgid "git-gui: fatal error"
 msgstr "git-gui: критическая ошибка"
 
 #: git-gui.sh:595
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Invalid font specified in %s:"
-msgstr "В оболочке установлен неверный шрифт.%s:"
+msgstr "В %s установлен неверный шрифт:"
 
 #: git-gui.sh:620
 msgid "Main Font"
@@ -31,7 +31,7 @@ msgstr "Шрифт интерфейса"
 
 #: git-gui.sh:621
 msgid "Diff/Console Font"
-msgstr "Шрифт в консоли diff"
+msgstr "Шрифт консоли и изменений (diff)"
 
 #: git-gui.sh:635
 msgid "Cannot find git in PATH."
@@ -64,9 +64,8 @@ msgid "Git directory not found:"
 msgstr "Каталог Git не найден:"
 
 #: git-gui.sh:860
-#, fuzzy
 msgid "Cannot move to top of working directory:"
-msgstr "Каталог.git испорчен: "
+msgstr "Невозможно перейти к корню рабочего каталога репозитория: "
 
 #: git-gui.sh:867
 msgid "Cannot use funny .git directory:"
@@ -78,7 +77,7 @@ msgstr "Отсутствует рабочий каталог"
 
 #: git-gui.sh:1019
 msgid "Refreshing file status..."
-msgstr "Обновление состояния файлов проекта..."
+msgstr "Обновление информации о состоянии файлов..."
 
 #: git-gui.sh:1084
 msgid "Scanning for modified files ..."
@@ -94,7 +93,7 @@ msgstr "Не изменено"
 
 #: git-gui.sh:1527
 msgid "Modified, not staged"
-msgstr "Изменено, но не включено"
+msgstr "Изменено, не подготовлено"
 
 #: git-gui.sh:1528 git-gui.sh:1533
 msgid "Staged for commit"
@@ -105,7 +104,6 @@ msgid "Portions staged for commit"
 msgstr "Части, подготовленные для сохранения"
 
 #: git-gui.sh:1530 git-gui.sh:1535
-#, fuzzy
 msgid "Staged for commit, missing"
 msgstr "Подготовлено для сохранения, отсутствует"
 
@@ -123,7 +121,7 @@ msgstr "Подготовлено для удаления"
 
 #: git-gui.sh:1539
 msgid "Staged for removal, still present"
-msgstr "Подготовлено для удаления, но еще не удалено"
+msgstr "Подготовлено для удаления, еще не удалено"
 
 #: git-gui.sh:1541 git-gui.sh:1542 git-gui.sh:1543 git-gui.sh:1544
 msgid "Requires merge resolution"
@@ -157,7 +155,6 @@ msgid "Branch"
 msgstr "Ветвь"
 
 #: git-gui.sh:1794 lib/choose_rev.tcl:547
-#, fuzzy
 msgid "Commit@@noun"
 msgstr "Состояние"
 
@@ -166,18 +163,16 @@ msgid "Merge"
 msgstr "Объединить"
 
 #: git-gui.sh:1798 lib/choose_rev.tcl:556
-#, fuzzy
 msgid "Remote"
-msgstr "внешний:"
+msgstr "Внешние репозитории"
 
 #: git-gui.sh:1807
 msgid "Browse Current Branch's Files"
 msgstr "Просмотреть файлы текущей ветви"
 
 #: git-gui.sh:1811
-#, fuzzy
 msgid "Browse Branch Files..."
-msgstr "Показать файлы ветви"
+msgstr "Показать файлы ветви..."
 
 #: git-gui.sh:1816
 msgid "Visualize Current Branch's History"
@@ -188,9 +183,9 @@ msgid "Visualize All Branch History"
 msgstr "История всех ветвей наглядно"
 
 #: git-gui.sh:1827
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Browse %s's Files"
-msgstr "Показать файлы ветви"
+msgstr "Показать файлы ветви %s"
 
 #: git-gui.sh:1829
 #, tcl-format
@@ -281,12 +276,10 @@ msgid "Rescan"
 msgstr "Перечитать"
 
 #: git-gui.sh:1953
-#, fuzzy
 msgid "Stage To Commit"
 msgstr "Подготовить для сохранения"
 
 #: git-gui.sh:1958
-#, fuzzy
 msgid "Stage Changed Files To Commit"
 msgstr "Подготовить измененные файлы для сохранения"
 
@@ -303,7 +296,6 @@ msgid "Sign Off"
 msgstr "Подписать"
 
 #: git-gui.sh:1980 git-gui.sh:2296
-#, fuzzy
 msgid "Commit@@verb"
 msgstr "Сохранить"
 
@@ -319,11 +311,10 @@ msgstr "Прервать объединение..."
 msgid "Push..."
 msgstr "Отправить..."
 
-# carbon copy
 #: git-gui.sh:2019 lib/choose_repository.tcl:41
 #, fuzzy
 msgid "Apple"
-msgstr "Apple"
+msgstr ""
 
 #: git-gui.sh:2022 git-gui.sh:2044 lib/about.tcl:13
 #: lib/choose_repository.tcl:44 lib/choose_repository.tcl:50
@@ -347,9 +338,8 @@ msgstr "Помощь"
 msgid "Online Documentation"
 msgstr "Документация в интернете"
 
-# TOVERIFY
 #: git-gui.sh:2165
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "fatal: cannot stat path %s: No such file or directory"
 msgstr "критическая ошибка: %s: нет такого файла или каталога"
 
@@ -358,43 +348,34 @@ msgid "Current Branch:"
 msgstr "Текущая ветвь:"
 
 #: git-gui.sh:2219
-#, fuzzy
 msgid "Staged Changes (Will Commit)"
 msgstr "Подготовлено (будет сохранено)"
 
-# TOVERIFY
 #: git-gui.sh:2239
-#, fuzzy
 msgid "Unstaged Changes"
-msgstr "Изменено"
+msgstr "Изменено (не будет сохранено)"
 
-# carbon copy
 #: git-gui.sh:2286
-#, fuzzy
 msgid "Stage Changed"
-msgstr "Stage Changed"
+msgstr "Подготовить все"
 
 #: git-gui.sh:2302 lib/transport.tcl:93 lib/transport.tcl:182
 msgid "Push"
 msgstr "Отправить"
 
 #: git-gui.sh:2332
-#, fuzzy
 msgid "Initial Commit Message:"
-msgstr "Первоначальный комментарий к состоянию:"
+msgstr "Комментарий к первому состоянию:"
 
 #: git-gui.sh:2333
-#, fuzzy
 msgid "Amended Commit Message:"
-msgstr "Исправленный комментарий к состоянию:"
+msgstr "Комментарий к исправленному состоянию:"
 
 #: git-gui.sh:2334
-#, fuzzy
 msgid "Amended Initial Commit Message:"
-msgstr "Первоначальный комментарий к исправленному состоянию:"
+msgstr "Комментарий к исправленному первоначальному состоянию:"
 
 #: git-gui.sh:2335
-#, fuzzy
 msgid "Amended Merge Commit Message:"
 msgstr "Комментарий к исправленному объединению:"
 
@@ -467,9 +448,7 @@ msgstr ""
 "запущенными из %s\n"
 "\n"
 
-# TOVERIFY
 #: git-gui.sh:2707
-#, fuzzy
 msgid ""
 "\n"
 "This is due to a known issue with the\n"
@@ -491,10 +470,10 @@ msgid ""
 msgstr ""
 "\n"
 "\n"
-"Хорошая замена для %s\n"
-"сохраняет значения для user.name и\n"
-"user.email в Ваш персональный\n"
-"~/.gitconfig файл.\n"
+"Вместо использования %s можно\n"
+"сохранить значения user.name и\n"
+"user.email в Вашем персональном\n"
+"файле ~/.gitconfig.\n"
 
 #: lib/about.tcl:25
 msgid "git-gui - a graphical user interface for Git."
@@ -510,69 +489,56 @@ msgstr "Сохраненное состояние:"
 
 #: lib/blame.tcl:249
 msgid "Copy Commit"
-msgstr "Копировать сохраненное состояние"
+msgstr "Скопировать SHA-1"
 
 #: lib/blame.tcl:369
 #, tcl-format
 msgid "Reading %s..."
 msgstr "Чтение %s..."
 
-# carbon copy
 #: lib/blame.tcl:473
-#, fuzzy
 msgid "Loading copy/move tracking annotations..."
-msgstr "Loading copy/move tracking annotations..."
+msgstr "Загрузка аннотации копирований/переименований..."
 
-# TOVERIFY
 #: lib/blame.tcl:493
-#, fuzzy
 msgid "lines annotated"
-msgstr "строк прокоментировано"
+msgstr "строк прокомментировано"
 
-# carbon copy
 #: lib/blame.tcl:674
-#, fuzzy
 msgid "Loading original location annotations..."
-msgstr "Loading original location annotations..."
+msgstr "Загрузка аннотаций первоначального положения объекта..."
 
-# carbon copy
 #: lib/blame.tcl:677
-#, fuzzy
 msgid "Annotation complete."
-msgstr "Annotation complete."
+msgstr "Аннотация завершена."
 
 #: lib/blame.tcl:731
-#, fuzzy
 msgid "Loading annotation..."
-msgstr "Загрузка %s..."
+msgstr "Загрузка аннотации..."
 
 #: lib/blame.tcl:787
 msgid "Author:"
 msgstr "Автор:"
 
 #: lib/blame.tcl:791
-#, fuzzy
 msgid "Committer:"
-msgstr "Сохраненное состояние:"
+msgstr "Сохранил:"
 
 #: lib/blame.tcl:796
 msgid "Original File:"
 msgstr "Исходный файл:"
 
-# carbon copy
 #: lib/blame.tcl:910
-#, fuzzy
 msgid "Originally By:"
-msgstr "Originally By:"
+msgstr "Источник:"
 
 #: lib/blame.tcl:916
-#, fuzzy
 msgid "In File:"
 msgstr "Файл:"
 
 #: lib/blame.tcl:921
 msgid "Copied Or Moved Here By:"
-msgstr "Кто скопировал/переместил сюда:"
+msgstr "Скопировано/перемещено в:"
 
 #: lib/branch_checkout.tcl:14 lib/branch_checkout.tcl:19
 msgid "Checkout Branch"
@@ -702,7 +668,7 @@ msgid ""
 "\n"
 " Delete the selected branches?"
 msgstr ""
-"Восстановить удаленную ветвь сложно. \n"
+"Восстанавливать удаленные ветви сложно. \n"
 "\n"
 " Удалить выбранные ветви?"
 
@@ -773,14 +739,14 @@ msgid "Browse"
 msgstr "Показать"
 
 #: lib/checkout_op.tcl:79
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Fetching %s from %s"
-msgstr "Получение изменений из %s "
+msgstr "Получение %s из %s "
 
 #: lib/checkout_op.tcl:127
 #, tcl-format
 msgid "fatal: Cannot resolve %s"
-msgstr "критическая ошибка: не могу распознать %s"
+msgstr "критическая ошибка: невозможно разрешить %s"
 
 #: lib/checkout_op.tcl:140 lib/console.tcl:79 lib/database.tcl:31
 msgid "Close"
@@ -807,7 +773,7 @@ msgstr ""
 #: lib/checkout_op.tcl:220
 #, tcl-format
 msgid "Merge strategy '%s' not supported."
-msgstr "Операция объединения '%s' не поддерживается."
+msgstr "Стратегия объединения '%s' не поддерживается."
 
 #: lib/checkout_op.tcl:239
 #, tcl-format
@@ -815,9 +781,8 @@ msgid "Failed to update '%s'."
 msgstr "Не удалось обновить '%s'."
 
 #: lib/checkout_op.tcl:251
-#, fuzzy
 msgid "Staging area (index) is already locked."
-msgstr "Индекс заблокирован."
+msgstr "Рабочая область заблокирована другим процессом."
 
 #: lib/checkout_op.tcl:266
 msgid ""
@@ -829,14 +794,15 @@ msgid ""
 msgstr ""
 "Последнее прочитанное состояние репозитория не соответствует текущему.\n"
 "\n"
-"С момента последней проверки репозиторий был изменен другой программой Git.Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь. \n"
+"С момента последней проверки репозиторий был изменен другой программой Git. "
+"Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь.\n"
 "\n"
 "Это будет сделано сейчас автоматически.\n"
 
 #: lib/checkout_op.tcl:322
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Updating working directory to '%s'..."
-msgstr "Отсутствует рабочий каталог"
+msgstr "Обновление рабочего каталога из '%s'..."
 
 #: lib/checkout_op.tcl:353
 #, tcl-format
@@ -863,9 +829,9 @@ msgstr ""
 "Если вы хотите снова вернуться к какой-нибудь ветви, создайте ее сейчас, начиная с 'Текущего отсоединенного состояния'."
 
 #: lib/checkout_op.tcl:446
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Checked out '%s'."
-msgstr "Перейти..."
+msgstr "Ветвь '%s' сделана текущей."
 
 #: lib/checkout_op.tcl:478
 #, tcl-format
@@ -901,7 +867,6 @@ msgstr ""
 "Этого не должно было произойти. %s завершается."
 
 #: lib/choose_font.tcl:39
-#, fuzzy
 msgid "Select"
 msgstr "Выделить все"
 
@@ -910,15 +875,13 @@ msgid "Font Family"
 msgstr "Шрифт"
 
 #: lib/choose_font.tcl:73
-#, fuzzy
 msgid "Font Size"
-msgstr "Уменьшить размер шрифта"
+msgstr "Размер шрифта"
 
 #: lib/choose_font.tcl:90
 msgid "Font Example"
 msgstr "Пример текста"
 
-# TOVERIFY: what's the Russian version of the font sample (see Windows Fonts).
 #: lib/choose_font.tcl:101
 msgid ""
 "This is example text.\n"
@@ -929,39 +892,34 @@ msgstr ""
 
 #: lib/choose_repository.tcl:25
 msgid "Git Gui"
-msgstr "Git Gui"
+msgstr ""
 
 #: lib/choose_repository.tcl:69 lib/choose_repository.tcl:204
-#, fuzzy
 msgid "Create New Repository"
-msgstr "Из репозитория"
+msgstr "Создать новый репозиторий"
 
 #: lib/choose_repository.tcl:74 lib/choose_repository.tcl:291
-#, fuzzy
 msgid "Clone Existing Repository"
-msgstr "Репозиторий назначения"
+msgstr "Склонировать существующий репозиторий"
 
 #: lib/choose_repository.tcl:79 lib/choose_repository.tcl:800
-#, fuzzy
 msgid "Open Existing Repository"
-msgstr "Репозиторий назначения"
+msgstr "Выбрать существующий репозиторий"
 
-# TOVERIFY
 #: lib/choose_repository.tcl:91
-#, fuzzy
 msgid "Next >"
 msgstr "Дальше >"
 
 #: lib/choose_repository.tcl:152
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Location %s already exists."
-msgstr "Ветвь '%s' уже существует."
+msgstr "Путь '%s' уже существует."
 
 #: lib/choose_repository.tcl:158 lib/choose_repository.tcl:165
 #: lib/choose_repository.tcl:172
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Failed to create repository %s:"
-msgstr "Не удалось полностью сохранить настройки:"
+msgstr "Не удалось создать репозиторий %s:"
 
 #: lib/choose_repository.tcl:209 lib/choose_repository.tcl:309
 msgid "Directory:"
@@ -969,121 +927,98 @@ msgstr "Каталог:"
 
 #: lib/choose_repository.tcl:238 lib/choose_repository.tcl:363
 #: lib/choose_repository.tcl:834
-#, fuzzy
 msgid "Git Repository"
 msgstr "Репозиторий"
 
 #: lib/choose_repository.tcl:253 lib/choose_repository.tcl:260
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Directory %s already exists."
-msgstr "Ветвь '%s' уже существует."
+msgstr "Каталог '%s' уже существует."
 
 #: lib/choose_repository.tcl:265
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "File %s already exists."
-msgstr "Ветвь '%s' уже существует."
+msgstr "Файл '%s' уже существует."
 
 #: lib/choose_repository.tcl:286
-#, fuzzy
 msgid "Clone"
-msgstr "Закрыть"
+msgstr "Склонировать"
 
 #: lib/choose_repository.tcl:299
 msgid "URL:"
 msgstr "Ссылка:"
 
-# TOVERIFY
 #: lib/choose_repository.tcl:319
-#, fuzzy
 msgid "Clone Type:"
 msgstr "Тип клона:"
 
-# TOVERIFY
 #: lib/choose_repository.tcl:325
-#, fuzzy
 msgid "Standard (Fast, Semi-Redundant, Hardlinks)"
 msgstr "Стандартный (Быстрый, полуизбыточный, \"жесткие\" ссылки)"
 
-# TOVERIFY
 #: lib/choose_repository.tcl:331
-#, fuzzy
 msgid "Full Copy (Slower, Redundant Backup)"
-msgstr "Полная копия (Медленный, избыточная резервная копия)"
+msgstr "Полная копия (Медленный, создает резервную копию)"
 
-# TOVERIFY
 #: lib/choose_repository.tcl:337
-#, fuzzy
 msgid "Shared (Fastest, Not Recommended, No Backup)"
 msgstr "Общий (Самый быстрый, не рекомендуется, без резервной копии)"
 
 #: lib/choose_repository.tcl:369 lib/choose_repository.tcl:418
 #: lib/choose_repository.tcl:560 lib/choose_repository.tcl:630
 #: lib/choose_repository.tcl:840 lib/choose_repository.tcl:848
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Not a Git repository: %s"
-msgstr "Не указан репозиторий"
+msgstr "Каталог не является репозиторием: %s"
 
-# TOVERIFY
 #: lib/choose_repository.tcl:405
-#, fuzzy
 msgid "Standard only available for local repository."
 msgstr "Стандартный клон возможен только для локального репозитория."
 
-# TOVERIFY
 #: lib/choose_repository.tcl:409
-#, fuzzy
 msgid "Shared only available for local repository."
 msgstr "Общий клон возможен только для локального репозитория."
 
-# TOVERIFY
 #: lib/choose_repository.tcl:439
-#, fuzzy
 msgid "Failed to configure origin"
-msgstr "Не могу сконфигурировать искходник."
+msgstr "Не могу сконфигурировать исходный репозиторий."
 
 #: lib/choose_repository.tcl:451
 msgid "Counting objects"
 msgstr "Считаю объекты"
 
-# carbon copy
 #: lib/choose_repository.tcl:452
 #, fuzzy
 msgid "buckets"
-msgstr "buckets"
+msgstr ""
 
-# TOVERIFY
 #: lib/choose_repository.tcl:476
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Unable to copy objects/info/alternates: %s"
-msgstr "Не могу скопировать объекты/инфо/альтернативы: %s"
+msgstr "Не могу скопировать objects/info/alternates: %s"
 
 #: lib/choose_repository.tcl:512
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Nothing to clone from %s."
-msgstr "Получение изменений из %s "
+msgstr "Нечего клонировать с %s."
 
-# TOVERIFY
 #: lib/choose_repository.tcl:514 lib/choose_repository.tcl:728
 #: lib/choose_repository.tcl:740
-#, fuzzy
 msgid "The 'master' branch has not been initialized."
 msgstr "Не инициализирована ветвь 'master'."
 
-# TOVERIFY
 #: lib/choose_repository.tcl:527
-#, fuzzy
 msgid "Hardlinks are unavailable.  Falling back to copying."
 msgstr "\"Жесткие ссылки\" не доступны. Буду использовать копирование."
 
 #: lib/choose_repository.tcl:539
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Cloning from %s"
-msgstr "Получение изменений из %s "
+msgstr "Клонирование %s"
 
 #: lib/choose_repository.tcl:570
-#, fuzzy
 msgid "Copying objects"
-msgstr "Сжатие базы объектов"
+msgstr "Копирование objects"
 
 #: lib/choose_repository.tcl:571
 msgid "KiB"
@@ -1096,42 +1031,33 @@ msgstr "Не могу скопировать объект: %s"
 
 #: lib/choose_repository.tcl:605
 msgid "Linking objects"
-msgstr "Связываю объекты"
+msgstr "Создание ссылок на objects"
 
-# TOVERIFY
 #: lib/choose_repository.tcl:606
-#, fuzzy
 msgid "objects"
-msgstr "объектов"
+msgstr "объекты"
 
-# TOVERIFY
 #: lib/choose_repository.tcl:614
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Unable to hardlink object: %s"
 msgstr "Не могу \"жестко связать\" объект: %s"
 
-# TOVERIFY
 #: lib/choose_repository.tcl:669
-#, fuzzy
 msgid "Cannot fetch branches and objects.  See console output for details."
-msgstr "Не могу получить ветви и объекты. Детали - на консоле."
+msgstr "Не могу получить ветви и объекты. Дополнительная информация на консоли."
 
-# TOVERIFY
 #: lib/choose_repository.tcl:680
-#, fuzzy
 msgid "Cannot fetch tags.  See console output for details."
-msgstr "Не могу получить таги. Детали - на консоле."
+msgstr "Не могу получить метки. Дополнительная информация на консоли."
 
-# TOVERIFY
 #: lib/choose_repository.tcl:704
-#, fuzzy
 msgid "Cannot determine HEAD.  See console output for details."
-msgstr "Не могу определить главную ветвь. Детали - на консоле."
+msgstr "Не могу определить HEAD. Дополнительная информация на консоли."
 
 #: lib/choose_repository.tcl:713
 #, tcl-format
 msgid "Unable to cleanup %s"
-msgstr "Не могу почистить %s"
+msgstr "Не могу очистить %s"
 
 #: lib/choose_repository.tcl:719
 msgid "Clone failed."
@@ -1139,7 +1065,7 @@ msgstr "Клонирование не удалось."
 
 #: lib/choose_repository.tcl:726
 msgid "No default branch obtained."
-msgstr "Не возможно получить ветвь по умолчанию."
+msgstr "Не было получено ветви по умолчанию."
 
 #: lib/choose_repository.tcl:737
 #, tcl-format
@@ -1147,9 +1073,8 @@ msgid "Cannot resolve %s as a commit."
 msgstr "Не могу распознать %s как состояние."
 
 #: lib/choose_repository.tcl:749
-#, fuzzy
 msgid "Creating working directory"
-msgstr "Отсутствует рабочий каталог"
+msgstr "Создаю рабочий каталог"
 
 #: lib/choose_repository.tcl:750 lib/index.tcl:15 lib/index.tcl:80
 #: lib/index.tcl:149
@@ -1158,21 +1083,20 @@ msgstr "файлов"
 
 #: lib/choose_repository.tcl:779
 msgid "Initial file checkout failed."
-msgstr "Первое получение файла не удалось."
+msgstr "Не удалось получить начальное состояние файлов репозитория."
 
 #: lib/choose_repository.tcl:795
 msgid "Open"
 msgstr "Открыть"
 
 #: lib/choose_repository.tcl:805
-#, fuzzy
 msgid "Repository:"
-msgstr "Репозиторий"
+msgstr "Репозиторий:"
 
 #: lib/choose_repository.tcl:854
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Failed to open repository %s:"
-msgstr "Не удалось полностью сохранить настройки:"
+msgstr "Не удалось открыть репозиторий %s:"
 
 #: lib/choose_rev.tcl:53
 msgid "This Detached Checkout"
@@ -1205,7 +1129,7 @@ msgstr "Версия не указана."
 
 #: lib/choose_rev.tcl:346
 msgid "Revision expression is empty."
-msgstr "Пустое выражения для определения версии."
+msgstr "Пустое выражение для определения версии."
 
 #: lib/choose_rev.tcl:530
 msgid "Updated"
@@ -1223,7 +1147,7 @@ msgid ""
 msgstr ""
 "Отсутствует состояние для исправления.\n"
 "\n"
-"Вы можете создать начальное сохраненное состояние. Других состояний для исправления нет.\n"
+"Вы создаете первое состояние в репозитории, здесь еще нечего исправлять.\n"
 
 #: lib/commit.tcl:18
 msgid ""
@@ -1257,12 +1181,12 @@ msgid ""
 msgstr ""
 "Последнее прочитанное состояние репозитория не соответствует текущему.\n"
 "\n"
-"С момента последней проверки репозиторий был изменен другой программой Git.Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь. \n"
+"С момента последней проверки репозиторий был изменен другой программой Git. Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь. \n"
 "\n"
 "Это будет сделано сейчас автоматически.\n"
 
 #: lib/commit.tcl:154
-#, fuzzy, tcl-format
+#, tcl-format
 msgid ""
 "Unmerged files cannot be committed.\n"
 "\n"
@@ -1284,7 +1208,6 @@ msgstr ""
 "Файл %s не может быть сохранен данной программой.\n"
 
 #: lib/commit.tcl:170
-#, fuzzy
 msgid ""
 "No changes to commit.\n"
 "\n"
@@ -1416,14 +1339,14 @@ msgid ""
 msgstr ""
 "Этот репозиторий сейчас содержит примерно %i свободных объектов\n"
 "\n"
-"Для лучшей производительности рекомендуется сжать базу данных, когда есть более %i свободных объектов.\n"
+"Для лучшей производительности рекомендуется сжать базу данных, когда есть более %i несвязанных объектов.\n"
 "\n"
 "Сжать базу данных сейчас?"
 
 #: lib/date.tcl:25
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Invalid date from Git: %s"
-msgstr "Неверная версия: %s"
+msgstr "Неправильная дата в репозитории: %s"
 
 #: lib/diff.tcl:42
 #, tcl-format
@@ -1445,9 +1368,9 @@ msgstr ""
 "Сейчас будет запущено перечитывание репозитория, чтобы найти подобные файлы."
 
 #: lib/diff.tcl:81
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Loading diff of %s..."
-msgstr "Загрузка %s..."
+msgstr "Загрузка изменений в %s..."
 
 #: lib/diff.tcl:114 lib/diff.tcl:184
 #, tcl-format
@@ -1460,7 +1383,7 @@ msgstr "Ошибка загрузки файла:"
 
 #: lib/diff.tcl:122
 msgid "Git Repository (subproject)"
-msgstr "Репозиторий Git (под-проект)"
+msgstr "Репозиторий Git (подпроект)"
 
 #: lib/diff.tcl:134
 msgid "* Binary file (not showing content)."
@@ -1472,11 +1395,11 @@ msgstr "Ошибка загрузки diff:"
 
 #: lib/diff.tcl:302
 msgid "Failed to unstage selected hunk."
-msgstr "Не удалось исключить выбранную часть"
+msgstr "Не удалось исключить выбранную часть."
 
 #: lib/diff.tcl:309
 msgid "Failed to stage selected hunk."
-msgstr "Не удалось подготовить к сохранению выбранную часть"
+msgstr "Не удалось подготовить к сохранению выбранную часть."
 
 #: lib/error.tcl:12 lib/error.tcl:102
 msgid "error"
@@ -1491,19 +1414,19 @@ msgid "You must correct the above errors before committing."
 msgstr "Прежде чем сохранить, исправьте вышеуказанные ошибки."
 
 #: lib/index.tcl:241
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Unstaging %s from commit"
-msgstr "Убрать из подготовленного"
+msgstr "Удаление %s из подготовленного"
 
 #: lib/index.tcl:285
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Adding %s"
-msgstr "Чтение %s..."
+msgstr "Добавление %s..."
 
 #: lib/index.tcl:340
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Revert changes in file %s?"
-msgstr "Отменить изменения"
+msgstr "Отменить изменения в файле %s?"
 
 #: lib/index.tcl:342
 #, tcl-format
@@ -1511,11 +1434,8 @@ msgid "Revert changes in these %i files?"
 msgstr "Отменить изменения в %i файле(-ах)?"
 
 #: lib/index.tcl:348
-#, fuzzy
 msgid "Any unstaged changes will be permanently lost by the revert."
 msgstr ""
-"Отменить изменения в %s?\n"
-"\n"
 "Любые изменения, не подготовленные к сохранению, будут потеряны при данной операции."
 
 #: lib/index.tcl:351
@@ -1542,12 +1462,12 @@ msgid ""
 msgstr ""
 "Последнее прочитанное состояние репозитория не соответствует текущему.\n"
 "\n"
-"С момента последней проверки репозиторий был изменен другой программой Git.Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь. \n"
+"С момента последней проверки репозиторий был изменен другой программой Git. Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь.\n"
 "\n"
 "Это будет сделано сейчас автоматически.\n"
 
 #: lib/merge.tcl:44
-#, fuzzy, tcl-format
+#, tcl-format
 msgid ""
 "You are in the middle of a conflicted merge.\n"
 "\n"
@@ -1599,9 +1519,8 @@ msgid "Merge Into %s"
 msgstr "Объединить с %s"
 
 #: lib/merge.tcl:177
-#, fuzzy
 msgid "Revision To Merge"
-msgstr "Версия"
+msgstr "Версия для объединения"
 
 #: lib/merge.tcl:212
 msgid ""
@@ -1622,12 +1541,12 @@ msgid ""
 "Continue with aborting the current merge?"
 msgstr ""
 "Прервать объединение?\n"
+"\n"
 "Прерывание объединения приведет к потере *ВСЕХ* несохраненных изменений.\n"
 "\n"
 "Продолжить?"
 
 #: lib/merge.tcl:228
-#, fuzzy
 msgid ""
 "Reset changes?\n"
 "\n"
@@ -1636,6 +1555,7 @@ msgid ""
 "Continue with resetting the current changes?"
 msgstr ""
 "Прервать объединение?\n"
+"\n"
 "Прерывание объединения приведет к потере *ВСЕХ* несохраненных изменений.\n"
 "\n"
 "Продолжить?"
@@ -1663,7 +1583,7 @@ msgstr "Сохранить"
 #: lib/option.tcl:96
 #, tcl-format
 msgid "%s Repository"
-msgstr "для репозитория %s "
+msgstr "для репозитория %s"
 
 #: lib/option.tcl:97
 msgid "Global (All Repositories)"
@@ -1710,7 +1630,6 @@ msgid "New Branch Name Template"
 msgstr "Шаблон для имени новой ветви"
 
 #: lib/option.tcl:176
-#, fuzzy
 msgid "Change Font"
 msgstr "Шрифт интерфейса"
 
@@ -1723,7 +1642,7 @@ msgstr "Выберите %s"
 #: lib/option.tcl:186
 #, fuzzy
 msgid "pt."
-msgstr "pt."
+msgstr ""
 
 #: lib/option.tcl:200
 msgid "Preferences"
@@ -1734,17 +1653,14 @@ msgid "Failed to completely save options:"
 msgstr "Не удалось полностью сохранить настройки:"
 
 #: lib/remote.tcl:165
-#, fuzzy
 msgid "Prune from"
-msgstr "Чистка %s... "
+msgstr "Чистка"
 
 #: lib/remote.tcl:170
-#, fuzzy
 msgid "Fetch from"
-msgstr "Чистка %s... "
+msgstr "Получение из"
 
 #: lib/remote.tcl:213
-#, fuzzy
 msgid "Push to"
 msgstr "Отправить"
 
@@ -1785,18 +1701,22 @@ msgid "A branch is required for 'Merged Into'."
 msgstr "Для опции 'Объединено с' требуется указать ветвь."
 
 #: lib/remote_branch_delete.tcl:184
-#, fuzzy, tcl-format
+#, tcl-format
 msgid ""
 "The following branches are not completely merged into %s:\n"
 "\n"
 " - %s"
-msgstr "Следующие ветви объединены с %s не полностью:"
+msgstr ""
+"Следующие ветви объединены с %s не полностью:"
+"\n"
+" - %s"
 
-# TOVERIFY
 #: lib/remote_branch_delete.tcl:189
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "One or more of the merge tests failed because you have not fetched the necessary commits.  Try fetching from %s first."
-msgstr "Один или несколько тестов на объединение не прошли, потому что Вы не получили необходимые состояния. Попробуйте сначала получить из %s."
+msgstr ""
+"Один или несколько тестов на объединение не прошли, потому что "
+"Вы не получили необходимые состояния. Попробуйте сначала получить их из %s."
 
 #: lib/remote_branch_delete.tcl:207
 msgid "Please select one or more branches to delete."
@@ -1819,7 +1739,7 @@ msgstr "Удаление ветвей из %s"
 
 #: lib/remote_branch_delete.tcl:286
 msgid "No repository selected."
-msgstr "Не указан репозиторий"
+msgstr "Не указан репозиторий."
 
 #: lib/remote_branch_delete.tcl:291
 #, tcl-format
@@ -1840,9 +1760,9 @@ msgid "%s ... %*i of %*i %s (%3i%%)"
 msgstr "%s ... %*i из %*i %s (%3i%%)"
 
 #: lib/transport.tcl:6
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "fetch %s"
-msgstr "Получить"
+msgstr "получение %s"
 
 #: lib/transport.tcl:7
 #, tcl-format
@@ -1851,9 +1771,9 @@ msgstr "Получение изменений из %s "
 
 # carbon copy
 #: lib/transport.tcl:18
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "remote prune %s"
-msgstr "remote prune %s"
+msgstr "чистка внешнего %s"
 
 #: lib/transport.tcl:19
 #, tcl-format
@@ -1877,7 +1797,7 @@ msgstr "Отправка %s %s в %s"
 
 #: lib/transport.tcl:89
 msgid "Push Branches"
-msgstr "Отправить изменения"
+msgstr "Отправить изменения в ветвях"
 
 #: lib/transport.tcl:103
 msgid "Source Branches"
@@ -1889,7 +1809,7 @@ msgstr "Репозиторий назначения"
 
 #: lib/transport.tcl:158
 msgid "Transfer Options"
-msgstr "Настройки передачи"
+msgstr "Настройки отправки"
 
 #: lib/transport.tcl:160
 msgid "Force overwrite existing branch (may discard changes)"
@@ -1903,31 +1823,3 @@ msgstr "Использовать thin pack (для медленных сетев
 msgid "Include tags"
 msgstr "Включить метки"
 
-#~ msgid "Cannot find the git directory:"
-#~ msgstr "Каталог Git не найден:"
-#~ msgid "Add To Commit"
-#~ msgstr "Подготовить к сохранению"
-#~ msgid "Add Existing To Commit"
-#~ msgstr "Подготовить имеющиеся файлы к сохранению"
-#~ msgid "Unstaged Changes (Will Not Be Committed)"
-#~ msgstr "Изменено (не будет сохранено)"
-#~ msgid "Add Existing"
-#~ msgstr "Добавить имеющиеся файлы"
-#~ msgid ""
-#~ "Abort commit?\n"
-#~ "\n"
-#~ "Aborting the current commit will cause *ALL* uncommitted changes to be "
-#~ "lost.\n"
-#~ "\n"
-#~ "Continue with aborting the current commit?"
-#~ msgstr ""
-#~ "Отменить изменения?\n"
-#~ "\n"
-#~ "Вызванная операция приведет к потере *ВСЕХ* несохраненных изменений.\n"
-#~ "\n"
-#~ "Продолжить?"
-#~ msgid "Aborting... please wait..."
-#~ msgstr "Прерывание выполнения... Пожалуйста, ждите..."
-#~ msgid "Push to %s..."
-#~ msgstr "Отправка в %s..."
-
-- 
1.5.3.4.245.g150b

^ permalink raw reply related

* Re: [PATCH] Add color to git-add--interactive diffs (Total different idea to solve the problem)
From: Peter Baumann @ 2007-10-22 20:47 UTC (permalink / raw)
  To: Tom Tobin
  Cc: Dan Zwell, Jonathan del Strother, Johannes Schindelin,
	Shawn O. Pearce, Git Mailing List
In-Reply-To: <1192351494.7226.18.camel@athena>

On Sun, Oct 14, 2007 at 03:44:54AM -0500, Tom Tobin wrote:
> (This is repost; my damned mail client wrapped a line in the patch last
> time, and now I've got that under control.  My apologies!)  :(
> 
> Seeing the recent discussion and code regarding adding color to
> git-add--interactive, I thought I'd throw in my recent attempt at
> colorizing the diffs.  (This doesn't handle anything else, such as the
> prompts.)
> 
> After banging my head against parsing colorized output of git-add-files,
> I gave up and implemented internal colorization keying off of the
> color.diff configuration.
> 
> Hopefully this can be of some use towards fully colorizing
> git-add--interactive; I'll admit up front that Perl isn't my primary
> language, so I apologize in advance for whatever stupidities I've
> introduced.  ;) 
> 
> Signed-off-by: Tom Tobin <korpios@korpios.com>

[...skiping patch ...]

Tossing around ideas, so feel free to ignore me.

Wouldn't it make more sense to implement the diff coloring inside git apply
so that you could use something like

        diff file1 file2|git apply --color

to make the generated diff with colors [1]? It already implements the
same semantic for generating a diffstat, using

        diff file1 file2|git apply --stat

so we would get a generic diff colorizing tool and you could use inside
git add -i the diff without color and just print it out with the
git apply --color filter. So if someone implements another tool which
needs color handling he could use this output filter.

-Peter

[1]: there is a programm colordiff which does exactly this, but AFAIK git
     colorization has more features.

^ permalink raw reply

* Re: [PATCH] use only the PATH for exec'ing git commands
From: Alex Riesen @ 2007-10-22 20:57 UTC (permalink / raw)
  To: Scott R Parish; +Cc: git
In-Reply-To: <1193083141.v2.fusewebmail-240137@f>

Scott R Parish, Mon, Oct 22, 2007 21:59:01 +0200:
> > > +        if (old_path)
> > > +                strbuf_addstr(&amp;new_path, old_path);
> > > +        else
> > > +                strbuf_addstr(&amp;new_path, "/usr/local/bin:/usr/bin:/bin");
> >
> > the default PATH is platform-dependent. Git is multi-platform.
> > You should consider putting the path list somewhere in Makefile,
> > config.mak or configure.
> >
> 
> The original code was already doing both of these things (see git.c's
> prepend_to_path())

Well, would be nice if your code was better in this respect.

Anyway, I suspect the mingw people will trash the code anyway sometime
(or not, which is just as well - it is a rare case).

^ permalink raw reply

* Re: [PATCH, take 2] Linear-time/space rename logic (exact renames only)
From: Alex Riesen @ 2007-10-22 21:17 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Git Mailing List, Junio C Hamano, Shawn O. Pearce, David Kastrup,
	Jeff King, Sven Verdoolaege
In-Reply-To: <alpine.LFD.0.999.0710221241560.30120@woody.linux-foundation.org>

Linus Torvalds, Mon, Oct 22, 2007 21:44:48 +0200:
> 
> 
> On Mon, 22 Oct 2007, Linus Torvalds wrote:
> > 
> > I'm sure there's more to come..
> 
> One more detail.. The updated comment explains the issue: if we broke a 
> file apart, and rename detection joined it back together, the result is 
> neither a rename nor a copy, it's a regular modification (and all 
> remaining renames will be copies of the original, so don't bother 
> decrementing the "rename_used" count).

It breaks t3402-rebase-merge.sh

^ permalink raw reply

* Re: [PATCH, take 2] Linear-time/space rename logic (exact renames only)
From: Linus Torvalds @ 2007-10-22 21:37 UTC (permalink / raw)
  To: Alex Riesen
  Cc: Git Mailing List, Junio C Hamano, Shawn O. Pearce, David Kastrup,
	Jeff King, Sven Verdoolaege
In-Reply-To: <20071022211706.GD23714@steel.home>



On Mon, 22 Oct 2007, Alex Riesen wrote:
> 
> It breaks t3402-rebase-merge.sh

Hmm. Works for me here. But I will check if there is some incomplete 
dependency in the makefile or something...

		Linus

^ permalink raw reply

* Re: [PATCH] use only the PATH for exec'ing git commands
From: Scott R Parish @ 2007-10-22 22:12 UTC (permalink / raw)
  To: Alex Riesen, git

> Alex Riesen, Mon, Oct 22, 2007 12:01
> Scott R Parish, Mon, Oct 22, 2007 19:01:48 +0200:
> > +                strbuf_addch(out, ':');
>
> Shouldn't it break MingW32 native port?

What can i do here to better accommodate MingW32? You're
right, just because the original code did it this way
isn't a good excuse for me not to do it better.

sRp

^ permalink raw reply

* Re: [PATCH] use only the PATH for exec'ing git commands
From: Alex Riesen @ 2007-10-22 22:40 UTC (permalink / raw)
  To: Scott R Parish; +Cc: git
In-Reply-To: <1193091122.v2.fusewebmail-240137@f>

Scott R Parish, Tue, Oct 23, 2007 00:12:02 +0200:
> > Alex Riesen, Mon, Oct 22, 2007 12:01
> > Scott R Parish, Mon, Oct 22, 2007 19:01:48 +0200:
> > > +                strbuf_addch(out, ':');
> >
> > Shouldn't it break MingW32 native port?
> 
> What can i do here to better accommodate MingW32? You're
> right, just because the original code did it this way
> isn't a good excuse for me not to do it better.

someone here mentioned "higher abstractions". Maybe he meant moving
the routines operating on path names and path lists out of the generic
code into platform specific (like compat/). Maybe he was even going to
do that himself, but I could be mistaken

^ permalink raw reply

* Re: Git User's Survey 2007 unfinished summary continued
From: Steven Grimm @ 2007-10-22 22:53 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Andreas Ericsson, Jakub Narebski, Steffen Prohaska,
	Federico Mena Quintero, git
In-Reply-To: <Pine.LNX.4.64.0710212308540.25221@racer.site>

Johannes Schindelin wrote:
> I'd really like people to respond not so much with broad and general 
> statements to my mail (those statements tend to be rather useless to find 
> how to make git more suitable to newbies), but rather with concrete top 
> ten lists of what they do daily.
>   

Maybe not top 10 per se, but here are a couple of my common command 
sequences and some comments about how they could maybe be simplified. I 
mostly use git to talk to an svn repo, which in some sense is a corner 
case but which I suspect is both (a) really common already, and (b) 
potentially even *more* common if we can make git an even easier way to 
work with svn repositories.

Pulling updates from svn:

git stash
git svn rebase
git stash apply

A "git svn up" command could do the above automatically (svn users are 
accustomed to doing "svn up" with dirty working copies.)

Committing my work:

git commit -a
(ask someone for a code review, usually involves "git diff" or "git show")
git commit --amend (to indicate in my commit message who did the review)
git svn rebase
git svn dcommit

This isn't too bad as is. I could save myself the "git commit --amend" 
if there were an option to "git svn dcommit" to pop up a commit message 
editor (using the existing text as the default, of course) but it 
doesn't bother me much.

A more extreme possibility which I predict approximately 0 people on 
this list will like: if the working copy is dirty but there is no local 
commit, "git svn dcommit" could pop up an editor for a commit message, 
make a local commit, then send it to svn. That would simplify the 
git-based workflow even further for svn users who don't care about local 
versioning. I'm not sure *I* even like this idea, mind you, but it would 
certainly address the "Why this extra step I don't need in svn?" 
complaint svn users sometimes raise.

Working in a topic branch:

git checkout whateverbranch
git svn rebase
git commit -a   (a bunch of times)
git checkout -b temp trunk
git merge --squash whateverbranch
git commit
(get code review)
git commit --amend
git svn dcommit

This could be shortened a bit with the above idea (edit commit message) 
plus an option to git-svn dcommit to squash everything into one svn commit.

Of course, whether adding more options like that would make things more 
newbie-friendly is a valid question in and of itself; a shorter workflow 
is not necessarily a more discoverable one.

-Steve

^ permalink raw reply

* Re: [PATCH, take 2] Linear-time/space rename logic (exact renames only)
From: Alex Riesen @ 2007-10-22 22:54 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Git Mailing List, Junio C Hamano, Shawn O. Pearce, David Kastrup,
	Jeff King, Sven Verdoolaege
In-Reply-To: <alpine.LFD.0.999.0710221437030.30120@woody.linux-foundation.org>

Linus Torvalds, Mon, Oct 22, 2007 23:37:55 +0200:
> On Mon, 22 Oct 2007, Alex Riesen wrote:
> > 
> > It breaks t3402-rebase-merge.sh
> 
> Hmm. Works for me here. But I will check if there is some incomplete 
> dependency in the makefile or something...
> 

Ok, resolved. Turns out I completely missed the last two patches

^ permalink raw reply

* [PATCH 1/2] Added basic color support to git add --interactive
From: Dan Zwell @ 2007-10-22 21:32 UTC (permalink / raw)
  To: Shawn O. Pearce
  Cc: Jeff King, Wincent Colaiuta, Git Mailing List,
	Jonathan del Strother, Johannes Schindelin, Frank Lichtenheld
In-Reply-To: <20071017015152.GN13801@spearce.org>

Added function "print_colored" that prints text with a color that
is passed in. Converted many calls to "print" to being calls to
"print_colored".

The prompt, the header, and the help output are the 3 types of
colorized output, and each has its own color.

Colorization is done through Term::ANSIColor, which is included
with modern versions of perl. This is optional, and should not
need to be present if color.interactive is not turned on.

Signed-off-by: Dan Zwell <dzwell@zwell.net>
---
 Documentation/config.txt  |    6 ++++++
 git-add--interactive.perl |   37 +++++++++++++++++++++++++++++++------
 2 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 971fd9f..c795a35 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -381,6 +381,12 @@ color.diff.<slot>::
 	whitespace).  The values of these variables may be specified as
 	in color.branch.<slot>.
 
+color.interactive::
+	When true (or `always`), always use colors in `git add
+	--interactive`.  When false (or `never`), never.  When set to
+	`auto`, use colors only when the output is to the
+	terminal. Defaults to false.
+
 color.pager::
 	A boolean to enable/disable colored output when the pager is in
 	use (default is true).
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index be68814..c66ed4d 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -2,6 +2,31 @@
 
 use strict;
 
+my ($use_color, $prompt_color, $header_color, $help_color);
+my $color_config = qx(git config --get color.interactive);
+if ($color_config=~/true|always/ || -t STDOUT && $color_config=~/auto/) {
+	$use_color = "true";
+        # Sane (visible) defaults:
+        $prompt_color = "blue bold";
+        $header_color = "bold";
+        $help_color = "red bold";
+
+	require Term::ANSIColor;
+}
+
+sub print_colored {
+	my $color = shift;
+	my @strings = @_;
+
+	if ($use_color) {
+		print Term::ANSIColor::color($color);
+		print(@strings);
+		print Term::ANSIColor::color("reset");
+	} else {
+		print @strings;
+	}
+}
+
 sub run_cmd_pipe {
 	if ($^O eq 'MSWin32') {
 		my @invalid = grep {m/[":*]/} @_;
@@ -175,7 +200,7 @@ sub list_and_choose {
 			if (!$opts->{LIST_FLAT}) {
 				print "     ";
 			}
-			print "$opts->{HEADER}\n";
+			print_colored $header_color, "$opts->{HEADER}\n";
 		}
 		for ($i = 0; $i < @stuff; $i++) {
 			my $chosen = $chosen[$i] ? '*' : ' ';
@@ -205,7 +230,7 @@ sub list_and_choose {
 
 		return if ($opts->{LIST_ONLY});
 
-		print $opts->{PROMPT};
+		print_colored $prompt_color, $opts->{PROMPT};
 		if ($opts->{SINGLETON}) {
 			print "> ";
 		}
@@ -544,7 +569,7 @@ sub coalesce_overlapping_hunks {
 }
 
 sub help_patch_cmd {
-	print <<\EOF ;
+	print_colored $help_color, <<\EOF ;
 y - stage this hunk
 n - do not stage this hunk
 a - stage this and all the remaining hunks
@@ -619,7 +644,7 @@ sub patch_update_cmd {
 		for (@{$hunk[$ix]{TEXT}}) {
 			print;
 		}
-		print "Stage this hunk [y/n/a/d$other/?]? ";
+		print_colored $prompt_color, "Stage this hunk [y/n/a/d$other/?]? ";
 		my $line = <STDIN>;
 		if ($line) {
 			if ($line =~ /^y/i) {
@@ -673,7 +698,7 @@ sub patch_update_cmd {
 			elsif ($other =~ /s/ && $line =~ /^s/) {
 				my @split = split_hunk($hunk[$ix]{TEXT});
 				if (1 < @split) {
-					print "Split into ",
+					print_colored "$header_color", "Split into ",
 					scalar(@split), " hunks.\n";
 				}
 				splice(@hunk, $ix, 1,
@@ -769,7 +794,7 @@ sub quit_cmd {
 }
 
 sub help_cmd {
-	print <<\EOF ;
+	print_colored $help_color, <<\EOF ;
 status        - show paths with changes
 update        - add working tree state to the staged set of changes
 revert        - revert staged set of changes back to the HEAD version
-- 
1.5.3.4.207.gc0ee

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox