Git development
 help / color / mirror / Atom feed
* Re: Change set based shallow clone
From: A Large Angry SCM @ 2006-09-08 17:18 UTC (permalink / raw)
  To: Martin Langhoff; +Cc: Junio C Hamano, Jon Smirl, git
In-Reply-To: <46a038f90609080015u56daae78u9d78584edae7fb72@mail.gmail.com>

Martin Langhoff wrote:
> On 9/8/06, Junio C Hamano <junkio@cox.net> wrote:
...
>> [*4*] In git, there is no inherent server vs client or upstream
>> vs downstream relationship between repositories.
> 
> Here an importaant distiction must be made. A "publishing" repo cannot
> be sparse. A sparse repo probably cannot be cloned from.

With the use of "placeholder" objects; neither one of these assertions
is true.

^ permalink raw reply

* git -1.4.1.1 bisect enhancement:show steps too instead only the number of revisions
From: Toralf Förster @ 2006-09-08 17:09 UTC (permalink / raw)
  To: git

[-- Attachment #1: Type: text/plain, Size: 328 bytes --]

What about telling the user/tester the number of (possible) reboots too and not only the amount of revisions, eg instead:
"3308 revisions left to test after this"
print a line like
"3308 revisions (~ 12 steps) left to test after this"

b/c ld 3308 = 12 steps until finish, isn't it ?

-- 
MfG/Sincerely
Toralf Förster

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: Change set based shallow clone
From: Jakub Narebski @ 2006-09-08 15:50 UTC (permalink / raw)
  To: git
In-Reply-To: <9e4733910609080720s7a143d9bp5a1dd36869967c22@mail.gmail.com>

My idea for lazy clone/fetch (lazy = on-demand) is via remote alternatives
mechanism. We put URI for repository (repositories) that hosts the project,
and we would need at start to download at least heads and tags, and only
heads and tags.

When there is request for an object (commit, tree, blob or tag) which we
don't have locally, we ask remote repository if it have it, and download it
(and perhaps some related objects); this needs extension I guess for the
git downloader ('wantonly'), it should be fairly easy for dumb downloaders
if you don't mind getting whole pack i.e. perhaps more than intended.
Perhaps 'wantonly' for git protocol should work the same: one would get
ready pack (perhaps with limit on pack size: otherwise one would get only
the requested objects).

One thing that needs extending for lazy clone is git-fsck... otherwise you
would get whole repository when calling git-fsck. Simplest would be
fsck-ing only the local part, perhaps checking if the "missing" objects are
present in remote repository, but not downloading them and not checking
connectivity further... and of course notifying user that this is lazy
clone. Unless we run git-fsck-objects on the remote side, then pass results
to the local side.

There is probably bunch of problems with this idea...
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply

* Re: Change set based shallow clone
From: Jon Smirl @ 2006-09-08 14:20 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Martin Langhoff, git
In-Reply-To: <7vac5ancvo.fsf@assigned-by-dhcp.cox.net>

On 9/8/06, Junio C Hamano <junkio@cox.net> wrote:
> [*4*] In git, there is no inherent server vs client or upstream
> vs downstream relationship between repositories.  You may be
> even fetching from many people and do not have a set upstream at
> all.  Or you are _the_ upstream, and your notebook has the
> latest devevelopment history, and after pushing that latest
> history to your mothership repository, you may decide you do not
> want ancient development history on a puny notebook, and locally
> cauterize the history on your notebook repository and prune
> ancient stuff.  The objects missing from the notebook repository
> are retrievable from your mothership repository again if/when
> needed and you as the user would know that (and if you are lucky
> you may even remember that a few months later), but git doesn't,
> and there is no reason for git to want to know it.  If we want
> to do "fault-in on demand", we need to add a way to say "it is
> Ok for this repository to be incomplete -- objects that are
> missing must be completed from that repository (or those
> repositories)".  But that's quite a special case of having a
> fixed upstream.

A 'not-present' object would be a normal git object, it would contain
a list of sha1s that it is stubbing for. These alias sha1s need to end
up somewhere where the git tools can find them. Maybe put all of the
'not-present' objects into their own pack and add the aliases to the
index. If the aliases point back the 'not-present' object everything
can be validated even if the alias sha1s don't match the one of the
object. This pack would be private and not sent to other repositories.

It would be useful to maintain a list of possible remote repositories
to search for the missing objects if needed. This list could be shared
with people that clone from you.

If you clone from a remote repository that is a partial copy you may
not be able to get all of the objects you want. The only choice here
is to point them to 'not-present' stub and try searching the
alternative repository list.

If you really want to build something for the future, have all of the
git repositories on the net talk to each other and use a distributed
hash scheme to spread redundant copies of the objects out over the
cloud of servers. This will have the effect of creating a global
namespace for all git projects.

-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply

* Re: Very complex rebasing - Need help
From: Jakub Narebski @ 2006-09-08 13:43 UTC (permalink / raw)
  To: git
In-Reply-To: <6208897.post@talk.nabble.com>

Jehreg wrote:

> In the Buildroot repo:
> initial--o--o--ID3--o--o--ID4--o--master
>                   \
>                    --o--o--o--o--o--o--o--o--myproject
> 
> My problem is that I need to kinda-rebase the ID4 into the myproject
branch
> to make it finally look like this:
> 
> initial--o--o--ID3--o--o--ID4--o--master
>                   \               \
>                    --o--o--o--o--o--x--o--o--myproject
> 
> 
> Any ideas ?

Grafts? Grafting additional parent to commit x.

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply

* Very complex rebasing - Need help
From: Jehreg @ 2006-09-08 13:27 UTC (permalink / raw)
  To: git


So, I grabbed a tarball of the Buildroot project a year ago and started a git
repo, and created a branch and did changes:

initial---master
              \
                --o--o--o--o--myproject

A few months later, I grabbed another Buildroot tarball and I diffed it from
my master and applied it to master.

initial--o--(new tarball)--master
          \
           --o--o--o--o--myproject

Which I then merged into myproject and did some additional development.

initial--o--(new tarball)--o--master
          \                      \
           --o--o--o--o--o----o--o--o--o--myproject

My problem is that I would like to bring in the svn-into-git repo of the
Buildroot project.

initial--ID1--(new tarball)--ID2--master
          \                          \
           --o--o--o--o--o-----o--o--o--o--myproject
other repo of the Buildroot project:
initial--o--o--ID3--o--o--ID4--o--master

So, I can actually match ID1=ID3 and ID2= ID4.

I can use rebase to do this:

In the Buildroot repo:
initial--o--o--ID3--o--o--ID4--o--master
                  \
                   --o--o--o--o--o--o--o--o--myproject

My problem is that I need to kinda-rebase the ID4 into the myproject branch
to make it finally look like this:

initial--o--o--ID3--o--o--ID4--o--master
                  \               \
                   --o--o--o--o--o--o--o--o--myproject


Any ideas ?

-- 
View this message in context: http://www.nabble.com/Very-complex-rebasing---Need-help-tf2239083.html#a6208897
Sent from the git forum at Nabble.com.

^ permalink raw reply

* Re: Some issues with current qgit on exit
From: Pavel Roskin @ 2006-09-08 11:32 UTC (permalink / raw)
  To: Marco Costalba; +Cc: git
In-Reply-To: <e5bfff550609061028y25aeb928i2c49d4a5d1be7a60@mail.gmail.com>

Hi, Marco!

On Wed, 2006-09-06 at 19:28 +0200, Marco Costalba wrote:

> Thanks for the very good bug reports. I have just  pushed the fix: it
> was a bogus delayed delete on exit the origin of this issues.

You never cease to amaze me by your quick (and hopefully correct) fixes.

> I was planning (well, still I am) to release new version this week
> end, and your bug report is arrived just in time ;-)

I tried to push qgit a bit harder, and it's still easy to crash:

Run qgit
Select a patch and an affected file in the file pane
Press Ctrl-A to open a tab for that file
Press Ctrl-Shift-A and hold it for some time to open more tabs
Close qgit before all tabs load

Two things can happen.  Either glibc detects double free or it doesn't.

Output in the case when double free is not detected:

Thrown exception 'Closing file viewer'
ASSERT in remove: 22228848 is not the first in list
Exception 'Closing file viewer' not handled in file viewer...re-throw
ASSERT in remove: 15 is not the first in list
Exception 'Closing file viewer' not handled in file viewer...re-throw
ASSERT in remove: 14 is not the first in list
Exception 'Closing file viewer' not handled in file viewer...re-throw
ASSERT in remove: 13449472 is not the first in list
Exception 'Closing file viewer' not handled in file viewer...re-throw
ASSERT in remove: 18662832 is not the first in list
Exception 'Closing file viewer' not handled in file viewer...re-throw
ASSERT in remove: 15427120 is not the first in list
Exception 'Closing file viewer' not handled in file viewer...re-throw
ASSERT in remove: 10 is not the first in list
Exception 'Closing file viewer' not handled in file viewer...re-throw
ASSERT in remove: 9 is not the first in list
Exception 'Closing file viewer' not handled in file viewer...re-throw
ASSERT in remove: 8 is not the first in list
Exception 'Closing file viewer' not handled in file viewer...re-throw
terminate called after throwing an instance of 'int'
Aborted (core dumped)


Output in the case if double free is detected, filtered through c++filt
(I have no idea how to make the glibc stack trace show qgit symbols)

Thrown exception 'Closing file viewer'
Catched exception 'Closing file viewer' while in updating file viewer
*** glibc detected *** ./qgit: double free or corruption (out): 0x00007fff47d997a0 ***
======= Backtrace: =========
/lib64/libc.so.6[0x2b8863438b00]
/lib64/libc.so.6(cfree+0x8c)[0x2b886343c27c]
./qgit[0x499138]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QWidget::~QWidget()+0x152)[0x372399a6a2]
./qgit[0x4b3416]
./qgit[0x497ea1]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QObject::event(QEvent*)+0x79)[0x3723960089]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QWidget::event(QEvent*)+0x28)[0x3723997af8]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QMainWindow::event(QEvent*)+0x25)[0x3723a554b5]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QApplication::internalNotify(QObject*, QEvent*)+0x85)[0x37238ffda5]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QApplication::notify(QObject*, QEvent*)+0xa4)[0x3723901274]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QApplication::sendPostedEvents(QObject*, int)+0x179)[0x3723900da9]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QEventLoop::processEvents(unsigned int)+0x3fa)[0x37238af11a]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QEventLoop::processEvents(unsigned int, int)+0x48)[0x37239174f8]
./qgit[0x47751a]
./qgit[0x444e21]
./qgit[0x449f7f]
./qgit[0x44a159]
./qgit[0x43ae3a]
./qgit[0x440715]
./qgit[0x435291]
./qgit[0x435448]
./qgit[0x43f4a6]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QObject::event(QEvent*)+0x96)[0x37239600a6]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QApplication::internalNotify(QObject*, QEvent*)+0x85)[0x37238ffda5]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QApplication::notify(QObject*, QEvent*)+0xa4)[0x3723901274]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QApplication::sendPostedEvents(QObject*, int)+0x179)[0x3723900da9]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QEventLoop::processEvents(unsigned int)+0x3fa)[0x37238af11a]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QEventLoop::processEvents(unsigned int, int)+0x48)[0x37239174f8]
./qgit[0x47751a]
./qgit[0x444e21]
./qgit[0x449f7f]
./qgit[0x44a159]
./qgit[0x43ae3a]
./qgit[0x440715]
./qgit[0x435291]
./qgit[0x435448]
./qgit[0x43f4a6]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QObject::event(QEvent*)+0x96)[0x37239600a6]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QApplication::internalNotify(QObject*, QEvent*)+0x85)[0x37238ffda5]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QApplication::notify(QObject*, QEvent*)+0xa4)[0x3723901274]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QApplication::sendPostedEvents(QObject*, int)+0x179)[0x3723900da9]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QEventLoop::processEvents(unsigned int)+0x3fa)[0x37238af11a]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QEventLoop::processEvents(unsigned int, int)+0x48)[0x37239174f8]
./qgit[0x47751a]
./qgit[0x444e21]
./qgit[0x449f7f]
./qgit[0x44a159]
./qgit[0x43ae3a]
./qgit[0x440715]
./qgit[0x435291]
./qgit[0x435448]
./qgit[0x43f4a6]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QObject::event(QEvent*)+0x96)[0x37239600a6]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QApplication::internalNotify(QObject*, QEvent*)+0x85)[0x37238ffda5]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QApplication::notify(QObject*, QEvent*)+0xa4)[0x3723901274]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QApplication::sendPostedEvents(QObject*, int)+0x179)[0x3723900da9]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QEventLoop::processEvents(unsigned int)+0x3fa)[0x37238af11a]
/usr/lib64/qt-3.3/lib/libqt-mt.so.3(QEventLoop::processEvents(unsigned int, int)+0x48)[0x37239174f8]
./qgit[0x47751a]
./qgit[0x444e21]
./qgit[0x449f7f]
./qgit[0x44a159]
======= Memory map: ========
00400000-00526000 r-xp 00000000 08:08 1523903                            /usr/local/src/qgit/src/qgit
00726000-00729000 rw-p 00126000 08:08 1523903                            /usr/local/src/qgit/src/qgit
00729000-03635000 rw-p 00729000 00:00 0                                  [heap]
371ca00000-371ca17000 r-xp 00000000 08:01 4836913                        /usr/lib64/libart_lgpl_2.so.2.3.17
371ca17000-371cc16000 ---p 00017000 08:01 4836913                        /usr/lib64/libart_lgpl_2.so.2.3.17
371cc16000-371cc17000 rw-p 00016000 08:01 4836913                        /usr/lib64/libart_lgpl_2.so.2.3.17
371ce00000-371ce30000 r-xp 00000000 08:01 4848834                        /usr/lib64/liblcms.so.1.0.15
371ce30000-371d030000 ---p 00030000 08:01 4848834                        /usr/lib64/liblcms.so.1.0.15
371d030000-371d032000 rw-p 00030000 08:01 4848834                        /usr/lib64/liblcms.so.1.0.15
371d032000-371d034000 rw-p 371d032000 00:00 0 
371d200000-371d213000 r-xp 00000000 08:01 4850552                        /usr/lib64/libXft.so.2.1.2
371d213000-371d412000 ---p 00013000 08:01 4850552                        /usr/lib64/libXft.so.2.1.2
371d412000-371d413000 rw-p 00012000 08:01 4850552                        /usr/lib64/libXft.so.2.1.2
371e600000-371e614000 r-xp 00000000 08:01 4843230                        /usr/lib64/libz.so.1.2.3
371e614000-371e813000 ---p 00014000 08:01 4843230                        /usr/lib64/libz.so.1.2.3
371e813000-371e814000 rw-p 00013000 08:01 4843230                        /usr/lib64/libz.so.1.2.3
371ea00000-371ea05000 r-xp 00000000 08:01 4844451                        /usr/lib64/libXdmcp.so.6.0.0
371ea05000-371ec04000 ---p 00005000 08:01 4844451                        /usr/lib64/libXdmcp.so.6.0.0
371ec04000-371ec05000 rw-p 00004000 08:01 4844451                        /usr/lib64/libXdmcp.so.6.0.0
371ee00000-371ee02000 r-xp 00000000 08:01 4842899                        /usr/lib64/libXau.so.6.0.0
371ee02000-371f001000 ---p 00002000 08:01 4842899                        /usr/lib64/libXau.so.6.0.0
371f001000-371f002000 rw-p 00001000 08:01 4842899                        /usr/lib64/libXau.so.6.0.0
371f200000-371f304000 r-xp 00000000 08:01 4845440                        /usr/lib64/libX11.so.6.2.0
371f304000-371f504000 ---p 00104000 08:01 4845440                        /usr/lib64/libX11.so.6.2.0
371f504000-371f50b000 rw-p 00104000 08:01 4845440                        /usr/lib64/libX11.so.6.2.0
371f600000-371f610000 r-xp 00000000 08:01 4848836                        /usr/lib64/libXext.so.6.4.0
371f610000-371f810000 ---p 00010000 08:01 4848836                        /usr/lib64/libXext.so.6.4.0
371f810000-371f811000 rw-p 00010000 08:01 4848836                        /usr/lib64/libXext.so.6.4.0
371fa00000-371fa20000 r-xp 00000000 08:01 3790170                        /lib64/libexpat.so.0.5.0
371fa20000-371fc1f000 ---p 00020000 08:01 3790170                        /lib64/libexpat.so.0.5.0
371fc1f000-371fc22000 rw-p 0001f000 08:01 3790170                        /lib64/libexpat.so.0.5.0
3720200000-3720209000 r-xp 00000000 08:01 4848835                        /usr/lib64/libXrender.so.1.3.0
3720209000-3720408000 ---p 00009000 08:01 4848835                        /usr/lib64/libXrender.so.1.3.0
3720408000-3720409000 rw-p 00008000 08:01 4848835                        /usr/lib64/libXrender.so.1.3.0
3720600000-372063c000 r-xp 00000000 08:01 4850470                        /usr/lib64/libfontconfig.so.1.0.4
372063c000-372083c000 ---p 0003c000 08:01 4850470                        /usr/lib64/libfontconfig.so.1.0.4
372083c000-3720841000 rw-p 0003c000 08:01 4850470                        /usr/lib64/libfontconfig.so.1.0.4
3720841000-3720844000 rw-p 3720841000 00:00 0 
3720a00000-3720a23000 r-xp 00000000 08:01 4841936                        /usr/lib64/libpng12.so.0.10.0
3720a23000-3720c23000 ---p 00023000 08:01 4841936                        /usr/lib64/libpng12.so.0.10.0
3720c23000-3720c24000 rw-p 00023000 08:01 4841936                        /usr/lib64/libpng12.so.0.10.0
3720e00000-3720e02000 r-xp 00000000 08:01 4850036                        /usr/lib64/libXinerama.so.1.0.0
3720e02000-3721001000 ---p 00002000 08:01 4850036                        /usr/lib64/libXinerama.so.1.0.0
3721001000-3721002000 rw-p 00001000 08:01 4850036                        /usr/lib64/libXinerama.so.1.0.0
3721200000-3721203000 r-xp 00000000 08:01 4848837                        /usr/lib64/libXrandr.so.2.0.0
3721203000-3721402000 ---p 00003000 08:01 4848837                        /usr/lib64/libXrandr.so.2.0.0
3721402000-3721403000 rw-p 00002000 08:01 4848837                        /usr/lib64/libXrandr.so.2.0.0
3721600000-372160a000 r-xp 00000000 08:01 4849031                        /usr/lib64/libXcursor.so.1.0.2
372160a000-3721809000 ---p 0000a000 08:01 4849031                        /usr/lib64/libXcursor.so.1.0.2
3721809000-372180a000 rw-p 00009000 08:01 4849031                        /usr/lib64/libXcursor.so.1.0.2
3721a00000-3721a05000 r-xp 00000000 08:01 4848838                        /usr/lib64/libXfixes.so.3.1.0
3721a05000-3721c04000 ---p 00005000 08:01 4848838                        /usr/lib64/libXfixes.so.3.1.0
3721c04000-3721c05000 rw-p 00004000 08:01 4848838                        /usr/lib64/libXfixes.so.3.1.0
3721e00000-3721e31000 r-xp 00000000 08:01 4851247 Aborted (core dumped)


As always, it's Fedora development on x86_64.

-- 
Regards,
Pavel Roskin

^ permalink raw reply

* gitweb: Add committags support
From: Jakub Narebski @ 2006-09-08 10:46 UTC (permalink / raw)
  To: git

Below is very preliminary code (think early alpha) 
to add committags support (a la gitweb-xmms2) to gitweb.

One of the problems is having committags support 
in the subject/title line, which is hyperlink itself 
(with title and class attribute).

-- >8 --
our %committags = (
	'commitsha' => {
		'pattern' => qr/[0-9a-fA-F]{40}/,
		'sub' => sub {
			my $hash_text = shift;
			if (git_get_type($hash_text) eq "commit") {
				return
					$cgi->a({-href => href(action=>"commit", hash=>$hash_text),
					        -class => "text"}, $hash_text);
			}
			return undef;
		},
		'islink' => 1,
	},
	'mantis' => {
		'pattern' => qr/(BUG|FEATURE)\(\d+\)/,
		'options' => [ 'http://bugs.xmms2.xmms.se/view.php?id=' ],
		'sub' => sub {
			my $match = shift;
			my $URL = shift;
			my ($issue) = $match =~ /(\d+)/;
			return
				$cgi->a({-href => "$URL$issue"},
				        $match);
		},
		'islink' => 1,
	},
);

sub format_log_line_html_generic {
	my $line = shift;
	my $a_attr = shift;
	my @committags = @_;
	my %subst;

	$line = esc_html($line);
	$line =~ s/ /&nbsp;/g;
	
	for my $ctname (@committags) {
		next unless exists $committags{$ctname};
		my $wrap = ref($a_attr) eq "HASH" && %$a_attr &&
			$committags{$ctname}{'islink'};
		my @opts =
			exists $committags{$ctname}{'options'} ?
			@{$committags{$ctname}{'options'}} :
			();

		while ($line =~ m/($committags{$ctname}{'pattern'})/gc) {
			my $match = $1;
			my $repl = $committags{$ctname}{'sub'}->($match, @opts);
			next unless $repl;

			if ($wrap) {
				$repl = $cgi->end_a() . $repl . $cgi->start_a($a_attr);
			}

			$subst{quotemeta $match} = $repl;
		}
	}

	while (my ($from, $to) = each %subst) {
		$line =~ s/$from/$to/g;
	}
	return $line;
}



foreach my $line (@log) {
	print format_log_line_html_generic($line, undef, keys %committags) . "<br/>\n";
#	print format_log_line_html_generic($line, {-href=>"href", -title => "TITEL"}, keys %committags) . "<br/>\n";
}

-- 
Jakub Narebski
Poland

^ permalink raw reply

* Re: Add git-archive [take #2]
From: Franck Bui-Huu @ 2006-09-08  9:43 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Franck, git
In-Reply-To: <7v64fyivk0.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:
> 
> I do not think I removed upload-tar.  I removed it from daemon
> service list and the documentation for daemon, because that part
> is a new code.
> 
> 	git tar-tree --remote=../linux-2.6/.git HEAD
> 	git tar-tree --remote=kernel.org:git next
> 
> should still work; the former is "from a directory next door"
> and connect.c invokes local /bin/sh as the transport, and the
> latter is "ssh login to kernel.org and use ./git directory".
> 

Sorry I was speaking about the git protocol. It has been included
in master branch. But

	git tar-tree --remote=git://anything/repo.git

does not work anymore, does it ? Do you plan to make it work again
with git-upload-archive (that would need some modifications in
git-tar-tree --remote code) or just let the --remote option work
for local and ssh transport (that would be one good reason for using
for git-archive instead of git-tar-tree) ?

> I recall from earlier review of your code, "git archive" should
> work well over these two transports in addition to git://
> protocol that talks with git-daemon.
> 
yes
		Franck

^ permalink raw reply

* Re: [PATCH] Move color option parsing out of diff.c and into color.[ch]
From: Jeff King @ 2006-09-08  9:12 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vk64eivzj.fsf@assigned-by-dhcp.cox.net>

On Fri, Sep 08, 2006 at 01:49:20AM -0700, Junio C Hamano wrote:

> > +	if (trail)
> > +		r += printf("%s", trail);
> > +	if (*color)
> > +		r += printf("%s", COLOR_RESET);
> > +	return r;
> > +}
> Hmm,... don't you mean RESET first and then trail (which is often "\n")?

ARGH. Yes, sorry about that. I wrote it correctly once, and then
refactored it to be wrong. :)

> Please spell NULL not 0 (please do not argue that writing a NULL

Sorry, I should clearly go read the linux CodingStyle doc before
subjecting you to any more of my patches.

I'm assuming you can mark both of those up yourself rather than having
me resend?

-Peff

^ permalink raw reply

* Re: [RFC] gitweb wishlist and TODO list
From: Jakub Narebski @ 2006-09-08  9:11 UTC (permalink / raw)
  To: git
In-Reply-To: <7vzmdbp38k.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:

> Jakub Narebski <jnareb@gmail.com> writes:
> 
>> I have very preliminary work, where gitweb uses @enabled_committags as list
>> of committags to use, and %committags_info for actual committags info.
>> Examples of committags includes current linking of commit sha1,
>> gitweb-xmms2 linking of BUG(n) and FEATURE(n) to site-wide based URL
>> (Mantis), and RELEASE x.y.z to site-wide based URL (Wiki); perhaps "bug n"
>> to site-wide/project-wide URL (Bugzilla)... any other ideas?
> 
> Use a regexp as %committags key and its value to be whatever
> that takes the matched string and munge it into a URL form
> perhaps?  A site that does not have commit tags do not have any
> element in that hash.

The problem is when you have a bunch of projects, all server by the same 
gitweb, but otherwise unrelated, so needing different committags (e.g. one 
project uses Mantis and needs "BUG(n)" and "FEATURE(n)", another uses 
Bugzilla and needs "bug nn", yet another doesn't use any bugtracker).
And for committag you would want also information if to use it in summary
(title) in shortlog, head, history etc. views.

But this might be a good idea.

We loop over all enabled (active) committags.
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply

* Re: [PATCH 1/4] Add git-archive
From: Franck Bui-Huu @ 2006-09-08  9:00 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Franck Bui-Huu, git
In-Reply-To: <7vodtrnl0f.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:
> Franck Bui-Huu <vagabon.xyz@gmail.com> writes:
> 
[snip]
> 
> Does your code work well when you run the remote archive
> fetching locally, i.e. "git-archive --remote=../other.git",
> I wonder?
> 
> ... goes on and reads the patch, notices that the protocol
> command is git-upload-archive with the archive location.  Which
> is GOOD.  It is just the above description is a tad stale.
> 

yeah, sorry for that. I forgot to update the patch description.


>> diff --git a/archive.h b/archive.h
>> new file mode 100644
>> index 0000000..f33398e
>> --- /dev/null
>> +++ b/archive.h
>> @@ -0,0 +1,41 @@
>> +#ifndef ARCHIVE_H
>> +#define ARCHIVE_H
>> +
>> +#define MAX_EXTRA_ARGS	32
>> +#define MAX_ARGS	(MAX_EXTRA_ARGS + 32)
>> +

[snip]

> 
> I thought the reason for archiver_args (and archiver_args.extra)
> was because we wanted to avoid storing per invocation parameters
> in static variables, which would hamper reentrancy.  If one
> process is creating two archives, both format=tar, it might be
> reasonable for the code (future archiver enhancement, not your
> current implementation of git-archive driver) to parse two sets
> of parameters first (to get separate archiver instances) and
> call their write_archive, but if archivers[] list has the
> per-invocation parameter args then we are back to square one,
> aren't we?
> 
> Reentrancy may not matter, but in any case the above archiver_args
> is not helping enough to improve the situation, I think.
> 
> Actually you may be able to get away by returning a copy of
> archivers[] element from get_archiver() when we need reentrancy
> in the future.  Of course the caller needs to free() it when it
> is done with it, since it is a per-invocation handle.
> 

yup I did half work here. Does the following is ok now ?

-- >8 --

Subject: Add git-archive

git-archive is a command to make TAR and ZIP archives of a git tree.
It helps prevent a proliferation of git-{format}-tree commands.

Instead of directly calling git-{tar,zip}-tree command, it defines
a very simple API, that archiver should implement and register in
"git-archive.c". This API is made up by 2 functions whose prototype
is defined in "archive.h" file.

 - The first one is used to parse 'extra' parameters which have
   signification only for the specific archiver. That would allow
   different archive backends to have different kind of options.

 - The second one is used to ask to an archive backend to build
   the archive given some already resolved parameters.

It also implements remote operations by defining a very simple
protocol: it first sends 'git-upload-archive' followed the
repository name. Then it sends options. It's done by sending a
sequence of one argument per packet, with prefix "argument ",
followed by a flush.

The remote protocol is implemented in "git-archive.c" for client
side and is triggered by "--remote=<repo>" option. For example,
to fetch a TAR archive in a remote repo, you can issue:

$ git archive --format=tar --remote=git://xxx/yyy/zzz.git HEAD

We choose to not make a new command "git-fetch-archive" for example,
avoind one more GIT command which should be nice for users (less
commands to remember, keeps existing --remote option).

Signed-off-by: Franck Bui-Huu <vagabon.xyz@gmail.com>
---
 .gitignore                    |    1 
 Documentation/git-archive.txt |  100 ++++++++++++++++++
 Makefile                      |    3 -
 archive.h                     |   41 +++++++
 builtin-archive.c             |  225 +++++++++++++++++++++++++++++++++++++++++
 builtin.h                     |    1 
 generate-cmdlist.sh           |    1 
 git.c                         |    1 
 8 files changed, 372 insertions(+), 1 deletions(-)

diff --git a/.gitignore b/.gitignore
index 78cb671..a3e7ca1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@ git-apply
 git-applymbox
 git-applypatch
 git-archimport
+git-archive
 git-bisect
 git-branch
 git-cat-file
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
new file mode 100644
index 0000000..913528d
--- /dev/null
+++ b/Documentation/git-archive.txt
@@ -0,0 +1,100 @@
+git-archive(1)
+==============
+
+NAME
+----
+git-archive - Creates a archive of the files in the named tree
+
+
+SYNOPSIS
+--------
+'git-archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>]
+	      [--remote=<repo>] <tree-ish> [path...]
+
+DESCRIPTION
+-----------
+Creates an archive of the specified format containing the tree
+structure for the named tree.  If <prefix> is specified it is
+prepended to the filenames in the archive.
+
+'git-archive' behaves differently when given a tree ID versus when
+given a commit ID or tag ID.  In the first case the current time is
+used as modification time of each file in the archive.  In the latter
+case the commit time as recorded in the referenced commit object is
+used instead.  Additionally the commit ID is stored in a global
+extended pax header if the tar format is used; it can be extracted
+using 'git-get-tar-commit-id'. In ZIP files it is stored as a file
+comment.
+
+OPTIONS
+-------
+
+--format=<fmt>::
+	Format of the resulting archive: 'tar', 'zip'...
+
+--list::
+	Show all available formats.
+
+--prefix=<prefix>/::
+	Prepend <prefix>/ to each filename in the archive.
+
+<extra>::
+	This can be any options that the archiver backend understand.
+
+--remote=<repo>::
+	Instead of making a tar archive from local repository,
+	retrieve a tar archive from a remote repository.
+
+<tree-ish>::
+	The tree or commit to produce an archive for.
+
+path::
+	If one or more paths are specified, include only these in the
+	archive, otherwise include all files and subdirectories.
+
+CONFIGURATION
+-------------
+By default, file and directories modes are set to 0666 or 0777 in tar
+archives.  It is possible to change this by setting the "umask" variable
+in the repository configuration as follows :
+
+[tar]
+        umask = 002	;# group friendly
+
+The special umask value "user" indicates that the user's current umask
+will be used instead. The default value remains 0, which means world
+readable/writable files and directories.
+
+EXAMPLES
+--------
+git archive --format=tar --prefix=junk/ HEAD | (cd /var/tmp/ && tar xf -)::
+
+	Create a tar archive that contains the contents of the
+	latest commit on the current branch, and extracts it in
+	`/var/tmp/junk` directory.
+
+git archive --format=tar --prefix=git-1.4.0/ v1.4.0 | gzip >git-1.4.0.tar.gz::
+
+	Create a compressed tarball for v1.4.0 release.
+
+git archive --format=tar --prefix=git-1.4.0/ v1.4.0{caret}\{tree\} | gzip >git-1.4.0.tar.gz::
+
+	Create a compressed tarball for v1.4.0 release, but without a
+	global extended pax header.
+
+git archive --format=zip --prefix=git-docs/ HEAD:Documentation/ > git-1.4.0-docs.zip::
+
+	Put everything in the current head's Documentation/ directory
+	into 'git-1.4.0-docs.zip', with the prefix 'git-docs/'.
+
+Author
+------
+Written by Franck Bui-Huu and Rene Scharfe.
+
+Documentation
+--------------
+Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
diff --git a/Makefile b/Makefile
index 389daf7..51ed4dd 100644
--- a/Makefile
+++ b/Makefile
@@ -242,7 +242,7 @@ LIB_FILE=libgit.a
 XDIFF_LIB=xdiff/lib.a
 
 LIB_H = \
-	blob.h cache.h commit.h csum-file.h delta.h \
+	archive.h blob.h cache.h commit.h csum-file.h delta.h \
 	diff.h object.h pack.h para-walk.h pkt-line.h quote.h refs.h \
 	run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
 	tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h
@@ -267,6 +267,7 @@ LIB_OBJS = \
 BUILTIN_OBJS = \
 	builtin-add.o \
 	builtin-apply.o \
+	builtin-archive.o \
 	builtin-cat-file.o \
 	builtin-checkout-index.o \
 	builtin-check-ref-format.o \
diff --git a/archive.h b/archive.h
new file mode 100644
index 0000000..24b016f
--- /dev/null
+++ b/archive.h
@@ -0,0 +1,41 @@
+#ifndef ARCHIVE_H
+#define ARCHIVE_H
+
+#define MAX_EXTRA_ARGS	32
+#define MAX_ARGS	(MAX_EXTRA_ARGS + 32)
+
+struct archiver_args {
+	const char *base;
+	struct tree *tree;
+	const unsigned char *commit_sha1;
+	time_t time;
+	const char **pathspec;
+	void *extra;
+};
+
+typedef int (*write_archive_fn_t)(struct archiver_args *);
+
+typedef void *(*parse_extra_args_fn_t)(int argc, const char **argv);
+
+struct archiver {
+	const char *name;
+	const char *remote;
+	struct archiver_args args;
+	write_archive_fn_t write_archive;
+	parse_extra_args_fn_t parse_extra;
+};
+
+extern struct archiver archivers[];
+
+extern int parse_archive_args(int argc,
+			      const char **argv,
+			      struct archiver *ar);
+
+extern void parse_treeish_arg(const char **treeish,
+			      struct archiver_args *ar_args,
+			      const char *prefix);
+
+extern void parse_pathspec_arg(const char **pathspec,
+			       struct archiver_args *args);
+
+#endif	/* ARCHIVE_H */
diff --git a/builtin-archive.c b/builtin-archive.c
new file mode 100644
index 0000000..5671cbd
--- /dev/null
+++ b/builtin-archive.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2006 Franck Bui-Huu
+ * Copyright (c) 2006 Rene Scharfe
+ */
+#include <time.h>
+#include "cache.h"
+#include "builtin.h"
+#include "archive.h"
+#include "commit.h"
+#include "tree-walk.h"
+#include "exec_cmd.h"
+#include "pkt-line.h"
+
+static const char archive_usage[] = \
+"git-archive --format=<fmt> [--prefix=<prefix>/] [<extra>] <tree-ish> [path...]";
+
+
+struct archiver archivers[] = { };
+
+
+static int run_remote_archiver(struct archiver *ar, int argc,
+			       const char **argv)
+{
+	char *url, buf[1024];
+	int fd[2], i, len, rv;
+	pid_t pid;
+
+	sprintf(buf, "git-upload-archive");
+
+	url = strdup(ar->remote);
+	pid = git_connect(fd, url, buf);
+	if (pid < 0)
+		return pid;
+
+	for (i = 1; i < argc; i++) {
+		if (!strncmp(argv[i], "--remote=", 9))
+			continue;
+		packet_write(fd[1], "argument %s\n", argv[i]);
+	}
+	packet_flush(fd[1]);
+
+	len = packet_read_line(fd[0], buf, sizeof(buf));
+	if (!len)
+		die("git-archive: expected ACK/NAK, got EOF");
+	if (buf[len-1] == '\n')
+		buf[--len] = 0;
+	if (strcmp(buf, "ACK")) {
+		if (len > 5 && !strncmp(buf, "NACK ", 5))
+			die("git-archive: NACK %s", buf + 5);
+		die("git-archive: protocol error");
+	}
+
+	len = packet_read_line(fd[0], buf, sizeof(buf));
+	if (len)
+		die("git-archive: expected a flush");
+
+	/* Now, start reading from fd[0] and spit it out to stdout */
+	rv = copy_fd(fd[0], 1);
+
+	close(fd[0]);
+	rv |= finish_connect(pid);
+
+	return !!rv;
+}
+
+static int init_archiver(const char *name, struct archiver *ar)
+{
+	int rv = -1, i;
+
+	for (i = 0; i < ARRAY_SIZE(archivers); i++) {
+		if (!strcmp(name, archivers[i].name)) {
+			memcpy(ar, &archivers[i], sizeof(struct archiver));
+			rv = 0;
+			break;
+		}
+	}
+	return rv;
+}
+
+void parse_pathspec_arg(const char **pathspec, struct archiver_args *ar_args)
+{
+	ar_args->pathspec = get_pathspec(ar_args->base, pathspec);
+}
+
+void parse_treeish_arg(const char **argv, struct archiver_args *ar_args,
+		       const char *prefix)
+{
+	const char *name = argv[0];
+	const unsigned char *commit_sha1;
+	time_t archive_time;
+	struct tree *tree;
+	struct commit *commit;
+	unsigned char sha1[20];
+
+	if (get_sha1(name, sha1))
+		die("Not a valid object name");
+
+	commit = lookup_commit_reference_gently(sha1, 1);
+	if (commit) {
+		commit_sha1 = commit->object.sha1;
+		archive_time = commit->date;
+	} else {
+		archive_time = time(NULL);
+	}
+
+	tree = parse_tree_indirect(sha1);
+	if (tree == NULL)
+		die("not a tree object");
+
+	if (prefix) {
+		unsigned char tree_sha1[20];
+		unsigned int mode;
+		int err;
+
+		err = get_tree_entry(tree->object.sha1, prefix,
+				     tree_sha1, &mode);
+		if (err || !S_ISDIR(mode))
+			die("current working directory is untracked");
+
+		free(tree);
+		tree = parse_tree_indirect(tree_sha1);
+	}
+	ar_args->tree = tree;
+	ar_args->commit_sha1 = commit_sha1;
+	ar_args->time = archive_time;
+}
+
+static const char *default_parse_extra(struct archiver *ar,
+				       const char **argv)
+{
+	static char msg[64];
+
+	snprintf(msg, sizeof(msg) - 4, "'%s' format does not handle %s",
+		 ar->name, *argv);
+
+	return strcat(msg, "...");
+}
+
+int parse_archive_args(int argc, const char **argv, struct archiver *ar)
+{
+	const char *extra_argv[MAX_EXTRA_ARGS];
+	int extra_argc = 0;
+	const char *format = NULL; /* some default values */
+	const char *remote = NULL;
+	const char *base = "";
+	int list = 0;
+	int i;
+
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+
+		if (!strcmp(arg, "--list") || !strcmp(arg, "-l")) {
+			list = 1;
+			continue;
+		}
+		if (!strncmp(arg, "--format=", 9)) {
+			format = arg + 9;
+			continue;
+		}
+		if (!strncmp(arg, "--prefix=", 9)) {
+			base = arg + 9;
+			continue;
+		}
+		if (!strncmp(arg, "--remote=", 9)) {
+			remote = arg + 9;
+			continue;
+		}
+		if (!strcmp(arg, "--")) {
+			i++;
+			break;
+		}
+		if (arg[0] == '-') {
+			extra_argv[extra_argc++] = arg;
+			continue;
+		}
+		break;
+	}
+	if (list) {
+		if (!remote) {
+			for (i = 0; i < ARRAY_SIZE(archivers); i++)
+				printf("%s\n", archivers[i].name);
+			exit(0);
+		}
+		die("--list and --remote are mutually exclusive");
+	}
+	if (argc - i < 1) {
+		die("%s", archive_usage);
+	}
+	if (!format){
+		die("You must specify an archive format");
+	}
+	if (init_archiver(format, ar) < 0) {
+		die("Unknown archive format '%s'", format);
+	}
+	if (extra_argc && !remote) {
+		if (!ar->parse_extra) {
+			die("%s", default_parse_extra(ar, extra_argv));
+		}
+		ar->args.extra = ar->parse_extra(extra_argc, extra_argv);
+	}
+	ar->remote = remote;
+	ar->args.base = base;
+
+	return i;
+}
+
+int cmd_archive(int argc, const char **argv, const char *prefix)
+{
+	struct archiver ar;
+	int tree_idx;
+
+	tree_idx = parse_archive_args(argc, argv, &ar);
+
+	if (ar.remote)
+		return run_remote_archiver(&ar, argc, argv);
+
+	if (prefix == NULL)
+		prefix = setup_git_directory();
+
+	argv += tree_idx;
+	parse_treeish_arg(argv, &ar.args, prefix);
+	parse_pathspec_arg(argv + 1, &ar.args);
+
+	return ar.write_archive(&ar.args);
+}
diff --git a/builtin.h b/builtin.h
index 8472c79..2391afb 100644
--- a/builtin.h
+++ b/builtin.h
@@ -15,6 +15,7 @@ extern int write_tree(unsigned char *sha
 
 extern int cmd_add(int argc, const char **argv, const char *prefix);
 extern int cmd_apply(int argc, const char **argv, const char *prefix);
+extern int cmd_archive(int argc, const char **argv, const char *prefix);
 extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
 extern int cmd_checkout_index(int argc, const char **argv, const char *prefix);
 extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh
index ec1eda2..5450918 100755
--- a/generate-cmdlist.sh
+++ b/generate-cmdlist.sh
@@ -12,6 +12,7 @@ struct cmdname_help common_cmds[] = {"
 sort <<\EOF |
 add
 apply
+archive
 bisect
 branch
 checkout
diff --git a/git.c b/git.c
index 82c8fee..c62c5cf 100644
--- a/git.c
+++ b/git.c
@@ -218,6 +218,7 @@ static void handle_internal_command(int 
 	} commands[] = {
 		{ "add", cmd_add, RUN_SETUP },
 		{ "apply", cmd_apply },
+		{ "archive", cmd_archive },
 		{ "cat-file", cmd_cat_file, RUN_SETUP },
 		{ "checkout-index", cmd_checkout_index, RUN_SETUP },
 		{ "check-ref-format", cmd_check_ref_format },
-- 
1.4.2

^ permalink raw reply related

* Re: Add git-archive [take #2]
From: Junio C Hamano @ 2006-09-08  8:58 UTC (permalink / raw)
  To: Franck; +Cc: git
In-Reply-To: <45012752.4070300@innova-card.com>

Franck Bui-Huu <vagabon.xyz@gmail.com> writes:

> Junio C Hamano wrote:
>> Franck Bui-Huu <vagabon.xyz@gmail.com> writes:
>>>
>>>   2/ Can I remove 'git-upload-tar' command ?
>>>   3/ Should I kill 'git-zip-tree' command ?
>> 
>> We do not deprecate commands that easily.  Notice we have kept
>> git-resolve for a long time (we should remove it and by now it
>> should be safe)?
>
> heh ? I've just noticed that you removed 'git-upload-tar' from
> master branch (commit d9edcbd6061a392c1315ab6f3aedb9992a3c01b1).
>
> Futhermore I was thinking about 'git-zip-tree' removal because
> it's a very recent command. It shouldn't hurt to remove it now
> and make our life easier, not sure though...

I do not think I removed upload-tar.  I removed it from daemon
service list and the documentation for daemon, because that part
is a new code.

	git tar-tree --remote=../linux-2.6/.git HEAD
	git tar-tree --remote=kernel.org:git next

should still work; the former is "from a directory next door"
and connect.c invokes local /bin/sh as the transport, and the
latter is "ssh login to kernel.org and use ./git directory".

I recall from earlier review of your code, "git archive" should
work well over these two transports in addition to git://
protocol that talks with git-daemon.

^ permalink raw reply

* Re: [PATCH] Move color option parsing out of diff.c and into color.[ch]
From: Junio C Hamano @ 2006-09-08  8:49 UTC (permalink / raw)
  To: Jeff King; +Cc: git
In-Reply-To: <20060908080318.GA3771@coredump.intra.peff.net>

Jeff King <peff@peff.net> writes:

> +static int color_vprintf(const char *color, const char *fmt,
> +		va_list args, const char *trail)
> +{
> +	int r = 0;
> +
> +	if (*color)
> +		r += printf("%s", color);
> +	r += vprintf(fmt, args);
> +	if (trail)
> +		r += printf("%s", trail);
> +	if (*color)
> +		r += printf("%s", COLOR_RESET);
> +	return r;
> +}

Hmm,... don't you mean RESET first and then trail (which is often "\n")?

> +int color_printf(const char *color, const char *fmt, ...)
> +{
> +	va_list args;
> +	int r;
> +	va_start(args, fmt);
> +	r = color_vprintf(color, fmt, args, 0);
> +	va_end(args);
> +	return r;
> +}

Please spell NULL not 0 (please do not argue that writing a NULL
pointer as integral constant 0 is perfectly valid C -- we all
know that.  This is not the language-lawyers correctness issue,
but ../linux-2.6/Documentation/CodingStyle thing).  Using
pointer as boolean seems to be Ok style (e.g. "if (trail)" does
not have to be written "if (trail == NULL)").

^ permalink raw reply

* Re: Change set based shallow clone
From: Andreas Ericsson @ 2006-09-08  8:48 UTC (permalink / raw)
  To: Jon Smirl; +Cc: Jakub Narebski, git
In-Reply-To: <9e4733910609071341u7e430214j71ddcbefa26810ca@mail.gmail.com>

Jon Smirl wrote:
> On 9/7/06, Jakub Narebski <jnareb@gmail.com> wrote:
>> I don't understand. Git is _not_ patchset based (like GNU Arch, or
> 
> I meant change set to refer to a commit plus trees plus blobs that
> make it up. These may be present in full or delta form.
> 
>> Mercurial, or CVS). It is snapshot based. So if you want to download
>> "skip", you need only for the local part of doenloader to make 
>> appropriate
>> grafts, like below
>>
>>
>>  *--*--*--*--*--*--*--*--*--*--*--HEAD    (server)
>>
>>  *--*--*...........*--*--*--*--*--HEAD    (shallow/sparse clone)
>>
>> But the part you were talking about is _easy_ part; the hard part is
>> merges including merging branch which was split off the trunk before
>> cutoff-point, history rewriting (c.f. 'pu' branch, and rebases), etc.
> 
> Does an average user do these things? The shallow clone is there to
> address the casual user who gags at a five hour download to get an
> initial check out Mozilla when they want to make a five line change or
> just browse the source for a few minutes.
> 

A better idea would be to allow those users to download a gzipped 
tarball of a pre-grafted repository. It shouldn't be terribly difficult 
to set up an update-hook that creates the pre-grafted repository for you 
whenever a tag (or some such) is created in the repo you host wherever 
everybody does their initial clone from.

As I understand it (although I've admittedly followed the git 
mailing-list sporadically the past three or so months), grafts already 
work as intended, and the users can then fetch into their grafted repo 
to get a bare minimum of objects.

> 
> There would also be a command to bring down all of the objects to
> fully populate a sparse tree. You could do the shallow clone to begin
> with and then do the full tree populate overnight or in the
> background.
> 

With the pre-grafted history this would work as follow

$ mkdir pregraft
$ wget http://pre-grafts.mozilla.org/pregrafted.git.tgz
$ cd pregraft
$ tar xvzf ../pregrafted.git.tgz
$ cd ..
$ git clone mozilla-repo-url >& /dev/null &
$ cd pregraft
# work, work, work; full clone completes
$ cd ../mozilla-repo
$ git pull ../pregraft master

or something similar.

iow, you get the small repo quickly and can start hacking while the 
full-history clone is downloading. If I understand grafts correctly, you 
could then merge in your changes made in the grafted repo to the one 
with full history.

> Maybe the answer is to build a shallow clone tool for casual use, and
> then if you try to run anything too complex on it git just tells you
> that you have to download the entire tree.
> 

I believe all tools that work with history understand grafts already, 
and if so they should provide sane messages when the user attempts to 
access history beyond the grafts. I might have missed or misunderstood 
something, but this seems to me like a simple solution to a complex problem.

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

^ permalink raw reply

* Re: Add git-archive [take #2]
From: Jakub Narebski @ 2006-09-08  8:47 UTC (permalink / raw)
  To: git
In-Reply-To: <45012752.4070300@innova-card.com>

Franck Bui-Huu wrote:

>> Especially tar-tree --remote and upload-archive talks different
>> protocols, so it is not like not removing it is making your life
>> more difficult.  Perhaps after next release (1.4.3 or 1.5?  I
> 
> since you removed 'git-upload-tar', it would be good to remove
> '--remote' option from 'git-tar-tree' command as well. 

git-tar-tree --remote was talked about, so I'd rather have the removal of
this option was postponed.

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply

* Re: Change set based shallow clone
From: Junio C Hamano @ 2006-09-08  8:39 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git
In-Reply-To: <edra0v$42a$1@sea.gmane.org>

Jakub Narebski <jnareb@gmail.com> writes:

> [*1*] From Documentation/repository-layout.txt or
> http://www.kernel.org/pub/software/scm/git/docs/repository-layout.html
>
> You can be using `objects/info/alternates` mechanism, or
> `$GIT_ALTERNATE_OBJECT_DIRECTORIES` mechanism to 'borrow'
> objects from other object stores.  A repository with this kind
> of incomplete object store is not suitable to be published for
> use with dumb transports but otherwise is OK as long as
> `objects/info/alternates` points at the right object stores
> it borrows from.

Ah, you spotted an obsolete documentation again ;-).

^ permalink raw reply

* Re: Change set based shallow clone
From: Jakub Narebski @ 2006-09-08  8:36 UTC (permalink / raw)
  To: git
In-Reply-To: <9e4733910609071923tf1c49f6o70419e961e9eb66f@mail.gmail.com>

Jon Smirl wrote:

> Here is another way to look at the shallow clone problem. The only
> public ids in a git tree are the head and tag pointers. Send these to
> the client. Now let's modify the git tools to fault the full objects
> in one by one from the server whenever a git operation needs the
> object.  Dangling references would point to 'not-present' objects.
> 
> For a typical user using a model like this, how much of the Mozilla
> repository would end up being faulted into their machine? Mozilla has
> 2M objects and 250K commits in a 450MB pack. My estimate is that a
> typical user is going to touch less than 200K of the objects and maybe
> less than 100K.
> 
> Of course always faulting in full objects is wasteful. A smart scheme
> would be to try and anticipate with some read ahead and figure out
> ways to send deltas. Tools like gitk would need to only touch the
> objects needed to draw the screen and not run the full commit chain at
> startup.

Yes, that is also recurring _lazy_ clone idea (or remote alternatives[*1*]
idea). With it's own set of difficulties, like cache management, readahead
and such, and of course differentiating between not present, and present on
the remote server. And what to do when network fails... wouldn't it be just
easier to use networking system like Coda or InterMezzo?


[*1*] From Documentation/repository-layout.txt or
http://www.kernel.org/pub/software/scm/git/docs/repository-layout.html

You can be using `objects/info/alternates` mechanism, or
`$GIT_ALTERNATE_OBJECT_DIRECTORIES` mechanism to 'borrow'
objects from other object stores.  A repository with this kind
of incomplete object store is not suitable to be published for
use with dumb transports but otherwise is OK as long as
`objects/info/alternates` points at the right object stores
it borrows from.

[...]

objects/info/alternates::
        This file records absolute filesystem paths of alternate
        object stores that this object store borrows objects
        from, one pathname per line.
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply

* Re: Change set based shallow clone
From: Junio C Hamano @ 2006-09-08  8:33 UTC (permalink / raw)
  To: Martin Langhoff; +Cc: git
In-Reply-To: <46a038f90609080015u56daae78u9d78584edae7fb72@mail.gmail.com>

"Martin Langhoff" <martin.langhoff@gmail.com> writes:

> As far as I can see, this would not need any change to the upload-pack
> protocol.

That I have to disagree.  Take your earlier example of "I have X
and I learned you have A B C D".  Now the fetch that got X was a
commit-only one (but you have full tree for X), but you got X
from somebody else, not the uploader you are talking with right
now.  There is a common ancestor Y somewhere behind X, but
between Y and X you lack trees and blobs.

How would the current protocol work (I am explaining that it
won't be "not need any change")?  After you express interest for
A, B, C, D with "want" messages, you start telling "have X",
"have X~1", have "X~2",... to the uploader (X, X~1 etc. are
object names not symbolic).  Eventually the uploader would
recognize Y that is an ancestor of X that it has and will Ack
it, you stop traversing the ancestor of an acked one and say
"done".  So now we have a common ancestor and the upload side
knows it can omit commits behind  that common commit Y, trees
and blobs contained in Y.

See an Oops here?  You do NOT have trees and blobs associated
with commit Y.

I am not saying we should not change the protocol.  I am just
trying to explain that the problem is not something you can
fudge without changing the protocol.

As a first level approximation, we could in addition to the
commit object name have a bit that says "do I have trees and
blobs associated with the commit" bit on each "have" message (by
the way, this is _expensive_.  You have to traverse down the
tree contained in each commit using has_sha1_file() recursively
to see if you have anything missing from _each_ commit you send
to the other).  Alternatively, you can say "I have this commit,
but I do not have this tree and I do not even know if I have
blobs needed to complete that tree because I do not know what
that tree I am missing contains -- I may have them, I may not. I
truly do not know" to convey the same information.

Think about it a bit -- saying "I know I am missing this tree"
is one thing, but if we end up saying "I do not even know what I
am missing", it is like saying "don't care what I say, just send
everything to me".  Are we gaining much by having only commit
objects on our end?

Once you end up sending a full tree, it is like doing an initial
checkout over CVS when you think you are incrementally fetching,
and you are already lost.  For example, a recent kernel tarball
compressed with gzip is around 50MB; the history for 34k commits
since 2.6.12-rc2 fully packed is slightly less than 150MB.

^ permalink raw reply

* Re: Add git-archive [take #2]
From: Franck Bui-Huu @ 2006-09-08  8:18 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Franck, git
In-Reply-To: <7v8xkvqjlq.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:
> Franck Bui-Huu <vagabon.xyz@gmail.com> writes:
>>
>>   2/ Can I remove 'git-upload-tar' command ?
>>   3/ Should I kill 'git-zip-tree' command ?
> 
> We do not deprecate commands that easily.  Notice we have kept
> git-resolve for a long time (we should remove it and by now it
> should be safe)?
> 

heh ? I've just noticed that you removed 'git-upload-tar' from
master branch (commit d9edcbd6061a392c1315ab6f3aedb9992a3c01b1).

Futhermore I was thinking about 'git-zip-tree' removal because
it's a very recent command. It shouldn't hurt to remove it now
and make our life easier, not sure though...

> Especially tar-tree --remote and upload-archive talks different
> protocols, so it is not like not removing it is making your life
> more difficult.  Perhaps after next release (1.4.3 or 1.5?  I

since you removed 'git-upload-tar', it would be good to remove
'--remote' option from 'git-tar-tree' command as well. 

> In any case, don't make removal of them as part of the series
> please.  Let's make sure this new toy works well first, and then
> start talking about removing things that have become obsolete.
> 

OK, I'll let you do that.

		Franck

^ permalink raw reply

* [PATCH] git-commit.sh: convert run_status to a C builtin
From: Jeff King @ 2006-09-08  8:05 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

This creates a new git-runstatus which should do roughly the same thing
as the run_status function from git-commit.sh. Except for color support,
the main focus has been to keep the output identical, so that it can be
verified as correct and then used as a C platform for other improvements to
the status printing code.

Signed-off-by: Jeff King <peff@peff.net>
---
This is a resend with:
 - formatting cleanups
 - s/status/wt_status/
 - avoid letting colored sections cross newlines

 .gitignore          |    1 
 Makefile            |    3 -
 builtin-runstatus.c |   34 ++++++
 builtin.h           |    1 
 dir.c               |    7 +
 dir.h               |    1 
 git-commit.sh       |  106 +-------------------
 git.c               |    1 
 wt-status.c         |  271 +++++++++++++++++++++++++++++++++++++++++++++++++++
 wt-status.h         |   24 +++++
 10 files changed, 349 insertions(+), 100 deletions(-)

diff --git a/.gitignore b/.gitignore
index 78cb671..f014ad3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,6 +94,7 @@ git-rev-list
 git-rev-parse
 git-revert
 git-rm
+git-runstatus
 git-send-email
 git-send-pack
 git-sh-setup
diff --git a/Makefile b/Makefile
index 78748cb..a9314ac 100644
--- a/Makefile
+++ b/Makefile
@@ -252,7 +252,7 @@ LIB_OBJS = \
 	fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
 	write_or_die.o trace.o \
 	alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
-	color.o
+	color.o wt-status.o
 
 BUILTIN_OBJS = \
 	builtin-add.o \
@@ -286,6 +286,7 @@ BUILTIN_OBJS = \
 	builtin-rev-list.o \
 	builtin-rev-parse.o \
 	builtin-rm.o \
+	builtin-runstatus.o \
 	builtin-show-branch.o \
 	builtin-stripspace.o \
 	builtin-symbolic-ref.o \
diff --git a/builtin-runstatus.c b/builtin-runstatus.c
new file mode 100644
index 0000000..7979d61
--- /dev/null
+++ b/builtin-runstatus.c
@@ -0,0 +1,34 @@
+#include "wt-status.h"
+#include "cache.h"
+
+extern int wt_status_use_color;
+
+static const char runstatus_usage[] =
+"git-runstatus [--color|--nocolor] [--amend] [--verbose]";
+
+int cmd_runstatus(int argc, const char **argv, const char *prefix)
+{
+	struct wt_status s;
+	int i;
+
+	git_config(git_status_config);
+	wt_status_prepare(&s);
+
+	for (i = 1; i < argc; i++) {
+		if (!strcmp(argv[i], "--color"))
+			wt_status_use_color = 1;
+		else if (!strcmp(argv[i], "--nocolor"))
+			wt_status_use_color = 0;
+		else if (!strcmp(argv[i], "--amend")) {
+			s.amend = 1;
+			s.reference = "HEAD^1";
+		}
+		else if (!strcmp(argv[i], "--verbose"))
+			s.verbose = 1;
+		else
+			usage(runstatus_usage);
+	}
+
+	wt_status_print(&s);
+	return s.commitable ? 0 : 1;
+}
diff --git a/builtin.h b/builtin.h
index 25431d7..53a896c 100644
--- a/builtin.h
+++ b/builtin.h
@@ -47,6 +47,7 @@ extern int cmd_repo_config(int argc, con
 extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
 extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
 extern int cmd_rm(int argc, const char **argv, const char *prefix);
+extern int cmd_runstatus(int argc, const char **argv, const char *prefix);
 extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
 extern int cmd_show(int argc, const char **argv, const char *prefix);
 extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
diff --git a/dir.c b/dir.c
index 5a40d8f..e2f472b 100644
--- a/dir.c
+++ b/dir.c
@@ -397,3 +397,10 @@ int read_directory(struct dir_struct *di
 	qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
 	return dir->nr;
 }
+
+int
+file_exists(const char *f)
+{
+  struct stat sb;
+  return stat(f, &sb) == 0;
+}
diff --git a/dir.h b/dir.h
index 56a1b7f..313f8ab 100644
--- a/dir.h
+++ b/dir.h
@@ -47,5 +47,6 @@ extern int excluded(struct dir_struct *,
 extern void add_excludes_from_file(struct dir_struct *, const char *fname);
 extern void add_exclude(const char *string, const char *base,
 			int baselen, struct exclude_list *which);
+extern int file_exists(const char *);
 
 #endif
diff --git a/git-commit.sh b/git-commit.sh
index 4cf3fab..10c269a 100755
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -60,26 +60,6 @@ #
 }
 
 run_status () {
-    (
-	# We always show status for the whole tree.
-	cd "$TOP"
-
-	IS_INITIAL="$initial_commit"
-	REFERENCE=HEAD
-	case "$amend" in
-	t)
-		# If we are amending the initial commit, there
-		# is no HEAD^1.
-		if git-rev-parse --verify "HEAD^1" >/dev/null 2>&1
-		then
-			REFERENCE="HEAD^1"
-			IS_INITIAL=
-		else
-			IS_INITIAL=t
-		fi
-		;;
-	esac
-
 	# If TMP_INDEX is defined, that means we are doing
 	# "--only" partial commit, and that index file is used
 	# to build the tree for the commit.  Otherwise, if
@@ -96,85 +76,13 @@ run_status () {
 	    export GIT_INDEX_FILE
 	fi
 
-	case "$branch" in
-	refs/heads/master) ;;
-	*)  echo "# On branch $branch" ;;
-	esac
-
-	if test -z "$IS_INITIAL"
-	then
-	    git-diff-index -M --cached --name-status \
-		--diff-filter=MDTCRA $REFERENCE |
-	    sed -e '
-		    s/\\/\\\\/g
-		    s/ /\\ /g
-	    ' |
-	    report "Updated but not checked in" "will commit"
-	    committable="$?"
-	else
-	    echo '#
-# Initial commit
-#'
-	    git-ls-files |
-	    sed -e '
-		    s/\\/\\\\/g
-		    s/ /\\ /g
-		    s/^/A /
-	    ' |
-	    report "Updated but not checked in" "will commit"
-
-	    committable="$?"
-	fi
-
-	git-diff-files  --name-status |
-	sed -e '
-		s/\\/\\\\/g
-		s/ /\\ /g
-	' |
-	report "Changed but not updated" \
-	    "use git-update-index to mark for commit"
-
-        option=""
-        if test -z "$untracked_files"; then
-            option="--directory --no-empty-directory"
-        fi
-	hdr_shown=
-	if test -f "$GIT_DIR/info/exclude"
-	then
-	    git-ls-files --others $option \
-		--exclude-from="$GIT_DIR/info/exclude" \
-		--exclude-per-directory=.gitignore
-	else
-	    git-ls-files --others $option \
-		--exclude-per-directory=.gitignore
-	fi |
-	while read line; do
-	    if [ -z "$hdr_shown" ]; then
-		echo '#'
-		echo '# Untracked files:'
-		echo '#   (use "git add" to add to commit)'
-		echo '#'
-		hdr_shown=1
-	    fi
-	    echo "#	$line"
-	done
-
-	if test -n "$verbose" -a -z "$IS_INITIAL"
-	then
-	    git-diff-index --cached -M -p --diff-filter=MDTCRA $REFERENCE
-	fi
-	case "$committable" in
-	0)
-		case "$amend" in
-		t)
-			echo "# No changes" ;;
-		*)
-			echo "nothing to commit" ;;
-		esac
-		exit 1 ;;
-	esac
-	exit 0
-    )
+  case "$status_only" in
+    t) color= ;;
+    *) color=--nocolor ;;
+  esac
+  git-runstatus ${color} \
+                ${verbose:+--verbose} \
+                ${amend:+--amend}
 }
 
 trap '
diff --git a/git.c b/git.c
index 335f405..495b39a 100644
--- a/git.c
+++ b/git.c
@@ -252,6 +252,7 @@ static void handle_internal_command(int 
 		{ "rev-list", cmd_rev_list, RUN_SETUP },
 		{ "rev-parse", cmd_rev_parse, RUN_SETUP },
 		{ "rm", cmd_rm, RUN_SETUP },
+		{ "runstatus", cmd_runstatus, RUN_SETUP },
 		{ "show-branch", cmd_show_branch, RUN_SETUP },
 		{ "show", cmd_show, RUN_SETUP | USE_PAGER },
 		{ "stripspace", cmd_stripspace },
diff --git a/wt-status.c b/wt-status.c
new file mode 100644
index 0000000..ec2c728
--- /dev/null
+++ b/wt-status.c
@@ -0,0 +1,271 @@
+#include "wt-status.h"
+#include "color.h"
+#include "cache.h"
+#include "object.h"
+#include "dir.h"
+#include "commit.h"
+#include "diff.h"
+#include "revision.h"
+#include "diffcore.h"
+
+int wt_status_use_color = 0;
+static char wt_status_colors[][COLOR_MAXLEN] = {
+	"",         /* WT_STATUS_HEADER: normal */
+	"\033[32m", /* WT_STATUS_UPDATED: green */
+	"\033[31m", /* WT_STATUS_CHANGED: red */
+	"\033[31m", /* WT_STATUS_UNTRACKED: red */
+};
+
+static int parse_status_slot(const char *var, int offset)
+{
+	if (!strcasecmp(var+offset, "header"))
+		return WT_STATUS_HEADER;
+	if (!strcasecmp(var+offset, "updated"))
+		return WT_STATUS_UPDATED;
+	if (!strcasecmp(var+offset, "changed"))
+		return WT_STATUS_CHANGED;
+	if (!strcasecmp(var+offset, "untracked"))
+		return WT_STATUS_UNTRACKED;
+	die("bad config variable '%s'", var);
+}
+
+static const char* color(int slot)
+{
+	return wt_status_use_color ? wt_status_colors[slot] : "";
+}
+
+void wt_status_prepare(struct wt_status *s)
+{
+	unsigned char sha1[20];
+	const char *head;
+
+	s->is_initial = get_sha1("HEAD", sha1) ? 1 : 0;
+
+	head = resolve_ref(git_path("HEAD"), sha1, 0);
+	s->branch = head ?
+		    strdup(head + strlen(get_git_dir()) + 1) :
+		    NULL;
+
+	s->reference = "HEAD";
+	s->amend = 0;
+	s->verbose = 0;
+	s->commitable = 0;
+}
+
+static void wt_status_print_header(const char *main, const char *sub)
+{
+	const char *c = color(WT_STATUS_HEADER);
+	color_printf_ln(c, "# %s:", main);
+	color_printf_ln(c, "#   (%s)", sub);
+	color_printf_ln(c, "#");
+}
+
+static void wt_status_print_trailer(void)
+{
+	color_printf_ln(color(WT_STATUS_HEADER), "#");
+}
+
+static void wt_status_print_filepair(int t, struct diff_filepair *p)
+{
+	const char *c = color(t);
+	color_printf(color(WT_STATUS_HEADER), "#\t");
+	switch (p->status) {
+	case DIFF_STATUS_ADDED:
+		color_printf(c, "new file: %s", p->one->path); break;
+	case DIFF_STATUS_COPIED:
+		color_printf(c, "copied: %s -> %s",
+				p->one->path, p->two->path);
+		break;
+	case DIFF_STATUS_DELETED:
+		color_printf_ln(c, "deleted: %s", p->one->path); break;
+	case DIFF_STATUS_MODIFIED:
+		color_printf(c, "modified: %s", p->one->path); break;
+	case DIFF_STATUS_RENAMED:
+		color_printf(c, "renamed: %s -> %s",
+				p->one->path, p->two->path);
+		break;
+	case DIFF_STATUS_TYPE_CHANGED:
+		color_printf(c, "typechange: %s", p->one->path); break;
+	case DIFF_STATUS_UNKNOWN:
+		color_printf(c, "unknown: %s", p->one->path); break;
+	case DIFF_STATUS_UNMERGED:
+		color_printf(c, "unmerged: %s", p->one->path); break;
+	default:
+		die("bug: unhandled diff status %c", p->status);
+	}
+	printf("\n");
+}
+
+static void wt_status_print_updated_cb(struct diff_queue_struct *q,
+		struct diff_options *options,
+		void *data)
+{
+	struct wt_status *s = data;
+	int shown_header = 0;
+	int i;
+	if (q->nr) {
+	}
+	for (i = 0; i < q->nr; i++) {
+		if (q->queue[i]->status == 'U')
+			continue;
+		if (!shown_header) {
+			wt_status_print_header("Updated but not checked in",
+					"will commit");
+			s->commitable = 1;
+			shown_header = 1;
+		}
+		wt_status_print_filepair(WT_STATUS_UPDATED, q->queue[i]);
+	}
+	if (shown_header)
+		wt_status_print_trailer();
+}
+
+static void wt_status_print_changed_cb(struct diff_queue_struct *q,
+                        struct diff_options *options,
+                        void *data)
+{
+	int i;
+	if (q->nr)
+		wt_status_print_header("Changed but not updated",
+				"use git-update-index to mark for commit");
+	for (i = 0; i < q->nr; i++)
+		wt_status_print_filepair(WT_STATUS_CHANGED, q->queue[i]);
+	if (q->nr)
+		wt_status_print_trailer();
+}
+
+void wt_status_print_initial(struct wt_status *s)
+{
+	int i;
+	read_cache();
+	if (active_nr) {
+		s->commitable = 1;
+		wt_status_print_header("Updated but not checked in",
+				"will commit");
+	}
+	for (i = 0; i < active_nr; i++) {
+		color_printf(color(WT_STATUS_HEADER), "#\t");
+		color_printf_ln(color(WT_STATUS_UPDATED), "new file: %s",
+				active_cache[i]->name);
+	}
+	if (active_nr)
+		wt_status_print_trailer();
+}
+
+static void wt_status_print_updated(struct wt_status *s)
+{
+	struct rev_info rev;
+	const char *argv[] = { NULL, NULL, NULL };
+	argv[1] = s->reference;
+	init_revisions(&rev, NULL);
+	setup_revisions(2, argv, &rev, NULL);
+	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = wt_status_print_updated_cb;
+	rev.diffopt.format_callback_data = s;
+	rev.diffopt.detect_rename = 1;
+	run_diff_index(&rev, 1);
+}
+
+static void wt_status_print_changed(struct wt_status *s)
+{
+	struct rev_info rev;
+	const char *argv[] = { NULL, NULL };
+	init_revisions(&rev, "");
+	setup_revisions(1, argv, &rev, NULL);
+	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = wt_status_print_changed_cb;
+	rev.diffopt.format_callback_data = s;
+	run_diff_files(&rev, 0);
+}
+
+static void wt_status_print_untracked(const struct wt_status *s)
+{
+	struct dir_struct dir;
+	const char *x;
+	int i;
+	int shown_header = 0;
+
+	memset(&dir, 0, sizeof(dir));
+
+	dir.exclude_per_dir = ".gitignore";
+	x = git_path("info/exclude");
+	if (file_exists(x))
+		add_excludes_from_file(&dir, x);
+
+	read_directory(&dir, ".", "", 0);
+	for(i = 0; i < dir.nr; i++) {
+		/* check for matching entry, which is unmerged; lifted from
+		 * builtin-ls-files:show_other_files */
+		struct dir_entry *ent = dir.entries[i];
+		int pos = cache_name_pos(ent->name, ent->len);
+		struct cache_entry *ce;
+		if (0 <= pos)
+			die("bug in wt_status_print_untracked");
+		pos = -pos - 1;
+		if (pos < active_nr) {
+			ce = active_cache[pos];
+			if (ce_namelen(ce) == ent->len &&
+			    !memcmp(ce->name, ent->name, ent->len))
+				continue;
+		}
+		if (!shown_header) {
+			wt_status_print_header("Untracked files",
+				"use \"git add\" to add to commit");
+			shown_header = 1;
+		}
+		color_printf(color(WT_STATUS_HEADER), "#\t");
+		color_printf_ln(color(WT_STATUS_UNTRACKED), "%.*s",
+				ent->len, ent->name);
+	}
+}
+
+static void wt_status_print_verbose(struct wt_status *s)
+{
+	struct rev_info rev;
+	const char *argv[] = { NULL, NULL, NULL };
+	argv[1] = s->reference;
+	init_revisions(&rev, NULL);
+	setup_revisions(2, argv, &rev, NULL);
+	rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
+	rev.diffopt.detect_rename = 1;
+	run_diff_index(&rev, 1);
+}
+
+void wt_status_print(struct wt_status *s)
+{
+	if (s->branch && strcmp(s->branch, "refs/heads/master"))
+		color_printf_ln(color(WT_STATUS_HEADER),
+			"# On branch %s", s->branch);
+
+	if (s->is_initial) {
+		color_printf_ln(color(WT_STATUS_HEADER), "#");
+		color_printf_ln(color(WT_STATUS_HEADER), "# Initial commit");
+		color_printf_ln(color(WT_STATUS_HEADER), "#");
+		wt_status_print_initial(s);
+	}
+	else {
+		wt_status_print_updated(s);
+		discard_cache();
+	}
+
+	wt_status_print_changed(s);
+	wt_status_print_untracked(s);
+
+	if (s->verbose && !s->is_initial)
+		wt_status_print_verbose(s);
+	if (!s->commitable)
+		printf("%s\n", s->amend ? "# No changes" : "nothing to commit");
+}
+
+int git_status_config(const char *k, const char *v)
+{
+	if (!strcmp(k, "status.color")) {
+		wt_status_use_color = git_config_colorbool(k, v);
+		return 0;
+	}
+	if (!strncmp(k, "status.color.", 13)) {
+		int slot = parse_status_slot(k, 13);
+		color_parse(v, k, wt_status_colors[slot]);
+	}
+	return git_default_config(k, v);
+}
diff --git a/wt-status.h b/wt-status.h
new file mode 100644
index 0000000..75d3cfe
--- /dev/null
+++ b/wt-status.h
@@ -0,0 +1,24 @@
+#ifndef STATUS_H
+#define STATUS_H
+
+enum color_wt_status {
+	WT_STATUS_HEADER,
+	WT_STATUS_UPDATED,
+	WT_STATUS_CHANGED,
+	WT_STATUS_UNTRACKED,
+};
+
+struct wt_status {
+	int is_initial;
+	char *branch;
+	const char *reference;
+	int commitable;
+	int verbose;
+	int amend;
+};
+
+int git_status_config(const char *var, const char *value);
+void wt_status_prepare(struct wt_status *s);
+void wt_status_print(struct wt_status *s);
+
+#endif /* STATUS_H */
-- 
1.4.2.g5290b

^ permalink raw reply related

* [PATCH] Move color option parsing out of diff.c and into color.[ch]
From: Jeff King @ 2006-09-08  8:03 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <20060908073452.GA25343@coredump.intra.peff.net>

The intent is to lib-ify colorizing code so it can be reused.

Signed-off-by: Jeff King <peff@peff.net>
---
This is a resend with formatting cleanups and a new function,
color_printf_ln.

 Makefile |    3 +
 color.c  |  176 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 color.h  |   12 ++++
 diff.c   |  136 +-----------------------------------------------
 4 files changed, 194 insertions(+), 133 deletions(-)

diff --git a/Makefile b/Makefile
index 7b3114f..78748cb 100644
--- a/Makefile
+++ b/Makefile
@@ -251,7 +251,8 @@ LIB_OBJS = \
 	tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
 	fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
 	write_or_die.o trace.o \
-	alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS)
+	alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
+	color.o
 
 BUILTIN_OBJS = \
 	builtin-add.o \
diff --git a/color.c b/color.c
new file mode 100644
index 0000000..a949136
--- /dev/null
+++ b/color.c
@@ -0,0 +1,176 @@
+#include "color.h"
+#include "cache.h"
+#include "git-compat-util.h"
+
+#include <stdarg.h>
+
+#define COLOR_RESET "\033[m"
+
+static int parse_color(const char *name, int len)
+{
+	static const char * const color_names[] = {
+		"normal", "black", "red", "green", "yellow",
+		"blue", "magenta", "cyan", "white"
+	};
+	char *end;
+	int i;
+	for (i = 0; i < ARRAY_SIZE(color_names); i++) {
+		const char *str = color_names[i];
+		if (!strncasecmp(name, str, len) && !str[len])
+			return i - 1;
+	}
+	i = strtol(name, &end, 10);
+	if (*name && !*end && i >= -1 && i <= 255)
+		return i;
+	return -2;
+}
+
+static int parse_attr(const char *name, int len)
+{
+	static const int attr_values[] = { 1, 2, 4, 5, 7 };
+	static const char * const attr_names[] = {
+		"bold", "dim", "ul", "blink", "reverse"
+	};
+	int i;
+	for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
+		const char *str = attr_names[i];
+		if (!strncasecmp(name, str, len) && !str[len])
+			return attr_values[i];
+	}
+	return -1;
+}
+
+void color_parse(const char *value, const char *var, char *dst)
+{
+	const char *ptr = value;
+	int attr = -1;
+	int fg = -2;
+	int bg = -2;
+
+	if (!strcasecmp(value, "reset")) {
+		strcpy(dst, "\033[m");
+		return;
+	}
+
+	/* [fg [bg]] [attr] */
+	while (*ptr) {
+		const char *word = ptr;
+		int val, len = 0;
+
+		while (word[len] && !isspace(word[len]))
+			len++;
+
+		ptr = word + len;
+		while (*ptr && isspace(*ptr))
+			ptr++;
+
+		val = parse_color(word, len);
+		if (val >= -1) {
+			if (fg == -2) {
+				fg = val;
+				continue;
+			}
+			if (bg == -2) {
+				bg = val;
+				continue;
+			}
+			goto bad;
+		}
+		val = parse_attr(word, len);
+		if (val < 0 || attr != -1)
+			goto bad;
+		attr = val;
+	}
+
+	if (attr >= 0 || fg >= 0 || bg >= 0) {
+		int sep = 0;
+
+		*dst++ = '\033';
+		*dst++ = '[';
+		if (attr >= 0) {
+			*dst++ = '0' + attr;
+			sep++;
+		}
+		if (fg >= 0) {
+			if (sep++)
+				*dst++ = ';';
+			if (fg < 8) {
+				*dst++ = '3';
+				*dst++ = '0' + fg;
+			} else {
+				dst += sprintf(dst, "38;5;%d", fg);
+			}
+		}
+		if (bg >= 0) {
+			if (sep++)
+				*dst++ = ';';
+			if (bg < 8) {
+				*dst++ = '4';
+				*dst++ = '0' + bg;
+			} else {
+				dst += sprintf(dst, "48;5;%d", bg);
+			}
+		}
+		*dst++ = 'm';
+	}
+	*dst = 0;
+	return;
+bad:
+	die("bad config value '%s' for variable '%s'", value, var);
+}
+
+int git_config_colorbool(const char *var, const char *value)
+{
+	if (!value)
+		return 1;
+	if (!strcasecmp(value, "auto")) {
+		if (isatty(1) || (pager_in_use && pager_use_color)) {
+			char *term = getenv("TERM");
+			if (term && strcmp(term, "dumb"))
+				return 1;
+		}
+		return 0;
+	}
+	if (!strcasecmp(value, "never"))
+		return 0;
+	if (!strcasecmp(value, "always"))
+		return 1;
+	return git_config_bool(var, value);
+}
+
+static int color_vprintf(const char *color, const char *fmt,
+		va_list args, const char *trail)
+{
+	int r = 0;
+
+	if (*color)
+		r += printf("%s", color);
+	r += vprintf(fmt, args);
+	if (trail)
+		r += printf("%s", trail);
+	if (*color)
+		r += printf("%s", COLOR_RESET);
+	return r;
+}
+
+
+
+int color_printf(const char *color, const char *fmt, ...)
+{
+	va_list args;
+	int r;
+	va_start(args, fmt);
+	r = color_vprintf(color, fmt, args, 0);
+	va_end(args);
+	return r;
+}
+
+int color_printf_ln(const char *color, const char *fmt, ...)
+{
+	va_list args;
+	int r;
+	va_start(args, fmt);
+	r = color_vprintf(color, fmt, args, "\n");
+	va_end(args);
+	return r;
+}
diff --git a/color.h b/color.h
new file mode 100644
index 0000000..88bb8ff
--- /dev/null
+++ b/color.h
@@ -0,0 +1,12 @@
+#ifndef COLOR_H
+#define COLOR_H
+
+/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
+#define COLOR_MAXLEN 24
+
+int git_config_colorbool(const char *var, const char *value);
+void color_parse(const char *var, const char *value, char *dst);
+int color_printf(const char *color, const char *fmt, ...);
+int color_printf_ln(const char *color, const char *fmt, ...);
+
+#endif /* COLOR_H */
diff --git a/diff.c b/diff.c
index a3ebc62..8178c11 100644
--- a/diff.c
+++ b/diff.c
@@ -10,6 +10,7 @@ #include "diff.h"
 #include "diffcore.h"
 #include "delta.h"
 #include "xdiff-interface.h"
+#include "color.h"
 
 static int use_size_cache;
 
@@ -17,8 +18,7 @@ static int diff_detect_rename_default;
 static int diff_rename_limit_default = -1;
 static int diff_use_color_default;
 
-/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
-static char diff_colors[][24] = {
+static char diff_colors[][COLOR_MAXLEN] = {
 	"\033[m",	/* reset */
 	"",		/* normal */
 	"\033[1m",	/* bold */
@@ -45,119 +45,6 @@ static int parse_diff_color_slot(const c
 	die("bad config variable '%s'", var);
 }
 
-static int parse_color(const char *name, int len)
-{
-	static const char * const color_names[] = {
-		"normal", "black", "red", "green", "yellow",
-		"blue", "magenta", "cyan", "white"
-	};
-	char *end;
-	int i;
-	for (i = 0; i < ARRAY_SIZE(color_names); i++) {
-		const char *str = color_names[i];
-		if (!strncasecmp(name, str, len) && !str[len])
-			return i - 1;
-	}
-	i = strtol(name, &end, 10);
-	if (*name && !*end && i >= -1 && i <= 255)
-		return i;
-	return -2;
-}
-
-static int parse_attr(const char *name, int len)
-{
-	static const int attr_values[] = { 1, 2, 4, 5, 7 };
-	static const char * const attr_names[] = {
-		"bold", "dim", "ul", "blink", "reverse"
-	};
-	int i;
-	for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
-		const char *str = attr_names[i];
-		if (!strncasecmp(name, str, len) && !str[len])
-			return attr_values[i];
-	}
-	return -1;
-}
-
-static void parse_diff_color_value(const char *value, const char *var, char *dst)
-{
-	const char *ptr = value;
-	int attr = -1;
-	int fg = -2;
-	int bg = -2;
-
-	if (!strcasecmp(value, "reset")) {
-		strcpy(dst, "\033[m");
-		return;
-	}
-
-	/* [fg [bg]] [attr] */
-	while (*ptr) {
-		const char *word = ptr;
-		int val, len = 0;
-
-		while (word[len] && !isspace(word[len]))
-			len++;
-
-		ptr = word + len;
-		while (*ptr && isspace(*ptr))
-			ptr++;
-
-		val = parse_color(word, len);
-		if (val >= -1) {
-			if (fg == -2) {
-				fg = val;
-				continue;
-			}
-			if (bg == -2) {
-				bg = val;
-				continue;
-			}
-			goto bad;
-		}
-		val = parse_attr(word, len);
-		if (val < 0 || attr != -1)
-			goto bad;
-		attr = val;
-	}
-
-	if (attr >= 0 || fg >= 0 || bg >= 0) {
-		int sep = 0;
-
-		*dst++ = '\033';
-		*dst++ = '[';
-		if (attr >= 0) {
-			*dst++ = '0' + attr;
-			sep++;
-		}
-		if (fg >= 0) {
-			if (sep++)
-				*dst++ = ';';
-			if (fg < 8) {
-				*dst++ = '3';
-				*dst++ = '0' + fg;
-			} else {
-				dst += sprintf(dst, "38;5;%d", fg);
-			}
-		}
-		if (bg >= 0) {
-			if (sep++)
-				*dst++ = ';';
-			if (bg < 8) {
-				*dst++ = '4';
-				*dst++ = '0' + bg;
-			} else {
-				dst += sprintf(dst, "48;5;%d", bg);
-			}
-		}
-		*dst++ = 'm';
-	}
-	*dst = 0;
-	return;
-bad:
-	die("bad config value '%s' for variable '%s'", value, var);
-}
-
 /*
  * These are to give UI layer defaults.
  * The core-level commands such as git-diff-files should
@@ -171,22 +58,7 @@ int git_diff_ui_config(const char *var, 
 		return 0;
 	}
 	if (!strcmp(var, "diff.color")) {
-		if (!value)
-			diff_use_color_default = 1; /* bool */
-		else if (!strcasecmp(value, "auto")) {
-			diff_use_color_default = 0;
-			if (isatty(1) || (pager_in_use && pager_use_color)) {
-				char *term = getenv("TERM");
-				if (term && strcmp(term, "dumb"))
-					diff_use_color_default = 1;
-			}
-		}
-		else if (!strcasecmp(value, "never"))
-			diff_use_color_default = 0;
-		else if (!strcasecmp(value, "always"))
-			diff_use_color_default = 1;
-		else
-			diff_use_color_default = git_config_bool(var, value);
+		diff_use_color_default = git_config_colorbool(var, value);
 		return 0;
 	}
 	if (!strcmp(var, "diff.renames")) {
@@ -201,7 +73,7 @@ int git_diff_ui_config(const char *var, 
 	}
 	if (!strncmp(var, "diff.color.", 11)) {
 		int slot = parse_diff_color_slot(var, 11);
-		parse_diff_color_value(value, var, diff_colors[slot]);
+		color_parse(value, var, diff_colors[slot]);
 		return 0;
 	}
 	return git_default_config(var, value);
-- 
1.4.2.g5290b

^ permalink raw reply related

* Re: [PATCH 3/3] git-commit.sh: convert run_status to a C builtin
From: Jeff King @ 2006-09-08  7:34 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7v64fynbpg.fsf@assigned-by-dhcp.cox.net>

On Thu, Sep 07, 2006 at 10:56:11PM -0700, Junio C Hamano wrote:

> I just wanted to point it out because I felt the names to
> programmers are slightly different matter.

Fair enough. Do you want to change git-runstatus? It should ideally not
be used by end users at all (and hopefully can eventually go away if
git-status and git-commit become builtins).

> > wt_status? ucu_status (updated, changed, untracked)?
> Yeah, something along those lines.

I think wt_status is the most reasonable of those.

> In a distant past I saw some terminals get confused near the
> edge if you do that, but these days everybody is on some sort of
> Xterm so it may not matter.  But that would probably be nice to
> fix.

OK, it will take a little wrangling with the color_printf interface, but
it should be doable.

> > OK. Besides the things you mentioned, what improvements would you like
> > to see?
> Besides the things I mentioned?  I dunno offhand -- otherwise I
> would have mentioned them ;-).

Heh. OK, I assumed your previous comment hinted at hidden depths of
dissatisfaction, but clearly not. :) Patches forthcoming...

-Peff

^ permalink raw reply

* Re: Change set based shallow clone
From: Martin Langhoff @ 2006-09-08  7:15 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jon Smirl, git
In-Reply-To: <7vac5ancvo.fsf@assigned-by-dhcp.cox.net>

On 9/8/06, Junio C Hamano <junkio@cox.net> wrote:
> "Martin Langhoff" <martin.langhoff@gmail.com> writes:
> > People who want shallow clones are actually asking for a "light"
> > clone, in terms of "how much do I need to download". If everyone has
> > the whole commit chain (but may be missing olden blobs, and even
> > trees), the problem becomes a lot easier.
>
> No, I do not think so.  You are just pushing the same problem to
> another layer.
>
> Reachability through commit ancestry chain is no more special
> than reachability through commit-tree or tree-containment
> relationships.  The grafts mechanism happen to treat commit

Agreed that it is no more special. OTOH, if we focus on the fact that
people want to avoid high-cost data transfers, transferring commit
chains is cheap and allows the client to ask good questions when
talking to the server.

So as far as tradeoffs go, it allows you to keep the protocol simple,
and minimise complex guessing at either end of the wire.

> But let's touch a slightly different but related topic first.
> People do not ask for shallow clones.  They just want faster
> transfer of "everything they care about".  Shallow and lazy

I'd disagree a bit here. They care about the whole project, and in
time they'll find that out and end up pulling it all if they use git
much at all ;-)

They want fast, cheap initial checkouts.

...
> So they are all not that different.

Earlier you were pointing out how hard it was for the client to even
know what to ask for because it can't see the whole picture. Having
the ancestry  complete means you always know what to ask for.

> Now, first and foremost, while I would love to have a system
> that gracefully operates with a "sparse" repository that lacks
> objects that should exist from tag/commit/tree/blob reachability
> point of view, it is an absolute requirement that I can tell why
> objects are missing from a repository when I find some are
> missing by running fsck-objects [*3*].

I agree -- and you can keep those objects you know are expected to be
missing listed in an "packless" idx file somewhere.

> If repository is a
> shallow clone, not having some object may be expected, but I
> want to be able to tell repository corruption locally even in
> that case,

+1

> I talked about the need of upload-pack protocol extension

As far as I can see, this would not need any change to the upload-pack
protocol.

There are some hard problems in dealing with a sparse repo that need
thinking through. My thinking is that by having the whole commit chain
around the protocol can be kept sane, by virtue of the local repo
always having a clear "overall" picture, including knowing what it's
missing.

> [*4*] In git, there is no inherent server vs client or upstream
> vs downstream relationship between repositories.

Here an importaant distiction must be made. A "publishing" repo cannot
be sparse. A sparse repo probably cannot be cloned from.

>  You may be
> even fetching from many people and do not have a set upstream at
> all.  Or you are _the_ upstream, and your notebook has the
> latest devevelopment history, and after pushing that latest
> history to your mothership repository, you may decide you do not
> want ancient development history on a puny notebook, and locally
> cauterize the history on your notebook repository and prune
> ancient stuff.

Well, that's easy again: "prune old blobs and list them in an idx"
should work well.

cheers,



martin

^ permalink raw reply

* Re: [PATCH 3/3] git-commit.sh: convert run_status to a C builtin
From: Junio C Hamano @ 2006-09-08  5:56 UTC (permalink / raw)
  To: Jeff King; +Cc: git
In-Reply-To: <20060908054226.GA19537@coredump.intra.peff.net>

Jeff King <peff@peff.net> writes:

> On Thu, Sep 07, 2006 at 05:20:20PM -0700, Junio C Hamano wrote:
>
>> "status.h" and "struct status" somehow sounds too broad.
>> Granted, "object.h" is also broad, but in git context "object"
>> has a specific meaning.
>
> I agree it is quite broad (as is git-runstatus). Conceptually it's
> another type of diff format, but making it a diff argument doesn't
> really makes much sense. We're at least not introducing any broadness,
> since there is already git-status; are we interested in fixing that
> name?

The command name is a name exposed to the end user.  We do not
currently have a command to give "repository status", and even
if we had one such a specialized command for repository
administrators would be called git-repository-status so
git-status is definitely fine as is.

I just wanted to point it out because I felt the names to
programmers are slightly different matter.

> wt_status? ucu_status (updated, changed, untracked)?

Yeah, something along those lines.

>> Very nicely done.  Especially I liked that you are careful not
>> to paint leading '#\t' (which is noticeable when you use reverse
>> as an attribute).
>
> Yes. I seem to recall some issues raised about color attributes
> persisting over a newline, but I can't find any reference to it now.
> Using color_printf makes sure every color is 'closed' but it sometimes
> includes the newline in the colorized portion. Does anybody object to
> that?

In a distant past I saw some terminals get confused near the
edge if you do that, but these days everybody is on some sort of
Xterm so it may not matter.  But that would probably be nice to
fix.

> OK. Besides the things you mentioned, what improvements would you like
> to see?

Besides the things I mentioned?  I dunno offhand -- otherwise I
would have mentioned them ;-).

^ permalink raw reply


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