Git development
 help / color / mirror / Atom feed
* Re: [PATCH] git-rebase: suggest to use git-add instead of git-update-index
From: Junio C Hamano @ 2007-06-02 19:07 UTC (permalink / raw)
  To: Jonas Fonseca; +Cc: git
In-Reply-To: <20070602175949.GB19952@diku.dk>

Jonas Fonseca <fonseca@diku.dk> writes:

> The command is part of the main porcelain making git-add more
> appropriate.
>
> Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
> ---
>  git-rebase.sh |    4 ++--
>  1 files changed, 2 insertions(+), 2 deletions(-)
>
>  I don't know if this is good or not, maybe it is a matter of taste, but
>  as a new git user I prefer to use git add.

I like it.  Thanks.

^ permalink raw reply

* StGIT: stgitformatversion vs. stgit.formatversion
From: Yann Dirson @ 2007-06-02 19:16 UTC (permalink / raw)
  To: Karl Hasselström, Catalin Marinas; +Cc: GIT list

What about using branch.*.stgit.formatversion to store the version, to
be consistent with other stgit-specific per-branch settings ?

Bet regards,
-- 
Yann.

^ permalink raw reply

* Re: [PATCH] Make the installation targets a little less chatty
From: Junio C Hamano @ 2007-06-02 19:58 UTC (permalink / raw)
  To: Alex Riesen; +Cc: git
In-Reply-To: <20070601230924.GA6360@steel.home>

Alex Riesen <raa.lkml@gmail.com> writes:

> by default. V=1 works as usual.

You obviously did not test that X-<.  V=1 does not work at all
for me.  This is what I get.

    ...
    install git '/home/junio/git-test/bin'
    :SETUP BUILTIN git-format-patch; rm -f '/home/junio/git-test/bin/git-format-patch' && ln '/home/junio/git-test/bin/git' '/home/junio/git-test/bin/git-format-patch'; ...
    ...
    /bin/sh: :SETUP: command not found
    /bin/sh: :SETUP: command not found
    /bin/sh: :SETUP: command not found
    /bin/sh: :SETUP: command not found
    ...

Two problems and a half.

 (0) You do not report the creation of target directory done
     with "install -d", so without $V there is no way to tell if
     things are installed in the expected location.

 (1) Obviously : and whatever action message needs to be
     separated so that it becomes a no-op command ':' followed
     by parameters;

 (2) Even with that ":SETUP: command not found" fixed, it now
     makes the command line twice as long as before for $V case,
     which makes it harder to diagnose a problem when Makefile
     goes wrong.

I think the way QUIET_CC and friends are done is quite sensible
and does not have this problem, especially (3).  With V=1 it
just becomes transparent, and that is what we would want.

^ permalink raw reply

* Re: git-p4import.py robustness changes
From: Scott Lamb @ 2007-06-02 20:41 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vbqg01reo.fsf@assigned-by-dhcp.cox.net>


On May 31, 2007, at 4:53 PM, Junio C Hamano wrote:

> Actually, my preference is to have a "patch 0" before all of the
> above, that demotes git-p4import to contrib/ hierarchy.  Having
> no access to p4 managed repositories (nor much inclination to
> get one), I can never test nor maintain it myself, so it is just
> crazy for me to be the maintainer for it.

Will do. What does that mean for Documentation/git-p4import.txt and  
the git-p4 rpm (defined in git.spec.in)? Should I move them with it?  
(Seems nothing else in the main tree references contrib.) If so,  
maybe I should set up a common "Documentation/asciidoc.mak" or  
something for building the man/html pages rather than duplicating all  
that Makefile logic.

-- 
Scott Lamb <http://www.slamb.org/>

^ permalink raw reply

* What's cooking in git.git (topics)
From: Junio C Hamano @ 2007-06-02 21:09 UTC (permalink / raw)
  To: git
In-Reply-To: <7virac547s.fsf@assigned-by-dhcp.cox.net>

Again, 'next' is getting quite lightweight compared to 'master'.
Good time to do "war on whitespace" Marco suggested myself.

'pu' has Shawn's 'pu' from git-gui, to help people experiment
with the proposed blame viewer improvements more easily.  I
personally like it quite a bit.

----------------------------------------------------------------

Here are the topics that have been cooking.  Commits prefixed
with '-' are only in 'pu' while commits prefixed with '+' are
in 'next'.  The topics list the commits in reverse chronological
order.

* lh/submodules (Sat Jun 2 03:27:42 2007 +0200) 2 commits
 + Add basic test-script for git-submodule
 + Add git-submodule command

I find this a 'master' material already.  Will merge soon.

* gb/idx (Fri Jun 1 15:18:05 2007 -0400) 1 commit
 + Unify write_index_file functions

Should graduate to 'master' by mid next week.

* pb/am (Thu May 24 19:25:25 2007 -0700) 2 commits
 + Remove git-applypatch
 + git-applymbox: Remove command

Will push out to 'master' soon to see if anybody screams.

* dh/repack (Fri May 25 14:40:24 2007 -0700) 1 commit
 - Enhance unpack-objects for live repo and large objects

I saw nobody other than Dana jump up and down and say we must
have this, so I still parked this in 'pu' without merging it to
'next'.  Maybe a time for a quick poll?

* jc/blame (Fri Apr 20 16:25:50 2007 -0700) 4 commits
 - blame: show log as it goes
 - git-blame: optimize get_origin() from linear search to hash-
   lookup.
 - git-blame: pass "struct scoreboard *" pointers around.
 - blame: lift structure definitions up

* jc/diff (Mon Dec 25 01:08:50 2006 -0800) 2 commits
 - test-para: combined diff between HEAD, index and working tree.
 - para-walk: walk n trees, index and working tree in parallel

Backburnered.  Further work on the latter, or something like
that, or something based on (disused) git-merge-tree, is needed
to exonerate Linus from having lied in the following part of his
talk (there is a transcript at http://git.or.cz/gitwiki of his
talk by the way):

    The source code may sometimes look complicated because we
    are very performance centric, I am.  I really care, and
    sometimes to make things go really fast, you have to use
    more complicated algorithms than just checking one file at a
    time.  When you are doing 22,000 file merges, you do not
    want to check one file at a time, you want to check the
    whole tree in one go and say, "Ah they are the same, I do
    not have to do anything".

as we _DO_ currently merge one path at a time.

You _could_ interpret "merge" in his message as applying
millions of patches from Andrew, in which case it is true ---
the cache-tree optimization in the index does help us skipping
the unchanged tree recomputation.  But that does not apply to a
true merge, even when it is a trivial tree-level merge.

^ permalink raw reply

* What's in git.git (stable)
From: Junio C Hamano @ 2007-06-02 21:09 UTC (permalink / raw)
  To: git
In-Reply-To: <7vejl0546b.fsf@assigned-by-dhcp.cox.net>

I will do a v1.5.2.1 with 'maint' and push it out this weekend.

----------------------------------------------------------------

* The 'maint' branch has these fixes since the last announcement.

 Frank Lichtenheld (2):
  git-config: Various small fixes to asciidoc documentation
  git-config: Improve documentation of git-config file handling

 Jeff King (1):
  Documentation: robustify asciidoc GIT_VERSION replacement

 Jerald Fitzjerald (1):
  decode_85(): fix missing return.

 Josh Triplett (1):
  Create a new manpage for the gitignore format, and reference it elsewhere

 Kristian Høgsberg (1):
  Use =20 when rfc2047 encoding spaces.

 Linus Torvalds (1):
  fix signed range problems with hex conversions


* The 'master' branch has these since the last announcement
  in addition to the above.

 James Bowes (1):
  rev-parse: Identify short sha1 sums correctly.

 Jonas Fonseca (2):
  Fix git-am(1) synopsis formatting
  git-rebase: suggest to use git-add instead of git-update-index

 Julian Phillips (1):
  Makefile: Use generic rule to build test programs

 Junio C Hamano (1):
  Add DLH to .mailmap

 Martin Koegler (4):
  builtin-pack-objects: don't fail, if delta is not possible
  git-pack-objects: cache small deltas between big objects
  builtin-pack-object: cache small deltas
  diff-delta: use realloc instead of xrealloc

 Nicolas Pitre (2):
  fix repack with --max-pack-size
  always start looking up objects in the last used pack first

 Shawn O. Pearce (7):
  Lazily open pack index files on demand
  Micro-optimize prepare_alt_odb
  Attempt to delay prepare_alt_odb during get_sha1
  Test for recent rev-parse $abbrev_sha1 regression
  Simplify index access condition in count-objects, pack-redundant
  Ensure the pack index is opened before access
  Style nit - don't put space after function names

 Theodore Ts'o (1):
  Fix minor grammatical typos in the git-gc man page

^ permalink raw reply

* Re: git-p4import.py robustness changes
From: Junio C Hamano @ 2007-06-02 21:33 UTC (permalink / raw)
  To: Scott Lamb; +Cc: git
In-Reply-To: <0EDF1E14-3682-4B1E-A7D2-F82388F752AA@slamb.org>

Scott Lamb <slamb@slamb.org> writes:

> On May 31, 2007, at 4:53 PM, Junio C Hamano wrote:
>
>> Actually, my preference is to have a "patch 0" before all of the
>> above, that demotes git-p4import to contrib/ hierarchy.  Having
>> no access to p4 managed repositories (nor much inclination to
>> get one), I can never test nor maintain it myself, so it is just
>> crazy for me to be the maintainer for it.
>
> Will do. What does that mean for Documentation/git-p4import.txt and
> the git-p4 rpm (defined in git.spec.in)? Should I move them with it?
> (Seems nothing else in the main tree references contrib.) If so,
> maybe I should set up a common "Documentation/asciidoc.mak" or
> something for building the man/html pages rather than duplicating all
> that Makefile logic.

A much more preferable alternative is for you to say "Hey, don't
say you want to demote it.  I'll keep it maintained, I regularly
use p4 and have a strong incentive to keep it working".  Then we
do not have to do the "patch 0" ;-)

^ permalink raw reply

* Re: [PATCH] gitweb: handle non UTF-8 text
From: Junio C Hamano @ 2007-06-02 22:15 UTC (permalink / raw)
  To: Jakub Narebski
  Cc: Martin Koegler, Petr Baudis, git, Martin Langhoff, Martyn Smith,
	Robin Rosenberg
In-Reply-To: <200706012305.41183.jnareb@gmail.com>

Jakub Narebski <jnareb@gmail.com> writes:

> On Tue, 29 May 2007, Martin Koegler wrote:
> ...
>> But I agree, that there should be the possibilty to choose a the
>> fallback encoding.
>
> I think for the beginning it would be enough to have
>
>   # assume this charset if line contains non-UTF-8 characters
>   our $fallback_encoding = "latin1";
>
> or something like that (perhaps different wording in the comment,
> perhaps different name of the variable) in the gitweb.perl for your
> idea to be accepted.
>
> That, and using to_utf8 (as before e3ad95a8) and not my_decode_utf8
> as subroutine name. If only it would be possible to avoid I think
> quote costly "eval {....}" invocation...

Except that I had an impression that block form of "eval" (as
opposed to "parse and evaluate string" kind) was not costly at
all.

Please make it so.

I'll read the other parts of your message again -- I might have
further comments.

^ permalink raw reply

* Re: [mingw port] git plumbing piping with CR/NL
From: Alex Riesen @ 2007-06-02 23:09 UTC (permalink / raw)
  To: Nguyen Thai Ngoc Duy; +Cc: Git Mailing List, Johannes Sixt
In-Reply-To: <fcaeb9bf0706011656p2145afe0k8be9797d250566df@mail.gmail.com>

Nguyen Thai Ngoc Duy, Sat, Jun 02, 2007 01:56:54 +0200:
> >Why does your grep _alters_ the input, instead of filtering it, btw?
> 
> I have no idea. It's grep from MKS Toolkit FYI.
>

Looks like it is buggy

^ permalink raw reply

* [RFC/PATCH 4/3] Simplify naming (versioning) of non-release tig tarball and rpm file
From: Jakub Narebski @ 2007-06-02 17:52 UTC (permalink / raw)
  To: Jonas Fonseca; +Cc: git
In-Reply-To: <20070531131615.GA27044@diku.dk>

Use the tag part of git-describe output, with `tig-' prefix stripped
off, as version number. Use number of commits since given tag as
release number, using 0 if we are at tagged version, and adding
'.dirty' suffix if working directory is dirty. Do not use 'g<sha 1>'
part of git-describe output.

For example, when git-describe output was tig-0.7-8-g26d0386, before
this commit tarball was named tig-0.7.8.g26d0386.tar.gz and rpm was
named tig-0.7.8.g26d0386-1.src.rpm (for dirty tree tarball was
tig-0.7.8.g26d0386.dirty.tar.gz), now tarball is named
tig-0.7-8.tar.gz and rpm is named tig-0.7-8.src.rpm (for dirty tree
tarball is tig-0.7-8.dirty.tar.gz).

Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
This is proposal to simplify naming of non-release tarballs and rpm file,
both for tig and also for git itself. Instead of using whole git-describe
output as version number in tarball/rpm name (BTW. it would be nice to
have command line switch to git-describe which would return old output,
without number of commits since given tag) use tag part as version number,
and number of commits since (plus optional marking dirty) as release
number.

What do you think about this?

 Makefile    |   13 ++++++++++---
 tig.spec.in |    2 +-
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/Makefile b/Makefile
index b49d7f8..1e67586 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,13 @@ ifdef DIST_VERSION
 VERSION	= $(DIST_VERSION)
 endif
 
-RPM_VERSION = $(subst -,.,$(VERSION))
+# $(GITDESC) looks like either x.y, or like x.y-z-g<sha1>
+SPLIT_VERSION := $(shell echo $(GITDESC) | \
+                   sed -e 's/^\(.*\)-\([0-9]\+\)-\(g[0-9a-f]\+\)$$/\1 \2 \3/g')
+RPM_VERSION = $(subst -,.,$(word 1,$(SPLIT_VERSION)))
+RPM_RELEASE = $(strip \
+              $(subst -,.,$(if $(word 2,$(SPLIT_VERSION)),\
+                               $(word 2,$(SPLIT_VERSION)),0)$(WTDIRTY)))
 
 LDLIBS	= -lcurses
 CFLAGS	= -Wall -O2 '-DVERSION="$(VERSION)"'
@@ -26,7 +32,7 @@ PROGS	= tig
 MANDOC	= tig.1 tigrc.5
 HTMLDOC	= tig.1.html tigrc.5.html manual.html README.html
 ALLDOC	= $(MANDOC) $(HTMLDOC) manual.html-chunked manual.pdf
-TARNAME	= tig-$(RPM_VERSION)
+TARNAME	= tig-$(RPM_VERSION)-$(RPM_RELEASE)
 
 all: $(PROGS)
 all-debug: $(PROGS)
@@ -104,7 +110,8 @@ release-dist: release-doc
 	install-doc-man install-doc-html clean spell-check dist rpm
 
 tig.spec: tig.spec.in
-	sed -e 's/@@VERSION@@/$(RPM_VERSION)/g' < $< > $@
+	sed -e 's/@@VERSION@@/$(RPM_VERSION)/g' \
+	    -e 's/@@RELEASE@@/$(RPM_RELEASE)/g' < $< > $@
 
 tig: tig.c
 
diff --git a/tig.spec.in b/tig.spec.in
index 2385fb8..8606b23 100644
--- a/tig.spec.in
+++ b/tig.spec.in
@@ -4,7 +4,7 @@
 Summary: 	Tig: text-mode interface for git
 Name: 		tig
 Version: 	@@VERSION@@
-Release: 	1%{?dist}
+Release: 	@@RELEASE@@%{?dist}
 License: 	GPL
 Group: 		Development/Tools
 Vendor: 	Jonas Fonseca <fonseca@diku.dk>
-- 
1.5.2

^ permalink raw reply related

* Re: git-p4import.py robustness changes
From: Scott Lamb @ 2007-06-02 23:21 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vzm3inisa.fsf@assigned-by-dhcp.cox.net>


On Jun 2, 2007, at 2:33 PM, Junio C Hamano wrote:

> A much more preferable alternative is for you to say "Hey, don't
> say you want to demote it.  I'll keep it maintained, I regularly
> use p4 and have a strong incentive to keep it working".  Then we
> do not have to do the "patch 0" ;-)

Hmm. I'd like to say that, but keep in mind that I'd never even used  
git before Wednesday, and I'm not sure yet how well git-p4import.py  
will work out for me.

It'd be a huge leap from git-p4import.py to something that could  
remove my need to use p4 commands daily. First, I'd need something  
that could follow all upstream branches with merge history. Then I'd  
either need to convince my team to ditch p4 entirely (not easy, and  
then I wouldn't use/maintain git-p4import.py afterward anyway) or a  
way to robustly generate "p4 integrate", "p4 resolve", "p4 submit"  
command sequences to merge between upstream branches.

We're attempting to address more modest needs, like those of our off- 
site contractors who should only be sending patches anyway. (Another  
guy wrote a script that pulls changes into an svn mirror basically by  
"svn ci -m 'changed some stuff'" every half hour, but I made fun of  
it and now have to replace it. ;)

I'll at least finish up the other patches first and see how it goes.

-- 
Scott Lamb <http://www.slamb.org/>

^ permalink raw reply

* Re: git-p4import.py robustness changes
From: Junio C Hamano @ 2007-06-02 23:52 UTC (permalink / raw)
  To: Scott Lamb; +Cc: git
In-Reply-To: <87F9A283-C51F-49FB-9A13-40E850AC0474@slamb.org>

Scott Lamb <slamb@slamb.org> writes:

> On Jun 2, 2007, at 2:33 PM, Junio C Hamano wrote:
>
>> A much more preferable alternative is for you to say "Hey, don't
>> say you want to demote it.  I'll keep it maintained, I regularly
>> use p4 and have a strong incentive to keep it working".  Then we
>> do not have to do the "patch 0" ;-)
>
> Hmm. I'd like to say that, but keep in mind that I'd never even used
> git before Wednesday, and I'm not sure yet how well git-p4import.py
> will work out for me.

Oh, you do not have to worry so much.  There certainly are
people who are familiar enough with git on this list to help
improving p4import from the git side.

The thing to me personally is that I am p4 illiterate.  However,
as you might be aware, a few people posted their own version of
"better than p4import" scripts to the list in the past few
months, so there should also be enough people with p4 expertise
and motivation to help you with it.

It _might_ turn out that one of their scripts might be better
than the p4import we have in-tree and we would end up replacing
it with it.  I won't be able to judge that myself, but if people
who need to interoperate with p4 on the list can join forces it
would be good.

^ permalink raw reply

* Re: [PATCH] Add option -L to git-tag.
From: Matthijs Melchior @ 2007-06-03  0:04 UTC (permalink / raw)
  To: git
In-Reply-To: <7vvee6qkr4.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:
> Matthijs Melchior <mmelchior@xs4all.nl> writes:
> 
>> Junio C Hamano wrote:
>> ...
>>> I dunno; I've never been very good at the user interfaces.
>>>   
>> Yes, since I have this command and have seen the tag annotations in the
>> git repository, I think we need this extra parameter.
>> I propose to give the number of lines you want to see, with 0 gives all.
>> So it will be --pretty=<max-number-lines> to limit the output and be
>> able to find interesting stuff before looking at the complete message.
> 
> Please do not use the same word used elsewhere ('pretty') and
> make it mean something different (they are 'short', 'oneline', etc.
> in other places).
> 
> Regardless of how we might do a single-liner output, I suspect that
> Instead of showing them like this (your patch):
> 
> 	$ git tag -L v2.6.1* | head -n 6
> 	v2.6.11
>             This is the 2.6.11 tree object.
> 	v2.6.11-tree
>             This is the 2.6.11 tree object.
> 	v2.6.12
>             This is the final 2.6.12 release
> 
> showing them in this way might be more pleasant:
> 
> 	$ git tag -L v2.6.1* | head -n 3
> 	v2.6.11      This is the 2.6.11 tree object.
> 	v2.6.11-tree This is the 2.6.11 tree object.
> 	v2.6.12      This is the final 2.6.12 release
> 
> This matches the way "git branch -v" without other arguments,
> which I think is the moral equivalent for branches to your "git
> tag -L", shows a bit more information than the usual (we could
> even say "git tag -l -v" but -v is already taken -- we could
> still do "git tag --list --verbose" and leave the short '-v' to
> mean 'verify' but I dunno).

Yes, this is a good idea.
I have dropped the -L option, and in stead introduced the -n option.
The -n option specifies how many lines of annotation you want to see.
Not using -n gives the old -l behavior, just -n gives the tag and
first annotation line together, and -n 9999 gives the full annotation.

I think this is better than having two different list options.

> 
> This is a slightly related tangent, but I've been wanting to
> extend the "the first line is special 'one-line summary',
> separated by a blank line from the rest of the more descriptive
> message" convention used in the commit log message formatter.
> When somebody asks for --pretty=oneline, instead of showing the
> "first line", we would give the first paragraph, with LFs
> replaced with SPs to make it a single line.  This would not
> affect commit log messages that follow the above convention.
> 
> If your tags have a few lines to describe what the commits are
> about, it might make it easier to get the overview by applying
> the same "first paragraph squashed down to a single line" logic,
> grab the first paragraph, present it as a one-liner" in the
> format shown above.

I will leave this for another time...

> 
>>>>  - Sorting the tag names resulting from git-rev-parse is not nessecary since
>>>>    the list of tags is already deliverd in sorted order.
>>> This I am a bit reluctant about, as that sorting done by
>>> rev-parse is purely by accident (i.e. it is an implementation
>>> detail).
>>>   
>> This accident can be repaired by documenting it.... :)
> 
> That would cast the implementation in stone, avoidance of which
> was the point of my comment.
> 

Yes, I understand. It would be good if the manual page for rev-parse
said something about the order in which the arguments are processed or
generated. Currently this is not mentioned, so I was not surprised
to find the generated names were sorted.

>>> What does this command exit with now?  It used to be that
>>>
>>> 	$ git tag -l no-such-tag-at-all ; echo $?
>>>
>>> said "1", I think, because grep did not match.
>>>   
>> It will always exit 0, either from sed or git-cat.
>>
>> ...
>>
>>  (maybe the exit code is not worth the added complexity...).
> 
> That's 40% satisfactory answer.
> 
> I do not speak for others, but when I comment on a patch, saying
> "This might be better done this other way", or "This change
> might be bad", I do not necessarily expect/want you to agree
> with me on all counts.  I would very much be happier to get a
> counter argument back -- that's how we both learn things and
> make progress.
> 
> Unlike Linus, I am not always right ;-)
> 
> But more seriously, I sometimes deliberately make suggestions
> that I know are not optimal, because I want to involve other
> people (not necessarily the author of the patch, but others on
> the list) in the process of making improvements.
> 
> The "40%" satisfactory part comes from that you correctly
> answered that your version now always exits zero while the
> original diagnosed the "no such tag whatsoever" situation with
> non-zero exit, with a slight hint that you think it might be
> better not to differenciate the "no match" case.
> 
> What I would prefer to see is to make that "slight hint" more
> explicit.  As you say, "is not worth the added complexity" is a
> possible justification, but in this particular case, I think we
> could (and probably should) even argue that the current exit
> code is not so useful.  It might go like this...
> 
>     Although "git tag -l <pattern>" currently signals non-match
>     with its exit code, "git tag -l do-i-have-this-tag" is not
>     the right way to ask that question to begin with, because
>     the tagname parameter is always taken as a pattern.  For
>     that, "git show-ref --verify refs/tags/do-i-have-this-tag"
>     is much better.  I do not think the current exit status from
>     "git-tag -l <pattern>" is useful, and we should change it to
>     exit with 0 unless we see other errors (e.g. "not a git
>     repository"), regardless of the addition of -L option.
> 
> and you would have got the remaining 60% ;-).
> 
> I care about documenting the change in behaviour and justifying
> why we changed the behavikour in the commit log.
> 

Take 3 of the patch is forthcoming.
 - A new -n option is introduced, specifying the number of
   annotation lines to print. The default value is 0.
 - The <pattern> is now a shell pattern, and not a list if grep
   parameters. It is called a pattern and not re, after all.
 - The -l <pattern> may be repeated with a different <pattern>
 - The exit code for -l is now always 0.


Thanks.

Regards,
	Matthijs Melchior.

^ permalink raw reply

* [PATCH] Teach git-tag about showing tag annotations.
From: Matthijs Melchior @ 2007-06-03  0:05 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Matthijs Melchior

The <pattern> for -l is now a shell pattern, not a list of grep parameters.
Option -l may be repeated with another <pattern>.

The new -n [<num>] option specifies how many lines from
the annotation are to be printed.
Not specifieing -n or -n 0 will just produce the tag names
Just -n or -n 1 will show the first line of the annotation on
the tag line.
Other valuse for -n will show that number of lines from the annotation.

The exit code used to indicate if any tag was found.
This is changed due to a different implementation.

A good way to test a tag for existence is to use:
git show-ref --quiet --verify refs/tags/$TAGNAME

Signed-off-by: Matthijs Melchior <mmelchior@xs4all.nl>
---
 Documentation/git-tag.txt |   13 +++++++++----
 git-tag.sh                |   44 +++++++++++++++++++++++++++++++++++++-------
 2 files changed, 46 insertions(+), 11 deletions(-)

diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 4e3e027..aee2c1b 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -11,7 +11,7 @@ SYNOPSIS
 [verse]
 'git-tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]  <name> [<head>]
 'git-tag' -d <name>...
-'git-tag' -l [<pattern>]
+'git-tag' [-n [<num>]] -l [<pattern>]
 'git-tag' -v <name>
 
 DESCRIPTION
@@ -38,8 +38,8 @@ GnuPG key for signing.
 
 `-v <tag>` verifies the gpg signature of the tag.
 
-`-l <pattern>` lists tags that match the given pattern (or all
-if no pattern is given).
+`-l <pattern>` lists tags with names that match the given pattern
+(or all if no pattern is given).
 
 OPTIONS
 -------
@@ -61,8 +61,13 @@ OPTIONS
 -v::
 	Verify the gpg signature of given the tag
 
+-n <num>::
+	<num> specifies how many lines from the annotation, if any,
+	are printed when using -l.
+	The default is not to print any annotation lines.
+
 -l <pattern>::
-	List tags that match the given pattern (or all if no pattern is given).
+	List tags with names that match the given pattern (or all if no pattern is given).
 
 -m <msg>::
 	Use the given tag message (instead of prompting)
diff --git a/git-tag.sh b/git-tag.sh
index 6f0b7a7..1563696 100755
--- a/git-tag.sh
+++ b/git-tag.sh
@@ -1,7 +1,7 @@
 #!/bin/sh
 # Copyright (c) 2005 Linus Torvalds
 
-USAGE='-l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg>] <tagname> [<head>]'
+USAGE='[-n [<num>]] -l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg>] <tagname> [<head>]'
 SUBDIRECTORY_OK='Yes'
 . git-sh-setup
 
@@ -13,6 +13,7 @@ message=
 username=
 list=
 verify=
+LINES=0
 while case "$#" in 0) break ;; esac
 do
     case "$1" in
@@ -26,14 +27,41 @@ do
     -f)
 	force=1
 	;;
-    -l)
-	case "$#" in
-	1)
-		set x . ;;
+    -n)
+        case $2 in
+	-*)	LINES=1 	# no argument
+		;;
+	*)	shift
+		LINES=$(expr "$1" : '\([0-9]*\)')
+		[ -z "$LINES" ] && LINES=1 # 1 line is default when -n is used
+		;;
 	esac
+	;;
+    -l)
+	list=1
 	shift
-	git rev-parse --symbolic --tags | sort | grep "$@"
-	exit $?
+	PATTERN="$1"	# select tags by shell pattern, not re
+	git rev-parse --symbolic --tags | sort |
+	    while read TAG
+	    do
+	        case "$TAG" in
+		*$PATTERN*) ;;
+		*)	    continue ;;
+		esac
+		[ "$LINES" -le 0 ] && { echo "$TAG"; continue ;}
+		OBJTYPE=$(git cat-file -t "$TAG")
+		case $OBJTYPE in
+		tag)	ANNOTATION=$(git cat-file tag "$TAG" |
+			    	       sed -e '1,/^$/d' \
+					   -e '/^-----BEGIN PGP SIGNATURE-----$/Q' )
+			printf "%-15s %s\n" "$TAG" "$ANNOTATION" |
+			  sed -e '2,$s/^/    /' \
+			      -e "${LINES}q"
+			;;
+		*)      echo "$TAG"
+			;;
+		esac
+	    done
 	;;
     -m)
     	annotate=1
@@ -97,6 +125,8 @@ do
     shift
 done
 
+[ -n "$list" ] && exit 0
+
 name="$1"
 [ "$name" ] || usage
 prev=0000000000000000000000000000000000000000
-- 
1.5.2

^ permalink raw reply related

* Re: What's cooking in git.git (topics)
From: Johannes Schindelin @ 2007-06-03  0:20 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7v6466oygl.fsf@assigned-by-dhcp.cox.net>

Hi,

On Sat, 2 Jun 2007, Junio C Hamano wrote:

> * lh/submodules (Sat Jun 2 03:27:42 2007 +0200) 2 commits
>  + Add basic test-script for git-submodule
>  + Add git-submodule command
> 
> I find this a 'master' material already.  Will merge soon.

I agree. Even if I had not time to review it closely, from a cursory look 
it is clean enough. I don't expect any regressions from that.

> * pb/am (Thu May 24 19:25:25 2007 -0700) 2 commits
>  + Remove git-applypatch
>  + git-applymbox: Remove command
> 
> Will push out to 'master' soon to see if anybody screams.

Ack.

> * jc/diff (Mon Dec 25 01:08:50 2006 -0800) 2 commits
>  - test-para: combined diff between HEAD, index and working tree.
>  - para-walk: walk n trees, index and working tree in parallel
> 
> Backburnered.

I actually like those two commits, and I always wanted to work on top of 
these, but my new boss keeps me away from Git :-(

Will review, and try to work some more on them in the next three weeks. 
Don't drop them!

As for the complicated source code: I cannot agree. If you have _any_ idea 
about what data structures are about, you will readily recognize what it 
is about. We _could_ be more explicit, but by a huge margin.

(IMHO too many people try to chime in without _any_ clue about the 
difference of hash tables and binary search, and no notion of Landau's 
symbol. We should not necessarily try to accomodate people who are _that_ 
unwilling to work up their theory.)

Ciao,
Dscho

^ permalink raw reply

* [PATCH] Add git-filter-branch
From: Johannes Schindelin @ 2007-06-03  0:31 UTC (permalink / raw)
  To: git, junkio, pasky


This script is derived from Pasky's cg-admin-rewritehist.

In fact, it _is_ the same script, minimally adapted to work without cogito.
It _should_ be able to perform the same tasks, even if only relying on
core-git programs.

All the work is Pasky's, just the adaption is mine.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Hopefully-signed-off-by: Petr "cogito master" Baudis <pasky@suse.cz>
---

	I will not have time to work on this for at least 24 hours. So, if 
	people want to go wild with enhancing the test case (and fixing the 
	script), go wild!

	IMHO this should go into core-git, as one of the many, many, many 
	enhancements that cogito brought to us.

	So really, this is a way of thanks to Pasky, rather than just 
	saying good-bye to cogito.

	Thanks, Pasky.

 Makefile                 |    3 +-
 git-filter-branch.sh     |  430 ++++++++++++++++++++++++++++++++++++++++++++++
 t/t7003-filter-branch.sh |   47 +++++
 3 files changed, 479 insertions(+), 1 deletions(-)
 create mode 100644 git-filter-branch.sh
 create mode 100755 t/t7003-filter-branch.sh

diff --git a/Makefile b/Makefile
index 7ecd8f0..da271ec 100644
--- a/Makefile
+++ b/Makefile
@@ -213,7 +213,8 @@ SCRIPT_SH = \
 	git-am.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 git-submodule.sh
+	git-lost-found.sh git-quiltimport.sh git-submodule.sh \
+	git-filter-branch.sh
 
 SCRIPT_PERL = \
 	git-add--interactive.perl \
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
new file mode 100644
index 0000000..c0a7680
--- /dev/null
+++ b/git-filter-branch.sh
@@ -0,0 +1,430 @@
+#!/bin/sh
+#
+# Rewrite revision history
+# Copyright (c) Petr Baudis, 2006
+# Minimal changes to "port" it to core-git (c) Johannes Schindelin, 2007
+#
+# Lets you rewrite GIT revision history by creating a new branch from
+# your current branch by applying custom filters on each revision.
+# Those filters can modify each tree (e.g. removing a file or running
+# a perl rewrite on all files) or information about each commit.
+# Otherwise, all information (including original commit times or merge
+# information) will be preserved.
+#
+# The command takes the new branch name as a mandatory argument and
+# the filters as optional arguments. If you specify no filters, the
+# commits will be recommitted without any changes, which would normally
+# have no effect and result with the new branch pointing to the same
+# branch as your current branch. (Nevertheless, this may be useful in
+# the future for compensating for some Git bugs or such, therefore
+# such a usage is permitted.)
+#
+# WARNING! The rewritten history will have different ids for all the
+# objects and will not converge with the original branch. You will not
+# be able to easily push and distribute the rewritten branch. Please do
+# not use this command if you do not know the full implications, and
+# avoid using it anyway - do not do what a simple single commit on top
+# of the current version would fix.
+#
+# Always verify that the rewritten version is correct before disposing
+# the original branch.
+#
+# Note that since this operation is extensively I/O expensive, it might
+# be a good idea to do it off-disk, e.g. on tmpfs. Reportedly the speedup
+# is very noticeable.
+#
+# OPTIONS
+# -------
+# -d TEMPDIR:: The path to the temporary tree used for rewriting
+#	When applying a tree filter, the command needs to temporary
+#	checkout the tree to some directory, which may consume
+#	considerable space in case of large projects. By default it
+#	does this in the '.git-rewrite/' directory but you can override
+#	that choice by this parameter.
+#
+# -r STARTREV:: The commit id to start the rewrite at
+#	Normally, the command will rewrite the entire history. If you
+#	pass this argument, though, this will be the first commit it
+#	will rewrite and keep the previous commits intact.
+#
+# -k KEEPREV:: A commit id until which _not_ to rewrite history
+#	If you pass this argument, this commit and all of its
+#	predecessors are kept intact.
+#
+# Filters
+# ~~~~~~~
+# The filters are applied in the order as listed below. The COMMAND
+# argument is always evaluated in shell using the 'eval' command.
+# The $GIT_COMMIT environment variable is permanently set to contain
+# the id of the commit being rewritten. The author/committer environment
+# variables are set before the first filter is run.
+#
+# A 'map' function is available that takes an "original sha1 id" argument
+# and outputs a "rewritten sha1 id" if the commit has been already
+# rewritten, fails otherwise; the 'map' function can return several
+# ids on separate lines if your commit filter emitted multiple commits
+# (see below).
+#
+# --env-filter COMMAND:: The filter for modifying environment
+#	This is the filter for modifying the environment in which
+#	the commit will be performed. Specifically, you might want
+#	to rewrite the author/committer name/email/time environment
+#	variables (see `git-commit` for details). Do not forget to
+#	re-export the variables.
+#
+# --tree-filter COMMAND:: The filter for rewriting tree (and its contents)
+#	This is the filter for rewriting the tree and its contents.
+#	The COMMAND argument is evaluated in shell with the working
+#	directory set to the root of the checked out tree. The new tree
+#	is then used as-is (new files are auto-added, disappeared files
+#	are auto-removed - .gitignore files nor any other ignore rules
+#	HAVE NO EFFECT!).
+#
+# --index-filter COMMAND:: The filter for rewriting index
+#	This is the filter for rewriting the Git's directory index.
+#	It is similar to the tree filter but does not check out the
+#	tree, which makes it much faster. However, you must use the
+#	lowlevel Git index manipulation commands to do your work.
+#
+# --parent-filter COMMAND:: The filter for rewriting parents
+#	This is the filter for rewriting the commit's parent list.
+#	It will receive the parent string on stdin and shall output
+#	the new parent string on stdout. The parent string is in
+#	format accepted by `git-commit-tree`: empty for initial
+#	commit, "-p parent" for a normal commit and "-p parent1
+#	-p parent2 -p parent3 ..." for a merge commit.
+#
+# --msg-filter COMMAND:: The filter for rewriting commit message
+#	This is the filter for rewriting the commit messages.
+#	The COMMAND argument is evaluated in shell with the original
+#	commit message on standard input; its standard output is
+#	is used as the new commit message.
+#
+# --commit-filter COMMAND:: The filter for performing the commit
+#	If this filter is passed, it will be called instead of the
+#	`git-commit-tree` command, with those arguments:
+#
+#		TREE_ID [-p PARENT_COMMIT_ID]...
+#
+#	and the log message on stdin. The commit id is expected on
+#	stdout. As a special extension, the commit filter may emit
+#	multiple commit ids; in that case, all of them will be used
+#	as parents instead of the original commit in further commits.
+#
+# --tag-name-filter COMMAND:: The filter for rewriting tag names.
+#	If this filter is passed, it will be called for every tag ref
+#	that points to a rewritten object (or to a tag object which
+#	points to a rewritten object). The original tag name is passed
+#	via standard input, and the new tag name is expected on standard
+#	output.
+#	
+#	The original tags are not deleted, but can be overwritten;
+#	use "--tag-name-filter=cat" to simply update the tags. In this
+#	case, be very careful and make sure you have the old tags
+#	backed up in case the conversion has run afoul.
+#
+#	Note that there is currently no support for proper rewriting of
+#	tag objects; in layman terms, if the tag has a message or signature
+#	attached, the rewritten tag won't have it. Sorry. (It is by
+#	definition impossible to preserve signatures at any rate, though.)
+#
+# EXAMPLE USAGE
+# -------------
+# Suppose you want to remove a file (containing confidential information
+# or copyright violation) from all commits:
+#
+#	git-filter-branch --tree-filter 'rm filename' newbranch
+#
+# A significantly faster version:
+#
+#	git-filter-branch --index-filter 'git-update-index --remove filename' newbranch
+#
+# Now, you will get the rewritten history saved in the branch 'newbranch'
+# (your current branch is left untouched).
+#
+# To "etch-graft" a commit to the revision history (set a commit to be
+# the parent of the current initial commit and propagate that):
+#
+#	git-filter-branch --parent-filter sed\ 's/^$/-p graftcommitid/' newbranch
+#
+# (if the parent string is empty - therefore we are dealing with the
+# initial commit - add graftcommit as a parent). Note that this assumes
+# history with a single root (that is, no git-merge without common ancestors
+# happened). If this is not the case, use:
+#
+#	git-filter-branch --parent-filter 'cat; [ "$GIT_COMMIT" = "COMMIT" ] && echo "-p GRAFTCOMMIT"' newbranch
+#
+# To remove commits authored by "Darl McBribe" from the history:
+#
+#	git-filter-branch --commit-filter 'if [ "$GIT_AUTHOR_NAME" = "Darl McBribe" ]; then shift; while [ -n "$1" ]; do shift; echo "$1"; shift; done; else git-commit-tree "$@"; fi' newbranch
+#
+# (the shift magic first throws away the tree id and then the -p
+# parameters). Note that this handles merges properly! In case Darl
+# committed a merge between P1 and P2, it will be propagated properly
+# and all children of the merge will become merge commits with P1,P2
+# as their parents instead of the merge commit.
+#
+# To restrict rewriting to only part of the history, use -r or -k or both.
+# Consider this history:
+#
+#	     D--E--F--G--H
+#	    /     /
+#	A--B-----C
+#
+# To rewrite only commits F,G,H, use:
+#
+#	git-filter-branch -r F ...
+#
+# To rewrite commits E,F,G,H, use one of these:
+#
+#	git-filter-branch -r E -k C ...
+#	git-filter-branch -k D -k C ...
+
+# Testsuite: TODO
+
+set -e
+
+USAGE="git-filter-branch [-d TEMPDIR] [-r STARTREV]... [-k KEEPREV]... [-s SRCBRANCH] [FILTERS] DESTBRANCH"
+. git-sh-setup
+
+map()
+{
+	[ -r "$workdir/../map/$1" ] || return 1
+	cat "$workdir/../map/$1"
+}
+
+# When piped a commit, output a script to set the ident of either
+# "author" or "committer
+
+set_ident () {
+	lid="$(echo "$1" | tr "A-Z" "a-z")"
+	uid="$(echo "$1" | tr "a-z" "A-Z")"
+	pick_id_script='
+		/^'$lid' /{
+			s/'\''/'\''\\'\'\''/g
+			h
+			s/^'$lid' \([^<]*\) <[^>]*> .*$/\1/
+			s/'\''/'\''\'\'\''/g
+			s/.*/export GIT_'$uid'_NAME='\''&'\''/p
+
+			g
+			s/^'$lid' [^<]* <\([^>]*\)> .*$/\1/
+			s/'\''/'\''\'\'\''/g
+			s/.*/export GIT_'$uid'_EMAIL='\''&'\''/p
+
+			g
+			s/^'$lid' [^<]* <[^>]*> \(.*\)$/\1/
+			s/'\''/'\''\'\'\''/g
+			s/.*/export GIT_'$uid'_DATE='\''&'\''/p
+
+			q
+		}
+	'
+
+	LANG=C LC_ALL=C sed -ne "$pick_id_script"
+	# Ensure non-empty id name.
+	echo "[ -n \"\$GIT_${uid}_NAME\" ] || export GIT_${uid}_NAME=\"\${GIT_${uid}_EMAIL%%@*}\""
+}
+
+# list all parent's object names for a given commit
+get_parents () {
+	git-rev-list -1 --parents "$1" | sed "s/^[0-9a-f]*//"
+}
+
+tempdir=.git-rewrite
+unchanged=" "
+filter_env=
+filter_tree=
+filter_index=
+filter_parent=
+filter_msg=cat
+filter_commit='git-commit-tree "$@"'
+filter_tag_name=
+srcbranch=HEAD
+while case "$#" in 0) usage;; esac
+do
+	case "$1" in
+	--)
+		shift
+		break
+		;;
+	-*)
+		;;
+	*)
+		break;
+	esac
+
+	# all switches take one argument
+	ARG="$1"
+	case "$#" in 1) usage ;; esac
+	shift
+	OPTARG="$1"
+	shift
+
+	case "$ARG" in
+	-d)
+		tempdir="$OPTARG"
+		;;
+	-r)
+		unchanged="$(get_parents "$OPTARG") $unchanged"
+		;;
+	-k)
+		unchanged="$(git-rev-parse "$OPTARG"^{commit}) $unchanged"
+		;;
+	--env-filter)
+		filter_env="$OPTARG"
+		;;
+	--tree-filter)
+		filter_tree="$OPTARG"
+		;;
+	--index-filter)
+		filter_index="$OPTARG"
+		;;
+	--parent-filter)
+		filter_parent="$OPTARG"
+		;;
+	--msg-filter)
+		filter_msg="$OPTARG"
+		;;
+	--commit-filter)
+		filter_commit="$OPTARG"
+		;;
+	--tag-name-filter)
+		filter_tag_name="$OPTARG"
+		;;
+	-s)
+		srcbranch="$OPTARG"
+		;;
+	*)
+		usage
+		;;
+	esac
+done
+
+dstbranch="$1"
+test -n "$dstbranch" || die "missing branch name"
+git-show-ref "refs/heads/$dstbranch" 2> /dev/null &&
+	die "branch $dstbranch already exists"
+
+test ! -e "$tempdir" || die "$tempdir already exists, please remove it"
+mkdir -p "$tempdir/t"
+cd "$tempdir/t"
+workdir="$(pwd)"
+
+case "$GIT_DIR" in
+/*)
+	;;
+*)
+	export GIT_DIR="$(pwd)/../../$GIT_DIR"
+	;;
+esac
+
+export GIT_INDEX_FILE="$(pwd)/../index"
+git-read-tree # seed the index file
+
+ret=0
+
+
+mkdir ../map # map old->new commit ids for rewriting parents
+
+# seed with identity mappings for the parents where we start off
+for commit in $unchanged; do
+	echo $commit > ../map/$commit
+done
+
+git-rev-list --reverse --topo-order $srcbranch --not $unchanged >../revs
+commits=$(cat ../revs | wc -l | tr -d " ")
+
+test $commits -eq 0 && die "Found nothing to rewrite"
+
+i=0
+while read commit; do
+	i=$((i+1))
+	printf "$commit ($i/$commits) "
+
+	git-read-tree -i -m $commit
+
+	export GIT_COMMIT=$commit
+	git-cat-file commit "$commit" >../commit
+
+	eval "$(set_ident AUTHOR <../commit)"
+	eval "$(set_ident COMMITTER <../commit)"
+	eval "$filter_env"
+
+	if [ "$filter_tree" ]; then
+		git-checkout-index -f -u -a
+		# files that $commit removed are now still in the working tree;
+		# remove them, else they would be added again
+		git-ls-files -z --others | xargs -0 rm -f
+		eval "$filter_tree"
+		git-diff-index -r $commit | cut -f 2- | tr '\n' '\0' | \
+			xargs -0 git-update-index --add --replace --remove
+		git-ls-files -z --others | \
+			xargs -0 git-update-index --add --replace --remove
+	fi
+
+	eval "$filter_index"
+
+	parentstr=
+	for parent in $(get_parents $commit); do
+		if [ -r "../map/$parent" ]; then
+			for reparent in $(cat "../map/$parent"); do
+				parentstr="$parentstr -p $reparent"
+			done
+		else
+			die "assertion failed: parent $parent for commit $commit not found in rewritten ones"
+		fi
+	done
+	if [ "$filter_parent" ]; then
+		parentstr="$(echo "$parentstr" | eval "$filter_parent")"
+	fi
+
+	sed -e '1,/^$/d' <../commit | \
+		eval "$filter_msg" | \
+		sh -c "$filter_commit" git-commit-tree $(git-write-tree) $parentstr | \
+		tee ../map/$commit
+done <../revs
+
+git-update-ref refs/heads/"$dstbranch" $(head -n 1 ../map/$(tail -n 1 ../revs))
+if [ "$(cat ../map/$(tail -n 1 ../revs) | wc -l)" -gt 1 ]; then
+	echo "WARNING: Your commit filter caused the head commit to expand to several rewritten commits. Only the first such commit was recorded as the current $dstbranch head but you will need to resolve the situation now (probably by manually merging the other commits). These are all the commits:" >&2
+	sed 's/^/	/' ../map/$(tail -n 1 ../revs) >&2
+	ret=1
+fi
+
+if [ "$filter_tag_name" ]; then
+	git-for-each-ref --format='%(objectname) %(objecttype) %(refname)' refs/tags |
+	while read sha1 type ref; do
+		ref="${ref#refs/tags/}"
+		# XXX: Rewrite tagged trees as well?
+		if [ "$type" != "commit" -a "$type" != "tag" ]; then
+			continue;
+		fi
+
+		if [ "$type" = "tag" ]; then
+			# Dereference to a commit
+			sha1t="$sha1"
+			sha1="$(git-rev-parse "$sha1"^{commit} 2>/dev/null)" || continue
+		fi
+
+		[ -f "../map/$sha1" ] || continue
+		new_sha1="$(cat "../map/$sha1")"
+		export GIT_COMMIT="$sha1"
+		new_ref="$(echo "$ref" | eval "$filter_tag_name")"
+
+		echo "$ref -> $new_ref ($sha1 -> $new_sha1)"
+
+		if [ "$type" = "tag" ]; then
+			# Warn that we are not rewriting the tag object itself.
+			warn "unreferencing tag object $sha1t"
+		fi
+
+		git-update-ref "refs/tags/$new_ref" "$new_sha1"
+	done
+fi
+
+cd ../..
+rm -rf "$tempdir"
+echo "Rewritten history saved to the $dstbranch branch"
+
+exit $ret
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
new file mode 100755
index 0000000..9a4dae4
--- /dev/null
+++ b/t/t7003-filter-branch.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+test_description='git-filter-branch'
+. ./test-lib.sh
+
+make_commit () {
+	lower=$(echo $1 | tr A-Z a-z)
+	echo $lower > $lower
+	git add $lower
+	git commit -m $1
+	git tag $1
+}
+
+test_expect_success 'setup' '
+	make_commit A
+	make_commit B
+	git checkout -b branch B
+	make_commit D
+	make_commit E
+	git checkout master
+	make_commit C
+	git checkout branch
+	git merge C
+	git tag F
+	make_commit G
+	make_commit H
+'
+
+H=$(git-rev-parse H)
+
+test_expect_success 'rewrite identically' '
+	git-filter-branch H2
+'
+
+test_expect_success 'result is really identical' '
+	test $H = $(git-rev-parse H2)
+'
+
+test_expect_success 'rewrite, renaming a specific file' '
+	git-filter-branch --tree-filter "mv d doh || :" H3
+'
+
+test_expect_success 'test that the file was renamed' '
+	test d = $(git show H3:doh)
+'
+
+test_done
-- 
1.5.2.2663.gd77e7-dirty

^ permalink raw reply related

* Re: [PATCH] Add git-filter-branch
From: Jakub Narebski @ 2007-06-03  0:46 UTC (permalink / raw)
  To: git
In-Reply-To: <Pine.LNX.4.64.0706030129110.4046@racer.site>

Johannes Schindelin wrote:

> This script is derived from Pasky's cg-admin-rewritehist.
> 
> In fact, it _is_ the same script, minimally adapted to work without cogito.
> It _should_ be able to perform the same tasks, even if only relying on
> core-git programs.
> 
> All the work is Pasky's, just the adaption is mine.

I was thinking about rewriting cg-adin-rewritehist as git-rewritehist
using Perl (IIRC it needs bash, not only POSIX shell), and make it
use git-fast-import.

But that was in planning (read: it would be nice...) phase...
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply

* [PATCH] Update to SubmittingPatches
From: Johannes Schindelin @ 2007-06-03  0:46 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Kristian Høgsberg, git
In-Reply-To: <7v8xb2qj37.fsf@assigned-by-dhcp.cox.net>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1716 bytes --]


Make people aware of our testsuite, and of non-ASCII encodings.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---

	On Sat, 2 Jun 2007, Junio C Hamano wrote:

	> Junio C Hamano <junkio@cox.net> writes:
	> 
	> > Kristian Høgsberg <hoegsberg@gmail.com> writes:
	> >
	> >> Encode ' ' using '=20' even though rfc2047 allows using '_' for
	> >> readability..
	> >
	> > Thanks.
	> >
	> > Your message was marked as iso-8859-1 even though it was utf-8
	> > (your signed-off-by line), so I'll fix it up with your From:
	> > header.
	> 
	> Oh, another thing.  Before you submit a patch, make sure the
	> whole testsuite in t/ passes by running "make test".

	We should remind people of both.

 Documentation/SubmittingPatches |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index b5f2ecd..b6e5847 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -14,6 +14,8 @@ Checklist (and a short version for the impatient):
 	  commit message (or just use the option "-s" when
 	  committing) to confirm that you agree to the Developer's
 	  Certificate of Origin
+	- make sure that you have tests for the bug you are fixing
+	- make sure that the test suit passes after your commit
 
 	Patch:
 
@@ -33,6 +35,8 @@ Checklist (and a short version for the impatient):
 	- if you change, add, or remove a command line option or
 	  make some other user interface change, the associated
 	  documentation should be updated as well.
+	- if your name is not writable in ASCII, make sure that 
+	  you send off a message in the correct encoding.
 
 Long version:
 
-- 
1.5.2.2663.gd77e7-dirty

^ permalink raw reply related

* Re: [PATCH] Add git-filter-branch
From: Johannes Schindelin @ 2007-06-03  0:50 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git
In-Reply-To: <f3t2mm$f0$1@sea.gmane.org>

Hi,

[thank you for not including me in the Cc: list]

On Sun, 3 Jun 2007, Jakub Narebski wrote:

> Johannes Schindelin wrote:
> 
> > This script is derived from Pasky's cg-admin-rewritehist.
> > 
> > In fact, it _is_ the same script, minimally adapted to work without cogito.
> > It _should_ be able to perform the same tasks, even if only relying on
> > core-git programs.
> > 
> > All the work is Pasky's, just the adaption is mine.
> 
> I was thinking about rewriting cg-adin-rewritehist as git-rewritehist
> using Perl (IIRC it needs bash, not only POSIX shell), and make it
> use git-fast-import.

First, it does not need Perl.

Second, it does not even need bash.

At least that is what I tried to make sure. I replaced the only instance 
of a bashim I was aware, namely the arrayism of $unchanged. It can be a 
string just as well, as we are only storing object names in it.

Tell me if it does not work for you.

Or even better, provide me with a test case that fails for you.

Ciao,
Dscho

^ permalink raw reply

* quieter installs
From: Shawn O. Pearce @ 2007-06-03  1:00 UTC (permalink / raw)
  To: Junio C Hamano, Alex Riesen; +Cc: git

So I'm looking at adding this to git-gui, to replace Alex's patch,
as it addresses most of the issues that Junio raised.  Thoughts?

I'm a little unhappy with how mess the install target is now, but
fortunately most of it is data driven through the other variables in
the Makefile, so hopefully I don't have to tweak it too frequently.
;-)

--8>--
git-gui: Quiet our installation process

Alex Riesen wanted a quieter installation process for git and its
contained git-gui.  His earlier patch to do this failed to work
properly when V=1, and didn't really give a great indication of
what the installation was doing.

These rules are a little bit on the messy side, as each of our
install actions is composed of at least two variables, but in the
V=1 case the text is identical to what we had before, while in the
non-V=1 case we use some more complex rules to show the interesting
details, and hide the less interesting bits.

We now can also set QUIET= (nothing) to see the rules that are used
when V= (nothing), so we can debug those too if we have to.  This is
actually a side-effect of how we insert the @ into the rules we use
for the "lists of things", like our builtins or our library files.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 Makefile |   42 +++++++++++++++++++++++++++++++++---------
 1 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/Makefile b/Makefile
index 3de0de1..a114a87 100644
--- a/Makefile
+++ b/Makefile
@@ -29,11 +29,35 @@ ifndef INSTALL
 	INSTALL = install
 endif
 
+INSTALL_D0 = $(INSTALL) -d -m755 # space is required here
+INSTALL_D1 =
+INSTALL_R0 = $(INSTALL) -m644 # space is required here
+INSTALL_R1 =
+INSTALL_X0 = $(INSTALL) -m755 # space is required here
+INSTALL_X1 =
+INSTALL_L0 = rm -f # space is required here
+INSTALL_L1 = && ln # space is required here
+INSTALL_L2 =
+INSTALL_L3 =
+
 ifndef V
-	QUIET_GEN      = @echo '   ' GEN $@;
-	QUIET_BUILT_IN = @echo '   ' BUILTIN $@;
-	QUIET_INDEX    = @echo '   ' INDEX $(dir $@);
+	QUIET          = @
+	QUIET_GEN      = $(QUIET)echo '   ' GEN $@ &&
+	QUIET_BUILT_IN = $(QUIET)echo '   ' BUILTIN $@ &&
+	QUIET_INDEX    = $(QUIET)echo '   ' INDEX $(dir $@) &&
 	QUIET_2DEVNULL = 2>/dev/null
+
+	INSTALL_D0 = dir=
+	INSTALL_D1 = && echo ' ' DEST $$dir && $(INSTALL) -d -m755 "$$dir"
+	INSTALL_R0 = src=
+	INSTALL_R1 = && echo '   ' INSTALL 644 `basename $$src` && $(INSTALL) -m644 $$src
+	INSTALL_X0 = src=
+	INSTALL_X1 = && echo '   ' INSTALL 755 `basename $$src` && $(INSTALL) -m755 $$src
+
+	INSTALL_L0 = dst=
+	INSTALL_L1 = && src=
+	INSTALL_L2 = && dst=
+	INSTALL_L3 = && echo '   ' 'LINK       ' `basename "$$dst"` '->' `basename "$$src"` && rm -f "$$dst" && ln "$$src" "$$dst"
 endif
 
 TCL_PATH   ?= tclsh
@@ -109,12 +133,12 @@ GIT-GUI-VARS: .FORCE-GIT-GUI-VARS
 all:: $(ALL_PROGRAMS) lib/tclIndex
 
 install: all
-	$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)'
-	$(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)'
-	$(foreach p,$(GITGUI_BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;)
-	$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(libdir_SQ)'
-	$(INSTALL) -m644 lib/tclIndex '$(DESTDIR_SQ)$(libdir_SQ)'
-	$(foreach p,$(ALL_LIBFILES), $(INSTALL) -m644 $p '$(DESTDIR_SQ)$(libdir_SQ)' ;)
+	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
+	$(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+	$(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
+	$(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(libdir_SQ)' $(INSTALL_D1)
+	$(QUIET)$(INSTALL_R0)lib/tclIndex $(INSTALL_R1) '$(DESTDIR_SQ)$(libdir_SQ)'
+	$(QUIET)$(foreach p,$(ALL_LIBFILES), $(INSTALL_R0)$p $(INSTALL_R1) '$(DESTDIR_SQ)$(libdir_SQ)' &&) true
 
 dist-version:
 	@mkdir -p $(TARDIR)
-- 
1.5.2.901.g27ad4

-- 
Shawn.

^ permalink raw reply related

* Re: What's cooking in git.git (topics)
From: Shawn O. Pearce @ 2007-06-03  1:10 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7v6466oygl.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> wrote:
> 'pu' has Shawn's 'pu' from git-gui, to help people experiment
> with the proposed blame viewer improvements more easily.  I
> personally like it quite a bit.

For what its worth, my 'pu' has the same policy as Junio's; it
rebases freely and topics can come and go from it at any time.
But that said, it is certainly suitable for Junio's 'pu'.  :-)

I just pushed an even newer version out a couple of minutes ago.
Now I'm running two passes of git-blame:

	*) Pass 1:  git-blame --incremental
	*) Pass 2:  git-blame -M -C -C --incremental

and the viewer shows them in two columns.  This gives you pretty
quick information about why a change exists, as you get both who
moved the block to where it is, and who originally wrote it.  ;-)

Lots of things still to be worked on in blame, like having it
keep track of what line(s) you are at or are trying to jump to.
I'll try to get to that stuff tonight or tomorrow.

-- 
Shawn.

^ permalink raw reply

* [PATCH 1/4] git-p4import: fix subcommand error handling
From: Scott Lamb @ 2007-06-03  3:58 UTC (permalink / raw)
  To: git, Junio C Hamano; +Cc: Scott Lamb
In-Reply-To: <4ACE2ABC-8D73-4097-87AC-F3B27EDA97DE@slamb.org>

Use the Python "subcommand" module to properly handle the subcommand
pipeline and raise exceptions on error.

Signed-off-by: Scott Lamb <slamb@slamb.org>
---
I folded the elimination of the shell pipelines into this patch - the error
handling couldn't work otherwise.

The difference between exceptions paths with "die" and ones with an exception
thrown to the top is somewhat arbitrary; I tried to use it to distinguish
between user error and bugs.

 git-p4import.py |  166 +++++++++++++++++++++++++++++++++----------------------
 1 files changed, 99 insertions(+), 67 deletions(-)

diff --git a/git-p4import.py b/git-p4import.py
index 60a758b..002f8d8 100644
--- a/git-p4import.py
+++ b/git-p4import.py
@@ -13,6 +13,9 @@ import os
 import sys
 import time
 import getopt
+import subprocess
+import re
+import errno
 
 from signal import signal, \
    SIGPIPE, SIGINT, SIG_DFL, \
@@ -34,7 +37,7 @@ def usage():
     sys.exit(1)
 
 verbosity = 1
-logfile = "/dev/null"
+logfile = file("/dev/null", "a")
 ignore_warnings = False
 stitch = 0
 tagall = True
@@ -44,59 +47,70 @@ def report(level, msg, *args):
     global logfile
     for a in args:
         msg = "%s %s" % (msg, a)
-    fd = open(logfile, "a")
-    fd.writelines(msg)
-    fd.close()
+    logfile.writelines(msg)
     if level <= verbosity:
         print msg
 
+class P4Exception(Exception):
+    def __init__(self, cmd, errmsg):
+        Exception.__init__(self, '%r: %s' % (cmd, errmsg))
+        self.cmd = cmd
+        self.errmsg = errmsg
+
 class p4_command:
     def __init__(self, _repopath):
-        try:
-            global logfile
-            self.userlist = {}
-            if _repopath[-1] == '/':
-                self.repopath = _repopath[:-1]
-            else:
-                self.repopath = _repopath
-            if self.repopath[-4:] != "/...":
-                self.repopath= "%s/..." % self.repopath
-            f=os.popen('p4 -V 2>>%s'%logfile, 'rb')
-            a = f.readlines()
-            if f.close():
-                raise
-        except:
-                die("Could not find the \"p4\" command")
+        self.userlist = {}
+        if _repopath[-1] == '/':
+            self.repopath = _repopath[:-1]
+        else:
+            self.repopath = _repopath
+        if self.repopath[-4:] != "/...":
+            self.repopath= "%s/..." % self.repopath
+        p4 = subprocess.Popen(['p4', '-V'],
+                              stdout=file('/dev/null', 'a'),
+                              stderr=subprocess.PIPE)
+        err = p4.stderr.read()
+        if p4.wait() != 0:
+            die("Could not run the \"p4\" command: %r" % (err,))
 
     def p4(self, cmd, *args):
         global logfile
         cmd = "%s %s" % (cmd, ' '.join(args))
+        cmdlist = ['p4', '-G'] + cmd.split(' ')
         report(2, "P4:", cmd)
-        f=os.popen('p4 -G %s 2>>%s' % (cmd,logfile), 'rb')
+        p4 = subprocess.Popen(cmdlist,
+                              stdout=subprocess.PIPE,
+                              stderr=logfile)
         list = []
         while 1:
            try:
-                list.append(marshal.load(f))
+                elem = marshal.load(p4.stdout)
            except EOFError:
                 break
-        self.ret = f.close()
+           if elem['code'] == 'error':
+                raise P4Exception(cmd, elem['data'])
+           list.append(elem)
+        if p4.wait() != 0:
+            raise Exception("'p4 %s' failed" % (cmd,))
         return list
 
     def sync(self, id, force=False, trick=False, test=False):
-        if force:
-            ret = self.p4("sync -f %s@%s"%(self.repopath, id))[0]
-        elif trick:
-            ret = self.p4("sync -k %s@%s"%(self.repopath, id))[0]
-        elif test:
-            ret = self.p4("sync -n %s@%s"%(self.repopath, id))[0]
-        else:
-            ret = self.p4("sync    %s@%s"%(self.repopath, id))[0]
-        if ret['code'] == "error":
-             data = ret['data'].upper()
-             if data.find('VIEW') > 0:
-                 die("Perforce reports %s is not in client view"% self.repopath)
-             elif data.find('UP-TO-DATE') < 0:
-                 die("Could not sync files from perforce", self.repopath)
+        try:
+            if force:
+                self.p4("sync -f %s@%s"%(self.repopath, id))
+            elif trick:
+                self.p4("sync -k %s@%s"%(self.repopath, id))
+            elif test:
+                self.p4("sync -n %s@%s"%(self.repopath, id))
+            else:
+                self.p4("sync    %s@%s"%(self.repopath, id))
+        except P4Exception, e:
+            data = e.errmsg.upper()
+            if data.find('VIEW') > 0:
+                die("Perforce reports %s is not in client view: %s"
+                    % (self.repopath, e))
+            elif data.find('UP-TO-DATE') < 0:
+                die(e)
 
     def changes(self, since=0):
         try:
@@ -105,8 +119,8 @@ class p4_command:
                 list.append(rec['change'])
             list.reverse()
             return list
-        except:
-            return []
+        except P4Exception, e:
+            die(e)
 
     def authors(self, filename):
         f=open(filename)
@@ -122,7 +136,8 @@ class p4_command:
             try:
                 user = self.p4("users", id)[0]
                 self.userlist[id] = (user['FullName'], user['Email'])
-            except:
+            except P4Exception, e:
+                report(2, "P4: missing user %s" % (id,))
                 self.userlist[id] = (id, "")
         return self.userlist[id]
 
@@ -143,7 +158,7 @@ class p4_command:
     def where(self):
         try:
             return self.p4("where %s" % self.repopath)[-1]['path']
-        except:
+        except P4Exception, e:
             return ""
 
     def describe(self, num):
@@ -153,16 +168,18 @@ class p4_command:
         self.date = self._format_date(time.localtime(long(desc['time'])))
         return self
 
+class GitException(Exception): pass
+
 class git_command:
     def __init__(self):
         try:
             self.version = self.git("--version")[0][12:].rstrip()
-        except:
-            die("Could not find the \"git\" command")
+        except GitException, e:
+            die(e)
         try:
             self.gitdir = self.get_single("rev-parse --git-dir")
             report(2, "gdir:", self.gitdir)
-        except:
+        except GitException, e:
             die("Not a git repository... did you forget to \"git init\" ?")
         try:
             self.cdup = self.get_single("rev-parse --show-cdup")
@@ -170,38 +187,47 @@ class git_command:
                 os.chdir(self.cdup)
             self.topdir = os.getcwd()
             report(2, "topdir:", self.topdir)
-        except:
+        except GitException, e:
             die("Could not find top git directory")
 
-    def git(self, cmd):
-        global logfile
+    def git(self, cmd, stdin=None):
         report(2, "GIT:", cmd)
-        f=os.popen('git %s 2>>%s' % (cmd,logfile), 'rb')
-        r=f.readlines()
-        self.ret = f.close()
-        return r
+        cmdlist = ['git'] + cmd.split(' ')
+        git = subprocess.Popen(cmdlist,
+                               stdin=subprocess.PIPE,
+                               stdout=subprocess.PIPE,
+                               stderr=subprocess.PIPE)
+        stdout, stderr = git.communicate(stdin)
+        if git.wait() != 0:
+            raise GitException("'git %s' failed: %s" % (cmd, stderr))
+        if stderr != '':
+            report(2, stderr)
+        return re.findall(r'.*\n', stdout)
 
     def get_single(self, cmd):
-        return self.git(cmd)[0].rstrip()
+        list = self.git(cmd)
+        if len(list) != 1:
+            raise GitException("%r returned %r" % (cmd, list))
+        return list[0].rstrip()
 
     def current_branch(self):
         try:
             testit = self.git("rev-parse --verify HEAD")[0]
             return self.git("symbolic-ref HEAD")[0][11:].rstrip()
-        except:
+        except GitException, e:
             return None
 
     def get_config(self, variable):
         try:
             return self.git("config --get %s" % variable)[0].rstrip()
-        except:
+        except GitException, e:
             return None
 
     def set_config(self, variable, value):
         try:
             self.git("config %s %s"%(variable, value) )
-        except:
-            die("Could not set %s to " % variable, value)
+        except GitException, e:
+            die(e)
 
     def make_tag(self, name, head):
         self.git("tag -f %s %s"%(name,head))
@@ -217,7 +243,8 @@ class git_command:
             return 0
 
     def update_index(self):
-        self.git("ls-files -m -d -o -z | git update-index --add --remove -z --stdin")
+        files = self.git("ls-files -m -d -o -z")
+        self.git("update-index --add --remove -z --stdin", stdin=files)
 
     def checkout(self, branch):
         self.git("checkout %s" % branch)
@@ -226,15 +253,21 @@ class git_command:
         self.git("symbolic-ref HEAD refs/heads/%s" % branch)
 
     def remove_files(self):
-        self.git("ls-files | xargs rm")
+        files = self.git("ls-files")
+        for file in files:
+            os.unlink(file)
 
     def clean_directories(self):
         self.git("clean -d")
 
     def fresh_branch(self, branch):
         report(1, "Creating new branch", branch)
-        self.git("ls-files | xargs rm")
-        os.remove(".git/index")
+        self.remove_files()
+        try:
+            os.remove(".git/index")
+        except OSError, e:
+            if e.errno != errno.ENOENT:
+                raise
         self.repoint_head(branch)
         self.git("clean -d")
 
@@ -243,21 +276,17 @@ class git_command:
 
     def commit(self, author, email, date, msg, id):
         self.update_index()
-        fd=open(".msg", "w")
-        fd.writelines(msg)
-        fd.close()
         try:
                 current = self.get_single("rev-parse --verify HEAD")
                 head = "-p HEAD"
-        except:
+        except GitException, e:
                 current = ""
                 head = ""
         tree = self.get_single("write-tree")
         for r,l in [('DATE',date),('NAME',author),('EMAIL',email)]:
             os.environ['GIT_AUTHOR_%s'%r] = l
             os.environ['GIT_COMMITTER_%s'%r] = l
-        commit = self.get_single("commit-tree %s %s < .msg" % (tree,head))
-        os.remove(".msg")
+        commit = self.get_single("commit-tree %s %s" % (tree,head), stdin=msg)
         self.make_tag("p4/%s"%id, commit)
         self.git("update-ref HEAD %s %s" % (commit, current) )
 
@@ -273,7 +302,7 @@ for o, a in opts:
     if o == "-v":
         verbosity += 1
     if o in ("--log"):
-        logfile = a
+        logfile = file(a, "a")
     if o in ("--notags"):
         tagall = False
     if o in ("-h", "--help"):
@@ -293,7 +322,10 @@ for o, a in opts:
 
 if len(args) == 2:
     branch = args[1]
-    git.checkout(branch)
+    try:
+        git.checkout(branch)
+    except GitException, e:
+        pass
     if branch == git.current_branch():
         die("Branch %s already exists!" % branch)
     report(1, "Setting perforce to ", args[0])
-- 
1.5.2

^ permalink raw reply related

* [PATCH 2/4] git-p4import: use lists of subcommand arguments
From: Scott Lamb @ 2007-06-03  3:58 UTC (permalink / raw)
  To: git, Junio C Hamano; +Cc: Scott Lamb
In-Reply-To: <1180843126948-git-send-email-slamb@slamb.org>

This fixes problems with spaces in filenames.

Signed-off-by: Scott Lamb <slamb@slamb.org>
---
 git-p4import.py |   84 +++++++++++++++++++++++++++++-------------------------
 1 files changed, 45 insertions(+), 39 deletions(-)

diff --git a/git-p4import.py b/git-p4import.py
index 002f8d8..54e5e9e 100644
--- a/git-p4import.py
+++ b/git-p4import.py
@@ -73,11 +73,12 @@ class p4_command:
         if p4.wait() != 0:
             die("Could not run the \"p4\" command: %r" % (err,))
 
-    def p4(self, cmd, *args):
+    def p4(self, args):
         global logfile
-        cmd = "%s %s" % (cmd, ' '.join(args))
-        cmdlist = ['p4', '-G'] + cmd.split(' ')
+        cmd = ' '.join(args)
         report(2, "P4:", cmd)
+        cmdlist = ['p4', '-G']
+        cmdlist.extend(args)
         p4 = subprocess.Popen(cmdlist,
                               stdout=subprocess.PIPE,
                               stderr=logfile)
@@ -97,13 +98,14 @@ class p4_command:
     def sync(self, id, force=False, trick=False, test=False):
         try:
             if force:
-                self.p4("sync -f %s@%s"%(self.repopath, id))
+                extra = ["-f"]
             elif trick:
-                self.p4("sync -k %s@%s"%(self.repopath, id))
+                extra = ["-k"]
             elif test:
-                self.p4("sync -n %s@%s"%(self.repopath, id))
+                extra = ["-n"]
             else:
-                self.p4("sync    %s@%s"%(self.repopath, id))
+                extra = []
+            self.p4(["sync"] + extra + ["%s@%s"%(self.repopath, id)])
         except P4Exception, e:
             data = e.errmsg.upper()
             if data.find('VIEW') > 0:
@@ -115,7 +117,8 @@ class p4_command:
     def changes(self, since=0):
         try:
             list = []
-            for rec in self.p4("changes %s@%s,#head" % (self.repopath, since+1)):
+            for rec in self.p4(["changes", "%s@%s,#head"
+                               % (self.repopath, since+1)]):
                 list.append(rec['change'])
             list.reverse()
             return list
@@ -134,7 +137,7 @@ class p4_command:
     def _get_user(self, id):
         if not self.userlist.has_key(id):
             try:
-                user = self.p4("users", id)[0]
+                user = self.p4(["users", id])[0]
                 self.userlist[id] = (user['FullName'], user['Email'])
             except P4Exception, e:
                 report(2, "P4: missing user %s" % (id,))
@@ -157,12 +160,12 @@ class p4_command:
 
     def where(self):
         try:
-            return self.p4("where %s" % self.repopath)[-1]['path']
+            return self.p4(["where", self.repopath])[-1]['path']
         except P4Exception, e:
             return ""
 
     def describe(self, num):
-        desc = self.p4("describe -s", num)[0]
+        desc = self.p4(["describe", "-s", num])[0]
         self.msg = desc['desc']
         self.author, self.email = self._get_user(desc['user'])
         self.date = self._format_date(time.localtime(long(desc['time'])))
@@ -173,16 +176,16 @@ class GitException(Exception): pass
 class git_command:
     def __init__(self):
         try:
-            self.version = self.git("--version")[0][12:].rstrip()
+            self.version = self.git(["--version"])[0][12:].rstrip()
         except GitException, e:
             die(e)
         try:
-            self.gitdir = self.get_single("rev-parse --git-dir")
+            self.gitdir = self.get_single(["rev-parse", "--git-dir"])
             report(2, "gdir:", self.gitdir)
         except GitException, e:
             die("Not a git repository... did you forget to \"git init\" ?")
         try:
-            self.cdup = self.get_single("rev-parse --show-cdup")
+            self.cdup = self.get_single(["rev-parse", "--show-cdup"])
             if self.cdup != "":
                 os.chdir(self.cdup)
             self.topdir = os.getcwd()
@@ -190,9 +193,11 @@ class git_command:
         except GitException, e:
             die("Could not find top git directory")
 
-    def git(self, cmd, stdin=None):
+    def git(self, args, stdin=None):
+        cmd = ' '.join(args)
         report(2, "GIT:", cmd)
-        cmdlist = ['git'] + cmd.split(' ')
+        cmdlist = ['git']
+        cmdlist.extend(args)
         git = subprocess.Popen(cmdlist,
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
@@ -204,37 +209,37 @@ class git_command:
             report(2, stderr)
         return re.findall(r'.*\n', stdout)
 
-    def get_single(self, cmd):
-        list = self.git(cmd)
+    def get_single(self, args, stdin=None):
+        list = self.git(args, stdin=stdin)
         if len(list) != 1:
-            raise GitException("%r returned %r" % (cmd, list))
+            raise GitException("%r returned %r" % (' '.join(args), list))
         return list[0].rstrip()
 
     def current_branch(self):
         try:
-            testit = self.git("rev-parse --verify HEAD")[0]
-            return self.git("symbolic-ref HEAD")[0][11:].rstrip()
+            testit = self.git(["rev-parse", "--verify", "HEAD"])[0]
+            return self.git(["symbolic-ref", "HEAD"])[0][11:].rstrip()
         except GitException, e:
             return None
 
     def get_config(self, variable):
         try:
-            return self.git("config --get %s" % variable)[0].rstrip()
+            return self.git(["config", "--get", variable])[0].rstrip()
         except GitException, e:
             return None
 
     def set_config(self, variable, value):
         try:
-            self.git("config %s %s"%(variable, value) )
+            self.git(["config", variable, value])
         except GitException, e:
             die(e)
 
     def make_tag(self, name, head):
-        self.git("tag -f %s %s"%(name,head))
+        self.git(["tag", "-f", name, head])
 
     def top_change(self, branch):
         try:
-            a=self.get_single("name-rev --tags refs/heads/%s" % branch)
+            a=self.get_single(["name-rev", "--tags", "refs/heads/%s" % branch])
             loc = a.find(' tags/') + 6
             if a[loc:loc+3] != "p4/":
                 raise
@@ -243,22 +248,23 @@ class git_command:
             return 0
 
     def update_index(self):
-        files = self.git("ls-files -m -d -o -z")
-        self.git("update-index --add --remove -z --stdin", stdin=files)
+        files = self.git("ls-files -m -d -o -z".split(" "))
+        self.git("update-index --add --remove -z --stdin".split(" "),
+                 stdin=files)
 
     def checkout(self, branch):
-        self.git("checkout %s" % branch)
+        self.git(["checkout", branch])
 
     def repoint_head(self, branch):
-        self.git("symbolic-ref HEAD refs/heads/%s" % branch)
+        self.git(["symbolic-ref", "HEAD", "refs/heads/%s" % branch])
 
     def remove_files(self):
-        files = self.git("ls-files")
+        files = self.git(["ls-files"])
         for file in files:
             os.unlink(file)
 
     def clean_directories(self):
-        self.git("clean -d")
+        self.git(["clean", "-d"])
 
     def fresh_branch(self, branch):
         report(1, "Creating new branch", branch)
@@ -269,7 +275,7 @@ class git_command:
             if e.errno != errno.ENOENT:
                 raise
         self.repoint_head(branch)
-        self.git("clean -d")
+        self.clean_directories()
 
     def basedir(self):
         return self.topdir
@@ -277,18 +283,18 @@ class git_command:
     def commit(self, author, email, date, msg, id):
         self.update_index()
         try:
-                current = self.get_single("rev-parse --verify HEAD")
-                head = "-p HEAD"
+                current = [self.get_single(["rev-parse", "--verify", "HEAD"])]
+                head = ["-p", "HEAD"]
         except GitException, e:
-                current = ""
-                head = ""
-        tree = self.get_single("write-tree")
+                current = []
+                head = []
+        tree = self.get_single(["write-tree"])
         for r,l in [('DATE',date),('NAME',author),('EMAIL',email)]:
             os.environ['GIT_AUTHOR_%s'%r] = l
             os.environ['GIT_COMMITTER_%s'%r] = l
-        commit = self.get_single("commit-tree %s %s" % (tree,head), stdin=msg)
+        commit = self.get_single(["commit-tree", tree] + head, stdin=msg)
         self.make_tag("p4/%s"%id, commit)
-        self.git("update-ref HEAD %s %s" % (commit, current) )
+        self.git(["update-ref", "HEAD", commit] + current)
 
 try:
     opts, args = getopt.getopt(sys.argv[1:], "qhvt:",
-- 
1.5.2

^ permalink raw reply related

* [PATCH 3/4] git-p4import: resume on correct p4 changeset
From: Scott Lamb @ 2007-06-03  3:58 UTC (permalink / raw)
  To: git, Junio C Hamano; +Cc: Scott Lamb
In-Reply-To: <11808431291938-git-send-email-slamb@slamb.org>

This had been resuming on change 222 rather than 22283.

top_change's removal of the last two characters must have predated the use
of rstrip() in get_single(). A regexp should be less fragile, or at least
more obvious when it breaks.

Signed-off-by: Scott Lamb <slamb@slamb.org>
---
 git-p4import.py |   13 +++++++------
 1 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/git-p4import.py b/git-p4import.py
index 54e5e9e..e7a52b3 100644
--- a/git-p4import.py
+++ b/git-p4import.py
@@ -237,15 +237,16 @@ class git_command:
     def make_tag(self, name, head):
         self.git(["tag", "-f", name, head])
 
+    _tag_re = re.compile(r'tags/p4/(\d+)')
     def top_change(self, branch):
         try:
             a=self.get_single(["name-rev", "--tags", "refs/heads/%s" % branch])
-            loc = a.find(' tags/') + 6
-            if a[loc:loc+3] != "p4/":
-                raise
-            return int(a[loc+3:][:-2])
-        except:
-            return 0
+        except GitException, e:
+            return 0 # fresh repository
+        m = self._tag_re.search(a)
+        if m is None:
+            raise Exception('unable to parse: %r' % (a,))
+        return int(m.group(1))
 
     def update_index(self):
         files = self.git("ls-files -m -d -o -z".split(" "))
-- 
1.5.2

^ permalink raw reply related

* [PATCH 4/4] git-p4import: partial history
From: Scott Lamb @ 2007-06-03  3:58 UTC (permalink / raw)
  To: git, Junio C Hamano; +Cc: Scott Lamb
In-Reply-To: <11808431364066-git-send-email-slamb@slamb.org>

Allow importing partial history, which is quicker and may be necessary with
a low Perforce MaxScanRows limit.

Signed-off-by: Scott Lamb <slamb@slamb.org>
---
 Documentation/git-p4import.txt |    6 ++++++
 git-p4import.py                |   14 ++++++++++++--
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-p4import.txt b/Documentation/git-p4import.txt
index 714abbe..bf40b5a 100644
--- a/Documentation/git-p4import.txt
+++ b/Documentation/git-p4import.txt
@@ -10,6 +10,7 @@ SYNOPSIS
 --------
 [verse]
 `git-p4import` [-q|-v] [--notags] [--authors <file>] [-t <timezone>]
+               [--start-with <change>]
                <//p4repo/path> <branch>
 `git-p4import` --stitch <//p4repo/path>
 `git-p4import`
@@ -59,6 +60,11 @@ OPTIONS
 	etc.  You only need to specify this once, it will be saved in
 	the git config file for the repository.
 
+\--start-with::
+	Start the import with the given Perforce change. A partial history can
+	be much faster to generate and is possible even with a low MaxScanRows
+	limit.
+
 <//p4repo/path>::
 	The Perforce path that will be imported into the specified branch.
 
diff --git a/git-p4import.py b/git-p4import.py
index e7a52b3..c7a2033 100644
--- a/git-p4import.py
+++ b/git-p4import.py
@@ -33,7 +33,12 @@ def die(msg, *args):
     sys.exit(1)
 
 def usage():
-    print "USAGE: git-p4import [-q|-v]  [--authors=<file>]  [-t <timezone>]  [//p4repo/path <branch>]"
+    print "usage:"
+    print "  git-p4import [-q|-v] [--notags] [--authors <file>] [-t <timezone>]"
+    print "               [--start-with <change>]"
+    print "               <//p4repo/path> <branch>"
+    print "  git-p4import --stitch <//p4repo/path>"
+    print "  git-p4import"
     sys.exit(1)
 
 verbosity = 1
@@ -41,6 +46,7 @@ logfile = file("/dev/null", "a")
 ignore_warnings = False
 stitch = 0
 tagall = True
+start_with = 0
 
 def report(level, msg, *args):
     global verbosity
@@ -299,7 +305,8 @@ class git_command:
 
 try:
     opts, args = getopt.getopt(sys.argv[1:], "qhvt:",
-            ["authors=","help","stitch=","timezone=","log=","ignore","notags"])
+            ["authors=","help","stitch=","timezone=","log=","ignore","notags",
+             "start-with="])
 except getopt.GetoptError:
     usage()
 
@@ -316,6 +323,8 @@ for o, a in opts:
         usage()
     if o in ("--ignore"):
         ignore_warnings = True
+    if o in ("--start-with"):
+        start_with = int(a)
 
 git = git_command()
 branch=git.current_branch()
@@ -361,6 +370,7 @@ if stitch == 0:
     top = git.top_change(branch)
 else:
     top = 0
+top = max(top, start_with)
 changes = p4.changes(top)
 count = len(changes)
 if count == 0:
-- 
1.5.2

^ permalink raw reply related


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