Git development
 help / color / mirror / Atom feed
* [PATCH 2/5] fix "git add --ignore-errors" to ignore pathspec errors
From: Luke Dashjr @ 2009-08-13  3:20 UTC (permalink / raw)
  To: git; +Cc: Luke Dashjr
In-Reply-To: <1250133624-2272-1-git-send-email-luke-jr+git@utopios.org>

Unmatched files are errors, and should be ignored with the rest of them.

Signed-off-by: Luke Dashjr <luke-jr+git@utopios.org>
---
 builtin-add.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/builtin-add.c b/builtin-add.c
index 0597fb9..e3132c8 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -280,6 +280,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 		add_interactive = 1;
 	if (add_interactive)
 		exit(interactive_add(argc - 1, argv + 1, prefix));
+	if (ignore_add_errors)
+		ignore_unmatch = 1;
 
 	if (edit_interactive)
 		return(edit_patch(argc, argv, prefix));
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH 5/5] Convert add_file_to_index's lstat failure from a die to an error
From: Luke Dashjr @ 2009-08-13  3:20 UTC (permalink / raw)
  To: git; +Cc: Luke Dashjr
In-Reply-To: <1250133624-2272-4-git-send-email-luke-jr+git@utopios.org>

In order to make --ignore-errors able to ignore a lstat failure in
add_file_to_index, it needs to raise an error, NOT a fatal die.

Signed-off-by: Luke Dashjr <luke-jr+git@utopios.org>
---
 read-cache.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/read-cache.c b/read-cache.c
index 4e3e272..074e6b8 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -638,7 +638,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int flags)
 {
 	struct stat st;
 	if (lstat(path, &st))
-		die_errno("unable to stat '%s'", path);
+		return error_errno("unable to stat '%s'", path);
 	return add_to_index(istate, path, &st, flags);
 }
 
-- 
1.6.3.3

^ permalink raw reply related

* Re: GCC Git mirror no longer updating
From: Eric Wong @ 2009-08-13  3:37 UTC (permalink / raw)
  To: Bernie Innocenti
  Cc: Jason Merrill, Daniel Berlin, Frank Ch. Eigler, overseers, git
In-Reply-To: <1250123299.8074.1593.camel@giskard>

Bernie Innocenti <bernie@codewiz.org> wrote:
> El Wed, 12-08-2009 a las 09:45 -0400, Jason Merrill escribió:
> > On 08/12/2009 06:56 AM, Bernie Innocenti wrote:
> > > The git repository format should support concurrent access, but perhaps
> > > it only applies to git-receive-pack, not fancy operations such as
> > > repacking.
> > 
> > The git repository format, yes, but maybe not the stuff in .git/svn.  It 
> > seems like a temporary index file was referring to an object that got 
> > garbage collected away.  Or maybe the index file was left over from the 
> > initial import, and not there due to a collision; there don't seem to be 
> > index files there normally.
> 
> git-svn might be keeping extra information in files that the other git
> tools don't know about.  This would explain why some objects looked
> like orphans and were thus culled.  [cc'ing the git list to catch the
> attention of the git-svn maintainer(s)].

Hi,

As far as I can remember, no version of git svn has ever relied on
orphanable objects.

Of course there are unavoidable race conditions that happen while git
svn is running.  It is never safe to run repack concurrently while git
svn is running (I wouldn't repack/gc simultaneously with _any_ write
activity on the repo).   git svn itself can/will run "git gc" in-between
revisions if needed.  You can safely repack manually whenever git svn is
not running.

-- 
Eric Wong

^ permalink raw reply

* [PATCH] block-sha1: more good unaligned memory access candidates
From: Nicolas Pitre @ 2009-08-13  4:29 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Linus Torvalds, git

In addition to X86, PowerPC and S390 are capable of unaligned memory 
accesses.

Signed-off-by: Nicolas Pitre <nico@cam.org>

diff --git a/block-sha1/sha1.c b/block-sha1/sha1.c
index d3121f7..e5a1007 100644
--- a/block-sha1/sha1.c
+++ b/block-sha1/sha1.c
@@ -67,7 +67,10 @@
  * and is faster on architectures with memory alignment issues.
  */
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || \
+    defined(__ppc__) || defined(__ppc64__) || \
+    defined(__powerpc__) || defined(__powerpc64__) || \
+    defined(__s390__) || defined(__s390x__)
 
 #define get_be32(p)	ntohl(*(unsigned int *)(p))
 #define put_be32(p, v)	do { *(unsigned int *)(p) = htonl(v); } while (0)

^ permalink raw reply related

* Re: fatal: bad revision 'HEAD'
From: Junio C Hamano @ 2009-08-13  4:36 UTC (permalink / raw)
  To: Jeff King; +Cc: Joel Mahoney, Johannes Schindelin, git
In-Reply-To: <20090813023137.GA17358@coredump.intra.peff.net>

Jeff King <peff@peff.net> writes:

> I.e., I have done in the past (but not frequently):
>
>   git symbolic-ref HEAD refs/heads/to-be-born
>
> in an existing repository to create a new root.

I honestly do not know of a sane reason (other than "because I can")
anybody would want to _start_ a new root in a repository with an existing
history.  And doing a "pull" with or without --rebase immediately after
starting a new root is doubly insane, as you say.

I do not think _ending up to_ have more than one root in your repository
is necessarily insane.  You may find a related project that earlier
started independently but later turned out to be better off managed
together with your project, and at that point you may perform Linus's
"coolest merge ever" to bind the two histories together, resulting in a
history with more than one root.

But that is the kind of "ending up to have" I am talking about; it is not
something you _aim to_ create on purpose.  If you want to _start_ a
separate history, and if you are sane, you would start the separate
history in a separate repository.

^ permalink raw reply

* Re: fatal: bad revision 'HEAD'
From: Jeff King @ 2009-08-13  4:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Joel Mahoney, Johannes Schindelin, git
In-Reply-To: <7v1vngmitn.fsf@alter.siamese.dyndns.org>

On Wed, Aug 12, 2009 at 09:36:04PM -0700, Junio C Hamano wrote:

> I honestly do not know of a sane reason (other than "because I can")
> anybody would want to _start_ a new root in a repository with an existing
> history.  And doing a "pull" with or without --rebase immediately after
> starting a new root is doubly insane, as you say.

IIRC, the reason I did it was to throw away history, starting a new root
at the current state. Which is at least a little bit sane, though I
think I might just do it with a graft and filter-branch these days.

> But that is the kind of "ending up to have" I am talking about; it is not
> something you _aim to_ create on purpose.  If you want to _start_ a
> separate history, and if you are sane, you would start the separate
> history in a separate repository.

Agreed. Let's not worry about it, then.

-Peff

^ permalink raw reply

* Re: fatal: bad revision 'HEAD'
From: Joel Mahoney @ 2009-08-13  5:02 UTC (permalink / raw)
  To: Jeff King; +Cc: Junio C Hamano, Johannes Schindelin, git
In-Reply-To: <20090813043855.GA21158@coredump.intra.peff.net>

Hello,

I'm not sure I completely understand where you guys are at with this  
thread : - ) but I thought I would mention that the question arose  
from my inability to install a plugin into a Ruby on Rails project  
based on my having (unknowingly) set branch.master.rebase = true.

I bring this up because a lot of people are getting their first  
exposure to git through Rails/github, and installing plugins in Rails  
is (I think) a good example of brining an existing history (the  
plugin) into a separate repository (your project).  and because this  
maneuver is built into the "./script/plugin install" action, it is not  
something that cannot be easily customized.

again, I may be a little off track here, but I thought I would remind  
you of the original context for what that is worth : - )

thanks again for your help!

Joel


On Aug 12, 2009, at 10:38 PM, Jeff King wrote:

> On Wed, Aug 12, 2009 at 09:36:04PM -0700, Junio C Hamano wrote:
>
>> I honestly do not know of a sane reason (other than "because I can")
>> anybody would want to _start_ a new root in a repository with an  
>> existing
>> history.  And doing a "pull" with or without --rebase immediately  
>> after
>> starting a new root is doubly insane, as you say.
>
> IIRC, the reason I did it was to throw away history, starting a new  
> root
> at the current state. Which is at least a little bit sane, though I
> think I might just do it with a graft and filter-branch these days.
>
>> But that is the kind of "ending up to have" I am talking about; it  
>> is not
>> something you _aim to_ create on purpose.  If you want to _start_ a
>> separate history, and if you are sane, you would start the separate
>> history in a separate repository.
>
> Agreed. Let's not worry about it, then.
>
> -Peff

^ permalink raw reply

* [PATCH 0/4] fast-import: add a new option command
From: Sverre Rabbelier @ 2009-08-13  5:09 UTC (permalink / raw)
  To: Junio C Hamano, Shawn O. Pearce, Johannes Schindelin, Git List

Sverre Rabbelier (4):
      fast-import: put option parsing code in seperate functions
      fast-import: define a new option command
      fast-import: add option command
      fast-import: test the new option command

 Documentation/git-fast-import.txt |   23 ++++++
 fast-import.c                     |  149 +++++++++++++++++++++++++++----------
 t/t9300-fast-import.sh            |   33 ++++++++
 3 files changed, 165 insertions(+), 40 deletions(-)

^ permalink raw reply

* [PATCH 1/4] fast-import: put option parsing code in seperate functions
From: Sverre Rabbelier @ 2009-08-13  5:09 UTC (permalink / raw)
  To: Junio C Hamano, Shawn O. Pearce, Johannes Schindelin, Git List
  Cc: Sverre Rabbelier
In-Reply-To: <1250140186-12363-1-git-send-email-srabbelier@gmail.com>

Putting the options in their own functions increases readability of
the option parsing block and makes it easier to reuse the option
parsing code later on.
---

    This is nearly identical to the RFC, but with parse_one_option
    also factored out for easy reuse.

 fast-import.c |  132 +++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 92 insertions(+), 40 deletions(-)

diff --git a/fast-import.c b/fast-import.c
index 7ef9865..17d57ab 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -291,6 +291,7 @@ static unsigned long branch_count;
 static unsigned long branch_load_count;
 static int failure;
 static FILE *pack_edges;
+static unsigned int show_stats = 1;
 
 /* Memory pools */
 static size_t mem_pool_alloc = 2*1024*1024 - sizeof(struct mem_pool);
@@ -2337,7 +2338,7 @@ static void parse_progress(void)
 	skip_optional_lf();
 }
 
-static void import_marks(const char *input_file)
+static void option_import_marks(const char *input_file)
 {
 	char line[512];
 	FILE *f = fopen(input_file, "r");
@@ -2372,6 +2373,93 @@ static void import_marks(const char *input_file)
 	fclose(f);
 }
 
+static void option_date_format(const char *fmt)
+{
+	if (!strcmp(fmt, "raw"))
+		whenspec = WHENSPEC_RAW;
+	else if (!strcmp(fmt, "rfc2822"))
+		whenspec = WHENSPEC_RFC2822;
+	else if (!strcmp(fmt, "now"))
+		whenspec = WHENSPEC_NOW;
+	else
+		die("unknown --date-format argument %s", fmt);
+}
+
+static void option_max_pack_size(const char *packsize)
+{
+	max_packsize = strtoumax(packsize, NULL, 0) * 1024 * 1024;
+}
+
+static void option_depth(const char *depth)
+{
+	max_depth = strtoul(depth, NULL, 0);
+	if (max_depth > MAX_DEPTH)
+		die("--depth cannot exceed %u", MAX_DEPTH);
+}
+
+static void option_active_branches(const char *branches)
+{
+	max_active_branches = strtoul(branches, NULL, 0);
+}
+
+static void option_export_marks(const char *marks)
+{
+	struct strbuf buf = STRBUF_INIT;
+	strbuf_addstr(&buf, marks);
+	mark_file = strbuf_detach(&buf, NULL);
+}
+
+static void option_export_pack_edges(const char *edges)
+{
+	if (pack_edges)
+		fclose(pack_edges);
+	pack_edges = fopen(edges, "a");
+	if (!pack_edges)
+		die_errno("Cannot open '%s'", edges);
+}
+
+static void option_force()
+{
+	force_update = 1;
+}
+
+static void option_quiet()
+{
+	show_stats = 0;
+}
+
+static void option_stats()
+{
+	show_stats = 1;
+}
+
+static void parse_one_option(const char *option)
+{
+    if (!prefixcmp(option, "date-format=")) {
+		option_date_format(option + 12);
+    } else if (!prefixcmp(option, "max-pack-size=")) {
+		option_max_pack_size(option + 14);
+    } else if (!prefixcmp(option, "depth=")) {
+		option_depth(option + 6);
+    } else if (!prefixcmp(option, "active-branches=")) {
+		option_active_branches(option + 16);
+    } else if (!prefixcmp(option, "import-marks=")) {
+		option_import_marks(option + 13);
+    } else if (!prefixcmp(option, "export-marks=")) {
+		option_export_marks(option + 13);
+    } else if (!prefixcmp(option, "export-pack-edges=")) {
+		option_export_pack_edges(option + 18);
+    } else if (!prefixcmp(option, "force")) {
+		option_force();
+    } else if (!prefixcmp(option, "quiet")) {
+		option_quiet();
+    } else if (!prefixcmp(option, "stats")) {
+		option_stats();
+    } else {
+		die("Unsupported option: %s", option);
+    }
+}
+
 static int git_pack_config(const char *k, const char *v, void *cb)
 {
 	if (!strcmp(k, "pack.depth")) {
@@ -2398,7 +2486,7 @@ static const char fast_import_usage[] =
 
 int main(int argc, const char **argv)
 {
-	unsigned int i, show_stats = 1;
+	unsigned int i;
 
 	git_extract_argv0_path(argv[0]);
 
@@ -2419,44 +2507,8 @@ int main(int argc, const char **argv)
 
 		if (*a != '-' || !strcmp(a, "--"))
 			break;
-		else if (!prefixcmp(a, "--date-format=")) {
-			const char *fmt = a + 14;
-			if (!strcmp(fmt, "raw"))
-				whenspec = WHENSPEC_RAW;
-			else if (!strcmp(fmt, "rfc2822"))
-				whenspec = WHENSPEC_RFC2822;
-			else if (!strcmp(fmt, "now"))
-				whenspec = WHENSPEC_NOW;
-			else
-				die("unknown --date-format argument %s", fmt);
-		}
-		else if (!prefixcmp(a, "--max-pack-size="))
-			max_packsize = strtoumax(a + 16, NULL, 0) * 1024 * 1024;
-		else if (!prefixcmp(a, "--depth=")) {
-			max_depth = strtoul(a + 8, NULL, 0);
-			if (max_depth > MAX_DEPTH)
-				die("--depth cannot exceed %u", MAX_DEPTH);
-		}
-		else if (!prefixcmp(a, "--active-branches="))
-			max_active_branches = strtoul(a + 18, NULL, 0);
-		else if (!prefixcmp(a, "--import-marks="))
-			import_marks(a + 15);
-		else if (!prefixcmp(a, "--export-marks="))
-			mark_file = a + 15;
-		else if (!prefixcmp(a, "--export-pack-edges=")) {
-			if (pack_edges)
-				fclose(pack_edges);
-			pack_edges = fopen(a + 20, "a");
-			if (!pack_edges)
-				die_errno("Cannot open '%s'", a + 20);
-		} else if (!strcmp(a, "--force"))
-			force_update = 1;
-		else if (!strcmp(a, "--quiet"))
-			show_stats = 0;
-		else if (!strcmp(a, "--stats"))
-			show_stats = 1;
-		else
-			die("unknown option %s", a);
+
+		parse_one_option(a + 2);
 	}
 	if (i != argc)
 		usage(fast_import_usage);
-- 
1.6.4.16.g72c66.dirty

^ permalink raw reply related

* [PATCH 2/4] fast-import: define a new option command
From: Sverre Rabbelier @ 2009-08-13  5:09 UTC (permalink / raw)
  To: Junio C Hamano, Shawn O. Pearce, Johannes Schindelin, Git List
  Cc: Sverre Rabbelier
In-Reply-To: <1250140186-12363-2-git-send-email-srabbelier@gmail.com>

This allows the frontend to specify any of the supported options as
long as no non-option command has been given.
---

    As requested, updated the documentation of the language format

 Documentation/git-fast-import.txt |   23 +++++++++++++++++++++++
 1 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index c2f483a..6b5bc1b 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -303,6 +303,11 @@ and control the current import process.  More detailed discussion
 	standard output.  This command is optional and is not needed
 	to perform an import.
 
+`option`::
+    Specify any of the options listed under OPTIONS to change
+    fast-import's behavior to suit the frontends needs. This command
+    is optional and is not needed to perform an import.
+
 `commit`
 ~~~~~~~~
 Create or update a branch with a new commit, recording one logical
@@ -813,6 +818,24 @@ Placing a `progress` command immediately after a `checkpoint` will
 inform the reader when the `checkpoint` has been completed and it
 can safely access the refs that fast-import updated.
 
+`option`
+~~~~~~~~
+Processes the specified option so that git fast-import behaves in a
+way that suits the front-ends needs.
+Note that options specified by the frontend override any options the
+user may specify to git fast-import itself.
+
+....
+    'option' SP <option> LF
+....
+
+The `<option>` part of the command may contain any of the options
+listed in the OPTIONS section, without the leading '--' and is
+treated in the same way.
+
+Option commands must be the first commands on the input, to give an
+option command after any non-option command is an error.
+
 Crash Reports
 -------------
 If fast-import is supplied invalid input it will terminate with a
-- 
1.6.4.16.g72c66.dirty

^ permalink raw reply related

* [PATCH 4/4] fast-import: test the new option command
From: Sverre Rabbelier @ 2009-08-13  5:09 UTC (permalink / raw)
  To: Junio C Hamano, Shawn O. Pearce, Johannes Schindelin, Git List
  Cc: Sverre Rabbelier
In-Reply-To: <1250140186-12363-4-git-send-email-srabbelier@gmail.com>

---

    Only difference with the previous version is
    s/export-marks /export-marks=/

 t/t9300-fast-import.sh |   33 +++++++++++++++++++++++++++++++++
 1 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 821be7c..4152c3a 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -1088,4 +1088,37 @@ INPUT_END
 test_expect_success 'P: fail on blob mark in gitlink' '
     test_must_fail git fast-import <input'
 
+###
+### series Q (options)
+###
+
+cat >input << EOF
+option quiet
+blob
+data 3
+hi
+
+EOF
+
+touch empty
+
+test_expect_success 'Q: quiet option results in no stats being output' '
+    cat input | git fast-import 2> output &&
+    test_cmp empty output
+'
+
+cat >input << EOF
+option export-marks=git.marks
+blob
+mark :1
+data 3
+hi
+
+EOF
+
+test_expect_success \
+    'Q: export-marks option results in a marks file being created' \
+    'cat input | git fast-import 2> output &&
+    grep :1 git.marks'
+
 test_done
-- 
1.6.4.16.g72c66.dirty

^ permalink raw reply related

* [PATCH 3/4] fast-import: add option command
From: Sverre Rabbelier @ 2009-08-13  5:09 UTC (permalink / raw)
  To: Junio C Hamano, Shawn O. Pearce, Johannes Schindelin, Git List
  Cc: Sverre Rabbelier
In-Reply-To: <1250140186-12363-3-git-send-email-srabbelier@gmail.com>

This allows the frontend to specify any of the supported options as
long as no non-option command has been given. This way the
user does not have to include any frontend-specific options, but
instead she can rely on the frontend to tell fast-import what it
needs.
---

    This is a lot simpler from the previous version as we can now
    reuse parse_one_option from 1/4.

 fast-import.c |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/fast-import.c b/fast-import.c
index 17d57ab..2ec804d 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -348,6 +348,7 @@ static struct recent_command *rc_free;
 static unsigned int cmd_save = 100;
 static uintmax_t next_mark;
 static struct strbuf new_data = STRBUF_INIT;
+static int seen_non_option_command;
 
 static void write_branch_report(FILE *rpt, struct branch *b)
 {
@@ -1663,6 +1664,10 @@ static int read_next_command(void)
 			if (stdin_eof)
 				return EOF;
 
+			if (!seen_non_option_command
+				&& prefixcmp(command_buf.buf, "option "))
+				seen_non_option_command = 1;
+
 			rc = rc_free;
 			if (rc)
 				rc_free = rc->next;
@@ -2460,6 +2465,16 @@ static void parse_one_option(const char *option)
     }
 }
 
+static void parse_option(void)
+{
+    char* option = command_buf.buf + 7;
+
+	if (seen_non_option_command)
+		die("Got option command '%s' after non-option command", option);
+
+    parse_one_option(option);
+}
+
 static int git_pack_config(const char *k, const char *v, void *cb)
 {
 	if (!strcmp(k, "pack.depth")) {
@@ -2534,6 +2549,8 @@ int main(int argc, const char **argv)
 			parse_checkpoint();
 		else if (!prefixcmp(command_buf.buf, "progress "))
 			parse_progress();
+		else if (!prefixcmp(command_buf.buf, "option "))
+			parse_option();
 		else
 			die("Unsupported command: %s", command_buf.buf);
 	}
-- 
1.6.4.16.g72c66.dirty

^ permalink raw reply related

* Re: fatal: bad revision 'HEAD'
From: Jeff King @ 2009-08-13  5:10 UTC (permalink / raw)
  To: Joel Mahoney; +Cc: Junio C Hamano, Johannes Schindelin, git
In-Reply-To: <89456E84-1A85-4D0C-9643-C191EE877E61@gmail.com>

On Wed, Aug 12, 2009 at 11:02:45PM -0600, Joel Mahoney wrote:

> I'm not sure I completely understand where you guys are at with this
> thread : - ) but I thought I would mention that the question arose
> from my inability to install a plugin into a Ruby on Rails project
> based on my having (unknowingly) set branch.master.rebase = true.
>
> I bring this up because a lot of people are getting their first
> exposure to git through Rails/github, and installing plugins in Rails
> is (I think) a good example of brining an existing history (the
> plugin) into a separate repository (your project).  and because this
> maneuver is built into the "./script/plugin install" action, it is
> not something that cannot be easily customized.

Yes, the discussion moved away bit from your original issue. To
summarize what is happening:

  - Setting branch.master.rebase in your ~/.gitconfig is probably not a
    good idea, as that tends to be a per-repository property, anyway.
    You can work around the problem for now by removing it.

  - Junio has committed a patch to fix the bug. It will definitely be in
    v1.6.5. If this is a common setup for Rails people, maybe we should
    consider putting it into 'maint' for v1.6.4.1.

-Peff

^ permalink raw reply

* [PATCH] svn: initial "master" points to trunk if possible
From: Eric Wong @ 2009-08-13  5:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Since "trunk" is a convention for the main development branch in
the SVN world, try to make that the master branch upon initial
checkout if it exists.  This is probably less surprising based
on user requests.

t9135 was the only test which relied on the previous behavior
and thus needed to be modified.

Signed-off-by: Eric Wong <normalperson@yhbt.net>
---

  pushed out to git://yhbt.net/git-svn along with some others

  Adam Brewster (1):
        svn: allow branches outside of refs/remotes

  Eric Wong (2):
        svn: initial "master" points to trunk if possible
        svn: (cleanup) use predefined constant for rev_map_fmt


 git-svn.perl                               |   11 +++++++++++
 t/t9135-git-svn-moved-branch-empty-file.sh |    7 ++++++-
 t/t9145-git-svn-master-branch.sh           |   25 +++++++++++++++++++++++++
 3 files changed, 42 insertions(+), 1 deletions(-)
 create mode 100755 t/t9145-git-svn-master-branch.sh

diff --git a/git-svn.perl b/git-svn.perl
index b0bfb74..fad2960 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -1156,6 +1156,17 @@ sub post_fetch_checkout {
 	my $gs = $Git::SVN::_head or return;
 	return if verify_ref('refs/heads/master^0');
 
+	# look for "trunk" ref if it exists
+	my $remote = Git::SVN::read_all_remotes()->{$gs->{repo_id}};
+	my $fetch = $remote->{fetch};
+	if ($fetch) {
+		foreach my $p (keys %$fetch) {
+			basename($fetch->{$p}) eq 'trunk' or next;
+			$gs = Git::SVN->new($fetch->{$p}, $gs->{repo_id}, $p);
+			last;
+		}
+	}
+
 	my $valid_head = verify_ref('HEAD^0');
 	command_noisy(qw(update-ref refs/heads/master), $gs->refname);
 	return if ($valid_head || !verify_ref('HEAD^0'));
diff --git a/t/t9135-git-svn-moved-branch-empty-file.sh b/t/t9135-git-svn-moved-branch-empty-file.sh
index 03705fa..5280e5f 100755
--- a/t/t9135-git-svn-moved-branch-empty-file.sh
+++ b/t/t9135-git-svn-moved-branch-empty-file.sh
@@ -10,7 +10,12 @@ test_expect_success 'load svn dumpfile'  '
 test_expect_success 'clone using git svn' 'git svn clone -s "$svnrepo" x'
 
 test_expect_success 'test that b1 exists and is empty' '
-	(cd x && test -f b1 && ! test -s b1)
+	(
+		cd x &&
+		git reset --hard branch-c &&
+		test -f b1 &&
+		! test -s b1
+	)
 	'
 
 test_done
diff --git a/t/t9145-git-svn-master-branch.sh b/t/t9145-git-svn-master-branch.sh
new file mode 100755
index 0000000..16852d2
--- /dev/null
+++ b/t/t9145-git-svn-master-branch.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Eric Wong
+#
+test_description='git svn initial master branch is "trunk" if possible'
+. ./lib-git-svn.sh
+
+test_expect_success 'setup test repository' '
+	mkdir i &&
+	> i/a &&
+	svn_cmd import -m trunk i "$svnrepo/trunk" &&
+	svn_cmd import -m b/a i "$svnrepo/branches/a" &&
+	svn_cmd import -m b/b i "$svnrepo/branches/b"
+'
+
+test_expect_success 'git svn clone --stdlayout sets up trunk as master' '
+	git svn clone -s "$svnrepo" g &&
+	(
+		cd g &&
+		test x`git rev-parse --verify refs/remotes/trunk^0` = \
+		     x`git rev-parse --verify refs/heads/master^0`
+	)
+'
+
+test_done
-- 
Eric Wong

^ permalink raw reply related

* [PATCH] svn: (cleanup) use predefined constant for rev_map_fmt
From: Eric Wong @ 2009-08-13  5:34 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

This makes life easier in case we ever need to change the
internal format of the rev_maps.

Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
 also pushed out to git://yhbt.net/git-svn

 git-svn.perl |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index a2934e8..1da9f07 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -3277,7 +3277,7 @@ sub _rev_map_get {
 		my $i = int(($l/24 + $u/24) / 2) * 24;
 		sysseek($fh, $i, SEEK_SET) or croak "seek: $!";
 		sysread($fh, my $buf, 24) == 24 or croak "read: $!";
-		my ($r, $c) = unpack('NH40', $buf);
+		my ($r, $c) = unpack(rev_map_fmt, $buf);
 
 		if ($r < $rev) {
 			$l = $i + 24;
-- 
Eric Wong

^ permalink raw reply related

* Re: [PATCH] svn: Add && to t9107-git-svn-migrarte.sh
From: Eric Wong @ 2009-08-13  5:36 UTC (permalink / raw)
  To: Adam Brewster; +Cc: git, Junio C Hamano
In-Reply-To: <c376da900908121735w7ee3c581pd1281efc83a2075d@mail.gmail.com>

Adam Brewster <adambrewster@gmail.com> wrote:
> Eric,
> 
> Thanks the help in getting this right.

No problem!  Thanks for fixing a long-standing issue with git svn.

I've pushed this last patch out along with a few others to
git://yhbt.net/git-svn for Junio

-- 
Eric Wong

^ permalink raw reply

* Re: [RFC PATCH v3 3/8] Read .gitignore from index if it is  assume-unchanged
From: Nguyen Thai Ngoc Duy @ 2009-08-13  6:37 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Johannes Schindelin
In-Reply-To: <7vocqlbv7a.fsf@alter.siamese.dyndns.org>

2009/8/12 Junio C Hamano <gitster@pobox.com>:
> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:
>
>> diff --git a/Documentation/technical/api-directory-listing.txt b/Documentation/technical/api-directory-listing.txt
>> index 5bbd18f..7d0e282 100644
>> --- a/Documentation/technical/api-directory-listing.txt
>> +++ b/Documentation/technical/api-directory-listing.txt
>> @@ -58,6 +58,9 @@ The result of the enumeration is left in these fields::
>>  Calling sequence
>>  ----------------
>>
>> +* Ensure the_index is populated as it may have CE_VALID entries that
>> +  affect directory listing.
>> +
>
> When you want to enumerate all paths in the work tree, instead of not just
> the untracked ones, it used to be possible to first run read_directory()
> before calling read_cache().  You are now forbidding this.

Either I phrased it badly, or I don't follow you. If you don't call
read_cache() before read_directory(), the_index should be empty and
read_assume_unchanged_from_index() will be no-op. So read_directory()
behavior does not change in this case.

> I do not think it is hard to resurrect the feature if it is necessary (add
> an option to dir_struct and teach dir_add_name() not to ignore paths the
> index knows about), and I do not think none of the existing code relies on
> it anymore (I think "git add" used to), but there may be some codepath I
> forgot about, which is a concern.

Hmm.. "git add" loaded index early since the first version of
builtin-add.c. I have checked all code path that can lead to
read_directory_recursively(). In all cases, index is loaded before
read_dir..() is called.

>> diff --git a/builtin-clean.c b/builtin-clean.c
>> index 2d8c735..d917472 100644
>> --- a/builtin-clean.c
>> +++ b/builtin-clean.c
>> @@ -71,8 +71,11 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
>>
>>       dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
>>
>> -     if (!ignored)
>> +     if (!ignored) {
>> +             if (read_cache() < 0)
>> +                     die("index file corrupt");
>>               setup_standard_excludes(&dir);
>> +     }
>>
>>       pathspec = get_pathspec(prefix, argv);
>>       read_cache();
>
> Wouldn't it be much cleaner to move the existing read_cache() up, like you
> did for ls-files, instead of conditionally reading the index at a random
> place in the program sequence depending on the combinations of options?

Agreed. read_cache() is called right below anyway.
-- 
Duy

^ permalink raw reply

* Implementing $Date$ substitution - solution using pre-commit
From: Peter Krefting @ 2009-08-13  6:47 UTC (permalink / raw)
  To: Git List
In-Reply-To: <alpine.DEB.2.00.0908092127420.17141@perkele.intern.softwolves.pp.se>

Hi!

So, my filter-based approach at doing RCS-like $Date$ expansion didn't work 
out. Since I wanted to have the Date expand on check-in, not on check-out, 
and be expanded in history, I had made it into a "clean" filter. But due to 
how Git internally checks if files are clean, that did not work properly.

The solution to this was instead to make the Date expansion into a 
pre-commit hook. Using .gitattributes, I set "datereplace=true" on all the 
files I want to have "$Date$" expand in, and then install the following 
file as .git/hooks/pre-commit:

===8< pre-commit >8===
#!/bin/bash -e

# Find base commit
if git-rev-parse --verify HEAD >/dev/null 2>&1
then
 	against=HEAD
else
 	# Initial commit: diff against an empty tree object
 	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# Set up Date substitution
export NOW=$(date +"%Y-%m-%d %H:%M:%S")
for file in $(git diff-index --cached --diff-filter=AM --name-only $against); do
   if git check-attr datereplace -- "$file" | grep 'datereplace: true' > /dev/null; then
     perl -w -i.bak -e 'my $now = $ENV{"NOW"};
$now =~ s/[^-:0-9 ]//g;
while (<>)
{
  if (/\$Date:?[^\$]*\$/)
  {
    s/\$Date:?[^\$]*\$/\$Date: ${now} \$/;
  }
  print
}' "$file"
     git update-index --add "$file"
   fi
done

exit 0
===8< pre-commit >8===

This has the added bonus over a filter that it all files committed at the 
same time will have the same date stamp, whereas the filter would expand on 
the time "git add" is executed.

-- 
\\// Peter - http://www.softwolves.pp.se/

^ permalink raw reply

* Re: [RFC PATCH v3 8/8] --sparse for porcelains
From: Nguyen Thai Ngoc Duy @ 2009-08-13  7:20 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Johannes Schindelin
In-Reply-To: <7v3a7xa6e5.fsf@alter.siamese.dyndns.org>

2009/8/12 Junio C Hamano <gitster@pobox.com>:
> It could also require core.sparseworktree configuration set to true if we
> are really paranoid, but without the actual sparse specification file
> flipping that configuration to true would not be useful anyway, so in
> practice, giving --sparse-work-tree option to these Porcelain commands
> would be no-op, but --no-sparse-work-tree option would be useful to
> ignore $GIT_DIR/info/sparse and populate the work tree fully.

Only part "ignore $GIT_DIR/info/sparse" is correct.
"--no-sparse-work-tree" would not clear CE_VALID from all entries in
index (which is good, if you are using CE_VALID for another purpose).

To quit sparse checkout, you must create an empty
$GIT_DIR/info/sparse, then do "git checkout" or "git read-tree -m -u
HEAD" so that the tree is full populated, then you can remove
$GIT_DIR/info/sparse. Quite unintuitive..
-- 
Duy

^ permalink raw reply

* [PATCH v2] gitk: parse arbitrary commit-ish in SHA1 field
From: Thomas Rast @ 2009-08-13  7:25 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: Junio C Hamano, git
In-Reply-To: <7vtz0fndak.fsf@alter.siamese.dyndns.org>

We only accepted either SHA1s or heads/tags that have been read.  This
meant the user could not, e.g., enter HEAD to go back to the current
commit.

Add code to call out to git rev-parse --verify with the string entered
if all other methods of interpreting it failed.  (git-rev-parse alone
is not enough as we really want a single revision.)

The error paths change slighly, because we now know from the rev-parse
invocation whether the expression was valid at all.  The previous
"unknown" path is now only triggered if the revision does exist, but
is not in the current view display.

Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---

Junio C Hamano wrote:
> > +     } else {
> > +         if {[catch {set id [exec git rev-parse $sha1string]}]} {
> 
> "--verify", or "--no-flags --revs-only"?

Indeed, thanks.


 gitk |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/gitk b/gitk
index 4604c83..e50b666 100755
--- a/gitk
+++ b/gitk
@@ -7906,6 +7906,11 @@ proc gotocommit {} {
 		}
 		set id [lindex $matches 0]
 	    }
+	} else {
+	    if {[catch {set id [exec git rev-parse --verify $sha1string]}]} {
+		error_popup [mc "Revision %s is not known" $sha1string]
+		return
+	    }
 	}
     }
     if {[commitinview $id $curview]} {
@@ -7915,7 +7920,7 @@ proc gotocommit {} {
     if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
 	set msg [mc "SHA1 id %s is not known" $sha1string]
     } else {
-	set msg [mc "Tag/Head %s is not known" $sha1string]
+	set msg [mc "Revision %s is not in the current view" $sha1string]
     }
     error_popup $msg
 }
-- 
1.6.4.269.g0449d

^ permalink raw reply related

* Re: [PATCH] git stash: Give friendlier errors when there is nothing to apply
From: Thomas Rast @ 2009-08-13  7:35 UTC (permalink / raw)
  To: Ori Avtalion; +Cc: git
In-Reply-To: <4a81787d.0e0f660a.5238.4c8b@mx.google.com>

Ori Avtalion wrote:
> The change makes sure a stash (given or default) exists before
> checking if the working tree is dirty.
> 
> If the default stash is requested, the old message was scary and
> included a 'fatal' error from rev-parse:
>      fatal: Needed a single revision
>      : no valid stashed state found
> 
> It is replaced with a friendlier 'Nothing to apply' error, similar to
> 'git stash branch'.
> 
> If a specific stash is specified, the 'Needed a single revision' errors
> from rev-parse are suppressed.
> 
> Signed-off-by: Ori Avtalion <ori@avtalion.name>
> ---
> 
> Thomas, I added handling for the 'git stash apply <stash>' case based
> on your reminder, and also changed the error messages related to it.
> 
> All of the stash tests pass, as before.

Acked-by: Thomas Rast <trast@student.ethz.ch>

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

^ permalink raw reply

* Re: [RFC PATCH v3 8/8] --sparse for porcelains
From: Johannes Sixt @ 2009-08-13  7:37 UTC (permalink / raw)
  To: Raja R Harinath, Nguyen Thai Ngoc Duy
  Cc: git, Johannes Schindelin, Junio C Hamano
In-Reply-To: <87ljlpvy4r.fsf@hariville.hurrynot.org>

Raja R Harinath schrieb:
> Hi,
> 
> Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:
> 
>> 2009/8/12 Johannes Sixt <j.sixt@viscovery.net>:
>>> BTW, the name .git/info/sparse is perhaps a bit too technical in the sense
>>> that only git developers know that this feature runs under the name
>>> "sparse checkout". Perhaps it should be named
>>>
>>>   .git/info/indexonly
>>>   .git/info/nocheckout
>>>
>>> or so.
>> I did not like the name "sparse" either. Another option is
>> .git/info/assume-unchanged.
> 
> Or .git/info/doppelgangers, or even .git/info/doppelgängers :-)

Heh!

   .git/info/phantoms
   git checkout --no-phantoms
   git read-tree --phantoms

-- Hannes

^ permalink raw reply

* Re: [RFC PATCH v3 8/8] --sparse for porcelains
From: Jakub Narebski @ 2009-08-13  9:58 UTC (permalink / raw)
  To: Nguyen Thai Ngoc Duy; +Cc: Junio C Hamano, git, Johannes Schindelin
In-Reply-To: <fcaeb9bf0908130020meaed129j5d6a4f04a6878bd0@mail.gmail.com>

Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:
> 2009/8/12 Junio C Hamano <gitster@pobox.com>:

> > It could also require core.sparseworktree configuration set to true if we
> > are really paranoid, but without the actual sparse specification file
> > flipping that configuration to true would not be useful anyway, so in
> > practice, giving --sparse-work-tree option to these Porcelain commands
> > would be no-op, but --no-sparse-work-tree option would be useful to
> > ignore $GIT_DIR/info/sparse and populate the work tree fully.
> 
> Only part "ignore $GIT_DIR/info/sparse" is correct.
> "--no-sparse-work-tree" would not clear CE_VALID from all entries in
> index (which is good, if you are using CE_VALID for another purpose).
> 
> To quit sparse checkout, you must create an empty
> $GIT_DIR/info/sparse, then do "git checkout" or "git read-tree -m -u
> HEAD" so that the tree is full populated, then you can remove
> $GIT_DIR/info/sparse. Quite unintuitive..

Hmmm... this looks like either argument for introducing --full option
to git-checkout (ignore CE_VALID bit, checkout everything, and clean
CE_VALID (?))...

...or for going with _separate_ bit for partial checkout, like in the
very first version of this series, which otherwise functions like
CE_VALID, or is just used to mark that CE_VALID was set using sparse.

Food for thought.
-- 
Jakub Narebski
Poland
ShadeHawk on #git

^ permalink raw reply

* Re: [PATCH 1/4] fast-import: put option parsing code in seperate functions
From: Johannes Schindelin @ 2009-08-13 10:19 UTC (permalink / raw)
  To: Sverre Rabbelier; +Cc: Junio C Hamano, Shawn O. Pearce, Git List
In-Reply-To: <1250140186-12363-2-git-send-email-srabbelier@gmail.com>

Hi,

On Wed, 12 Aug 2009, Sverre Rabbelier wrote:

> +static void option_export_marks(const char *marks)
> +{
> +	struct strbuf buf = STRBUF_INIT;
> +	strbuf_addstr(&buf, marks);
> +	mark_file = strbuf_detach(&buf, NULL);
> +}

Heh, this is a pretty convoluted way to write

	mark_file = xstrdup(marks);

;-)

> +static void option_force()
> +{
> +	force_update = 1;
> +}

I'm not sure that I would put these simple assignments in separate 
functions, but that's certainly up to you!

Thanks,
Dscho

^ permalink raw reply

* [PATCH 1/6 (v3)] revision caching documentation: man page and technical docs
From: Nick Edelen @ 2009-08-13 10:24 UTC (permalink / raw)
  To: Junio C Hamano, Nicolas Pitre, Johannes Schindelin, Sam Vilain,
	Michael J Gruber

Before any code is introduced the full documentation is put forth.  This 
provides a man page for the porcelain, and a technical doc in technical/.  The 
latter describes the API, and discusses rev-cache's design, file format and 
mechanics.

Signed-off-by: Nick Edelen <sirnot@gmail.com>

---
 Documentation/git-rev-cache.txt       |  144 ++++++++
 Documentation/technical/rev-cache.txt |  594 +++++++++++++++++++++++++++++++++
 2 files changed, 738 insertions(+), 0 deletions(-)

diff --git a/Documentation/git-rev-cache.txt b/Documentation/git-rev-cache.txt
new file mode 100644
index 0000000..3479499
--- /dev/null
+++ b/Documentation/git-rev-cache.txt
@@ -0,0 +1,144 @@
+git-rev-cache(1)
+================
+
+NAME
+----
+git-rev-cache - Add, walk and maintain revision cache slices
+
+SYNOPSIS
+--------
+'git-rev-cache' COMMAND [options] [<commit>...]
+
+DESCRIPTION
+-----------
+The revision cache ('rev-cache') provides a mechanism for significantly
+speeding up revision traversals.  It does this by creating an efficient
+database (cache) of commits, their related objects and topological relations.
+Independant of packs and the object store, this database is composed of
+rev-cache "slices" -- each a different file storing a given segment of commit
+history.  To map commits to their respective slices, a single index file is
+kept for the rev-cache.
+
+'git-rev-cache' provides a front-end for the rev-cache mechanism, intended for
+updating and maintaining rev-cache slices in the current repository.  New cache
+slice files can be 'add'ed, to keep the cache up-to-date; individual slices can
+be traversed; smaller slices can be 'fuse'd into a larger slice; and the
+rev-cache index can be regenerated.
+
+COMMANDS
+--------
+
+add
+~~~
+Add revisions to the cache by creating a new cache slice.  Reads a revision
+list from the command line, formatted as: `START START ... \--not END END ...`
+
+Options:
+
+\--all::
+	Include all refs in the new cache slice, like the \--all option in
+	'rev-list'.
+
+\--fresh::
+	Exclude everything already in the revision cache, analogous to
+	\--incremental in 'pack-objects'.
+
+\--stdin::
+	Read newline-seperated revisions from the standard input.  Use \--not
+	to exclude commits, as on the command line.
+
+\--legs::
+	Ensure newly-generated cache slice has no partial ends.  This means that
+	no commit has partially cached parents, in that all its parents are
+	cached or none of them are.
++
+\--legs will cause 'rev-cache' to expand potential slice end-points (creating
+"legs") until this condition is met, simplifying the cache slice structure.
+'rev-cache' itself does not care if a slice has legs or not, but the condition
+may reduce the required complexity of other applications that might use the
+revision cache.
+
+\--no-objects::
+	Non-commit objects are normally included along with the commit with
+	which they were introduced.  This is obviously very benificial, but can
+	take longer in cache slice generation.  Using this option will disable
+	non-commit object caching.
++
+\--no-objects is mainly intended for debugging or development purposes, but may
+find use in special situations (e.g. common traversal of only commits).
+
+walk
+~~~~
+Analogous to a slice-oriented 'rev-list', 'walk' will traverse a region in a
+particular cache slice.  Interesting and uninteresting (delimited, as with
+'rev-list', with \--not) are specified on the command line, and output is the
+same as vanilla 'rev-list'.
+
+Options:
+
+\--objects::
+	Like 'rev-list', 'walk' will normally only list commits.  Use this
+	option to list non-commit objects as well, if they are present in the
+	cache slice.
+
+fuse
+~~~~
+Merge several cache slices into a single large slice, like 'repack' for
+'rev-cache'.  On each invocation of 'add' a new file ("slice") is added to the
+revision cache directory, and after several additions the directory may become
+populated with many, relatively small slices.  Numerous smaller slices will
+yield poorer performance than a one or two large ones, because of the overhead
+of loading new slices into memory.
+
+Running 'fuse' every once in a while will solve this problem by coalescing all
+the cache slices into one larger slice.  For very large projects, using
+\--ignore-size is advisable to prevent overly large cache slices.  Setting git
+'config' option 'gc.revcache' to 1 will enable cache slice fusion upon garbage
+collection.
+
+Note that 'fuse' uses the internal revision walker, so the options used in
+fusion override those of the cache slices upon which it operates.  For example,
+if some slices were generated with \--no-objects, yet 'fuse' was performed with
+non-commit objects, the resulting slice would still contain objects but would
+take longer to generate.
+
+Options:
+
+\--all::
+	Normally fuse will only include everything that's already in the
+	revision cache.  \--add tells it to start walking from the branch
+	heads, effectively an `add --all --fresh; fuse` (pseudo-command).
+
+\--no-objects::
+	As in 'add', this option disables inclusion of non-commit objects.  If
+	some cache slices do contain such objects, the information will be lost.
+
+\--ignore-size[=N]::
+	Do not merge cache slices of size >=N (be aware that slices must be
+	mapped to memory).  N can have a suffix of "k" or "m", denoting N as
+	kilobytes and megabytes, respectively.  If N is not provided 'fuse'
+	will default to a size of ~25MB.
+
+index
+~~~~~
+Regenerate the revision cache index.  If the rev-cache index file associating
+objects with cache slices gets corrupted, lost, or otherwise becomes unusable,
+'index' will quickly regenerate the file.  It's most likely that this won't be
+needed in every day use, as it is targeted towards debugging and development.
+
+alt
+~~~
+Create a cache slice pointer to another slice, identified by its full path:
+`fuse path/to/other/slice`
+
+This command is useful if you have several repositories sharing a common
+history.  Although space requirements for rev-cache are slim anyway, you can in
+this situation reduce it further by using slice pointers, pointing to relavant
+slices in other repositories.  Note that only one level of redirection is
+allowed, and the slice pointer will break if the original slice is removed.
+'fuse' will not touch slice pointers.
+
+DISCUSSION
+----------
+For an explanation of the API and its inner workings, see
+link:technical/rev-cache.txt[technical info on rev-cache].
diff --git a/Documentation/technical/rev-cache.txt b/Documentation/technical/rev-cache.txt
new file mode 100644
index 0000000..a9e4c42
--- /dev/null
+++ b/Documentation/technical/rev-cache.txt
@@ -0,0 +1,594 @@
+rev-cache
+=========
+
+The revision cache API ('rev-cache') provides a method for efficiently storing
+and accessing commit branch sections.  Such branch slices are defined by a
+series of start/top (interesting) and end/bottom (uninteresting) commits.  Each
+slice contains information on commits in topological order.  Recorded with each
+commit is:
+
+* All intra-slice topological relations, encoded into path "channels" (see
+  'Mechanics' for full explanation).
+* Object meta-data: type, SHA-1, size, date (for commits).
+* Objects introduced by that commit, not present in the its cached parents.
+
+In addition to the API, basic structures are exported for the possibility of
+direct access.
+
+The API
+-------
+You can find the function prototypes in `revision.h`.
+
+Data Structures
+~~~~~~~~~~~~~~~
+The `rev_cache_info` struct holds all the options and flags for the API.
+
+----
+struct rev_cache_info {
+	/* generation flags */
+	unsigned objects : 1, 
+		legs : 1, 
+		make_index : 1, 
+		fuse_me : 1;
+	
+	/* index inclusion */
+	unsigned overwrite_all : 1;
+	
+	/* traversal flags */
+	unsigned add_to_pending : 1;
+	
+	/* fuse options */
+	unsigned int ignore_size;
+	
+	/* reserved */
+	struct rev_cache_slice_map *maps, 
+		*last_map;
+};
+----
+
+The fields:
+
+`objects`::
+	Add non-commit objects to slice.
+
+`legs`::
+	Ensure end/bottom commits have no children.
+
+`make_index`::
+	Integrate newly-made slice into index.
+
+`fuse_me`::
+	This is specified if a fuse is occuring, and slices are to be reused.
+	This option requires `maps` and `last_maps` to be initialized.
+
+`overwrite_all`::
+	When a cache slice is added to the index, sometimes overlap occures
+	between it and other slices.  Normally, original index entries are kept
+	unless the new entry represents a start commit (older entries are more
+	likely to lead to greater in-slice traversals).  This options overrides
+	that, and updates all entries of the new slice.
+
+`add_to_pending`::
+	Append unique non-commit objects to the `pending` object list in the
+	passed `rev_info` instance.
+
+`add_names`::
+	Include non-commit object names in the pending object entries if
+	`add_to_pending` is set.
+
+`ignore_size`::
+	If non-zero, ignore slices with size greater or equal to this during
+fusion.
+
+`maps`/`last_map`::
+	An array of slice mappings, indexed by their id in the slice index
+	header, to be re-used with `fuse_me`.  `last_map` points to the last
+	mapping used, and should be initialized to 0.
+
+Functions
+~~~~~~~~~
+
+init_rev_cache
+^^^^^^^^^^^^^^
+----
+void init_rev_cache_info(
+	struct rev_cache_info *rci OUT
+)
+----
+
+Initialize `rci` to default options.
+
+make_cache_slice
+^^^^^^^^^^^^^^^^
+----
+int make_cache_slice(
+	struct rev_cache_info *rci IN,
+	struct rev_info *revs IN,
+	struct commit_list **starts IN/OUT,
+	struct commit_list **ends IN/OUT,
+	unsigned char *cache_sha1 OUT
+)
+----
+
+Create a cache slice based on either `revs` (if non-NULL) *or* the `starts` and
+`ends` lists.  The actual list of start and end commits of the slice may be
+different from the parameters, based on what defines the branch segment, and
+this actual list is passed back through `starts` and `ends`.
+
+The cache slice is identified via a SHA-1 generated from the actual start/end
+commit lists.  `cache_sha1`, if non-NULL, can recieve the cache slice name.
+`rci` is used to specify generation options, but can be NULL if you want
+`make_cache_slice` to fall back on defaults.  Returns 0 on success, non-zero on
+failure.
+
+make_cache_index
+^^^^^^^^^^^^^^^^
+----
+int make_cache_index(
+	struct rev_cache_info *rci IN, 
+	unsigned char *cache_sha1 IN, 
+	int fd IN, 
+	unsigned int size IN
+)
+----
+
+Add a slice to the rev-cache index.  `cache_sha1` is the identity hash of the
+cache slice; `fd` is a file descriptor of the cache slice opened with
+read/write privileges (the slice is not actually modified); `size` is the size
+of the cache slice.  Although there are currently no options for index
+updating, `rci` is a placeholder in case of future options.  Note that this
+function is normally called by `make_cache_slice`.  Returns 0 on success,
+non-zero on failure.
+
+open_cache_slice
+^^^^^^^^^^^^^^^^
+----
+int open_cache_slice(
+	unsigned char *sha1 IN, 
+	int flags IN
+)
+----
+
+Returns a file descriptor to a cache slice described by `sha1` hash, using
+`flags` as the access mode.  This will follow cache slice pointers to one level
+of indirection.
+
+get_cache_slice
+^^^^^^^^^^^^^^^
+----
+unsigned char *get_cache_slice(
+	struct commit *commit IN
+)
+----
+
+Given a commit object `get_cache_slice` will search the revision cache index
+and return, if found, the cache slice SHA-1.
+
+traverse_cache_slice
+^^^^^^^^^^^^^^^^^^^^
+----
+int traverse_cache_slice(
+	struct rev_info *revs IN/OUT, 
+	unsigned char *cache_sha1 IN, 
+	struct commit *commit IN, 
+	unsigned long *date_so_far IN/OUT, 
+	int *slop_so_far IN/OUT, 
+	struct commit_list ***queue OUT, 
+	struct commit_list **work IN/OUT
+)
+----
+
+Traverse a specified cache slice.  An explanation of the each field:
+
+`revs`::
+	The revision walk instance.  `traverse_cache_slice` uses this for
+	general options (e.g. which objects are included) and slice traversal
+	options (in the `rev_cache_info` field).  If the `add_to_pending`
+	option is specified, non-commit objects are appended to the `pending`
+	object list field.
+
+`cache_sha1`::
+	SHA-1 identifying the cache slice to use.  This can be taken directly
+	from `get_cache_slice`.
+
+`commit`::
+	The current commit object in the revision walk, i.e. the commit which
+	inspired this slice traversal.  Although theoretically redundant in
+	view of the `work` list, this simplifies interaction with normal
+	revision walks, which pop commits from `work` before analyzing them.
+
+`date_so_far`::
+	The date of the oldest encountered interesting commit.  Passing NULL
+	will let `traverse_cache_slice` use defaults.
+
+`slop_so_far`::
+	The `slop` value, a la revision.c.  This is a counter used to determine
+	when to stop traversing, based on how many extra uninteresting commits
+	should be encountered.  NULL will enable defaults, as above.
+
+`queue`::
+	Refers to a pointer to the head of a FIFO commit list, recieving the
+	commits we've seen and added.
+
+`work`::
+	A date-ordered list of commits that have yet to be processed (i.e. seen
+	but not added).  Commits from here present in the slice are removed
+	(and, obviously, used as starting places for traversal), and any end
+	commits encountered are inserted.
+
+starts_from_slices
+^^^^^^^^^^^^^^^^^^
+----
+void starts_from_slices(
+	struct rev_info *revs OUT, 
+	unsigned int flags IN, 
+	unsigned char *which IN, 
+	int n IN
+)
+----
+
+Will mark start-commits in certain rev-cache slices with `flag`, and added them
+to the pending list of `revs`.  If `n` is zero, `starts_from_slices` will use
+all slices.  Otherwise `which` will specify an *unseperated* list of cache
+SHA-1s to use (20 bytes each), and `n` will contain the number of slices (i.e.
+20 * `n` = size of `which`).
+
+fuse_cache_slices
+^^^^^^^^^^^^^^^^^
+----
+int fuse_cache_slices(
+	struct rev_cache_info *rci IN, 
+	struct rev_info *revs IN
+)
+----
+
+Generate a slice based on `revs`, replacing all encountered slices with one
+(larger) slice.  The `ignore_size` field in `rci`, if non-zero, will dictate
+which cache slice sizes to ignore in both traversal and replacement.
+
+regenerate_cache_index
+^^^^^^^^^^^^^^^^^^^^^^
+----
+int regenerate_cache_index(
+	struct rev_cache_info *rci IN
+)
+----
+
+Remake the revision cache index, including all the slices.  Currently no
+options in `rci` exist for index (re)generation, but some may develop in the
+future.
+
+Example Usage
+-------------
+
+A few examples to demonstrate usage:
+
+.Creating a slice
+----
+/* pretend you're a porcelain for rev-cache reading from the command line */
+struct rev_info revs;
+struct rev_cache_info rci;
+
+init_revisions(&revs, 0);
+init_rci(&rci);
+
+flags = 0;
+for (i = 1; i < argc; i++) {
+        if (!strcmp(argv[i], "--not"))
+                flags ^= UNINTERESTING;
+        else if(!strcmp(argv[i], "--fresh"))
+                starts_from_slices(&revs, UNINTERESTING, 0, 0);
+        else
+                handle_revision_arg(argv[i], &revs, flags, 1);
+}
+
+/* we want to explicitly set certain options */
+rci.objects = 0;
+
+if (!make_cache_slice(&rci, &revs, 0, 0, cache_sha1))
+        printf("made slice!  it's called %s\n", sha1_to_hex(cache_sha1));
+----
+
+.Traversing a slice
+----
+/* let's say you're walking the tree with a 'work' list of current heads and a
+ * FILO output list 'out' */
+out = 0;
+outp = &out;
+
+while (work) {
+        struct commit *commit = pop_commit(&work);
+        struct object *object = &commit->object;
+        unsigned char *cache_sha1;
+        
+        if (cache_sha1 = get_cache_slice(object->sha1)) {
+                /* note that this will instatiate any topo-relations 
+                 * as it goes */
+                if (traverse_cache_slice(&revs, cache_sha1,
+                        commit, 0, 0, /* use defaults */
+                        &outp, &work) < 0)
+                        die("I'm overreacting to a non-fatal cache error");
+        } else {
+                struct commit_list *parents = commit->parents;
+                
+                while (parents) {
+                        struct commit *p = parents->item;
+                        struct object *po = &p->object;
+                        
+                        parents = parents->next;
+                        if (po->flags & UNINTERESTING)
+                                continue;
+                        
+                        if (object->flags & UNINTERESTING)
+                                po->flags |= UNINTERESTING;
+                        else if (po->flags & SEEN)
+                                continue;
+                        
+                        if (!po->parsed)
+                                parse_commit(p);
+                        insert_by_date(p, &work);
+                }
+                
+                if (object->flags & (SEEN | UNINTERESTING) == 0)
+                        outp = &commit_list_insert(commit, outp)->next;
+                object->flags |= SEEN;
+        }
+}
+----
+
+Some Internals
+--------------
+For more advanced usage, the slice and index file(s) may be accessed directly.
+Relavant structures are availabe in `rev-cache.h`.
+
+File Formats
+~~~~~~~~~~~~
+
+Cache Slices
+^^^^^^^^^^^^
+A slice has a basic fixed-size header, followed by a certain number of object
+entries, then a NULL-seperated list of object names.  Commits are sorted in
+topo-order, and each commit entry is followed by the objects added in that
+commit.
+
+----
+         -- +--------------------------------+
+header      | object number, etc...          |
+         -- +--------------------------------+
+commit      | commit info                    |
+entry       | path data                      |
+            +--------------------------------+
+            | tree/blob info                 |
+            +--------------------------------+
+            | tree/blob info                 |
+            +--------------------------------+
+            | ...                            |
+         -- +--------------------------------+
+commit      | commit info                    |
+entry       | path data                      |
+            +--------------------------------+
+            | tree/blob info                 |
+            +--------------------------------+
+            | ...                            |
+         -- +--------------------------------+
+...         ...                               
+         -- +--------------------------------+
+name list   | \0some_file_name\0             |
+(note       +--------------------------------+
+preceeding  | another_file\0                 |
+null)       ...                              |
+            +--------------------------------+
+----
+
+Here is the header:
+
+----
+struct rc_cache_slice_header {
+	char signature[8]; /* REVCACHE */
+	unsigned char version;
+	uint32_t ofs_objects;
+	
+	uint32_t object_nr;
+	uint16_t path_nr;
+	uint32_t size;
+	
+	unsigned char sha1[20];
+	
+	uint32_t names_size;
+};
+----
+
+Explanations:
+
+`signature`::
+	The identifying signature of cache slice file.  Always "REVCACHE".
+`version`::
+	The version number, currently 1.
+`ofs_objects`::
+	The byte offset at which the commit/object listing starts.  Always
+	present at the 10th byte, regardless of file version.
+`object_nr`::
+	The total number of objects (commit + non-commit objects) present in
+	the slice.
+`path_nr`::
+	The total number of paths/channels used in encoding the topological
+	data.  Note that paths are reused (see 'Mechanics'), so there will
+	never be more than a few hundred paths (if that) used.
+`size`::
+	The size of the slice *excluding* the name list.  In other words, the
+	size of the portion mapped to memory.
+`sha1`::
+	The cache slice SHA-1.
+`names_size`::
+	The size of the name list.  `size` + `names_size` = size of slice
+
+Revision Cache Index
+^^^^^^^^^^^^^^^^^^^^
+The index is a single file that associates SHA-1s with cache slices and file
+positions.  It is somewhat similar to pack-file indexes, containing a fanout
+table and a list of index entries sorted by hash.
+
+----
+         -- +--------------------------------+
+header      | object #, cache #, etc.        |
+         -- +--------------------------------+
+sha1s of    | SHA-1                          |
+slices      | ...                            |
+         -- +--------------------------------+
+fanout      | fanout[0x00]                   |
+table       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+            | fanout[0xff]                   |
+         -- +--------------------------------+
+index       | SHA-1 of object                |
+entries     | index of cache slice SHA-1     |
+            | position in cache slice        |
+            +--------------------------------+
+            |                                |
+            ...                               
+            +--------------------------------+
+----
+
+The header:
+
+----
+struct rc_index_header {
+	char signature[8]; /* REVINDEX */
+	unsigned char version;
+	uint32_t ofs_objects;
+	
+	uint32_t object_nr;
+	unsigned char cache_nr;
+	
+	uint32_t max_date;
+};
+----
+
+Explanations:
+
+`signature`::
+	Always "REVINDEX".
+`version`::
+	Version number, currently 1.
+`ofs_objects`::
+	Offset at which the entry objects begin.  This is more obviously useful
+	in the index because the list of slice SHA-1s is variably-sized.
+`object_nr`::
+	Number of index entry objects present.
+`cache_nr`::
+	Number of cache slices to which the index maps, and hence the number of
+slice SHA-1s listed.
+`max_date`::
+	The oldest commit represented in the index.  This is used to help speed
+up lookup times by knowing what range of commits we definitely don't have
+cached.  Normal usage of 'rev-cache' would leave no "holes" in its coverage of
+commit history -- once a commit is cached, everything reachable from it should
+be cached as well.  Most of the time refs are added to rev-cache simultaneous
+as well.  This means that in most situations almost everything <= `max_date`
+will be cached.
+
+Mechanics
+~~~~~~~~~
+
+The most important part of rev-cache is its method of encoding topological
+relations.  To ensure fluid traversal and reconstruction, commits are related
+through high-level "streams"/"channels" rather than individual
+interconnections.  Intuitively, rev-cache stores history the way gitk shows it:
+commits strung up on lines, which interconnect at merges and branches.
+
+Each commit is associated to a given channel/path via a 'path id', and
+variable-length fields govern which paths (if any) are closed or opened at that
+object.  This means that topo-data can be preserved in only a few bytes extra
+per object entry.  Other information stored per entry is the sha-1 hash, type,
+date, size, name, and status in cache slice.  Here is format of an object
+entry, both on-disk and in-memory:
+
+----
+struct object_entry {
+        unsigned type : 3;
+        unsigned is_end : 1;
+        unsigned is_start : 1;
+        unsigned uninteresting : 1;
+        unsigned include : 1;
+        unsigned flags : 1;
+        unsigned char sha1[20];
+        
+        unsigned char merge_nr;
+        unsigned char split_nr;
+        unsigned size_size : 3;
+        unsigned name_size : 3;
+        
+        uint32_t date;
+        uint16_t path;
+        
+        /* merge paths */
+        /* split paths */
+        /* size */
+        /* name index */
+};
+----
+
+An explanation of each field:
+
+`type`::
+	Object type
+`is_end`::
+	The commit has some parents outside the cache slice (all if slice has
+	legs)
+`is_start`::
+	The commit has no children in cache slice
+`uninteresting`::
+	Run-time flag, used in traversal
+`include`::
+	Run-time flag, used in traversal (initialization)
+`flags`::
+	Currently unused, extra bit
+`sha1`::
+	Object SHA-1 hash
+
+`merge_nr`::
+	The number of paths the current channel diverges into; the current path
+	ends upon any merge.
+`split_nr`::
+	The number of paths this commit ends; used on both merging and
+	branching.
+`size_size`::
+	Number of bytes the object size takes up.
+`name_size`::
+	Number of bytes the name index takes up.
+
+`date`::
+	The date of the commit.
+`path`::
+	The path ID of the channel with which this commit is associated.
+
+merge paths::
+	The path IDs (16-bit) that are to be created.  Overflow is not a
+	problem as path IDs are reused, leaving even complicated projects to
+	consume no more than a few hundred IDs.
+split paths::
+	The path IDs (16-bit) that are to be ended.
+size::
+	The size split into the minimum number of bytes.  That is, 1-8 bytes
+	representing the size, least-significant byte first.
+name index::
+	An offset for the null-seperated, object name list at the end of the
+	cache slice.  Also split into the minimum number of bytes.
+
+Each path ID refers to an index in a 'path array', which stores the current
+status (eg. active, interestingness) of each channel.
+
+Due to topo-relations and boundary tracking, all of a commit's parents must be
+encountered before the path is reallocated.  This is achieved by using a
+counter system per merge: starting at the parent number, the counter is
+decremented as each parent is encountered (dictated by 'split paths'); at 0 the
+path is cleared.
+
+Boundary tracking is necessary because non-commits are stored relative to the
+commit in which they were introduced.  If a series of commits is not included
+in the output, the last interesting commit must be parsed manually to ensure
+all objects are accounted for.
+
+To prevent list-objects from recursing into trees that we've already taken care
+of, the flag `FACE_VALUE` is introduced.  An object with this flag is not
+explored (= "taken at face value"), significantly reducing I/O and processing
+time.
-- 
tg: (24e14b8..) t/revcache/docs (depends on: t/revcache/integration)

^ 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