* Re: Volume of commits
From: Sven Verdoolaege @ 2007-07-13 10:30 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: VMiklos, Fredrik Tolf, git
In-Reply-To: <Pine.LNX.4.64.0707121451290.4516@racer.site>
On Thu, Jul 12, 2007 at 02:59:53PM +0100, Johannes Schindelin wrote:
> In this case, "messy history" means that there are tiny patches which are
> often in the wrong order, or should be squashed into one commit. "git
> rebase -i upstream" presents you with the list of A - HEAD, and you can
> reorder the patches. If you want to, you can combine ("squash") some
> into one commit, or you can skip it, by removing the corresponding line.
If I squash a whole series of commits, how do I prevent git-rebase -i
from firing up an editor after every single commit in the series?
Also, if I do the following:
bash-3.00$ git init
Initialized empty Git repository in .git/
bash-3.00$ for i in a b c; do touch $i; git add $i; git commit -m $i -a; done
Created initial commit 19a8485: a
0 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 a
Created commit 4a00f85: b
0 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 b
Created commit defe3b5: c
0 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 c
bash-3.00$ git rebase -i HEAD~2
and then replace the second "pick" by "squash", then I get presented
a commit message that contains the commit message of "c" twice and
after the rebase there are still three commits in the history.
This is with git version 1.5.3.rc1.10.gae1ae
(on top of v1.5.3-rc1-4-gaf83bed).
skimo
^ permalink raw reply
* Re: Better handling of local changes in 'gitk'?
From: Paul Mackerras @ 2007-07-13 10:09 UTC (permalink / raw)
To: Linus Torvalds, Git Mailing List
In-Reply-To: <18071.19489.6733.665052@cargo.ozlabs.ibm.com>
I wrote:
> Try this, let me know what you think. I called the changes in the
> working directory "Local uncommitted changes, not checked in to index"
> and the changes in the index "Local changes checked in to index but
> not committed". If you prefer some other wording, let me know. I
> made the working directory commit red (as before) and the index commit
> magenta, as being between red and blue. The index commit gets a fake
> SHA1 id of 00..001.
I should add that I'm sure that gitk won't yet do the right thing if
there are files in the index at other than stage 0, or if the local
changes are the result of an incomplete merge. (In the latter case I
suppose one or other of the fake commits should have multiple parents,
but I don't have the infrastructure to add fake commits with multiple
parents yet.)
Paul.
^ permalink raw reply
* git-svn patch faulty (was: failing to send patches to the list)
From: martin f krafft @ 2007-07-13 9:56 UTC (permalink / raw)
To: git discussion list
In-Reply-To: <20070713093050.GA18001@lapse.madduck.net>
[-- Attachment #1: Type: text/plain, Size: 762 bytes --]
Hi there,
still not having figured out the problem with the list (and I did
contact postmaster@), I just discovered that in fact the patch only
handles git-svn clone, not git-svn init. Thus, it's best to ignore
it for now. I am sorry for not taking enough care before publishing
it.
The openssl-autodetect patch does work and is ready for inclusion,
if you agree.
--
martin; (greetings from the heart of the sun.)
\____ echo mailto: !#^."<*>"|tr "<*> mailto:" net@madduck
spamtraps: madduck.bogus@madduck.net
"if builders built buildings the way
programmers wrote programs,
then the first woodpecker that came along
would destroy civilization."
-- gerald weinberg
[-- Attachment #2: Digital signature (GPG/PGP) --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: Better handling of local changes in 'gitk'?
From: Paul Mackerras @ 2007-07-13 9:55 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Git Mailing List
In-Reply-To: <alpine.LFD.0.999.0707121214420.20061@woody.linux-foundation.org>
Linus Torvalds writes:
> It would be very nice to have *two* such commits (either or both of which
> just disappear), where the top-most is the diff to the index, and the
> second is the diff from the index to HEAD.
Try this, let me know what you think. I called the changes in the
working directory "Local uncommitted changes, not checked in to index"
and the changes in the index "Local changes checked in to index but
not committed". If you prefer some other wording, let me know. I
made the working directory commit red (as before) and the index commit
magenta, as being between red and blue. The index commit gets a fake
SHA1 id of 00..001.
Paul.
diff --git a/gitk b/gitk
index 39e452a..7ce86b8 100755
--- a/gitk
+++ b/gitk
@@ -262,11 +262,11 @@ proc chewcommits {view} {
set tlimit [expr {[clock clicks -milliseconds] + 50}]
set more [layoutmore $tlimit $allread]
if {$allread && !$more} {
- global displayorder nullid commitidx phase
+ global displayorder commitidx phase
global numcommits startmsecs
if {[info exists pending_select]} {
- set row [expr {[lindex $displayorder 0] eq $nullid}]
+ set row [first_real_row]
selectline $row 1
}
if {$commitidx($curview) > 0} {
@@ -437,6 +437,19 @@ proc readrefs {} {
}
}
+# skip over fake commits
+proc first_real_row {} {
+ global nullid nullid2 displayorder numcommits
+
+ for {set row 0} {$row < $numcommits} {incr row} {
+ set id [lindex $displayorder $row]
+ if {$id ne $nullid && $id ne $nullid2} {
+ break
+ }
+ }
+ return $row
+}
+
# update things for a head moved to a child of its previous location
proc movehead {id name} {
global headids idheads
@@ -1871,7 +1884,7 @@ proc showview {n} {
} elseif {$selid ne {}} {
set pending_select $selid
} else {
- set row [expr {[lindex $displayorder 0] eq $nullid}]
+ set row [first_real_row]
if {$row < $numcommits} {
selectline $row 0
} else {
@@ -2643,7 +2656,7 @@ proc layoutmore {tmax allread} {
proc showstuff {canshow last} {
global numcommits commitrow pending_select selectedline curview
- global lookingforhead mainheadid displayorder nullid selectfirst
+ global lookingforhead mainheadid displayorder selectfirst
global lastscrollset
if {$numcommits == 0} {
@@ -2676,7 +2689,7 @@ proc showstuff {canshow last} {
if {[info exists selectedline] || [info exists pending_select]} {
set selectfirst 0
} else {
- set l [expr {[lindex $displayorder 0] eq $nullid}]
+ set l [first_real_row]
selectline $l 1
set selectfirst 0
}
@@ -2700,48 +2713,93 @@ proc doshowlocalchanges {} {
}
proc dohidelocalchanges {} {
- global lookingforhead localrow lserial
+ global lookingforhead localfrow localirow lserial
set lookingforhead 0
- if {$localrow >= 0} {
- removerow $localrow
- set localrow -1
+ if {$localfrow >= 0} {
+ removerow $localfrow
+ set localfrow -1
+ if {$localirow > 0} {
+ incr localirow -1
+ }
+ }
+ if {$localirow >= 0} {
+ removerow $localirow
+ set localirow -1
}
incr lserial
}
-# spawn off a process to do git diff-index HEAD
+# spawn off a process to do git diff-index --cached HEAD
proc dodiffindex {} {
- global localrow lserial
+ global localirow localfrow lserial
incr lserial
- set localrow -1
- set fd [open "|git diff-index HEAD" r]
+ set localfrow -1
+ set localirow -1
+ set fd [open "|git diff-index --cached HEAD" r]
fconfigure $fd -blocking 0
filerun $fd [list readdiffindex $fd $lserial]
}
proc readdiffindex {fd serial} {
- global localrow commitrow mainheadid nullid curview
+ global localirow commitrow mainheadid nullid2 curview
global commitinfo commitdata lserial
+ set isdiff 1
if {[gets $fd line] < 0} {
- if {[eof $fd]} {
- close $fd
- return 0
+ if {![eof $fd]} {
+ return 1
}
- return 1
+ set isdiff 0
}
# we only need to see one line and we don't really care what it says...
close $fd
- if {$serial == $lserial && $localrow == -1} {
+ # now see if there are any local changes not checked in to the index
+ if {$serial == $lserial} {
+ set fd [open "|git diff-files" r]
+ fconfigure $fd -blocking 0
+ filerun $fd [list readdifffiles $fd $serial]
+ }
+
+ if {$isdiff && $serial == $lserial && $localirow == -1} {
+ # add the line for the changes in the index to the graph
+ set localirow $commitrow($curview,$mainheadid)
+ set hl "Local changes checked in to index but not committed"
+ set commitinfo($nullid2) [list $hl {} {} {} {} " $hl\n"]
+ set commitdata($nullid2) "\n $hl\n"
+ insertrow $localirow $nullid2
+ }
+ return 0
+}
+
+proc readdifffiles {fd serial} {
+ global localirow localfrow commitrow mainheadid nullid curview
+ global commitinfo commitdata lserial
+
+ set isdiff 1
+ if {[gets $fd line] < 0} {
+ if {![eof $fd]} {
+ return 1
+ }
+ set isdiff 0
+ }
+ # we only need to see one line and we don't really care what it says...
+ close $fd
+
+ if {$isdiff && $serial == $lserial && $localfrow == -1} {
# add the line for the local diff to the graph
- set localrow $commitrow($curview,$mainheadid)
- set hl "Local uncommitted changes"
+ if {$localirow >= 0} {
+ set localfrow $localirow
+ incr localirow
+ } else {
+ set localfrow $commitrow($curview,$mainheadid)
+ }
+ set hl "Local uncommitted changes, not checked in to index"
set commitinfo($nullid) [list $hl {} {} {} {} " $hl\n"]
set commitdata($nullid) "\n $hl\n"
- insertrow $localrow $nullid
+ insertrow $localfrow $nullid
}
return 0
}
@@ -3338,12 +3396,14 @@ proc drawcmittext {id row col} {
global commitlisted commitinfo rowidlist parentlist
global rowtextx idpos idtags idheads idotherrefs
global linehtag linentag linedtag markingmatches
- global mainfont canvxmax boldrows boldnamerows fgcolor nullid
+ global mainfont canvxmax boldrows boldnamerows fgcolor nullid nullid2
# listed is 0 for boundary, 1 for normal, 2 for left, 3 for right
set listed [lindex $commitlisted $row]
if {$id eq $nullid} {
set ofill red
+ } elseif {$id eq $nullid2} {
+ set ofill magenta
} else {
set ofill [expr {$listed != 0? "blue": "white"}]
}
@@ -4582,16 +4642,19 @@ proc goforw {} {
}
proc gettree {id} {
- global treefilelist treeidlist diffids diffmergeid treepending nullid
+ global treefilelist treeidlist diffids diffmergeid treepending
+ global nullid nullid2
set diffids $id
catch {unset diffmergeid}
if {![info exists treefilelist($id)]} {
if {![info exists treepending]} {
- if {$id ne $nullid} {
- set cmd [concat | git ls-tree -r $id]
+ if {$id eq $nullid} {
+ set cmd [list | git ls-files]
+ } elseif {$id eq $nullid2} {
+ set cmd [list | git ls-files --stage -t]
} else {
- set cmd [concat | git ls-files]
+ set cmd [list | git ls-tree -r $id]
}
if {[catch {set gtf [open $cmd r]}]} {
return
@@ -4608,12 +4671,14 @@ proc gettree {id} {
}
proc gettreeline {gtf id} {
- global treefilelist treeidlist treepending cmitmode diffids nullid
+ global treefilelist treeidlist treepending cmitmode diffids nullid nullid2
set nl 0
while {[incr nl] <= 1000 && [gets $gtf line] >= 0} {
- if {$diffids ne $nullid} {
- if {[lindex $line 1] ne "blob"} continue
+ if {$diffids eq $nullid} {
+ set fname $line
+ } else {
+ if {$diffids ne $nullid2 && [lindex $line 1] ne "blob"} continue
set i [string first "\t" $line]
if {$i < 0} continue
set sha1 [lindex $line 2]
@@ -4622,8 +4687,6 @@ proc gettreeline {gtf id} {
set fname [lindex $fname 0]
}
lappend treeidlist($id) $sha1
- } else {
- set fname $line
}
lappend treefilelist($id) $fname
}
@@ -4645,7 +4708,7 @@ proc gettreeline {gtf id} {
}
proc showfile {f} {
- global treefilelist treeidlist diffids nullid
+ global treefilelist treeidlist diffids nullid nullid2
global ctext commentend
set i [lsearch -exact $treefilelist($diffids) $f]
@@ -4653,15 +4716,15 @@ proc showfile {f} {
puts "oops, $f not in list for id $diffids"
return
}
- if {$diffids ne $nullid} {
- set blob [lindex $treeidlist($diffids) $i]
- if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
- puts "oops, error reading blob $blob: $err"
+ if {$diffids eq $nullid} {
+ if {[catch {set bf [open $f r]} err]} {
+ puts "oops, can't read $f: $err"
return
}
} else {
- if {[catch {set bf [open $f r]} err]} {
- puts "oops, can't read $f: $err"
+ set blob [lindex $treeidlist($diffids) $i]
+ if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
+ puts "oops, error reading blob $blob: $err"
return
}
}
@@ -4789,11 +4852,13 @@ proc getmergediffline {mdf id np} {
}
proc startdiff {ids} {
- global treediffs diffids treepending diffmergeid nullid
+ global treediffs diffids treepending diffmergeid nullid nullid2
set diffids $ids
catch {unset diffmergeid}
- if {![info exists treediffs($ids)] || [lsearch -exact $ids $nullid] >= 0} {
+ if {![info exists treediffs($ids)] ||
+ [lsearch -exact $ids $nullid] >= 0 ||
+ [lsearch -exact $ids $nullid2] >= 0} {
if {![info exists treepending]} {
gettreediffs $ids
}
@@ -4809,22 +4874,41 @@ proc addtocflist {ids} {
}
proc diffcmd {ids flags} {
- global nullid
+ global nullid nullid2
set i [lsearch -exact $ids $nullid]
+ set j [lsearch -exact $ids $nullid2]
if {$i >= 0} {
- set cmd [concat | git diff-index $flags]
+ if {[llength $ids] > 1 && $j < 0} {
+ # comparing working directory with some specific revision
+ set cmd [concat | git diff-index $flags]
+ if {$i == 0} {
+ lappend cmd -R [lindex $ids 1]
+ } else {
+ lappend cmd [lindex $ids 0]
+ }
+ } else {
+ # comparing working directory with index
+ set cmd [concat | git diff-files $flags]
+ if {$j == 1} {
+ lappend cmd -R
+ }
+ }
+ } elseif {$j >= 0} {
+ set cmd [concat | git diff-index --cached $flags]
if {[llength $ids] > 1} {
+ # comparing index with specific revision
if {$i == 0} {
lappend cmd -R [lindex $ids 1]
} else {
lappend cmd [lindex $ids 0]
}
} else {
+ # comparing index with HEAD
lappend cmd HEAD
}
} else {
- set cmd [concat | git diff-tree --no-commit-id -r $flags $ids]
+ set cmd [concat | git diff-tree -r $flags $ids]
}
return $cmd
}
@@ -4834,7 +4918,7 @@ proc gettreediffs {ids} {
set treepending $ids
set treediff {}
- if {[catch {set gdtf [open [diffcmd $ids {}] r]}]} return
+ if {[catch {set gdtf [open [diffcmd $ids {--no-commit-id}] r]}]} return
fconfigure $gdtf -blocking 0
filerun $gdtf [list gettreediffline $gdtf $ids]
}
@@ -4877,7 +4961,7 @@ proc getblobdiffs {ids} {
global diffinhdr treediffs
set env(GIT_DIFF_OPTS) $diffopts
- if {[catch {set bdf [open [diffcmd $ids {-p -C}] r]} err]} {
+ if {[catch {set bdf [open [diffcmd $ids {-p -C --no-commit-id}] r]} err]} {
puts "error getting diffs: $err"
return
}
@@ -5468,7 +5552,7 @@ proc mstime {} {
proc rowmenu {x y id} {
global rowctxmenu commitrow selectedline rowmenuid curview
- global nullid fakerowmenu mainhead
+ global nullid nullid2 fakerowmenu mainhead
set rowmenuid $id
if {![info exists selectedline]
@@ -5477,7 +5561,7 @@ proc rowmenu {x y id} {
} else {
set state normal
}
- if {$id ne $nullid} {
+ if {$id ne $nullid && $id ne $nullid2} {
set menu $rowctxmenu
$menu entryconfigure 7 -label "Reset $mainhead branch to here"
} else {
@@ -5596,18 +5680,12 @@ proc mkpatchrev {} {
}
proc mkpatchgo {} {
- global patchtop nullid
+ global patchtop nullid nullid2
set oldid [$patchtop.fromsha1 get]
set newid [$patchtop.tosha1 get]
set fname [$patchtop.fname get]
- if {$newid eq $nullid} {
- set cmd [list git diff-index -p $oldid]
- } elseif {$oldid eq $nullid} {
- set cmd [list git diff-index -p -R $newid]
- } else {
- set cmd [list git diff-tree -p $oldid $newid]
- }
+ set cmd [diffcmd [list $oldid $newid] -p]
lappend cmd >$fname &
if {[catch {eval exec $cmd} err]} {
error_popup "Error creating patch: $err"
@@ -7522,6 +7600,8 @@ if {$i >= [llength $argv] && $revtreeargs ne {}} {
}
set nullid "0000000000000000000000000000000000000000"
+set nullid2 "0000000000000000000000000000000000000001"
+
set runq {}
set history {}
@@ -7550,7 +7630,8 @@ set stopped 0
set stuffsaved 0
set patchnum 0
set lookingforhead 0
-set localrow -1
+set localirow -1
+set localfrow -1
set lserial 0
setcoords
makewindow
^ permalink raw reply related
* Re: git-svn: failure to clone logcheck's repo
From: Peter Baumann @ 2007-07-13 9:56 UTC (permalink / raw)
To: git discussion list
In-Reply-To: <20070713094710.GB18199@xp.machine.xx>
On Fri, Jul 13, 2007 at 11:47:10AM +0200, Peter Baumann wrote:
> On Fri, Jul 13, 2007 at 11:36:22AM +0200, martin f krafft wrote:
> > Hi list,
> >
> > I am trying to access the logcheck repository with git-svn. Even
> > though I can happily clone the trunk:
> >
> > git-svn clone svn://svn.debian.org/svn/logcheck/logcheck/trunk git
> >
> > as soon as I try to clone the entire thing with tags and branches:
> >
> > git-svn clone -T trunk -t tags -b branches
> > svn://svn.debian.org/svn/logcheck/logcheck git
> >
> > it barfs:
> >
> > Initialized empty Git repository in .git/
> > Using higher level of URL: svn://svn.debian.org/svn/logcheck/logcheck => svn://svn.debian.org/svn/logcheck
> > r19 = 95d0625b6c62935cfd3e44ec7dca5b6f6b05ab44 (trunk)
> > [...]
> > r20 = a3e5240dcc4d064b46273584800d3ae7a1e21330 (trunk)
> > Found possible branch point: svn://svn.debian.org/svn/logcheck/logcheck/trunk => svn://svn.debian.org/svn/logcheck/logcheck/branches/VENDOR, 20
> > Found branch parent: (VENDOR) a3e5240dcc4d064b46273584800d3ae7a1e21330
> > Following parent with do_switch
> > Successfully followed parent
> > r21 = 0ffcb70923d77c1d24019362e1ed1cd18d05f235 (VENDOR)
> > Malformed network data: Malformed network data at /usr/local/bin/git-svn line 1029
> >
> > I think I'll be fine with *not* preserving logcheck's history when
> > I move it to git, but thought best to let you know since this may be
> > a bug in git-svn.
> >
>
> This is a known problem. If I remember correctly,it is save to just
> resume the import with git-svn fetch, and nothing bad should happen.
>
> Just search the list archive for more info (sorry, I don't have a
> reference to the thread)
Just found it. Look e.g. here on the comment from Eric Wong:
http://thread.gmane.org/gmane.comp.version-control.git/50962/focus=275913
-Peter
^ permalink raw reply
* Re: git-svn: failure to clone logcheck's repo
From: Peter Baumann @ 2007-07-13 9:47 UTC (permalink / raw)
To: git discussion list
In-Reply-To: <20070713093622.GA21001@lapse.madduck.net>
On Fri, Jul 13, 2007 at 11:36:22AM +0200, martin f krafft wrote:
> Hi list,
>
> I am trying to access the logcheck repository with git-svn. Even
> though I can happily clone the trunk:
>
> git-svn clone svn://svn.debian.org/svn/logcheck/logcheck/trunk git
>
> as soon as I try to clone the entire thing with tags and branches:
>
> git-svn clone -T trunk -t tags -b branches
> svn://svn.debian.org/svn/logcheck/logcheck git
>
> it barfs:
>
> Initialized empty Git repository in .git/
> Using higher level of URL: svn://svn.debian.org/svn/logcheck/logcheck => svn://svn.debian.org/svn/logcheck
> r19 = 95d0625b6c62935cfd3e44ec7dca5b6f6b05ab44 (trunk)
> [...]
> r20 = a3e5240dcc4d064b46273584800d3ae7a1e21330 (trunk)
> Found possible branch point: svn://svn.debian.org/svn/logcheck/logcheck/trunk => svn://svn.debian.org/svn/logcheck/logcheck/branches/VENDOR, 20
> Found branch parent: (VENDOR) a3e5240dcc4d064b46273584800d3ae7a1e21330
> Following parent with do_switch
> Successfully followed parent
> r21 = 0ffcb70923d77c1d24019362e1ed1cd18d05f235 (VENDOR)
> Malformed network data: Malformed network data at /usr/local/bin/git-svn line 1029
>
> I think I'll be fine with *not* preserving logcheck's history when
> I move it to git, but thought best to let you know since this may be
> a bug in git-svn.
>
This is a known problem. If I remember correctly,it is save to just
resume the import with git-svn fetch, and nothing bad should happen.
Just search the list archive for more info (sorry, I don't have a
reference to the thread)
-Peter
^ permalink raw reply
* git-svn: failure to clone logcheck's repo
From: martin f krafft @ 2007-07-13 9:36 UTC (permalink / raw)
To: git discussion list
[-- Attachment #1: Type: text/plain, Size: 1525 bytes --]
Hi list,
I am trying to access the logcheck repository with git-svn. Even
though I can happily clone the trunk:
git-svn clone svn://svn.debian.org/svn/logcheck/logcheck/trunk git
as soon as I try to clone the entire thing with tags and branches:
git-svn clone -T trunk -t tags -b branches
svn://svn.debian.org/svn/logcheck/logcheck git
it barfs:
Initialized empty Git repository in .git/
Using higher level of URL: svn://svn.debian.org/svn/logcheck/logcheck => svn://svn.debian.org/svn/logcheck
r19 = 95d0625b6c62935cfd3e44ec7dca5b6f6b05ab44 (trunk)
[...]
r20 = a3e5240dcc4d064b46273584800d3ae7a1e21330 (trunk)
Found possible branch point: svn://svn.debian.org/svn/logcheck/logcheck/trunk => svn://svn.debian.org/svn/logcheck/logcheck/branches/VENDOR, 20
Found branch parent: (VENDOR) a3e5240dcc4d064b46273584800d3ae7a1e21330
Following parent with do_switch
Successfully followed parent
r21 = 0ffcb70923d77c1d24019362e1ed1cd18d05f235 (VENDOR)
Malformed network data: Malformed network data at /usr/local/bin/git-svn line 1029
I think I'll be fine with *not* preserving logcheck's history when
I move it to git, but thought best to let you know since this may be
a bug in git-svn.
Cheers,
--
martin; (greetings from the heart of the sun.)
\____ echo mailto: !#^."<*>"|tr "<*> mailto:" net@madduck
spamtraps: madduck.bogus@madduck.net
windoze is the one-night-stand of operating systems;
you feel so cheap after having used it.
[-- Attachment #2: Digital signature (GPG/PGP) --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* failing to send patches to the list
From: martin f krafft @ 2007-07-13 9:30 UTC (permalink / raw)
To: git discussion list
[-- Attachment #1.1: Type: text/plain, Size: 937 bytes --]
Dear list,
attached you may find two patches, which I've previously sent to the
list with
git format-patch -s --stdout | sendmail git@vger.kernel.org
Even though my mail server seems to have delivered them correctly:
Jul 13 10:53:32 albatross postfix/smtp[29758]: C404D895D6F:
to=<git@vger.kernel.org>,
relay=vger.kernel.org[209.132.176.167]:25, delay=2.2,
delays=0.08/0.04/0.56/1.6, dsn=2.7.1, status=sent (250 2.7.1 Looks
like Linux source DIFF email.. BF:<H 5.0943e-06>; S932911AbXGMIxb)
they never made it onto the list.
What am I doing wrong?
Should I resubmit the patches or is this enough for now?
--
martin; (greetings from the heart of the sun.)
\____ echo mailto: !#^."<*>"|tr "<*> mailto:" net@madduck
spamtraps: madduck.bogus@madduck.net
all software projects are done by iterative prototyping.
some companies call their prototypes "releases", that's all.
[-- Attachment #1.2: 0001-fall-back-to-mozilla-s-sha.h-if-openssl-sha.h-is-not.patch --]
[-- Type: text/x-diff, Size: 1009 bytes --]
From 7b2bb44f78b8bc691bbc1445c6c333fdc281a788 Mon Sep 17 00:00:00 2001
From: martin f. krafft <madduck@madduck.net>
Date: Fri, 13 Jul 2007 11:09:05 +0200
Subject: [PATCH] fall back to mozilla's sha.h if openssl/sha.h is not available
Uses $(CPP) to attempt to preprocess an include <openssl/sha.h> directive. If
that fails, NO_OPENSSL is defined, causing the Makefile to fall back to using
mozilla's SHA implementation.
Signed-off-by: martin f. krafft <madduck@madduck.net>
---
Makefile | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
index d7541b4..1676343 100644
--- a/Makefile
+++ b/Makefile
@@ -532,6 +532,12 @@ ifndef NO_CURL
endif
endif
+HAS_OPENSSL := $(shell echo "\#include <openssl/sha.h>" \
+ | $(CPP) -o/dev/null - 2>/dev/null || echo no)
+ifeq "$(HAS_OPENSSL)" "no"
+ NO_OPENSSL = "openssl_sha.h_not_found"
+endif
+
ifndef NO_OPENSSL
OPENSSL_LIBSSL = -lssl
ifdef OPENSSLDIR
--
1.5.3.rc1.7.gcae4
[-- Attachment #1.3: 0002-Provide-stdlayout-option-for-git-svn-to-set-trunk.patch --]
[-- Type: text/x-diff, Size: 2789 bytes --]
From 5f537c75774c5c0b45b74585ace4178738f251f0 Mon Sep 17 00:00:00 2001
From: martin f. krafft <madduck@madduck.net>
Date: Fri, 13 Jul 2007 11:09:46 +0200
Subject: [PATCH] Provide --stdlayout option for git-svn to set trunk,tags,branches to defaults
The --stdlayout option to git-svn init initialises the default Subversion
values of trunk,tags,branches: -T trunk -b branches -t tags. If any of the
-T/-t/-b options are given in addition, they are given preference.
Signed-off-by: martin f. krafft <madduck@madduck.net>
---
Documentation/git-svn.txt | 6 +++++-
git-svn.perl | 8 +++++++-
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 0a210e4..9e74b27 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -44,10 +44,14 @@ COMMANDS
--tags=<tags_subdir>;;
-b<branches_subdir>;;
--branches=<branches_subdir>;;
+--stdlayout;;
These are optional command-line options for init. Each of
these flags can point to a relative repository path
(--tags=project/tags') or a full url
- (--tags=https://foo.org/project/tags)
+ (--tags=https://foo.org/project/tags). The option --stdlayout is
+ a shorthand way of setting trunk,tags,branches as the relative paths,
+ which is the Subversion default. If any of the other options are given
+ as well, they take precedence.
--no-metadata;;
Set the 'noMetadata' option in the [svn-remote] config.
--use-svm-props;;
diff --git a/git-svn.perl b/git-svn.perl
index b3dffcc..5b443ee 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -77,11 +77,12 @@ my %fc_opts = ( 'follow-parent|follow!' => \$Git::SVN::_follow_parent,
\$Git::SVN::_repack_flags,
%remote_opts );
-my ($_trunk, $_tags, $_branches);
+my ($_trunk, $_tags, $_branches, $_stdlayout);
my %icv;
my %init_opts = ( 'template=s' => \$_template, 'shared:s' => \$_shared,
'trunk|T=s' => \$_trunk, 'tags|t=s' => \$_tags,
'branches|b=s' => \$_branches, 'prefix=s' => \$_prefix,
+ 'stdlayout' => \$_stdlayout,
'minimize-url|m' => \$Git::SVN::_minimize_url,
'no-metadata' => sub { $icv{noMetadata} = 1 },
'use-svm-props' => sub { $icv{useSvmProps} = 1 },
@@ -296,6 +297,11 @@ sub cmd_clone {
$url !~ m#^[a-z\+]+://#) {
$path = $url;
}
+ if (defined $_stdlayout) {
+ $_trunk = 'trunk' if (!defined $_trunk);
+ $_tags = 'tags' if (!defined $_tags);
+ $_branches = 'branches' if (!defined $_branches);
+ }
$path = basename($url) if !defined $path || !length $path;
cmd_init($url, $path);
Git::SVN::fetch_all($Git::SVN::default_repo_id);
--
1.5.3.rc1.7.gcae4
[-- Attachment #2: Digital signature (GPG/PGP) --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply related
* Re: Draft release notes for v1.5.3, as of -rc1
From: Sven Verdoolaege @ 2007-07-13 9:29 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vlkdkq00o.fsf_-_@assigned-by-dhcp.cox.net>
On Thu, Jul 12, 2007 at 11:40:39PM -0700, Junio C Hamano wrote:
> - "git-filter-branch" lets you rewrite the revision history of
> the current branch, creating a new branch. You can specify a
> number of filters to modify the commits, files and trees.
Are you sure you want to announce this so publicly given that
Dscho has basically declared git-filter-branch dead?
(I know, I'm mostly to blame.)
skimo
^ permalink raw reply
* Re: [PATCH] make git-send-email.perl handle email addresses with no names when Email::Valid is present
From: Stephen Rothwell @ 2007-07-13 8:28 UTC (permalink / raw)
To: Greg KH; +Cc: Junio C Hamano, git
In-Reply-To: <20070713063414.GN24317@kroah.com>
[-- Attachment #1: Type: text/plain, Size: 1138 bytes --]
On Thu, 12 Jul 2007 23:34:14 -0700 Greg KH <greg@kroah.com> wrote:
>
> On Thu, Jul 12, 2007 at 10:47:17PM -0700, Junio C Hamano wrote:
> > Greg KH <greg@kroah.com> writes:
> >
> > > When using git-send-email.perl on a changeset that has:
> > > Cc: <stable@kernel.org>
> > > in the body of the description, and the Email::Valid perl module is
> > > installed on the system, the email address will be deemed "invalid" for
> > > some reason (Email::Valid isn't smart enough to handle this?) and
> > > complain and not send the address the email.
> >
> > That appears to be the case.
> >
> > bad foo
> > bad <foo@bar.baz>
> > ok foo@bar.baz
> > ok Foo <foo@bar.baz>
This would be a bug in Email::Valid as it complains that the second
address fails the rfc822 check, however rfc822 says that the "display
name" before the '<' is optional.
> > I'd probably do:
> >
> > if ($have_email_valid) {
> > $address =~ s/^<(.*)>$/$1/;
$address =~ s/^\s*<(.*)>\s*$/$1/;
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: git-update-server-info may be required,cannot clone and pull from a remote repository
From: pradeep singh @ 2007-07-13 8:27 UTC (permalink / raw)
To: Jakub Narebski; +Cc: Eric Wong, git
In-Reply-To: <200707130217.37817.jnareb@gmail.com>
Thank you all for your valuable suggestions and timely help.
I am now able to view the git repo in a web browser.
Thank you once again for help and for a great tool like git.
--pradeep
On 7/13/07, Jakub Narebski <jnareb@gmail.com> wrote:
> Pradeep Singh wrote:
> > On 7/12/07, Jakub Narebski <jnareb@gmail.com> wrote:
> >> [Cc: git@vger.kernel.org, Pradeep Singh <pradeep.rautela@gmail.com>,
> >> Eric Wong <normalperson@yhbt.net> (instaweb creator)]
> >>
> >> pradeep singh wrote:
> >>
> >>> Anyway i could not get gitweb running after running git-instaweb.
> >>>
> >>> Any thoughts on how to setup a gitweb interface ?
> >>
> >> What information does gitweb/INSTALL lack?
> >
> > May be I am running some old version on my Ubuntu Edgy machine
> > perhaps? I cannot find such a file anywhere?
>
> You can always look up this file at git.git gitweb (either kernel.org
> one, or repo.or.cz one), e.g.
>
> http://repo.or.cz/w/alt-git.git/:gitweb/INSTALL
>
> > Looks like it is available in newer versions.
> > Does it works for git-1.4.4?
>
> The installation instructions may have changed a bit since then. It is
> much easier to use 1.5.x series, nevertheless.
>
> --
> Jakub Narebski
> Poland
>
--
Pradeep
^ permalink raw reply
* Re: [PATCH 6/6] Add git-rewrite-commits
From: Sven Verdoolaege @ 2007-07-13 8:01 UTC (permalink / raw)
To: git, Junio C Hamano; +Cc: Johannes Schindelin
In-Reply-To: <11842671631635-git-send-email-skimo@liacs.nl>
On Thu, Jul 12, 2007 at 09:06:03PM +0200, skimo@liacs.nl wrote:
> +static int rewrite_parents(struct commit *commit, int path_pruning)
> +{
> + int n;
> + struct commit_list *list, *parents, **prev;
> + unsigned char sha1[20];
> +
> + for (n = 0, prev = &commit->parents; *prev; ++n) {
> + list = *prev;
> +
> + rewrite_parents(list->item, path_pruning);
> + if (!is_pruned(list->item, path_pruning)) {
> + prev = &list->next;
> + continue;
> + }
Oops... that should be the other way around...
diff --git a/builtin-rewrite-commits.c b/builtin-rewrite-commits.c
index d95a16c..4cd17ae 100644
--- a/builtin-rewrite-commits.c
+++ b/builtin-rewrite-commits.c
@@ -279,11 +279,11 @@ static int rewrite_parents(struct commit *commit, int path_pruning)
for (n = 0, prev = &commit->parents; *prev; ++n) {
list = *prev;
- rewrite_parents(list->item, path_pruning);
if (!is_pruned(list->item, path_pruning)) {
prev = &list->next;
continue;
}
+ rewrite_parents(list->item, path_pruning);
hashcpy(sha1, list->item->object.sha1);
get_rewritten_sha1(sha1);
I'll include it in my next version.
skimo
^ permalink raw reply related
* Re: pull-fetch-param.txt
From: Gerrit Pape @ 2007-07-13 7:48 UTC (permalink / raw)
To: Junio C Hamano, git
In-Reply-To: <7vejjcpyb5.fsf@assigned-by-dhcp.cox.net>
On Fri, Jul 13, 2007 at 12:17:34AM -0700, Junio C Hamano wrote:
> Gerrit Pape <pape@smarden.org> writes:
> >> Quick question. Is the build done with "make
> >> ASCIIDOC8=YesPlease"?
> >
> > No, must have missed that. This solves the first issue ...
> > ..., but not the second one with callout lists.
>
> Sorry, does not reproduce for me, with asciidoc 8.2.1. There
> must be something different between our environments.
Yes, I have docbook-xsl 1.72.0.
> Here is an excerpt from what I get for git-reset.txt in
> git-reset.1:
>
> -- >8 --
> .\" Title: git\-reset
> .\" Author:
> .\" Generator: DocBook XSL Stylesheets v1.71.0 <http://docbook.sf.net/>
> .\" Date: 07/13/2007
> .\" Manual: Git Manual
> .\" Source: Git 1.5.3.rc1.4.gaf83
>
> ...
>
> .SH "EXAMPLES"
> .PP
> Undo a commit and redo
> .RS 3n
> .sp
> .RS 3n
> .nf
> $ git commit ...
> $ git reset \-\-soft HEAD^ \fB(1)\fR
> $ edit \fB(2)\fR
> $ git commit \-a \-c ORIG_HEAD \fB(3)\fR
I get the same with docbook-xsl 1.71.0, but with 1.72.0:
.\" Title: git-reset
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.72.0 <http://docbook.sf.net/>
.\" Date: 07/13/2007
.\" Manual: Git Manual
.\" Source: Git 1.5.3.rc0.104.g71f98
[...]
.SH "EXAMPLES"
.PP
Undo a commit and redo
.RS 4
.sp
.RS 4
.nf
$ git commit ...
$ git reset \-\-soft HEAD^ \efB(1)\efR
$ edit \efB(2)\efR
$ git commit \-a \-c ORIG_HEAD \efB(3)\efR
.fi
.RE
\&.sp
\efB1. \efRThis is most often done when you remembered what you just committed is incomplete, or you misspelled your commit message, or both. Leaves working tree as it was before "reset".
\&.br
\efB2. \efRmake corrections to working tree files.
\&.br
\efB3. \efR"reset" copies the old head to .git/ORIG_HEAD; redo the commit by starting with its log message. If you do not need to edit the message further, you can give \-C option instead.
I'll check with the docbook-xsl Debian maintainer.
Thanks, Gerrit.
^ permalink raw reply
* Re: pull-fetch-param.txt
From: Junio C Hamano @ 2007-07-13 7:17 UTC (permalink / raw)
To: Gerrit Pape; +Cc: git
In-Reply-To: <20070713055346.634.qmail@1e54e4f4e1041d.315fe32.mid.smarden.org>
Gerrit Pape <pape@smarden.org> writes:
>> Quick question. Is the build done with "make
>> ASCIIDOC8=YesPlease"?
>
> No, must have missed that. This solves the first issue ...
> ..., but not the second one with callout lists.
Sorry, does not reproduce for me, with asciidoc 8.2.1. There
must be something different between our environments.
Here is an excerpt from what I get for git-reset.txt in
git-reset.1:
-- >8 --
.\" Title: git\-reset
.\" Author:
.\" Generator: DocBook XSL Stylesheets v1.71.0 <http://docbook.sf.net/>
.\" Date: 07/13/2007
.\" Manual: Git Manual
.\" Source: Git 1.5.3.rc1.4.gaf83
...
.SH "EXAMPLES"
.PP
Undo a commit and redo
.RS 3n
.sp
.RS 3n
.nf
$ git commit ...
$ git reset \-\-soft HEAD^ \fB(1)\fR
$ edit \fB(2)\fR
$ git commit \-a \-c ORIG_HEAD \fB(3)\fR
.fi
.RE
.sp
\fB1. \fRThis is most often done when you remembered what you just committed is incomplete, or you misspelled your commit message, or both. Leaves working tree as it was before "reset".
.br
\fB2. \fRmake corrections to working tree files.
.br
\fB3. \fR"reset" copies the old head to .git/ORIG_HEAD; redo the commit by starting with its log message. If you do not need to edit the message further, you can give \-C option instead.
See also the \-\-amend option to \fBgit\-commit\fR(1).
.br
.RE
-- 8< --
and "man -l git-reset.1" seems to show the callouts just fine.
-- >8 --
...
EXAMPLES
Undo a commit and redo
$ git commit ...
$ git reset --soft HEAD^ (1)
$ edit (2)
$ git commit -a -c ORIG_HEAD (3)
1. This is most often done when you remembered what you just
committed is incomplete, or you misspelled your commit message,
or both. Leaves working tree as it was before "reset".
2. make corrections to working tree files.
3. "reset" copies the old head to .git/ORIG_HEAD; redo the
commit by starting with its log message. If you do not need to
edit the message further, you can give -C option instead.
See also the --amend option to git-commit(1).
-- 8< --
^ permalink raw reply
* Re: Perforce support.
From: Alex Riesen @ 2007-07-13 6:45 UTC (permalink / raw)
To: Govind Salinas; +Cc: git
In-Reply-To: <69b0c0350707121134t61905e87xaa2fc78c30891bb0@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 2699 bytes --]
On 7/12/07, Govind Salinas <govindsalinas@gmail.com> wrote:
> I am hoping to convince my co-workers to start using a Distributed
> SCM, hopefully git, and I wanted to see what people had to say about
> the Perforce-git interoperability. To make it more fun we are doing
> this on Windows.
There are two scripts. git-p4import.py, is in standard distribution,
and is AFAIK not used very much Windows. The other, git-p4-import.bat
is never tried on anywhere but Windows and is maintained outside
of mainstream Git.
I maintain the second one, git-p4-import.bat. I don't dare to submit
it for distribution with Git: it is very centered on stu^H^H^H^H suboptimal
practices I have at work.
> I have been playing around with git for a month or so and have started
> writing, what I hope will be, a nice GUI over git that works well on
> Windows (Cygwin) and offers some feeling of familiarity to our
> Perforce users. That however is only half the problem.
I trust you already seen git gui...
> We need to be able to go back and forth to our main Perforce depot,
> and while I understand that git-svn support is very good, I have only
> seen limited support of Perforce.
Because Perforce is, in some respects, even worse: it is closed.
It will never get the level of support SVN or even CVS have.
> I was wondering if anyone has been
> using git with p4 and how well did it work. We have very complex and
> somewhat large "clients" that do a lot of mapping of directories
> (which strikes me as particularly insane) and I was wondering if any
> of the tools support that.
I am in such situation. Perforce is so bad in managing it,
that people here had to write a handful of wrappers around
standard commands just to make it limping (and it is falling
apart right now).
I use the git-p4-import.bat to import and export the commits.
It is PITA though. Try it (attached), but don't expect too much.
It is a perl script, geared towards Windows and Activision Perl
(hopefully not too much and it still can work with cygwin's perl).
Some examples (I assume a useful shell, not cmd):
Import a range of P4 changelists, convert p4 path to local path
$ git-p4-import.bat --p4-path //Very/stupid/perforce \
--local-path "" --p4-range '@123,456'
Result can be found in the reference named p4/IMPORT.
Export some commits:
$ git-p4-import.bat --merge my-branch -y --edit=vim
This prepare a change lists, let you edit the changelist description
in vim and submit it. I suggest you always rebase my-branch
before this: p4 linearizes the history, so in case you loose your
original git branch, the _useful_ parenthood information is lost with it.
Better not even have any hopes associated with this.
[-- Attachment #2: git-p4-import.bat.txt --]
[-- Type: text/plain, Size: 50773 bytes --]
@rem = 'NT: CMD.EXE vim: syntax=perl noet sw=4
@perl -x -s %0 -- %*
@goto __end_of_file__
@rem ';
#!perl -w
#line 7
local $VERBOSE = 0;
local $DRYRUN = 0;
local $SHOW_DIFFS = 0;
local $AUTO_COMMIT = 0;
local $JUST_COMMIT = 0;
local $GIT_DIR = undef;
local $P4CLIENT = undef;
local $EDIT_COMMIT = 0;
local $FORCE = 0;
local @FULL_IMPORT = 0;
local @DESC = ();
local $SPEC = undef;
local $P4HAVE_FILE = undef;
local %P4USERS = ();
local $FULL_DESC = 1;
local $HEAD_FROM_P4 = 0;
local $P4_EDIT_MERGE = 0;
local $P4_EDIT_CHANGED = 0;
local $P4_EDIT_HEAD = undef;
local $editor = undef;
local $P4_PATH = undef;
local $P4_RANGE = undef;
local $P4_LOCAL_PATH = undef;
local $START_POINT = undef;
local $UPDATE_BRANCH = undef;
local $P4_TAG = undef;
local $P4_SYNC_TO = undef;
# cache for refs/p4import references
local %P4IMPORT_HEADS = ();
sub read_args {
my $no_opt = 0;
my $no_EDIT_COMMIT = 0;
while (my $f = shift) {
goto _files if $no_opt;
$no_opt=1, next if $f eq '--';
$DRYRUN=1, next if $f eq '-n' or $f eq '--dry-run';
$SHOW_DIFFS=$DRYRUN=1, next if $f eq '--diffs';
$AUTO_COMMIT=1, next if $f eq '-y' or $f eq '--yes';
$JUST_COMMIT=1, next if $f =~ /^--(just-)?commit$/;
$EDIT_COMMIT=1, next if $f eq '-e' or $f eq '--edit';
$no_EDIT_COMMIT=1, next if $f eq '-ne' or $f eq '--no-edit';
$FORCE=1, next if $f eq '--force';
if ($f =~ /^-(e|-edit=)(.*)/) {
$editor = $2;
$EDIT_COMMIT=1;
next;
}
$FULL_IMPORT=1, next if $f eq '--full';
$FULL_DESC++, next if $f eq '--p4-desc';
$VERBOSE++, next if $f eq '-v' or $f eq '--verbose';
$P4CLIENT = shift, next if $f eq '--client' and @_;
$P4CLIENT = $1, next if $f =~ /^--client=(.*)/;
push(@DESC,'c'.shift), next if $f eq '-C' and @_;
push(@DESC,"c$1"), next if $f =~ /^--changelist=(.*)/;
push(@DESC,'f'.shift), next if $f eq '-F' and @_;
push(@DESC,"f$1"), next if $f =~ /^--file=(.*)/;
push(@DESC,'4'.shift), next if ($f eq '--ptr' or $f eq '--p4') and @_;
push(@DESC,"4$2"), next if $f =~ /^--(p4|ptr)=(.*)/;
$P4_EDIT_CHANGED=1, next if $f eq '--p4-edit-changed';
if ($f =~ /^--p4-edit-changed=(.*)/) {
$P4_EDIT_CHANGED=1;
$P4_EDIT_HEAD=$1;
next
}
if ($f =~ /^--merge=(.*)/ or
($f eq '--merge' and @_)) {
$P4_EDIT_MERGE=1;
$P4_EDIT_CHANGED=1;
$EDIT_COMMIT=1;
$P4_EDIT_HEAD= $f eq '--merge' ? shift: $1;
next
}
$P4_TAG=$1, next if $f =~ /^--p4-tag=(.+)/;
$P4_TAG=shift, next if $f eq '--p4-tag' and @_;
# $P4_EDIT_MERGE = 'submit' if $f eq '--submit';
$P4_PATH=$1, next if $f =~ /^--p4-path=(.*)/;
$P4_PATH=shift, next if $f eq '--p4-path' and @_;
$P4_RANGE=$1, next if $f =~ /^--p4-range=(.*)/;
$P4_RANGE=shift, next if $f eq '--p4-range' and @_;
$P4_LOCAL_PATH=$1, next if $f =~ /^--local-path=(.*)/;
$P4_LOCAL_PATH=shift, next if $f eq '--local-path' and @_;
$START_POINT=$1, next if $f =~ /^--start=(.*)/;
$START_POINT=shift, next if $f eq '--start' and @_;
$UPDATE_BRANCH=$1, next if $f =~ /^--branch=(.*)/;
$UPDATE_BRANCH=shift, next if $f eq '--branch' and @_;
$P4_SYNC_TO=$1, next if $f =~ /--sync=(.*)/;
$P4_SYNC_TO=shift, next if $f eq '--sync' and @_;
if ($f eq '--help' or $f eq '-h') {
print <<EOF;
$0 [-n|--dry-run] [-y|--yes] [--client <client-name>] [--diffs] \
[-e|--edit] [--just-commit] [--full] [-v|--verbose] [-C <change-number>] \
[-F <filename>] [--ptr|--p4 <p4-path-and/or-revision>] [--p4-desc] \
[--] [<specification>]
Perforce client state importer. Creates a git commit on the current
branch from a state the given p4 client and working directory hold.
<specification> must be given and is expected to be a file which will be
stored on the side branch under the name "spec".
Remote-to-local mapping and the revisions of files are stored in "have",
and the client definition - in "client".
--client client Specify client name (saved in .git/p4/client for the next time)
--full Perform full import, don't even try to figure out what changed
-y|--yes Commit automatically (by default only index updated)
--just-commit To be used after you forgot to run with --yes first time
-n|--dry-run Do not update the index and do not commit
-e|--edit Edit commit description before committing
-v|--verbose Be more verbose. Can be given many times, increases verbosity
--file=file
-F file Take description for the commit from a file in the
next parameter
--changelist=change
-C change Take description for the commit from this p4 change
--p4|--ptr=p4-path-and/or-revision
Take description for the commit from the p4 change described
by this p4 path, possibly including revision specification
--p4-path=p4-path
Import changes directly from Perforce concerning the given
p4-path. The first change list defines the starting state
of imported path
--p4-range=revrange
Restrict the changes to the revrange change lists.
The first change list is always imported fully,
all the subsequent - incrementally. If not given -
all changes on the patch will be imported
--local-path=local-path
Replace the p4-path given to --p4-path with local-path
in the imported pathnames
--start=git-ref
Start commiting at the given reference. If not given,
the value of reference given to --branch is used,
otherwise the current HEAD is assumed
--branch=git-branch
After everything is imported and committed, update the
reference git-branch with sha1 of the last commit.
If not given - the last commit of the import is stored
in the reference /p4/IMPORT
--p4-desc Increase amount of junk from p4 change description
--diffs Show files which are different between local filesystem, index,
and the current HEAD. Does not do anything else
--merge=branch
Merge with the given sha1 and prepare a p4 submission.
Current HEAD will be git-merged with branch.
The working directory must have no local changes
--p4-edit-changed
--p4-edit-changed=branch
Read the given branch in the index and prepare a p4 submission.
Current HEAD must fast-forward to sha1. If branch is omited,
the current HEAD is assumed (useful after push on HEAD).
The working directory must have no local changes
--sync=ref
Sync the current client to the state given by ref:head
file. The file must have been stored by previous import.
The option considers all references under p4import when
looking for the "have"-file
The descriptions taken from p4 changes given by -C and --p4 will
be concatenated if the options given multiple times.
"--" can be used to separate options from description files.
EOF
exit(0);
}
die "$0: unknown option $f\n" if $f =~ /^-/;
_files:
warn "$0: spec was already set, $SPEC ignored\n" if defined($SPEC);
$SPEC = $f;
}
$EDIT_COMMIT = 0 if $no_EDIT_COMMIT;
}
read_args(@ARGV);
$editor = $ENV{VISUAL} unless defined($editor);
$editor = $ENV{EDITOR} unless defined($editor);
$editor = 'vim' unless defined($editor);
die "$0: no editor defined\n" if $EDIT_COMMIT and !defined($editor);
if (!defined($GIT_DIR)) {
$GIT_DIR = git_rev_parse('--git-dir');
die "$0: GIT_DIR not found\n" if !defined($GIT_DIR) or !-d $GIT_DIR;
}
exit(git_show_diffs() ? 1: 0) if $SHOW_DIFFS;
# the most commands below need GIT_DIR/p4, try to create it
mkdir "$GIT_DIR/p4", 0775;
if (defined($P4_PATH)) {
$START_POINT = $UPDATE_BRANCH
if !defined($START_POINT) and defined($UPDATE_BRANCH);
my $parent = undef;
$parent = git_rev_parse($START_POINT) if defined($START_POINT);
$parent = '' if !defined($parent);
$P4_RANGE = '#head' if !defined($P4_RANGE); # import all changes
$P4_LOCAL_PATH = $P4_PATH if !defined($P4_LOCAL_PATH);
$P4_LOCAL_PATH =~ s!^/+!!o;
s!/+\.\.\.$!!o for ($P4_PATH,$P4_LOCAL_PATH);
s!/+$!!o for ($P4_PATH,$P4_LOCAL_PATH);
print "Path conversion:\n'$P4_PATH' ->\n'$P4_LOCAL_PATH'\n" if $VERBOSE > 1;
import_p4_dir($P4_PATH,$P4_LOCAL_PATH,$P4_RANGE,$parent,$UPDATE_BRANCH);
exit 0;
}
if (defined($P4_TAG)) {
my $rc = git_p4_tag_HEAD($P4_TAG);
exit 127 if $rc & 0xff;
exit 1 if $rc;
exit 0;
}
# P4 client was given in command-line. Store it
if ( defined($P4CLIENT) ) {
mkdir "$GIT_DIR/p4", 0777;
if ( open(F, '>', "$GIT_DIR/p4/client") ) {
print F "$P4CLIENT\n";
close(F);
} else {
die "$0: cannot store client name: $!\n"
}
} else {
if ( open(F, '<', "$GIT_DIR/p4/client") ) {
($P4CLIENT) = <F>;
close(F);
$P4CLIENT =~ s/^\s*//,$P4CLIENT =~ s/\s*$// if defined($P4CLIENT);
}
}
die "P4 client not defined\n" if !defined($P4CLIENT) or !length($P4CLIENT);
print "reading client $P4CLIENT\n" if $VERBOSE;
local ($P4ROOT, $p4clnt, $P4HOST);
open(my $fdo, '>', "$GIT_DIR/p4/client.def") or die "p4/client.def: $!\n";
binmode($fdo);
open(my $fdi, '-|', "p4 client -o $P4CLIENT") or die "p4 client: $!\n";
binmode($fdi);
my $last_line_len = 0;
while (<$fdi>) {
next if /^#/o;
if ( m/^\s*Root:\s*(\S+)[\\\/]*\s*$/so ) { $P4ROOT = $1 }
elsif ( m/^\s*Client:\s*(\S+)/o ) { $p4clnt = $1 }
elsif ( m/^\s*Host:\s*(\S+)/o ) { $P4HOST = $1 }
($VERBOSE and print), next if /^(Access|Update):/;
s/\r?\n$//so;
my $len = length($_);
print $fdo "$_\n" if $len or $len != $last_line_len;
$last_line_len = $len;
}
close($fdi);
close($fdo);
die "Client root not defined\n" unless defined($P4ROOT);
if ( $VERBOSE ) {
use Cwd;
print "GIT_DIR: $GIT_DIR\n";
print "Root: $P4ROOT (cwd: ".cwd()."\n";
print "Host: $P4HOST\n";
print "Client: $p4clnt\n" if $p4clnt ne $P4CLIENT;
}
die if defined $P4_SYNC_TO;
#exit(git_sync_to($P4_SYNC_TO)) if defined $P4_SYNC_TO;
if ($P4_EDIT_CHANGED) {
exit(git_p4_merge($P4_EDIT_HEAD, $P4_EDIT_MERGE, $AUTO_COMMIT));
}
my ($git_head,$git_p4_head,$git_p4_have) = git_p4_init();
if ($JUST_COMMIT) {
git_p4_commit($git_head, $git_p4_head);
exit 0;
}
local %gitignore_dirs = ();
$gitignore_dirs{'/'} = read_filter_file("$GIT_DIR/info/exclude");
push(@{$gitignore_dirs{'/'}}, @{read_filter_file('.gitignore')});
my %git_index = ();
$/ = "\0";
my @git_X = ();
print "Reading git file list(git ls-files @git_X --cached -z)...\n" if $VERBOSE;
foreach ( qx{git ls-files @git_X --cached -z} ) {
chop; # chop \0
next if m/^\.gitignore$/o;
next if m/\/\.gitignore$/o;
next if filtered($_);
$git_index{$_} = 1;
}
my @git_add = ();
my @git_addx = ();
my @git_del = ();
my @git_upd = ();
print "Reading P4 file list...\n" if $VERBOSE;
local ($Conflicts,$Ignored,$Added,$Deleted,$Updated) = (0,0,0,0,0);
$/ = "\n";
my $in_name = 0;
my @root = split(/[\/\\]+/, $P4ROOT);
my %p4_index = ();
my %p4_a_lc = ();
my %lnames = ();
my %lconflicts = ();
if (opendir(DIR, '.')) {
$lnames{'.'} = [grep {$_ ne '.' and $_ ne '..'} readdir(DIR)];
closedir(DIR);
}
open(my $have, "p4 -G -c $P4CLIENT -H $P4HOST -d $P4ROOT have |") or
die "$0: failed to start p4: $!\n";
binmode($have);
$P4HAVE_FILE = "$GIT_DIR/p4/have";
open(my $storedhave, '>', $P4HAVE_FILE) or die "$P4HAVE_FILE: $!\n";
binmode($storedhave);
my ($cnt,$err,$ent) = (0,0,undef);
while (defined($ent=read_pydict_entry($have))) {
if (defined($ent->{code}) and defined($ent->{data})) {
++$err if $ent->{code} eq 'error';
print STDERR 'p4: '.$ent->{code}.': '.$ent->{data}."\n";
next;
}
next if !defined($ent->{depotFile}) or !defined($ent->{clientFile});
++$cnt;
my $a = $ent->{depotFile};
$ent->{clientFile} =~ m!^//[^/]+/(.*)!o;
my $b = $1;
my @bb = split(/\/+/, $b);
print $storedhave "$a\0$ent->{clientFile}\0$ent->{haveRev}\0\n";
if ( $^O eq 'MSWin32' ) {
# stupid windows, daft activestate, dumb P4
# This piece below is checking for file name conflicts
# which happen on windows because of it mangling the names.
my $blc = lc $b;
if ( $#bb > 0 ) {
my $path = '.';
foreach my $n (@bb[0 .. $#bb -1]) {
my @conflicts =
grep {lc $_ eq lc $n and $_ ne $n} @{$lnames{$path}};
if (@conflicts and !exists($lconflicts{"$path/$n"})) {
warn "warning: $a -> $b\n".
"warning: conflict between path \"$path/$n\" and ".
"local filesystem in \"@conflicts\"\n";
$Conflicts++;
$lconflicts{"$path/$n"} = 1;
}
$path .= "/$n";
if (!exists($lnames{$path})) {
if (opendir(DIR, $path)) {
$lnames{$path} =
[grep {$_ ne '.' and $_ ne '..'} readdir(DIR)];
closedir(DIR);
#print "read $path (",scalar(@{$lnames{$path}}),")\n";
}
}
}
}
if (!exists($p4_a_lc{$blc})) {
$p4_a_lc{$blc} = [$a, $b];
} else {
warn("warning: $a -> $b\n".
"warning: conflicts with ".
$p4_a_lc{$blc}->[0]." -> ".
$p4_a_lc{$blc}->[1]."\n");
$Conflicts++;
next;
}
}
my $i;
for ($i = 0; $i < $#bb; ++$i) {
my $bdir = join('/',@bb[0 .. $i]) . '/';
if ( !exists($gitignore_dirs{$bdir}) ) {
$gitignore_dirs{$bdir} = read_filter_file("$bdir.gitignore");
}
}
if (filtered($b)) {
print " i $b\n" if $VERBOSE > 3;
$Ignored++;
next
}
$p4_index{$b} = $a;
if ( exists($git_index{$b}) ) {
my $needup = 1;
if (defined($git_p4_have)) {
$prev = $git_p4_have->{$a};
if (defined($prev)) {
$prev->[0] =~ m!^//[^/]+/(.*)!o;
$needup = 0 if ($b eq $1) and ($prev->[1] eq $ent->{haveRev});
if ($needup and $VERBOSE > 1) {
my $reason;
$reason = 'local file' if $b ne $1;
$reason = 'revision' if $prev->[1] ne $ent->{haveRev};
print "$a ($reason changed)\n";
}
}
}
if ($needup) {
$Updated++;
push(@git_upd, $b);
}
} else {
$Added++;
if ( $b =~ m/\.(bat|cmd|pl|sh|exe|dll)$/io )
{ push(@git_addx, $b) } else { push(@git_add, $b) }
}
}
close($storedhave);
close($have);
exit 1 if $err; # the error already reported
die "Nothing in the client $P4CLIENT\n" if !$cnt;
undef %p4_a_lc;
@git_del = grep { !exists($p4_index{$_}) } keys %git_index;
$Deleted = $#git_del + 1;
#foreach (keys %git_index)
#{ push(@git_del, $_) if !exists($p4_index{$_}) }
if ( $DRYRUN ) {
print($#git_add+$#git_addx+ 2," files to add\n") if $VERBOSE;
print map {" a $_\n"} @git_add if $VERBOSE > 2;
print map {" a $_\n"} @git_addx if $VERBOSE > 2;
print($#git_del+1," files to unreg\n") if $VERBOSE;
print map {" d $_\n"} @git_del if $VERBOSE > 2;
print($#git_upd+1," files to update\n") if $VERBOSE;
print map {" u $_\n"} @git_upd if $VERBOSE > 2;
print "added: $Added, unregd: $Deleted, updated: $Updated, ignored: $Ignored";
print ", conflicts: $Conflicts" if $Conflicts;
print "\n";
} else {
if (@git_add || @git_addx) {
print($#git_add+$#git_addx+ 2,
" files | git update-index --add -z --stdin\n")
if $VERBOSE;
if (@git_add) {
open(GIT, '| git update-index --add --chmod=-x -z --stdin') or
die "$0 git-update-index(add): $!\n";
print GIT map {print " a $_\n" if $VERBOSE > 1; "$_\0"} @git_add;
close(GIT);
}
if (@git_addx) {
open(GIT, '| git update-index --add --chmod=+x -z --stdin') or
die "$0 git-update-index(add): $!\n";
print GIT map {print " a $_\n" if $VERBOSE > 1; "$_\0"} @git_addx;
close(GIT);
}
}
if (@git_del) {
print($#git_del+1," files | git update-index --remove -z --stdin\n")
if $VERBOSE;
open(GIT, '| git update-index --force-remove -z --stdin') or
die "$0 git-update-index(del): $!\n";
print GIT map {print " d $_\n" if $VERBOSE > 1; "$_\0"} @git_del;
close(GIT);
}
if (@git_upd) {
print($#git_upd+1," files | git update-index -z --stdin\n")
if $VERBOSE;
open(GIT, '| git update-index -z --stdin') or
die "$0 git-update-index(upd): $!\n";
print GIT map {print " u $_\n" if $VERBOSE > 1; "$_\0"} @git_upd;
close(GIT);
}
print "added: $Added, unregd: $Deleted, updated: $Updated, ignored: $Ignored";
print ", conflicts: $Conflicts" if $Conflicts;
print "\n";
git_p4_commit($git_head, $git_p4_head) if $AUTO_COMMIT;
}
exit 0;
sub run_or_exit {
my $rc = system(@_);
exit(127) if $rc & 0xff;
exit(1) if $rc;
return 0;
}
sub filtered {
my $name = shift;
study($name);
my @path = split(/\/+/o, $name);
my $dir = '';
$name = '';
foreach my $d (@path) {
$name .= $d;
# print STDERR "$dir: $name $d\n" if $v;
foreach my $re (@{$gitignore_dirs{'/'}}) {
return 1 if $name =~ m/$re/;
return 1 if $d =~ m/$re/;
}
if ( length($dir) and exists($gitignore_dirs{$dir}) ) {
foreach my $re (@{$gitignore_dirs{$dir}}) {
return 1 if $name =~ m/$re/;
return 1 if $d =~ m/$re/;
}
}
$name .= '/';
$dir = $name;
}
# print STDERR "$name not filtered\n" if $v;
return 0;
}
sub read_filter_file {
my @filts = ();
my $file = shift;
if ( open(my $if, '<', $file) ) {
print "added ignore file $file\n" if $VERBOSE;
$/ = "\n";
while (my $l = <$if>) {
next if $l =~ /^\s*#/o;
next if $l =~ /^\s*$/o;
$l =~ s/[\r\n]+$//so;
$l =~ s/\./\\./go;
$l =~ s/\*/.*/go;
if ( $l =~ m/\// ) {
$l = "^$l($|/)";
} else {
$l = "(^|/)$l\$";
}
print " filter $l\n" if $VERBOSE > 1;
push(@filts, qr/$l/);
}
close($if);
}
return \@filts;
}
sub r_pystr
{
my $fd = shift;
my ($len,$str)=('','');
my ($c,$rd,$b) = (4,0,'');
while ($c > 0) {
$rd = sysread($fd,$b,$c);
warn("failed to read len: $!"), return undef if !defined($rd);
warn("not enough data for len"), return undef if !$rd;
$len .= $b;
$c -= $rd;
}
$len = unpack('V',$len);
while ($len > 0) {
$rd = sysread($fd,$b,$len);
warn("failed to read data: $!"), return undef if !defined($rd);
warn("not enough data"), return undef if !$rd;
$str .= $b;
$len -= $rd;
}
return $str;
}
sub read_pydict_entry
{
my $f = shift;
my ($buf,$rd);
FIL: while (1) {
# object type identifier
$rd = sysread($f, $buf, 1);
last FIL if $rd == 0;
warn("p4: object type: $!\n"),last if $rd != 1;
# '{' is a python marshalled dict
warn("p4: object type: not {\n"),last if $buf ne '{';
my $ent = {};
PAIR: while (1) {
my ($b,$key);
# key type identifier
$rd = sysread($f, $b, 1);
warn("p4: key type: $!\n"),last FIL if $rd != 1;
if ($b eq 's') { # length-prefixed string
$key = r_pystr($f);
warn("p4: key: $!\n"),last FIL if !defined($b);
} elsif ($b eq '0') { # NULL-element, end of entry
last PAIR;
} else {
die("p4: key type: not s (string)\n");
last FIL;
}
# value type identifier
$rd = sysread($f, $b, 1);
warn("p4: $key value type: $!\n"),last FIL if $rd != 1;
if ($b eq 's') { # length-prefixed string
$b = r_pystr($f);
warn("p4: $key value: $!\n"),last FIL if !defined($b);
$ent->{$key} = $b;
} elsif ($b eq 'i') { # 4-byte integer
$rd = sysread($f, $b, 4);
warn("p4: $key value data: $!\n"),last FIL if $rd != 4;
$ent->{$key} = unpack('V',$b);
} else {
warn("p4: $key value type: not s ($b)\n");
last FIL;
}
}
return $ent;
}
return undef;
}
sub p4user_to_env {
my $u = shift;
$ENV{GIT_AUTHOR_NAME} = '';
$ENV{GIT_AUTHOR_EMAIL} = '';
return if !defined($u);
if (!exists($P4USERS{$u})) {
my ($mail,$name) = grep {/^(Email|FullName):/} qx{p4 user -o $u};
if ($? == 0 and defined($mail) and defined($name)) {
s/^\S+: ([^\r\n]*)\r?\n$/$1/so for ($mail,$name);
if (length($name) and length($mail)) {
$P4USERS{$u} = {name=>$name, email=>$mail};
}
}
}
if ($P4USERS{$u}) {
$p4u = $P4USERS{$u};
$ENV{GIT_AUTHOR_NAME} = $p4u->{name};
$ENV{GIT_AUTHOR_EMAIL} = $p4u->{email};
}
return 1;
}
sub p4_get_change {
my ($fd,$p4);
my $cl = shift;
if (!open($fd, '>', "$GIT_DIR/p4/files")) {
warn "p4/files: $!\n";
return;
}
print $fd "-o\n$cl\n";
close($fd);
if (!open($p4, "p4 -x $GIT_DIR/p4/files change|")) {
warn "p4: failed to read p4 change $cl: $!\n";
return;
}
my @change = <$p4>;
close($p4);
return @change;
}
sub cl2msg {
my $cl = shift;
my($o1,$o2,$i);
if(!open($o1, '>>', "$GIT_DIR/p4/msg")) {
warn "p4/msg: $!\n";
return;
}
binmode($o1);
if(!open($o2, '>>', "$GIT_DIR/p4/p4msg")) {
warn "p4/p4msg: $!\n";
close($o1);
return
}
binmode($o2);
if(!open($i, '-|', "p4 describe -s $cl")){
warn "p4 describe: $!\n";
close($o1);
close($o2);
return
}
binmode($i);
print $o1 "$cl: " if $FULL_DESC;
print $o2 "$cl: ";
my @a;
my $u = undef;
while (my $l = <$i>) {
if ($l =~ /^Change \d+ by (\S+)@[^ ]* on ([^\r\n]*)/so) {
$u = $1;
$ENV{GIT_AUTHOR_DATE} = $2 if length($2);
}
last if $FULL_DESC < 2 and $l =~ /^\s*Affected files \.{3}\s*$/so;
$l =~ s/\r?\n$//so;
push @a, $l;
}
close($i);
print $o2 substr($a[2],1),"\n"; # p4 side-branch commit description
close($o2);
# import branch commit description
if ($FULL_DESC > 1) {
# desc level 2+: keep the Change line
print $o1 map {"$_\n"} (substr($a[2],1),"\n",@a);
} else {
# levels 0 and 1: remove the Change line
print $o1 map { (length($_) ? substr($_,1):'')."\n" } @a[2..$#a];
}
close($o1);
p4user_to_env($u);
}
# looks for p4import/ commit which points to the given reference
# returns undef if not found
sub git_find_p4info {
my $branch = shift;
if (!%P4IMPORT_HEADS) {
foreach my $l (qx{git show-ref}) {
$P4IMPORT_HEADS{$2} = $1
if $l =~ m!^([0-9a-f]{40}) refs/(p4import/[^\r\n]+)\r?\n!so;
}
}
my ($commit,$parent,$p4commit,$p4parent);
my $r = git_rev_parse($branch);
return undef if !defined($r);
while (my ($k,$p4head) = each %P4IMPORT_HEADS) {
my $commit;
do {
print "trying $k:$p4head\n" if $VERBOSE >3;
($commit,$p4head) =
grep { s/^parent ([0-9a-f]{40}).*/$1/s }
qx{git cat-file commit $p4head};
$commit = $p4head = '' if $?;
return $p4head if $commit eq $r;
} while (defined($p4head) && length($p4head));
}
warn "$branch is not imported from Perforce\n";
return undef;
}
sub git_get_p4have {
my $p4head = shift;
my $p4have = undef;
if (defined($p4head) and length($p4head) and
open(my $f, '-|', "git cat-file blob $p4head:have")) {
my $old = $/;
$/ = "\0";
my $cnt = 0;
while(1) {
my $p4name = <$f>;
last if !defined($p4name);
$p4name =~ s/^.//so if $cnt; # remove \n
my $name = <$f>;
my $rev = <$f>;
last if !defined($name) or !defined($rev);
chop($p4name,$name,$rev);
++$cnt;
if (defined($p4have)) {
$p4have->{$p4name} = [$name,$rev];
} else {
$p4have = {$p4name=>[$name,$rev]};
}
}
$/ = $old;
close($f);
print "loaded $cnt revisions from $p4head\n" if $VERBOSE;
}
return $p4have;
}
sub p4_get_have {
print "reading state of $P4CLIENT\n" if $VERBOSE;
my ($p4have, $fdi);
open($fdi, "p4 -G -c $P4CLIENT -H $P4HOST -d $P4ROOT have|") or
die "p4 have: $!\n";
binmode($fdi);
my ($err,$ent) = (0,undef);
while (defined($ent=read_pydict_entry($fdi))) {
if (defined($ent->{code}) and defined($ent->{data})) {
++$err if $ent->{code} eq 'error';
print STDERR "p4: $ent->{code}: $ent->{data}\n";
next;
}
next if !defined($ent->{depotFile});
next if !defined($ent->{clientFile});
if (defined($p4have)) {
$p4have->{$ent->{depotFile}}=[$ent->{clientFile},$ent->{haveRev}];
} else {
$p4have={$$ent->{depotFile}=>[$ent->{clientFile},$ent->{haveRev}]};
}
}
close($fdi);
return $p4have;
}
sub git_p4_init {
my ($commit,$parent,$p4commit,$p4parent);
my $HEAD = git_rev_parse('HEAD');
$HEAD = '' if !defined($HEAD);
my $p4head = git_rev_parse("refs/p4import/$P4CLIENT");
$p4head = '' if !defined($p4head);
die "No HEAD commit! Refusing to import.\n" if !length($HEAD);
if (length($p4head)) {
($commit,$p4parent) =
grep { s/^parent (.{40}).*/$1/s }
qx{git cat-file commit $p4head};
$commit = $p4parent = '' if $?;
$p4parent = '' if !defined($p4parent);
} else {
$commit = $p4parent = '';
}
while (($commit ne $HEAD) and length($p4parent)) {
$p4head = $p4parent;
($commit,$p4parent) =
grep { s/^parent (.{40}).*/$1/so }
qx{git cat-file commit $p4head};
$commit = $p4parent = '' if $?;
$p4parent = '' if !defined($p4parent);
if ($VERBOSE and ($HEAD eq $commit)) {
print "found p4 import commit ";
system('git','name-rev',$p4head);
}
}
if ($HEAD ne $commit) {
$HEAD_FROM_P4 = 0;
warn "Current HEAD is not from $P4CLIENT, doing full import\n";
} else {
$HEAD_FROM_P4 = 1;
}
my $p4have = undef;
if (!$FULL_IMPORT and ($HEAD eq $commit) and length($p4head)) {
if (open(my $f, '-|', "git cat-file blob $p4head:have")) {
my $old = $/;
$/ = "\0";
my $cnt = 0;
while(1) {
my $p4name = <$f>;
last if !defined($p4name);
$p4name =~ s/^.//so if $cnt; # remove \n
my $name = <$f>;
my $rev = <$f>;
last if !defined($name) or !defined($rev);
chop($p4name,$name,$rev);
++$cnt;
if (defined($p4have)) {
$p4have->{$p4name} = [$name,$rev];
} else {
$p4have = {$p4name=>[$name,$rev]};
}
}
$/ = $old;
close($f);
print "loaded $cnt revisions from $p4head\n" if $VERBOSE;
}
}
return ($HEAD, $p4head, $p4have);
}
sub get_one_line {
my ($line) = qx{@_};
return undef if $?;
$line = '' if !defined($line);
$line =~ s/\r?\n//gs;
return $line;
}
sub git_rev_parse {
return get_one_line('git', 'rev-parse', shift);
}
sub git_write_tree {
my $sha1 = get_one_line('git','write-tree');
return undef if !defined($sha1) or !length($sha1);
return $sha1;
}
sub git_commit_tree {
my $sha1 = get_one_line('git','commit-tree',@_);
return undef if !defined($sha1) or !length($sha1);
return $sha1;
}
sub git_hash_stdin {
my $sha1 = get_one_line('git','hash-object','-t','blob','-w','--stdin');
return undef if !defined($sha1) or !length($sha1);
return $sha1;
}
sub git_hash_file {
open(STDIN, '<', $_[0]) or die "$0: git_hash_file $_[0]: $!\n";
return git_hash_stdin();
}
sub git_update_ref_directly {
return system('git','update-ref',@_);
}
sub git_update_ref {
my ($msg,$refname,$refval) = @_;
if ($refname =~ m!^(ORIG_|FETCH_|MERGE_)?HEAD$!o) {}
elsif ($refname =~ s!^/+!!o) {}
elsif ($refname =~ m!^refs/!o) {}
elsif ($refname =~ m!^(heads|remotes|tags|p4import)/!o) {
$refname = "refs/$refname"
} else { $refname = "refs/heads/$refname" }
print STDERR "Updating $refname with $refval\n" if $VERBOSE > 1;
return git_update_ref_directly('-m',$msg,$refname,$refval);
}
sub git_p4_commit {
my ($HEAD, $p4head) = @_;
my ($commit,$parent,$p4commit,$p4parent);
my ($fdo,$fdi,$rc);
$rc = system('git','diff-index','--exit-code','--quiet','--cached','HEAD');
if ($rc == 0) {
warn("No changes\n");
return;
}
return if $DRYRUN;
if (!@DESC && !$EDIT_COMMIT) {
warn "$0: no commit description given\n";
return;
}
my $p4x = "$GIT_DIR/p4/idx.tmp";
unlink($p4x);
$ENV{PAGER} = 'cat';
if (!defined($SPEC) or !open(STDIN, '<', $SPEC)) {
if ( $^O eq 'MSWin32' ) {
open(STDIN, '<', 'NUL') or die "$SPEC: $!\n";
} else {
open(STDIN, '<', '/dev/null') or die "$SPEC: $!\n";
}
}
my $p4spec = git_hash_stdin();
die "Failed to store $SPEC in git repo\n" if !defined($p4spec);
my $p4clnt = git_hash_file("$GIT_DIR/p4/client.def");
die "Failed to save mappings of $P4CLIENT in git repo" if !defined($p4clnt);
if (!defined($P4HAVE_FILE)) {
print "reading state of $P4CLIENT\n" if $VERBOSE;
$P4HAVE_FILE = "$GIT_DIR/p4/have";
open($fdo, '>', $P4HAVE_FILE) or die "p4/have: $!\n";
binmode($fdo);
open($fdi, "p4 -G -c $P4CLIENT -H $P4HOST -d $P4ROOT have|") or
die "p4 have: $!\n";
binmode($fdi);
my ($cnt,$err,$ent) = (0,0,undef);
while (defined($ent=read_pydict_entry($fdi))) {
if (defined($ent->{code}) and defined($ent->{data})) {
++$err if $ent->{code} eq 'error';
print STDERR 'p4: '.$ent->{code}.': '.$ent->{data}."\n";
next;
}
next if !defined($ent->{depotFile});
next if !defined($ent->{clientFile});
++$cnt;
print $fdo "$ent->{depotFile}\0",
"$ent->{clientFile}\0",
"$ent->{haveRev}\0\n";
}
close($fdi);
close($fdo);
exit 1 if $err; # the error already reported
die "The client $P4CLIENT has nothing\n" if !$cnt;
}
my $p4have = git_hash_file($P4HAVE_FILE);
die "Failed to save state of $P4CLIENT in git repo" if !defined($p4have);
#
# Prepare commit messages
#
unlink("$GIT_DIR/p4/msg", "$GIT_DIR/p4/p4msg");
open($fdo, '>', "$GIT_DIR/p4/msg"); close($fdo);
open($fdo, '>', "$GIT_DIR/p4/p4msg"); close($fdo);
foreach my $i (@DESC) {
$i =~ s/^(.)//o;
if ('c' eq $1) {
print "reading changes for $i\n" if $VERBOSE;
cl2msg($i);
} elsif ('f' eq $1) {
my($o1,$o2,$i);
if (open($o1, '>>', "$GIT_DIR/p4/msg")) {
if (open($o2, '>>', "$GIT_DIR/p4/p4msg")) {
if (open($i, '<', $i)) {
my $n = 0;
while(<$i>) {
$n++;
print $o1 $_;
print $o2 $_ if $n == 1;
}
close($i);
}
close($o2);
}
close($o1);
}
} elsif ('4' eq $1) {
print "reading changes for $i\n" if $VERBOSE;
my $change = get_one_line('p4', 'changes', '-m1', $i);
if (!defined($change) or $change !~ m/\s+(\d+)\s/) {
die "$i does not resolve into a change number\n";
}
cl2msg($1);
}
}
system("$editor $GIT_DIR/p4/msg") if $EDIT_COMMIT;
# copy mirror-branch commit message into side-branch
# commit message if no other description were given.
if (!-s "$GIT_DIR/p4/p4msg") {
open($fdi, '<', "$GIT_DIR/p4/msg") or die "$GIT_DIR/p4/msg: $!\n";
sysread($fdi,$buf,-s "$GIT_DIR/p4/msg");
close($fdi);
open($fdo, '>>', "$GIT_DIR/p4/p4msg") or die "$GIT_DIR/p4/p4msg: $!\n";
syswrite($fdo,$buf);
close($fdo);
}
#
# Store the imported file data
#
if ($VERBOSE < 2) {
if ( $^O eq 'MSWin32' ) { open(STDERR, "NUL") }
else { open(STDERR, "/dev/null") }
}
my $remove_merge_heads = 0;
my $tree = git_write_tree();
die "failed to write current tree\n" if !defined($tree);
open(STDIN, '<', "$GIT_DIR/p4/msg") or die "p4/msg: $!\n";
if (length($HEAD)) {
my @mergeparents;
if (open($fd, '<', "$GIT_DIR/MERGE_HEAD")) {
while(<$fd>) {
s/\r?\n$//gs;
push(@mergeparents, '-p', $_) if /^[0-9a-f]{40}$/;
}
close($fd);
}
$commit = git_commit_tree($tree, '-p', $HEAD, @mergeparents);
die "failed to commit the merged tree\n" if !defined($commit);
$remove_merge_heads = 1 if @mergeparents;
} else {
$commit = git_commit_tree($tree);
die "failed to commit current tree\n" if !defined($commit);
}
print "current tree stored in commit $commit\n" if $VERBOSE;
#
# Storing import control data
#
$ENV{GIT_INDEX_FILE} = $p4x;
open($fdo, '|-', 'git update-index --add --index-info') or
die "could not start git update-index\n";
binmode($fdo);
print $fdo "100644 $p4spec\tspec\n";
print $fdo "100644 $p4clnt\tclient\n";
print $fdo "100644 $p4have\thave\n";
close($fdo);
if($?) {
die "Failed to store $SPEC in p4import index and git repo\n".
"Failed to save mappings of $P4CLIENT in p4import index and git repo\n".
"Failed to save state of $P4CLIENT in p4import index and git repo\n"
}
my $p4tree = git_write_tree();
die "Failed to store $SPEC (tree) in git repo\n" if $?;
# Bind import control data to the file data
open(STDIN, '<', "$GIT_DIR/p4/p4msg") or die "p4/p4msg: $!\n";
$p4commit = length($p4head) ?
git_commit_tree($p4tree, '-p', $commit, '-p', $p4head):
git_commit_tree($p4tree, '-p', $commit);
die "Failed to store $SPEC (commit) in git repo\n" if $?;
# Finishing touches: update references
if (!$DRYRUN) {
git_update_ref('backup ref of current branch','/p4/backup-HEAD','HEAD');
git_update_ref('backup ref of p4import',
'/p4/backup-p4import',"refs/p4import/$P4CLIENT");
$rc = git_update_ref('data of p4import','HEAD',$commit);
die "Failed to update HEAD\n" if $rc;
unlink("$GIT_DIR/MERGE_HEAD") if $remove_merge_heads;
$rc = git_update_ref('p4import',"p4import/$P4CLIENT",$p4commit);
die "Failed to store $SPEC (reference) in git repo\n" if $rc;
}
$ENV{GIT_PAGER} = 'cat';
if ($VERBOSE) {
print STDOUT (grep {s/\r?\n//gs;s/.*?\s//} qx{git name-rev refs/p4import/$P4CLIENT}), ":\n";
system('git','log','--max-count=1','--pretty=format:%h %s%n',$p4commit);
}
print STDOUT (grep {s/\r?\n//gs;s/.*?\s//} qx{git name-rev HEAD}),":\n";
system('git','log','--max-count=1','--pretty=format:%h %s%n',$commit);
}
sub import_p4_dir {
my ($p4path, $local_path, $revrange, $parent, $branch) = @_;
my ($fd, $ent, $error, $rc) = (undef,undef,0,0);
print "Running changes\n" if $VERBOSE;
if (open($fd, '>', "$GIT_DIR/p4/files")) {
print "looking for changes $p4path/...$revrange\n" if $VERBOSE > 1;
print $fd "$p4path/...$revrange\n";
close($fd);
} else {
die "$0: p4/files: $!\n"
}
open(STDIN, '<', "$GIT_DIR/p4/files") or die "$0: p4/files: $!\n";
die "$0: changes $p4path: $!\n" if !open($fd, '-|', 'p4 -G -x - changes');
my %CHANGES = ();
while (defined($ent = read_pydict_entry($fd))) {
next if $error;
if ($ent->{code} eq 'error') {
warn "$0: p4: $ent->{data}\n";
$error = 1;
next;
}
print "change $ent->{change}\n" if $VERBOSE > 1;
$CHANGES{$ent->{change}} = {
change =>$ent->{change},
desc =>'', # have to read the desc anyway with describe
mtime =>$ent->{'time'},
user =>$ent->{user},
files =>[],
};
}
close($fd);
warn("$0: nothing found\n"), exit(0) if !%CHANGES;
exit 1 if $error;
print "Running describe for ".scalar(keys %CHANGES)." change lists\n"
if $VERBOSE;
if (open($fd, '>', "$GIT_DIR/p4/files")) {
print $fd map { "$_\n"} sort {$a <=> $b} keys %CHANGES;
close($fd);
} else {
die "$0: p4/files: $!\n"
}
open(STDIN, '<', "$GIT_DIR/p4/files") or die "$0: p4/files: $!\n";
die "$0: describe: $!\n" if !open($fd, '-|', 'p4 -G -x - describe');
while (defined($ent = read_pydict_entry($fd))) {
next if $error;
if ($ent->{code} eq 'error') {
warn "$0: p4: $ent->{data}\n";
$error = 1;
next;
}
$CHANGES{$ent->{change}}->{desc} = $ent->{desc};
$CHANGES{$ent->{change}}->{files} = {};
for (my $i=0;; ++$i) {
my $fn = $ent->{"depotFile$i"};
last if !defined($fn);
next if $fn !~ m!^$p4path(/|$)!;
$CHANGES{$ent->{change}}->{files}->{$fn} = {
action => $ent->{"action$i"},
};
# $ent->{"type$i"} : text, binary
}
}
close($fd);
exit 1 if $error;
print "Reading file data and creating git history\n" if $VERBOSE;
# Prepare clean index under the local path
$ENV{GIT_INDEX_FILE} = "$GIT_DIR/p4/idx.tmp";
unlink($ENV{GIT_INDEX_FILE});
if (length($parent)) {
$rc = system('git', 'read-tree', '-i', '--reset', $parent);
die "git read-tree $parent\n" if $rc;
$rc = system('git','update-index','--force-remove','--',$local_path);
die "git update-index $local_path\n" if $rc;
}
# Read file data for each change list
my $first = undef;
my $ch;
foreach my $k (sort {$a <=> $b} keys %CHANGES) {
$ch = $CHANGES{$k};
print "$k\n" if $VERBOSE > 1;
# Read the full tree for the first change number
if (open($fd, '>', "$GIT_DIR/p4/files")) {
if (!defined($first)) {
print $fd "$p4path/...\@$k\n";
$first = $k;
} else {
foreach my $f (keys(%{$ch->{files}})) {
print $fd "$f\@$k\n";
}
}
close($fd);
} else {
die "$0: p4/files: $!\n"
}
open(STDIN, '<', "$GIT_DIR/p4/files") or die "$0: p4/files: $!\n";
print "Reading file data for $k\n" if $VERBOSE > 1;
die "$0: print: $!\n" if !open($fd, '-|', 'p4 -G -x - print');
my $tmpfile = "$GIT_DIR/p4/cp.tmp";
while (defined($ent = read_pydict_entry($fd))) {
next if $error;
if ($ent->{code} eq 'error') {
warn "$0: p4: $ent->{data}\n";
$error = 1;
next;
}
if ($ent->{code} eq 'binary') {
if (!defined($f)) {
warn "$0: file data without stat info\n";
$error = 1;
next;
}
$f->{size} += length($ent->{data});
if (length($ent->{data})) {
if (!defined(syswrite($f->{tmpfd}, $ent->{data}))) {
warn "$f->{depotFile}: $tmpfile: $!\n";
close($f->{tmpfd});
$f = undef;
$error = 1;
next;
}
} else {
# FILE FINISHED IF AN EMPTY BINARY PACKET RECEIVED
close($f->{tmpfd});
my $fn = $f->{depotFile};
# put file data into git repo
my $tmpsha1 = git_hash_file($tmpfile);
die "Failed to save $fn in git repo\n" if !defined($tmpsha1);
unlink($tmpfile);
$f->{sha1} = $tmpsha1;
print "$k\t$tmpsha1\t$f->{size}\t$fn\n" if $VERBOSE > 2;
$ch->{files}->{$fn} = $f;
delete $f->{depotFile}; # cleanup
delete $f->{tmpfd}; # cleanup
$f = undef;
}
next;
}
if ($ent->{code} eq 'stat') {
die "$0: file $f->{depotFile} truncated\n" if defined($f);
die "$ent->{depotFile}: the leading path not expected\n"
if substr($ent->{depotFile},0,length($p4path)) ne $p4path;
die "$ent->{depotFile}\@$ent->{change}: the change not expected\n"
if $ent->{change} > $k;
my $prev = $ch->{files}->{$ent->{depotFile}};
$f = {
action => defined($prev->{action}) ? $prev->{action}:'add',
change => $ent->{change},
depotFile => $ent->{depotFile},
mtime => $ent->{'time'},
size => 0,
};
my $ft;
open($ft,'>',$tmpfile) or die "$tmpfile: $!\n";
$f->{tmpfd} = $ft;
}
}
close($fd);
exit 1 if $error;
my $modcnt = 0;
my @delfiles = ();
my $fdo = undef;
open($fdo, '|-', 'git update-index -z --replace --add --index-info') or
die "could not start git update-index\n";
binmode($fdo);
while (my ($fn,$f) = each %{$ch->{files}}) {
if (substr($fn,0,length($p4path)) ne $p4path) {
die "$fn: the leading path not expected\n";
}
my $locfile = $fn;
substr($locfile,0,length($p4path)) = $local_path;
$locfile =~ s!^/+!!o;
push(@delfiles, $locfile), next if $f->{action} eq 'delete';
print "\t$f->{sha1}\t$locfile\n" if $VERBOSE > 1;
my $mode = '100644';
$mode = '100755' if $locfile =~ /\.(exe|bat|cmd|pl|dll|so)$/io;
print $fdo "$mode $f->{sha1}\t$locfile\0";
++$modcnt;
}
close($fdo);
die "failed to build the trees in $local_path for $k\n" if $?;
if (@delfiles) {
open($fdo, '|-', 'git update-index -z --force-remove --stdin') or
die "could not start git update-index to remove files\n";
binmode($fdo);
print $fdo map { "$_\0" } @delfiles;
close($fdo);
print map { "\tdelete $_\n" } @delfiles if $VERBOSE > 1;
die "failed to clean the trees in $local_path for $k\n" if $?;
$modcnt += scalar @delfiles;
}
my $tree = git_write_tree();
die "Failed to store tree of $k in git repo\n" if !defined($tree);
print "\ttree of $k written as $tree\n" if $VERBOSE > 1;
# prepare commit
open($fdo,'>',"$GIT_DIR/p4/msg") or die "p4/msg: $!\n";
print $fdo "$k: $ch->{desc}";
close($fdo);
p4user_to_env($ch->{user});
$ENV{GIT_AUTHOR_DATE} = $ch->{mtime};
open(STDIN, '<', "$GIT_DIR/p4/msg") or die "p4/msg (commit): $!\n";
my $commit = length($parent) ?
git_commit_tree($tree, '-p', $parent): git_commit_tree($tree);
die "Failed to commit $k in git repo\n" if !defined($commit);
print "$k committed as $commit";
print " ($modcnt modification".($modcnt==1?'':'s').')' if $VERBOSE;
print "\n";
$parent = $commit;
}
if (!$DRYRUN and length($parent)) {
git_update_ref("backup ref of $branch", "/p4/backup-$branch",$branch)
if defined($branch);
$branch = '/p4/IMPORT' if !defined($branch);
my $rc = git_update_ref("p4 import $branch", $branch, $parent);
die "failed to update $branch with $parent\n" if $rc;
$branch =~ s!^/+!!;
print "Branch '$branch' updated with state from $ch->{change}\n";
$ENV{GIT_PAGER} = 'cat';
system('git','log','--max-count=1','--pretty=format:%h %s%n',$branch);
}
}
sub git_show_diffs {
my $sep = $/;
$/="\0";
my ($show, $cnt) = (0, 0);
if (open(F, '-|', 'git diff-files -r --name-only -z')) {
while (<F>) {
my $c = chop;
$_ .= $c if $c ne "\0";
print "Changed files:\n" if !$show;
print " $_\n";
$show = 1;
$cnt++;
}
close(F);
}
if (open(F, '-|', 'git diff-index --cached -r -z HEAD')) {
$show = 0;
my ($diff, $info) = (0, 1);
while (<F>) {
my $c = chop;
$_ .= $c if $c ne "\0";
if ($info) {
next if !/^:(\d{6}) (\d{6}) ([0-9a-f]{40}) ([0-9a-f]{40}) ./o;
# show only content changes, p4 does not support exec-bit anyway
$diff = $3 ne $4;
} elsif ($diff) {
print "Changes between index and HEAD:\n" if !$show;
print " $_\n";
$show = 1;
$cnt++;
}
$info = !$info;
}
close(F);
}
$/ = $sep;
return $cnt;
}
sub git_sync_to {
my $rc;
my $branch = shift;
if (!$FORCE) {
$rc = system('git', 'diff', '--quiet');
warn("There are changes in the working directory. Refusing to sync\n")
if $rc;
$rc = system('git', 'diff', '--quiet', '--cached');
warn("There are changes in the index. Refusing to sync\n") if $rc;
}
my $p4head = git_find_p4info($branch);
print "found p4 import commit $p4head for $branch\n"
if ($VERBOSE > 1 or $DRYRUN) and defined $p4head;
return 0 if $DRYRUN and defined $p4head;
my $p4have = git_get_p4have($p4head);
die "$p4head has no p4 data\n" if !defined($p4have);
my ($fd,$fdo);
die "reading client $P4CLIENT: $!\n"
if !open($fd, '-|', "p4 -G client -o $P4CLIENT");
binmode($fd);
my %cdata = (Client=>'', Description=>'', LineEnd=>'', Options=>'');
while (defined($ent = read_pydict_entry($fd))) {
next if $error;
if ($ent->{code} eq 'error') {
warn "p4 client $P4CLIENT: $ent->{data}\n";
$error = 1;
next;
}
foreach my $k (keys %cdata) {
$cdata{$k} = $ent->{$k} if defined $ent->{$k};
}
}
close($fd);
die "client.def: $!\n" if !open($fdo, '>', "$GIT_DIR/p4/client.def");
binmode($fdo);
print $fdo "Client: $P4CLIENT\n\n";
print $fdo "Description:\n";
$cdata{Description} =~ s/\n/\n\t/gs;
$cdata{Description} =~ s/\t$//s;
print $fdo "\t$cdata{Description}\n";
my $wd = cwd();
$wd =~ s/\\/\//go;
print $fdo "Root:\t$wd\n\n";
print $fdo "LineEnd:\t$cdata{LineEnd}\n\n";
print $fdo "Options:\t$cdata{Options}\n\n";
print $fdo "View:\n";
print $fdo
map {
my $fn = $p4have->{$_}->[0];
$fn =~ s!^//[^/]*/!//$P4CLIENT/!o;
s/([ \t"'@*#%])/sprintf("%%%02x",ord($1))/geo for ($_,$fn);
"\t$_ $fn\n"
} sort { $a cmp $b }
keys %{$p4have};
close($fdo);
print "loading client $P4CLIENT\n";
open(STDIN, '<', "$GIT_DIR/p4/client.def") or die "client.def: $!\n";
run_or_exit('p4', 'client', '-i');
die "files: $!\n" if !open($fdo, '>', "$GIT_DIR/p4/files");
print $fdo
map {
my $fn = $_;
s/([ \t"'@*#%])/sprintf("%%%02x",ord($1))/geo;
"$_#$p4have->{$fn}->[1]\n"
} sort { $a cmp $b }
keys %{$p4have};
close($fdo);
print "syncing client $P4CLIENT\n";
open(STDIN, '<', "$GIT_DIR/p4/files") or die "p4/files: $!\n";
run_or_exit('p4', '-c', $P4CLIENT, '-H', $P4HOST, '-d', $P4ROOT,'-x', '-', 'sync');
return defined($p4head) ? 0: 1;
}
sub git_p4_tag_HEAD {
my $cl = shift;
my @change = p4_get_change($cl);
return 0x100 if !@change;
my $d=0;
my ($first_line) = grep {
if ($d==1) {
if (!/^\s*[\r\n]*$/so) { $d=0; 1 }
else { 0 }
} else {
$d=1 if /^Description:/o; 0
}
} @change;
my $fd;
if (!open($fd, '>', "$GIT_DIR/p4/desc")) {
warn "p4/desc: $!\n";
return 0x100;
}
unshift(@change, '');
$first_line =~ s/^\s+//;
unshift(@change, $first_line);
print $fd map {s/\r?\n$//so;"$_\n"} @change;
close($fd);
my $rc = system('git', 'tag', '-f', '-F', "$GIT_DIR/p4/desc", "p4/$cl");
print "HEAD tagged p4/$cl\n" if !$rc;
return $rc;
}
sub git_p4_merge {
my ($source_head,$do_merge,$auto_submit) = @_;
my $rc = system('git', 'diff-files', '--quiet');
exit(127) if $rc & 0xff; # error starting the program
die "There are changes in $P4ROOT. Clean them up first.\n" if $rc;
$source_head = 'HEAD' if !defined($source_head);
my $mergehead = git_rev_parse($source_head);
exit(1) if !defined($mergehead) or !length($mergehead);
my $fast_forward = 1;
# Check if the given reference is a direct descendant of current branch
if ($source_head ne 'HEAD') {
my $sha1 = get_one_line('git', 'rev-list', '--max-count=1', "$mergehead..HEAD");
exit 1 if !defined($sha1);
if (length($sha1) and defined($sha1) and $sha1 =~ /^[0-9a-f]{40}\b/) {
my $msg = "HEAD does not fast-forward to $source_head\n";
$do_merge ? warn("Warning: $msg"): die("Fatal: $msg");
$fast_forward = 0;
}
}
print "Checking out $source_head ($mergehead) for p4 edit\n" if $VERBOSE;
my $cnt;
my @files = ();
my $sep = $/;
$/="\0";
if (open(F, '-|', "git diff-index -R --cached -r -z $mergehead")) {
my ($diff, $info, $M) = (0, 1, '');
while (<F>) {
my $c = chop;
$_ .= $c if $c ne "\0";
if ($info) {
next if !/^:\d{6} \d{6} ([0-9a-f]{40}) ([0-9a-f]{40}) (\w+)/o;
# use only content changes, p4 does not support exec-bit
$diff = $1 ne $2;
$M = $3; # change type marker
} elsif ($diff) {
print "$M $_\n" if $VERBOSE;
die "File contains characters which p4 cannot support\n"
if /[\n@#%*]/s;
push @files, "$M$_";
$cnt++;
}
$info = !$info;
}
close(F);
}
$/ = $sep;
if (!$cnt) {
warn "$0: No content changes found between HEAD and $source_head";
return 0;
}
# Create a new changelist
my $p4;
open($p4, "p4 -c $P4CLIENT -H $P4HOST -d $P4ROOT change -o|") or
die "$0: failed to create changelist\n";
my @desc = map {s/\r?\n$//so; $_} <$p4>;
close($p4);
my $desc_pos = 0;
foreach (@desc) {
++$desc_pos;
last if /^Description:/o;
}
my $editfd;
die "$GIT_DIR/p4/desc.txt: $!\n"
if !open($editfd, '>', "$GIT_DIR/p4/desc.txt");
my $range = "..$mergehead";
# because I have no information about what I am merging with:
# this is the case when a push modified HEAD.
$range = "${mergehead}^..$mergehead" if $source_head eq 'HEAD';
if (open(my $fd, '-|', "git log $range")) {
while(<$fd>) {
# I believe it is not possible to save this information
# in Perforce. They are primitive
next if /^(commit |Author:|Date:)/;
s/\r?\n$//so;
next if !length($_); # header/message separator line
s/^\s{4}//o;
print $editfd "$_\n" if defined($editfd);
}
close($fd);
}
print $editfd map { /^\s?(.*)/o;"$1\n" } @desc[$desc_pos..$#desc];
close($editfd);
system("$editor $GIT_DIR/p4/desc.txt") if $EDIT_COMMIT;
die "$GIT_DIR/p4/desc.txt: $!\n"
if !open($editfd, '<', "$GIT_DIR/p4/desc.txt");
my @tmpdesc = <$editfd>;
die "No change description, not merging.\n"
if !grep {!m/^(\s|[\r\n])*$/so} @tmpdesc;
splice(@desc, $desc_pos, $#desc + 1 - $desc_pos,
map {s/\r?\n$//so;" $_"} @tmpdesc);
close($editfd);
open($p4, '>', "$GIT_DIR/p4/changelist") or
die "$GIT_DIR/p4/changelist: $!\n";
print $p4 map {"$_\n"} @desc;
close($p4);
return 0 if $DRYRUN;
open(STDIN, '<', "$GIT_DIR/p4/changelist") or
die "$GIT_DIR/p4/changelist: $!\n";
open($p4, "p4 -c $P4CLIENT -H $P4HOST -d $P4ROOT change -i|") or
die "$0: failed to create changelist\n";
my ($newchange) = grep {s/^Change (\d+) created\b.*/$1/so} <$p4>;
close($p4);
print "Checking out P4 files in changelist $newchange\n" if $VERBOSE;
sub runp4 {
run_or_exit('p4','-c',$P4CLIENT,'-H',$P4HOST,'-d',$P4ROOT,@_);
}
# open files for edit
$cnt = 0;
open($p4, '>', "$GIT_DIR/p4/files") or die "$GIT_DIR/p4/files: $!\n";
print $p4 "-c\n$newchange\n";
print $p4 (map {++$cnt; substr($_,1)."\n"} grep {/^M/} @files);
close($p4);
runp4('-x',"$GIT_DIR/p4/files", 'edit') if $cnt;
exit(1) if $?;
$cnt = 0;
open($p4, '>', "$GIT_DIR/p4/files") or die "$GIT_DIR/p4/files: $!\n";
print $p4 "-c\n$newchange\n";
print $p4 (map {++$cnt; substr($_,1)."\n"} grep {/^A/} @files);
close($p4);
runp4('-x',"$GIT_DIR/p4/files", 'add') if $cnt;
exit(1) if $?;
$cnt = 0;
open($p4, '>', "$GIT_DIR/p4/files") or die "$GIT_DIR/p4/files: $!\n";
print $p4 "-c\n$newchange\n";
print $p4 (map {++$cnt; substr($_,1)."\n"} grep {/^D/} @files);
close($p4);
runp4('-x',"$GIT_DIR/p4/files", 'delete') if $cnt;
exit(1) if $?;
# p4 modifies working directory on checkout, stupid thing
system('git', 'update-index', '--refresh');
if ($do_merge) {
run_or_exit('git', 'merge', '--no-commit', $mergehead);
} else {
run_or_exit('git', 'read-tree', '-m', '-u', $mergehead);
print "The state of $source_head($mergehead) is checked out.\n";
}
if (!$auto_submit) {
print "A p4 changelist $newchange is prepared.\n";
print "To submit:\n\tp4 submit -c $newchange\n";
print "To commit:\n\tgit-p4-import.bat -y -C SUBMITTED_CHANGE\n"
if !$fast_forward;
} else {
die "p4/files: $!\n" if !open($p4, '>', "$GIT_DIR/p4/files");
print $p4 "-c\n$newchange\n";
close($p4);
my @res;
my $subchange = undef;
@res = qx{p4 -c $P4CLIENT -H $P4HOST -d $P4ROOT -x $GIT_DIR/p4/files submit};
die "p4: failed to run p4 submit -c $newchange\n" if $?;
foreach(@res) {
print;
if (/^\s*Change (\d+) submitted\..*/s) {
$subchange = $1;
}
elsif (/^\s*Change (\d+) renamed change (\d+) and submitted.*/s) {
$subchange = $2 if $1 eq $newchange;
}
}
die "p4 submit behaved unexpectedly\n".
"To tag the current HEAD use \n".
"\tgit-p4-import --p4-tag <the new change>\n"
if !defined($subchange);
$subchange =~ s/\r?\n$//so;
print "Submitted as $subchange\n";
if ($fast_forward) {
$rc = git_p4_tag_HEAD($subchange);
exit(127) if $rc & 0xff;
exit(1) if $rc;
print "Tagged as p4/$subchange\n";
} else {
print "The merged tree is left in $P4ROOT.\n";
print "To commit:\n\tgit-p4-import.bat -y -C $subchange\n";
}
}
return 0;
}
__END__
:__end_of_file__
^ permalink raw reply
* Draft release notes for v1.5.3, as of -rc1
From: Junio C Hamano @ 2007-07-13 6:40 UTC (permalink / raw)
To: git
In-Reply-To: <7vzm20q1l7.fsf_-_@assigned-by-dhcp.cox.net>
GIT v1.5.3 Release Notes (draft)
========================
Updates since v1.5.2
--------------------
* The commit walkers other than http are officially deprecated,
but still supported for now.
* The submodule support has Porcelain layer.
* There are a handful pack-objects changes to help you cope better
with repositories with pathologically large blobs in them.
* For people who need to import from Perforce, a front-end for
fast-import is in contrib/fast-import/.
* Comes with git-gui 0.8.0.
* Comes with updated gitk.
* New commands and options.
- The hunk header output from "git diff" family can be customized
with the attributes mechanism. See gitattributes(5) for details.
- "git stash" allows you to quickly save away your work in
progress and replay it later on an updated state.
- "git rebase" learned an "interactive" mode that let you
pick and reorder which commits to rebuild.
- "git fsck" can save its findings in $GIT_DIR/lost-found,
without a separate invocation of "git lost-found" command.
- $GIT_WORK_TREE environment variable can be used together with
$GIT_DIR to work in a subdirectory of a working tree that is
not located at "$GIT_DIR/..".
- "git log" learned a new option "--follow", to follow
renaming history of a single file.
- "git-filter-branch" lets you rewrite the revision history of
the current branch, creating a new branch. You can specify a
number of filters to modify the commits, files and trees.
- "git-cvsserver" learned new options (--base-path, --export-all,
--strict-paths) inspired by git-daemon.
- "git-submodule" command helps you manage the projects from
the superproject that contain them.
- In addition to core.compression configuration option,
core.loosecompression and pack.compression options can
independently tweak zlib compression levels used for loose
and packed objects.
- "git-ls-tree -l" shows size of blobs pointed at by the
tree entries, similar to "/bin/ls -l".
- "git-rev-list" learned --regexp-ignore-case and
--extended-regexp options to tweak its matching logic used
for --grep fitering.
- "git-describe --contains" is a handier way to call more
obscure command "git-name-rev --tags".
- "git gc --aggressive" tells the command to spend more cycles
to optimize the repository harder.
- "git repack" can be told to split resulting packs to avoid
exceeding limit specified with "--max-pack-size".
- "git fsck" gained --verbose option. This is really really
verbose but it might help you identify exact commit that is
corrupt in your repository.
- "git format-patch" learned --numbered-files option. This
may be useful for MH users.
- "git format-patch" learned format.subjectprefix configuration
variable, which serves the same purpose as "--subject-prefix"
option.
- "git tag -n -l" shows tag annotations while listing tags.
- "git cvsimport" can optionally use the separate-remote layout.
- "git blame" can be told to see through commits that change
whitespaces and indentation levels with "-w" option.
- "git send-email" can be told not to thread the messages when
sending out more than one patches.
- "git config" learned NUL terminated output format via -z to
help scripts.
- "git init -q" makes the command quieter.
* Updated behavior of existing commands.
- "git svn dcommit" retains local merge information.
- "git config" to set values also honors type flags like --bool
and --int.
- core.quotepath configuration can be used to make textual git
output to emit most of the characters in the path literally.
- "git mergetool" chooses its backend more wisely, taking
notice of its environment such as use of X, Gnome/KDE, etc.
- "gitweb" shows merge commits a lot nicer than before. The
default view uses more compact --cc format, while the UI
allows to choose normal diff with any parent.
- snapshot files "gitweb" creates from a repository at
$path/$project/.git are more useful. We use $project part
in the filename, which we used to discard.
- "git cvsimport" creates lightweight tags; there is no
interesting information we can record in an annotated tag,
and the handcrafted ones the old code created was not
properly formed anyway.
- "git-push" pretends that you immediately fetched back from
the remote by updating corresponding remote tracking
branches if you have any.
- The diffstat given after a merge (or a pull) honors the
color.diff configuration.
- "git-apply --whitespace=strip" removes blank lines added at
the end of the file.
- "git-fetch" over git native protocols with "-v" option shows
connection status, and the IP address of the other end, to
help diagnosing problems.
- We used to have core.legacyheaders configuration, when
set to false, allowed git to write loose objects in a format
that mimicks the format used by objects stored in packs. It
turns out that this was not so useful. Although we will
continue to read objects written in that format, we do not
honor that configuration anymore and create loose objects in
the legacy/traditional format.
- "--find-copies-harder" option to diff family can now be
spelled as "-C -C" for brevity.
- "git-mailsplit" (hence "git-am") can read from Maildir
formatted mailboxes.
- "git-cvsserver" does not barf upon seeing "cvs login"
request.
- "pack-objects" honors "delta" attribute set in
.gitattributes. It does not attempt to deltify blobs that
come from paths with delta attribute set to false.
- "new-workdir" script (in contrib) can now be used with a
bare repository.
- "git-mergetool" learned to use gvimdiff.
- "gitview" (in contrib) has a better blame interface.
- "git log" and friends did not handle a commit log message
that is larger than 16kB; they do now.
- "--pretty=oneline" output format for "git log" and friends
deals with "malformed" commit log messages that have more
than one lines in the first paragraph better. We used to
show the first line, cutting the title at mid-sentence; we
concatenate them into a single line and treat the result as
"oneline".
* Builds
- old-style function definitions (most notably, a function
without parameter defined with "func()", not "func(void)")
have been eradicated.
* Performance Tweaks
- git-pack-objects avoids re-deltification cost by caching
small enough delta results it creates while looking for the
best delta candidates.
- git-pack-objects learned a new heuristcs to prefer delta
that is shallower in depth over the smallest delta
possible. This improves both overall packfile access
performance and packfile density.
- diff-delta code that is used for packing has been improved
to work better on big files.
- when there are more than one pack files in the repository,
the runtime used to try finding an object always from the
newest packfile; it now tries the same packfile as we found
the object requested the last time, which exploits the
locality of references.
- verifying pack contents done by "git fsck --full" got boost
by carefully choosing the order to verify objects in them.
Fixes since v1.5.2
------------------
All of the fixes in v1.5.2 maintenance series are included in
this release, unless otherwise noted.
* Bugfixes
- "gitweb" had trouble handling non UTF-8 text with older
Encode.pm Perl module.
^ permalink raw reply
* Re: [PATCH] make git-send-email.perl handle email addresses with no names when Email::Valid is present
From: Greg KH @ 2007-07-13 6:34 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vr6ncrh22.fsf@assigned-by-dhcp.cox.net>
On Thu, Jul 12, 2007 at 10:47:17PM -0700, Junio C Hamano wrote:
> Greg KH <greg@kroah.com> writes:
>
> > When using git-send-email.perl on a changeset that has:
> > Cc: <stable@kernel.org>
> > in the body of the description, and the Email::Valid perl module is
> > installed on the system, the email address will be deemed "invalid" for
> > some reason (Email::Valid isn't smart enough to handle this?) and
> > complain and not send the address the email.
>
> That appears to be the case.
>
> bad foo
> bad <foo@bar.baz>
> ok foo@bar.baz
> ok Foo <foo@bar.baz>
>
> > Anyway, this tiny patch fixes this problem for me. Note, my perl-foo is
> > quite week, so this could probably be easily done in one line for those
> > with better reg-ex skills.
>
> > --- a/git-send-email.perl
> > +++ b/git-send-email.perl
> > @@ -410,6 +410,9 @@ sub extract_valid_address {
> > return $address if ($address =~ /^($local_part_regexp)$/);
> >
> > if ($have_email_valid) {
> > + if ($address =~ s/^<//) {
> > + $address =~ s/>$//;
> > + }
> > return scalar Email::Valid->address($address);
> > } else {
>
> I'd probably do:
>
> if ($have_email_valid) {
> $address =~ s/^<(.*)>$/$1/;
Ah, yeah, that looks better :)
Thanks for the fix,
greg k-h
^ permalink raw reply
* Re: Lump commit HOWTO?
From: martin f krafft @ 2007-07-13 6:09 UTC (permalink / raw)
To: Git Mailing List
In-Reply-To: <625fc13d0707121821l70e2d6aaw555c79b5d700585f@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 692 bytes --]
also sprach Josh Boyer <jwboyer@gmail.com> [2007.07.13.0321 +0200]:
> 8) take all local commits (A - D) and create a single commit without
> any of the upstream changes in it
This is entirely untested and since I am a newbie, it might well not
work, but shouldn't the following do what you want?
git log origin..master --> gives you the local commits not in origin
git checkout -b merger
git merge --squash <sha> <sha> <sha> ...
git commit ...
--
martin; (greetings from the heart of the sun.)
\____ echo mailto: !#^."<*>"|tr "<*> mailto:" net@madduck
spamtraps: madduck.bogus@madduck.net
officer, arrest that man! he's whistling a copyrighted song.
[-- Attachment #2: Digital signature (GPG/PGP) --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* What's in git.git
From: Junio C Hamano @ 2007-07-13 6:06 UTC (permalink / raw)
To: git
In-Reply-To: <7vk5tj3bj1.fsf@assigned-by-dhcp.cox.net>
Executive summary:
* (maint) hopefully the last maintenance release for v1.5.2
codebase, v1.5.2.4, is out.
* (master) v1.5.3 is nicely progressing and we have v1.5.3-rc1
out, but it has a serious last minute glitch in pack-objects,
so please do not use "git-gc", or "git-repack" from vanilla
v1.5.3-rc1.
v1.5.3-rc1-1-g7d7baa5 or later should be Ok.
* (next/pu) No topics are cooking in 'next' right now, although
I might apply a few series I did not pick up from the list in
the past few days, just to keep them from getting lost.
As usual, v1.5.3-rc1 means:
* I personally will be using 'master' version for my work until
v1.5.3 final (I usually run 'next', and switch to 'master'
after -rc0); I ask contributors to do the same to shake out
the last minute bugs from 'master'.
* No more features and large code churning on 'master' until
v1.5.3 final.
* Bugfixes and documenation updates are always welcomed, but
even more so than usual until v1.5.3 final.
I'll send out a draft release notes for v1.5.3 in a separate
message.
----------------------------------------------------------------
* The 'maint' branch spawned 1.5.2.4 with accumulated fixes.
Most notably, we are in sync with git-gui 0.7.5.
* The 'master' branch has these since the last announcement;
we are at v1.5.3-rc1 plus a few fixes.
Adam Roben (1):
format-patch: Add format.subjectprefix config option
Alecs King (1):
fix remote.origin.url in tutorial.txt
Alex Riesen (4):
Handle missing prefix for "Subject:" as if no prefix given
Handle format.subjectprefix for every command which accepts
--pretty
Fix t5516 to create test repo without hooks
Add -v|--verbose to git remote to show remote url
Andrew Ruder (2):
Remove USE_PAGER from git-pickaxe and git-annotate
Add urls.txt to git-clone man page
Brian Downing (10):
pack-objects: Prefer shallower deltas if the size is equal
gitk: Fix for tree view ending in nested directories
Pack information tool
Correct shebang line for contrib/stats/packinfo.pl
Don't try to delta if target is much smaller than source
Support fetching the memory usage of a delta index
Add functions for parsing integers with size suffixes
Add pack-objects window memory usage limit
Add --window-memory option to git-repack
Add documentation for --window-memory, pack.windowMemory
Brian Gernhardt (1):
Add core.pager config variable.
CJ van den Berg (1):
git-submodule: Fix two instances of the same typo
Carlos Rica (5):
t7004: Skip tests for signed tags in an old version of gpg.
t0030: Remove repeated instructions and add missing &&
t0030: Add tests with consecutive text lines and others with spaces
added.
t7004: Add tests for the git tag -n option.
Function stripspace now gets a buffer instead file descriptors.
Daniel Barkalow (2):
Add allocation and freeing functions for struct refs
Some cosmetic changes to remote library
David Kastrup (1):
Add missing functions to contrib/emacs/vc-git.el
Emil Medve (1):
git-submodule: Instead of using only annotated tags, use any tags.
Eric Wong (2):
git-svn: allow dcommit to retain local merge information
git-svn: fix blocking with svn:// servers after do_switch
Frank Lichtenheld (1):
cvsserver: always initialize state in argsplit()
Gerrit Pape (1):
git-commit: don't add multiple Signed-off-by: from the same
identity
Jakub Narebski (3):
Update git-merge documentation.
Document long options '--message=<msg>' and '--no-commit'
Document git commit --untracked-files and --verbose
James Bowes (1):
stash: allow running from a subdirectory
Jeff King (6):
git-stash: fix "no arguments" case in documentation
git-stash: fix "can't shift that many" with no arguments
git-stash: don't complain when listing in a repo with no stash
Documentation: quote {non-attributes} for asciidoc
Documentation: quote {non-attributes} for asciidoc
Documentation: minor cleanups to branch/checkout wording
Jeffrey C. Ollie (2):
Add an option to quiet git-init.
Quiet the output from git-init when cloning, if requested.
Johannes Schindelin (28):
Move the pick_author code to git-sh-setup
Teach rebase an interactive mode
rebase -i: several cleanups
rebase -i: provide reasonable reflog for the rebased branch
Teach rebase -i about --preserve-merges
Make '!' aliases more useful
git-fsck: add --lost-found option
Document git-filter-branch
Add diff-option --ext-diff
filter-branch: add a test for the commit removal example
filter-branch: make output nicer
filter-branch: a few more touch ups to the man page
filter-branch documentation: clarify which filters are eval'ed
filter-branch: fail gracefully when a filter fails
Future-proof source for changes in xdemitconf_t
Teach git-stash to "apply --index"
Enable "git rerere" by the config variable rerere.enabled
git-branch: default to --track
branch.autosetupmerge: allow boolean values, or "all"
rebase -i: handle --continue more like non-interactive rebase
rebase -i: actually show the diffstat when being verbose
rebase -i: remember the settings of -v, -s and -p when interrupted
rebase -i: put a nice warning into the todo list
rerere: record resolution even if file is not in merge base
Fix core.sharedRepository = 2
Fix --cherry-pick with given paths
Add for_each_remote() function, and extend remote_find_tracking()
branch --track: code cleanup and saner handling of local branches
Johannes Sixt (4):
Test 'git add' for unmerged entries when core.symlinks=false.
filter-branch: Avoid an error message in the map function.
filter-branch documentation: some more touch-ups.
Allow rebase to run if upstream is completely merged
Jonas Fonseca (1):
fsck --lost-found writes to subdirectories in .git/lost-found/
Junio C Hamano (30):
diffcore_count_changes: pass diffcore_filespec
diffcore_filespec: add is_binary
diffcore-delta.c: update the comment on the algorithm.
diffcore-delta.c: Ignore CR in CRLF for text files
git-stash: require "save" to be explicit and update documentation
Update public documentation links for 1.5.2.3
"git-push $URL" without refspecs pushes only matching branches
Rewrite "git-frotz" to "git frotz"
git-stash: make "save" the default action again.
Mark disused commit walkers officially deprecated.
Update draft Release Notes for 1.5.3
Update reflog message created for stashes
Do not check if getcwd() result begins with a slash.
Fix git-stash(1) markup.
git-stash: allow more descriptive reminder message when saving
Introduce diff_filespec_is_binary()
Per-path attribute based hunk header selection.
Fix configuration syntax to specify customized hunk header
patterns.
diff: honor binariness specified in attributes
gitweb: make repeated calls to git_get_project_owner() bearable
diff.c: make built-in hunk header pattern a separate table
git-gui: use "blame -w -C -C" for "where did it come from,
originally?"
git-stash: try reusing cached stat info as much as possible
Fix merge-one-file for our-side-added/our-side-removed cases
Document custom hunk header selection
revision.c: remove duplicated parents after history simplification
Revert 88494423 (removal of duplicate parents in the output
codepath)
Re-code builtin-branch.c in UTF-8
Update list of older git docs
GIT v1.5.3-rc1
Lars Hjemli (1):
git-submodule(1): update description and key names
Linus Torvalds (1):
Start deprecating "git-command" in favor of "git command"
Marcus Fritzsch (1):
Fixed a formulation mistake in Documentation/user-manual.txt
Matt Kraai (3):
Prefer EMAIL to username@hostname.
Change "added.moved or removed" to "added, moved or removed" in
Add [verse] to the SYNOPSIS section of git-submodule.txt.
Matt McCutchen (3):
gitweb: make search form generate pathinfo-style URLs
gitweb: make "No commits" in project list gray, not bold green
Makefile: rebuild git.o on version change, clean up git$X flags
Matthias Lederhofer (5):
ignore git-rebase--interactive
getenv/setenv: use constants if available
git-init: set core.worktree if GIT_WORK_TREE is specified
git-clone: split up long &&-command-chain and use a function for
cleanup
make git-clone GIT_WORK_TREE aware
Michael Hendricks (2):
git-send-email: allow an email alias for --from
gitweb: configurable width for the projects list Description column
Miklos Vajna (2):
gitweb: prefer git_get_project_owner() over get_file_owner()
gitweb: new cgi parameter: opt
Nanako Shiraishi (2):
Add git-stash script
Document git-stash
Nicolas Pitre (4):
apply delta depth bias to already deltified objects
script to display a distribution of longest common hash prefixes
reduce git-pack-objects memory usage a little more
Pack-objects: properly initialize the depth value
Paul Mackerras (6):
gitk: Fix the find and highlight functions
gitk: Fix bug in the anc_or_desc routine
gitk: Remove the unused stopfindproc function
gitk: Fix bug causing "can't read commitrow(0,n)" error
gitk: Use git log and add support for --left-right
gitk: Improve handling of -- and ambiguous arguments
René Scharfe (1):
diff-lib.c: don't strdup twice
Sean Estabrooks (1):
Alter git-checkout reflog message to include "from" branch
Shawn O. Pearce (36):
git-gui: Start blame windows as tall as possible
git-gui: Correct resizing of remote branch delete dialog
git-gui: Honor rerere.enabled configuration option
git-gui: New Git version check support routine
git-gui: Teach class system to support [$this cmd] syntax
git-gui: Abstract the revision picker into a mega widget
git-gui: Refactor the delete branch dialog to use class system
git-gui: Optimize for newstyle refs/remotes layout
git-gui: Maintain remote and source ref for tracking branches
git-gui: Allow users to match remote branch names locally
git-gui: Fast-forward existing branch in branch create dialog
git-gui: Enhance choose_rev to handle hundreds of branches
git-gui: Sort tags descending by tagger date
git-gui: Option to default new branches to match tracking branches
git-gui: Automatically refresh tracking branches when needed
git-gui: Better handling of detached HEAD
git-gui: Refactor our ui_status_value update technique
git-gui: Refactor branch switch to support detached head
git-gui: Unabbreviate commit SHA-1s prior to display
git-gui: Default selection to first matching ref
git-gui: Allow double-click in checkout dialog to start checkout
git-gui: Extract blame viewer status bar into mega-widget
git-gui: Change the main window progress bar to use status_bar
git-gui: Show a progress meter for checking out files
git-gui: Always use absolute path to all git executables
git-gui: Correct gitk installation location
git-gui: Assume unfound commands are known by git wrapper
git-gui: Treat `git version` as `git --version`
git-gui: Perform our own magic shbang detection on Windows
git-gui: Teach console widget to use git_read
git-gui: Improve the Windows and Mac OS X shortcut creators
git-gui: Paper bag fix for Cygwin shortcut creation
git-gui: Use sh.exe in Cygwin shortcuts
git-gui: Include a space in Cygwin shortcut command lines
Support wholesale directory renames in fast-import
git-gui: Change prior tree SHA-1 verification to use git_read
Steffen Prohaska (1):
filter-branch: added missing warn function
Steven Walter (1):
Documentation for git-log --follow
Sven Verdoolaege (2):
git-submodule: provide easy way of adding new submodules
git-clone: fetch possibly detached HEAD over dumb http
Uwe Kleine-König (2):
stash: end commit log with a newline
repack: don't report "Nothing new to pack." if -q is given
^ permalink raw reply
* Re: pull-fetch-param.txt
From: Gerrit Pape @ 2007-07-13 5:53 UTC (permalink / raw)
To: Junio C Hamano, git
In-Reply-To: <7vvecps2rz.fsf@assigned-by-dhcp.cox.net>
On Thu, Jul 12, 2007 at 02:58:08PM -0700, Junio C Hamano wrote:
> Gerrit Pape <pape@smarden.org> writes:
> > Hi, this still is a problem, at least on Debian/unstable; with asciidoc
> > 8.2.1, the git-push(1) and git-fetch(1) man pages have this 'broken'
> > refspec description[0].
>
> Quick question. Is the build done with "make
> ASCIIDOC8=YesPlease"?
No, must have missed that. This solves the first issue with the refspec
in git-push(1), git-fetch(1), but not the second one with callout lists.
Thanks, Gerrit.
^ permalink raw reply
* Re: [PATCH] make git-send-email.perl handle email addresses with no names when Email::Valid is present
From: Junio C Hamano @ 2007-07-13 5:47 UTC (permalink / raw)
To: Greg KH; +Cc: git
In-Reply-To: <20070713041749.GA28824@kroah.com>
Greg KH <greg@kroah.com> writes:
> When using git-send-email.perl on a changeset that has:
> Cc: <stable@kernel.org>
> in the body of the description, and the Email::Valid perl module is
> installed on the system, the email address will be deemed "invalid" for
> some reason (Email::Valid isn't smart enough to handle this?) and
> complain and not send the address the email.
That appears to be the case.
bad foo
bad <foo@bar.baz>
ok foo@bar.baz
ok Foo <foo@bar.baz>
> Anyway, this tiny patch fixes this problem for me. Note, my perl-foo is
> quite week, so this could probably be easily done in one line for those
> with better reg-ex skills.
> --- a/git-send-email.perl
> +++ b/git-send-email.perl
> @@ -410,6 +410,9 @@ sub extract_valid_address {
> return $address if ($address =~ /^($local_part_regexp)$/);
>
> if ($have_email_valid) {
> + if ($address =~ s/^<//) {
> + $address =~ s/>$//;
> + }
> return scalar Email::Valid->address($address);
> } else {
I'd probably do:
if ($have_email_valid) {
$address =~ s/^<(.*)>$/$1/;
return scalar Email::Valid->address($address);
} else {
instead, but they are moral equivalents.
Thanks for a fix.
^ permalink raw reply
* Re: sharing between local "work" and "nightly build" git repos
From: Alex Riesen @ 2007-07-13 5:11 UTC (permalink / raw)
To: David Frech; +Cc: Junio C Hamano, git
In-Reply-To: <7154c5c60707121733r6584a407r8d60d5890b9c89e2@mail.gmail.com>
David Frech, Fri, Jul 13, 2007 02:33:19 +0200:
> On 7/12/07, David Frech <nimblemachines@gmail.com> wrote:
> >On 7/12/07, Junio C Hamano <gitster@pobox.com> wrote:
> >> Then a nightly update would go like this:
> >>
> >> $ cd ~/nightly-git
> >> $ git pull origin next
> >> $ make clean
> >> $ make test || barf
>
> One more thing: would it make sense to do "make -k test" so that *all*
> failures (if >1) show up?
Yes, definitely. You'll find you will see failures which you know are
already fixed, just didn't reach the nightly-build yet.
BTW, do _not_ send the errors to this mailing list. It just too easy
gets out of control. And consider saving the build log somewhere after
doing a _completely_ clean build, i.e. like this:
#!/bin/bash
cd ~/nightly-git || exit
echo 'Subject: Nightly build git next ' $(date) >/tmp/mail.msg
echo >>/tmp/mail.msg
{
rm -rf * # it does not remove .git
git reset --hard
git pull origin next || exit 1
make || exit 1
make -k test|| exit 1
} &>> /tmp/mail.msg
$ nightly-build || sendmail local-user@localhost < /tmp/mail.msg
It is simplier to find out what went wrong if you know what state did
you have before doing the test. And the state after rm -rf * is very
simple to predict.
^ permalink raw reply
* Re: Lump commit HOWTO?
From: Alex Riesen @ 2007-07-13 4:54 UTC (permalink / raw)
To: Josh Boyer; +Cc: Git Mailing List
In-Reply-To: <625fc13d0707121821l70e2d6aaw555c79b5d700585f@mail.gmail.com>
Josh Boyer, Fri, Jul 13, 2007 03:21:17 +0200:
> Hi All,
>
> I have a specific workflow in mind that I'm not entirely sure how to
> accomplish with git. What I'd like to do is track a project in a
> local branch, and do commits of my own there as well. Then when I'm
> ready to submit the work, I want to take all the incremental commits
> and lump them into a single new commit and push that out as a patch or
> into a branch for people to pull from.
See git merge --squash. It is exactly that.
Also git-rebase --interactive and git cherry-pick -n can help you to
get the same.
^ permalink raw reply
* [PATCH] make git-send-email.perl handle email addresses with no names when Email::Valid is present
From: Greg KH @ 2007-07-13 4:17 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
When using git-send-email.perl on a changeset that has:
Cc: <stable@kernel.org>
in the body of the description, and the Email::Valid perl module is
installed on the system, the email address will be deemed "invalid" for
some reason (Email::Valid isn't smart enough to handle this?) and
complain and not send the address the email.
Anyway, this tiny patch fixes this problem for me. Note, my perl-foo is
quite week, so this could probably be easily done in one line for those
with better reg-ex skills.
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -410,6 +410,9 @@ sub extract_valid_address {
return $address if ($address =~ /^($local_part_regexp)$/);
if ($have_email_valid) {
+ if ($address =~ s/^<//) {
+ $address =~ s/>$//;
+ }
return scalar Email::Valid->address($address);
} else {
# less robust/correct than the monster regexp in Email::Valid,
^ permalink raw reply
* Re: mtimes of working files
From: Theodore Tso @ 2007-07-13 0:37 UTC (permalink / raw)
To: David Woodhouse; +Cc: Andy Parkins, git, Jan Hudec, Johannes Schindelin
In-Reply-To: <1184261246.31598.139.camel@pmac.infradead.org>
On Thu, Jul 12, 2007 at 06:27:26PM +0100, David Woodhouse wrote:
> On Thu, 2007-07-12 at 08:57 +0100, Andy Parkins wrote:
> > The only time you get an unnecessary rebuild is if you do
> >
> > git checkout branch1
> > git checkout branch2
> > git checkout branch1
> >
> > But we can hardly expect git to be responsible for that.
>
> Indeed. That's a user error. Git makes it cheap and easy to have
> separate _trees_. Just use them -- branches are just another mental
> hangover from CVS which we should try to cure ourselves of :)
Personally, I just use branches a huge amount, and I will often do
git checkout branch1
<hack hack hack>
git commit --amend
<build, test>
git checkout branch2
<hack hack hack>
git commit
<build, test>
git checkout branch1
<build>
Rebuilding isn't a problem, because I use ccache. :-)
I could use separate trees, I suppose, but then I have to keep
multiple copies of the .o files around in all of those separate trees,
and it's cheaper and more efficient to keep them in the ccache cache
IMHO. And with 7200 RPM laptop drives and dual core processors
combined with ccache, I hardly notice the rebuild/relink time.
- Ted
^ 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