* [RFCv4 3/3] gitweb: link to patch(es) view from commit and log views
From: Giuseppe Bilotta @ 2008-12-06 15:02 UTC (permalink / raw)
To: git; +Cc: Jakub Narebski, Petr Baudis, Junio C Hamano, Giuseppe Bilotta
In-Reply-To: <1228575755-13432-3-git-send-email-giuseppe.bilotta@gmail.com>
We link to patch view in commit and commitdiff view, and to patches view
in log and shortlog view.
In (short)log view, the link is only offered when the number of commits
shown is no more than the allowed maximum number of patches.
Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
---
gitweb/gitweb.perl | 30 ++++++++++++++++++++++++++++--
1 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index dfc7128..8198875 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -5019,6 +5019,15 @@ sub git_log {
my $paging_nav = format_paging_nav('log', $hash, $head, $page, $#commitlist >= 100);
+ my $patch_max = gitweb_check_feature('patches');
+ if ($patch_max) {
+ if ($patch_max < 0 || @commitlist <= $patch_max) {
+ $paging_nav .= " ⋅ " .
+ $cgi->a({-href => href(action=>"patches", -replay=>1)},
+ @commitlist > 1 ? "patchset" : "patch");
+ }
+ }
+
git_header_html();
git_print_page_nav('log','', $hash,undef,undef, $paging_nav);
@@ -5098,6 +5107,11 @@ sub git_commit {
} @$parents ) .
')';
}
+ if (gitweb_check_feature('patches')) {
+ $formats_nav .= " | " .
+ $cgi->a({-href => href(action=>"patch", -replay=>1)},
+ "patch");
+ }
if (!defined $parent) {
$parent = "--root";
@@ -5413,9 +5427,8 @@ sub git_commitdiff {
# if only a single commit is passed?
my $single_patch = shift && 1;
- my $patch_max;
+ my $patch_max = gitweb_check_feature('patches');
if ($format eq 'patch') {
- $patch_max = gitweb_check_feature('patches');
die_error(403, "Patch view not allowed") unless $patch_max;
}
@@ -5433,6 +5446,11 @@ sub git_commitdiff {
$formats_nav =
$cgi->a({-href => href(action=>"commitdiff_plain", -replay=>1)},
"raw");
+ if ($patch_max) {
+ $formats_nav .= " | " .
+ $cgi->a({-href => href(action=>"patch", -replay=>1)},
+ "patch");
+ }
if (defined $hash_parent &&
$hash_parent ne '-c' && $hash_parent ne '--cc') {
@@ -5989,6 +6007,14 @@ sub git_shortlog {
$cgi->a({-href => href(-replay=>1, page=>$page+1),
-accesskey => "n", -title => "Alt-n"}, "next");
}
+ my $patch_max = gitweb_check_feature('patches');
+ if ($patch_max) {
+ if ($patch_max < 0 || @commitlist <= $patch_max) {
+ $paging_nav .= " ⋅ " .
+ $cgi->a({-href => href(action=>"patches", -replay=>1)},
+ @commitlist > 1 ? "patchset" : "patch");
+ }
+ }
git_header_html();
git_print_page_nav('shortlog','', $hash,$hash,$hash, $paging_nav);
--
1.5.6.5
^ permalink raw reply related
* Re: [RFCv3 2/2] gitweb: links to patch action in commitdiff and shortlog view
From: Jakub Narebski @ 2008-12-06 15:25 UTC (permalink / raw)
To: Giuseppe Bilotta; +Cc: git, Petr Baudis, Junio C Hamano
In-Reply-To: <cb7bb73a0812060525k65a7f549l2cce5f0dae9fc76c@mail.gmail.com>
Dnia sobota 6. grudnia 2008 14:25, Giuseppe Bilotta napisał:
> On Sat, Dec 6, 2008 at 1:53 AM, Jakub Narebski <jnareb@gmail.com> wrote:
>> On Wed, 3 Dec 2008, Giuseppe Bilotta wrote:
>>
>>> In shortlog view, a link to the patchset is only offered when the number
>>> of commits shown is less than the allowed maximum number of patches.
>>>
>>> Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
>>> + if (gitweb_check_feature('patches')) {
>>> + $formats_nav .= " | " .
>>> + $cgi->a({-href => href(action=>"patch", -replay=>1)},
>>> + "patch");
>>> + }
>>>
>>> if (!defined $parent) {
>>> $parent = "--root";
>>> @@ -5415,6 +5420,11 @@ sub git_commitdiff {
>>> $formats_nav =
>>> $cgi->a({-href => href(action=>"commitdiff_plain", -replay=>1)},
>>> "raw");
>>> + if ($patch_max) {
>>> + $formats_nav .= " | " .
>>> + $cgi->a({-href => href(action=>"patch", -replay=>1)},
>>> + "patch");
>>> + }
>>>
>>> if (defined $hash_parent &&
>>> $hash_parent ne '-c' && $hash_parent ne '--cc') {
>>
>> In the above two hunks 'patch' view functions as "git show --pretty=email"
>> text/plain equivalent, but this duplicates a bit 'commitdiff_plain'
>> functionality. Well, 'commitdiff_plain' has currently some errors,
>> but...
>
> All things considered, for single commit view there is (modulo bugs)
> no factual difference between plain diff and patch view.
>
> Although we could merge them, I'm thinking that the plain diff view
> has somewhat too much information in it. For backwards compatibility
> it's probably not wise to change it, but we should consider it for the
> next major version, honestly.
I'm just wondering if we should add 'patch' link to 'commit' and
'commitdiff' views (as alternate view) at all...
>>> @@ -5949,6 +5959,14 @@ sub git_shortlog {
>>> $cgi->a({-href => href(-replay=>1, page=>$page+1),
>>> -accesskey => "n", -title => "Alt-n"}, "next");
>>> }
>>> + my $patch_max = gitweb_check_feature('patches');
>>> + if ($patch_max) {
>>> + if ($patch_max < 0 || @commitlist <= $patch_max) {
>>> + $paging_nav .= " ⋅ " .
>>> + $cgi->a({-href => href(action=>"patch", -replay=>1)},
>>> + @commitlist> 1 ? "patchset" : "patch");
>>> + }
>>> + }
>>
>> Here 'patch' view functions as "git format-patch", able to be downloaded
>> and fed to git-am. Perhaps the action should also be named 'patches'
>> here?; it could lead to the same function.
>
> I had half an idea to do so. 'patches' or 'patchset'?
Hmmm... I think 'patches'.
>> By the way, there is subtle bug in above link. If shortlog view is less
>> than $patch_max commits long, but it is because the history for a given
>> branch (or starting from given commit) is so short, and not because
>> there is cutoff $hash_parent set, the 'patchset' view wouldn't display
>> plain text equivalent view, but only patch for top commit.
>
> Ah, good point.
>
> Hm, not easy to solve. One way could be to add the hash_parent
> manually. Or we could make the 'patches' view different from the
> 'patch' view in the way it handles refspecs without ranges. I'm
> leaning towards the latter. What's your opinion?
I think simplest solution would be to add $hash_parent if it is not
set from the last commit, i.e. $commitlist[-1]{'id'}
>> I assume that the link is only for 'shortlog' view, and not also for
>> 'log' and 'history' views because 'shortlog' is the only log-like view
>> which support $hash_parent?
>
> The actual reason is that I never use log nor history view, but since
> they don't support hash_parent because of this (I was the one who sent
> the patch to support hash_parent in shortlog view) you could
> paralogistically say that's the reason ;-)
>
> I'm not sure about history view, but for log view I'm considering
> addiong also a 'patch' link next to each commit. I'll think about it.
Well, you can add it only for 'shortlog' view, and when the code for
all log-like views would get consolidated, you will get link to 'patches'
view automatically :-)
--
Jakub Narebski
Poland
^ permalink raw reply
* [PATCH (GIT-GUI FIX)] git-gui: Fix handling of relative paths in blame.
From: Alexander Gavrilov @ 2008-12-06 17:21 UTC (permalink / raw)
To: Git Mailing List; +Cc: Shawn O. Pearce, Paul Mackerras
Currently using '..' or '.' in the file path for gui blame
causes it to break, because the path is passed inside the
SHA:PATH spec to cat-file, which apparently does not understand
such items. As a result, cat-file returns nothing, and the
viewer crashes because of an "index out of range" error.
This commit adds a simple function that normalizes such paths.
I choose not to use [file normalize], because it uses some data
from the file system, e.g. dereferences symlinks, and creates
an absolute path, while blame may be used to inspect historical
information that bears no relation to the current filesystem state.
Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
---
On Saturday 06 December 2008 13:56:45 Paul Mackerras wrote:
> I have checked in a fix into my gitk.git repository at
> git://git.kernel.org/pub/scm/gitk/gitk.git. However, there seems to
> be a bug in git gui blame; it gives a "list index out of range" error
> sometimes.
>
> Shawn, to see an example of the error, get a current kernel tree and
> do:
>
> $ cd arch/powerpc
> $ git gui blame --line=1183 2c5e76158fcea6e3b9536a74efa7b5e2e846d374 \
> ../../net/sunrpc/svcsock.c
git-gui.sh | 18 ++++++++++++++++--
1 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/git-gui.sh b/git-gui.sh
index 8a4b42d..65dacf9 100755
--- a/git-gui.sh
+++ b/git-gui.sh
@@ -2630,6 +2630,20 @@ proc usage {} {
exit 1
}
+proc normalize_relpath {path} {
+ set elements {}
+ foreach item [file split $path] {
+ if {$item eq {.}} continue
+ if {$item eq {..} && [llength $elements] > 0
+ && [lindex $elements end] ne {..}} {
+ set elements [lrange $elements 0 end-1]
+ continue
+ }
+ lappend elements $item
+ }
+ return [eval file join $elements]
+}
+
# -- Not a normal commit type invocation? Do that instead!
#
switch -- $subcommand {
@@ -2648,7 +2662,7 @@ blame {
foreach a $argv {
if {$is_path || [file exists $_prefix$a]} {
if {$path ne {}} usage
- set path $_prefix$a
+ set path [normalize_relpath $_prefix$a]
break
} elseif {$a eq {--}} {
if {$path ne {}} {
@@ -2671,7 +2685,7 @@ blame {
unset is_path
if {$head ne {} && $path eq {}} {
- set path $_prefix$head
+ set path [normalize_relpath $_prefix$head]
set head {}
}
--
1.6.0.4.30.gf4240
^ permalink raw reply related
* [PATCH (GIT-GUI FIX)] git-gui: Fix commit encoding handling.
From: Alexander Gavrilov @ 2008-12-06 17:24 UTC (permalink / raw)
To: Git Mailing List; +Cc: Shawn O. Pearce
Commits without an encoding header are supposed to
be encoded in utf8. While this apparently hasn't always
been the case, currently it is the active convention, so
it is better to follow it; otherwise people who have to
use commitEncoding on their machines are unable to read
utf-8 commits made by others.
I also think that it is preferrable to display the warning
about an unsupported value of commitEncoding more prominently,
because this condition may lead to surprising behavior and,
eventually, to loss of data.
Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
---
lib/blame.tcl | 5 ++---
lib/commit.tcl | 7 +++----
2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/lib/blame.tcl b/lib/blame.tcl
index c1cd7f3..1f3b08f 100644
--- a/lib/blame.tcl
+++ b/lib/blame.tcl
@@ -940,9 +940,8 @@ method _showcommit {cur_w lno} {
catch {
set fd [git_read cat-file commit $cmit]
fconfigure $fd -encoding binary -translation lf
- if {[catch {set enc $repo_config(i18n.commitencoding)}]} {
- set enc utf-8
- }
+ # By default commits are assumed to be in utf-8
+ set enc utf-8
while {[gets $fd line] > 0} {
if {[string match {encoding *} $line]} {
set enc [string tolower [string range $line 9 end]]
diff --git a/lib/commit.tcl b/lib/commit.tcl
index 3345149..9cc8410 100644
--- a/lib/commit.tcl
+++ b/lib/commit.tcl
@@ -27,9 +27,8 @@ You are currently in the middle of a merge that has not been fully completed. Y
if {[catch {
set fd [git_read cat-file commit $curHEAD]
fconfigure $fd -encoding binary -translation lf
- if {[catch {set enc $repo_config(i18n.commitencoding)}]} {
- set enc utf-8
- }
+ # By default commits are assumed to be in utf-8
+ set enc utf-8
while {[gets $fd line] > 0} {
if {[string match {parent *} $line]} {
lappend parents [string range $line 7 end]
@@ -208,7 +207,7 @@ A good commit message has the following format:
if {$use_enc ne {}} {
fconfigure $msg_wt -encoding $use_enc
} else {
- puts stderr [mc "warning: Tcl does not support encoding '%s'." $enc]
+ error_popup [mc "warning: Tcl does not support encoding '%s'." $enc]
fconfigure $msg_wt -encoding utf-8
}
puts $msg_wt $msg
--
1.6.0.4.30.gf4240
^ permalink raw reply related
* Re: What's cooking in git.git (Nov 2008, #06; Wed, 26)
From: Nguyen Thai Ngoc Duy @ 2008-12-06 17:26 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: Junio C Hamano, Shawn O. Pearce, Johannes Schindelin, git
In-Reply-To: <alpine.LNX.1.00.0811301509070.19665@iabervon.org>
On 12/1/08, Daniel Barkalow <barkalow@iabervon.org> wrote:
> On Sun, 30 Nov 2008, Nguyen Thai Ngoc Duy wrote:
>
> > On 11/29/08, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
> > > On 11/29/08, Daniel Barkalow <barkalow@iabervon.org> wrote:
> > > > If there's any need for this to be distinguished from "assume unchanged",
> > > > I think it should be used with, not instead of, the CE_VALID bit; and it
> > > > could probably use some bit in the stat info section, since we don't need
> > > > stat info if we know by assumption that the entry is valid.
> > >
> > >
> > > Interesting. I'll think more about this.
> > >
> >
> > As I said, CE_VALID implies all files are present.
>
>
> My first question is whether this actually should be true. Going back to
> the message for 5f73076c1a9b4b8dc94f77eac98eb558d25e33c0, it sounds like
> the CE_VALID code is designed to be safe and sort of correct even if the
> files are not actually unchanged; I don't think it would be out-of-spec
> for CE_VALID to (1) always produce output as if the working tree contained
> what the index contains, while (2) refusing to make any changes to working
> tree files that do not actually match the index. As it is now, (2) is
> explicitly true, but (1) is left vague-- commands may fail entirely or
> produce different output if CE_VALID is set in the index for a file that
> has changes in the working tree, but not in any particular way.
(1) is not always true. For example diff machinary may examine
worktree files regardless CE_VALID, which is updated for
CE_NO_CHECKOUT in d9f8fca (Prevent diff machinery from examining
worktree outside sparse checkout)
> Now, it might be necessary for CE_NO_CHECKOUT to differ from CE_VALID in
> some ways in (2): if a file is CE_NO_CHECKOUT and absent, code which would
> modify it could probably just report sucess, while CE_VALID on a file
> with changes should probably report failure. On the other hand, that could
> just as easily be at the porcelain layer, with the porcelain instructing
> the plumbing to change the index without changing the working tree for
> those files outside the sparse checkout, and the plumbing would report
> errors if the porcelain did not do this.
That's right. Much of work in the last half of the series is on
porcelain layer. "git grep" fix is the only porcelain that gets fixed
in this series.
> > I could make CE_NO_CHECKOUT to be used with CE_VALID, but I would need
> > to check all CE_VALID code path to make sure the behaviour remains if
> > CE_NO_CHECKOUT is absent. It's just more intrusive.
>
>
> I would expect all code that has a CE_VALID path to do something actually
> wrong if it took the non-CE_VALID code path on CE_NO_CHECKOUT and there
> was no CE_NO_CHECKOUT code path. So I'd expect that your patch is
> insufficient to the extent that CE_NO_CHECKOUT doesn't imply CE_VALID
> (since there is very little in the way of CE_NO_CHECKOUT-specific
> handling in your patch).
I read the code again. CE_NO_CHECKOUT should follow CE_VALID code path
(which was extended to CE_VALID_MASK to have both flags). That means
CE_NO_CHECKOUT is treated as same as CE_VALID. The only difference
here is CE_VALID is set/unset by "git update-index --really-refresh"
and core.ingorestat while CE_NO_CHECKOUT has its own way to set/unset.
There is not much work for CE_NO_CHECKOUT on plumbling level except
some fixes. The last half of the series, for porcelain level, you will
see more.
> The only case I can think of where NO_CHECKOUT is more like !VALID than
> VALID is with respect to whether we can report the content in the index by
> looking in the filesystem instead of in the database; I don't think this
> is an intentional optimization anywhere, and I think it would be a likely
> source of bugs if it were (e.g., it would have to know about files which
> are up-to-date with respect to stat info, but which have been "smudged" on
> disk and therefore don't match byte-for-byte with the database).
There is worktree file reuse in diff code somewhere IIRC. Yes, this
should be checked.
> Actually,
> it might be most accurate to treat --no-checkout as being CE_VALID with a
> smudge filter of "rm". If the combination of CE_VALID and on-disk
> conversion works (which is likely to be the common pattern for Windows
> users, who need autocrlf and have a slow lstat(), and is therefore
> maintained), surely this combination would work for CE_NO_CHECKOUT.
Very interesting.
> > I have nothing against storing CE_NO_CHECKOUT in stat info except that
> > it seems inappropriate/hidden place to do. ce_flags is more obvious
> > choice. I haven't looked closely to stat info code in read-cache.c
> > though.
>
>
> It should be pretty clean to check CE_VALID when reading an entry from
> disk and remap bits from it to additional flags in memory. I wouldn't
> suggest overlaying them in memory, but there's also no shortage of space
> for flags in memory.
I see. Still I prefer the current approach, less headache to decide
what bit to take from stat info ;-)
--
Duy
^ permalink raw reply
* Re: What's cooking in git.git (Nov 2008, #06; Wed, 26)
From: Daniel Barkalow @ 2008-12-06 18:39 UTC (permalink / raw)
To: Nguyen Thai Ngoc Duy
Cc: Junio C Hamano, Shawn O. Pearce, Johannes Schindelin, git
In-Reply-To: <fcaeb9bf0812060926r2ee443bfl3adb3f2d1129e5b8@mail.gmail.com>
On Sun, 7 Dec 2008, Nguyen Thai Ngoc Duy wrote:
> On 12/1/08, Daniel Barkalow <barkalow@iabervon.org> wrote:
> > On Sun, 30 Nov 2008, Nguyen Thai Ngoc Duy wrote:
> >
> > > On 11/29/08, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
> > > > On 11/29/08, Daniel Barkalow <barkalow@iabervon.org> wrote:
> > > > > If there's any need for this to be distinguished from "assume unchanged",
> > > > > I think it should be used with, not instead of, the CE_VALID bit; and it
> > > > > could probably use some bit in the stat info section, since we don't need
> > > > > stat info if we know by assumption that the entry is valid.
> > > >
> > > >
> > > > Interesting. I'll think more about this.
> > > >
> > >
> > > As I said, CE_VALID implies all files are present.
> >
> >
> > My first question is whether this actually should be true. Going back to
> > the message for 5f73076c1a9b4b8dc94f77eac98eb558d25e33c0, it sounds like
> > the CE_VALID code is designed to be safe and sort of correct even if the
> > files are not actually unchanged; I don't think it would be out-of-spec
> > for CE_VALID to (1) always produce output as if the working tree contained
> > what the index contains, while (2) refusing to make any changes to working
> > tree files that do not actually match the index. As it is now, (2) is
> > explicitly true, but (1) is left vague-- commands may fail entirely or
> > produce different output if CE_VALID is set in the index for a file that
> > has changes in the working tree, but not in any particular way.
>
> (1) is not always true. For example diff machinary may examine
> worktree files regardless CE_VALID, which is updated for
> CE_NO_CHECKOUT in d9f8fca (Prevent diff machinery from examining
> worktree outside sparse checkout)
I know (1) is not always true in the current implementation. What I'm
getting at is to ask (a) whether our documented behavior ever violates (1)
and (b) whether enforcing (1) would be an improvement.
I suspect that enforcing (1) would be less surprising to users in the
situation where the assumption is false that worktree files match the
index when CE_VALID is set. As it is, the diff machinery does surprising
things in this situation, and I think we just say "Nasal Monkey Territory"
(that is, we tell the user, "if you don't want git to do surprising
things, don't get into this situation"). If that is the case, we should be
fine changing it to match your CE_NO_CHECKOUT behavior, and it wouldn't be
worse for CE_VALID and might be better.
> > Now, it might be necessary for CE_NO_CHECKOUT to differ from CE_VALID in
> > some ways in (2): if a file is CE_NO_CHECKOUT and absent, code which would
> > modify it could probably just report sucess, while CE_VALID on a file
> > with changes should probably report failure. On the other hand, that could
> > just as easily be at the porcelain layer, with the porcelain instructing
> > the plumbing to change the index without changing the working tree for
> > those files outside the sparse checkout, and the plumbing would report
> > errors if the porcelain did not do this.
>
> That's right. Much of work in the last half of the series is on
> porcelain layer. "git grep" fix is the only porcelain that gets fixed
> in this series.
I haven't gotten to reading the last half yet, so I'll avoid taking a
specific position on how it should work, and just make unsupported
suggestions.
> > > I could make CE_NO_CHECKOUT to be used with CE_VALID, but I would need
> > > to check all CE_VALID code path to make sure the behaviour remains if
> > > CE_NO_CHECKOUT is absent. It's just more intrusive.
> >
> >
> > I would expect all code that has a CE_VALID path to do something actually
> > wrong if it took the non-CE_VALID code path on CE_NO_CHECKOUT and there
> > was no CE_NO_CHECKOUT code path. So I'd expect that your patch is
> > insufficient to the extent that CE_NO_CHECKOUT doesn't imply CE_VALID
> > (since there is very little in the way of CE_NO_CHECKOUT-specific
> > handling in your patch).
>
> I read the code again. CE_NO_CHECKOUT should follow CE_VALID code path
> (which was extended to CE_VALID_MASK to have both flags). That means
> CE_NO_CHECKOUT is treated as same as CE_VALID. The only difference
> here is CE_VALID is set/unset by "git update-index --really-refresh"
> and core.ingorestat while CE_NO_CHECKOUT has its own way to set/unset.
I think, then, that it would be cleaner to have CE_VALID instead of
CE_VALID_MASK, and have the things that care test CE_NO_CHECKOUT or
!CE_NO_CHECKOUT. This wouldn't be all that different, except that it would
mean that distinguishing them appears as a special case, which in turn
makes it easier to question whether they should differ.
> There is not much work for CE_NO_CHECKOUT on plumbling level except
> some fixes. The last half of the series, for porcelain level, you will
> see more.
For the porcelain level, do we need the difference to be in the index? If
the porcelain knows the sparse checkout area and can instruct the plumbing
appropriately, the information shouldn't need to be stored in the index
unless it's ever important to remember whether an entry is CE_VALID due to
having been outside the checkout when the index was written, even though
the checkout area now includes it. I don't have a good intuition as to
what ought to happen if the user manually changes what's specified for
checkout without actually updating the index and working tree.
> > The only case I can think of where NO_CHECKOUT is more like !VALID than
> > VALID is with respect to whether we can report the content in the index by
> > looking in the filesystem instead of in the database; I don't think this
> > is an intentional optimization anywhere, and I think it would be a likely
> > source of bugs if it were (e.g., it would have to know about files which
> > are up-to-date with respect to stat info, but which have been "smudged" on
> > disk and therefore don't match byte-for-byte with the database).
>
> There is worktree file reuse in diff code somewhere IIRC. Yes, this
> should be checked.
>
> > Actually,
> > it might be most accurate to treat --no-checkout as being CE_VALID with a
> > smudge filter of "rm". If the combination of CE_VALID and on-disk
> > conversion works (which is likely to be the common pattern for Windows
> > users, who need autocrlf and have a slow lstat(), and is therefore
> > maintained), surely this combination would work for CE_NO_CHECKOUT.
>
> Very interesting.
>
> > > I have nothing against storing CE_NO_CHECKOUT in stat info except that
> > > it seems inappropriate/hidden place to do. ce_flags is more obvious
> > > choice. I haven't looked closely to stat info code in read-cache.c
> > > though.
> >
> >
> > It should be pretty clean to check CE_VALID when reading an entry from
> > disk and remap bits from it to additional flags in memory. I wouldn't
> > suggest overlaying them in memory, but there's also no shortage of space
> > for flags in memory.
>
> I see. Still I prefer the current approach, less headache to decide
> what bit to take from stat info ;-)
True. But it would be even easier if it didn't have to be marked in the
index at all.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: ETA for release of gjit 0.4?
From: Robin Rosenberg @ 2008-12-06 18:47 UTC (permalink / raw)
To: Farrukh Najmi; +Cc: git, Shawn O. Pearce
In-Reply-To: <49393BFC.6010606@wellfleetsoftware.com>
fredag 05 december 2008 15:34:36 skrev Farrukh Najmi:
>
> Dear colleagues,
>
> I am using jgit in my maven project. Since current version is a SNAPSHOT
> (0.4-SNAPSHOT) I cannot release my project with a SNAPSHOT dependency
> (maven does not allow it). WHat is the time line for releasing version
> 0.4 of jgit so I can plan accordingly.
> Thanks for any info.
What? Plan? :)
You could name the version something else like 0.3.1.42b27c
It was a long time since we labeled anything. Shawn, how about merging
my recent close-file-patches, reverting 3ffa47d9294086fbd1cdeb9b1564f922a23e3c6f
and e7307f14c531d52cf231c39d844841c4adaf5e5a and then just call i 0.4 ?
-- robin
# from my pu branch, the latest Tentative build in the update site. Works quite well for
me. Refactoring and
$ git log --pretty=oneline origin/master..pu
2aafc054446f9b3aecdc01687a6949e4c54be6eb Revert "Rewrite GitMoveDeleteHook to use DirCacheBuilder"
439277860e1e315b7f0cd339b2435cc8311956c1 Revert "Teach GitMoveDeleteHook how to move a folder recursively"
abc44bc6efa47c4c6e3c23f85fe9de9cd8460224 Improve closing of files in error situations.
22e2808ac2915446ed81115b663c684341ce6bdd Close a forgotten reference to the HEAD ref.
^ permalink raw reply
* Re: ETA for release of gjit 0.4?
From: Farrukh Najmi @ 2008-12-06 18:57 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git, Shawn O. Pearce
In-Reply-To: <200812061947.27905.robin.rosenberg.lists@dewire.com>
Robin Rosenberg wrote:
> fredag 05 december 2008 15:34:36 skrev Farrukh Najmi:
>
>> Dear colleagues,
>>
>> I am using jgit in my maven project. Since current version is a SNAPSHOT
>> (0.4-SNAPSHOT) I cannot release my project with a SNAPSHOT dependency
>> (maven does not allow it). WHat is the time line for releasing version
>> 0.4 of jgit so I can plan accordingly.
>> Thanks for any info.
>>
>
> What? Plan? :)
>
:-)
> You could name the version something else like 0.3.1.42b27c
>
>
I could but maven (and good project release) practices are that a
project's release version should be managed by the project and not
consumers of the project.
BTW, If there is interest in maveninzing the project I can offer to
contribute that change to the project. Just let me know if that is
something the project wishes to do.
Maven offers many benefits to projects as described in links below. It
takes a little getting used to for project dev team but its not bad. It
does not impact consumers of projects negatively in any way.
Background blog:
<http://farrukhnajmi.blogspot.com/2008/02/why-maven-rocks-in-beginning-there-was.html>
More useful link:
<http://ebxmlrr.wiki.sourceforge.net/whymaven>
Thanks for a great project.
> It was a long time since we labeled anything. Shawn, how about merging
> my recent close-file-patches, reverting 3ffa47d9294086fbd1cdeb9b1564f922a23e3c6f
> and e7307f14c531d52cf231c39d844841c4adaf5e5a and then just call i 0.4 ?
>
> -- robin
>
> # from my pu branch, the latest Tentative build in the update site. Works quite well for
> me. Refactoring and
> $ git log --pretty=oneline origin/master..pu
> 2aafc054446f9b3aecdc01687a6949e4c54be6eb Revert "Rewrite GitMoveDeleteHook to use DirCacheBuilder"
> 439277860e1e315b7f0cd339b2435cc8311956c1 Revert "Teach GitMoveDeleteHook how to move a folder recursively"
> abc44bc6efa47c4c6e3c23f85fe9de9cd8460224 Improve closing of files in error situations.
> 22e2808ac2915446ed81115b663c684341ce6bdd Close a forgotten reference to the HEAD ref.
>
>
--
Regards,
Farrukh Najmi
Web: http://www.wellfleetsoftware.com
^ permalink raw reply
* Re: git tag -s: TAG_EDITMSG should not be deleted upon failures
From: Jeff King @ 2008-12-06 19:40 UTC (permalink / raw)
To: Christian Jaeger; +Cc: Junio C Hamano, Git Mailing List
In-Reply-To: <4936AB74.3090901@jaeger.mine.nu>
tag: delete TAG_EDITMSG only on successful tag
The user may put some effort into writing an annotated tag
message. When the tagging process later fails (which can
happen fairly easily, since it may be dependent on gpg being
correctly configured and used), there is no record left on
disk of the tag message.
Instead, let's keep the TAG_EDITMSG file around until we are
sure the tag has been created successfully. If we die
because of an error, the user can recover their text from
that file. Leaving the file in place causes no conflicts;
it will be silently overwritten by the next annotated tag
creation.
This matches the behavior of COMMIT_EDITMSG, which stays
around in case of error.
Signed-off-by: Jeff King <peff@peff.net>
---
On Wed, Dec 03, 2008 at 04:53:24PM +0100, Christian Jaeger wrote:
> Before I've now set my default signing key id in my ~/.gitconfig, I've
> run at least half a dozen times into the case where I'm running "git tag
> -s $tagname", carefully preparing a tag message, saving the file &
> exiting from the editor, only to be greeted with an error message that no
> key could be found for my (deliberately host-specific) email address, and
> my message gone. If it would keep the TAG_EDITMSG file (like git commit
> seems to be doing with COMMIT_EDITMSG anyway), I could rescue the message
> from there. I relentlessly assume that this small change would also make a
> handful of other people happier.
I think that is sensible. Here is the patch.
There are two possible improvements I can think of:
- we can be more friendly about helping the user recover. Right now,
we don't tell them that their message was saved anywhere, and it
will be silently overwritten if they try another tag. I'm not sure
what would be the best way to go about that, though.
- the "path" variable became a little less local. It might be worth
giving it a better name ("editmsg_path" or similar), but keeping it
made the diff a lot less noisy (and it's still local to a fairly
simple function).
builtin-tag.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/builtin-tag.c b/builtin-tag.c
index d339971..ea596d2 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -260,6 +260,7 @@ static void create_tag(const unsigned char *object, const char *tag,
enum object_type type;
char header_buf[1024];
int header_len;
+ char *path;
type = sha1_object_info(object, NULL);
if (type <= OBJ_NONE)
@@ -279,7 +280,6 @@ static void create_tag(const unsigned char *object, const char *tag,
die("tag header too big.");
if (!message) {
- char *path;
int fd;
/* write the template message before editing: */
@@ -300,9 +300,6 @@ static void create_tag(const unsigned char *object, const char *tag,
"Please supply the message using either -m or -F option.\n");
exit(1);
}
-
- unlink(path);
- free(path);
}
stripspace(buf, 1);
@@ -316,6 +313,9 @@ static void create_tag(const unsigned char *object, const char *tag,
die("unable to sign the tag");
if (write_sha1_file(buf->buf, buf->len, tag_type, result) < 0)
die("unable to write tag file");
+
+ unlink(path);
+ free(path);
}
struct msg_arg {
--
1.6.1.rc1.335.gf97227.dirty
^ permalink raw reply related
* Re: git tag -s: TAG_EDITMSG should not be deleted upon failures
From: Jeff King @ 2008-12-06 19:42 UTC (permalink / raw)
To: Christian Jaeger; +Cc: Junio C Hamano, Git Mailing List
In-Reply-To: <20081206194034.GA18418@coredump.intra.peff.net>
On Sat, Dec 06, 2008 at 02:40:34PM -0500, Jeff King wrote:
> Subject: Re: git tag -s: TAG_EDITMSG should not be deleted upon failures
>
> tag: delete TAG_EDITMSG only on successful tag
Oops, of course I bungled the subject here, and the email subject should
simply be ignored.
-Peff
^ permalink raw reply
* Re: Git Books
From: Björn Steinbrink @ 2008-12-06 19:45 UTC (permalink / raw)
To: Scott Chacon; +Cc: git list
In-Reply-To: <d411cc4a0812060358ub640ea3kd04072c5640eef68@mail.gmail.com>
On 2008.12.06 03:58:28 -0800, Scott Chacon wrote:
> So, since I'm near the beginning of this process, I was wondering if
> the group had any feedback as to what might be super helpful to
> include. I mean, I have a pretty good layout and all, but if you
> wanted to point me to some threads that tend to crop up in the mailing
> list and IRC channel from relative newcomers that I might be able to
> nip in the bud, I would like to. I'm addressing the stuff that _I_
> hear a lot, and I'm scanning the IRC logs and list for topics, but I
> figured many of you must answer the same questions all the time, too.
Just some random thoughts:
Please explain HEAD early on, and what it actually means. I've seen
quite a number of people understanding HEAD as, for example, a magic
keyword, a branch property, or a _direct_ reference to the latest commit
on the branch they have checked out. Especially the last one has really
confused the hell out of some people when they came across the concept
of a detached HEAD.
Explaining remote tracking branches early on, say after the first
"clone" is also important I guess. A number of readers will probably
just "dive in" when they learned a few commands and clone some random
repo to start playing. Unless Murphy lets us down, they'll clone a repo
that has multiple branches and will sit there, wondering how to get one
of the branches that only exist as remote tracking branches in their
repo.
And for commands, it's IMHO best to always start with the "full blown"
form, and only then, after introducing the command and what it does,
start to talk about short forms and how you can leave out some arguments
and fall back to defaults.
For example:
rebase:
Start with "rebase --onto <onto> <upstream> <branch>" and how that takes
the commits from <upstream>..<branch> and "replays" them on top of
<onto>. In my experience, starting with that version and showing how it
affects the commit DAG helps people to actually understand what happens,
while a plain "git rebase master" seems like pure magic to some, because
you can't even use the arguments to explain why and where things are
placed, or you start telling how those are all defaults, and then have
to explain everything all over again, when you use the explicit form for
more complicated things and people seem to get confused by that.
fetch:
Include refspecs in the first examples and show how a missing rhs causes
the fetched stuff to be stored in FETCH_HEAD. And only then go on to
tell that remotes usually have a default refspec in their config, and
that you can thus omit the refspecs when you fetch from a remote.
push:
refspecs again. Maybe start with pushing a single branch/tag/whatever,
explicitly, eg. "git push origin refs/heads/master:refs/heads/master",
and only then introduce the DWIM stuff like "git push origin master".
Same thing for the default ":" refspec, please mention what that refspec
means and that it is the default when no refspec is given (either on the
command line or in the config). A lot of people don't seem to know about
refspecs at all, and the "matching branch names" refspec is IMHO worth
being mentioned, as I've seen a bunch of questions lately that could be
answered by explaining that. For example, updating matching branches and
pushing a new tag at once, or having a push config that pushes one or
more branches to differently named branches on the remote, but using the
name matching for all other. And personally, I also like "git push
origin : v1.2.3" better than pushing twice or naming my branches
explicitly :-)
Björn
^ permalink raw reply
* [PATCH 1/2] gitk: Mark forgotten strings (header sentence parts in color chooser) for translation.
From: Christian Stimming @ 2008-12-06 19:48 UTC (permalink / raw)
To: Paul Mackerras; +Cc: git
---
gitk | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/gitk b/gitk
index a5e24e4..39aabb3 100755
--- a/gitk
+++ b/gitk
@@ -10150,26 +10150,26 @@ proc doprefs {} {
grid $top.cdisp - -sticky w -pady 10
label $top.bg -padx 40 -relief sunk -background $bgcolor
button $top.bgbut -text [mc "Background"] -font optionfont \
- -command [list choosecolor bgcolor {} $top.bg background setbg]
+ -command [list choosecolor bgcolor {} $top.bg [mc "background"] setbg]
grid x $top.bgbut $top.bg -sticky w
label $top.fg -padx 40 -relief sunk -background $fgcolor
button $top.fgbut -text [mc "Foreground"] -font optionfont \
- -command [list choosecolor fgcolor {} $top.fg foreground setfg]
+ -command [list choosecolor fgcolor {} $top.fg [mc "foreground"] setfg]
grid x $top.fgbut $top.fg -sticky w
label $top.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
button $top.diffoldbut -text [mc "Diff: old lines"] -font optionfont \
- -command [list choosecolor diffcolors 0 $top.diffold "diff old lines" \
+ -command [list choosecolor diffcolors 0 $top.diffold [mc "diff old lines"] \
[list $ctext tag conf d0 -foreground]]
grid x $top.diffoldbut $top.diffold -sticky w
label $top.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
button $top.diffnewbut -text [mc "Diff: new lines"] -font optionfont \
- -command [list choosecolor diffcolors 1 $top.diffnew "diff new lines" \
+ -command [list choosecolor diffcolors 1 $top.diffnew [mc "diff new lines"] \
[list $ctext tag conf dresult -foreground]]
grid x $top.diffnewbut $top.diffnew -sticky w
label $top.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
button $top.hunksepbut -text [mc "Diff: hunk header"] -font optionfont \
-command [list choosecolor diffcolors 2 $top.hunksep \
- "diff hunk header" \
+ [mc "diff hunk header"] \
[list $ctext tag conf hunksep -foreground]]
grid x $top.hunksepbut $top.hunksep -sticky w
label $top.markbgsep -padx 40 -relief sunk -background $markbgcolor
@@ -10180,7 +10180,7 @@ proc doprefs {} {
grid x $top.markbgbut $top.markbgsep -sticky w
label $top.selbgsep -padx 40 -relief sunk -background $selectbgcolor
button $top.selbgbut -text [mc "Select bg"] -font optionfont \
- -command [list choosecolor selectbgcolor {} $top.selbgsep background setselbg]
+ -command [list choosecolor selectbgcolor {} $top.selbgsep [mc "background"] setselbg]
grid x $top.selbgbut $top.selbgsep -sticky w
label $top.cfont -text [mc "Fonts: press to choose"]
--
1.6.0.3.517.g759a
^ permalink raw reply related
* [PATCH 2/2] gitk: Update German translation.
From: Christian Stimming @ 2008-12-06 19:49 UTC (permalink / raw)
To: Paul Mackerras; +Cc: git
In-Reply-To: <200812062048.30412.stimming@tuhh.de>
[-- Attachment #1: Type: text/plain, Size: 60 bytes --]
Attached to avoid whitespace problems.
Regards,
Christian
[-- Attachment #2: 0002-gitk-Update-German-translation.patch --]
[-- Type: text/x-diff, Size: 7557 bytes --]
From 282060ac531fee722142f9d39c4ff29570723cbb Mon Sep 17 00:00:00 2001
From: Christian Stimming <stimming@tuhh.de>
Date: Sat, 6 Dec 2008 20:47:15 +0100
Subject: [PATCH 2/2] gitk: Update German translation.
Merged with most recent "make update-po" result.
Signed-off-by: Christian Stimming <stimming@tuhh.de>
---
po/de.po | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 157 insertions(+), 29 deletions(-)
diff --git a/po/de.po b/po/de.po
index e0a6dee..825dc98 100644
--- a/po/de.po
+++ b/po/de.po
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: git-gui\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-10-25 13:18+0200\n"
-"PO-Revision-Date: 2008-10-25 13:23+0200\n"
+"POT-Creation-Date: 2008-12-06 20:40+0100\n"
+"PO-Revision-Date: 2008-12-06 20:45+0100\n"
"Last-Translator: Christian Stimming <stimming@tuhh.de>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"
@@ -90,7 +90,11 @@ msgstr "Zweige neu laden"
msgid "List references"
msgstr "Zweige/Markierungen auflisten"
-#: gitk:1815
+#: gitk:1915
+msgid "Start git gui"
+msgstr "»git gui« starten"
+
+#: gitk:1917
msgid "Quit"
msgstr "Beenden"
@@ -295,7 +299,15 @@ msgstr "Externer Vergleich"
msgid "Blame parent commit"
msgstr "Annotieren der Elternversion"
-#: gitk:2488
+#: gitk:2360
+msgid "Show origin of this line"
+msgstr "Herkunft dieser Zeile anzeigen"
+
+#: gitk:2361
+msgid "Run git gui blame on this line"
+msgstr "Annotieren (»git gui blame«) von dieser Zeile"
+
+#: gitk:2606
msgid ""
"\n"
"Gitk - a commit viewer for git\n"
@@ -501,7 +513,38 @@ msgstr "Version nicht gefunden"
msgid "git gui blame: command failed:"
msgstr "git gui blame: Kommando fehlgeschlagen:"
-#: gitk:3092
+#: gitk:3398
+#, tcl-format
+msgid "Couldn't read merge head: %s"
+msgstr "Zusammenführungs-Spitze konnte nicht gelesen werden: %s"
+
+#: gitk:3406
+#, tcl-format
+msgid "Error reading index: %s"
+msgstr "Fehler beim Lesen der Bereitstellung (»index«): %s"
+
+#: gitk:3431
+#, tcl-format
+msgid "Couldn't start git blame: %s"
+msgstr "»git blame« konnte nicht gestartet werden: %s"
+
+#: gitk:3434 gitk:6160
+msgid "Searching"
+msgstr "Suchen"
+
+#: gitk:3466
+#, tcl-format
+msgid "Error running git blame: %s"
+msgstr "Fehler beim Ausführen von »git blame«: %s"
+
+#: gitk:3494
+#, tcl-format
+msgid "That line comes from commit %s, which is not in this view"
+msgstr ""
+"Diese Zeile stammt aus Version %s, welche nicht in dieser Ansicht gezeigt "
+"wird."
+
+#: gitk:3508
msgid "External diff viewer failed:"
msgstr "Externes Vergleich-(Diff-)Programm fehlgeschlagen:"
@@ -509,11 +552,7 @@ msgstr "Externes Vergleich-(Diff-)Programm fehlgeschlagen:"
msgid "Gitk view definition"
msgstr "Gitk Ansichten"
-#: gitk:3225
-msgid "Name"
-msgstr "Name"
-
-#: gitk:3228
+#: gitk:3630
msgid "Remember this view"
msgstr "Diese Ansicht speichern"
@@ -521,15 +560,55 @@ msgstr "Diese Ansicht speichern"
msgid "Commits to include (arguments to git log):"
msgstr "Versionen anzeigen (Argumente von git-log):"
-#: gitk:3239
+#: gitk:3632
+msgid "Use all refs"
+msgstr "Alle Zweige verwenden"
+
+#: gitk:3633
+msgid "Strictly sort by date"
+msgstr "Streng nach Datum sortieren"
+
+#: gitk:3634
+msgid "Mark branch sides"
+msgstr "Zweig-Seiten markieren"
+
+#: gitk:3635
+msgid "Since date:"
+msgstr "Von Datum:"
+
+#: gitk:3636
+msgid "Until date:"
+msgstr "Bis Datum:"
+
+#: gitk:3637
+msgid "Max count:"
+msgstr "Max. Anzahl:"
+
+#: gitk:3638
+msgid "Skip:"
+msgstr "Ãberspringen:"
+
+#: gitk:3639
+msgid "Limit to first parent"
+msgstr "Auf erste Elternversion beschränken"
+
+#: gitk:3640
msgid "Command to generate more commits to include:"
msgstr "Versionsliste durch folgendes Kommando erzeugen lassen:"
-#: gitk:3246
+#: gitk:3749
+msgid "Name"
+msgstr "Name"
+
+#: gitk:3797
msgid "Enter files and directories to include, one per line:"
msgstr "Folgende Dateien und Verzeichnisse anzeigen (eine pro Zeile):"
-#: gitk:3293
+#: gitk:3811
+msgid "Apply (F5)"
+msgstr "Anwenden (F5)"
+
+#: gitk:3849
msgid "Error in commit selection arguments:"
msgstr "Fehler in den ausgewählten Versionen:"
@@ -569,11 +648,7 @@ msgstr "Lokale Ãnderungen bereitgestellt, aber nicht eingetragen"
msgid "Local uncommitted changes, not checked in to index"
msgstr "Lokale Ãnderungen, nicht bereitgestellt"
-#: gitk:5549
-msgid "Searching"
-msgstr "Suchen"
-
-#: gitk:6049
+#: gitk:6673
msgid "Tags:"
msgstr "Markierungen:"
@@ -597,11 +672,12 @@ msgstr "Folgt auf"
msgid "Precedes"
msgstr "Vorgänger von"
-#: gitk:6378
-msgid "Error getting merge diffs:"
-msgstr "Fehler beim Laden des Vergleichs:"
+#: gitk:7209
+#, tcl-format
+msgid "Error getting diffs: %s"
+msgstr "Fehler beim Laden des Vergleichs: %s"
-#: gitk:7113
+#: gitk:7748
msgid "Goto:"
msgstr "Gehe zu:"
@@ -722,7 +798,12 @@ msgstr "Name:"
msgid "Please specify a name for the new branch"
msgstr "Bitte geben Sie einen Namen für den neuen Zweig an."
-#: gitk:7703
+#: gitk:8328
+#, tcl-format
+msgid "Branch '%s' already exists. Overwrite?"
+msgstr "Zweig »%s« existiert bereits. Soll er überschrieben werden?"
+
+#: gitk:8394
#, tcl-format
msgid "Commit %s is already included in branch %s -- really re-apply it?"
msgstr ""
@@ -733,7 +814,26 @@ msgstr ""
msgid "Cherry-picking"
msgstr "Version pflücken"
-#: gitk:7720
+#: gitk:8408
+#, tcl-format
+msgid ""
+"Cherry-pick failed because of local changes to file '%s'.\n"
+"Please commit, reset or stash your changes and try again."
+msgstr ""
+"Pflücken fehlgeschlagen, da noch lokale Ãnderungen in Datei »%s«\n"
+"vorliegen. Bitte diese Ãnderungen eintragen, zurücksetzen oder\n"
+"zwischenspeichern (»git stash») und dann erneut versuchen."
+
+#: gitk:8414
+msgid ""
+"Cherry-pick failed because of merge conflict.\n"
+"Do you wish to run git citool to resolve it?"
+msgstr ""
+"Pflücken fehlgeschlagen, da ein Zusammenführungs-Konflikt aufgetreten\n"
+"ist. Soll das »git citool« (Zusammenführungs-Werkzeug) aufgerufen\n"
+"werden, um diesen Konflikt aufzulösen?"
+
+#: gitk:8430
msgid "No changes committed"
msgstr "Keine Ãnderungen eingetragen"
@@ -889,23 +989,51 @@ msgstr "Farben: Klicken zum Wählen"
msgid "Background"
msgstr "Hintergrund"
-#: gitk:9435
+#: gitk:10153 gitk:10183
+msgid "background"
+msgstr "Hintergrund"
+
+#: gitk:10156
msgid "Foreground"
msgstr "Vordergrund"
-#: gitk:9439
+#: gitk:10157
+msgid "foreground"
+msgstr "Vordergrund"
+
+#: gitk:10160
msgid "Diff: old lines"
msgstr "Vergleich: Alte Zeilen"
-#: gitk:9444
+#: gitk:10161
+msgid "diff old lines"
+msgstr "Vergleich - Alte Zeilen"
+
+#: gitk:10165
msgid "Diff: new lines"
msgstr "Vergleich: Neue Zeilen"
-#: gitk:9449
+#: gitk:10166
+msgid "diff new lines"
+msgstr "Vergleich - Neue Zeilen"
+
+#: gitk:10170
msgid "Diff: hunk header"
msgstr "Vergleich: Ãnderungstitel"
-#: gitk:9455
+#: gitk:10172
+msgid "diff hunk header"
+msgstr "Vergleich - Ãnderungstitel"
+
+#: gitk:10176
+msgid "Marked line bg"
+msgstr "Markierte Zeile Hintergrund"
+
+#: gitk:10178
+msgid "marked line background"
+msgstr "markierte Zeile Hintergrund"
+
+#: gitk:10182
msgid "Select bg"
msgstr "Hintergrundfarbe Auswählen"
--
1.6.0.3.517.g759a
^ permalink raw reply related
* [PATCH] git-gui: Updated German translation
From: Christian Stimming @ 2008-12-06 20:23 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: git
[-- Attachment #1: Type: text/plain, Size: 58 bytes --]
Attached to avoid whitespace issues.
Regards,
Christian
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-git-gui-Update-German-completed-translation.patch --]
[-- Type: text/x-diff; charset="us-ascii"; name="0001-git-gui-Update-German-completed-translation.patch", Size: 12851 bytes --]
From 224db827d57b01e908b8b0594b6fa33d512d7ad4 Mon Sep 17 00:00:00 2001
From: Christian Stimming <stimming@tuhh.de>
Date: Sat, 6 Dec 2008 21:22:16 +0100
Subject: [PATCH] git-gui: Update German (completed) translation.
Signed-off-by: Christian Stimming <stimming@tuhh.de>
---
po/de.po | 279 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 239 insertions(+), 40 deletions(-)
diff --git a/po/de.po b/po/de.po
index 5c04812..a6f730b 100644
--- a/po/de.po
+++ b/po/de.po
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: git-gui\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-10-25 13:32+0200\n"
-"PO-Revision-Date: 2008-10-25 22:47+0200\n"
+"POT-Creation-Date: 2008-12-06 20:51+0100\n"
+"PO-Revision-Date: 2008-12-06 21:22+0100\n"
"Last-Translator: Christian Stimming <stimming@tuhh.de>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"
@@ -86,17 +86,15 @@ msgstr "Dateistatus aktualisieren..."
msgid "Scanning for modified files ..."
msgstr "Nach geänderten Dateien suchen..."
-#: git-gui.sh:1325
-#, fuzzy
+#: git-gui.sh:1367
msgid "Calling prepare-commit-msg hook..."
-msgstr "Aufrufen der Vor-Eintragen-Kontrolle..."
+msgstr "Aufrufen der Eintragen-Vorbereiten-Kontrolle..."
-#: git-gui.sh:1342
-#, fuzzy
+#: git-gui.sh:1384
msgid "Commit declined by prepare-commit-msg hook."
-msgstr "Eintragen abgelehnt durch Vor-Eintragen-Kontrolle (»pre-commit hook«)."
+msgstr "Eintragen abgelehnt durch Eintragen-Vorbereiten-Kontrolle (»prepare-commit hook«)."
-#: git-gui.sh:1502 lib/browser.tcl:246
+#: git-gui.sh:1542 lib/browser.tcl:246
msgid "Ready."
msgstr "Bereit."
@@ -180,7 +178,11 @@ msgstr "Zusammenführen"
msgid "Remote"
msgstr "Andere Archive"
-#: git-gui.sh:2242
+#: git-gui.sh:2293
+msgid "Tools"
+msgstr "Werkzeuge"
+
+#: git-gui.sh:2302
msgid "Explore Working Copy"
msgstr "Arbeitskopie im Dateimanager"
@@ -363,7 +365,11 @@ msgstr "Einstellungen..."
msgid "Options..."
msgstr "Optionen..."
-#: git-gui.sh:2113 lib/choose_repository.tcl:47
+#: git-gui.sh:2576
+msgid "Remove..."
+msgstr "Entfernen..."
+
+#: git-gui.sh:2585 lib/choose_repository.tcl:50
msgid "Help"
msgstr "Hilfe"
@@ -371,7 +377,11 @@ msgstr "Hilfe"
msgid "Online Documentation"
msgstr "Online-Dokumentation"
-#: git-gui.sh:2238
+#: git-gui.sh:2614 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56
+msgid "Show SSH Key"
+msgstr "SSH-Schlüssel anzeigen"
+
+#: git-gui.sh:2707
#, tcl-format
msgid "fatal: cannot stat path %s: No such file or directory"
msgstr ""
@@ -548,7 +558,11 @@ msgstr "Version:"
msgid "Copy Commit"
msgstr "Version kopieren"
-#: lib/blame.tcl:260
+#: lib/blame.tcl:275
+msgid "Find Text..."
+msgstr "Text suchen..."
+
+#: lib/blame.tcl:284
msgid "Do Full Copy Detection"
msgstr "Volle Kopie-Erkennung"
@@ -609,12 +623,11 @@ msgstr "Eintragender:"
msgid "Original File:"
msgstr "Ursprüngliche Datei:"
-#: lib/blame.tcl:1013
-#, fuzzy
+#: lib/blame.tcl:1021
msgid "Cannot find HEAD commit:"
-msgstr "Elternversion kann nicht gefunden werden:"
+msgstr "Zweigspitze (»HEAD«) kann nicht gefunden werden:"
-#: lib/blame.tcl:1068
+#: lib/blame.tcl:1076
msgid "Cannot find parent commit:"
msgstr "Elternversion kann nicht gefunden werden:"
@@ -1049,7 +1062,7 @@ msgstr "Zuletzt benutztes Projektarchiv öffnen:"
msgid "Failed to create repository %s:"
msgstr "Projektarchiv »%s« konnte nicht erstellt werden:"
-#: lib/choose_repository.tcl:381 lib/choose_repository.tcl:478
+#: lib/choose_repository.tcl:387
msgid "Directory:"
msgstr "Verzeichnis:"
@@ -1058,12 +1071,12 @@ msgstr "Verzeichnis:"
msgid "Git Repository"
msgstr "Git Projektarchiv"
-#: lib/choose_repository.tcl:437
+#: lib/choose_repository.tcl:442
#, tcl-format
msgid "Directory %s already exists."
msgstr "Verzeichnis »%s« existiert bereits."
-#: lib/choose_repository.tcl:441
+#: lib/choose_repository.tcl:446
#, tcl-format
msgid "File %s already exists."
msgstr "Datei »%s« existiert bereits."
@@ -1072,11 +1085,11 @@ msgstr "Datei »%s« existiert bereits."
msgid "Clone"
msgstr "Klonen"
-#: lib/choose_repository.tcl:467
+#: lib/choose_repository.tcl:473
msgid "Source Location:"
-msgstr ""
+msgstr "Herkunft:"
-#: lib/choose_repository.tcl:478
+#: lib/choose_repository.tcl:484
msgid "Target Directory:"
msgstr "Zielverzeichnis:"
@@ -1565,20 +1578,24 @@ msgid ""
"LOCAL: deleted\n"
"REMOTE:\n"
msgstr ""
+"LOKAL: gelöscht\n"
+"ANDERES:\n"
#: lib/diff.tcl:125
msgid ""
"REMOTE: deleted\n"
"LOCAL:\n"
msgstr ""
+"ANDERES: gelöscht\n"
+"LOKAL:\n"
#: lib/diff.tcl:132
msgid "LOCAL:\n"
-msgstr ""
+msgstr "LOKAL:\n"
#: lib/diff.tcl:135
msgid "REMOTE:\n"
-msgstr ""
+msgstr "ANDERES:\n"
#: lib/diff.tcl:197 lib/diff.tcl:296
#, tcl-format
@@ -1603,6 +1620,8 @@ msgid ""
"* Untracked file is %d bytes.\n"
"* Showing only first %d bytes.\n"
msgstr ""
+"* Datei nicht unter Versionskontrolle, Dateigröße %d Bytes.\n"
+"* Nur erste %d Bytes werden angezeigt.\n"
#: lib/diff.tcl:228
#, tcl-format
@@ -1611,8 +1630,11 @@ msgid ""
"* Untracked file clipped here by %s.\n"
"* To see the entire file, use an external editor.\n"
msgstr ""
+"\n"
+"* Datei nicht unter Versionskontrolle, hier abgeschnitten durch %s.\n"
+"* Zum Ansehen der vollständigen Datei externen Editor benutzen.\n"
-#: lib/diff.tcl:437
+#: lib/diff.tcl:436
msgid "Failed to unstage selected hunk."
msgstr ""
"Fehler beim Herausnehmen des gewählten Kontexts aus der Bereitstellung."
@@ -2045,7 +2067,7 @@ msgstr "Namensvorschlag für neue Zweige"
#: lib/option.tcl:155
msgid "Default File Contents Encoding"
-msgstr "Vorgestellte Zeichenkodierung"
+msgstr "Voreingestellte Zeichenkodierung"
#: lib/option.tcl:203
msgid "Change"
@@ -2113,19 +2135,18 @@ msgid "Do Nothing Else Now"
msgstr "Nichts tun"
#: lib/remote_add.tcl:101
-#, fuzzy
msgid "Please supply a remote name."
-msgstr "Bitte geben Sie einen Zweignamen an."
+msgstr "Bitte geben Sie einen Namen des anderen Archivs an."
#: lib/remote_add.tcl:114
-#, fuzzy, tcl-format
+#, tcl-format
msgid "'%s' is not an acceptable remote name."
-msgstr "»%s« ist kein zulässiger Zweigname."
+msgstr "»%s« ist kein zulässiger Name eines anderen Archivs."
#: lib/remote_add.tcl:125
-#, fuzzy, tcl-format
+#, tcl-format
msgid "Failed to add remote '%s' of location '%s'."
-msgstr "Fehler beim Umbenennen von »%s«."
+msgstr "Fehler beim Hinzufügen des anderen Archivs »%s« aus Herkunftsort »%s«."
#: lib/remote_add.tcl:133 lib/transport.tcl:6
#, tcl-format
@@ -2133,16 +2154,18 @@ msgid "fetch %s"
msgstr "»%s« anfordern"
#: lib/remote_add.tcl:134
-#, fuzzy, tcl-format
+#, tcl-format
msgid "Fetching the %s"
-msgstr "Änderungen »%s« von »%s« anfordern"
+msgstr "»%s« anfordern"
#: lib/remote_add.tcl:157
#, tcl-format
msgid "Do not know how to initialize repository at location '%s'."
-msgstr "Initialisieren eines anderen Archivs an Adresse »%s« ist nicht möglich."
+msgstr ""
+"Initialisieren eines anderen Archivs an Adresse »%s« ist nicht möglich."
-#: lib/remote_add.tcl:163 lib/transport.tcl:25 lib/transport.tcl:71
+#: lib/remote_add.tcl:163 lib/transport.tcl:25 lib/transport.tcl:63
+#: lib/transport.tcl:81
#, tcl-format
msgid "push %s"
msgstr "»%s« versenden..."
@@ -2266,9 +2289,9 @@ msgstr "Nächster"
msgid "Prev"
msgstr "Voriger"
-#: lib/search.tcl:24
+#: lib/search.tcl:25
msgid "Case-Sensitive"
-msgstr ""
+msgstr "Groß-/Kleinschreibung unterscheiden"
#: lib/shortcut.tcl:20 lib/shortcut.tcl:61
msgid "Cannot write shortcut:"
@@ -2315,11 +2338,182 @@ msgstr "Unerwartetes EOF vom Rechtschreibprüfungsprogramm"
msgid "Spell Checker Failed"
msgstr "Rechtschreibprüfung fehlgeschlagen"
+#: lib/sshkey.tcl:31
+msgid "No keys found."
+msgstr "Keine Schlüssel gefunden."
+
+#: lib/sshkey.tcl:34
+#, tcl-format
+msgid "Found a public key in: %s"
+msgstr "Öffentlicher Schlüssel gefunden in: %s"
+
+#: lib/sshkey.tcl:40
+msgid "Generate Key"
+msgstr "Schlüssel erzeugen"
+
+#: lib/sshkey.tcl:56
+msgid "Copy To Clipboard"
+msgstr "In Zwischenablage kopieren"
+
+#: lib/sshkey.tcl:70
+msgid "Your OpenSSH Public Key"
+msgstr "Ihr OpenSSH öffenlicher Schlüssel"
+
+#: lib/sshkey.tcl:78
+msgid "Generating..."
+msgstr "Erzeugen..."
+
+#: lib/sshkey.tcl:84
+#, tcl-format
+msgid ""
+"Could not start ssh-keygen:\n"
+"\n"
+"%s"
+msgstr ""
+"Konnte »ssh-keygen« nicht starten:\n"
+"\n"
+"%s"
+
+#: lib/sshkey.tcl:111
+msgid "Generation failed."
+msgstr "Schlüsselerzeugung fehlgeschlagen."
+
+#: lib/sshkey.tcl:118
+msgid "Generation succeded, but no keys found."
+msgstr "Schlüsselerzeugung erfolgreich, aber keine Schlüssel gefunden."
+
+#: lib/sshkey.tcl:121
+#, tcl-format
+msgid "Your key is in: %s"
+msgstr "Ihr Schlüssel ist abgelegt in: %s"
+
#: lib/status_bar.tcl:83
#, tcl-format
msgid "%s ... %*i of %*i %s (%3i%%)"
msgstr "%s ... %*i von %*i %s (%3i%%)"
+#: lib/tools_dlg.tcl:22
+msgid "Add Tool"
+msgstr "Werkzeug hinzufügen"
+
+#: lib/tools_dlg.tcl:28
+msgid "Add New Tool Command"
+msgstr "Neues Kommando für Werkzeug hinzufügen"
+
+#: lib/tools_dlg.tcl:33
+msgid "Add globally"
+msgstr "Global hinzufügen"
+
+#: lib/tools_dlg.tcl:45
+msgid "Tool Details"
+msgstr "Einzelheiten des Werkzeugs"
+
+#: lib/tools_dlg.tcl:48
+msgid "Use '/' separators to create a submenu tree:"
+msgstr "Benutzen Sie einen Schrägstrich »/«, um Untermenüs zu erstellen:"
+
+#: lib/tools_dlg.tcl:61
+msgid "Command:"
+msgstr "Kommando:"
+
+#: lib/tools_dlg.tcl:74
+msgid "Show a dialog before running"
+msgstr "Bestätigungsfrage vor Starten anzeigen"
+
+#: lib/tools_dlg.tcl:80
+msgid "Ask the user to select a revision (sets $REVISION)"
+msgstr "Benutzer nach Version fragen (setzt $REVISION)"
+
+#: lib/tools_dlg.tcl:85
+msgid "Ask the user for additional arguments (sets $ARGS)"
+msgstr "Benutzer nach zusätzlichen Argumenten fragen (setzt $ARGS)"
+
+#: lib/tools_dlg.tcl:92
+msgid "Don't show the command output window"
+msgstr "Kein Ausgabefenster zeigen"
+
+#: lib/tools_dlg.tcl:97
+msgid "Run only if a diff is selected ($FILENAME not empty)"
+msgstr "Nur starten, wenn ein Vergleich gewählt ist ($FILENAME ist nicht leer)"
+
+#: lib/tools_dlg.tcl:121
+msgid "Please supply a name for the tool."
+msgstr "Bitte geben Sie einen Werkzeugnamen an."
+
+#: lib/tools_dlg.tcl:129
+#, tcl-format
+msgid "Tool '%s' already exists."
+msgstr "Werkzeug »%s« existiert bereits."
+
+#: lib/tools_dlg.tcl:151
+#, tcl-format
+msgid ""
+"Could not add tool:\n"
+"%s"
+msgstr ""
+"Werkzeug konnte nicht hinzugefügt werden:\n"
+"\n"
+"%s"
+
+#: lib/tools_dlg.tcl:190
+msgid "Remove Tool"
+msgstr "Werkzeug entfernen"
+
+#: lib/tools_dlg.tcl:196
+msgid "Remove Tool Commands"
+msgstr "Werkzeugkommandos entfernen"
+
+#: lib/tools_dlg.tcl:200
+msgid "Remove"
+msgstr "Entfernen"
+
+#: lib/tools_dlg.tcl:236
+msgid "(Blue denotes repository-local tools)"
+msgstr "(Werkzeuge für lokales Archiv werden in Blau angezeigt)"
+
+#: lib/tools_dlg.tcl:297
+#, tcl-format
+msgid "Run Command: %s"
+msgstr "Kommando aufrufen: %s"
+
+#: lib/tools_dlg.tcl:311
+msgid "Arguments"
+msgstr "Argumente"
+
+#: lib/tools_dlg.tcl:348
+msgid "OK"
+msgstr "Ok"
+
+#: lib/tools.tcl:75
+#, tcl-format
+msgid "Running %s requires a selected file."
+msgstr "Um »%s« zu starten, muss eine Datei ausgewählt sein."
+
+#: lib/tools.tcl:90
+#, tcl-format
+msgid "Are you sure you want to run %s?"
+msgstr "Wollen Sie %s wirklich starten?"
+
+#: lib/tools.tcl:110
+#, tcl-format
+msgid "Tool: %s"
+msgstr "Werkzeug: %s"
+
+#: lib/tools.tcl:111
+#, tcl-format
+msgid "Running: %s"
+msgstr "Starten: %s"
+
+#: lib/tools.tcl:149
+#, tcl-format
+msgid "Tool completed succesfully: %s"
+msgstr "Werkzeug erfolgreich abgeschlossen: %s"
+
+#: lib/tools.tcl:151
+#, tcl-format
+msgid "Tool failed: %s"
+msgstr "Werkzeug fehlgeschlagen: %s"
+
#: lib/transport.tcl:7
#, tcl-format
msgid "Fetching new changes from %s"
@@ -2340,7 +2534,12 @@ msgstr "Übernahmezweige aufräumen und entfernen, die in »%s« gelöscht wurde
msgid "Pushing changes to %s"
msgstr "Änderungen nach »%s« versenden"
-#: lib/transport.tcl:72
+#: lib/transport.tcl:64
+#, tcl-format
+msgid "Mirroring to %s"
+msgstr "Spiegeln nach %s"
+
+#: lib/transport.tcl:82
#, tcl-format
msgid "Pushing %s %s to %s"
msgstr "%s %s nach %s versenden"
--
1.6.0.3.517.g759a
^ permalink raw reply related
* [PATCH] fetch-pack: Avoid memcpy() with src==dst
From: Thomas Rast @ 2008-12-06 20:50 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
memcpy() may only be used for disjoint memory areas, but when invoked
from cmd_fetch_pack(), we have my_args == &args. (The argument cannot
be removed entirely because transport.c invokes with its own
variable.)
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
Found this while valgrinding too much.
builtin-fetch-pack.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c
index 372bfa2..67fb80e 100644
--- a/builtin-fetch-pack.c
+++ b/builtin-fetch-pack.c
@@ -780,7 +780,8 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
struct ref *ref_cpy;
fetch_pack_setup();
- memcpy(&args, my_args, sizeof(args));
+ if (&args != my_args)
+ memcpy(&args, my_args, sizeof(args));
if (args.depth > 0) {
if (stat(git_path("shallow"), &st))
st.st_mtime = 0;
--
tg: (7f705dc..) t/fp-memcpy-fix (depends on: origin/master)
^ permalink raw reply related
* Re: git tag -s: TAG_EDITMSG should not be deleted upon failures
From: Junio C Hamano @ 2008-12-06 21:28 UTC (permalink / raw)
To: Jeff King; +Cc: Christian Jaeger, Git Mailing List
In-Reply-To: <20081206194034.GA18418@coredump.intra.peff.net>
Jeff King <peff@peff.net> writes:
> tag: delete TAG_EDITMSG only on successful tag
>
> The user may put some effort into writing an annotated tag
> message. When the tagging process later fails (which can
> happen fairly easily, since it may be dependent on gpg being
> correctly configured and used), there is no record left on
> disk of the tag message.
>
> Instead, let's keep the TAG_EDITMSG file around until we are
> sure the tag has been created successfully. If we die
> because of an error, the user can recover their text from
> that file. Leaving the file in place causes no conflicts;
> it will be silently overwritten by the next annotated tag
> creation.
>
> This matches the behavior of COMMIT_EDITMSG, which stays
> around in case of error.
Thanks. I love patches that addresses bugs during -rc period.
> There are two possible improvements I can think of:
>
> - we can be more friendly about helping the user recover. Right now,
> we don't tell them that their message was saved anywhere, and it
> will be silently overwritten if they try another tag. I'm not sure
> what would be the best way to go about that, though.
>
> - the "path" variable became a little less local. It might be worth
> giving it a better name ("editmsg_path" or similar), but keeping it
> made the diff a lot less noisy (and it's still local to a fairly
> simple function).
There is another.
- the "path" variable is uninitialized if we do not start editor at
all, so unlink(path) and free(path) have a very high chance of
failing.
I think you need [Update #1] below squashed in to fix this.
As to your first potential improvement, I think you could do something
like [Update #2] (on top of [Update #1], of course).
[Update #1]
diff --git c/builtin-tag.c w/builtin-tag.c
index ea596d2..8086b3a 100644
--- c/builtin-tag.c
+++ w/builtin-tag.c
@@ -260,7 +260,7 @@ static void create_tag(const unsigned char *object, const char *tag,
enum object_type type;
char header_buf[1024];
int header_len;
- char *path;
+ char *path = NULL;
type = sha1_object_info(object, NULL);
if (type <= OBJ_NONE)
@@ -314,8 +314,10 @@ static void create_tag(const unsigned char *object, const char *tag,
if (write_sha1_file(buf->buf, buf->len, tag_type, result) < 0)
die("unable to write tag file");
- unlink(path);
- free(path);
+ if (path) {
+ unlink(path);
+ free(path);
+ }
}
struct msg_arg {
[Update #2]
diff --git i/builtin-tag.c w/builtin-tag.c
index 8086b3a..20c1c0e 100644
--- i/builtin-tag.c
+++ w/builtin-tag.c
@@ -253,6 +253,15 @@ static void write_tag_body(int fd, const unsigned char *sha1)
free(buf);
}
+static int build_tag_object(struct strbuf *buf, int sign, unsigned char *result)
+{
+ if (sign && do_sign(buf) < 0)
+ return error("unable to sign the tag");
+ if (write_sha1_file(buf->buf, buf->len, tag_type, result) < 0)
+ return error("unable to write tag file");
+ return 0;
+}
+
static void create_tag(const unsigned char *object, const char *tag,
struct strbuf *buf, int message, int sign,
unsigned char *prev, unsigned char *result)
@@ -309,11 +318,12 @@ static void create_tag(const unsigned char *object, const char *tag,
strbuf_insert(buf, 0, header_buf, header_len);
- if (sign && do_sign(buf) < 0)
- die("unable to sign the tag");
- if (write_sha1_file(buf->buf, buf->len, tag_type, result) < 0)
- die("unable to write tag file");
-
+ if (build_tag_object(buf, sign, result) < 0) {
+ if (path)
+ fprintf(stderr, "What you edited in your editor is left in %s",
+ path);
+ exit(128);
+ }
if (path) {
unlink(path);
free(path);
^ permalink raw reply related
* Re: git tag -s: TAG_EDITMSG should not be deleted upon failures
From: Jeff King @ 2008-12-06 21:54 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Christian Jaeger, Git Mailing List
In-Reply-To: <7v8wqtvvql.fsf@gitster.siamese.dyndns.org>
On Sat, Dec 06, 2008 at 01:28:50PM -0800, Junio C Hamano wrote:
> Thanks. I love patches that addresses bugs during -rc period.
Well, I'm not sure this was a bug fix versus an improvement, but at
least wasn't an all new feature. And it was short enough to look at in
one sitting.
Of course, I did still manage to introduce a bug in my 4-line
change...;)
> - the "path" variable is uninitialized if we do not start editor at
> all, so unlink(path) and free(path) have a very high chance of
> failing.
>
> I think you need [Update #1] below squashed in to fix this.
Oops. Yes, that is definitely a problem.
> [Update #1]
> [...]
> - char *path;
> + char *path = NULL;
Right, that fix looks good.
> + if (build_tag_object(buf, sign, result) < 0) {
> + if (path)
> + fprintf(stderr, "What you edited in your editor is left in %s",
> + path);
> + exit(128);
> + }
Much better, though the message is a bit awkward. How about
"The tag message has been left in %s"
?
Do you want me to resend, or do you want to fix up locally?
-Peff
^ permalink raw reply
* [PATCH] Spelling fix in release notes
From: Bjørn Lindeijer @ 2008-12-06 22:00 UTC (permalink / raw)
To: git, gitster
Signed-off-by: Bjørn Lindeijer <bjorn@lindeijer.nl>
---
Documentation/RelNotes-1.6.1.txt | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/Documentation/RelNotes-1.6.1.txt b/Documentation/RelNotes-1.6.1.txt
index 9f5c0b5..9593075 100644
--- a/Documentation/RelNotes-1.6.1.txt
+++ b/Documentation/RelNotes-1.6.1.txt
@@ -70,7 +70,7 @@ on.
subsequent "git diff" will show a diff as if they are creation events.
* "git add" gained a built-in synonym for people who want to say "stage
- changes" instead of "add contents the the staging area" which amounts
+ changes" instead of "add contents to the staging area" which amounts
to the same thing.
* "git apply" learned --include=paths option, similar to the existing
--
1.6.1.rc1.57.g71562
^ permalink raw reply related
* [PATCH] Documentation: Remove duplicated info from RelNotes-1.6.1
From: Jakub Narebski @ 2008-12-06 22:36 UTC (permalink / raw)
To: git; +Cc: Jakub Narebski
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
I feel a bit silly signing off such simple patch.
The duplicated contents is:
* "git diff" learned to put more sensible hunk headers for Python,
HTML and ObjC contents.
There are two entries which talk about nearly the same things, but
I am not sure there if it is duplication or not:
* "git diff" learned "textconv" filters --- a binary or hard-to-read
contents can be munged into human readable form and the difference
between the results of the conversion can be viewed (obviously this
cannot produce a patch that can be applied, so this is disabled in
format-patch among other things).
* a "textconv" filter that makes binary files textual form for human
consumption can be specified as an attribute for paths; "git diff"
learnt to make use of it.
Documentation/RelNotes-1.6.1.txt | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/Documentation/RelNotes-1.6.1.txt b/Documentation/RelNotes-1.6.1.txt
index 9f5c0b5..a82e2ae 100644
--- a/Documentation/RelNotes-1.6.1.txt
+++ b/Documentation/RelNotes-1.6.1.txt
@@ -135,8 +135,6 @@ on.
cannot produce a patch that can be applied, so this is disabled in
format-patch among other things).
-* "git diff" hunk header pattern for ObjC has been added.
-
* "--cached" option to "git diff has an easier to remember synonym "--staged",
to ask "what is the difference between the given commit and the
contents staged in the index?"
--
1.6.0.4
^ permalink raw reply related
* [EGIT PATCH] Drop StGit support
From: Robin Rosenberg @ 2008-12-06 23:01 UTC (permalink / raw)
To: spearce; +Cc: git, Robin Rosenberg
It is slow and none of the jgit/egit developers use it.
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
.../internal/decorators/GitResourceDecorator.java | 20 ++----
.../src/org/spearce/jgit/lib/Repository.java | 62 --------------------
2 files changed, 7 insertions(+), 75 deletions(-)
This applies on top of the close outputstream bugfix patch posted recently.
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java
index 1055fcc..97a0311 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java
@@ -322,19 +322,13 @@ public void decorate(final Object element, final IDecoration decoration) {
Repository repo = mapped.getRepository();
try {
String branch = repo.getBranch();
- if (repo.isStGitMode()) {
- String patch = repo.getPatch();
- decoration.addSuffix(" [StGit " + patch + "@" + branch
- + "]");
- } else {
- RepositoryState repositoryState = repo.getRepositoryState();
- String statename;
- if (repositoryState.equals(RepositoryState.SAFE))
- statename = "";
- else
- statename = repositoryState.getDescription() + " ";
- decoration.addSuffix(" [Git " + statename + "@ " + branch + "]");
- }
+ RepositoryState repositoryState = repo.getRepositoryState();
+ String statename;
+ if (repositoryState.equals(RepositoryState.SAFE))
+ statename = "";
+ else
+ statename = repositoryState.getDescription() + " ";
+ decoration.addSuffix(" [Git " + statename + "@ " + branch + "]");
} catch (IOException e) {
e.printStackTrace();
decoration.addSuffix(" [Git ?]");
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
index da1494f..b63ef18 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -58,7 +58,6 @@
import org.spearce.jgit.errors.IncorrectObjectTypeException;
import org.spearce.jgit.errors.RevisionSyntaxException;
-import org.spearce.jgit.stgit.StGitPatch;
import org.spearce.jgit.util.FS;
/**
@@ -988,67 +987,6 @@ public Ref peel(final Ref ref) {
return ret;
}
- /**
- * @return true if HEAD points to a StGit patch.
- */
- public boolean isStGitMode() {
- File file = new File(getDirectory(), "HEAD");
- BufferedReader reader = null;
- try {
- reader = new BufferedReader(new FileReader(file));
- String string = reader.readLine();
- if (!string.startsWith("ref: refs/heads/"))
- return false;
- String branch = string.substring("ref: refs/heads/".length());
- File currentPatches = new File(new File(new File(getDirectory(),
- "patches"), branch), "applied");
- if (!currentPatches.exists())
- return false;
- if (currentPatches.length() == 0)
- return false;
- return true;
-
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- } finally {
- try {
- if (reader != null)
- reader.close();
- } catch (IOException e1) {
- // nothing to do here
- }
- }
- }
-
- /**
- * @return applied patches in a map indexed on current commit id
- * @throws IOException
- */
- public Map<ObjectId,StGitPatch> getAppliedPatches() throws IOException {
- Map<ObjectId,StGitPatch> ret = new HashMap<ObjectId,StGitPatch>();
- if (isStGitMode()) {
- File patchDir = new File(new File(getDirectory(),"patches"),getBranch());
- BufferedReader apr = new BufferedReader(new FileReader(new File(patchDir,"applied")));
- try {
- for (String patchName=apr.readLine(); patchName!=null; patchName=apr.readLine()) {
- File topFile = new File(new File(new File(patchDir,"patches"), patchName), "top");
- BufferedReader tfr = new BufferedReader(new FileReader(topFile));
- try {
- String objectId = tfr.readLine();
- ObjectId id = ObjectId.fromString(objectId);
- ret.put(id, new StGitPatch(patchName, id));
- } finally {
- tfr.close();
- }
- }
- } finally {
- apr.close();
- }
- }
- return ret;
- }
-
/** Clean up stale caches */
public void refreshFromDisk() {
refs.clearCache();
--
1.6.0.3.640.g6331a
^ permalink raw reply related
* Re: git tag -s: TAG_EDITMSG should not be deleted upon failures
From: Junio C Hamano @ 2008-12-06 23:00 UTC (permalink / raw)
To: Jeff King; +Cc: Christian Jaeger, Git Mailing List
In-Reply-To: <20081206215400.GA29440@coredump.intra.peff.net>
Jeff King <peff@peff.net> writes:
> Much better, though the message is a bit awkward. How about
>
> "The tag message has been left in %s"
>
> ?
>
> Do you want me to resend, or do you want to fix up locally?
I'll squash these two plus your wording fix (with trailing LF) in to your
original patch. Thanks.
^ permalink raw reply
* [RFC PATCH v3 0/2] fetch-pack: log(n)-transmission find_common()
From: Thomas Rast @ 2008-12-06 23:20 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nicolas Pitre, Nanako Shiraishi
In-Reply-To: <alpine.LFD.2.00.0810281034500.13034@xanadu.home>
If you still know what this was about, you can skip ahead to the "=="
marker below.
The mail that started it all was
http://kerneltrap.org/mailarchive/git/2008/9/17/3328364
[Abstract:]
Using two passes, first exponential stride through history, then
bisection on the "right" windows, we implement the find_common
handshake in log(history_size) many transmissions. The followup
patch partially achieves that, but a few points are open and strict
backwards compatibility is missing (but its absence is Mostly
Harmless).
This spawned out of a problem originally reported on IRC where pulling
several disjoint histories together takes ages (due to the load on the
server caused by ok_to_give_up()). Apparently this is a common
workflow in the Ruby-on-Rails. The bound on the number of
transmissions holds in other cases too, of course.
The idea attracted some interest, but to my knowledge nobody actually
reviewed the code, and it eventually died because of Nicholas's
finding:
Nicolas Pitre wrote:
> FWIW, I had to back this patch out from my version as things seemed to
> fall into an infinite loop of ref negotiation while fetching the Linux
> kernel repository at some point. Doing a "git fetch -v -v" turned up an
> endless stream of "got" and "have" lines. I was in a hurry for $work so
> didn't think of preserving my local refs for reproduction of the
> problem.
Unfortunately, I was never able to reliably reproduce this problem.
(IIRC I did once when running an automated hammering script but it
vanished when I tried again manually.)
==
After a long break, I decided to pick this up again. I'm not sure
this is the best time to do so, but I had the time to spare, and
(unless there are more serious bugs, and Gods and Junio willing) we
might get it into 'next' sometime early in the next cycle for better
testing.
I rewrote the core of the algorithm, though some helpers and most of
the glue to surrounding routines are still the same. I took the
following design decisions that weren't in v2:
0. Lots of comments. Well, by my standards in any case.
1. The old code stays. I mostly want to make it (far) easier to be
certain that it behaves exactly as before if the server does not
support disabling ok_to_give_up(). [The idea is that it should be
easy to verify that 1/2 is a no-change refactoring and 2/2 only
does something if the server supports it.]
2. The work list now uses a Fibonacci heap to order jobs. I'm not
religious about the specific flavour of heap, but I had the
description of these handy. (The work list can get rather large.)
3. The bisection is essentially precomputed. By staring at the binary
representation of the distance from the starting commit hard
enough, it can be constructed during the stride pass. Barring a
circular bisection "tree", the algorithm is now guaranteed to
terminate even if it, say, emits too many or too few sha1s due to
some other bug.
The last point of course means that the main work is now in the
tangled mess that is get_rev_new_stride(), and "staring hard enough"
frequently enough meant grabbing a notepad. YMMV.
While I did run a lot of tests, including 'make test' and some
automated hammering, it seems quite hard to make sure it _really_
bisects correctly (except manually in toy examples, such as two linear
histories with a common base). Suggestions for automated tests
welcome.
To see the effects of the patch, try
git fetch-pack -v -k <url> <head> 2>&1 \
| git name-rev --stdin refs/heads/master
with a daemon that supports the feature.
^ permalink raw reply
* [RFC PATCH v3 1/2] fetch-pack: rearrange main loop
From: Thomas Rast @ 2008-12-06 23:20 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nicolas Pitre, Nanako Shiraishi
In-Reply-To: <1228605621-29685-1-git-send-email-trast@student.ethz.ch>
This patch does not change the results (nor any of the semantics
except for the get_rev return type), but we need the changed layout
for the exponential-stride feature.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
builtin-fetch-pack.c | 108 +++++++++++++++++++++++++++++--------------------
1 files changed, 64 insertions(+), 44 deletions(-)
diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c
index 372bfa2..ae0a67a 100644
--- a/builtin-fetch-pack.c
+++ b/builtin-fetch-pack.c
@@ -111,7 +111,7 @@ static void mark_common(struct commit *commit,
Get the next rev to send, ignoring the common.
*/
-static const unsigned char* get_rev(void)
+static struct commit* get_rev(void)
{
struct commit *commit = NULL;
@@ -153,15 +153,41 @@ static const unsigned char* get_rev(void)
rev_list = rev_list->next;
}
- return commit->object.sha1;
+ return commit;
}
+/*
+ * Send 'have' for the next batch of revisions. Returns 0 if we ran
+ * out of commits to send, 1 otherwise.
+ */
+
+static int send_have_lines(int fd[2], int *flushes, unsigned *in_vain)
+{
+ struct commit *commit;
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ commit = get_rev();
+ if (!commit)
+ return 0;
+ packet_write(fd[1], "have %s\n",
+ sha1_to_hex(commit->object.sha1));
+ if (args.verbose)
+ fprintf(stderr, "have %s\n",
+ sha1_to_hex(commit->object.sha1));
+ }
+ packet_flush(fd[1]);
+ *flushes += 1;
+ *in_vain += 32;
+ return 1;
+}
+
+
static int find_common(int fd[2], unsigned char *result_sha1,
struct ref *refs)
{
int fetching;
int count = 0, flushes = 0, retval;
- const unsigned char *sha1;
unsigned in_vain = 0;
int got_continue = 0;
@@ -243,51 +269,45 @@ static int find_common(int fd[2], unsigned char *result_sha1,
flushes = 0;
retval = -1;
- while ((sha1 = get_rev())) {
- packet_write(fd[1], "have %s\n", sha1_to_hex(sha1));
- if (args.verbose)
- fprintf(stderr, "have %s\n", sha1_to_hex(sha1));
- in_vain++;
- if (!(31 & ++count)) {
- int ack;
- packet_flush(fd[1]);
- flushes++;
+ /*
+ * We keep one window "ahead" of the other side, and
+ * will wait for an ACK only on the next one
+ */
+ if (!send_have_lines(fd, &flushes, &in_vain))
+ goto done;
- /*
- * We keep one window "ahead" of the other side, and
- * will wait for an ACK only on the next one
- */
- if (count == 32)
- continue;
+ while (send_have_lines(fd, &flushes, &in_vain)) {
+ int ack;
+ int unwound = 0;
- do {
- ack = get_ack(fd[0], result_sha1);
- if (args.verbose && ack)
- fprintf(stderr, "got ack %d %s\n", ack,
- sha1_to_hex(result_sha1));
- if (ack == 1) {
- flushes = 0;
- multi_ack = 0;
- retval = 0;
- goto done;
- } else if (ack == 2) {
- struct commit *commit =
- lookup_commit(result_sha1);
- mark_common(commit, 0, 1);
- retval = 0;
- in_vain = 0;
- got_continue = 1;
- }
- } while (ack);
- flushes--;
- if (got_continue && MAX_IN_VAIN < in_vain) {
- if (args.verbose)
- fprintf(stderr, "giving up\n");
- break; /* give up */
+ do {
+ ack = get_ack(fd[0], result_sha1);
+ if (args.verbose && ack)
+ fprintf(stderr, "got ack %d %s\n", ack,
+ sha1_to_hex(result_sha1));
+ if (ack == 1) {
+ flushes = 0;
+ multi_ack = 0;
+ retval = 0;
+ goto done;
+ } else if (ack == 2) {
+ struct commit *commit =
+ lookup_commit(result_sha1);
+ mark_common(commit, 0, 1);
+ retval = 0;
+ in_vain = 0;
+ got_continue = 1;
}
+ } while (ack);
+ flushes--;
+ if (got_continue && MAX_IN_VAIN < in_vain) {
+ if (args.verbose)
+ fprintf(stderr, "giving up\n");
+ break; /* give up */
}
}
+
done:
packet_write(fd[1], "done\n");
if (args.verbose)
--
tg: (7f705dc..) t/fp-refactor (depends on: origin/master)
^ permalink raw reply related
* [RFC PATCH v3 2/2] fetch-pack: log(n)-transmission find_common()
From: Thomas Rast @ 2008-12-06 23:20 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nicolas Pitre, Nanako Shiraishi
In-Reply-To: <1228605621-29685-2-git-send-email-trast@student.ethz.ch>
Replaces the existing simple history search with a more sophisticated
algorithm:
1) Walk history with exponentially increasing stride lengths; i.e.,
send the 1st commit, then the 2nd after that, then the 4th after
that, and so on.
2) Bisect the resulting intervals.
Combined with tracking the "outstanding haves" so that we can detect
which sha1s were never ACKed by upload-pack (and hence not common),
this gives O(log(n)) required "have" lines.
Unfortunately this cannot work if the server sends fake ACKs, so we
introduce a capability 'no-giveup' which instructs upload-pack to
disable ok_to_give_up(). (Which incidentally saves the server a lot
of work.)
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
builtin-fetch-pack.c | 789 +++++++++++++++++++++++++++++++++++++++++++++++++-
upload-pack.c | 7 +-
2 files changed, 787 insertions(+), 9 deletions(-)
diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c
index ae0a67a..ea88e28 100644
--- a/builtin-fetch-pack.c
+++ b/builtin-fetch-pack.c
@@ -9,6 +9,7 @@
#include "fetch-pack.h"
#include "remote.h"
#include "run-command.h"
+#include <string.h>
static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1;
@@ -25,6 +26,14 @@ static const char fetch_pack_usage[] =
#define COMMON_REF (1U << 2)
#define SEEN (1U << 3)
#define POPPED (1U << 4)
+#define BISECTED_FW (1U << 5)
+#define BISECTED_BW (1U << 6)
+#define NOTCOMMON (1U << 7)
+#define HAS_INFO (1U << 8)
+#define PARSED_WITH_PARENTS (1U << 9)
+#define CLEAN_MARKS (COMMON | COMMON_REF | SEEN | POPPED | BISECTED_FW \
+ | BISECTED_BW | NOTCOMMON | HAS_INFO \
+ | PARSED_WITH_PARENTS)
static int marked;
@@ -34,8 +43,61 @@ static int marked;
*/
#define MAX_IN_VAIN 256
+struct work_heap
+{
+ struct work_heap *next;
+ struct work_heap *prev;
+ struct work_item *item;
+};
+
+struct work_item
+{
+ /* Fibonacci heap data */
+ /* we don't need a parent pointer because we don't support changing keys */
+ struct work_item *child;
+ struct work_item *sibling;
+ int rank;
+ int marked;
+
+ /* actual content */
+ struct commit *commit;
+ unsigned int stride; /* for stride mode */
+ unsigned int steps;
+ unsigned int depth;
+ unsigned int bisect; /* for bisection mode */
+
+ /*
+ * Helper array to generate the bisection order. A size of 32
+ * is ok as long as the history length is less than 2**32.
+ */
+ struct commit **ladder;
+};
+
+/*
+ * "Recursion stack" of the exponential-stride algorithm
+ *
+ * This is a priority queue implemented as a Fibonacci heap since we
+ * expect to stuff a lot of commits into it.
+ */
+static struct work_heap *work_heap = NULL;
+static struct work_heap *work_min = NULL;
+
+/* list of commits not ACKed yet */
+static struct commit_list *outstanding = NULL;
+static struct commit_list *outstanding_end = NULL;
+
+struct commit_info
+{
+ struct commit_list *children;
+ struct commit_list *bisect_forward;
+ struct commit_list *bisect_backward;
+ struct commit_list *forward_bound;
+ struct commit_list *backward_bound;
+};
+
static struct commit_list *rev_list;
static int non_common_revs, multi_ack, use_sideband;
+static int exp_stride_algorithm;
static void rev_list_push(struct commit *commit, int mark)
{
@@ -68,8 +130,7 @@ static int clear_marks(const char *path, const unsigned char *sha1, int flag, vo
struct object *o = deref_tag(parse_object(sha1), path, 0);
if (o && o->type == OBJ_COMMIT)
- clear_commit_marks((struct commit *)o,
- COMMON | COMMON_REF | SEEN | POPPED);
+ clear_commit_marks((struct commit *)o, CLEAN_MARKS);
return 0;
}
@@ -107,6 +168,354 @@ static void mark_common(struct commit *commit,
}
}
+static struct commit_info *get_commit_info(struct commit *commit)
+{
+ if (commit->object.flags & HAS_INFO)
+ return commit->util;
+
+ struct commit_info *info = xmalloc(sizeof(struct commit_info));
+ info->children = NULL;
+ info->bisect_forward = NULL;
+ info->bisect_backward = NULL;
+ info->forward_bound = NULL;
+ info->backward_bound = NULL;
+ commit->util = info;
+ commit->object.flags |= HAS_INFO;
+ return info;
+}
+
+static void add_child(struct commit *parent, struct commit *child)
+{
+ struct commit_info *info = get_commit_info(parent);
+ struct commit_list *item;
+ for (item = info->children; item; item = item->next)
+ if (item->item == child)
+ break;
+ if (!item)
+ commit_list_insert(child, &(info->children));
+}
+
+/* implemented further below */
+static void mark_not_common(struct commit *commit);
+
+static void check_parsed_and_mark(struct commit *commit)
+{
+ struct commit_list *parent;
+
+ if (!commit || commit->object.flags & PARSED_WITH_PARENTS)
+ return;
+
+ parse_commit(commit);
+
+ commit->object.flags |= PARSED_WITH_PARENTS;
+
+ for (parent = commit->parents; parent; parent = parent->next) {
+ add_child(parent->item, commit);
+ if (parent->item->object.flags & NOTCOMMON)
+ mark_not_common(commit);
+ }
+}
+
+static void work_item_free(struct work_item *item)
+{
+ if (!item->bisect)
+ free(item->ladder);
+ free(item);
+}
+
+/*
+ * Ordering imposed on the "recursion" that generates the commits.
+ * The smallest item is processed first. To maintain the O(log n)
+ * transmissions bound we want to achieve, bisections must come after
+ * (compare >0) strides.
+ */
+
+static int work_item_cmp(struct work_item *a, struct work_item *b)
+{
+ if (a->bisect || b->bisect) {
+ /* bisections last */
+ if (a->bisect > b->bisect)
+ return 1;
+ else if (a->bisect < b->bisect)
+ return -1;
+
+ /* older commits later */
+ if (a->commit->date < b->commit->date)
+ return 1;
+ else if (a->commit->date == b->commit->date)
+ return 0;
+ else
+ return -1;
+ } else {
+ /* deeper sidelines of history later */
+ if (a->depth > b->depth)
+ return 1;
+ else if (a->depth < b->depth)
+ return -1;
+
+ /* older commits later */
+ if (a->commit->date < b->commit->date)
+ return 1;
+ else if (a->commit->date == b->commit->date)
+ return 0;
+ else
+ return -1;
+ }
+}
+
+/*
+ * Insert/remove items from the work_heap. _pop() always returns the
+ * smallest one.
+ */
+
+static void work_heap_insert_internal(struct work_item *item)
+{
+ struct work_heap *entry = xmalloc(sizeof(struct work_heap));
+ entry->item = item;
+
+ if (!work_heap) {
+ entry->prev = entry;
+ entry->next = entry;
+ work_heap = entry;
+ work_min = work_heap;
+ return;
+ }
+
+ entry->next = work_heap;
+ entry->prev = work_heap->prev;
+ work_heap->prev = entry;
+ entry->prev->next = entry;
+ if (!work_min || work_item_cmp(item, work_min->item) < 0)
+ work_min = entry;
+ work_heap = entry;
+}
+
+static void work_heap_insert(struct work_item *item)
+{
+ item->marked = 0;
+ item->child = NULL;
+ item->sibling = NULL;
+ item->rank = 0;
+
+ work_heap_insert_internal(item);
+}
+
+static struct work_item *work_heap_pop(void)
+{
+ struct work_heap *entry = work_min;
+ struct work_item *x, *y, *t;
+ struct work_item *child, *item;
+ /* The rank of any child in a Fib heap of size n can be at
+ * most log_{3/2}(n), and we only support 2**32 items
+ * anyway */
+ struct work_item *ranks[55] = {0,};
+ int i;
+
+ if (!entry)
+ return NULL;
+
+ if (entry == entry->prev) {
+ work_heap = NULL;
+ work_min = NULL;
+ item = entry->item;
+ free(entry);
+ for (child = item->child; child; child = child->sibling) {
+ child->marked = 0;
+ work_heap_insert_internal(child);
+ }
+ return item;
+ }
+
+ work_heap = entry->next;
+ entry->next->prev = entry->prev;
+ entry->prev->next = entry->next;
+ item = entry->item;
+ free(entry);
+ work_min = NULL;
+
+ for (child = item->child; child; child = child->sibling) {
+ child->marked = 0;
+ work_heap_insert_internal(child);
+ }
+
+ while (work_heap) {
+ entry = work_heap;
+ if (entry == entry->prev) {
+ work_heap = NULL;
+ } else {
+ work_heap = entry->next;
+ entry->next->prev = entry->prev;
+ entry->prev->next = entry->next;
+ }
+ x = entry->item;
+ free(entry);
+ while ((y = ranks[x->rank])) {
+ ranks[x->rank] = NULL;
+ if (work_item_cmp(x, y) > 0) {
+ t = x;
+ x = y;
+ y = t;
+ }
+ y->sibling = x->child;
+ x->child = y;
+ x->rank++;
+ }
+ ranks[x->rank] = x;
+ }
+
+ for (i = 0; i < 55; i++)
+ if (ranks[i])
+ work_heap_insert_internal(ranks[i]);
+
+ return item;
+}
+
+static void work_insert_stride(struct commit *commit, int stride,
+ int steps, int depth, struct commit **ladder)
+{
+ struct work_item *item = xmalloc(sizeof(struct work_item));
+ check_parsed_and_mark(commit);
+ item->commit = commit;
+ item->stride = stride;
+ item->steps = steps;
+ item->depth = depth;
+ item->bisect = 0;
+ item->ladder = xmalloc(32*sizeof(struct commit *));
+ if (ladder)
+ memcpy(item->ladder, ladder, 32*sizeof(struct commit *));
+ work_heap_insert(item);
+}
+
+static void work_insert_bisect(struct commit *commit, int bisect)
+{
+ struct work_item *item = xmalloc(sizeof(struct work_item));
+ item->commit = commit;
+ item->stride = 0;
+ item->steps = 0;
+ item->depth = 0;
+ item->bisect = bisect;
+ item->ladder = NULL;
+ work_heap_insert(item);
+}
+
+static void work_insert_strides(struct commit_list *commits,
+ int stride, int steps, int depth, int depth2,
+ struct commit **ladder,
+ struct work_item *reusable_item)
+{
+ struct work_item *item = reusable_item;
+
+ while (commits) {
+ if (!(commits->item->object.flags &= SEEN)) {
+ if (!item)
+ item = xmalloc(sizeof(struct work_item));
+
+ item->commit = commits->item;
+ item->stride = stride;
+ item->steps = steps;
+ item->depth = depth;
+ item->bisect = 0;
+ item->ladder = xmalloc(32*sizeof(struct commit *));
+ if (ladder)
+ memcpy(item->ladder, ladder, 32*sizeof(struct commit *));
+ work_heap_insert(item);
+ }
+ commits = commits->next;
+ item = NULL;
+ depth = depth2;
+ }
+
+ if (item)
+ work_item_free(item);
+}
+
+static void work_insert_bisects(struct commit_list *commits,
+ int bisect,
+ struct work_item *reusable_item)
+{
+ struct work_item *item = reusable_item;
+
+ while (commits) {
+ if (!item)
+ item = xmalloc(sizeof(struct work_item));
+
+ item->commit = commits->item;
+ item->stride = 0;
+ item->steps = 0;
+ item->depth = 0;
+ item->bisect = bisect;
+ work_heap_insert(item);
+
+ commits = commits->next;
+ item = NULL;
+ }
+
+ if (item)
+ work_item_free(item);
+}
+
+static int work_heap_insert_ref(const char *path, const unsigned char *sha1,
+ int flag, void *cb_data)
+{
+ struct object *o = deref_tag(parse_object(sha1), path, 0);
+
+ if (o && o->type == OBJ_COMMIT && !(o->flags & SEEN))
+ work_insert_stride((struct commit *)o, 0, 0, 0, NULL);
+
+ return 0;
+}
+
+
+/*
+ * Marks all (known) children of this commit NOTCOMMON. We call this
+ * for all sha1s the server did not ACK.
+ */
+
+static void mark_not_common(struct commit *commit)
+{
+ struct commit_info *info = get_commit_info(commit);
+ struct commit_list *child;
+
+ assert(!(commit->object.flags & COMMON));
+
+ if (commit->object.flags & NOTCOMMON)
+ return;
+
+ commit->object.flags |= NOTCOMMON;
+
+ for (child = info->children; child; child = child->next)
+ mark_not_common(child->item);
+}
+
+/*
+ * Similar for the ACKed ones. We have a _new() version because the
+ * old one interacts with the work queue.
+ */
+
+static void mark_common_new(struct commit *commit, int ancestors_only, int dont_parse)
+{
+ struct commit_list *parents;
+ struct object *o;
+
+ if (commit == NULL || commit->object.flags & (COMMON_REF|COMMON))
+ return;
+
+ if (!dont_parse && !(commit->object.parsed))
+ check_parsed_and_mark(commit);
+
+ o = (struct object *)commit;
+
+ if (!ancestors_only)
+ o->flags |= COMMON;
+
+ for (parents = commit->parents; parents; parents = parents->next) {
+ add_child(parents->item, commit);
+ mark_common_new(parents->item, 0, dont_parse);
+ }
+}
+
+
+
/*
Get the next rev to send, ignoring the common.
*/
@@ -156,6 +565,330 @@ static struct commit* get_rev(void)
return commit;
}
+
+int flag_in_list(int flag, struct commit_list *list)
+{
+ while (list) {
+ if (list->item->object.flags & flag)
+ return 1;
+ list = list->next;
+ }
+ return 0;
+}
+
+
+/*
+ * Find the second bit set in x, similar to ffs() from string.h.
+ * Assumes that x>0.
+ */
+
+int fss(int x)
+{
+ return ffs(x - (1<<(ffs(x)-1)));
+}
+
+/*
+ * The exponential-stride algorithm, part 1 and 1.5.
+ *
+ * We take exponential strides through history, that is we emit the
+ * 1st commit, the 2nd, the 4th, etc. But we also simultaneously
+ * build pointers that help us bisect later: Every commit has a
+ * bisect_forward and bisect_backward list (if history is linear, both
+ * have at most 1 element) that tells us where to continue bisection
+ * after this.
+ *
+ * To achieve this with good running time, we think of the commits in
+ * a line of history as being numbered in binary:
+ *
+ * o 1000
+ * o 111
+ * o 110 <- current [1]
+ * o 101 [0]
+ * t | o 100 [2]
+ * i | o 11
+ * m | o 10
+ * e v o 1
+ *
+ * Every commit of the form 10...0 is emitted, since it is an
+ * exponential step. Between that, we want to have
+ * (100).bisect_backward=[110], (110).bisect_forward=[101],
+ * (110).bisect_backward=[111], etc. Define the lowest bit set (as
+ * per ffs()-1) in a commit as its "order", then we can achieve this
+ * by keeping track of the last commit of every order (marked with [n]
+ * in the diagram) as we go through history. Then [n] must be on
+ * [n+1].bisect_backward and [n-1] must be on [n].bisect_forward.
+ *
+ * Similarly, we track the boundaries forward_bound and
+ * backward_bound, which indicate the furthest commit(s) that can be
+ * reached by bisecting this one. We use them to detect when it
+ * becomes pointless to pursue this branch of the bisection because
+ * the far end is already COMMON (NOTCOMMON) in forward (backward)
+ * mode. In the scheme chosen, a current commit [n] numbered N is a
+ * backward boundary of [i] for all i=0..n, and [fss(N)-1] is a
+ * forward boundary of the current [n].
+ *
+ * The tough problem is if we stop (because we hit a root, or a part
+ * of history that we've already seen) at a non-exp-stride commit.
+ * Then we must ensure that all history up to the current commit can
+ * be reached by bisecting. Consider
+ *
+ * o 1000
+ * o 111
+ * o 110
+ * o 101 <- current [0]
+ * t | o 100 [2]
+ * i | o 11
+ * m | o 10 [1]
+ * e v o 1
+ *
+ * then stopping at the commit 101 without any corrective measures
+ * would leave it unreachable because the intermediate step 110 has
+ * not been seen yet.
+ *
+ * Observe that any given commit x10z, where x is arbitrary and z only
+ * zeros, has outgoing pointers to x01z (forward) and x11z (backward).
+ * Conversely this means x01z needs an incoming forward pointer from
+ * x10z, even if we haven't seen it yet. So there are two cases:
+ *
+ * SEEN CASE: We stopped because we hit a SEEN commit. Assume that
+ * the last commit not SEEN is numbered x1y1z, where x is arbitrary
+ * and y and z are only zeros (z possibly empty). Then unless y is
+ * empty, x1y'01z needs an incoming forward pointer from x1y'10z
+ * (where y'0=y), which we haven't seen yet. Repeat until y is empty.
+ * Note that during this repetition, we might hit a root commit.
+ *
+ * ROOT CASE: We cannot fix this with forward pointers since there are
+ * no commits left to put them in. Assume that the root commit is
+ * numbered x1y1z as in the SEEN case. Then we fix by pointing a
+ * backwards pointer from x1y'00z to x1y'01z, then iterate with
+ * x1y'00z. Note that x1y'00z is the last seen commit of order
+ * fss(x1y1z).
+ *
+ * Note that we only need to bisect (first level) exp-stride commits
+ * in one direction. We choose backward. This choice needs to be
+ * consistent among get_rev_new_stride() and get_rev_new(), and it
+ * happens to match the faster code path of get_rev_new_bisect().
+ */
+
+static struct commit *get_rev_new_stride(struct work_item *item)
+{
+ struct commit_info *info;
+ struct commit *commit = item->commit;
+ int steps = item->steps;
+ int stride = item->stride;
+ int depth = item->depth;
+ int order = -1;
+ struct commit **ladder = item->ladder;
+ int i;
+ /* The next two are for the pointer-fixing iterations */
+ int order2;
+ struct commit *commit2;
+
+ while (!(commit->object.flags & SEEN)) {
+ steps++;
+ order = ffs(steps)-1;
+
+ commit->object.flags |= SEEN;
+
+ if (order > 0 && stride == order) {
+ info = get_commit_info(ladder[order-1]);
+ commit_list_insert(commit, &info->backward_bound);
+ for (i = order-2; i>=0; i--) {
+ info = get_commit_info(ladder[i]);
+ commit_list_insert(commit, &info->backward_bound);
+ }
+ }
+
+ ladder[order] = commit;
+
+ if (stride == order) {
+ /* this is precisely a 2**k'th commit, emit it */
+ work_insert_strides(commit->parents, stride+1, steps,
+ depth, depth+1, ladder, item);
+ return commit;
+ }
+
+ /*
+ * We are the next step in the higher-order commit's
+ * backward (in time) bisection
+ */
+ info = get_commit_info(ladder[order+1]);
+ commit_list_insert(commit, &info->bisect_backward);
+ info = get_commit_info(commit);
+ commit_list_insert(ladder[fss(steps)-1], &info->forward_bound);
+
+ if (order > 0) {
+ /*
+ * The lower-order commit is our next step for
+ * forward (in time) bisection
+ */
+ info = get_commit_info(commit);
+ commit_list_insert(ladder[order-1], &info->bisect_forward);
+ for (i = order-1; i >= 0; i--) {
+ info = get_commit_info(ladder[i]);
+ commit_list_insert(commit, &info->backward_bound);
+ }
+ }
+
+ if (commit->parents) {
+ work_insert_strides(commit->parents->next, stride,
+ steps, depth+1, depth+1, ladder,
+ NULL);
+ commit = commit->parents->item;
+ check_parsed_and_mark(commit);
+ } else {
+ /* ROOT CASE: fix missing pointers */
+ order2 = fss(steps)-1;
+ commit2 = commit;
+ while (order != order2-1 && order2 > 0) {
+ info = get_commit_info(ladder[order2]);
+ commit_list_insert(commit2, &info->bisect_backward);
+ info = get_commit_info(commit2);
+ commit_list_insert(ladder[order2], &info->forward_bound);
+ commit2 = ladder[order2];
+ steps -= 1 << order;
+ order = order2;
+ order2 = fss(steps)-1;
+ }
+ work_item_free(item);
+ return commit;
+ }
+ }
+
+ if (order == -1) {
+ /* this just means we hit a SEEN commit immediately */
+ work_item_free(item);
+ return NULL;
+ }
+
+ /* SEEN CASE: fix missing pointers w.r.t. the _last_ commit
+ * before this */
+
+ /* unless/until we hit a root, 'commit' tracks the steps
+ * backward through the SEEN commits that we stick the
+ * pointers in. 'order2' only serves to figure out if the 'y'
+ * (see comment at function head) of 'commit' is empty. */
+ order2 = fss(steps)-1;
+ assert(order2 > order || order2 == 0);
+ while (order != order2-1 && order2 > 0) {
+ int i;
+ /* skip ahead to the next commit2 of order 'order+1' */
+ for (i = (1<<order); i > 0; i--) {
+ steps++;
+ assert (steps < (1<<stride));
+ if (commit->parents) {
+ commit = commit->parents->item;
+ check_parsed_and_mark(commit);
+ continue;
+ }
+ /* we hit a root commit! use the root strategy
+ * for the rest */
+ order2 = fss(steps)-1;
+ commit2 = commit;
+ while (order != order2-1 && order2 > 0) {
+ info = get_commit_info(ladder[order2]);
+ commit_list_insert(commit2, &info->bisect_backward);
+ info = get_commit_info(commit2);
+ commit_list_insert(ladder[order2], &info->forward_bound);
+ commit2 = ladder[order2];
+ steps -= 1 << order;
+ order = order2;
+ order2 = fss(steps)-1;
+ }
+ /* short-cut out of the big loop */
+ work_item_free(item);
+ return NULL;
+ }
+ info = get_commit_info(commit);
+ commit_list_insert(ladder[order], &info->bisect_forward);
+ for (i = order; i >= 0; i--) {
+ info = get_commit_info(ladder[i]);
+ commit_list_insert(commit, &info->backward_bound);
+ }
+ order++;
+ /* this has not changed order2. we still keep track
+ * of 'steps' carefully in case we hit a root
+ * commit. */
+ }
+
+ work_item_free(item);
+ return NULL;
+}
+
+/*
+ * The exponential-stride algorithm, part 2.
+ *
+ * Bisecting is now easy: just follow the forward/backward pointers,
+ * stopping when we already know enough to not search any further.
+ */
+
+static struct commit *get_rev_new_bisect(struct work_item *item)
+{
+ struct commit *commit = item->commit;
+ struct commit_info *info = get_commit_info(commit);
+ int flags = commit->object.flags;
+
+ if (!(flags & (BISECTED_FW|NOTCOMMON))
+ && !flag_in_list(COMMON, info->forward_bound)) {
+ commit->object.flags |= BISECTED_FW;
+ work_insert_bisects(info->bisect_forward, item->bisect+1, NULL);
+ if (!(flags & (POPPED|COMMON))) {
+ /* re-queue for backward bisection */
+ work_heap_insert(item);
+ item = NULL;
+ return commit;
+ }
+ }
+
+ if (!(flags & (BISECTED_BW|COMMON))
+ && !flag_in_list(NOTCOMMON, info->backward_bound)) {
+ commit->object.flags |= BISECTED_BW;
+ work_insert_bisects(info->bisect_backward, item->bisect+1, item);
+ item = NULL;
+ if (!(flags & (POPPED|NOTCOMMON)))
+ return commit;
+ }
+
+ if (item)
+ free(item);
+ return NULL;
+}
+
+
+static struct commit* get_rev_new(void)
+{
+ struct commit *commit = NULL;
+ struct work_item *item;
+
+ while (commit == NULL) {
+ item = work_heap_pop();
+ if (!item)
+ return NULL;
+ check_parsed_and_mark(item->commit);
+ if (item->bisect) {
+ commit = get_rev_new_bisect(item);
+ } else {
+ commit = get_rev_new_stride(item);
+ if (commit) {
+ /* there's no point in bisecting the
+ * first level both ways */
+ commit->object.flags |= BISECTED_FW;
+ work_insert_bisect(commit, 1);
+ }
+ }
+ }
+
+ commit->object.flags |= POPPED;
+ return commit;
+}
+
+static void pop_outstanding(void)
+{
+ struct commit_list *item = outstanding;
+ outstanding = item->next;
+ free(item);
+}
+
/*
* Send 'have' for the next batch of revisions. Returns 0 if we ran
* out of commits to send, 1 otherwise.
@@ -167,7 +900,10 @@ static int send_have_lines(int fd[2], int *flushes, unsigned *in_vain)
int i;
for (i = 0; i < 32; i++) {
- commit = get_rev();
+ if (exp_stride_algorithm)
+ commit = get_rev_new();
+ else
+ commit = get_rev();
if (!commit)
return 0;
packet_write(fd[1], "have %s\n",
@@ -175,6 +911,14 @@ static int send_have_lines(int fd[2], int *flushes, unsigned *in_vain)
if (args.verbose)
fprintf(stderr, "have %s\n",
sha1_to_hex(commit->object.sha1));
+
+ if (outstanding) {
+ commit_list_insert(commit, &(outstanding_end->next));
+ outstanding_end = outstanding_end->next;
+ } else {
+ commit_list_insert(commit, &outstanding);
+ outstanding_end = outstanding;
+ }
}
packet_flush(fd[1]);
*flushes += 1;
@@ -195,7 +939,10 @@ static int find_common(int fd[2], unsigned char *result_sha1,
for_each_ref(clear_marks, NULL);
marked = 1;
- for_each_ref(rev_list_insert_ref, NULL);
+ if (exp_stride_algorithm)
+ for_each_ref(work_heap_insert_ref, NULL);
+ else
+ for_each_ref(rev_list_insert_ref, NULL);
fetching = 0;
for ( ; refs ; refs = refs->next) {
@@ -218,7 +965,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
}
if (!fetching)
- packet_write(fd[1], "want %s%s%s%s%s%s%s%s\n",
+ packet_write(fd[1], "want %s%s%s%s%s%s%s%s%s\n",
sha1_to_hex(remote),
(multi_ack ? " multi_ack" : ""),
(use_sideband == 2 ? " side-band-64k" : ""),
@@ -226,6 +973,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
(args.use_thin_pack ? " thin-pack" : ""),
(args.no_progress ? " no-progress" : ""),
(args.include_tag ? " include-tag" : ""),
+ (exp_stride_algorithm ? " no-giveup" : ""),
" ofs-delta");
else
packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
@@ -294,12 +1042,31 @@ static int find_common(int fd[2], unsigned char *result_sha1,
} else if (ack == 2) {
struct commit *commit =
lookup_commit(result_sha1);
- mark_common(commit, 0, 1);
+ if (exp_stride_algorithm) {
+ while (commit != outstanding->item) {
+ if (args.verbose)
+ fprintf(stderr, "unwinding: %s\n", sha1_to_hex(outstanding->item->object.sha1));
+ mark_not_common(outstanding->item);
+ pop_outstanding();
+ unwound++;
+ }
+ pop_outstanding();
+ unwound++;
+ mark_common_new(commit, 0, 1);
+ } else {
+ mark_common(commit, 0, 1);
+ }
retval = 0;
in_vain = 0;
got_continue = 1;
}
} while (ack);
+ while (exp_stride_algorithm && unwound++ < 32) {
+ if (args.verbose)
+ fprintf(stderr, "unwinding: %s\n", sha1_to_hex(outstanding->item->object.sha1));
+ mark_not_common(outstanding->item);
+ pop_outstanding();
+ }
flushes--;
if (got_continue && MAX_IN_VAIN < in_vain) {
if (args.verbose)
@@ -467,7 +1234,10 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
if (!(o->flags & SEEN)) {
rev_list_push((struct commit *)o, COMMON_REF | SEEN);
- mark_common((struct commit *)o, 1, 1);
+ if (exp_stride_algorithm)
+ mark_common_new((struct commit *)o, 1, 1);
+ else
+ mark_common((struct commit *)o, 1, 1);
}
}
@@ -617,6 +1387,11 @@ static struct ref *do_fetch_pack(int fd[2],
fprintf(stderr, "Server supports side-band\n");
use_sideband = 1;
}
+ if (server_supports("no-giveup")) {
+ if (args.verbose)
+ fprintf(stderr, "Server supports no-giveup\n");
+ exp_stride_algorithm = 1;
+ }
if (everything_local(&ref, nr_match, match)) {
packet_flush(fd[1]);
goto all_done;
diff --git a/upload-pack.c b/upload-pack.c
index e5adbc0..8f05dbf 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -37,6 +37,7 @@ static unsigned int timeout;
*/
static int use_sideband;
static int debug_fd;
+static int disable_give_up;
static void reset_timeout(void)
{
@@ -414,7 +415,7 @@ static int get_common_commits(void)
if (!prefixcmp(line, "have ")) {
switch (got_sha1(line+5, sha1)) {
case -1: /* they have what we do not */
- if (multi_ack && ok_to_give_up())
+ if (multi_ack && !disable_give_up && ok_to_give_up())
packet_write(1, "ACK %s continue\n",
sha1_to_hex(sha1));
break;
@@ -501,6 +502,8 @@ static void receive_needs(void)
no_progress = 1;
if (strstr(line+45, "include-tag"))
use_include_tag = 1;
+ if (strstr(line+45, "no-giveup"))
+ disable_give_up = 1;
/* We have sent all our refs already, and the other end
* should have chosen out of them; otherwise they are
@@ -573,7 +576,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
{
static const char *capabilities = "multi_ack thin-pack side-band"
" side-band-64k ofs-delta shallow no-progress"
- " include-tag";
+ " include-tag no-giveup";
struct object *o = parse_object(sha1);
if (!o)
--
tg: (73ef856..) t/fp-speedup (depends on: origin/master t/fp-refactor)
^ permalink raw reply related
* Re: Git Books
From: Deskin Miller @ 2008-12-06 23:48 UTC (permalink / raw)
To: Scott Chacon; +Cc: git list
In-Reply-To: <20081206194515.GA4721@atjola.homenet>
On 2008.12.06 03:58:28 -0800, Scott Chacon wrote:
> So, since I'm near the beginning of this process, I was wondering if
> the group had any feedback as to what might be super helpful to
> include. I mean, I have a pretty good layout and all, but if you
> wanted to point me to some threads that tend to crop up in the mailing
> list and IRC channel from relative newcomers that I might be able to
> nip in the bud, I would like to. I'm addressing the stuff that _I_
> hear a lot, and I'm scanning the IRC logs and list for topics, but I
> figured many of you must answer the same questions all the time, too.
I agree with pretty much all of the other suggestions made thus far.
One I'd vote for is to explain why pushing to a non-bare repository
doesn't magically update the working tree as well; I'd say it's easily
one of the most repeated questions on #git.
I also vote for addressing workflows heavily. Also, I think a reference
section akin to Tv's 'Git for Computer Scientists' page[1] would be
handy; I find understanding how git represents the project to inform
almost every interesting question about how to accomplish one's goals in
a particular situation.
Deskin Miller
[1] http://eagain.net/articles/git-for-computer-scientists/
^ 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