* [PATCH] More useful/hinting error messages in git-checkout
From: Josef Weidendorfer @ 2006-02-15 19:22 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7v3bilr2zr.fsf@assigned-by-dhcp.cox.net>
Signed-off-by: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
---
On Tuesday 14 February 2006 23:26, you wrote:
>
> $ git checkout -b test v2.6.10
>
> The user wanted to create a new branch test based on tag
> v2.6.10, alas that tag does not exist. We give quite confusing
> error message because we are confused that the user meant to
> checkout only "./v2.6.10" file and that operation and switching
> branches are incompatible.
Does this patch clarify the error condition?
Josef
git-checkout.sh | 13 ++++++++++---
1 files changed, 10 insertions(+), 3 deletions(-)
d15e024c0bd07a2f0dad6e2729e2681df374c8e6
diff --git a/git-checkout.sh b/git-checkout.sh
index 6a87c71..b7d892d 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -22,7 +22,7 @@ while [ "$#" != "0" ]; do
[ -e "$GIT_DIR/refs/heads/$newbranch" ] &&
die "git checkout: branch $newbranch already exists"
git-check-ref-format "heads/$newbranch" ||
- die "we do not like '$newbranch' as a branch name."
+ die "git checkout: we do not like '$newbranch' as a branch name."
;;
"-f")
force=1
@@ -75,9 +75,15 @@ done
if test "$#" -ge 1
then
+ hint=
+ if test "$#" -eq 1
+ then
+ hint="
+Did you intend to checkout '$@' which can not be resolved as commit?"
+ fi
if test '' != "$newbranch$force$merge"
then
- die "updating paths and switching branches or forcing are incompatible."
+ die "git checkout: updating paths is incompatible with switching branches/forcing$hint"
fi
if test '' != "$new"
then
@@ -117,7 +123,8 @@ fi
[ -z "$branch$newbranch" ] &&
[ "$new" != "$old" ] &&
- die "git checkout: you need to specify a new branch name"
+ die "git checkout: to checkout the requested commit you need to specify
+ a name for a new branch which is created and switched to"
if [ "$force" ]
then
--
1.2.0.g719b
^ permalink raw reply related
* Re: [ANNOUNCE] pg - A patch porcelain for GIT
From: J. Bruce Fields @ 2006-02-15 19:45 UTC (permalink / raw)
To: Sam Vilain, Petr Baudis, Chuck Lever, Karl Hasselström,
Catalin Marinas, git
In-Reply-To: <20060215065411.GB26632@spearce.org>
On Wed, Feb 15, 2006 at 01:54:11AM -0500, Shawn Pearce wrote:
> "J. Bruce Fields" <bfields@fieldses.org> wrote:
> > On Tue, Feb 14, 2006 at 07:35:10PM -0500, Shawn Pearce wrote:
> > > Publishing a repository with a stg (or pg) patch series isn't
> > > a problem; the problem is that no clients currently know how to
> > > follow along with the remote repository's patch series. And I can't
> > > think of a sensible behavior for doing so that isn't what git-core is
> > > already doing today for non patch series type clients (as in don't go
> > > backwards by popping but instead by pushing a negative delta). :-)
> >
> > If you represent each patch as a branch, with each modification to the
> > patch a commit on the corresponding branch, and each "push" operation a
> > merge from the branch corresponding to the previous patch to a branch
> > corresponding to the new patch (isn't that what pg's trying to do?),
> > then it should be possible just to track the branch corresponding to the
> > top patch.
>
> Yes that's pg in a nutshell.
>
> But what happens when I pop back two patches (of three) and then push
> down a different (fourth) patch? The tree just rewound backwards
> and then forwards again in a different direction.
So you've got p1, p2, and p3 applied, each with its corresponding
branch--respectively, b1, b2, and b3. Popping two patches just checks
out b1, and doesn't affect the repository at all. If you push a new
patch, p4, you've just created a new branch, b4--you haven't touched the
existing branches. If you push p2 and p3 back on, you're just merging
the new changes from b4 into b2 and then merging the newly merged b2
into b3.
>From the point of view of someone tracking b3, this is all fine. OK,
maybe it's excessively complicated, but pulls should work, because it
never sees history diseappear as it does when you represent each patch
with a commit on a single branch.
> > If you really want revision control on patches the simplest thing might
> > be just to run quilt or Andrew Morton's scripts on top of a git
> > repository--the documentation with Andrew's scripts recommends doing
> > that with CVS.
>
> True but you also then run into problems about needing to know which
> base each patch revision was applied against so you can reproduce
> a source tree plus patch at a specific point in time.
Right, so you keep the tree under revision control as well as the
patches.
--b.
^ permalink raw reply
* Modified files coming from v2.6.12 checkout
From: Shawn Pearce @ 2006-02-15 20:04 UTC (permalink / raw)
To: git
I'm trying to do a performance test suggested by Catalin. I cloned
(what I thought to be) Linus public kernel tree[1] then locally
cloned it again and tried to checkout a working directory of v2.6.12:
$ git-clone [1]
$ git-clone -l -n linux-2.6 bigmergetest
$ cd bigmergetest
$ ls -a
. .. .git
$ git-update-ref HEAD $(git-rev-parse --verify v2.6.12^{commit})
$ git-read-tree HEAD
$ git-checkout-index -u -a
git-checkout-index: include/linux/netfilter_ipv4/ipt_connmark.h already exists
...
git-checkout-index: net/ipv4/netfilter/ipt_tos.c already exists
git-checkout-index: net/ipv6/netfilter/ip6t_mark.c already exists
That can't be right. Why do so many files already exist during
an empty checkout? git-status is reporting these files as being
modified. If I commit these 'modified' files there's actually a
rather large delta if I diff v2.6.12 and the new commit.
I've tried this both with git 1.1.4 and 1.2.0. Same result.
I've also tried it with both the v2.6.12 tag and the current HEAD.
Same result just different files having the problem.
I just looked at the linux-2.6 directory which I cloned from [1];
it appears to have the same problem but on a slightly different
set of files than the v.2.6.12 clone:
$ git-status | grep modified | wc -l
18
Thoughts? Suggestions of where to start looking for a fault?
Does the fault exist between the chair and the keyboard?
[1] http://www.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git/
--
Shawn.
^ permalink raw reply
* Re: Modified files coming from v2.6.12 checkout
From: Shawn Pearce @ 2006-02-15 20:21 UTC (permalink / raw)
To: git
In-Reply-To: <20060215200442.GB5742@spearce.org>
Gaaah. This is was on MacOS X. Whose filesystem isn't case
sensitive yet somehow tries to be. If ipt_TOS.c and ipt_tos.c
both exist in the same directory I'm not surprised this works ok
for everyone else except me. :-)
Fault found: A problem exists between the chair and the keyboard.
I'll switch to a Linux system to work with Linux kernel sources.
Sorry for the noise.
Shawn Pearce <spearce@spearce.org> wrote:
> I'm trying to do a performance test suggested by Catalin. I cloned
> (what I thought to be) Linus public kernel tree[1] then locally
> cloned it again and tried to checkout a working directory of v2.6.12:
>
> $ git-clone [1]
> $ git-clone -l -n linux-2.6 bigmergetest
> $ cd bigmergetest
> $ ls -a
> . .. .git
> $ git-update-ref HEAD $(git-rev-parse --verify v2.6.12^{commit})
> $ git-read-tree HEAD
> $ git-checkout-index -u -a
> git-checkout-index: include/linux/netfilter_ipv4/ipt_connmark.h already exists
> ...
> git-checkout-index: net/ipv4/netfilter/ipt_tos.c already exists
> git-checkout-index: net/ipv6/netfilter/ip6t_mark.c already exists
>
> That can't be right. Why do so many files already exist during
> an empty checkout? git-status is reporting these files as being
> modified. If I commit these 'modified' files there's actually a
> rather large delta if I diff v2.6.12 and the new commit.
>
> I've tried this both with git 1.1.4 and 1.2.0. Same result.
> I've also tried it with both the v2.6.12 tag and the current HEAD.
> Same result just different files having the problem.
>
> I just looked at the linux-2.6 directory which I cloned from [1];
> it appears to have the same problem but on a slightly different
> set of files than the v.2.6.12 clone:
>
> $ git-status | grep modified | wc -l
> 18
>
> Thoughts? Suggestions of where to start looking for a fault?
> Does the fault exist between the chair and the keyboard?
>
>
> [1] http://www.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git/
--
Shawn.
^ permalink raw reply
* git faq : draft and rfc
From: Thomas Riboulet @ 2006-02-16 0:36 UTC (permalink / raw)
To: git
hi,
After a quick talk on irc with pasky, fonseca and Tv, I've started to
write a git faq starting with questions I had and they have suggested.
I've setted up a git repos : http://git.librium.org/git_faq.git (atm
it's on my DSL link, so it could be slow, should move soon)
The faq is available in both docbook xml and text format (don't know
what you prefer).
You can see the html output there : http://koalabs.org/~ange/git_faq/faq.html
and the text file : http://koalabs.org/~ange/git_faq/faq.txt
if needed I can write specific xsl stylesheets to handle better or
more suited output.
Comments and suggestions are welcome (on the content, the form, format, etc ...)
I'll try to add questions from the archives of this ml, I'm also open
to any suggestions.
Here is a first (text) version :
----
. Why the 'git' name ?
As Linus' own words as the inventor of git :
"git" can mean anything, depending on your mood.
- random three-letter combination that is pronounceable, and not
actually used by any common UNIX command. The fact that it is a
mispronunciation of "get" may or may not be relevant.
- stupid. contemptible and despicable. simple. Take your pick from the
dictionary of slang.
- "global information tracker": you're in a good mood, and it actually
works for you. Angels sing, and a light suddenly fills the room.
- "goddamn idiotic truckload of sh*t": when it breaks
. Can I use my git public repository in a shared way ?
Yes. Use cg-admin-setuprepo -g or do git-init-db --shared and some
additional stuff. It's ok that refs aren't group writable, it's
enough the directory is. See Cogito README or GIT's cvs-migration doc,
"Emulating the CVS Development Model" for details.
. Git commit is dying telling me "fatal : empty ident <user@myhost>
not allowed", what's wrong ?
Make sure your Full Name is not empty in chsh or the 5th field of your
user line in /etc/passwd isn't empty. If you @myhost is empty make sure
your hostname is correctly set.
. What's the difference between fetch and pull ?
Fetch : download objects and a head from another repository.
Pull : pull and merge from another repository.
See man git-fetch and git-pull for more.
. Can I tell git to ignore files ?
Yes. Put the files path in the repository in the .git/info/exclude file.
. Can I import from cvs ?
Yes. Use git-cvsimport. See the cvs-migration doc for more details.
. Can I import from svn ?
Yes. Use git-svnimport. See the svn-import doc for more details.
. What can I use to setup a public repository ?
A ssh server, an http server, or the git-daemon.
See the tutorial for more details.
--
Thom/ange
^ permalink raw reply
* Re: "git reset --hard" leaves empty directories that shouldn't exist
From: Linus Torvalds @ 2006-02-16 1:35 UTC (permalink / raw)
To: Carl Worth; +Cc: git
In-Reply-To: <87y80dhxfd.wl%cworth@cworth.org>
On Tue, 14 Feb 2006, Carl Worth wrote:
>
> I've been exploring the potential for git-sync, and I found some odd
> behavior with "git reset --hard". It appears that if the current tree
> has some directory structure (at least two levels deep) that does not
> exist in the tree being reset to, that empty directories are left
> around after the reset:
"git reset --hard xyz" in many ways is a sledgehammer, and it says "I want
the state at the point of xyz, and I don't care _what_ the heck the
current state is".
Now, that's somewhat problematic, exactly because of that "screw the
current state" thing. It actually tries to remove files (see the
"tmp-exists" thing in the git-reset script), but it's being pretty stupid
about it. It also very definitely will not try to remove subdirectories,
empty or not.
(I say that without being able to read perl, so I might be wrong. Maybe it
tries and just fails).
Anyway, if you want to do the "gentle and smart" thing, you should
probably actually use
git-read-tree -m -u <oldtree> <newtree>
which unlike "git-reset" will gently _update_ the tree from one version to
another (and will error out if your checked-out copy doesn't match the
old tree).
And the gentle way will actually do the right thing wrt subdirectories
(note that it will _not_ remove empty subdirectories if you have left
files - like object files - around that it doesn't know about: that's not
an error, but the unknown file will not, nor the subdirectory, be
removed).
And yes, git-reset should probably do the subdirectory thing too. In the
meantime you should think of it as the brute-force and not very smart way
(in Calvin and Hobbes terms, "git reset" is Moe).
Linus
^ permalink raw reply
* [PATCH] pack-objects: reuse data from existing pack.
From: Junio C Hamano @ 2006-02-16 1:43 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <7vd5hpm2x0.fsf@assigned-by-dhcp.cox.net>
When generating a new pack, notice if we have already the wanted
object in existing packs. If the object has a delitified
representation, and its base object is also what we are going to
pack, then reuse the existing deltified representation
unconditionally, bypassing all the expensive find_deltas() and
try_deltas() routines.
Also, when writing out such deltified representation and
undeltified representation, if a matching data already exists in
an existing pack, just write it out without uncompressing &
recompressing.
Without this patch:
$ git-rev-list --objects v1.0.0 >RL
$ time git-pack-objects p <RL
Generating pack...
Done counting 12233 objects.
Packing 12233 objects....................
60a88b3979df41e22d1edc3967095e897f720192
real 0m32.751s
user 0m27.090s
sys 0m2.750s
With this patch:
$ git-rev-list --objects v1.0.0 >RL
$ time ../git.junio/git-pack-objects q <RL
Generating pack...
Done counting 12233 objects.
Packing 12233 objects.....................
60a88b3979df41e22d1edc3967095e897f720192
Total 12233, written 12233, reused 12177
real 0m4.007s
user 0m3.360s
sys 0m0.090s
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
* This may depend on one cleanup patch I have not sent out, but
I am so excited that I could not help sending this out first.
Admittedly this is hot off the press, I have not had enough
time to beat this too hard, but the resulting pack from the
above passed unpack-objects, index-pack and verify-pack.
pack-objects.c | 317 ++++++++++++++++++++++++++++++++++++++++++++++----------
pack.h | 4 +
sha1_file.c | 19 +++
3 files changed, 283 insertions(+), 57 deletions(-)
0d574a3c3ec6924118d06ee0487d02d2fbb12646
diff --git a/pack-objects.c b/pack-objects.c
index c5a5e61..f2a45a2 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -9,13 +9,16 @@ static const char pack_usage[] = "git-pa
struct object_entry {
unsigned char sha1[20];
- unsigned long size;
- unsigned long offset;
- unsigned int depth;
- unsigned int hash;
+ unsigned long size; /* uncompressed size */
+ unsigned long offset; /* offset into the final pack file (nonzero if already written) */
+ unsigned int depth; /* delta depth */
+ unsigned int hash; /* name hint hash */
enum object_type type;
- unsigned long delta_size;
- struct object_entry *delta;
+ unsigned long delta_size; /* delta data size (uncompressed) */
+ struct object_entry *delta; /* delta base object */
+ struct packed_git *in_pack; /* already in pack */
+ enum object_type in_pack_type; /* could be delta */
+ unsigned int in_pack_offset;
};
static unsigned char object_list_sha1[20];
@@ -29,6 +32,105 @@ static const char *base_name;
static unsigned char pack_file_sha1[20];
static int progress = 1;
+static int *object_ix = NULL;
+static int object_ix_hashsz = 0;
+
+struct pack_revindex {
+ struct packed_git *p;
+ unsigned long *revindex;
+} *pack_revindex = NULL;
+static int pack_revindex_hashsz = 0;
+
+static int pack_revindex_ix(struct packed_git *p)
+{
+ unsigned int ui = (unsigned int) p;
+ int i;
+ ui = ui ^ (ui >> 16);
+ i = (int)(ui % pack_revindex_hashsz);
+ while (pack_revindex[i].p) {
+ if (pack_revindex[i].p == p)
+ return i;
+ if (++i == pack_revindex_hashsz)
+ i = 0;
+ }
+ return -1 - i;
+}
+
+static void prepare_pack_ix(void)
+{
+ int num;
+ struct packed_git *p;
+ for (num = 0, p = packed_git; p; p = p->next)
+ num++;
+ if (!num)
+ return;
+ pack_revindex_hashsz = num * 11;
+ pack_revindex = xcalloc(sizeof(*pack_revindex), pack_revindex_hashsz);
+ for (p = packed_git; p; p = p->next) {
+ num = pack_revindex_ix(p);
+ num = - 1 - num;
+ pack_revindex[num].p = p;
+ }
+ /* revindex elements are lazily initialized */
+}
+
+static int cmp_offset(const void *a_, const void *b_)
+{
+ unsigned long a = *(unsigned long *) a_;
+ unsigned long b = *(unsigned long *) b_;
+ if (a < b)
+ return -1;
+ else if (a == b)
+ return 0;
+ else
+ return 1;
+}
+
+static void prepare_pack_revindex(struct pack_revindex *rix)
+{
+ struct packed_git *p = rix->p;
+ int num_ent = num_packed_objects(p);
+ int i;
+ void *index = p->index_base + 256;
+
+ rix->revindex = xmalloc(sizeof(unsigned long) * (num_ent + 1));
+ for (i = 0; i < num_ent; i++) {
+ long hl = *((long *)(index + 24 * i));
+ rix->revindex[i] = ntohl(hl);
+ }
+ rix->revindex[num_ent] = p->pack_size - 20;
+ qsort(rix->revindex, num_ent, sizeof(unsigned long), cmp_offset);
+}
+
+static unsigned long find_packed_object_size(struct packed_git *p,
+ unsigned long ofs)
+{
+ int num;
+ int lo, hi;
+ struct pack_revindex *rix;
+ unsigned long *revindex;
+ num = pack_revindex_ix(p);
+ if (num < 0)
+ die("internal error: pack revindex uninitialized");
+ rix = &pack_revindex[num];
+ if (!rix->revindex)
+ prepare_pack_revindex(rix);
+ revindex = rix->revindex;
+ lo = 0;
+ hi = num_packed_objects(p) + 1;
+ do {
+ int mi = (lo + hi) / 2;
+ if (revindex[mi] == ofs) {
+ return revindex[mi+1] - ofs;
+ }
+ else if (ofs < revindex[mi])
+ hi = mi;
+ else
+ lo = mi + 1;
+ } while (lo < hi);
+ die("internal error: pack revindex corrupt");
+}
+
static void *delta_against(void *buf, unsigned long size, struct object_entry *entry)
{
unsigned long othersize, delta_size;
@@ -74,39 +176,59 @@ static int encode_header(enum object_typ
return n;
}
+static int written = 0;
+static int reused = 0;
+
static unsigned long write_object(struct sha1file *f, struct object_entry *entry)
{
unsigned long size;
char type[10];
- void *buf = read_sha1_file(entry->sha1, type, &size);
+ void *buf;
unsigned char header[10];
unsigned hdrlen, datalen;
enum object_type obj_type;
- if (!buf)
- die("unable to read %s", sha1_to_hex(entry->sha1));
- if (size != entry->size)
- die("object %s size inconsistency (%lu vs %lu)", sha1_to_hex(entry->sha1), size, entry->size);
-
- /*
- * The object header is a byte of 'type' followed by zero or
- * more bytes of length. For deltas, the 20 bytes of delta sha1
- * follows that.
- */
obj_type = entry->type;
- if (entry->delta) {
- buf = delta_against(buf, size, entry);
- size = entry->delta_size;
- obj_type = OBJ_DELTA;
- }
- hdrlen = encode_header(obj_type, size, header);
- sha1write(f, header, hdrlen);
- if (entry->delta) {
- sha1write(f, entry->delta, 20);
- hdrlen += 20;
+ if (!entry->in_pack ||
+ (obj_type != entry->in_pack_type)) {
+ buf = read_sha1_file(entry->sha1, type, &size);
+ if (!buf)
+ die("unable to read %s", sha1_to_hex(entry->sha1));
+ if (size != entry->size)
+ die("object %s size inconsistency (%lu vs %lu)",
+ sha1_to_hex(entry->sha1), size, entry->size);
+ if (entry->delta) {
+ buf = delta_against(buf, size, entry);
+ size = entry->delta_size;
+ obj_type = OBJ_DELTA;
+ }
+ /*
+ * The object header is a byte of 'type' followed by zero or
+ * more bytes of length. For deltas, the 20 bytes of delta
+ * sha1 follows that.
+ */
+ hdrlen = encode_header(obj_type, size, header);
+ sha1write(f, header, hdrlen);
+
+ if (entry->delta) {
+ sha1write(f, entry->delta, 20);
+ hdrlen += 20;
+ }
+ datalen = sha1write_compressed(f, buf, size);
+ free(buf);
+ }
+ else {
+ struct packed_git *p = entry->in_pack;
+ use_packed_git(p);
+
+ datalen = find_packed_object_size(p, entry->in_pack_offset);
+ buf = p->pack_base + entry->in_pack_offset;
+ sha1write(f, buf, datalen);
+ unuse_packed_git(p);
+ hdrlen = 0; /* not really */
+ reused++;
}
- datalen = sha1write_compressed(f, buf, size);
- free(buf);
+ written++;
return hdrlen + datalen;
}
@@ -196,18 +318,21 @@ static int add_object_entry(unsigned cha
{
unsigned int idx = nr_objects;
struct object_entry *entry;
-
- if (incremental || local) {
- struct packed_git *p;
-
- for (p = packed_git; p; p = p->next) {
- struct pack_entry e;
-
- if (find_pack_entry_one(sha1, &e, p)) {
- if (incremental)
- return 0;
- if (local && !p->pack_local)
- return 0;
+ struct packed_git *p;
+ unsigned int found_offset;
+ struct packed_git *found_pack;
+
+ found_pack = NULL;
+ for (p = packed_git; p; p = p->next) {
+ struct pack_entry e;
+ if (find_pack_entry_one(sha1, &e, p)) {
+ if (incremental)
+ return 0;
+ if (local && !p->pack_local)
+ return 0;
+ if (!found_pack) {
+ found_offset = e.offset;
+ found_pack = e.p;
}
}
}
@@ -221,30 +346,99 @@ static int add_object_entry(unsigned cha
memset(entry, 0, sizeof(*entry));
memcpy(entry->sha1, sha1, 20);
entry->hash = hash;
+ if (found_pack) {
+ entry->in_pack = found_pack;
+ entry->in_pack_offset = found_offset;
+ }
nr_objects = idx+1;
return 1;
}
+static int locate_object_entry_hash(unsigned char *sha1)
+{
+ int i;
+ unsigned int ui;
+ memcpy(&ui, sha1, sizeof(unsigned int));
+ i = ui % object_ix_hashsz;
+ while (0 < object_ix[i]) {
+ if (!memcmp(sha1, objects[object_ix[i]-1].sha1, 20))
+ return i;
+ if (++i == object_ix_hashsz)
+ i = 0;
+ }
+ return -1 - i;
+}
+
+static struct object_entry *locate_object_entry(unsigned char *sha1)
+{
+ int i = locate_object_entry_hash(sha1);
+ if (0 <= i)
+ return &objects[object_ix[i]-1];
+ return NULL;
+}
+
static void check_object(struct object_entry *entry)
{
char type[20];
- if (!sha1_object_info(entry->sha1, type, &entry->size)) {
- if (!strcmp(type, "commit")) {
- entry->type = OBJ_COMMIT;
- } else if (!strcmp(type, "tree")) {
- entry->type = OBJ_TREE;
- } else if (!strcmp(type, "blob")) {
- entry->type = OBJ_BLOB;
- } else if (!strcmp(type, "tag")) {
- entry->type = OBJ_TAG;
- } else
- die("unable to pack object %s of type %s",
- sha1_to_hex(entry->sha1), type);
+ if (entry->in_pack) {
+ /* Check if it is delta, and the base is also an object
+ * we are going to pack. If so we will reuse the existing
+ * delta.
+ */
+ unsigned char base[20];
+ unsigned long size;
+ struct object_entry *base_entry;
+ if (!check_reuse_pack_delta(entry->in_pack,
+ entry->in_pack_offset,
+ base, &size,
+ &entry->in_pack_type) &&
+ (base_entry = locate_object_entry(base))) {
+ /* we do not know yet, but it does not matter */
+ entry->depth = 1;
+ /* uncompressed size */
+ entry->size = entry->delta_size = size;
+ entry->delta = base_entry;
+ entry->type = OBJ_DELTA; /* !! */
+ return;
+ }
+ /* Otherwise we would do the usual */
}
- else
+
+ if (sha1_object_info(entry->sha1, type, &entry->size))
die("unable to get type of object %s",
sha1_to_hex(entry->sha1));
+
+ if (!strcmp(type, "commit")) {
+ entry->type = OBJ_COMMIT;
+ } else if (!strcmp(type, "tree")) {
+ entry->type = OBJ_TREE;
+ } else if (!strcmp(type, "blob")) {
+ entry->type = OBJ_BLOB;
+ } else if (!strcmp(type, "tag")) {
+ entry->type = OBJ_TAG;
+ } else
+ die("unable to pack object %s of type %s",
+ sha1_to_hex(entry->sha1), type);
+}
+
+static void hash_objects(void)
+{
+ int i;
+ struct object_entry *oe;
+
+ object_ix_hashsz = nr_objects * 2;
+ object_ix = xcalloc(sizeof(int), object_ix_hashsz);
+ for (i = 0, oe = objects; i < nr_objects; i++, oe++) {
+ int ix = locate_object_entry_hash(oe->sha1);
+ if (0 <= ix) {
+ error("the same object '%s' added twice",
+ sha1_to_hex(oe->sha1));
+ continue;
+ }
+ ix = -1 - ix;
+ object_ix[ix] = i + 1;
+ }
}
static void get_object_details(void)
@@ -252,6 +446,8 @@ static void get_object_details(void)
int i;
struct object_entry *entry = objects;
+ hash_objects();
+ prepare_pack_ix();
for (i = 0; i < nr_objects; i++)
check_object(entry++);
}
@@ -382,6 +578,11 @@ static void find_deltas(struct object_en
eye_candy -= nr_objects / 20;
fputc('.', stderr);
}
+
+ if (entry->delta)
+ /* we already know what we need to know */
+ continue;
+
free(n->data);
n->entry = entry;
n->data = read_sha1_file(entry->sha1, type, &size);
@@ -411,10 +612,12 @@ static void find_deltas(struct object_en
static void prepare_pack(int window, int depth)
{
- get_object_details();
-
if (progress)
fprintf(stderr, "Packing %d objects", nr_objects);
+ get_object_details();
+ if (progress)
+ fprintf(stderr, ".");
+
sorted_by_type = create_sorted_list(type_size_sort);
if (window && depth)
find_deltas(sorted_by_type, window+1, depth);
@@ -599,5 +802,7 @@ int main(int argc, char **argv)
puts(sha1_to_hex(object_list_sha1));
}
}
+ fprintf(stderr, "Total %d, written %d, reused %d\n",
+ nr_objects, written, reused);
return 0;
}
diff --git a/pack.h b/pack.h
index 9dafa2b..694e0c5 100644
--- a/pack.h
+++ b/pack.h
@@ -29,5 +29,7 @@ struct pack_header {
};
extern int verify_pack(struct packed_git *, int);
-
+extern int check_reuse_pack_delta(struct packed_git *, unsigned long,
+ unsigned char *, unsigned long *,
+ enum object_type *);
#endif
diff --git a/sha1_file.c b/sha1_file.c
index 64cf245..0a3a721 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -826,6 +826,25 @@ static unsigned long unpack_object_heade
return offset;
}
+int check_reuse_pack_delta(struct packed_git *p, unsigned long offset,
+ unsigned char *base, unsigned long *sizep,
+ enum object_type *kindp)
+{
+ unsigned long ptr;
+ int status = -1;
+
+ use_packed_git(p);
+ ptr = offset;
+ ptr = unpack_object_header(p, ptr, kindp, sizep);
+ if (*kindp != OBJ_DELTA)
+ goto done;
+ memcpy(base, p->pack_base + ptr, 20);
+ status = 0;
+ done:
+ unuse_packed_git(p);
+ return status;
+}
+
void packed_object_info_detail(struct pack_entry *e,
char *type,
unsigned long *size,
--
1.2.0.gcfba7
^ permalink raw reply related
* [PATCH] packed objects: minor cleanup
From: Junio C Hamano @ 2006-02-16 1:45 UTC (permalink / raw)
To: git; +Cc: Linus Torvalds
In-Reply-To: <7vbqx8m62q.fsf@assigned-by-dhcp.cox.net>
The delta depth is unsigned.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
* And this is the clean-up patch that comes before the "packed
representation reuse" patch.
cache.h | 2 +-
pack-check.c | 4 ++--
sha1_file.c | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)
f8f135c9bae74f846a92e1f1f1fea8308802ace5
diff --git a/cache.h b/cache.h
index c255421..b5db01f 100644
--- a/cache.h
+++ b/cache.h
@@ -322,7 +322,7 @@ extern int num_packed_objects(const stru
extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
extern int find_pack_entry_one(const unsigned char *, struct pack_entry *, struct packed_git *);
extern void *unpack_entry_gently(struct pack_entry *, char *, unsigned long *);
-extern void packed_object_info_detail(struct pack_entry *, char *, unsigned long *, unsigned long *, int *, unsigned char *);
+extern void packed_object_info_detail(struct pack_entry *, char *, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
/* Dumb servers support */
extern int update_server_info(int);
diff --git a/pack-check.c b/pack-check.c
index 67a7ecd..eca32b6 100644
--- a/pack-check.c
+++ b/pack-check.c
@@ -84,7 +84,7 @@ static void show_pack_info(struct packed
char type[20];
unsigned long size;
unsigned long store_size;
- int delta_chain_length;
+ unsigned int delta_chain_length;
if (nth_packed_object_sha1(p, i, sha1))
die("internal error pack-check nth-packed-object");
@@ -98,7 +98,7 @@ static void show_pack_info(struct packed
if (!delta_chain_length)
printf("%-6s %lu %u\n", type, size, e.offset);
else
- printf("%-6s %lu %u %d %s\n", type, size, e.offset,
+ printf("%-6s %lu %u %u %s\n", type, size, e.offset,
delta_chain_length, sha1_to_hex(base_sha1));
}
diff --git a/sha1_file.c b/sha1_file.c
index 3d11a9b..64cf245 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -830,7 +830,7 @@ void packed_object_info_detail(struct pa
char *type,
unsigned long *size,
unsigned long *store_size,
- int *delta_chain_length,
+ unsigned int *delta_chain_length,
unsigned char *base_sha1)
{
struct packed_git *p = e->p;
@@ -844,7 +844,7 @@ void packed_object_info_detail(struct pa
if (kind != OBJ_DELTA)
*delta_chain_length = 0;
else {
- int chain_length = 0;
+ unsigned int chain_length = 0;
memcpy(base_sha1, pack, 20);
do {
struct pack_entry base_ent;
--
1.2.0.gcfba7
^ permalink raw reply related
* Re: [FYI] pack idx format
From: Junio C Hamano @ 2006-02-16 1:58 UTC (permalink / raw)
To: git
In-Reply-To: <Pine.LNX.4.64.0602151144010.5606@localhost.localdomain>
Nicolas Pitre <nico@cam.org> writes:
> On Wed, 15 Feb 2006, Junio C Hamano wrote:
>
>> This is still WIP but if anybody is interested... Once done, it
>> should become Documentation/technical/pack-format.txt.
>>
> [...]
>>
>> Pack file entry: <+
>>
>> packed object header:
>> 1-byte type (upper 4-bit)
>
> Actually the type occupies only 3 bits (bits 4 to 6) as bit 7 is the
> size continuation bit.
You are right.
^ permalink raw reply
* Genealogical branches
From: Ron Parker @ 2006-02-16 2:20 UTC (permalink / raw)
To: git
[-- Attachment #1: Type: text/plain, Size: 3710 bytes --]
I am working on a stepped tutorial that walks the user through the
development of a number of related files. I have been trying to keep
this under various SCMs. Currently git seems like the best match. But
I have some questions.
The issue is that I want to have a directory which will ultimately
contain selected portions of the final products genealogy in addition
to other files. For example:
README
...
test1
test2
test3a
test3b
...
And each step is developed from the preceding one. However, not being
perfect, there have been occasions where I have found mistakes in an
earlier step that need to be corrected and propagated to the later
steps.
I have found a work flow that seems to do what I want, but there may
be a better way to do this and I would like some advice. I initialize
the DB and work on test1, that is then branched to step2 where test1
is first renamed and then modified to become test2.
At this point I create a "final" branch and through some shenanigans I
don't completely understand, I pull from master and B2 to get both
step1 and step2 into final with their full history. Then as changes
are made to step1 I can pull those into later steps. Another tricky
part is that when I get to final, I have to pull from all of the
ancestral branches simultaneously.
Anyway, here is an annotated script that illustrates this, it is also
attached without the extra commentary:
--- BEGIN GENETEST.SH ---
mkdir genetest
cd genetest
git init-db
cat - >test1 <<EOF
aaaaaaaa
BBBBBBBB
cccccccc
EOF
echo README>README
git add .
git commit -a -m "Initial checkin"
# Create step2 branch
git checkout -b step2
git mv test1 test2
git commit -a -m "Created step2"
echo dddddddd>>test2
echo "README 2">README
git commit -a -m "Added step2 changes"
# Create conglomerate branch
git checkout master
git checkout -b final
# This is where the shenanigans come in. I'm not even completely sure
# why it works. But arrived at the first two commands through
# experimentation. I thought one or the other would suffice, but
# neither alone did. The two together, however, bring this basically
# up to step2 status with test1 being deleted and a step2->step2
# merge indicated in the log.
git fetch -a . step2
git pull -a . step2
# So then this finds the deleted file and brings it back in from master.
FILES=$(git-diff-index --name-only --diff-filter=D master)
git add $FILES
git commit -a -m "Created final"
# Now let's go modify master and see whether or not changes
# propagate forward to both files in final.
git checkout master
cat - >test1 <<EOF
aaaaaaaa
bbbbbbbb
cccccccc
EOF
git commit -a -m "Fixed the B... line"
# Pull the changes into step2 and resolve the conflict from the
# too-close-together line changes.
git checkout step2
git pull . master || true
mv -f test1 test2
echo dddddddd>>test2
MSG=$(cat .git/MERGE_MSG)
git commit -a -m "$MSG"
# Now check that all changes come through successfully,
# the interesting thing is that all the "ancestor" branches
# MUST be pulled at together or things don't work.
git checkout final
git pull . master step2
# Check that README matches the one from step2
# and that the B... line has been corrected in both
# versions of the ancestor file.
cat README
cat test1
cat test2
# If we've gotten this far, say so.
echo SUCCEEDED
--- END GENETEST.SH ---
So can anyone explain why the mystery portions "work" and why I have
to pull from all the ancestral branches simultaneously?
Also, if you have a better solution or work flow I'm open to it.
Thanks,
--
Ron Parker
[-- Attachment #2: genetest.sh --]
[-- Type: application/x-sh, Size: 1314 bytes --]
^ permalink raw reply
* git-rev-list --date-order ?
From: Paul Mackerras @ 2006-02-16 2:40 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Junio,
Gitk has a -d option that tells it to reorder the commits in
decreasing order of their commit time, subject to the constraint that
parents come after all of their children. Currently it uses
git-rev-list --header --topo-order --parents and then reorders the
commits internally.
How hard would it be to add a --date-order flag to git-rev-list to
make it order the commits in decreasing commit time order, subject to
the constraint that parents come after their children?
If we had that then I could remove another chunk of code from gitk and
make it a bit faster.
Thanks,
Paul.
^ permalink raw reply
* Re: git-rev-list --date-order ?
From: Junio C Hamano @ 2006-02-16 3:11 UTC (permalink / raw)
To: Paul Mackerras; +Cc: git
In-Reply-To: <17395.58926.26670.23572@cargo.ozlabs.ibm.com>
Paul Mackerras <paulus@samba.org> writes:
> Junio,
>
> Gitk has a -d option that tells it to reorder the commits in
> decreasing order of their commit time, subject to the constraint that
> parents come after all of their children. Currently it uses
> git-rev-list --header --topo-order --parents and then reorders the
> commits internally.
>
> How hard would it be to add a --date-order flag to git-rev-list to
> make it order the commits in decreasing commit time order, subject to
> the constraint that parents come after their children?
>
> If we had that then I could remove another chunk of code from gitk and
> make it a bit faster.
It's been a while that I read the topo-order code, but I suspect
something like this? I may be completely off the mark here.
--
diff --git a/commit.c b/commit.c
index 67e11d7..0d94e4d 100644
--- a/commit.c
+++ b/commit.c
@@ -630,7 +630,9 @@ void sort_in_topological_order(struct co
}
next=next->next;
}
+
/* process the list in topological order */
+ sort_by_date(&work);
while (work) {
struct commit * work_item = pop_commit(&work);
struct sort_node * work_node = (struct sort_node *)work_item->object.util;
@@ -648,7 +650,7 @@ void sort_in_topological_order(struct co
*/
pn->indegree--;
if (!pn->indegree)
- commit_list_insert(parent, &work);
+ insert_by_date(parent, &work);
}
parents=parents->next;
}
^ permalink raw reply related
* Re: Handling large files with GIT
From: Linus Torvalds @ 2006-02-16 3:25 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Fredrik Kuivinen, Git Mailing List
In-Reply-To: <7vd5hpj6ab.fsf@assigned-by-dhcp.cox.net>
Btw, here's one last gasp on this thread: it generalizes the notion of
traversing several trees in sync, which could be used to do the n-way diff
for the "-c" and "--cc" style merge diffs a lot more efficiently.
I didn't check, but I'm pretty sure that this would bring the cost of
doing the 12-way diff down to way under a second. Right now:
[torvalds@g5 linux]$ time git-diff-tree -c 9fdb62a > /dev/null
real 0m1.279s
user 0m1.272s
sys 0m0.008s
and that's a bit too much. We I'd really have expected us to be able to do
better.
It should be possible to do this as a
traverse_trees(12, &trees, "", combined_diff_callback);
fairly cheaply (and quickly throw away anything where any of the parents
was the same as the result).
Junio, that "traverse_trees()" logic is totally independent of whether we
actually do "git-merge-tree" or not, so if you want to, I could split up
the patches the other way (and merge "traverse_trees()" first as a new
interface, independently).
Linus
----
git-merge-tree: generalize the "traverse <n> trees in sync" functionality
It's actually very useful for other things too. Notably, we could do the
combined diff a lot more efficiently with this.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/merge-tree.c b/merge-tree.c
index 6381118..2a9a013 100644
--- a/merge-tree.c
+++ b/merge-tree.c
@@ -125,44 +125,19 @@ static void unresolved(const char *base,
printf("3 %06o %s %s%s\n", n[2].mode, sha1_to_hex(n[2].sha1), base, n[2].path);
}
-/*
- * Merge two trees together (t[1] and t[2]), using a common base (t[0])
- * as the origin.
- *
- * This walks the (sorted) trees in lock-step, checking every possible
- * name. Note that directories automatically sort differently from other
- * files (see "base_name_compare"), so you'll never see file/directory
- * conflicts, because they won't ever compare the same.
- *
- * IOW, if a directory changes to a filename, it will automatically be
- * seen as the directory going away, and the filename being created.
- *
- * Think of this as a three-way diff.
- *
- * The output will be either:
- * - successful merge
- * "0 mode sha1 filename"
- * NOTE NOTE NOTE! FIXME! We really really need to walk the index
- * in parallel with this too!
- *
- * - conflict:
- * "1 mode sha1 filename"
- * "2 mode sha1 filename"
- * "3 mode sha1 filename"
- * where not all of the 1/2/3 lines may exist, of course.
- *
- * The successful merge rules are the same as for the three-way merge
- * in git-read-tree.
- */
-static void merge_trees(struct tree_desc t[3], const char *base)
+typedef void (*traverse_callback_t)(int n, unsigned long mask, struct name_entry *entry, const char *base);
+
+static void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callback_t callback)
{
+ struct name_entry *entry = xmalloc(n*sizeof(*entry));
+
for (;;) {
struct name_entry entry[3];
- unsigned int mask = 0;
+ unsigned long mask = 0;
int i, last;
last = -1;
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < n; i++) {
if (!t[i].size)
continue;
entry_extract(t+i, entry+i);
@@ -182,7 +157,7 @@ static void merge_trees(struct tree_desc
if (cmp < 0)
mask = 0;
}
- mask |= 1u << i;
+ mask |= 1ul << i;
last = i;
}
if (!mask)
@@ -192,38 +167,77 @@ static void merge_trees(struct tree_desc
* Update the tree entries we've walked, and clear
* all the unused name-entries.
*/
- for (i = 0; i < 3; i++) {
- if (mask & (1u << i)) {
+ for (i = 0; i < n; i++) {
+ if (mask & (1ul << i)) {
update_tree_entry(t+i);
continue;
}
entry_clear(entry + i);
}
+ callback(n, mask, entry, base);
+ }
+ free(entry);
+}
- /* Same in both? */
- if (same_entry(entry+1, entry+2)) {
- if (entry[0].sha1) {
- resolve(base, NULL, entry+1);
- continue;
- }
+/*
+ * Merge two trees together (t[1] and t[2]), using a common base (t[0])
+ * as the origin.
+ *
+ * This walks the (sorted) trees in lock-step, checking every possible
+ * name. Note that directories automatically sort differently from other
+ * files (see "base_name_compare"), so you'll never see file/directory
+ * conflicts, because they won't ever compare the same.
+ *
+ * IOW, if a directory changes to a filename, it will automatically be
+ * seen as the directory going away, and the filename being created.
+ *
+ * Think of this as a three-way diff.
+ *
+ * The output will be either:
+ * - successful merge
+ * "0 mode sha1 filename"
+ * NOTE NOTE NOTE! FIXME! We really really need to walk the index
+ * in parallel with this too!
+ *
+ * - conflict:
+ * "1 mode sha1 filename"
+ * "2 mode sha1 filename"
+ * "3 mode sha1 filename"
+ * where not all of the 1/2/3 lines may exist, of course.
+ *
+ * The successful merge rules are the same as for the three-way merge
+ * in git-read-tree.
+ */
+static void threeway_callback(int n, unsigned long mask, struct name_entry *entry, const char *base)
+{
+ /* Same in both? */
+ if (same_entry(entry+1, entry+2)) {
+ if (entry[0].sha1) {
+ resolve(base, NULL, entry+1);
+ return;
}
+ }
- if (same_entry(entry+0, entry+1)) {
- if (entry[2].sha1 && !S_ISDIR(entry[2].mode)) {
- resolve(base, entry+1, entry+2);
- continue;
- }
+ if (same_entry(entry+0, entry+1)) {
+ if (entry[2].sha1 && !S_ISDIR(entry[2].mode)) {
+ resolve(base, entry+1, entry+2);
+ return;
}
+ }
- if (same_entry(entry+0, entry+2)) {
- if (entry[1].sha1 && !S_ISDIR(entry[1].mode)) {
- resolve(base, NULL, entry+1);
- continue;
- }
+ if (same_entry(entry+0, entry+2)) {
+ if (entry[1].sha1 && !S_ISDIR(entry[1].mode)) {
+ resolve(base, NULL, entry+1);
+ return;
}
-
- unresolved(base, entry);
}
+
+ unresolved(base, entry);
+}
+
+static void merge_trees(struct tree_desc t[3], const char *base)
+{
+ traverse_trees(3, t, base, threeway_callback);
}
static void *get_tree_descriptor(struct tree_desc *desc, const char *rev)
^ permalink raw reply related
* Re: Handling large files with GIT
From: Junio C Hamano @ 2006-02-16 3:29 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0602151915010.916@g5.osdl.org>
Linus Torvalds <torvalds@osdl.org> writes:
> Junio, that "traverse_trees()" logic is totally independent of whether we
> actually do "git-merge-tree" or not, so if you want to, I could split up
> the patches the other way (and merge "traverse_trees()" first as a new
> interface, independently).
I won't have time to look at the actual patch tonight but I am
interested. I think the general idea should work nice with both
multi-base and octopus merge cases as well ;-).
^ permalink raw reply
* Re: [PATCH] pack-objects: reuse data from existing pack.
From: Nicolas Pitre @ 2006-02-16 3:41 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Linus Torvalds, git
In-Reply-To: <7vbqx8m62q.fsf@assigned-by-dhcp.cox.net>
On Wed, 15 Feb 2006, Junio C Hamano wrote:
> When generating a new pack, notice if we have already the wanted
> object in existing packs. If the object has a delitified
> representation, and its base object is also what we are going to
> pack, then reuse the existing deltified representation
> unconditionally, bypassing all the expensive find_deltas() and
> try_deltas() routines.
>
> Also, when writing out such deltified representation and
> undeltified representation, if a matching data already exists in
> an existing pack, just write it out without uncompressing &
> recompressing.
Great !
> Without this patch:
>
> $ git-rev-list --objects v1.0.0 >RL
> $ time git-pack-objects p <RL
>
> Generating pack...
> Done counting 12233 objects.
> Packing 12233 objects....................
> 60a88b3979df41e22d1edc3967095e897f720192
>
> real 0m32.751s
> user 0m27.090s
> sys 0m2.750s
>
> With this patch:
>
> $ git-rev-list --objects v1.0.0 >RL
> $ time ../git.junio/git-pack-objects q <RL
>
> Generating pack...
> Done counting 12233 objects.
> Packing 12233 objects.....................
> 60a88b3979df41e22d1edc3967095e897f720192
> Total 12233, written 12233, reused 12177
>
> real 0m4.007s
> user 0m3.360s
> sys 0m0.090s
>
> Signed-off-by: Junio C Hamano <junkio@cox.net>
>
> ---
>
> * This may depend on one cleanup patch I have not sent out, but
> I am so excited that I could not help sending this out first.
>
> Admittedly this is hot off the press, I have not had enough
> time to beat this too hard, but the resulting pack from the
> above passed unpack-objects, index-pack and verify-pack.
In fact, the resulting pack should be identical with or without this
patch, shouldn't it?
FYI: I have list of patches to produce even smaller (yet still
compatible) packs, or less dense ones but with much reduced CPU usage.
All depending on a new --speed argument to git-pack-objects. I've been
able to produce 15-20% smaller packs with the same depth and window
size, but taking twice as much CPU time to produce. Combined with your
patch, one could repack the object store with the maximum compression
even if it is expensive CPU wise, but any pull will benefit from it
afterwards with no additional cost.
I only need to find some time to finally clean and re-test those
patches...
Nicolas
^ permalink raw reply
* Re: [PATCH] pack-objects: reuse data from existing pack.
From: Linus Torvalds @ 2006-02-16 3:55 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vbqx8m62q.fsf@assigned-by-dhcp.cox.net>
On Wed, 15 Feb 2006, Junio C Hamano wrote:
>
> When generating a new pack, notice if we have already the wanted
> object in existing packs. If the object has a delitified
> representation, and its base object is also what we are going to
> pack, then reuse the existing deltified representation
> unconditionally, bypassing all the expensive find_deltas() and
> try_deltas() routines.
I bow down before you.
No ugly special-case caching, just automatically "the right thing", with
very little overhead.
It just makes sense.
We have a winner.
Linus
^ permalink raw reply
* Re: [PATCH] pack-objects: reuse data from existing pack.
From: Junio C Hamano @ 2006-02-16 3:59 UTC (permalink / raw)
To: Nicolas Pitre; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0602152226130.5606@localhost.localdomain>
Nicolas Pitre <nico@cam.org> writes:
> On Wed, 15 Feb 2006, Junio C Hamano wrote:
>
>> Generating pack...
>> Done counting 12233 objects.
>> Packing 12233 objects.....................
>> 60a88b3979df41e22d1edc3967095e897f720192
>> Total 12233, written 12233, reused 12177
>> ...
> In fact, the resulting pack should be identical with or without this
> patch, shouldn't it?
Not necessarily. The delta-depth limitation is currently lifted
when reusing deltified objects (finding out the current depth is
not so expensive compared to uncompress-delta-recompress cycle,
but still costs somewhat, and the objective of this exercise is
to gain performance).
Notice the numbers 'written' and 'reused' in the output?
The difference in that example comes from the fact that I am
omitting some objects from the set of objects to be packed
(v1.0.0 is ancient) in a repository where some newer objects are
packed. Since packing-delta goes backwards, what is in v1.0.0
but not in my tip tends to be delitified in the original pack,
but the resulting pack needs to have them expanded -- that is
where the difference comes from.
A cleaned-up patch will be in "pu" branch tonight. I considered
putting it in "next", but decided against it. I have not spent
enough time really beating on it, although I haven't seen major
breakage.
^ permalink raw reply
* Re: git faq : draft and rfc
From: Martin Langhoff @ 2006-02-16 4:04 UTC (permalink / raw)
To: Thomas Riboulet; +Cc: git
In-Reply-To: <22e91bb0602151636r2e70e60cpa5038f4b6caccc9c@mail.gmail.com>
On 2/16/06, Thomas Riboulet <riboulet@gmail.com> wrote:
> . Can I import from cvs ?
> Yes. Use git-cvsimport. See the cvs-migration doc for more details.
>
> . Can I import from svn ?
> Yes. Use git-svnimport. See the svn-import doc for more details.
+ Can I import from arch/baz/tla? Use git-archimport.
+ Can I import from others? Maybe -- check if tailor.py can do it.
cheers,
martin
^ permalink raw reply
* Re: [PATCH] pack-objects: reuse data from existing pack.
From: Junio C Hamano @ 2006-02-16 4:07 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0602151953290.916@g5.osdl.org>
Linus Torvalds <torvalds@osdl.org> writes:
> No ugly special-case caching, just automatically "the right thing", with
> very little overhead.
>
> It just makes sense.
Thanks. I threw away two rounds of crap before this one, which
were full of ugly special cases ;-).
^ permalink raw reply
* [PATCH] topo-order: make --date-order optional.
From: Junio C Hamano @ 2006-02-16 6:18 UTC (permalink / raw)
To: Paul Mackerras; +Cc: git
In-Reply-To: <17395.58926.26670.23572@cargo.ozlabs.ibm.com>
This adds --date-order to rev-list; it is similar to topo order
in the sense that no parent comes before all of its children,
but otherwise things are still ordered in the commit timestamp
order.
The same flag is also added to show-branch.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
* Paul, this supersedes the previous one, which made topo-order
behave date-order unconditionally.
The thing is, topological ordering code has a nice property
that the equally eligible ones are pushed into a LIFO, which
keeps single strand of pearls together and as good as the
merge order for practical purposes. Doing date-order breaks
it. Since we would want both, there is a new option as you
originally wanted.
I've tested it to see that it passes the tests, but that is
not saying much ;-).
commit.c | 13 ++++++++++---
commit.h | 4 +++-
rev-list.c | 11 ++++++++++-
rev-parse.c | 1 +
show-branch.c | 9 +++++----
5 files changed, 29 insertions(+), 9 deletions(-)
4c8725f16abff4be4812d0d07a663250bef3ef0e
diff --git a/commit.c b/commit.c
index 67e11d7..c550a00 100644
--- a/commit.c
+++ b/commit.c
@@ -571,7 +571,7 @@ int count_parents(struct commit * commit
/*
* Performs an in-place topological sort on the list supplied.
*/
-void sort_in_topological_order(struct commit_list ** list)
+void sort_in_topological_order(struct commit_list ** list, int lifo)
{
struct commit_list * next = *list;
struct commit_list * work = NULL, **insert;
@@ -630,7 +630,10 @@ void sort_in_topological_order(struct co
}
next=next->next;
}
+
/* process the list in topological order */
+ if (!lifo)
+ sort_by_date(&work);
while (work) {
struct commit * work_item = pop_commit(&work);
struct sort_node * work_node = (struct sort_node *)work_item->object.util;
@@ -647,8 +650,12 @@ void sort_in_topological_order(struct co
* guaranteeing topological order.
*/
pn->indegree--;
- if (!pn->indegree)
- commit_list_insert(parent, &work);
+ if (!pn->indegree) {
+ if (!lifo)
+ insert_by_date(parent, &work);
+ else
+ commit_list_insert(parent, &work);
+ }
}
parents=parents->next;
}
diff --git a/commit.h b/commit.h
index 986b22d..70a7c75 100644
--- a/commit.h
+++ b/commit.h
@@ -72,6 +72,8 @@ int count_parents(struct commit * commit
* Post-conditions:
* invariant of resulting list is:
* a reachable from b => ord(b) < ord(a)
+ * in addition, when lifo == 0, commits on parallel tracks are
+ * sorted in the dates order.
*/
-void sort_in_topological_order(struct commit_list ** list);
+void sort_in_topological_order(struct commit_list ** list, int lifo);
#endif /* COMMIT_H */
diff --git a/rev-list.c b/rev-list.c
index 63391fc..f2d1105 100644
--- a/rev-list.c
+++ b/rev-list.c
@@ -27,6 +27,7 @@ static const char rev_list_usage[] =
" ordering output:\n"
" --merge-order [ --show-breaks ]\n"
" --topo-order\n"
+" --date-order\n"
" formatting output:\n"
" --parents\n"
" --objects\n"
@@ -56,6 +57,7 @@ static int merge_order = 0;
static int show_breaks = 0;
static int stop_traversal = 0;
static int topo_order = 0;
+static int lifo = 1;
static int no_merges = 0;
static const char **paths = NULL;
static int remove_empty_trees = 0;
@@ -856,6 +858,13 @@ int main(int argc, const char **argv)
}
if (!strcmp(arg, "--topo-order")) {
topo_order = 1;
+ lifo = 1;
+ limited = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--date-order")) {
+ topo_order = 1;
+ lifo = 0;
limited = 1;
continue;
}
@@ -940,7 +949,7 @@ int main(int argc, const char **argv)
if (limited)
list = limit_list(list);
if (topo_order)
- sort_in_topological_order(&list);
+ sort_in_topological_order(&list, lifo);
show_commit_list(list);
} else {
#ifndef NO_OPENSSL
diff --git a/rev-parse.c b/rev-parse.c
index b82f294..9161fae 100644
--- a/rev-parse.c
+++ b/rev-parse.c
@@ -48,6 +48,7 @@ static int is_rev_argument(const char *a
"--show-breaks",
"--sparse",
"--topo-order",
+ "--date-order",
"--unpacked",
NULL
};
diff --git a/show-branch.c b/show-branch.c
index 511fd3b..5a86ae2 100644
--- a/show-branch.c
+++ b/show-branch.c
@@ -535,6 +535,7 @@ int main(int ac, char **av)
int num_rev, i, extra = 0;
int all_heads = 0, all_tags = 0;
int all_mask, all_revs;
+ int lifo = 1;
char head_path[128];
const char *head_path_p;
int head_path_len;
@@ -544,7 +545,6 @@ int main(int ac, char **av)
int no_name = 0;
int sha1_name = 0;
int shown_merge_point = 0;
- int topo_order = 0;
int with_current_branch = 0;
int head_at = -1;
@@ -586,7 +586,9 @@ int main(int ac, char **av)
else if (!strcmp(arg, "--independent"))
independent = 1;
else if (!strcmp(arg, "--topo-order"))
- topo_order = 1;
+ lifo = 1;
+ else if (!strcmp(arg, "--date-order"))
+ lifo = 0;
else
usage(show_branch_usage);
ac--; av++;
@@ -710,8 +712,7 @@ int main(int ac, char **av)
exit(0);
/* Sort topologically */
- if (topo_order)
- sort_in_topological_order(&seen);
+ sort_in_topological_order(&seen, lifo);
/* Give names to commits */
if (!sha1_name && !no_name)
--
1.2.1.gbf0a
^ permalink raw reply related
* [ANNOUNCE] GIT 1.2.1
From: Junio C Hamano @ 2006-02-16 6:25 UTC (permalink / raw)
To: git; +Cc: linux-kernel
The latest maintenance release GIT 1.2.1 is available at the
usual places:
http://www.kernel.org/pub/software/scm/git/
git-1.2.1.tar.{gz,bz2} (tarball)
RPMS/$arch/git-*-1.2.1-1.$arch.rpm (RPM)
Nothing earth-shattering but cleanups and cleanups and cleanups.
All the interesting things are happening in "master" and "pu",
which will be a topic for a separate message.
----------------------------------------------------------------
Changes since v1.2.0 are as follows:
Fernando J. Pereda:
Print an error if cloning a http repo and NO_CURL is set
Fredrik Kuivinen:
s/SHELL/SHELL_PATH/ in Makefile
Josef Weidendorfer:
More useful/hinting error messages in git-checkout
Junio C Hamano:
Documentation: git-commit in 1.2.X series defaults to --include.
Documentation: git-ls-files asciidocco.
bisect: remove BISECT_NAMES after done.
combine-diff: diff-files fix.
combine-diff: diff-files fix (#2)
checkout: fix dirty-file display.
^ permalink raw reply
* RE: [ANNOUNCE] GIT 1.2.1
From: Brown, Len @ 2006-02-16 6:47 UTC (permalink / raw)
To: Junio C Hamano, git; +Cc: linux-kernel
Happy to notice Documentation/git-send-email
to standardize greg's scripts, but don't see it in the release.
anybody using it?
-Len
^ permalink raw reply
* What's in git.git
From: Junio C Hamano @ 2006-02-16 6:57 UTC (permalink / raw)
To: git
* Master branch has these since 1.2.1 maintenance release.
- documentation fixes:
git-commit: Now --only semantics is the default.
- usability:
- rebase aquired a hook to refuse rebasing.
- commit and add detects misspelled pathspec while making a partial commit.
- git-svnimport: -r adds svn revision number to commit messages
- properly git-bisect reset after bisecting from non-master head
- send-email: Add some options for controlling how addresses
are automatically added to the cc: list.
- send-email: Add --cc
* Next branch has these, that are not in master. If you feel
you would benefit from these, testing and feedback is greatly
appreciated.
- "Assume unchanged git" series (7 commits):
This was done in response to people on filesystems with slow
lstat(2). I do not have such an environment, so I cannot say
I tested it that much.
- "Rebase to different branch" (1 commit):
This was previously discussed on the list. With this command
line:
$ git rebase --onto master~1 master topic
would rebase this ancestry graph to:
A---B---C topic
/
D---E---F---G master
another graph that looks like this:
A'--B'--C' topic
/
D---E---F---G master
Earlier, you couldn't rebase to anywhere other than on top of
"the other branch".
* Proposed updates "pu" branch has these, not in "next". Some
of them are of iffy nature, and without further work will not
go anywhere.
- "merge-tree" series by Linus (2 commits).
I haven't spent enough time looking at and thinking about
this yet.
- "reuse pack data" (1 commit).
I still haven't seen data corruption with this one, which is
a good sign, but would like to keep beating it privately for
a while. Perhaps will graduate to "next" by next week.
- "bind commit" series (6 commits).
I think the core-side is more or less done with this one.
Anybody interested in doing Porcelain side?
- "shallow clone" series (1 commit).
I should drop this one for now and perhaps when enough people
are interested reopen the issue.
^ permalink raw reply
* Re: Make "git clone" less of a deathly quiet experience
From: Eric W. Biederman @ 2006-02-16 6:56 UTC (permalink / raw)
To: Andreas Ericsson
Cc: Keith Packard, Linus Torvalds, Junio C Hamano, Git Mailing List,
Petr Baudis
In-Reply-To: <43EF15D1.1050609@op5.se>
Andreas Ericsson <ae@op5.se> writes:
> Keith Packard wrote:
>> On Sun, 2006-02-12 at 04:43 +0100, Andreas Ericsson wrote:
>>
>>>A weird oddity; Cloning is faster over rsync, day-to-day pulling is not.
>> Precisely. If the protocol could deliver existing packs instead of
>> unpacking and repacking them, then git would be as fast as rsync and I
>> wouldn't have to worry about supporting two protocols.
>>
>
> Caching features have been discussed, but that means the daemon needs to have
> write-access to some directory within the repository. It would also work poorly
> for projects that see very rapid development unless the cached pack-files can be
> amended to. A sort of "create packs on demand". It shouldn't be too difficult,
> really.
Actually for the clone case we don't need a writable directory for the
git-daemon.
If we assume that a repository up for download is reasonably packed,
we can just lob all of the packs in the current repository, and then
pack the few remaining objects and send them.
I don't know how well multiple packs will work with the current git
protocol but it should be pretty natural, and the clone case is easy
detect as there are no heads in common. Can that be detected quickly?
I don't have a patch but it feels like a pretty straight forward thing
to implement.
Eric
^ permalink raw reply
* Re: Make "git clone" less of a deathly quiet experience
From: Junio C Hamano @ 2006-02-16 7:33 UTC (permalink / raw)
To: Eric W. Biederman
Cc: Andreas Ericsson, Keith Packard, Linus Torvalds, Git Mailing List,
Petr Baudis
In-Reply-To: <m1ek23rduh.fsf@ebiederm.dsl.xmission.com>
ebiederm@xmission.com (Eric W. Biederman) writes:
> I don't know how well multiple packs will work with the current git
> protocol...
Then I wonder why you are making this observation ... ;-)
In any case, I suspect this would be helped to a certain degree
by the pack-object that reuses delta data from existing packs,
if your repository is reasonably packed.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox