* Re: 'sparse' clone idea
From: Johannes Schindelin @ 2006-06-14 9:20 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
In-Reply-To: <e6oh2g$ngh$1@sea.gmane.org>
Hi,
On Wed, 14 Jun 2006, Jakub Narebski wrote:
> I wonder if 'sparse clone' idea described below would avoid the most
> difficult part of 'shallow clone' idea, namely the [sometimes] need to
> un-cauterize history. See: (<7vac8lidwi.fsf@assigned-by-dhcp.cox.net>).
I do not think that is the hardest problem. The hardest thing is to tell
the server in an efficient manner which objects we have.
Example:
A - B - C - D
^ cutoff
^ current HEAD
Suppose B is your fake root, C is your HEAD, you want to fetch D. Now,
make it a difficult example: both A and D contain a certain blob Z, but
neither B nor C do. You have to tell the server _in an efficient manner_
to send Z also.
And by efficient manner I mean: you may not bring the server down just
because 5 people with shallow clones decide to fetch from it.
> 'sparse clone' begins like 'shallow clone': full history is copied down to
> specified point of history (cut-off or cauterization point for shallow
> clone), but instead of cauterizing the history from that point downwards,
> the history is simplified using grafts.
>
> In the sparse part we need:
> * all commits pointed by tags (if we clone/copy tags)
> and other refs (if we clone/copy those tags)
> * merge bases for all commits in full, and in the sparse part,
> _including_ merge bases themselves
Hmmm. You cannot know _all_ merge bases beforehand, because you do not
decide where other people fork off.
> * all roots
Why?
> Commits in sparse part would be connected like in original history, only
> skipping "uniteresting" commits.
Interesting idea, though I do not think it solves the most pressing
problems we have with shallow clones.
Ciao,
Dscho
P.S.: I think the problems of a lazy clone are much easier to solve...
^ permalink raw reply
* Re: Repacking many disconnected blobs
From: Johannes Schindelin @ 2006-06-14 9:07 UTC (permalink / raw)
To: Shawn Pearce; +Cc: Keith Packard, Git Mailing List
In-Reply-To: <20060614072923.GB13886@spearce.org>
Hi,
On Wed, 14 Jun 2006, Shawn Pearce wrote:
> Keith Packard <keithp@keithp.com> wrote:
> > parsecvs scans every ,v file and creates a blob for every revision of
> > every file right up front. Once these are created, it discards the
> > actual file contents and deals solely with the hash values.
> >
> > The problem is that while this is going on, the repository consists
> > solely of disconnected objects, and I can't make git-repack put those
> > into pack objects. This leaves the directories bloated, and operations
> > within the tree quite sluggish. I'm importing a project with 30000 files
> > and 30000 revisions (the CVS repository is about 700MB), and after
> > scanning the files, and constructing (in memory) a complete revision
> > history, the actual construction of the commits is happening at about 2
> > per second, and about 70% of that time is in the kernel, presumably
> > playing around in the repository.
> >
> > I'm assuming that if I could get these disconnected blobs all neatly
> > tucked into a pack object, things might go a bit faster.
>
> What about running git-update-index using .git/objects as the
> current working directory and adding all files in ??/* into the
> index, then git-write-tree that index and git-commit-tree the tree.
>
> When you are done you have a bunch of orphan trees and a commit
> but these shouldn't be very big and I'd guess would prune out with
> a repack if you don't hold a ref to the orphan commit.
Alternatively, you could construct fake trees like this:
README/1.1.1.1
README/1.2
README/1.3
...
i.e. every file becomes a directory -- containing all the versions of that
file -- in the (virtual) tree, which you can point to by a temporary ref.
Ciao,
Dscho
^ permalink raw reply
* Your future, N electron
From: Buford Greer @ 2006-06-14 12:31 UTC (permalink / raw)
To: linux-newbie
Even if you have no erectin problems SOFT CIAzLIS
would help you to make BETTER SE X MORE OFTEN!
and to bring unimagnable plesure to her.
Just disolve half a pil under your tongue
and get ready for action in 15 minutes.
The tests showed that the majority of men
after taking this medic ation were able to have
PERFECT ER ECTI ON during 36 hours!
VISIT US, AND GET OUR SPECIAL 70% DISC OUNT OFER!
http://tvewuu.jugjest.com/?62746363
==========
weapons--and you have the framework of this amazing short novel. Add the
their teeth on this cotton problem for some time. You see, they were
own sake, the search for new devices, new techniques, to achieve new heights
"It's just a garage."
"I don't mind being bone and feathers mom. I just want to know what I
and against the spitting devil's cabbage.... All right.
fourteen miles per hour! It was a breakthrough, the greatest single moment
"Of course! But I would like to Finish with science first. As a
^ permalink raw reply
* 'sparse' clone idea
From: Jakub Narebski @ 2006-06-14 8:23 UTC (permalink / raw)
To: git
I wonder if 'sparse clone' idea described below would avoid the most
difficult part of 'shallow clone' idea, namely the [sometimes] need to
un-cauterize history. See: (<7vac8lidwi.fsf@assigned-by-dhcp.cox.net>).
'sparse clone' begins like 'shallow clone': full history is copied down to
specified point of history (cut-off or cauterization point for shallow
clone), but instead of cauterizing the history from that point downwards,
the history is simplified using grafts.
In the sparse part we need:
* all commits pointed by tags (if we clone/copy tags)
and other refs (if we clone/copy those tags)
* merge bases for all commits in full, and in the sparse part,
_including_ merge bases themselves
* all roots
Commits in sparse part would be connected like in original history, only
skipping "uniteresting" commits.
Thoughts? Comments?
--
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
^ permalink raw reply
* Re: Repacking many disconnected blobs
From: Shawn Pearce @ 2006-06-14 7:29 UTC (permalink / raw)
To: Keith Packard; +Cc: Git Mailing List
In-Reply-To: <1150269478.20536.150.camel@neko.keithp.com>
Keith Packard <keithp@keithp.com> wrote:
> parsecvs scans every ,v file and creates a blob for every revision of
> every file right up front. Once these are created, it discards the
> actual file contents and deals solely with the hash values.
>
> The problem is that while this is going on, the repository consists
> solely of disconnected objects, and I can't make git-repack put those
> into pack objects. This leaves the directories bloated, and operations
> within the tree quite sluggish. I'm importing a project with 30000 files
> and 30000 revisions (the CVS repository is about 700MB), and after
> scanning the files, and constructing (in memory) a complete revision
> history, the actual construction of the commits is happening at about 2
> per second, and about 70% of that time is in the kernel, presumably
> playing around in the repository.
>
> I'm assuming that if I could get these disconnected blobs all neatly
> tucked into a pack object, things might go a bit faster.
What about running git-update-index using .git/objects as the
current working directory and adding all files in ??/* into the
index, then git-write-tree that index and git-commit-tree the tree.
When you are done you have a bunch of orphan trees and a commit
but these shouldn't be very big and I'd guess would prune out with
a repack if you don't hold a ref to the orphan commit.
--
Shawn.
^ permalink raw reply
* Repacking many disconnected blobs
From: Keith Packard @ 2006-06-14 7:17 UTC (permalink / raw)
To: Git Mailing List; +Cc: keithp
[-- Attachment #1: Type: text/plain, Size: 963 bytes --]
parsecvs scans every ,v file and creates a blob for every revision of
every file right up front. Once these are created, it discards the
actual file contents and deals solely with the hash values.
The problem is that while this is going on, the repository consists
solely of disconnected objects, and I can't make git-repack put those
into pack objects. This leaves the directories bloated, and operations
within the tree quite sluggish. I'm importing a project with 30000 files
and 30000 revisions (the CVS repository is about 700MB), and after
scanning the files, and constructing (in memory) a complete revision
history, the actual construction of the commits is happening at about 2
per second, and about 70% of that time is in the kernel, presumably
playing around in the repository.
I'm assuming that if I could get these disconnected blobs all neatly
tucked into a pack object, things might go a bit faster.
--
keith.packard@intel.com
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Porcelain specific metadata under .git?
From: Shawn Pearce @ 2006-06-14 6:22 UTC (permalink / raw)
To: git
So I'm reaching a point with my Eclipse plugin[*1*] where its
actually doing something with a GIT repository and I want to store a
ref (to a tree, not a commit) under .git/refs/eclipse-workspaces to
help the plugin cache state between workbench restarts. But there
doesn't really seem to be any policy to what paths under .git are
available for Porcelain and what definately should be off-limits.
I already assume/know that refs/heads and refs/tags are completely
off-limits as they are for user refs only.
I also think the core GIT tools already assume that anything
directly under .git which is strictly a file and which is named
entirely with uppercase letters (aside from "HEAD") is strictly a
temporary/short-lived state type item (e.g. COMMIT_MSG) used by a
Porcelain.
But is saying ".git/refs/eclipse-workspaces" is probably able to
be used for this purpose safe? :-)
[*1*] The Eclipse plugin is getting close to something that is worth
releasing as an early alpha for other developers. I think I finally
found the last bug in the pack reading code and am now working on the
basic operations (add/remove/commit/status). I hope to have all of
that working within a few days, at which point I'll publish/announce
a public GIT repository with the complete source code and an Eclipse
update site for those brave souls who might want to just install it.
--
Shawn.
^ permalink raw reply
* Re: oprofile on svn import
From: Jon Smirl @ 2006-06-14 5:26 UTC (permalink / raw)
To: Ryan Anderson; +Cc: Eric Wong, git
In-Reply-To: <20060614044802.GE30825@h4x0r5.com>
On 6/14/06, Ryan Anderson <ryan@michonline.com> wrote:
> On Tue, Jun 13, 2006 at 07:01:08PM -0700, Eric Wong wrote:
> > Anybody want to see how my latest patches to git-svn (and using SVN perl
> > libraries) stacks up against the mozilla repo? Speedwise, I don't
> > expect git-svn to be too different than git-svnimport, but it should use
> > much less memory (I'll probably port the hacks to git-svnimport, too).
>
> I've got access to a pretty good machine to run this on - where can I
> grab the svn repo from?
> (I can just grab the CVS one and convert it, first, as well, just point
> me at that, if that's got more bandwidth.)
rsync -az cvs-mirror.mozilla.org::mozilla ~/mozilla/cvs-mirror
It took about three days for my machine to convert that cvs to svn.
I have the converted repo local but it is 8.2GB and I have 256kb up.
There is no real purpose in converting mozilla cvs to svn to git other
than to test the tools. My last attempt at svn to git ran five days
before I lost power. Towards the end it was getting significantly slow
implying some kind of n squared problem in the import process. The
idea was to see if cvsimport and svnimport both end up with the same
output.
I am going to use git-cvsimport on the mozilla repo but that tool
needs to 2GB+ physical RAM to run. I ordered 2GB more and it will be
here tomorrow. I have just been playing with the svn conversion while
I wait five days for my 2nd day air package to show up.
>
> --
>
> Ryan Anderson
> sometimes Pug Majere
>
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* Re: oprofile on svn import
From: Ryan Anderson @ 2006-06-14 4:48 UTC (permalink / raw)
To: Eric Wong; +Cc: Jon Smirl, git
In-Reply-To: <20060614020108.GB12083@hand.yhbt.net>
On Tue, Jun 13, 2006 at 07:01:08PM -0700, Eric Wong wrote:
> Anybody want to see how my latest patches to git-svn (and using SVN perl
> libraries) stacks up against the mozilla repo? Speedwise, I don't
> expect git-svn to be too different than git-svnimport, but it should use
> much less memory (I'll probably port the hacks to git-svnimport, too).
I've got access to a pretty good machine to run this on - where can I
grab the svn repo from?
(I can just grab the CVS one and convert it, first, as well, just point
me at that, if that's got more bandwidth.)
--
Ryan Anderson
sometimes Pug Majere
^ permalink raw reply
* Re: oprofile on svn import
From: Martin Langhoff @ 2006-06-14 3:32 UTC (permalink / raw)
To: Jon Smirl; +Cc: git
In-Reply-To: <9e4733910606131810ya6aa585m5d2349f651b01492@mail.gmail.com>
On 6/14/06, Jon Smirl <jonsmirl@gmail.com> wrote:
> I'm going back to cvsimport tomorrow. My svn import that had been
For best results, make sure you remove the -a from the git-repack
line. Once it's done, run git-repack -a -d manually.
cheers,
martin
^ permalink raw reply
* Re: oprofile on svn import
From: Eric Wong @ 2006-06-14 3:02 UTC (permalink / raw)
To: Jon Smirl; +Cc: git, Matthias Urlichs, Linus Torvalds
In-Reply-To: <9e4733910606131939h35b2278bvaa296459ea061621@mail.gmail.com>
Linus: I hope I'm right on [1] (the stuff about fork).
Jon Smirl <jonsmirl@gmail.com> wrote:
> On 6/13/06, Eric Wong <normalperson@yhbt.net> wrote:
> >Jon Smirl <jonsmirl@gmail.com> wrote:
> >> I'm going back to cvsimport tomorrow. My svn import that had been
> >> running for five days got killed this morning when the city decided to
> >> move the telephone pole that provides my electricty.
> >>
> >> Some oprofile data, this doesn't make a lot of sense to me. Why is it
> >> in libcypto so much?
> >
> >The sha1 calculation is done in libcrypto, afaik.
>
> That make sense, but it's eating up 14% of my CPU in a long sample.
>
> >Anybody want to see how my latest patches to git-svn (and using SVN perl
> >libraries) stacks up against the mozilla repo? Speedwise, I don't
> >expect git-svn to be too different than git-svnimport, but it should use
> >much less memory (I'll probably port the hacks to git-svnimport, too).
>
> Can svnimport be rewritten to avoid calling fork? If I am reading the
> oprofiles correctly that fork is very expensive especially when the
> svnimport task grows to 600MB.
I think the problem is the process growing to 600MB, and not the fork :)
git-svn avoids process growth pretty well from my tests with the gcc
repo.
See the fetch_lib() function in this patch on how I avoid process
growth by _using_ fork():
Subject: [PATCH 12/13] git-svn: add support for Perl SVN::* libraries
(<115022175180-git-send-email-normalperson@yhbt.net>)
Perl processes (at least on my machines (5.8.x, Linux x86) don't like to
release memory back to the OS when they're done using it (although it
can reuse the memory within the process itself). This is why SVN::Pool
isn't very effective in many cases.
fork() will only duplicate memory for the pages that are changed by the
child, not the entire process[1]. So I fork children that run temporarily
to avoid accumulating memory usage inside the process.
This technique should probably be added to git-svnimport as well.
> I have an import running but post your code when it is ready and I can
> try it on the next run. They always seem to fail so there will
> probably be another run.
I've posted a two series of patches the past few days that have yet
to be merged by Junio:
Subject: [PATCH] git-svn: bug fixes (some resends)
<11500094252972-git-send-email-normalperson@yhbt.net>
Subject: [PATCH 0/13] git-svn: better branch support, SVN:: lib usage, feature additions
<11502217352245-git-send-email-normalperson@yhbt.net>
--
Eric Wong
^ permalink raw reply
* Re: oprofile on svn import
From: Jon Smirl @ 2006-06-14 2:39 UTC (permalink / raw)
To: Eric Wong; +Cc: git
In-Reply-To: <20060614020108.GB12083@hand.yhbt.net>
On 6/13/06, Eric Wong <normalperson@yhbt.net> wrote:
> Jon Smirl <jonsmirl@gmail.com> wrote:
> > I'm going back to cvsimport tomorrow. My svn import that had been
> > running for five days got killed this morning when the city decided to
> > move the telephone pole that provides my electricty.
> >
> > Some oprofile data, this doesn't make a lot of sense to me. Why is it
> > in libcypto so much?
>
> The sha1 calculation is done in libcrypto, afaik.
That make sense, but it's eating up 14% of my CPU in a long sample.
> Anybody want to see how my latest patches to git-svn (and using SVN perl
> libraries) stacks up against the mozilla repo? Speedwise, I don't
> expect git-svn to be too different than git-svnimport, but it should use
> much less memory (I'll probably port the hacks to git-svnimport, too).
Can svnimport be rewritten to avoid calling fork? If I am reading the
oprofiles correctly that fork is very expensive especially when the
svnimport task grows to 600MB.
I have an import running but post your code when it is ready and I can
try it on the next run. They always seem to fail so there will
probably be another run.
> I'll see about freeing up one of my machines to test the mozilla repo.
> Unfortunately, all of my hardware is a few years old and not extremely
> fast.
>
> --
> Eric Wong
>
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* Re: oprofile on svn import
From: Jon Smirl @ 2006-06-14 2:32 UTC (permalink / raw)
To: git
In-Reply-To: <9e4733910606131810ya6aa585m5d2349f651b01492@mail.gmail.com>
>From the previous data it is obvious that I had slab debugging
enabled. I usally never notice having it turned on but in this case it
make a lot of difference.
New numbers without slab debug. Could forking off the git tasks be
causing all of this vm load?
[root@jonsmirl jonsmirl]# vmstat 10
procs -----------memory---------- ---swap-- -----io---- --system--
-----cpu------
r b swpd free buff cache si so bi bo in cs us
sy id wa st
2 0 0 13504 91220 563280 0 0 299 232 244 426 23
18 53 6 0
2 0 0 10900 91344 565128 0 0 169 464 481 737 26
23 48 2 0
2 0 0 10804 91436 564832 0 0 196 650 478 780 25
24 49 3 0
4 0 0 13516 91512 561696 0 0 166 612 474 790 26
23 49 2 0
1 0 0 10928 91632 563548 0 0 124 471 464 789 24
25 48 2 0
1 0 0 12312 91684 562000 0 0 179 688 472 783 26
23 48 3 0
1 0 0 13232 91748 560712 0 0 51 198 445 794 25
26 48 1 0
9951967 44.5102 /home/good/vmlinux
3192131 14.2768 /lib/libcrypto.so.0.9.8a
2207857 9.8747 /lib/libc-2.4.so
1587518 7.1002 /usr/lib/libz.so.1.2.3
663114 2.9658 /usr/lib/perl5/5.8.8/i386-linux-thread-multi/CORE/libperl.so
517463 2.3144 /lib/ld-2.4.so
435100 1.9460 /usr/lib/libapr-1.so.0.2.2
430292 1.9245 /usr/local/bin/git-update-index
285157 1.2754 /usr/local/bin/git-read-tree
2331728 22.8834 copy_page_range
1076769 10.5673 unmap_vmas
667975 6.5555 page_remove_rmap
663844 6.5149 page_fault
654668 6.4249 release_pages
440547 4.3235 get_page_from_freelist
245142 2.4058 do_wp_page
174656 1.7141 vm_normal_page
155185 1.5230 __handle_mm_fault
133584 1.3110 do_page_fault
131456 1.2901 __d_lookup
94194 0.9244 __link_path_walk
92927 0.9120 flush_tlb_page
91775 0.9007 find_get_page
85927 0.8433 copy_process
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* Re: [PATCH 6/8] Make git-update-ref a builtin
From: Shawn Pearce @ 2006-06-14 2:22 UTC (permalink / raw)
To: Lukas Sandström; +Cc: Junio C Hamano, Git Mailing List
In-Reply-To: <448F1E68.5090504@etek.chalmers.se>
Lukas Sandstr?m <lukass@etek.chalmers.se> wrote:
> Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>
> ---
> Makefile | 7 ++++---
> update-ref.c => builtin-update-ref.c | 5 ++++-
> builtin.h | 1 +
> git.c | 3 ++-
> 4 files changed, 11 insertions(+), 5 deletions(-)
Thanks for doing this. I know I had written this change and I was
pretty sure I had sent it to Junio a while ago but I guess it got
lost in the shuffle and I just failed to follow through with it
when it didn't show up in `next`.
--
Shawn.
^ permalink raw reply
* Re: oprofile on svn import
From: Eric Wong @ 2006-06-14 2:01 UTC (permalink / raw)
To: Jon Smirl; +Cc: git
In-Reply-To: <9e4733910606131810ya6aa585m5d2349f651b01492@mail.gmail.com>
Jon Smirl <jonsmirl@gmail.com> wrote:
> I'm going back to cvsimport tomorrow. My svn import that had been
> running for five days got killed this morning when the city decided to
> move the telephone pole that provides my electricty.
>
> Some oprofile data, this doesn't make a lot of sense to me. Why is it
> in libcypto so much?
The sha1 calculation is done in libcrypto, afaik.
Anybody want to see how my latest patches to git-svn (and using SVN perl
libraries) stacks up against the mozilla repo? Speedwise, I don't
expect git-svn to be too different than git-svnimport, but it should use
much less memory (I'll probably port the hacks to git-svnimport, too).
I'll see about freeing up one of my machines to test the mozilla repo.
Unfortunately, all of my hardware is a few years old and not extremely
fast.
--
Eric Wong
^ permalink raw reply
* Re: git-cvsimport doesn't quite work, wrt branches
From: Martin Langhoff @ 2006-06-14 1:56 UTC (permalink / raw)
To: Keith Packard
Cc: Linus Torvalds, Jim Meyering, Git Mailing List, Matthias Urlichs,
Yann Dirson, Pavel Roskin
In-Reply-To: <1150241459.20536.98.camel@neko.keithp.com>
On 6/14/06, Keith Packard <keithp@keithp.com> wrote:
> On Wed, 2006-06-14 at 10:55 +1200, Martin Langhoff wrote:
>
> > In terms of history parsing, parsecvs and cvs2svn are similar. I like
> > cvs2svn "many passes" approach better, though the Python source is
> > really messy. A good thing about cvs2svn is that it is a lot more
> > conservative WRT memory use.
>
> I will try to fix parsecvs so it doesn't take so much memory. Of course,
> my goal was to import various X.org repositories which have horrible
> issues, but aren't all that huge. And, for them, it works just fine.
Would it be possible to have it parse the RCS histories from a remote repo?
I had forgotten, but that's something else that the cvsps +
git-cvsimport combo can do. In short, to replace cvsps+git-cvsimport
...
+ not memory bound -- or at least must be able to import large
(mozilla, gentoo) with a decent amount of memory
+ must work local and remote (of course local can be faster)
+ must do incrementals reasonably well
> I'd like some help figuring out how to do incremental imports with
> parsecvs. As parsecvs already constructs the project history from the
> present into the past, it should be possible to "notice" when it hits
> existing bits in the repository and stop automatically. I think this
> will just take saving a bit of state in the git repository to mark where
> in CVS the tips of each branch come from.
Ok. Before starting to read the RCS files, I would look at all the
branch tips in the git repo, and read some metadata of the last commit
of each head into memory (author, commitmsg, timestamp, diffstat).
When parsing RCS files and building changesets to import, compare them
with the 'head' data. The timestamp granularity is seconds which is
pretty coarse -- you can ask for history post those timestamps, but
there's the risk of missing commits (this affects git-cvsimport today,
and I'm thinking how to fix it there). So borderline changesets should
be compared against the metadata you have.
There is the chance that your earlier import caught a commit partway
through, so you may end up putting in the 'rest' of the commit. That's
why diffstat can be useful.
Is that useful?
cheers,
martin
^ permalink raw reply
* oprofile on svn import
From: Jon Smirl @ 2006-06-14 1:10 UTC (permalink / raw)
To: git
I'm going back to cvsimport tomorrow. My svn import that had been
running for five days got killed this morning when the city decided to
move the telephone pole that provides my electricty.
Some oprofile data, this doesn't make a lot of sense to me. Why is it
in libcypto so much?
12632739 30.6077 /lib/libcrypto.so.0.9.8a
11762639 28.4995 /home/good/vmlinux
6310191 15.2889 /lib/libc-2.4.so
2498812 6.0543 /usr/lib/perl5/5.8.8/i386-linux-thread-multi/CORE/libperl.so
2079975 5.0395 /usr/local/bin/git-update-index
1103116 2.6727 /usr/lib/libz.so.1.2.3
617395 1.4959 /usr/lib/libapr-1.so.0.2.2
484625 1.1742 /usr/local/bin/git-read-tree
kernel breakdown
2035561 16.4450 copy_page_range
1110813 8.9741 get_page_from_freelist
851064 6.8756 check_poison_obj
759296 6.1342 unmap_vmas
670659 5.4181 release_pages
667657 5.3939 page_remove_rmap
595826 4.8136 page_fault
241962 1.9548 __copy_from_user_ll
185876 1.5017 do_wp_page
176506 1.4260 do_page_fault
I reset the statistics and took another snapshot half an hour later.
2232310 44.3485 /home/good/vmlinux
757114 15.0413 /lib/libcrypto.so.0.9.8a
507282 10.0780 /lib/libc-2.4.so
203440 4.0417 /usr/lib/libz.so.1.2.3
179105 3.5582 /usr/lib/libapr-1.so.0.2.2
169724 3.3718 /usr/lib/perl5/5.8.8/i386-linux-thread-multi/CORE/libperl.so
114384 2.2724 /usr/local/bin/git-update-index
102350 2.0334 /usr/lib/libsvn_subr-1.so.0.0.0
74673 1.4835 /usr/lib/libaprutil-1.so.0.2.2
69987 1.3904 /usr/lib/libsvn_fs_fs-1.so.0.0.0
Kernel:
543264 21.2518 copy_page_range
243383 9.5208 check_poison_obj
227788 8.9108 unmap_vmas
161806 6.3296 page_remove_rmap
153201 5.9930 release_pages
119092 4.6587 page_fault
100116 3.9164 get_page_from_freelist
45014 1.7609 do_wp_page
42130 1.6481 vm_normal_page
34804 1.3615 poison_obj
28231 1.1044 do_page_fault
27403 1.0720 __handle_mm_fault
24558 0.9607 __copy_to_user_ll
20618 0.8066 flush_tlb_page
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* Re: git-cvsimport doesn't quite work, wrt branches
From: Keith Packard @ 2006-06-13 23:30 UTC (permalink / raw)
To: Martin Langhoff
Cc: keithp, Linus Torvalds, Jim Meyering, Git Mailing List,
Matthias Urlichs, Yann Dirson, Pavel Roskin
In-Reply-To: <46a038f90606131555m7b1fa744g9770140c87598b7b@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1405 bytes --]
On Wed, 2006-06-14 at 10:55 +1200, Martin Langhoff wrote:
> In terms of history parsing, parsecvs and cvs2svn are similar. I like
> cvs2svn "many passes" approach better, though the Python source is
> really messy. A good thing about cvs2svn is that it is a lot more
> conservative WRT memory use.
I will try to fix parsecvs so it doesn't take so much memory. Of course,
my goal was to import various X.org repositories which have horrible
issues, but aren't all that huge. And, for them, it works just fine.
> So far, I have been relying on parsecvs for initial imports, and for
> cvsps+git-cvsimport for incrementals on top of that initial import.
> But parsecvs falls over with large repos.
I'd like some help figuring out how to do incremental imports with
parsecvs. As parsecvs already constructs the project history from the
present into the past, it should be possible to "notice" when it hits
existing bits in the repository and stop automatically. I think this
will just take saving a bit of state in the git repository to mark where
in CVS the tips of each branch come from.
> The main problem, however, is that it doesn't do incremental imports,
> so this would be a roundabout way of fixing parsecvs's
> memory-bound-ness. We still need cvsps :(
Parsecvs is currently O(nrev * nfile), and I'd like to make it O(nrev)
instead.
--
keith.packard@intel.com
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: git-cvsimport doesn't quite work, wrt branches
From: Martin Langhoff @ 2006-06-13 22:55 UTC (permalink / raw)
To: Keith Packard
Cc: Linus Torvalds, Jim Meyering, Git Mailing List, Matthias Urlichs,
Yann Dirson, Pavel Roskin
In-Reply-To: <1150224411.20536.79.camel@neko.keithp.com>
On 6/14/06, Keith Packard <keithp@keithp.com> wrote:
> cvs rlog is designed to 'represent' the history of the repository to
> users. Cvsps was built as a software analysis tool, and is used by
> putative software engineering researchers. Basing a supposedly lossless
> repository conversion system on this pair seems foolish to me,
> notwithstanding the heroic efforts to make it work.
Yes, cvsps is relying on the wrong things. I am looking at parsecvs
and the cvs2svn tool and wondering where to from here.
In terms of history parsing, parsecvs and cvs2svn are similar. I like
cvs2svn "many passes" approach better, though the Python source is
really messy. A good thing about cvs2svn is that it is a lot more
conservative WRT memory use.
So far, I have been relying on parsecvs for initial imports, and for
cvsps+git-cvsimport for incrementals on top of that initial import.
But parsecvs falls over with large repos.
I am starting to look at what I can do with cvs2svn to get the import
into git. It seems to get very good patchsets, and it yields an easily
readable DB. I'll either learn Python, or read the DB from Perl
(probably from git-cvsimport).
The main problem, however, is that it doesn't do incremental imports,
so this would be a roundabout way of fixing parsecvs's
memory-bound-ness. We still need cvsps :(
martin
^ permalink raw reply
* Re: [PATCH 0/8] Make a couple of commands builtin
From: Lukas Sandström @ 2006-06-13 22:03 UTC (permalink / raw)
To: Timo Hirvonen; +Cc: junkio, git, Lukas Sandström
In-Reply-To: <20060614005437.69ff6a62.tihirvon@gmail.com>
Timo Hirvonen wrote:
> Lukas Sandström <lukass@etek.chalmers.se> wrote:
>
>> This patchseries has the ultimate goal of making
>> git-am a builtin.
>>
>> The version of git-am I'm sending out makes quite heavy
>> use of system(), but I think that can be worked around.
>> I just haven't figured out how, yet.
>
> I don't think git-stripspace needs to be a built-in. It doesn't even
> depend on git. It is just a tiny helper program used by git-am,
> git-applymbox, git-commit and git-tag. If all these commands are made
> built-in then git-stripspace becomes useless.
>
The reason I made it builtin was to de able to call it easily from git-am.
As you say, once all the users are builtin it could be removed, unless somone
is using it in their scripts.
/Lukas
^ permalink raw reply
* Re: [PATCH 0/8] Make a couple of commands builtin
From: Timo Hirvonen @ 2006-06-13 21:54 UTC (permalink / raw)
To: lukass; +Cc: junkio, git
In-Reply-To: <448F1E41.1040607@etek.chalmers.se>
Lukas Sandström <lukass@etek.chalmers.se> wrote:
> This patchseries has the ultimate goal of making
> git-am a builtin.
>
> The version of git-am I'm sending out makes quite heavy
> use of system(), but I think that can be worked around.
> I just haven't figured out how, yet.
I don't think git-stripspace needs to be a built-in. It doesn't even
depend on git. It is just a tiny helper program used by git-am,
git-applymbox, git-commit and git-tag. If all these commands are made
built-in then git-stripspace becomes useless.
--
http://onion.dynserv.net/~timo/
^ permalink raw reply
* [BUG] stgit branch renaming into new dir crashes
From: Yann Dirson @ 2006-06-13 21:40 UTC (permalink / raw)
To: Catalin Marinas; +Cc: GIT list
When trying to rename a branch to a name including a slash, there is
no explicit creation of leading dirs, and stgit crashes:
$ stg branch -r multitag dev/multitag
Traceback (most recent call last):
File "/usr/bin/stg", line 43, in ?
main()
File "/usr/lib/python2.3/site-packages/stgit/main.py", line 187, in main
command.func(parser, options, args)
File "/usr/lib/python2.3/site-packages/stgit/commands/branch.py", line 214, in func
stack.Series(args[0]).rename(args[1])
File "/usr/lib/python2.3/site-packages/stgit/stack.py", line 497, in rename
os.rename(self.__series_dir, to_stack.__series_dir)
OSError: [Errno 2] No such file or directory
--
Yann Dirson <ydirson@altern.org> |
Debian-related: <dirson@debian.org> | Support Debian GNU/Linux:
| Freedom, Power, Stability, Gratis
http://ydirson.free.fr/ | Check <http://www.debian.org/>
^ permalink raw reply
* Re: git-cvsimport doesn't quite work, wrt branches
From: Yann Dirson @ 2006-06-13 21:13 UTC (permalink / raw)
To: Linus Torvalds
Cc: Jim Meyering, Git Mailing List, Matthias Urlichs, Pavel Roskin
In-Reply-To: <Pine.LNX.4.64.0606131008470.5498@g5.osdl.org>
On Tue, Jun 13, 2006 at 10:20:10AM -0700, Linus Torvalds wrote:
> Sadly, it also seems to be one that isn't fixed by the patches _I_ have,
> and looking at Yann's set of patches, I don't think they fix it either.
I don't think so either.
> So CVSps basically tells git-cvsimport that commit 2 (on branch B) is
> based on commit 1, and doesn't say that "on-trunk" has gone away, so the
> resulting git repository has branch B containing "on-trunk" version 1.1,
> and "on-br" version 1.1.2.1.
>
> CVS branches obviously sometimes confuse CVSps. Sadly, they also confuse
> _me_, so I don't see how to fix this particular CVSps bug, because I'm as
> confused as CVSps is ;)
>
> We'd need to have CVSps tell git that the "on-trunk" file was never added
> to branch B: the simplest way to do that would be to say that it has
> become (DEAD) in PatchSet 2 (which is not technically true in CVS terms,
> but _is_ technically true on git terms - on branch B, that file is
> obviously dead).
>
> Yann? Pavel? Anybody? Ideas?
This is exactly the problem I encountered one week ago with one my old
cvs repos, where I had created a branch only for a part of a source
hierarchy :)
One thing that amused me, is that in that case cvsps was DWIM enough
that the result was indeed what I expected from the conversion (I had
forgotten about the particular way that branch was created 3 years
ago). I only discovered the problem when tailor's cvs backend
generated deletions when starting my branch.
So basically, because of how awkward cvs branches are, cvsps may
indeed do what many users expect here, because branches in cvs repos
are sometimes created in strange ways, (in my case, to avoid having to
merge changes in unrelevant areas of the tree - nowadays, I'd just use
stgit to isolate changes).
I don't know what was the particular thing in coreutils developement
that led to branching only some files. In my case, it can be seen as
the cvs idiom for "branching a part of the tree" - something I don't
think there is a need to have a special idiom in GIT for.
If we want cvsps to output the exact history derived from cvs
(ie. what Jim expected, and I think it is reasonable), I fear it would
require substential modification to cvsps. I should check, but I
don't think it currently keeps track of which files are part of the
tree resulting from a changeset, but only of the files actually touhed
by the changeset. So the change would probably have a big ram
usage impact, if we store the file refs in each changeset.
That reminds me of another funny cs behaviour I noticed a couple of
months ago (not sure if it was in 1.11.x or 1.12.x): "cvs import" was
not marking files as dead on the vendor branch when it disappeared
from one upstream version to another, it was just not tagged in the
new version. I guess cvsps would have a hard time figuring out what
happenned, and would just mark the taks as invalid.
For this type of cvsps issues and cvs tags in general, my latest idea
would be to add "fake" patchsets on which to apply tags and
branchpoints. The ideal way would seem to make those similar to git's
merge commits, having as parents all patchsets the tag takes revision
from (obviously it's so biased towards the git model it would be a
pleasure to add support for this in git-cvsimport :) - but that would
produce patchsets not fitting well into the current cvsps model, so
that may require more thinking.
Anyway, it should provide a way to make sense out of what cvsps
currently considers to be "invalid" tags.
Best regards,
--
Yann Dirson <ydirson@altern.org> |
Debian-related: <dirson@debian.org> | Support Debian GNU/Linux:
| Freedom, Power, Stability, Gratis
http://ydirson.free.fr/ | Check <http://www.debian.org/>
^ permalink raw reply
* [PATCH/RFC 8/8] Make git-am a builtin
From: Lukas Sandström @ 2006-06-13 20:22 UTC (permalink / raw)
To: Junio C Hamano, Git Mailing List; +Cc: Lukas Sandström
In-Reply-To: <448EF791.7070504@etek.chalmers.se>
Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>
---
Being able to switch index-file on the fly would reduce the number of
system() calls.
A way to check if the index/working dir is dirty would also help.
Makefile | 6 -
builtin-am.c | 664 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
builtin.h | 1
git-am.sh | 427 -------------------------------------
git.c | 3
5 files changed, 670 insertions(+), 431 deletions(-)
diff --git a/Makefile b/Makefile
index 4b30ca0..e9b372e 100644
--- a/Makefile
+++ b/Makefile
@@ -122,7 +122,7 @@ SCRIPT_SH = \
git-repack.sh git-request-pull.sh git-reset.sh \
git-resolve.sh git-revert.sh git-sh-setup.sh \
git-tag.sh git-verify-tag.sh \
- git-applymbox.sh git-applypatch.sh git-am.sh \
+ git-applymbox.sh git-applypatch.sh \
git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
git-merge-resolve.sh git-merge-ours.sh \
git-lost-found.sh git-quiltimport.sh
@@ -166,7 +166,7 @@ PROGRAMS = \
BUILT_INS = git-log$X git-whatchanged$X git-show$X git-update-ref$X \
git-count-objects$X git-diff$X git-push$X git-mailsplit$X \
git-grep$X git-add$X git-rm$X git-rev-list$X git-stripspace$X \
- git-check-ref-format$X git-rev-parse$X git-mailinfo$X \
+ git-check-ref-format$X git-rev-parse$X git-mailinfo$X git-am$X \
git-init-db$X git-tar-tree$X git-upload-tar$X git-format-patch$X \
git-ls-files$X git-ls-tree$X git-get-tar-commit-id$X \
git-read-tree$X git-commit-tree$X git-write-tree$X \
@@ -220,7 +220,7 @@ LIB_OBJS = \
BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-add.o builtin-rev-list.o builtin-check-ref-format.o \
- builtin-rm.o builtin-init-db.o builtin-rev-parse.o \
+ builtin-rm.o builtin-init-db.o builtin-rev-parse.o builtin-am.o \
builtin-tar-tree.o builtin-upload-tar.o builtin-update-index.o \
builtin-ls-files.o builtin-ls-tree.o builtin-write-tree.o \
builtin-read-tree.o builtin-commit-tree.o builtin-mailinfo.o \
diff --git a/builtin-am.c b/builtin-am.c
new file mode 100644
index 0000000..d9e7ac5
--- /dev/null
+++ b/builtin-am.c
@@ -0,0 +1,664 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Lukas Sandström, 2006
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/wait.h>
+
+#include "git-compat-util.h"
+#include "cache.h"
+#include "builtin.h"
+
+static char builtin_am_usage[] = "[--signoff] [--dotest=<dir>] [--utf8] [--binary] [--3way] "
+ "[--interactive] [--whitespace=<option>] <mbox>...\n"
+ "or, when resuming [--skip | --resolved]";
+
+static int binary, interactive, threeway, signoff, utf8, keep_subject, resolved, skip, resume;
+static char whitespace[40] = "--whitespace=warn", **env;
+static const char **mbox, *dotest, *resolvmsg;
+
+#define PATCH_PREC 4
+
+#define AGAIN 0
+#define SKIP 1
+#define YES 2
+
+//ugly hack to be able to change the index file
+extern char *git_index_file;
+
+static int rm_rf(const char* path)
+{
+ char cmd[PATH_MAX + 10];
+ snprintf(cmd, sizeof(cmd), "rm -rf %s", path);
+ return system(cmd);
+}
+
+static int mkdir_p(const char *path)
+{
+ char p[PATH_MAX], n, *l;
+
+ strcpy(p, path);
+ while ((l = strchr(p, '/'))) {
+ n = *l;
+ *l = '\0';
+ if (access(p, F_OK) && mkdir(p, 0777))
+ return -1;
+ *l = n;
+ }
+ return mkdir(p, 0777);
+}
+
+static int fcat(char *file, char *fmt, ...)
+{
+ va_list args;
+ int ret;
+ FILE *f;
+
+ file = mkpath("%s/%s", dotest, file);
+ if ((f = fopen(file, "r")) == NULL) {
+ perror(file);
+ die("Couldn't open file %s", file);
+ }
+ va_start(args, fmt);
+ ret = vfscanf(f, fmt, args);
+ va_end(args);
+ fclose(f);
+ return ret;
+}
+
+static int fecho(char *file, char *fmt, ...)
+{
+ va_list args;
+ int ret;
+ FILE *f;
+
+ file = mkpath("%s/%s", dotest, file);
+ if ((f = fopen(file, "w")) == NULL) {
+ perror(file);
+ die("Couldn't open file %s/%s", dotest, file);
+ }
+ va_start(args, fmt);
+ ret = vfprintf(f, fmt, args);
+ va_end(args);
+ fclose(f);
+ return ret;
+}
+
+static FILE* get_output(char *cmd, int *status)
+{
+ char c[2000];
+ FILE *ret;
+ int s;
+
+ snprintf(c, sizeof(c), "%s > \"%s/outtmp\"", cmd, dotest);
+ s = system(c);
+ if (status)
+ *status = s;
+ if ((ret = fopen(mkpath("%s/outtmp", dotest), "r")) == NULL)
+ die("cmd: %s\nOpen \"%s\" failed.", c, mkpath("%s/outtmp", dotest));
+ unlink(mkpath("%s/outtmp", dotest));
+ return ret;
+}
+
+static int has_zero_output(char *cmd)
+{
+ struct stat s;
+
+ system(mkpath("%s > %s/zerotmp", cmd, dotest));
+ stat(mkpath("%s/zerotmp", dotest), &s);
+ unlink(mkpath("%s/zerotmp", dotest));
+ return s.st_size == 0;
+}
+
+static int go_next(int this) {
+ unlink(mkpath("%s/%0*d", dotest, PATCH_PREC, this));
+ unlink(mkpath("%s/msg", dotest));
+ unlink(mkpath("%s/msg-clean", dotest));
+ unlink(mkpath("%s/patch", dotest));
+ unlink(mkpath("%s/info", dotest));
+ fecho("next", "%d", this + 1);
+ return this + 1;
+}
+
+static void stop_here(int this)
+{
+ fecho("next","%d\n", this);
+ exit(1);
+}
+
+static void stop_here_user_resolve(int this)
+{
+ char cmdline[1000] = "git am";
+ int pos = 6; /* "git am" */
+
+ if (resolvmsg != NULL) {
+ printf("%s", resolvmsg);
+ stop_here(this);
+ }
+
+ if (interactive)
+ pos += sprintf(cmdline + pos, " -i");
+ if (threeway)
+ pos += sprintf(cmdline + pos, " -3");
+ if (strcmp(".dotest", dotest))
+ pos += sprintf(cmdline + pos, " -d=%s", dotest);
+
+ printf("When you have resolved this problem run \"git am %s --resolved\".\n", cmdline);
+ printf("If you would prefer to skip this patch, instead run \"%s --skip\".\n", cmdline);
+
+ stop_here(this);
+}
+
+static int fall_back_3way()
+{
+ char cmd[1000];
+ char tmp_index[PATH_MAX], old_index[PATH_MAX] = "";
+ int ret = -1;
+
+ snprintf(cmd, sizeof(cmd), "git-apply -z --index-info \"%s/patch\""
+ " > %s/patch-merge-index-info 2> /dev/null", dotest, dotest);
+ if (!system(cmd)) {
+ snprintf(tmp_index, sizeof(tmp_index),"%s/patch-merge-tmp-index", dotest);
+ if (getenv(INDEX_ENVIRONMENT))
+ strcpy(old_index, getenv(INDEX_ENVIRONMENT));
+ setenv(INDEX_ENVIRONMENT, tmp_index, 1);
+
+ snprintf(cmd, sizeof(cmd), "git-update-index -z --index-info <\"%s/patch-merge-index-info\"", dotest);
+ if (!system(cmd)) {
+#if 1
+ system(mkpath("git-write-tree > \"%s/patch-merge-base\"", dotest));
+ snprintf(cmd, sizeof(cmd), "git-apply %s --cached < \"%s/patch\"", binary ? "--allow-binary-replacement":"", dotest);
+ if (!system(cmd)) {
+ char his_tree[41], orig_tree[41];
+ printf("Using index info to reconstruct a base tree...\n");
+ system(mkpath("git-write-tree > \"%s/his-tree\"", dotest));
+ fcat("his-tree", "%40s", his_tree);
+ fcat("patch-merge-base", "%40s", orig_tree);
+
+ printf("Falling back to patching base and 3-way merge...\n");
+
+ if (*old_index)
+ setenv(INDEX_ENVIRONMENT, old_index, 1);
+ else
+ unsetenv(INDEX_ENVIRONMENT);
+ if (!system(mkpath("git-merge-resolve %s -- HEAD %s", orig_tree, his_tree)))
+ return 0;
+ }
+ }
+#else
+ unsigned char orig_tree[20], his_tree[20];
+
+ // We need a way to switch the index file on the fly for this to work
+
+ char *opts[] = { "git-apply", "--allow-binary-replacement", "--cached", NULL, NULL };
+ char **opt = &opts[0];
+ char patch[PATH_MAX];
+ int optc = ARRAY_SIZE(opts) - 1;
+
+ opts[optc - 1] = strncpy(patch, mkpath("%s/patch", dotest), sizeof(patch));
+ if (!binary) {
+ opts[1] = "git-apply";
+ opt++; optc--;
+ }
+ write_tree(orig_tree, 0, NULL);
+ if (!cmd_apply(optc, (const char**)opt, env)) {
+ printf("Using index info to reconstruct a base tree...\n");
+ write_tree(his_tree, 0, NULL);
+
+ snprintf(cmd, sizeof(cmd), "git-merge-resolve %s -- HEAD %s", sha1_to_hex(orig_tree),
+ sha1_to_hex(his_tree));
+ ret = system(cmd);
+ }
+ }
+ if (*old_index)
+ setenv(INDEX_ENVIRONMENT, old_index, 1);
+ else
+ unsetenv(INDEX_ENVIRONMENT);
+#endif
+ if (!ret)
+ return 0;
+ }
+ if (!access(mkpath("%s/rr-cache/.", get_git_dir()), F_OK))
+ system("git-rerere");
+ die("Failed to merge in the changes.");
+}
+
+static int go_interactive(void)
+{
+ int action = AGAIN;
+
+ if (!isatty(0))
+ die("Cannot be interactive without stdin connected to a terminal.");
+
+ while (action == AGAIN) {
+ char line[1000];
+ FILE *cmt;
+
+ printf("Commit Body is:\n--------------------------\n");
+ cmt = fopen(mkpath("%s/final-commit", dotest), "r");
+ while (fgets(line, sizeof(line), cmt))
+ fputs(line, stdout);
+ fclose(cmt);
+ printf("--------------------------\nApply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all ");
+
+ fgets(line, sizeof(line), stdin);
+ switch (line[0]) {
+ case 'y':
+ case 'Y':
+ action = YES;
+ break;
+ case 'a':
+ case 'A':
+ action = YES;
+ interactive = 0;
+ break;
+ case 'n':
+ case 'N':
+ action = SKIP;
+ break;
+ case 'e':
+ case 'E':
+ system(mkpath("\"${VISUAL:-${EDITOR:-vi}}\" \"%s/final-commit\"", dotest));
+ action = AGAIN;
+ break;
+ case 'v':
+ case 'V':
+ system(mkpath("LESS=-S ${PAGER:-less} \"%s/patch\"", dotest));
+ action = AGAIN;
+ break;
+ default:
+ action = AGAIN;
+ break;
+ }
+ }
+ return action;
+}
+
+static int commit(char *subject)
+{
+ unsigned char sha1[20];
+ char commit[41], parent[41], cmd[1000];
+ FILE *f;
+ int status;
+
+ if (!write_tree(sha1, 0, NULL)) {
+ printf("Wrote tree %s\n", sha1_to_hex(sha1));
+ f = get_output("git-rev-parse --verify HEAD", &status);
+ if (!status) {
+ fgets(parent, 41, f);
+ fclose(f);
+ snprintf(cmd, sizeof(cmd), "git-commit-tree %s -p %s <\"%s/final-commit\"",
+ sha1_to_hex(sha1), parent, dotest);
+ f = get_output(cmd, &status);
+ if (!status) {
+ //git-update-ref -m "am: $SUBJECT" HEAD $commit $parent
+ char *opts[] = { "git-update-ref", "-m", NULL, "HEAD", NULL, NULL, NULL };
+ const char **opt = (const char**)&opts[0];
+ fgets(commit, 41, f);
+ fclose(f);
+ printf("Committed: %s\n", commit);
+ snprintf(cmd, sizeof(cmd), "am: %s", subject);
+ opts[2] = cmd;
+ opts[4] = commit;
+ opts[5] = parent;
+ if (!cmd_update_ref(ARRAY_SIZE(opts) - 1, opt, env))
+ return 0;
+ }
+ }
+ }
+ return -1;
+}
+
+int cmd_am(int argc, const char **argv, char **envp)
+{
+ int i, this, last, apply_status, action;
+ char sign[1000] = "";
+
+ env = envp;
+
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+
+ if (arg[0] != '-')
+ break;
+ if (!strcmp(arg, "--")) {
+ i++;
+ break;
+ }
+ if (!strcmp(arg, "-i") || !strcmp(arg, "--interactive")) {
+ interactive = 1;
+ continue;
+ }
+ if (!strcmp(arg, "-b") || !strcmp(arg, "--binary")) {
+ binary = 1;
+ continue;
+ }
+ if (!strcmp(arg, "-3") || !strcmp(arg, "--3way")) {
+ threeway = 1;
+ continue;
+ }
+ if (!strcmp(arg, "-s") || !strcmp(arg, "--signoff")) {
+ signoff = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--skip")) {
+ skip = 1;
+ continue;
+ }
+ if (!strcmp(arg, "-u") || !strcmp(arg, "--utf8")) {
+ utf8 = 1;
+ continue;
+ }
+ if (!strcmp(arg, "-k") || !strcmp(arg, "--keep")) {
+ keep_subject = 1;
+ continue;
+ }
+ if (!strcmp(arg, "-r") || !strcmp(arg, "--resolved")) {
+ resolved = 1;
+ continue;
+ }
+ if (!strncmp(arg, "--whitespace=", 13)) {
+ strncpy(whitespace, arg, sizeof(whitespace));
+ continue;
+ }
+ if (!strncmp(arg, "--resolvemsg=", 13)) {
+ resolvmsg = arg + 13;
+ continue;
+ }
+ if (!strncmp(arg, "--dotest", 8)) {
+ if (arg[8] == '=')
+ dotest = arg + 9;
+ else {
+ i++;
+ if (argv[i] == NULL)
+ die(builtin_am_usage);
+ dotest = argv[i];
+ }
+ continue;
+ }
+ usage(builtin_am_usage);
+ }
+ mbox = argv + i;
+
+ if (!dotest)
+ dotest = ".dotest";
+
+ /* Cleanup old .dotest */
+ if (mbox && !access(dotest, F_OK))
+ if (fcat("next", "%d", &this) && fcat("last", "%d", &last))
+ if (this > last)
+ rm_rf(dotest);
+
+ if (!access(dotest, F_OK)) {
+ if (mbox != NULL)
+ die("previous dotest directory \"%s\" still exists but mbox given.", dotest);
+ resume = 1;
+ } else {
+ if (skip || resolved)
+ die("Resolve operation not in progress, we are not resuming.");
+
+ if (mkdir_p(dotest))
+ die("Unable to create directory %s.", dotest);
+
+ if ((last = split_mbox(mbox, dotest, 1 /*allow bare*/, PATCH_PREC, 0 /*skip*/)) == -1) {
+ rm_rf(dotest);
+ die("split_mbox failed");
+ }
+
+ /*
+ -b, -s, -u, -k and --whitespace flags are kept for the
+ resuming session after a patch failure.
+ -3 and -i can and must be given when resuming.
+ */
+ fecho("binary", "%d\n", binary);
+ fecho("whitespace", "%s\n", whitespace);
+ fecho("sign", "%d\n", signoff);
+ fecho("utf8", "%d\n", utf8);
+ fecho("keep", "%d\n", keep_subject);
+ fecho("next", "%d\n", 1);
+ fecho("last", "%d\n", last);
+ }
+
+ if (!resolved) {
+ /* Make sure we have a clean index */
+ char buf[PATH_MAX];
+ int status = 0;
+ FILE *f;
+
+ if ((f = get_output("git-diff-index --name-only HEAD", &status)) == NULL || status)
+ die("Command: \"git-diff-index --name-only HEAD\" failed");
+
+ if ((status = fgetc(f)) != EOF) {
+ ungetc(status, f);
+ fprintf(stderr, "Dirty index: cannot apply patches. Dirty files:\n");
+ while (fgets(buf, sizeof(buf), f))
+ fprintf(stderr, "%s", buf);
+ return 1;
+ }
+ fclose(f);
+ }
+
+ /* Read back saved state */
+ fcat("binary", "%d", &binary);
+ fcat("utf8", "%d", &utf8);
+ fcat("keep", "%d", &keep_subject);
+ fcat("whitespace", "%40[^\n]", whitespace);
+ fcat("sign", "%d", &signoff);
+ fcat("last", "%d", &last);
+ fcat("next", "%d", &this);
+
+ if (this > last) {
+ printf("Nothing to do.\n");
+ rm_rf(dotest);
+ return 0;
+ }
+
+ if (signoff) {
+ int off = snprintf(sign, sizeof(sign), "Signed-off-by: %s <%s>",
+ getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL"));
+ if (off > sizeof(sign))
+ die ("Impossibly long committer identifier");
+ }
+
+ if (skip) {
+ this++;
+ resume = 0;
+ }
+
+ while (this <= last) {
+ char patch_no[PATCH_PREC + 1];
+ char name[1000];
+ char email[1000];
+ char date[1000];
+ char s[1000] = "[PATCH] ", *subject = &s[0];
+
+ snprintf(patch_no, sizeof(patch_no), "%0*d", PATCH_PREC, this);
+
+ if (access(mkpath("%s/%s", dotest, patch_no), F_OK)) {
+ resume = 0;
+ this = go_next(this);
+ continue;
+ }
+
+ /*
+ If we are not resuming, parse and extract the patch information
+ into separate files:
+ - info records the authorship and title
+ - msg is the rest of commit log message
+ - patch is the patch body.
+
+ When we are resuming, these files are either already prepared
+ by the user, or the user can tell us to do so by --resolved flag.
+ */
+ if (!resume) {
+ FILE *out, *in;
+ char msg_path[PATH_MAX];
+
+ if ((out = fopen(mkpath("%s/info", dotest), "w")) == NULL) {
+ perror(mkpath("%s/info", dotest));
+ die("fopen failed");
+ }
+ if ((in = fopen(mkpath("%s/%s", dotest, patch_no), "r")) == NULL) {
+ perror(mkpath("%s/%s", dotest, patch_no));
+ die("fopen failed");
+ }
+
+ snprintf(msg_path, sizeof(msg_path), "%s/msg", dotest);
+ if (mailinfo(in, out, keep_subject, utf8 ? git_commit_encoding : NULL,
+ msg_path, mkpath("%s/patch",dotest)))
+ stop_here(this);
+ fclose(in);
+ fclose(out);
+
+ in = fopen(msg_path, "r");
+ out = fopen(mkpath("%s/msg-clean", dotest), "w");
+ stripspace(in, out);
+ fclose(in);
+ fclose(out);
+ }
+
+ fcat("info", "Author: %1000[^\n]\nEmail: %1000s\n"
+ "Subject: %992[^\n]\nDate: %1000[^\n]\n\n",
+ name, email, subject + 8 /*[PATCH] */, date);
+
+ if (!keep_subject)
+ subject = subject + 8; /*[PATCH] */
+
+ if (email == NULL || !strcmp(email, "")) {
+ printf("Patch does not have a valid e-mail address.\n");
+ stop_here(this);
+ }
+
+ if (!resume) { /* Prepare the commit-message and the patch */
+ char c, *t;
+ char line[1000];
+ char last_signoff[1000] = "";
+ FILE *cmt, *msg;
+
+ /* Find the last Signed-off line */
+ msg = fopen(mkpath("%s/msg-clean", dotest), "r");
+ while ((fgets(line, sizeof(line), msg))) {
+ if ((t = strstr(line, "Signed-off-by: ")))
+ strncpy(last_signoff, t, sizeof(last_signoff));
+ }
+ if ((t = strrchr(last_signoff, '>')))
+ *++t = '\0';
+
+ /* Write the commit-mesage */
+ cmt = fopen(mkpath("%s/final-commit", dotest), "w");
+ fprintf(cmt, "%s\n", subject);
+
+ rewind(msg);
+ if ((c = fgetc(msg)) != EOF) {
+ fprintf(cmt, "\n");
+ ungetc(c, msg);
+ }
+ while (fgets(line, sizeof(line), msg))
+ fputs(line, cmt);
+
+ /* Add a signoff */
+ if (signoff && strcmp(last_signoff, sign)) {
+ if (!strcmp(last_signoff, ""))
+ fputc('\n', cmt);
+ fputs(sign, cmt);
+ }
+ fclose(cmt);
+ fclose(msg);
+ } else
+ if (resolved && interactive)
+ /* This is used only for interactive view option. */
+ system(mkpath("git-diff-index -p --cached HEAD >\"%s/patch\"", dotest));
+
+ resume = 0;
+ if (interactive)
+ action = go_interactive();
+ else
+ action = YES;
+
+ if (action == SKIP) {
+ this = go_next(this);
+ continue;
+ }
+
+ if (!access(mkpath("%s/hooks/applypatch-msg", get_git_dir()), X_OK))
+ if (system(mkpath("%s/hooks/applypatch-msg %s/final-commit", get_git_dir(), dotest)))
+ stop_here(this);
+
+ printf("\nApplying %s\n\n", subject);
+
+ if (!resolved) {
+ /*git-apply $binary --index $ws "$dotest/patch" */
+ char patch[PATH_MAX];
+ char *opts[6] = { "git-apply", "--allow-binary-replacement", "--index", NULL, NULL, NULL };
+ char **opt = &opts[0];
+ int optc = 5;
+
+ if (!binary) {
+ opts[1] = "git-apply";
+ opt++; optc--;
+ }
+ opts[3] = whitespace;
+ snprintf(patch, sizeof(patch), "%s/patch", dotest);
+ opts[4] = patch;
+ apply_status = cmd_apply(optc, (const char**)opt, envp);
+ } else {
+ /* Resolved means the user did all the hard work, and
+ we do not have to do any patch application. Just
+ trust what the user has in the index file and the
+ working tree.*/
+ resolved = 0;
+
+ if (has_zero_output("git-diff-index --cached --name-only HEAD")) {
+ printf("No changes - did you forget update-index?\n");
+ stop_here_user_resolve(this);
+ }
+ if (!has_zero_output("git-ls-files -u")) {
+ printf("You still have unmerged paths in your index,\n"
+ "did you forget update-index?");
+ stop_here_user_resolve(this);
+ }
+ apply_status = 0;
+ }
+
+ if (apply_status && threeway) {
+ fall_back_3way();
+ /* Applying the patch to an earlier tree and merging the
+ result may have produced the same tree as ours. */
+ if (has_zero_output("git-diff-index --cached --name-only HEAD")) {
+ printf("No changes -- Patch already applied.\n");
+ this = go_next(this);
+ continue;
+ }
+ /* We have merged successfully */
+ apply_status = 0;
+ }
+
+ if (apply_status) {
+ printf("Patch failed at %s\n.", patch_no);
+ stop_here_user_resolve(this);
+ }
+
+ if (!access(mkpath("%s/hooks/pre-applypatch", get_git_dir()), X_OK))
+ if (system(mkpath("%s/hooks/pre-applypatch", get_git_dir())))
+ stop_here(this);
+
+ if (commit(subject) == -1)
+ stop_here(this);
+
+ if (!access(mkpath("%s/hooks/post-applypatch", get_git_dir()), X_OK))
+ system(mkpath("%s/hooks/post-applypatch", get_git_dir()));
+
+ this = go_next(this);
+ }
+ rm_rf(dotest);
+ return 0;
+}
diff --git a/builtin.h b/builtin.h
index c1f3395..8771e36 100644
--- a/builtin.h
+++ b/builtin.h
@@ -49,6 +49,7 @@ extern int cmd_cat_file(int argc, const
extern int cmd_rev_parse(int argc, const char **argv, char **envp);
extern int cmd_update_index(int argc, const char **argv, char **envp);
extern int cmd_update_ref(int argc, const char **argv, char **envp);
+extern int cmd_am(int argc, const char **argv, char **envp);
extern int cmd_write_tree(int argc, const char **argv, char **envp);
extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
diff --git a/git-am.sh b/git-am.sh
deleted file mode 100755
index 4232e27..0000000
--- a/git-am.sh
+++ /dev/null
@@ -1,427 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005, 2006 Junio C Hamano
-
-USAGE='[--signoff] [--dotest=<dir>] [--utf8] [--binary] [--3way]
- [--interactive] [--whitespace=<option>] <mbox>...
- or, when resuming [--skip | --resolved]'
-. git-sh-setup
-
-git var GIT_COMMITTER_IDENT >/dev/null || exit
-
-stop_here () {
- echo "$1" >"$dotest/next"
- exit 1
-}
-
-stop_here_user_resolve () {
- if [ -n "$resolvemsg" ]; then
- echo "$resolvemsg"
- stop_here $1
- fi
- cmdline=$(basename $0)
- if test '' != "$interactive"
- then
- cmdline="$cmdline -i"
- fi
- if test '' != "$threeway"
- then
- cmdline="$cmdline -3"
- fi
- if test '.dotest' != "$dotest"
- then
- cmdline="$cmdline -d=$dotest"
- fi
- echo "When you have resolved this problem run \"$cmdline --resolved\"."
- echo "If you would prefer to skip this patch, instead run \"$cmdline --skip\"."
-
- stop_here $1
-}
-
-go_next () {
- rm -f "$dotest/$msgnum" "$dotest/msg" "$dotest/msg-clean" \
- "$dotest/patch" "$dotest/info"
- echo "$next" >"$dotest/next"
- this=$next
-}
-
-fall_back_3way () {
- O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
-
- rm -fr "$dotest"/patch-merge-*
- mkdir "$dotest/patch-merge-tmp-dir"
-
- # First see if the patch records the index info that we can use.
- if git-apply -z --index-info "$dotest/patch" \
- >"$dotest/patch-merge-index-info" 2>/dev/null &&
- GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
- git-update-index -z --index-info <"$dotest/patch-merge-index-info" &&
- GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
- git-write-tree >"$dotest/patch-merge-base+" &&
- # index has the base tree now.
- GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
- git-apply $binary --cached <"$dotest/patch"
- then
- echo Using index info to reconstruct a base tree...
- mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base"
- mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index"
- fi
-
- test -f "$dotest/patch-merge-index" &&
- his_tree=$(GIT_INDEX_FILE="$dotest/patch-merge-index" git-write-tree) &&
- orig_tree=$(cat "$dotest/patch-merge-base") &&
- rm -fr "$dotest"/patch-merge-* || exit 1
-
- echo Falling back to patching base and 3-way merge...
-
- # This is not so wrong. Depending on which base we picked,
- # orig_tree may be wildly different from ours, but his_tree
- # has the same set of wildly different changes in parts the
- # patch did not touch, so resolve ends up cancelling them,
- # saying that we reverted all those changes.
-
- git-merge-resolve $orig_tree -- HEAD $his_tree || {
- if test -d "$GIT_DIR/rr-cache"
- then
- git-rerere
- fi
- echo Failed to merge in the changes.
- exit 1
- }
-}
-
-prec=4
-dotest=.dotest sign= utf8= keep= skip= interactive= resolved= binary= ws= resolvemsg=
-
-while case "$#" in 0) break;; esac
-do
- case "$1" in
- -d=*|--d=*|--do=*|--dot=*|--dote=*|--dotes=*|--dotest=*)
- dotest=`expr "$1" : '-[^=]*=\(.*\)'`; shift ;;
- -d|--d|--do|--dot|--dote|--dotes|--dotest)
- case "$#" in 1) usage ;; esac; shift
- dotest="$1"; shift;;
-
- -i|--i|--in|--int|--inte|--inter|--intera|--interac|--interact|\
- --interacti|--interactiv|--interactive)
- interactive=t; shift ;;
-
- -b|--b|--bi|--bin|--bina|--binar|--binary)
- binary=t; shift ;;
-
- -3|--3|--3w|--3wa|--3way)
- threeway=t; shift ;;
- -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
- sign=t; shift ;;
- -u|--u|--ut|--utf|--utf8)
- utf8=t; shift ;;
- -k|--k|--ke|--kee|--keep)
- keep=t; shift ;;
-
- -r|--r|--re|--res|--reso|--resol|--resolv|--resolve|--resolved)
- resolved=t; shift ;;
-
- --sk|--ski|--skip)
- skip=t; shift ;;
-
- --whitespace=*)
- ws=$1; shift ;;
-
- --resolvemsg=*)
- resolvemsg=$(echo "$1" | sed -e "s/^--resolvemsg=//"); shift ;;
-
- --)
- shift; break ;;
- -*)
- usage ;;
- *)
- break ;;
- esac
-done
-
-# If the dotest directory exists, but we have finished applying all the
-# patches in them, clear it out.
-if test -d "$dotest" &&
- last=$(cat "$dotest/last") &&
- next=$(cat "$dotest/next") &&
- test $# != 0 &&
- test "$next" -gt "$last"
-then
- rm -fr "$dotest"
-fi
-
-if test -d "$dotest"
-then
- test ",$#," = ",0," ||
- die "previous dotest directory $dotest still exists but mbox given."
- resume=yes
-else
- # Make sure we are not given --skip nor --resolved
- test ",$skip,$resolved," = ,,, ||
- die "Resolve operation not in progress, we are not resuming."
-
- # Start afresh.
- mkdir -p "$dotest" || exit
-
- git-mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" || {
- rm -fr "$dotest"
- exit 1
- }
-
- # -b, -s, -u, -k and --whitespace flags are kept for the
- # resuming session after a patch failure.
- # -3 and -i can and must be given when resuming.
- echo "$binary" >"$dotest/binary"
- echo " $ws" >"$dotest/whitespace"
- echo "$sign" >"$dotest/sign"
- echo "$utf8" >"$dotest/utf8"
- echo "$keep" >"$dotest/keep"
- echo 1 >"$dotest/next"
-fi
-
-case "$resolved" in
-'')
- files=$(git-diff-index --cached --name-only HEAD) || exit
- if [ "$files" ]; then
- echo "Dirty index: cannot apply patches (dirty: $files)" >&2
- exit 1
- fi
-esac
-
-if test "$(cat "$dotest/binary")" = t
-then
- binary=--allow-binary-replacement
-fi
-if test "$(cat "$dotest/utf8")" = t
-then
- utf8=-u
-fi
-if test "$(cat "$dotest/keep")" = t
-then
- keep=-k
-fi
-ws=`cat "$dotest/whitespace"`
-if test "$(cat "$dotest/sign")" = t
-then
- SIGNOFF=`git-var GIT_COMMITTER_IDENT | sed -e '
- s/>.*/>/
- s/^/Signed-off-by: /'
- `
-else
- SIGNOFF=
-fi
-
-last=`cat "$dotest/last"`
-this=`cat "$dotest/next"`
-if test "$skip" = t
-then
- this=`expr "$this" + 1`
- resume=
-fi
-
-if test "$this" -gt "$last"
-then
- echo Nothing to do.
- rm -fr "$dotest"
- exit
-fi
-
-while test "$this" -le "$last"
-do
- msgnum=`printf "%0${prec}d" $this`
- next=`expr "$this" + 1`
- test -f "$dotest/$msgnum" || {
- resume=
- go_next
- continue
- }
-
- # If we are not resuming, parse and extract the patch information
- # into separate files:
- # - info records the authorship and title
- # - msg is the rest of commit log message
- # - patch is the patch body.
- #
- # When we are resuming, these files are either already prepared
- # by the user, or the user can tell us to do so by --resolved flag.
- case "$resume" in
- '')
- git-mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \
- <"$dotest/$msgnum" >"$dotest/info" ||
- stop_here $this
- git-stripspace < "$dotest/msg" > "$dotest/msg-clean"
- ;;
- esac
-
- GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$dotest/info")"
- GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$dotest/info")"
- GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$dotest/info")"
-
- if test -z "$GIT_AUTHOR_EMAIL"
- then
- echo "Patch does not have a valid e-mail address."
- stop_here $this
- fi
-
- export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
-
- SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")"
- case "$keep_subject" in -k) SUBJECT="[PATCH] $SUBJECT" ;; esac
-
- case "$resume" in
- '')
- if test '' != "$SIGNOFF"
- then
- LAST_SIGNED_OFF_BY=`
- sed -ne '/^Signed-off-by: /p' \
- "$dotest/msg-clean" |
- tail -n 1
- `
- ADD_SIGNOFF=`
- test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || {
- test '' = "$LAST_SIGNED_OFF_BY" && echo
- echo "$SIGNOFF"
- }`
- else
- ADD_SIGNOFF=
- fi
- {
- echo "$SUBJECT"
- if test -s "$dotest/msg-clean"
- then
- echo
- cat "$dotest/msg-clean"
- fi
- if test '' != "$ADD_SIGNOFF"
- then
- echo "$ADD_SIGNOFF"
- fi
- } >"$dotest/final-commit"
- ;;
- *)
- case "$resolved$interactive" in
- tt)
- # This is used only for interactive view option.
- git-diff-index -p --cached HEAD >"$dotest/patch"
- ;;
- esac
- esac
-
- resume=
- if test "$interactive" = t
- then
- test -t 0 ||
- die "cannot be interactive without stdin connected to a terminal."
- action=again
- while test "$action" = again
- do
- echo "Commit Body is:"
- echo "--------------------------"
- cat "$dotest/final-commit"
- echo "--------------------------"
- printf "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
- read reply
- case "$reply" in
- [yY]*) action=yes ;;
- [aA]*) action=yes interactive= ;;
- [nN]*) action=skip ;;
- [eE]*) "${VISUAL:-${EDITOR:-vi}}" "$dotest/final-commit"
- action=again ;;
- [vV]*) action=again
- LESS=-S ${PAGER:-less} "$dotest/patch" ;;
- *) action=again ;;
- esac
- done
- else
- action=yes
- fi
-
- if test $action = skip
- then
- go_next
- continue
- fi
-
- if test -x "$GIT_DIR"/hooks/applypatch-msg
- then
- "$GIT_DIR"/hooks/applypatch-msg "$dotest/final-commit" ||
- stop_here $this
- fi
-
- echo
- echo "Applying '$SUBJECT'"
- echo
-
- case "$resolved" in
- '')
- git-apply $binary --index $ws "$dotest/patch"
- apply_status=$?
- ;;
- t)
- # Resolved means the user did all the hard work, and
- # we do not have to do any patch application. Just
- # trust what the user has in the index file and the
- # working tree.
- resolved=
- changed="$(git-diff-index --cached --name-only HEAD)"
- if test '' = "$changed"
- then
- echo "No changes - did you forget update-index?"
- stop_here_user_resolve $this
- fi
- unmerged=$(git-ls-files -u)
- if test -n "$unmerged"
- then
- echo "You still have unmerged paths in your index"
- echo "did you forget update-index?"
- stop_here_user_resolve $this
- fi
- apply_status=0
- ;;
- esac
-
- if test $apply_status = 1 && test "$threeway" = t
- then
- if (fall_back_3way)
- then
- # Applying the patch to an earlier tree and merging the
- # result may have produced the same tree as ours.
- changed="$(git-diff-index --cached --name-only HEAD)"
- if test '' = "$changed"
- then
- echo No changes -- Patch already applied.
- go_next
- continue
- fi
- # clear apply_status -- we have successfully merged.
- apply_status=0
- fi
- fi
- if test $apply_status != 0
- then
- echo Patch failed at $msgnum.
- stop_here_user_resolve $this
- fi
-
- if test -x "$GIT_DIR"/hooks/pre-applypatch
- then
- "$GIT_DIR"/hooks/pre-applypatch || stop_here $this
- fi
-
- tree=$(git-write-tree) &&
- echo Wrote tree $tree &&
- parent=$(git-rev-parse --verify HEAD) &&
- commit=$(git-commit-tree $tree -p $parent <"$dotest/final-commit") &&
- echo Committed: $commit &&
- git-update-ref -m "am: $SUBJECT" HEAD $commit $parent ||
- stop_here $this
-
- if test -x "$GIT_DIR"/hooks/post-applypatch
- then
- "$GIT_DIR"/hooks/post-applypatch
- fi
-
- go_next
-done
-
-rm -fr "$dotest"
diff --git a/git.c b/git.c
index 652e3c4..b9261e4 100644
--- a/git.c
+++ b/git.c
@@ -184,7 +184,8 @@ static void handle_internal_command(int
{ "mailinfo", cmd_mailinfo },
{ "stripspace", cmd_stripspace },
{ "update-index", cmd_update_index },
- { "update-ref", cmd_update_ref }
+ { "update-ref", cmd_update_ref },
+ { "am", cmd_am }
};
int i;
--
1.4.0
^ permalink raw reply related
* [PATCH 5/8] Make git-update-index a builtin
From: Lukas Sandström @ 2006-06-13 20:21 UTC (permalink / raw)
To: Junio C Hamano, Git Mailing List; +Cc: Lukas Sandström
In-Reply-To: <448EF791.7070504@etek.chalmers.se>
Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>
---
Makefile | 6 +++---
update-index.c => builtin-update-index.c | 19 ++++++++++++-------
builtin.h | 1 +
git.c | 3 ++-
4 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/Makefile b/Makefile
index 181255f..906fc0f 100644
--- a/Makefile
+++ b/Makefile
@@ -157,7 +157,7 @@ PROGRAMS = \
git-send-pack$X git-shell$X \
git-show-index$X git-ssh-fetch$X \
git-ssh-upload$X git-unpack-file$X \
- git-unpack-objects$X git-update-index$X git-update-server-info$X \
+ git-unpack-objects$X git-update-server-info$X \
git-upload-pack$X git-verify-pack$X \
git-update-ref$X git-symbolic-ref$X \
git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \
@@ -170,7 +170,7 @@ BUILT_INS = git-log$X git-whatchanged$X
git-init-db$X git-tar-tree$X git-upload-tar$X git-format-patch$X \
git-ls-files$X git-ls-tree$X git-get-tar-commit-id$X \
git-read-tree$X git-commit-tree$X git-write-tree$X \
- git-apply$X git-show-branch$X git-diff-files$X \
+ git-apply$X git-show-branch$X git-diff-files$X git-update-index$X \
git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X
# what 'all' will build and 'install' will install, in gitexecdir
@@ -221,7 +221,7 @@ BUILTIN_OBJS = \
builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
builtin-grep.o builtin-add.o builtin-rev-list.o builtin-check-ref-format.o \
builtin-rm.o builtin-init-db.o builtin-rev-parse.o \
- builtin-tar-tree.o builtin-upload-tar.o \
+ builtin-tar-tree.o builtin-upload-tar.o builtin-update-index.o \
builtin-ls-files.o builtin-ls-tree.o builtin-write-tree.o \
builtin-read-tree.o builtin-commit-tree.o builtin-mailinfo.o \
builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
diff --git a/update-index.c b/builtin-update-index.c
similarity index 97%
rename from update-index.c
rename to builtin-update-index.c
index fbccc4a..325cd09 100644
--- a/update-index.c
+++ b/builtin-update-index.c
@@ -8,6 +8,7 @@ #include "strbuf.h"
#include "quote.h"
#include "cache-tree.h"
#include "tree-walk.h"
+#include "builtin.h"
/*
* Default to not allowing changes to the list of files. The
@@ -186,8 +187,6 @@ static void chmod_path(int flip, const c
die("git-update-index: cannot chmod %cx '%s'", flip, path);
}
-static struct lock_file lock_file;
-
static void update_one(const char *path, const char *prefix, int prefix_length)
{
const char *p = prefix_path(prefix, prefix_length, path);
@@ -238,7 +237,7 @@ static void read_index_info(int line_ter
* (2) mode SP type SP sha1 TAB path
* The second format is to stuff git-ls-tree output
* into the index file.
- *
+ *
* (3) mode SP sha1 SP stage TAB path
* This format is to put higher order stages into the
* index file and matches git-ls-files --stage output.
@@ -477,7 +476,7 @@ static int do_reupdate(int ac, const cha
return 0;
}
-int main(int argc, const char **argv)
+int cmd_update_index(int argc, const char **argv, char **envp)
{
int i, newfd, entries, has_errors = 0, line_termination = '\n';
int allow_options = 1;
@@ -486,12 +485,16 @@ int main(int argc, const char **argv)
int prefix_length = prefix ? strlen(prefix) : 0;
char set_executable_bit = 0;
unsigned int refresh_flags = 0;
+ struct lock_file *lock_file;
git_config(git_default_config);
- newfd = hold_lock_file_for_update(&lock_file, get_index_file());
+ /* We can't free this memory, it becomes part of a linked list parsed atexit() */
+ lock_file = xmalloc(sizeof(struct lock_file));
+
+ newfd = hold_lock_file_for_update(lock_file, get_index_file());
if (newfd < 0)
- die("unable to create new index file");
+ die("unable to create new cachefile");
entries = read_cache();
if (entries < 0)
@@ -645,9 +648,11 @@ int main(int argc, const char **argv)
finish:
if (active_cache_changed) {
if (write_cache(newfd, active_cache, active_nr) ||
- commit_lock_file(&lock_file))
+ commit_lock_file(lock_file))
die("Unable to write new index file");
}
+ rollback_lock_file(lock_file);
+
return has_errors ? 1 : 0;
}
diff --git a/builtin.h b/builtin.h
index c934d7a..9ee5ea6 100644
--- a/builtin.h
+++ b/builtin.h
@@ -47,6 +47,7 @@ extern int cmd_diff_stages(int argc, con
extern int cmd_diff_tree(int argc, const char **argv, char **envp);
extern int cmd_cat_file(int argc, const char **argv, char **envp);
extern int cmd_rev_parse(int argc, const char **argv, char **envp);
+extern int cmd_update_index(int argc, const char **argv, char **envp);
extern int cmd_write_tree(int argc, const char **argv, char **envp);
extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
diff --git a/git.c b/git.c
index 31196f5..4a931fb 100644
--- a/git.c
+++ b/git.c
@@ -182,7 +182,8 @@ static void handle_internal_command(int
{ "write-tree", cmd_write_tree },
{ "mailsplit", cmd_mailsplit },
{ "mailinfo", cmd_mailinfo },
- { "stripspace", cmd_stripspace }
+ { "stripspace", cmd_stripspace },
+ { "update-index", cmd_update_index }
};
int i;
--
1.4.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox