From: Junio C Hamano <hidden> Date: 2016-06-15 22:44:36
Nicolas Pitre [off-list ref] writes:
Let's see what happens here even before any packing is attempted
|$ git rev-list --objects 492c2e4..9404ef0
|362
|
|$ git rev-list --objects --all \
| --unpacked=pack-6a3438b2702be06697023d80b77e67a73a0b0b5c.pack |
| wc -l
|26559
So this --unpacked= argument (which undocumented semantics I still have
issues with) is certainly not doing what is expected.
The output from rev-list is not surprising. --unpacked=$this.pack implies
the usual --unpacked behaviour (i.e. only show unpacked objects by not
traversing into commits that are packed) and at the same time pretends
that objects in $this.pack are loose.
It was meant to be used for a partial incremental repacking. If you have
a pack to be kept (perhaps a highly packed deep pack that holds the
earlier parts of the history), marked with .keep, and a handful young
packs, you would give these young ones with --unpacked, so that the
resulting single pack contains all that are loose or in these young
packs. After that, you can remove all the young packs and loose objects.
At least that is the idea.
I am not sure where that rev-list experiment you showed fits in the bigger
picture, but if that is used for repacking the young packs, perhaps the
issue is that after the repacking the code forgets to remove the young
ones whose objects are now moved into the new pack?
Junio C Hamano writes:
> The output from rev-list is not surprising. --unpacked=$this.pack implies
> the usual --unpacked behaviour (i.e. only show unpacked objects by not
> traversing into commits that are packed)
The problem is unconditional traversing into commits that are
unpacked. This behavior is immediately obvious if the packed blob in
the .keep pack is large. I've been using the following since the large
object discussion with Dana, but it might be completely broken (though
the test case is probably correct).
--
Previously --unpacked would filter on the commit level, ignoring whether the
objects comprising the commit actually were packed or unpacked.
This makes it impossible to store e.g. excessively large blobs in
different packs from the commits referencing them, since the next repack of
such a commit will suck all referenced blobs into the same pack.
This change moves the unpacked check to the output stage and no longer checks
the flag during commit traversal and adds a trivial test demonstrating the
problem.
---
Note that t6009 is already taken, so it might be better to merge the test
into one of the other rev-list tests.
list-objects.c | 6 ++++--
revision.c | 2 --
t/t6009-rev-list-unpacked.sh | 32 ++++++++++++++++++++++++++++++++
3 files changed, 36 insertions(+), 4 deletions(-)
create mode 100644 t/t6009-rev-list-unpacked.sh
@@ -0,0 +1,32 @@+#!/bin/sh++test_description='test git rev-list --unpacked --objects'++../test-lib.sh++# Create an unpacked commit that references a packed object.++test_expect_successsetup'+echoHallo>foo&&+gitaddfoo&&+test_tick&&+gitcommit-m"A"&&+gitgc&&+echoCello>bar&&+gitaddbar&&+test_tick&&+gitcommit-m"B"+'++test_expect_success\+'object list should contain foo''+gitrev-list--all--objects|grep-q"foo"+'++test_expect_success\+'unpacked object list should not contain foo''+test_must_fail"git rev-list --all --unpacked --objects | grep -q \"foo\""+'+++test_done
From: Nicolas Pitre <hidden> Date: 2016-06-15 22:44:36
On Wed, 14 May 2008, Juergen Ruehle wrote:
Junio C Hamano writes:
> The output from rev-list is not surprising. --unpacked=$this.pack implies
> the usual --unpacked behaviour (i.e. only show unpacked objects by not
> traversing into commits that are packed)
The problem is unconditional traversing into commits that are
unpacked. This behavior is immediately obvious if the packed blob in
the .keep pack is large.
That's what I was suspecting too. And because the Linux repo contains
many files, then a single commit will fetch a large bunch of objects
indeed.
I've been using the following since the large
object discussion with Dana, but it might be completely broken (though
the test case is probably correct).
This is not some part of git code I'm familiar with, so I can't tell if
the patch is broken or not. What I can do is repeat my simple test
which produces the following results with your patch:
|$ git rev-list --objects 492c2e4..9404ef0
|362
|
|$ git rev-list --objects --all \
| --unpacked=pack-6a3438b2702be06697023d80b77e67a73a0b0b5c.pack |
| wc -l
|362
That's exactly what is expected.
Nicolas
Previously --unpacked would filter on the commit level, ignoring whether the
objects comprising the commit actually were packed or unpacked.
I think this patch is correct, but I wonder why you removed the pruning
from revision.c? Why do we want to process trees for commits that aren't
going to be shown? This is going to slow down things a lot, and we've long
had the rule that commits have to be complete in the packs that are kept
(ie you should never have a pack-file that points to an unpacked object).
So I'd suggest a slightly less intrusive patch (untested!!) instead, which
leaves the commit object logic alone.
(Your test-case should obviously be merged regardless)
Linus
---
list-objects.c | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)
I think this patch is correct, but I wonder why you removed the pruning
from revision.c?
In fact, it might be a good idea to not just keep it in revision.c, but
move it up a bit, so that a commit that is packed and should be ignored
won't even have its parents put on the list (which means that we not only
ignore the trees in that commit, but also all parents).
Of course, the more aggressively we prune, the more we end up having to
depend on the fact that a commit that is in a pack that is marked "keep"
must *always* have everything that leads to it in that pack or others also
marked "keep". We effectively have that already (because we've always
pruned away the commits early), but it's a thing to keep in mind whenever
we prune even more aggressively.
Linus
From: Nicolas Pitre <hidden> Date: 2016-06-15 22:44:36
On Wed, 14 May 2008, Linus Torvalds wrote:
Of course, the more aggressively we prune, the more we end up having to
depend on the fact that a commit that is in a pack that is marked "keep"
must *always* have everything that leads to it in that pack or others also
marked "keep". We effectively have that already (because we've always
pruned away the commits early), but it's a thing to keep in mind whenever
we prune even more aggressively.
I wonder if this is a good thing. Such a rule would effectively put
restrictions on how objects like big blobs could be distributed amongst
many .keep packs. I just wish we're not painting ourselves in a corner.
Nicolas
Of course, the more aggressively we prune, the more we end up having to
depend on the fact that a commit that is in a pack that is marked "keep"
must *always* have everything that leads to it in that pack or others also
marked "keep". We effectively have that already (because we've always
pruned away the commits early), but it's a thing to keep in mind whenever
we prune even more aggressively.
I wonder if this is a good thing. Such a rule would effectively put
restrictions on how objects like big blobs could be distributed amongst
many .keep packs. I just wish we're not painting ourselves in a corner.
You can distribute big objects arbitrarily among many .keep packs, but
what you can *NOT* do (and which has _always_ been a bug to do) is to have
a *.keep pack that refers to objects that are not in a .keep pack!
So keep<->keep you can do anything you want, and distribute objects any
way.
But a keep pack must only refer to objects in itself or in other keep
packs.
Because otherwise, if we ever hit an object in a keep pack, we'll stop
even looking further when we use --unpacked. And that has always been true
(admittedly only for "commit" objects, but those are the ones that most
commonly refer to other objects, so ..)
Linus
From: A Large Angry SCM <hidden> Date: 2016-06-15 22:44:36
Linus Torvalds wrote:
On Wed, 14 May 2008, Nicolas Pitre wrote:
quoted
On Wed, 14 May 2008, Linus Torvalds wrote:
quoted
Of course, the more aggressively we prune, the more we end up having to
depend on the fact that a commit that is in a pack that is marked "keep"
must *always* have everything that leads to it in that pack or others also
marked "keep". We effectively have that already (because we've always
pruned away the commits early), but it's a thing to keep in mind whenever
we prune even more aggressively.
I wonder if this is a good thing. Such a rule would effectively put
restrictions on how objects like big blobs could be distributed amongst
many .keep packs. I just wish we're not painting ourselves in a corner.
You can distribute big objects arbitrarily among many .keep packs, but
what you can *NOT* do (and which has _always_ been a bug to do) is to have
a *.keep pack that refers to objects that are not in a .keep pack!
So keep<->keep you can do anything you want, and distribute objects any
way.
But a keep pack must only refer to objects in itself or in other keep
packs.
Because otherwise, if we ever hit an object in a keep pack, we'll stop
even looking further when we use --unpacked. And that has always been true
(admittedly only for "commit" objects, but those are the ones that most
commonly refer to other objects, so ..)
Sounds like git-fsck needs to start checking for this.