* 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
* [PATCH 6/8] Make git-update-ref 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>
---
Makefile | 7 ++++---
update-ref.c => builtin-update-ref.c | 5 ++++-
builtin.h | 1 +
git.c | 3 ++-
4 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/Makefile b/Makefile
index 906fc0f..4b30ca0 100644
--- a/Makefile
+++ b/Makefile
@@ -159,11 +159,11 @@ PROGRAMS = \
git-ssh-upload$X git-unpack-file$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-symbolic-ref$X \
git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \
git-describe$X git-merge-tree$X git-blame$X git-imap-send$X
-BUILT_INS = git-log$X git-whatchanged$X git-show$X \
+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 \
@@ -226,7 +226,8 @@ BUILTIN_OBJS = \
builtin-read-tree.o builtin-commit-tree.o builtin-mailinfo.o \
builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
- builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o
+ builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \
+ builtin-update-ref.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/update-ref.c b/builtin-update-ref.c
similarity index 89%
rename from update-ref.c
rename to builtin-update-ref.c
index a1e6bb9..00333c7 100644
--- a/update-ref.c
+++ b/builtin-update-ref.c
@@ -1,10 +1,11 @@
#include "cache.h"
#include "refs.h"
+#include "builtin.h"
static const char git_update_ref_usage[] =
"git-update-ref <refname> <value> [<oldval>] [-m <reason>]";
-int main(int argc, char **argv)
+int cmd_update_ref(int argc, const char **argv, char **envp)
{
const char *refname=NULL, *value=NULL, *oldval=NULL, *msg=NULL;
struct ref_lock *lock;
@@ -52,5 +53,7 @@ int main(int argc, char **argv)
return 1;
if (write_ref_sha1(lock, sha1, msg) < 0)
return 1;
+
+ /* write_ref_sha1 always unlocks the ref, no need to do it explicitly */
return 0;
}
diff --git a/builtin.h b/builtin.h
index 9ee5ea6..c1f3395 100644
--- a/builtin.h
+++ b/builtin.h
@@ -48,6 +48,7 @@ extern int cmd_diff_tree(int argc, const
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_update_ref(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 4a931fb..652e3c4 100644
--- a/git.c
+++ b/git.c
@@ -183,7 +183,8 @@ static void handle_internal_command(int
{ "mailsplit", cmd_mailsplit },
{ "mailinfo", cmd_mailinfo },
{ "stripspace", cmd_stripspace },
- { "update-index", cmd_update_index }
+ { "update-index", cmd_update_index },
+ { "update-ref", cmd_update_ref }
};
int i;
--
1.4.0
^ permalink raw reply related
* [PATCH 7/8] Make it possible to call cmd_apply multiple times
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>
* xmalloc a new struct lock_file each invocation.
* Don't die() if the patch doesn't apply.
* Initialize the global variables each invocation.
* Roll back the lock_file.
Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>
---
builtin-apply.c | 94 +++++++++++++++++++++++++++++++++++--------------------
1 files changed, 60 insertions(+), 34 deletions(-)
diff --git a/builtin-apply.c b/builtin-apply.c
index e113c74..a76c553 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -22,24 +22,13 @@ #include "builtin.h"
// --index updates the cache as well.
// --cached updates only the cache without ever touching the working tree.
//
-static const char *prefix;
-static int prefix_length = -1;
-static int newfd = -1;
-
-static int p_value = 1;
-static int allow_binary_replacement = 0;
-static int check_index = 0;
-static int write_index = 0;
-static int cached = 0;
-static int diffstat = 0;
-static int numstat = 0;
-static int summary = 0;
-static int check = 0;
-static int apply = 1;
-static int no_add = 0;
-static int show_index_info = 0;
-static int line_termination = '\n';
+static const char *prefix, *patch_input_file;
+static int prefix_length, newfd, p_value, allow_binary_replacement, check_index,
+ write_index, cached, diffstat, numstat, summary, check, apply, no_add,
+ show_index_info, line_termination, whitespace_error, squelch_whitespace_errors,
+ applied_after_stripping;
static unsigned long p_context = -1;
+
static const char apply_usage[] =
"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>...";
@@ -49,10 +38,31 @@ static enum whitespace_eol {
error_on_whitespace,
strip_whitespace,
} new_whitespace = warn_on_whitespace;
-static int whitespace_error = 0;
-static int squelch_whitespace_errors = 5;
-static int applied_after_stripping = 0;
-static const char *patch_input_file = NULL;
+
+static void setup_state()
+{
+ prefix = NULL;
+ prefix_length = -1;
+ newfd = -1;
+ p_value = 1;
+ allow_binary_replacement = 0;
+ check_index = 0;
+ write_index = 0;
+ cached = 0;
+ diffstat = 0;
+ numstat = 0;
+ summary = 0;
+ check = 0;
+ apply = 1;
+ no_add = 0;
+ show_index_info = 0;
+ line_termination = '\n';
+ p_context = -1;
+ whitespace_error = 0;
+ squelch_whitespace_errors = 5;
+ applied_after_stripping = 0;
+ patch_input_file = NULL;
+}
static void parse_whitespace_option(const char *option)
{
@@ -2072,7 +2082,7 @@ static void write_out_results(struct pat
}
}
-static struct lock_file lock_file;
+static struct lock_file *lock_file;
static struct excludes {
struct excludes *next;
@@ -2106,7 +2116,7 @@ static int apply_patch(int fd, const cha
patch_input_file = filename;
if (!buffer)
- return -1;
+ return -2;
offset = 0;
while (size > 0) {
struct patch *patch;
@@ -2134,7 +2144,7 @@ static int apply_patch(int fd, const cha
write_index = check_index && apply;
if (write_index && newfd < 0) {
- newfd = hold_lock_file_for_update(&lock_file,
+ newfd = hold_lock_file_for_update(lock_file,
get_index_file());
if (newfd < 0)
die("unable to create new index file");
@@ -2145,7 +2155,7 @@ static int apply_patch(int fd, const cha
}
if ((check || apply) && check_patch_list(list) < 0)
- exit(1);
+ return -1;
if (apply)
write_out_results(list, skipped_patch);
@@ -2175,20 +2185,27 @@ static int git_apply_config(const char *
return git_default_config(var, value);
}
-
int cmd_apply(int argc, const char **argv, char **envp)
{
- int i;
+ int i, ret = 0;
int read_stdin = 1;
const char *whitespace_option = NULL;
+ setup_state();
+
+ /* This memory can't be free()'d since it's needed atexit() */
+ lock_file = xmalloc(sizeof(struct lock_file));
+
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
char *end;
- int fd;
+ int fd, apply_status;
if (!strcmp(arg, "-")) {
- apply_patch(0, "<stdin>");
+ if (apply_patch(0, "<stdin>")) {
+ ret = 1;
+ goto err;
+ }
read_stdin = 0;
continue;
}
@@ -2281,12 +2298,18 @@ int cmd_apply(int argc, const char **arg
usage(apply_usage);
read_stdin = 0;
set_default_whitespace_mode(whitespace_option);
- apply_patch(fd, arg);
+ apply_status = apply_patch(fd, arg);
close(fd);
+ if (apply_status) {
+ ret = 1;
+ goto err;
+ }
}
set_default_whitespace_mode(whitespace_option);
- if (read_stdin)
- apply_patch(0, "<stdin>");
+ if (read_stdin && apply_patch(0, "<stdin>")) {
+ ret = 1;
+ goto err;
+ }
if (whitespace_error) {
if (squelch_whitespace_errors &&
squelch_whitespace_errors < whitespace_error) {
@@ -2316,9 +2339,12 @@ int cmd_apply(int argc, const char **arg
if (write_index) {
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");
}
- return 0;
+err:
+ rollback_lock_file(lock_file);
+
+ return ret;
}
--
1.4.0
^ permalink raw reply related
* [PATCH 4/8] Make git-stripspace 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 +++---
stripspace.c => builtin-stripspace.c | 16 +++++++++++-----
builtin.h | 6 ++++--
git.c | 3 ++-
4 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/Makefile b/Makefile
index e64d943..181255f 100644
--- a/Makefile
+++ b/Makefile
@@ -144,7 +144,7 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)
# The ones that do not have to link with lcrypto, lz nor xdiff.
SIMPLE_PROGRAMS = \
- git-stripspace$X git-daemon$X
+ git-daemon$X
# ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS = \
@@ -165,7 +165,7 @@ PROGRAMS = \
BUILT_INS = git-log$X git-whatchanged$X git-show$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-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-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 \
@@ -226,7 +226,7 @@ BUILTIN_OBJS = \
builtin-read-tree.o builtin-commit-tree.o builtin-mailinfo.o \
builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
- builtin-cat-file.o builtin-mailsplit.o
+ builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/stripspace.c b/builtin-stripspace.c
similarity index 76%
rename from stripspace.c
rename to builtin-stripspace.c
index 65a6346..2ce1264 100644
--- a/stripspace.c
+++ b/builtin-stripspace.c
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <string.h>
#include <ctype.h>
+#include "builtin.h"
/*
* Remove empty lines from the beginning and end.
@@ -28,21 +29,21 @@ static int cleanup(char *line)
return 1;
}
-int main(int argc, char **argv)
+void stripspace(FILE *in, FILE *out)
{
int empties = -1;
int incomplete = 0;
char line[1024];
- while (fgets(line, sizeof(line), stdin)) {
+ while (fgets(line, sizeof(line), in)) {
incomplete = cleanup(line);
/* Not just an empty line? */
if (line[0] != '\n') {
if (empties > 0)
- putchar('\n');
+ fputc('\n', out);
empties = 0;
- fputs(line, stdout);
+ fputs(line, out);
continue;
}
if (empties < 0)
@@ -50,6 +51,11 @@ int main(int argc, char **argv)
empties++;
}
if (incomplete)
- putchar('\n');
+ fputc('\n', out);
+}
+
+int cmd_stripspace(int argc, const char **argv, char **envp)
+{
+ stripspace(stdin, stdout);
return 0;
}
diff --git a/builtin.h b/builtin.h
index 979e0cd..c934d7a 100644
--- a/builtin.h
+++ b/builtin.h
@@ -55,6 +55,8 @@ extern int cmd_mailsplit(int argc, const
extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
extern int cmd_mailinfo(int argc, const char **argv, char **envp);
-extern int mailinfo(FILE *in, FILE *out, int ks, char *encoding,
- const char *msg, const char *patch);
+extern int mailinfo(FILE *in, FILE *out, int ks, char *encoding, const char *msg, const char *patch);
+
+extern int cmd_stripspace(int argc, const char **argv, char **envp);
+extern void stripspace(FILE *in, FILE *out);
#endif
diff --git a/git.c b/git.c
index 1e216de..31196f5 100644
--- a/git.c
+++ b/git.c
@@ -181,7 +181,8 @@ static void handle_internal_command(int
{ "rev-parse", cmd_rev_parse },
{ "write-tree", cmd_write_tree },
{ "mailsplit", cmd_mailsplit },
- { "mailinfo", cmd_mailinfo }
+ { "mailinfo", cmd_mailinfo },
+ { "stripspace", cmd_stripspace }
};
int i;
--
1.4.0
^ permalink raw reply related
* [PATCH 3/8] Make git-mailinfo 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 | 12 ++---
mailinfo.c => builtin-mailinfo.c | 85 ++++++++++++++++++++++----------------
builtin.h | 6 +++
git.c | 3 +
4 files changed, 62 insertions(+), 44 deletions(-)
diff --git a/Makefile b/Makefile
index 7bee30d..e64d943 100644
--- a/Makefile
+++ b/Makefile
@@ -151,7 +151,7 @@ PROGRAMS = \
git-checkout-index$X git-clone-pack$X \
git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \
git-hash-object$X git-index-pack$X git-local-fetch$X \
- git-mailinfo$X git-merge-base$X \
+ git-merge-base$X \
git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
git-peek-remote$X git-prune-packed$X git-receive-pack$X \
git-send-pack$X git-shell$X \
@@ -166,7 +166,7 @@ PROGRAMS = \
BUILT_INS = git-log$X git-whatchanged$X git-show$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-check-ref-format$X git-rev-parse$X \
+ git-check-ref-format$X git-rev-parse$X git-mailinfo$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 \
@@ -223,7 +223,7 @@ BUILTIN_OBJS = \
builtin-rm.o builtin-init-db.o builtin-rev-parse.o \
builtin-tar-tree.o builtin-upload-tar.o \
builtin-ls-files.o builtin-ls-tree.o builtin-write-tree.o \
- builtin-read-tree.o builtin-commit-tree.o \
+ builtin-read-tree.o builtin-commit-tree.o builtin-mailinfo.o \
builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
builtin-cat-file.o builtin-mailsplit.o
@@ -486,7 +486,7 @@ strip: $(PROGRAMS) git$X
git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS)
$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
$(ALL_CFLAGS) -o $@ $(filter %.c,$^) \
- $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
+ $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS) $(LIB_4_ICONV)
builtin-help.o: common-cmds.h
@@ -563,10 +563,6 @@ git-%$X: %.o $(GITLIBS)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIB_FILE) $(SIMPLE_LIB)
-git-mailinfo$X: mailinfo.o $(LIB_FILE)
- $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
- $(LIB_FILE) $(SIMPLE_LIB) $(LIB_4_ICONV)
-
git-local-fetch$X: fetch.o
git-ssh-fetch$X: rsh.o fetch.o
git-ssh-upload$X: rsh.o
diff --git a/mailinfo.c b/builtin-mailinfo.c
similarity index 94%
rename from mailinfo.c
rename to builtin-mailinfo.c
index 5b6c215..6e30758 100644
--- a/mailinfo.c
+++ b/builtin-mailinfo.c
@@ -12,8 +12,9 @@ #include <iconv.h>
#endif
#include "git-compat-util.h"
#include "cache.h"
+#include "builtin.h"
-static FILE *cmitmsg, *patchfile;
+static FILE *cmitmsg, *patchfile, *fin, *fout;
static int keep_subject = 0;
static char *metainfo_charset = NULL;
@@ -49,7 +50,7 @@ static int bogus_from(char *line)
/* This is fallback, so do not bother if we already have an
* e-mail address.
- */
+ */
if (*email)
return 0;
@@ -311,12 +312,12 @@ static char *cleanup_subject(char *subje
if (remove <= len *2) {
subject = p+1;
continue;
- }
+ }
break;
}
return subject;
}
-}
+}
static void cleanup_space(char *buf)
{
@@ -638,7 +639,7 @@ static void handle_info(void)
cleanup_space(email);
cleanup_space(sub);
- printf("Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n",
+ fprintf(fout, "Author: %s\nEmail: %s\nSubject: %s\nDate: %s\n\n",
name, email, sub, date);
}
@@ -675,7 +676,7 @@ static int handle_commit_msg(int *seen)
continue;
fputs(line, cmitmsg);
- } while (fgets(line, sizeof(line), stdin) != NULL);
+ } while (fgets(line, sizeof(line), fin) != NULL);
fclose(cmitmsg);
cmitmsg = NULL;
return 0;
@@ -696,7 +697,7 @@ static void handle_patch(void)
decode_transfer_encoding(line);
fputs(line, patchfile);
patch_lines++;
- } while (fgets(line, sizeof(line), stdin) != NULL);
+ } while (fgets(line, sizeof(line), fin) != NULL);
}
/* multipart boundary and transfer encoding are set up for us, and we
@@ -709,7 +710,7 @@ static int handle_multipart_one_part(int
{
int n = 0;
- while (fgets(line, sizeof(line), stdin) != NULL) {
+ while (fgets(line, sizeof(line), fin) != NULL) {
again:
n++;
if (is_multipart_boundary(line))
@@ -730,7 +731,7 @@ static void handle_multipart_body(void)
int part_num = 0;
/* Skip up to the first boundary */
- while (fgets(line, sizeof(line), stdin) != NULL)
+ while (fgets(line, sizeof(line), fin) != NULL)
if (is_multipart_boundary(line)) {
part_num = 1;
break;
@@ -739,7 +740,7 @@ static void handle_multipart_body(void)
return;
/* We are on boundary line. Start slurping the subhead. */
while (1) {
- int hdr = read_one_header_line(line, sizeof(line), stdin);
+ int hdr = read_one_header_line(line, sizeof(line), fin);
if (!hdr) {
if (handle_multipart_one_part(&seen) < 0)
return;
@@ -762,7 +763,7 @@ static void handle_body(void)
{
int seen = 0;
- if (line[0] || fgets(line, sizeof(line), stdin) != NULL) {
+ if (line[0] || fgets(line, sizeof(line), fin) != NULL) {
handle_commit_msg(&seen);
handle_patch();
}
@@ -773,10 +774,45 @@ static void handle_body(void)
}
}
+int mailinfo(FILE *in, FILE *out, int ks, char *encoding,
+ const char *msg, const char *patch)
+{
+ keep_subject = ks;
+ metainfo_charset = encoding;
+ fin = in;
+ fout = out;
+
+ cmitmsg = fopen(msg, "w");
+ if (!cmitmsg) {
+ perror(msg);
+ return -1;
+ }
+ patchfile = fopen(patch, "w");
+ if (!patchfile) {
+ perror(patch);
+ fclose(cmitmsg);
+ return -1;
+ }
+ while (1) {
+ int hdr = read_one_header_line(line, sizeof(line), fin);
+ if (!hdr) {
+ if (multipart_boundary[0])
+ handle_multipart_body();
+ else
+ handle_body();
+ handle_info();
+ break;
+ }
+ check_header_line(line);
+ }
+
+ return 0;
+}
+
static const char mailinfo_usage[] =
"git-mailinfo [-k] [-u | --encoding=<encoding>] msg patch <mail >info";
-int main(int argc, char **argv)
+int cmd_mailinfo(int argc, const char **argv, char **envp)
{
/* NEEDSWORK: might want to do the optional .git/ directory
* discovery
@@ -797,27 +833,6 @@ int main(int argc, char **argv)
if (argc != 3)
usage(mailinfo_usage);
- cmitmsg = fopen(argv[1], "w");
- if (!cmitmsg) {
- perror(argv[1]);
- exit(1);
- }
- patchfile = fopen(argv[2], "w");
- if (!patchfile) {
- perror(argv[2]);
- exit(1);
- }
- while (1) {
- int hdr = read_one_header_line(line, sizeof(line), stdin);
- if (!hdr) {
- if (multipart_boundary[0])
- handle_multipart_body();
- else
- handle_body();
- handle_info();
- break;
- }
- check_header_line(line);
- }
- return 0;
+
+ return !!mailinfo(stdin, stdout, keep_subject, metainfo_charset, argv[1], argv[2]);
}
diff --git a/builtin.h b/builtin.h
index 92e1e1b..979e0cd 100644
--- a/builtin.h
+++ b/builtin.h
@@ -1,6 +1,8 @@
#ifndef BUILTIN_H
#define BUILTIN_H
+#include <stdio.h>
+
#ifndef PATH_MAX
# define PATH_MAX 4096
#endif
@@ -51,4 +53,8 @@ extern int write_tree(unsigned char *sha
extern int cmd_mailsplit(int argc, const char **argv, char **envp);
extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
+
+extern int cmd_mailinfo(int argc, const char **argv, char **envp);
+extern int mailinfo(FILE *in, FILE *out, int ks, char *encoding,
+ const char *msg, const char *patch);
#endif
diff --git a/git.c b/git.c
index 3264c65..1e216de 100644
--- a/git.c
+++ b/git.c
@@ -180,7 +180,8 @@ static void handle_internal_command(int
{ "cat-file", cmd_cat_file },
{ "rev-parse", cmd_rev_parse },
{ "write-tree", cmd_write_tree },
- { "mailsplit", cmd_mailsplit }
+ { "mailsplit", cmd_mailsplit },
+ { "mailinfo", cmd_mailinfo }
};
int i;
--
1.4.0
^ permalink raw reply related
* [PATCH 2/8] Make git-mailsplit 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 | 5 +--
mailsplit.c => builtin-mailsplit.c | 71 +++++++++++++++++++++---------------
builtin.h | 2 +
git.c | 3 +-
4 files changed, 48 insertions(+), 33 deletions(-)
diff --git a/Makefile b/Makefile
index 37b5e40..7bee30d 100644
--- a/Makefile
+++ b/Makefile
@@ -144,7 +144,6 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)
# The ones that do not have to link with lcrypto, lz nor xdiff.
SIMPLE_PROGRAMS = \
- git-mailsplit$X \
git-stripspace$X git-daemon$X
# ... and all the rest that could be moved out of bindir to gitexecdir
@@ -165,7 +164,7 @@ PROGRAMS = \
git-describe$X git-merge-tree$X git-blame$X git-imap-send$X
BUILT_INS = git-log$X git-whatchanged$X git-show$X \
- git-count-objects$X git-diff$X git-push$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-check-ref-format$X git-rev-parse$X \
git-init-db$X git-tar-tree$X git-upload-tar$X git-format-patch$X \
@@ -227,7 +226,7 @@ BUILTIN_OBJS = \
builtin-read-tree.o builtin-commit-tree.o \
builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
- builtin-cat-file.o
+ builtin-cat-file.o builtin-mailsplit.o
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
LIBS = $(GITLIBS) -lz
diff --git a/mailsplit.c b/builtin-mailsplit.c
similarity index 85%
rename from mailsplit.c
rename to builtin-mailsplit.c
index 70a569c..e2a0058 100644
--- a/mailsplit.c
+++ b/builtin-mailsplit.c
@@ -12,6 +12,7 @@ #include <sys/stat.h>
#include <string.h>
#include <stdio.h>
#include "cache.h"
+#include "builtin.h"
static const char git_mailsplit_usage[] =
"git-mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> <mbox>...";
@@ -102,14 +103,48 @@ static int split_one(FILE *mbox, const c
exit(1);
}
-int main(int argc, const char **argv)
+int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip)
{
- int nr = 0, nr_prec = 4;
+ char *name = xmalloc(strlen(dir) + 2 + 3 * sizeof(skip));
+ int ret = -1;
+
+ while (*mbox) {
+ const char *file = *mbox++;
+ FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
+ int file_done = 0;
+
+ if ( !f ) {
+ error("cannot open mbox %s", file);
+ goto out;
+ }
+
+ if (fgets(buf, sizeof(buf), f) == NULL) {
+ if (f == stdin)
+ break; /* empty stdin is OK */
+ error("cannot read mbox %s", file);
+ goto out;
+ }
+
+ while (!file_done) {
+ sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+ file_done = split_one(f, name, allow_bare);
+ }
+
+ if (f != stdin)
+ fclose(f);
+ }
+ ret = skip;
+out:
+ free(name);
+ return ret;
+}
+int cmd_mailsplit(int argc, const char **argv, char **envp)
+{
+ int nr = 0, nr_prec = 4, ret;
int allow_bare = 0;
const char *dir = NULL;
const char **argp;
static const char *stdin_only[] = { "-", NULL };
- char *name;
for (argp = argv+1; *argp; argp++) {
const char *arg = *argp;
@@ -158,31 +193,9 @@ int main(int argc, const char **argv)
argp = stdin_only;
}
- name = xmalloc(strlen(dir) + 2 + 3 * sizeof(nr));
-
- while (*argp) {
- const char *file = *argp++;
- FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
- int file_done = 0;
-
- if ( !f )
- die ("cannot open mbox %s", file);
-
- if (fgets(buf, sizeof(buf), f) == NULL) {
- if (f == stdin)
- break; /* empty stdin is OK */
- die("cannot read mbox %s", file);
- }
-
- while (!file_done) {
- sprintf(name, "%s/%0*d", dir, nr_prec, ++nr);
- file_done = split_one(f, name, allow_bare);
- }
-
- if (f != stdin)
- fclose(f);
- }
+ ret = split_mbox(argp, dir, allow_bare, nr_prec, nr);
+ if (ret != -1)
+ printf("%d\n", ret);
- printf("%d\n", nr);
- return 0;
+ return ret == -1;
}
diff --git a/builtin.h b/builtin.h
index 885422e..92e1e1b 100644
--- a/builtin.h
+++ b/builtin.h
@@ -49,4 +49,6 @@ extern int cmd_rev_parse(int argc, const
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);
+extern int cmd_mailsplit(int argc, const char **argv, char **envp);
+extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
#endif
diff --git a/git.c b/git.c
index 5868fb9..3264c65 100644
--- a/git.c
+++ b/git.c
@@ -179,7 +179,8 @@ static void handle_internal_command(int
{ "diff-tree", cmd_diff_tree },
{ "cat-file", cmd_cat_file },
{ "rev-parse", cmd_rev_parse },
- { "write-tree", cmd_write_tree }
+ { "write-tree", cmd_write_tree },
+ { "mailsplit", cmd_mailsplit }
};
int i;
--
1.4.0
^ permalink raw reply related
* [PATCH 1/8] Make git-write-tree 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 ++-
write-tree.c => builtin-write-tree.c | 68 +++++++++++++++++++++-------------
builtin.h | 3 ++
git.c | 3 +-
4 files changed, 50 insertions(+), 30 deletions(-)
diff --git a/Makefile b/Makefile
index 2a1e639..37b5e40 100644
--- a/Makefile
+++ b/Makefile
@@ -159,7 +159,7 @@ PROGRAMS = \
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-upload-pack$X git-verify-pack$X git-write-tree$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 \
git-describe$X git-merge-tree$X git-blame$X git-imap-send$X
@@ -170,7 +170,7 @@ BUILT_INS = git-log$X git-whatchanged$X
git-check-ref-format$X git-rev-parse$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-read-tree$X git-commit-tree$X git-write-tree$X \
git-apply$X git-show-branch$X git-diff-files$X \
git-diff-index$X git-diff-stages$X git-diff-tree$X git-cat-file$X
@@ -223,7 +223,7 @@ BUILTIN_OBJS = \
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-ls-files.o builtin-ls-tree.o \
+ builtin-ls-files.o builtin-ls-tree.o builtin-write-tree.o \
builtin-read-tree.o builtin-commit-tree.o \
builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
diff --git a/write-tree.c b/builtin-write-tree.c
similarity index 66%
rename from write-tree.c
rename to builtin-write-tree.c
index bd07da6..c3aac36 100644
--- a/write-tree.c
+++ b/builtin-write-tree.c
@@ -3,41 +3,24 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
+#include "builtin.h"
#include "cache.h"
#include "tree.h"
#include "cache-tree.h"
-static int missing_ok = 0;
-static char *prefix = NULL;
-
static const char write_tree_usage[] =
"git-write-tree [--missing-ok] [--prefix=<prefix>/]";
-static struct lock_file lock_file;
-
-int main(int argc, char **argv)
+int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
{
int entries, was_valid, newfd;
- setup_git_directory();
+ /* We can't free this memory, it becomes part of a linked list parsed atexit() */
+ struct lock_file *lock_file = xmalloc(sizeof(struct lock_file));
- newfd = hold_lock_file_for_update(&lock_file, get_index_file());
- entries = read_cache();
-
- while (1 < argc) {
- char *arg = argv[1];
- if (!strcmp(arg, "--missing-ok"))
- missing_ok = 1;
- else if (!strncmp(arg, "--prefix=", 9))
- prefix = arg + 9;
- else
- die(write_tree_usage);
- argc--; argv++;
- }
-
- if (argc > 2)
- die("too many options");
+ newfd = hold_lock_file_for_update(lock_file, get_index_file());
+ entries = read_cache();
if (entries < 0)
die("git-write-tree: error reading cache");
@@ -45,6 +28,7 @@ int main(int argc, char **argv)
active_cache_tree = cache_tree();
was_valid = cache_tree_fully_valid(active_cache_tree);
+
if (!was_valid) {
if (cache_tree_update(active_cache_tree,
active_cache, active_nr,
@@ -52,7 +36,7 @@ int main(int argc, char **argv)
die("git-write-tree: error building trees");
if (0 <= newfd) {
if (!write_cache(newfd, active_cache, active_nr))
- commit_lock_file(&lock_file);
+ commit_lock_file(lock_file);
}
/* Not being able to write is fine -- we are only interested
* in updating the cache-tree part, and if the next caller
@@ -61,12 +45,44 @@ int main(int argc, char **argv)
* performance penalty and not a big deal.
*/
}
+
if (prefix) {
struct cache_tree *subtree =
cache_tree_find(active_cache_tree, prefix);
- printf("%s\n", sha1_to_hex(subtree->sha1));
+ memcpy(sha1, subtree->sha1, 20);
}
else
- printf("%s\n", sha1_to_hex(active_cache_tree->sha1));
+ memcpy(sha1, active_cache_tree->sha1, 20);
+
+ rollback_lock_file(lock_file);
+
return 0;
}
+
+int cmd_write_tree(int argc, const char **argv, char **envp)
+{
+ int missing_ok = 0, ret;
+ const char *prefix = NULL;
+ unsigned char sha1[20];
+
+ setup_git_directory();
+
+ while (1 < argc) {
+ const char *arg = argv[1];
+ if (!strcmp(arg, "--missing-ok"))
+ missing_ok = 1;
+ else if (!strncmp(arg, "--prefix=", 9))
+ prefix = arg + 9;
+ else
+ die(write_tree_usage);
+ argc--; argv++;
+ }
+
+ if (argc > 2)
+ die("too many options");
+
+ ret = write_tree(sha1, missing_ok, prefix);
+ printf("%s\n", sha1_to_hex(sha1));
+
+ return ret;
+}
diff --git a/builtin.h b/builtin.h
index b9f36be..885422e 100644
--- a/builtin.h
+++ b/builtin.h
@@ -46,4 +46,7 @@ extern int cmd_diff_tree(int argc, const
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_write_tree(int argc, const char **argv, char **envp);
+extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
+
#endif
diff --git a/git.c b/git.c
index 9469d44..5868fb9 100644
--- a/git.c
+++ b/git.c
@@ -178,7 +178,8 @@ static void handle_internal_command(int
{ "diff-stages", cmd_diff_stages },
{ "diff-tree", cmd_diff_tree },
{ "cat-file", cmd_cat_file },
- { "rev-parse", cmd_rev_parse }
+ { "rev-parse", cmd_rev_parse },
+ { "write-tree", cmd_write_tree }
};
int i;
--
1.4.0
^ permalink raw reply related
* [PATCH 0/8] Make a couple of commands builtin
From: Lukas Sandström @ 2006-06-13 20:21 UTC (permalink / raw)
To: Junio C Hamano, Git Mailing List; +Cc: Lukas Sandström
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.
/Lukas
^ permalink raw reply
* Re: git-cvsimport doesn't quite work, wrt branches
From: Keith Packard @ 2006-06-13 18:46 UTC (permalink / raw)
To: Linus Torvalds
Cc: keithp, Jim Meyering, Git Mailing List, Matthias Urlichs,
Yann Dirson, Pavel Roskin
In-Reply-To: <Pine.LNX.4.64.0606131008470.5498@g5.osdl.org>
[-- Attachment #1: Type: text/plain, Size: 542 bytes --]
On Tue, 2006-06-13 at 10:20 -0700, Linus Torvalds wrote:
> Well, it's a cvsps problem.
>
> Big surprise.
Yeah, we've got
git-cvsimport
cvsps
cvs rlog
,v files
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.
--
keith.packard@intel.com
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox