Git development
 help / color / mirror / Atom feed
* Re: The git newbie experience
From: Junio C Hamano @ 2006-05-15  8:39 UTC (permalink / raw)
  To: Shawn Pearce, Tommi Virtanen; +Cc: git
In-Reply-To: <20060515053133.GB28068@spearce.org>

Shawn Pearce <spearce@spearce.org> writes:

>> I'd rather do that with a diff file that can be used to do a
>> 3-way (see how rebase does it with --full-index diff with am -3).
>> No point creating and forgetting to remove a throw away branch
>> and getting more complaints.
>
> How is a quick stash different from a topic branch?

The original version of my message in response to TV looked like
this.

 - Jack is a beginning user of git and does not (want to) understand
   the index (right now).

 - Jack works on branch X, say his HEAD points to X1. He has an edited,
   uncommitted files with the names A, B and C.

 - Jack wants to pull new changes made by others to his branch.
   But "git merge" invoked from "git pull" says he needs to stash
   away the local changes to do the merge.

 - Jack stashes away what he has been working on and cleans up
   his mess.

   git checkout -b stash ;# risks error when "stash" exists
   git commit -a -m 'Stashing WIP'
   git checkout master ;# assuming that was where he was

 - Jack then pulls.  There are merge conflicts in files D, E, ..., Z.

 - Jack resolves the merge conflicts and is ready to commit the resulting
   merge. Note files A, B and C do not have his unfinished work.

   There is no "if Jack does this or that" problem; he says "git
   commit -a" because that is the only "commit" command he knows
   about.

 - Jack then reapplies what he stashed away, and keeps working.

   git pull . --no-commit stash
   git branch -D stash

You have to teach the new user to (1) name something, only to
immediately discard it when he returns to what he was in the
middle of, (2) remember to clean up the temporary thing once he
is done lest he forgets to clean it up (and common names like
"stash", "tmp" will be reused by accident causing grief next
time he needs to do another stash), and (3) use of --no-commit
pull.

On the other hand, "git stash/unstash" workflow would be quite
simple:

	$ git stash >my.precious.state
        ... do whatever you want to deviate to
        $ git unstash <my.precious.state

Merge resolve might be needed while unstashing, but 
we are talking about pulling somebody else's work in "do
whatever" part, so that is something the user knows how to
perform anyway.

A quick and dirty stash implementation would go like this:

Stash is easy.

        #!/bin/sh
        # git stash
        git diff --binary HEAD
        git reset --hard

Unstash is a bit involved.

        #!/bin/sh
        # git unstash
        . git-sh-setup
        O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
        O_DIR=`cd "$GIT_DIR" && pwd`
        stash="$O_DIR/.stash$$"
        rm -fr "$stash.*"
        trap 'rm -rf $stash.*' 0
        cat >"$stash.patch"
        git-apply -z --index-info <"$stash.patch" >"$stash.list"
        GIT_INDEX_FILE="$stash.index"  \
        GIT_OBJECT_DIRECTORY="$O_OBJECT" \
        (
                mkdir -p "$stash.tmp" &&
                git-update-index -z --index-info <"$stash.list" &&
                git-write-tree >"$stash.base" &&
                cd "$stash.tmp" &&
                git-apply --binary --index <"$stash.patch" &&
                git-write-tree >"$stash.his"
        )
        his_tree=$(cat "$stash.his")
        orig_tree=$(cat "$stash.base")
        rm -fr "$stash.*"
        git-merge-resolve $orig_tree -- HEAD $his_tree

This is essentially the core of "am -3" logic; if you are going
to use this for real, you would probably want to see if the
patch applies cleanly before falling back on the three-way
merge, though.

^ permalink raw reply

* Re: Simplify "git reset --hard"
From: Junio C Hamano @ 2006-05-15  7:46 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <7vwtcnvk76.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> writes:

> Junio C Hamano <junkio@cox.net> writes:
>
>>> Instead, just pass in "-u" to git-read-tree when we do a hard reset, and 
>>> depend on git-read-tree to update the working tree appropriately.
>>
>> Well, this is wrong.  Local modifications remain after your
>> version of "git-reset --hard HEAD". which is not what we want
>> from a hard reset.
>
> ... and attempting to paper it over in git-reset.sh is also
> wrong.  Keep your "--hard is noop" change in git-reset.sh and
> replace it with this would be the right fix.

-- >8 --
read-tree -u one-way merge fix to check out locally modified paths.

The "-u" flag means "update the working tree files", but to
other types of merges, it also implies "I want to keep my local
changes" -- because they prevent local changes from getting lost
by using verify_uptodate.  The one-way merge is different from
other merges in that its purpose is opposite of doing something
else while keeping unrelated local changes.  The point of
one-way merge is to nuke local changes.  So while it feels
somewhat wrong that this actively loses local changes, it is the
right thing to do.

The earlier one marked old->ce_flags to be updated
unconditionally, but that would cause 18,000 paths to be updated
when you have only a few paths different from the HEAD you are
switching to, which is far worse than what we used to do in
git-reset by hand.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 * Third time lucky ;-)

diff --git a/read-tree.c b/read-tree.c
index 11157f4..d847c6f 100644
--- a/read-tree.c
+++ b/read-tree.c
@@ -686,6 +698,9 @@ static int oneway_merge(struct cache_ent
 	if (!a)
 		return deleted_entry(old, NULL);
 	if (old && same(old, a)) {
+		struct stat st;
+		if (lstat(old->name, &st) || ce_match_stat(old, &st, 1))
+			old->ce_flags |= htons(CE_UPDATE);
 		return keep_entry(old);
 	}
 	return merged_entry(a, NULL);

^ permalink raw reply related

* Re: Simplify "git reset --hard"
From: Junio C Hamano @ 2006-05-15  7:08 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <7v1wuvwzdv.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> writes:

>> Instead, just pass in "-u" to git-read-tree when we do a hard reset, and 
>> depend on git-read-tree to update the working tree appropriately.
>
> Well, this is wrong.  Local modifications remain after your
> version of "git-reset --hard HEAD". which is not what we want
> from a hard reset.

... and attempting to paper it over in git-reset.sh is also
wrong.  Keep your "--hard is noop" change in git-reset.sh and
replace it with this would be the right fix.

-- >8 --

diff --git a/read-tree.c b/read-tree.c
index 11157f4..c135f08 100644
--- a/read-tree.c
+++ b/read-tree.c
@@ -686,6 +686,7 @@ static int oneway_merge(struct cache_ent
 	if (!a)
 		return deleted_entry(old, NULL);
 	if (old && same(old, a)) {
+		old->ce_flags |= htons(CE_UPDATE);
 		return keep_entry(old);
 	}
 	return merged_entry(a, NULL);

^ permalink raw reply related

* Re: Simplify "git reset --hard"
From: Junio C Hamano @ 2006-05-15  6:55 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0605141110150.3866@g5.osdl.org>

Linus Torvalds <torvalds@osdl.org> writes:

> Now that the one-way merge strategy does the right thing wrt files that do 
> not exist in the result, just remove all the random crud we did in "git 
> reset" to do this all by hand.
>
> Instead, just pass in "-u" to git-read-tree when we do a hard reset, and 
> depend on git-read-tree to update the working tree appropriately.

Well, this is wrong.  Local modifications remain after your
version of "git-reset --hard HEAD". which is not what we want
from a hard reset.

-- >8 --

diff --git a/git-reset.sh b/git-reset.sh
index 0ee3e3e..ecc111b 100755
--- a/git-reset.sh
+++ b/git-reset.sh
@@ -52,7 +52,7 @@ git-update-ref HEAD "$rev"
 
 case "$reset_type" in
 --hard )
-	;; # Nothing else to do
+	git-checkout-index -f -q -u -a ;;
 --soft )
 	;; # Nothing else to do
 --mixed )

^ permalink raw reply related

* Re: how to display file history?
From: Junio C Hamano @ 2006-05-15  6:42 UTC (permalink / raw)
  To: Brown, Len; +Cc: git
In-Reply-To: <CFF307C98FEABE47A452B27C06B85BB670F4FD@hdsmsx411.amr.corp.intel.com>

"Brown, Len" <len.brown@intel.com> writes:

>  
>>	git whatchanged A
>
> thanks.  I've used this on entire repos before, but
> for some reason didn't think of this command name
> when looking for individual file history.

Probably with recent enough git, one of

	git log --stat -- A
	git log -p -- A
	git log -p --full-diff -- A

might be more pleasant, depending on what you are trying to look
for.

"A" can be a single file, more than one files, a directory,...

^ permalink raw reply

* Re: Tracking branch history
From: Shawn Pearce @ 2006-05-15  6:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vac9jx0nq.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> wrote:
> Shawn Pearce <spearce@spearce.org> writes:
> 
> > This is all well and good but its sort of useless without the diffcore
> > being able to lookup what SHA1 was valid on a given branch at a given
> > point in time.  :-)
> >
> > I'm thinking about extending the 'extended SHA1' syntax to accept
> > a date (or date expression) as a suffix:
> >
> > 	HEAD@'2 hours ago'
> > 	HEAD@'2006-04-20'
> > 	HEAD@'2006-04-20 14:12'
> >
> > etc... This would be merged into get_sha1 (sha1_name.c) so its
> > usable pretty much anywhere.  Does this seem reasonable?  If so
> > I'll work up a patch for it.
> 
> HEAD?
> 
> Are you going to hook into symbolic-ref as well to track branch
> switching?

I hadn't planned on it.  I was going to resolve the symref HEAD
down to the real ref (e.g. refs/heads/sp/ref-log) and then do the
date range searching on the real branch.  I didn't think it was
interesting to track what HEAD is.  But I think it would be very
common for the user to use HEAD rather than their actual branch
ref names when forming an expression.
 
[snip]
> The time-warp format would make sense for individual branches,
> like refs/heads/master, though.
> 
> sha1_name.c and sha1_file.c were supposed to be real core, but
> get_sha1() is looking more and more Porcelainish these days, and
> I do not have much problem with being able to say "tip of this
> branch, two hours ago".
> 
> I am not sure about the syntax though.  We would want to be able
> to say "start from the commit that was at the tip of 'master'
> branch two days ago, grab its tree and look at arch/sparc64
> directory", so things like
> 
>             "master@2006-05-14 14:12"
>             "master@2006-05-14 14:12^{tree}"
>             "master@two days ago:arch/sparc64"
> 
> would need to be supported.

Yea, I realize that.  I'm currently looking at get_sha1_1 and how
I can put the date resolution in before the ^, ~ and :.  :-)

-- 
Shawn.

^ permalink raw reply

* Re: Tracking branch history
From: Junio C Hamano @ 2006-05-15  6:27 UTC (permalink / raw)
  To: Shawn Pearce; +Cc: git
In-Reply-To: <20060515055830.GC28068@spearce.org>

Shawn Pearce <spearce@spearce.org> writes:

> This is all well and good but its sort of useless without the diffcore
> being able to lookup what SHA1 was valid on a given branch at a given
> point in time.  :-)
>
> I'm thinking about extending the 'extended SHA1' syntax to accept
> a date (or date expression) as a suffix:
>
> 	HEAD@'2 hours ago'
> 	HEAD@'2006-04-20'
> 	HEAD@'2006-04-20 14:12'
>
> etc... This would be merged into get_sha1 (sha1_name.c) so its
> usable pretty much anywhere.  Does this seem reasonable?  If so
> I'll work up a patch for it.

HEAD?

Are you going to hook into symbolic-ref as well to track branch
switching?

Since there is no reverse pointer to tell which symbolic
reference is pointing at branch heads,and there are symbolic
references like refs/remotes/origin/HEAD that point at
refs/remotes/origin/master, detecting that such and such
symbolic refs are pointing at a branch that is advanced by a
call to update-ref and update the log for the symbolic refs that
point at it becomes rather expensive.
So probably you would need a separate log format that tracks
which concrete ref a symbolic ref was pointing at at any given
time and use that to keep track of them.

I personally doubt it is worth the trouble.  I switch branches
between master, next and the topics all the time, and never is
interested in which branch I happened to be on 30 minutes ago.

The time-warp format would make sense for individual branches,
like refs/heads/master, though.

sha1_name.c and sha1_file.c were supposed to be real core, but
get_sha1() is looking more and more Porcelainish these days, and
I do not have much problem with being able to say "tip of this
branch, two hours ago".

I am not sure about the syntax though.  We would want to be able
to say "start from the commit that was at the tip of 'master'
branch two days ago, grab its tree and look at arch/sparc64
directory", so things like

            "master@2006-05-14 14:12"
            "master@2006-05-14 14:12^{tree}"
            "master@two days ago:arch/sparc64"

would need to be supported.

^ permalink raw reply

* RE: how to display file history?
From: Brown, Len @ 2006-05-15  6:13 UTC (permalink / raw)
  To: spearce; +Cc: git

 
>	git whatchanged A

thanks.  I've used this on entire repos before, but
for some reason didn't think of this command name
when looking for individual file history.

Searching git(7) for "history" didn't take me here.
Searching for "log" would have, but I must have
terminated that search when git-log and git-shortlog
turned out to not be what I was looking for.

-Len

^ permalink raw reply

* Re: [PATCH] send-email: quiet some warnings
From: Junio C Hamano @ 2006-05-15  6:04 UTC (permalink / raw)
  To: Eric Wong; +Cc: git
In-Reply-To: <11476606883991-git-send-email-normalperson@yhbt.net>

Eric Wong <normalperson@yhbt.net> writes:

> @@ -507,8 +507,16 @@ sub unique_email_list(@) {
>  	my @emails;
>  
>  	foreach my $entry (@_) {
> -		my $clean = extract_valid_address($entry);
> -		next if $seen{$clean}++;
> +		if (my $clean = extract_valid_address($entry)) {
> +			$seen{$clean} ||= 0;
> +			next if $seen{$clean}++;
> +		} else {
> +			# it could still be a local email address without '@',
> +			# which neither Email::Valid or our own small regex says
> +			# is valid...
> +			$seen{$entry} ||= 0;
> +			next if $seen{$entry}++;
> +		}

Wouldn't you want three kinds of return values from
sub extract_valid_address() if you want to do this?  That is, 

 (1) address is valid and this is the cleaned up value;
 (2) address is known to be bogus; do not use it.
 (3) address might be local.

And (1) and (3) are probably the same thing in practice.  In a
localsite setting, it is often convenient to be able to use
addr-spec that is local-part only, so something like the
attached change, with your error squelching for 'undef' return
in the second case, might be more appropriate.

-- >8 --

diff --git a/git-send-email.perl b/git-send-email.perl
index d8c4b1f..7a89e26 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -300,6 +300,9 @@ our ($message_id, $cc, %mail, $subject, 
 
 sub extract_valid_address {
 	my $address = shift;
+
+	return $address if ($address =~ /^(\w+)$/);
+
 	if ($have_email_valid) {
 		return Email::Valid->address($address);
 	} else {

^ permalink raw reply related

* Re: how to display file history?
From: Shawn Pearce @ 2006-05-15  6:00 UTC (permalink / raw)
  To: Brown, Len; +Cc: git
In-Reply-To: <CFF307C98FEABE47A452B27C06B85BB670F4F8@hdsmsx411.amr.corp.intel.com>

"Brown, Len" <len.brown@intel.com> wrote:
> it is tiresome to access kernel.org/git tree display
> to see the list of commits that changed a particular file.
> (and for files on my local disk, this isn't available).
> 
> How do I print the list of commits that change a particular file
> on my local disk?

I'm confused - why aren't these available on your local disk?  Do you
not have a clone of the kernel repository local?  If you don't have
a clone you aren't really going to be able to get a history.

But assuming you had one use whatchanged:

	git whatchanged A

will show only the commits which affected file A, listing them in
reverse order (most recent to oldest).

-- 
Shawn.

^ permalink raw reply

* Re: Tracking branch history
From: Shawn Pearce @ 2006-05-15  5:58 UTC (permalink / raw)
  To: git
In-Reply-To: <20060515031511.GA27505@spearce.org>

Shawn Pearce <spearce@spearce.org> wrote:
> Log ref updates to logs/refs/<ref>
> 
> If config parameter core.logAllRefUpdates is true or the log
> file already exists then append a line to ".git/logs/refs/<ref>"
> whenever git-update-ref <ref> is executed.  Each log line contains
> the following information:
> 
>   oldsha1 <SP> newsha1 <SP> committer <LF>
> 
> where committer is the current user, date, time and timezone in
> the standard GIT ident format.  If the caller is unable to append
> to the log file then git-update-ref will fail without updating <ref>.
> 
> An optional message may be included in the log line with the -m flag.

This is all well and good but its sort of useless without the diffcore
being able to lookup what SHA1 was valid on a given branch at a given
point in time.  :-)

I'm thinking about extending the 'extended SHA1' syntax to accept
a date (or date expression) as a suffix:

	HEAD@'2 hours ago'
	HEAD@'2006-04-20'
	HEAD@'2006-04-20 14:12'

etc... This would be merged into get_sha1 (sha1_name.c) so its
usable pretty much anywhere.  Does this seem reasonable?  If so
I'll work up a patch for it.

-- 
Shawn.

^ permalink raw reply

* how to display file history?
From: Brown, Len @ 2006-05-15  5:52 UTC (permalink / raw)
  To: git

it is tiresome to access kernel.org/git tree display
to see the list of commits that changed a particular file.
(and for files on my local disk, this isn't available).

How do I print the list of commits that change a particular file
on my local disk?

thanks,
-Len
 

^ permalink raw reply

* Re: [PATCH] send-email: allow sendmail binary to be used instead of SMTP
From: Junio C Hamano @ 2006-05-15  5:52 UTC (permalink / raw)
  To: Eric Wong; +Cc: git
In-Reply-To: <1147660345772-git-send-email-normalperson@yhbt.net>

Eric Wong <normalperson@yhbt.net> writes:

> This should make local mailing possible for machines without
> a connection to an SMTP server.

Which is a good thing, but

> It'll default to using /usr/sbin/sendmail or /usr/lib/sendmail
> if no SMTP server is specified (the default).  If it can't find
> either of those paths, it'll fall back to connecting to an SMTP
> server on localhost.

I do not know if it is OK to change the default to first prefer
local MDA executable and then "localhost".  That is, ...

> @@ -179,8 +180,14 @@ if (!defined $initial_reply_to && $promp
>  	$initial_reply_to =~ s/(^\s+|\s+$)//g;
>  }
>  
> -if (!defined $smtp_server) {
> -	$smtp_server = "localhost";
> +if (!$smtp_server) {
> +	foreach (qw( /usr/sbin/sendmail /usr/lib/sendmail )) {
> +		if (-x $_) {
> +			$smtp_server = $_;
> +			last;
> +		}
> +	}
> +	$smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*
>  }
>  
>  if ($compose) {

Without this hunk, people who did not specify --smtp-server=host
could get away with having anything that listens to 25/tcp on
the localhost that is not either of the above two paths; now
they have to explicitly say --smtp-server=localhost to defeat
what this hunk does.  I do not know if it is a big deal, though.

> +	if ($smtp_server =~ m#^/#) {

I like this if(){}else{} here, but have a feeling that the
logging part should be placed outside it to be shared.

While we are at it, we might want to enhance $smtp_server parsing
to take host:port notation so that people can use message
submission port 587/tcp (RFC 4409) instead.

^ permalink raw reply

* Re: The git newbie experience
From: Shawn Pearce @ 2006-05-15  5:31 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Tommi Virtanen, git
In-Reply-To: <7vy7x3x3ux.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> wrote:
> Tommi Virtanen <tv@inoi.fi> writes:
> 
> > Oh, I'd love to have a quick stash, that's what we actually ended up
> > doing a lot. Although I'd rather see a real implementation use a branch
> > and not just a diff file, but.. yes please.
> 
> I'd rather do that with a diff file that can be used to do a
> 3-way (see how rebase does it with --full-index diff with am -3).
> No point creating and forgetting to remove a throw away branch
> and getting more complaints.

How is a quick stash different from a topic branch?  I don't see
any difference between the two.  Your working directory was a topic
branch, just an unnamed topic branch.  Why don't you name it and
deal with it once it is named?

I can see new users getting confused about what changes are in
their quick stash or accidentially losing their quick stash by
running it twice in a row.

Teaching new users to always work on a topic branch and committing
before pulling/merging should be the favored workflow.

-- 
Shawn.

^ permalink raw reply

* Re: [PATCH] Fix compilation on newer NetBSD systems
From: Junio C Hamano @ 2006-05-15  5:31 UTC (permalink / raw)
  To: Dennis Stosberg; +Cc: git
In-Reply-To: <20060511173531.G18d4553c@leonov.stosberg.net>

Dennis Stosberg <dennis@stosberg.net> writes:

> NetBSD >=2.0 has iconv() in libc.  A libiconv is not required and
> does not exist.

I do not doubt that, but...

> +	ifeq ($(shell test `uname -r | sed -e 's/^\([0-9]\).*/\1/'` -lt 2 && echo y),y)
> +		NEEDS_LIBICONV = YesPlease
> +	endif

This looks rather ugly.  I do not know if NetBSD has 0.xx
versions, but perhaps something like this?

	ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)

^ permalink raw reply

* Re: The git newbie experience
From: Shawn Pearce @ 2006-05-15  5:27 UTC (permalink / raw)
  To: Tommi Virtanen; +Cc: Junio C Hamano, git
In-Reply-To: <44680C54.8040206@inoi.fi>

Tommi Virtanen <tv@inoi.fi> wrote:
> Junio C Hamano wrote:
[snip]
> > - Jack stashes away what he has been working on and cleans up
> >   his mess.
> > 
> >   git diff >P.diff
> >   git checkout HEAD A B C
> ...
> > - Jack then reapplies what he stashed away with "git apply P.diff"
> >   and keeps working.
> > 
> > Maybe "git stash" command that does "git diff --full-index" with
> > some frills, and "git unstash" command which does an equivalent
> > of "git am -3" would help this workflow (bare "git apply" does
> > not do the three-way merge like am does).
> 
> Oh, I'd love to have a quick stash, that's what we actually ended up
> doing a lot. Although I'd rather see a real implementation use a branch
> and not just a diff file, but.. yes please.
> 
> Although, "git stash" and "git unstash" are yet another command to add
> to the newbie set, and I just complained about the size of the set ;)

This is perhaps one area where SVN's user interface is actually nice.
SVN's equiv. of stash is making a copy of your working directory into
the repository; something that is rather simple to do for the user.

What about "git commit -b foo -a" to commit the current working
directory to branch 'foo'?

Then restoring is a pull of foo ("git pull . foo"), but that
intermediate commit is now part of the repository history.  And "git
commit -a" doesn't automatically add extra/other files to the
repository and it probably should in the case of a "stash".

-- 
Shawn.

^ permalink raw reply

* Re: The git newbie experience
From: Junio C Hamano @ 2006-05-15  5:18 UTC (permalink / raw)
  To: Tommi Virtanen; +Cc: git
In-Reply-To: <44680C54.8040206@inoi.fi>

Tommi Virtanen <tv@inoi.fi> writes:

> Oh, I'd love to have a quick stash, that's what we actually ended up
> doing a lot. Although I'd rather see a real implementation use a branch
> and not just a diff file, but.. yes please.

I'd rather do that with a diff file that can be used to do a
3-way (see how rebase does it with --full-index diff with am -3).
No point creating and forgetting to remove a throw away branch
and getting more complaints.

^ permalink raw reply

* Re: The git newbie experience
From: Tommi Virtanen @ 2006-05-15  5:06 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vfyjcntro.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:
> Anyway, I think the time to commit is too late to save somebody
> who does not understand the index.  How would you explain why
> you sometimes need to use -A and sometimes -a? 

I guess what I really want is "a smarter -a".

> That is why I
> suggested to make "git pull" and "git merge" refuse to work if
> there are local changes for novice users, where the definition
> of novice is "git commit -a" is the only way to make a commit.
> We can have [core] novice = yes in .git/config for that.
> 
> If somebody does not understand the index, if the merge is
> prevented because the local change does conflict with it, how
> would you explain why sometimes you can merge and sometimes you
> cannot?

By the same logic that is already implemented. "pull refuses to pull
changes to files that are modified but not committed".

>> For example, we had a case where we absolutely _had_ to keep
>> an ugly workaround in the tree, in a file not otherwise
>> edited, but we definitely did not want to commit the kludge,
> Your example is a very ill-thought out one.
>
> If you are leaving the uncommitable kludge around, you cannot be
> using "commit -a" with the normal non-merge workflow.  Why
> would you worry about not being able to do "commit -a" on a
> merge then?

The indexless working mode means you know two kinds of commits.
"git commit -a" or "git commit FILE..". The uncommitted kludge hanging
around means people listed file names. The case where the merge differs
is that it's not just a few files, and they didn't even really
know what files to list. And "git status" showed them something
they were not used to seeing.

> For the beginning user without index, I would rewrite your
> scenario like this.
> 
...
> - Jack stashes away what he has been working on and cleans up
>   his mess.
> 
>   git diff >P.diff
>   git checkout HEAD A B C
...
> - Jack then reapplies what he stashed away with "git apply P.diff"
>   and keeps working.
> 
> Maybe "git stash" command that does "git diff --full-index" with
> some frills, and "git unstash" command which does an equivalent
> of "git am -3" would help this workflow (bare "git apply" does
> not do the three-way merge like am does).

Oh, I'd love to have a quick stash, that's what we actually ended up
doing a lot. Although I'd rather see a real implementation use a branch
and not just a diff file, but.. yes please.

Although, "git stash" and "git unstash" are yet another command to add
to the newbie set, and I just complained about the size of the set ;)

-- 
Inoi Oy, Tykistökatu 4 D (4. krs), FI-20520 Turku, Finland
http://www.inoi.fi/
Mobile +358 40 762 5656

^ permalink raw reply

* Re: [PATCH (resend)] send-email: address expansion for common mailers
From: Ryan Anderson @ 2006-05-15  4:12 UTC (permalink / raw)
  To: Eric Wong; +Cc: Junio C Hamano, git, Ryan Anderson
In-Reply-To: <11476592243181-git-send-email-normalperson@yhbt.net>

On Sun, May 14, 2006 at 07:13:44PM -0700, Eric Wong wrote:
> mutt, gnus, pine, mailrc formats should be supported.
> 
> Testing and feedback for correctness and completeness of all formats
> and support for additional formats would be good.
> 
> Nested expansions are also supported.
> 
> More than one alias file to be used.
> 
> All alias file formats must still of be the same type, though.
> 
> Two git repo-config keys are required for this
> (as suggested by Ryan Anderson):
> 
>     sendemail.aliasesfile = <filename of aliases file>
>     sendemail.aliasfiletype = (mutt|gnus|pine|mailrc)
> 
> Signed-off-by: Eric Wong <normalperson@yhbt.net>
Acked-by: Ryan Anderson <ryan@michonline.com>

> ---
> 
> Looks like this patch got forgotten a while ago, and I never noticed
> because I forgot to set WITH_SEND_EMAIL when doing make install.
> Of course, WITH_SEND_EMAIL should no longer be needed...
> 
>  git-send-email.perl |   48 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 48 insertions(+), 0 deletions(-)
> 
> ff6593287dc500853c1cf05bdb0f32f970f10c9d
> diff --git a/git-send-email.perl b/git-send-email.perl
> index 703dd1f..d8c4b1f 100755
> --- a/git-send-email.perl
> +++ b/git-send-email.perl
> @@ -89,6 +89,41 @@ sub gitvar_ident {
>  my ($author) = gitvar_ident('GIT_AUTHOR_IDENT');
>  my ($committer) = gitvar_ident('GIT_COMMITTER_IDENT');
>  
> +my %aliases;
> +chomp(my @alias_files = `git-repo-config --get-all sendemail.aliasesfile`);
> +chomp(my $aliasfiletype = `git-repo-config sendemail.aliasfiletype`);
> +my %parse_alias = (
> +	# multiline formats can be supported in the future
> +	mutt => sub { my $fh = shift; while (<$fh>) {
> +		if (/^alias\s+(\S+)\s+(.*)$/) {
> +			my ($alias, $addr) = ($1, $2);
> +			$addr =~ s/#.*$//; # mutt allows # comments
> +			 # commas delimit multiple addresses
> +			$aliases{$alias} = [ split(/\s*,\s*/, $addr) ];
> +		}}},
> +	mailrc => sub { my $fh = shift; while (<$fh>) {
> +		if (/^alias\s+(\S+)\s+(.*)$/) {
> +			# spaces delimit multiple addresses
> +			$aliases{$1} = [ split(/\s+/, $2) ];
> +		}}},
> +	pine => sub { my $fh = shift; while (<$fh>) {
> +		if (/^(\S+)\s+(.*)$/) {
> +			$aliases{$1} = [ split(/\s*,\s*/, $2) ];
> +		}}},
> +	gnus => sub { my $fh = shift; while (<$fh>) {
> +		if (/\(define-mail-alias\s+"(\S+?)"\s+"(\S+?)"\)/) {
> +			$aliases{$1} = [ $2 ];
> +		}}}
> +);
> +
> +if (@alias_files && defined $parse_alias{$aliasfiletype}) {
> +	foreach my $file (@alias_files) {
> +		open my $fh, '<', $file or die "opening $file: $!\n";
> +		$parse_alias{$aliasfiletype}->($fh);
> +		close $fh;
> +	}
> +}
> +
>  my $prompting = 0;
>  if (!defined $from) {
>  	$from = $author || $committer;
> @@ -112,6 +147,19 @@ if (!@to) {
>  	$prompting++;
>  }
>  
> +sub expand_aliases {
> +	my @cur = @_;
> +	my @last;
> +	do {
> +		@last = @cur;
> +		@cur = map { $aliases{$_} ? @{$aliases{$_}} : $_ } @last;
> +	} while (join(',',@cur) ne join(',',@last));
> +	return @cur;
> +}
> +
> +@to = expand_aliases(@to);
> +@initial_cc = expand_aliases(@initial_cc);
> +
>  if (!defined $initial_subject && $compose) {
>  	do {
>  		$_ = $term->readline("What subject should the emails start with? ",
> -- 
> 1.3.2.g1c9b
> 
> 

^ permalink raw reply

* Re: git diff: support "-U" and "--unified" options properly
From: Linus Torvalds @ 2006-05-15  3:49 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0605141745410.3866@g5.osdl.org>



On Sun, 14 May 2006, Linus Torvalds wrote:
> 
> So I would actually assume that the solution is to simply make 
> grep_cache() have a simple
> 
> 	#ifdef __unix__
> 		if (!cached) {
> 			hit = external_grep(opt, paths, cached);
> 			if (hit >= 0)
> 				return hit;
> 		}
> 	#endif
> 
> at the top, so that we'd have the best of both worlds.

Ok. Here's a slightly tested version, my out-lined thing from the email 
was pretty close to working already.

It's not perfect, but it gets the "git grep some-random-string" down to 
the good old half-a-second range for the kernel.

It should convert more of the argument flags for "grep", that should be 
trivial to expand (I did a few just as an example). It should also bother 
to try to return the right "hit" value (which it doesn't, right now - the 
code is kind of there, but I didn't actually bother to do it _right_).

Also, right now it _just_ limits by number of arguments, but it should 
also strictly speaking limit by total argument size (ie add up the length 
of the filenames, and do the "exec_grep()" flush call if it's bigger than 
some random value like 32kB).

But I think that it's _conceptually_ doing all the right things, and it 
seems to work. So maybe somebody else can do some of the final polish.

		Linus

----
diff --git a/builtin-grep.c b/builtin-grep.c
index fead356..14471db 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -12,6 +12,7 @@ #include "tree-walk.h"
 #include "builtin.h"
 #include <regex.h>
 #include <fnmatch.h>
+#include <sys/wait.h>
 
 /*
  * git grep pathspecs are somewhat different from diff-tree pathspecs;
@@ -409,12 +410,90 @@ static int grep_file(struct grep_opt *op
 	return i;
 }
 
+static int exec_grep(int argc, const char **argv)
+{
+	pid_t pid;
+	int status;
+
+	argv[argc] = NULL;
+	pid = fork();
+	if (pid < 0)
+		return pid;
+	if (!pid) {
+		execvp("grep", (char **) argv);
+		exit(255);
+	}
+	while (waitpid(pid, &status, 0) < 0) {
+		if (errno == EINTR)
+			continue;
+		return -1;
+	}
+	if (WIFEXITED(status)) {
+		if (!WEXITSTATUS(status))
+			return 1;
+		return 0;
+	}
+	return -1;
+}
+
+#define MAXARGS 1000
+
+static int external_grep(struct grep_opt *opt, const char **paths, int cached)
+{
+	int i, nr, argc, hit;
+	const char *argv[MAXARGS+1];
+	struct grep_pat *p;
+
+	nr = 0;
+	argv[nr++] = "grep";
+	if (opt->word_regexp)
+		argv[nr++] = "-w";
+	if (opt->name_only)
+		argv[nr++] = "-l";
+	for (p = opt->pattern_list; p; p = p->next) {
+		argv[nr++] = "-e";
+		argv[nr++] = p->pattern;
+	}
+	argv[nr++] = "--";
+
+	hit = 0;
+	argc = nr;
+	for (i = 0; i < active_nr; i++) {
+		struct cache_entry *ce = active_cache[i];
+		if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode)))
+			continue;
+		if (!pathspec_matches(paths, ce->name))
+			continue;
+		argv[argc++] = ce->name;
+		if (argc < MAXARGS)
+			continue;
+		hit += exec_grep(argc, argv);
+		argc = nr;
+	}
+	if (argc > nr)
+		hit += exec_grep(argc, argv);
+	return 0;
+}
+
 static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
 {
 	int hit = 0;
 	int nr;
 	read_cache();
 
+#ifdef __unix__
+	/*
+	 * Use the external "grep" command for the case where
+	 * we grep through the checked-out files. It tends to
+	 * be a lot more optimized
+	 */
+	if (!cached) {
+		hit = external_grep(opt, paths, cached);
+		if (hit >= 0)
+			return hit;
+	}
+#endif
+
 	for (nr = 0; nr < active_nr; nr++) {
 		struct cache_entry *ce = active_cache[nr];
 		if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode)))

^ permalink raw reply related

* Re: Tracking branch history
From: Shawn Pearce @ 2006-05-15  3:15 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vk68o19n4.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> wrote:
> Shawn Pearce <spearce@spearce.org> writes:
> 
> > Log ref updates to logs/refs/<ref>
> >
> > If config parameter core.logRefUpdates is true then append a line
> > to .git/logs/refs/<ref> whenever git-update-ref <ref> is executed.
> 
> I cannot decide if a parameter makes more sense, or just making
> the existence of such a file a cue is better.  For example, I do
> not much care about when I updated each of my topic branch head,
> while I do care about master, next, and pu branches.  A global
> parameter would make this black-or-white choice, while opening
> the log without O_CREAT and write things out only when the log
> file exists might make things as easy and controllable.
> 
> I could "touch" the ones I care about to prime the process.

I'm as torn as you are on this.  My `pg' would have some serious
issues with update-ref and the logRefUpdates config being true as it
uses a large number of refs to track the patch stack.  StGIT might
also be in a somewhat similiar position, but I think it uses slightly
less refs.  Opening without O_CREAT and letting the user touch the
log file into existance would fix this problem for most users.

But I can also see the case where the user has most branches logged
then infrequently creates a new branch but expects that branch
to also be logged.  What happens when they later find out its not
logging but they were counting on that log data to be there?

Perhaps a mix of the two solutions is ideal.  Use O_CREAT if
logRefUpdates is true and otherwise log only if the file already
exists.  This is now in the patch below.

I have also added an optional '-m <reason>' flag to update-ref,
for use in e.g. git-commit.  I have also moved the logging code to
refs.c where it could be used by fetch or upload-pack, but those
changes are not yet included in this patch.

--> -
Log ref updates to logs/refs/<ref>

If config parameter core.logAllRefUpdates is true or the log
file already exists then append a line to ".git/logs/refs/<ref>"
whenever git-update-ref <ref> is executed.  Each log line contains
the following information:

  oldsha1 <SP> newsha1 <SP> committer <LF>

where committer is the current user, date, time and timezone in
the standard GIT ident format.  If the caller is unable to append
to the log file then git-update-ref will fail without updating <ref>.

An optional message may be included in the log line with the -m flag.

---

 Documentation/config.txt         |    8 ++++++
 Documentation/git-update-ref.txt |   28 +++++++++++++++++++-
 cache.h                          |    1 +
 config.c                         |    5 ++++
 environment.c                    |    1 +
 refs.c                           |   50 ++++++++++++++++++++++++++++++++++++
 refs.h                           |    3 ++
 update-ref.c                     |   53 ++++++++++++++++++++++++++++++++------
 8 files changed, 139 insertions(+), 10 deletions(-)

bbac000fbc779c7434d66b10639eaa5ea218f62e
diff --git a/Documentation/config.txt b/Documentation/config.txt
index d1a4bec..e178ee2 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -70,6 +70,14 @@ core.preferSymlinkRefs::
 	This is sometimes needed to work with old scripts that
 	expect HEAD to be a symbolic link.
 
+core.logAllRefUpdates::
+	If true, `git-update-ref` will append a line to
+	"$GIT_DIR/logs/<ref>" listing the new SHA1 and the date/time
+	of the update.	If the file does not exist it will be
+	created automatically.	This information can be used to
+	determine what commit was the tip of a branch "2 days ago".
+	This value is false by default (no logging).
+
 core.repositoryFormatVersion::
 	Internal variable identifying the repository format and layout
 	version.
diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt
index 475237f..dfbd886 100644
--- a/Documentation/git-update-ref.txt
+++ b/Documentation/git-update-ref.txt
@@ -7,7 +7,7 @@ git-update-ref - update the object name 
 
 SYNOPSIS
 --------
-'git-update-ref' <ref> <newvalue> [<oldvalue>]
+'git-update-ref' <ref> <newvalue> [<oldvalue>] [-m <reason>]
 
 DESCRIPTION
 -----------
@@ -49,6 +49,32 @@ for reading but not for writing (so we'l
 ref symlink to some other tree, if you have copied a whole
 archive by creating a symlink tree).
 
+Logging Updates
+---------------
+If config parameter "core.logAllRefUpdates" is true or the file
+"$GIT_DIR/logs/<ref>" exists then `git-update-ref` will append
+a line to the log file "$GIT_DIR/logs/<ref>" (dereferencing all
+symbolic refs before creating the log name) describing the change
+in ref value.  Log lines are formatted as:
+
+    . oldsha1 SP newsha1 SP committer LF
++
+Where "oldsha1" is the 40 character hexadecimal value previously
+stored in <ref>, "newsha1" is the 40 character hexadecimal value of
+<newvalue> and "committer" is the committer's name, email address
+and date in the standard GIT committer ident format.
+
+Optionally with -m:
+
+    . oldsha1 SP newsha1 SP committer TAB message LF
++
+Where all fields are as described above and "message" is the
+value supplied to the -m option.
+
+An update will fail (without changing <ref>) if the current user is
+unable to create a new log file, append to the existing log file
+or does not have committer information available.
+
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>.
diff --git a/cache.h b/cache.h
index b1300cd..82adbba 100644
--- a/cache.h
+++ b/cache.h
@@ -171,6 +171,7 @@ extern void rollback_index_file(struct c
 extern int trust_executable_bit;
 extern int assume_unchanged;
 extern int prefer_symlink_refs;
+extern int log_all_ref_updates;
 extern int warn_ambiguous_refs;
 extern int diff_rename_limit_default;
 extern int shared_repository;
diff --git a/config.c b/config.c
index 0f518c9..fa6db4b 100644
--- a/config.c
+++ b/config.c
@@ -232,6 +232,11 @@ int git_default_config(const char *var, 
 		return 0;
 	}
 
+	if (!strcmp(var, "core.logallrefupdates")) {
+		log_all_ref_updates = git_config_bool(var, value);
+		return 0;
+	}
+
 	if (!strcmp(var, "core.warnambiguousrefs")) {
 		warn_ambiguous_refs = git_config_bool(var, value);
 		return 0;
diff --git a/environment.c b/environment.c
index 444c99e..2e79eab 100644
--- a/environment.c
+++ b/environment.c
@@ -14,6 +14,7 @@ char git_default_name[MAX_GITNAME];
 int trust_executable_bit = 1;
 int assume_unchanged = 0;
 int prefer_symlink_refs = 0;
+int log_all_ref_updates = 0;
 int warn_ambiguous_refs = 1;
 int repository_format_version = 0;
 char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
diff --git a/refs.c b/refs.c
index 275b914..691a8ba 100644
--- a/refs.c
+++ b/refs.c
@@ -375,3 +375,53 @@ int write_ref_sha1_unlocked(const char *
 	free(lock_filename);
 	return retval;
 }
+
+int log_ref_update(const char *ref, const unsigned char *currsha1, const unsigned char *newsha1, const char *msg)
+{
+	char *logpath, *logrec;
+	const char *comitter;
+	unsigned maxlen, len;
+	int oflags, logfd, written;
+
+	oflags = O_APPEND | O_WRONLY;
+	logpath = git_path("logs/%s", ref);
+	if (log_all_ref_updates) {
+		if (safe_create_leading_directories(logpath) < 0)
+			return error("Unable to create all of %s", logpath);
+		oflags |= O_CREAT;
+	}
+
+	logfd = open(logpath, oflags, 0666);
+	if (logfd < 0) {
+		if (!log_all_ref_updates && errno == ENOENT)
+			return 0;
+		return error("Unable to append to %s: %s", logpath, strerror(errno));
+	}
+
+	setup_ident();
+	comitter = git_committer_info(1);
+	if (msg) {
+		maxlen = strlen(comitter) + strlen(msg) + 2*40 + 5;
+		logrec = xmalloc(maxlen);
+		len = snprintf(logrec, maxlen, "%s %s %s\t%s\n",
+			sha1_to_hex(currsha1),
+			sha1_to_hex(newsha1),
+			comitter,
+			msg);
+	} else {
+		maxlen = strlen(comitter) + 2*40 + 4;
+		logrec = xmalloc(maxlen);
+		len = snprintf(logrec, maxlen, "%s %s %s\n",
+			sha1_to_hex(currsha1),
+			sha1_to_hex(newsha1),
+			comitter);
+	}
+	if (len >= maxlen)
+		return error("Internal error formatting log record.");
+	written = write(logfd, logrec, len);
+	if (written != len)
+		return error("Unable to append to %s", logpath);
+	free(logrec);
+	close(logfd);
+	return 0;
+}
diff --git a/refs.h b/refs.h
index 2625596..9345942 100644
--- a/refs.h
+++ b/refs.h
@@ -25,4 +25,7 @@ extern int write_ref_sha1_unlocked(const
 /** Returns 0 if target has the right format for a ref. **/
 extern int check_ref_format(const char *target);
 
+/** If logging is enabled logs the change made to the ref. **/
+extern int log_ref_update(const char *ref, const unsigned char *currsha1, const unsigned char *newsha1, const char *msg);
+
 #endif /* REFS_H */
diff --git a/update-ref.c b/update-ref.c
index fd48742..95940dd 100644
--- a/update-ref.c
+++ b/update-ref.c
@@ -1,7 +1,8 @@
 #include "cache.h"
 #include "refs.h"
 
-static const char git_update_ref_usage[] = "git-update-ref <refname> <value> [<oldval>]";
+static const char git_update_ref_usage[] =
+"git-update-ref <refname> <value> [<oldval>] [-m <reason>]";
 
 static int re_verify(const char *path, unsigned char *oldsha1, unsigned char *currsha1)
 {
@@ -19,26 +20,50 @@ static int re_verify(const char *path, u
 int main(int argc, char **argv)
 {
 	char *hex;
-	const char *refname, *value, *oldval, *path;
+	const char *refname=NULL, *value=NULL, *oldval=NULL, *msg=NULL, *path;
 	char *lockpath;
 	unsigned char sha1[20], oldsha1[20], currsha1[20];
-	int fd, written;
+	int i, fd, written, pfxlen;
 
 	setup_git_directory();
 	git_config(git_default_config);
-	if (argc < 3 || argc > 4)
+
+	for (i = 1; i < argc; i++) {
+		if (!strcmp("-m", argv[i])) {
+			if (i+1 >= argc)
+				usage(git_update_ref_usage);
+			msg = argv[++i];
+			if (!*msg)
+				die("Refusing to perform update with empty message.");
+			if (strchr(msg, '\n'))
+				die("Refusing to perform update with \\n in message.");
+			continue;
+		}
+		if (!refname) {
+			refname = argv[i];
+			continue;
+		}
+		if (!value) {
+			value = argv[i];
+			continue;
+		}
+		if (!oldval) {
+			oldval = argv[i];
+			continue;
+		}
+	}
+	if (!refname || !value)
 		usage(git_update_ref_usage);
 
-	refname = argv[1];
-	value = argv[2];
-	oldval = argv[3];
 	if (get_sha1(value, sha1))
 		die("%s: not a valid SHA1", value);
 	memset(oldsha1, 0, 20);
 	if (oldval && get_sha1(oldval, oldsha1))
 		die("%s: not a valid old SHA1", oldval);
 
-	path = resolve_ref(git_path("%s", refname), currsha1, !!oldval);
+	path = git_path("%s", refname);
+	pfxlen = strlen(path) - strlen(refname);
+	path = resolve_ref(path, currsha1, !!oldval);
 	if (!path)
 		die("No such ref: %s", refname);
 
@@ -49,8 +74,13 @@ int main(int argc, char **argv)
 		if (!memcmp(oldsha1, sha1, 20))
 			exit(0);
 	}
+
+	/* No change in ref.  Don't do anything. */
+	if (!memcmp(currsha1, sha1, 20))
+		exit(0);
+
 	path = strdup(path);
-	lockpath = mkpath("%s.lock", path);
+	lockpath = strdup(mkpath("%s.lock", path));
 	if (safe_create_leading_directories(lockpath) < 0)
 		die("Unable to create all of %s", lockpath);
 
@@ -74,6 +104,11 @@ int main(int argc, char **argv)
 		die("Ref lock failed");
 	}
 
+	if (log_ref_update(path + pfxlen, currsha1, sha1, msg) < 0) {
+		unlink(lockpath);
+		die("Logging ref update failed, update aborted.");
+	}
+
 	/*
 	 * Finally, replace the old ref with the new one
 	 */
-- 
1.3.2.g7278

^ permalink raw reply related

* [PATCH] send-email: quiet some warnings
From: Eric Wong @ 2006-05-15  2:38 UTC (permalink / raw)
  To: Junio C Hamano, git; +Cc: Eric Wong
In-Reply-To: <1147660345772-git-send-email-normalperson@yhbt.net>

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 git-send-email.perl |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)

0e5a33f56f62e527b74b2afbd93a1cca812f97af
diff --git a/git-send-email.perl b/git-send-email.perl
index d27a7a5..379e0c4 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -507,8 +507,16 @@ sub unique_email_list(@) {
 	my @emails;
 
 	foreach my $entry (@_) {
-		my $clean = extract_valid_address($entry);
-		next if $seen{$clean}++;
+		if (my $clean = extract_valid_address($entry)) {
+			$seen{$clean} ||= 0;
+			next if $seen{$clean}++;
+		} else {
+			# it could still be a local email address without '@',
+			# which neither Email::Valid or our own small regex says
+			# is valid...
+			$seen{$entry} ||= 0;
+			next if $seen{$entry}++;
+		}
 		push @emails, $entry;
 	}
 	return @emails;
-- 
1.3.2.g0e5a

^ permalink raw reply related

* Re: [PATCH] Add "--summary" option to git diff.
From: Junio C Hamano @ 2006-05-15  2:34 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Sean, git, Johannes.Schindelin
In-Reply-To: <Pine.LNX.4.64.0605141848080.3866@g5.osdl.org>

Linus Torvalds <torvalds@osdl.org> writes:

> On Sun, 14 May 2006, Sean wrote:
>> 
>> What's a bit more worrying is that:
>> 
>> $ PAGER= ./git whatchanged -B -C --stat --no-merges --diff-filter=RC
>> 
>> Causes the same problem on the current (1.3.2) release branch without any
>> other patches applied at all.

And the culprit was _me_ X-<.  *BLUSH*


-- >8 --

diff --git a/diff.c b/diff.c
index 7a7b839..2d72673 100644
--- a/diff.c
+++ b/diff.c
@@ -232,11 +232,16 @@ static char *pprint_rename(const char *a
 	 * name-a => name-b
 	 */
 	if (pfx_length + sfx_length) {
+		int a_len = len_a - pfx_length - sfx_length;
+		int b_len = len_b - pfx_length - sfx_length;
+		if (a_len < 0) a_len = 0;
+		if (b_len < 0) b_len = 0;
+
 		name = xmalloc(len_a + len_b - pfx_length - sfx_length + 7);
 		sprintf(name, "%.*s{%.*s => %.*s}%s",
 			pfx_length, a,
-			len_a - pfx_length - sfx_length, a + pfx_length,
-			len_b - pfx_length - sfx_length, b + pfx_length,
+			a_len, a + pfx_length,
+			b_len, b + pfx_length,
 			a + len_a - sfx_length);
 	}
 	else {

^ permalink raw reply related

* Re: [PATCH] send-email: allow sendmail binary to be used instead of SMTP
From: Eric Wong @ 2006-05-15  2:34 UTC (permalink / raw)
  To: git; +Cc: Martin Langhoff
In-Reply-To: <1147660345772-git-send-email-normalperson@yhbt.net>

Eric Wong <normalperson@yhbt.net> wrote:
> This should make local mailing possible for machines without
> a connection to an SMTP server.
> 
> It'll default to using /usr/sbin/sendmail or /usr/lib/sendmail
> if no SMTP server is specified (the default).  If it can't find
> either of those paths, it'll fall back to connecting to an SMTP
> server on localhost.
> 
> Signed-off-by: Eric Wong <normalperson@yhbt.net>

Also, Thanks to Martin Langhoff for bringing this up.

-- 
Eric Wong

^ permalink raw reply

* [PATCH] send-email: allow sendmail binary to be used instead of SMTP
From: Eric Wong @ 2006-05-15  2:32 UTC (permalink / raw)
  To: Junio C Hamano, git; +Cc: Eric Wong

This should make local mailing possible for machines without
a connection to an SMTP server.

It'll default to using /usr/sbin/sendmail or /usr/lib/sendmail
if no SMTP server is specified (the default).  If it can't find
either of those paths, it'll fall back to connecting to an SMTP
server on localhost.

Signed-off-by: Eric Wong <normalperson@yhbt.net>

---

 git-send-email.perl |   55 +++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 42 insertions(+), 13 deletions(-)

1c9bacc5a2bfe382f68046aeba62302d28e4c976
diff --git a/git-send-email.perl b/git-send-email.perl
index d8c4b1f..d27a7a5 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -40,7 +40,8 @@ # Variables we fill in automatically, or
 my (@to,@cc,@initial_cc,$initial_reply_to,$initial_subject,@files,$from,$compose,$time);
 
 # Behavior modification variables
-my ($chain_reply_to, $smtp_server, $quiet, $suppress_from, $no_signed_off_cc) = (1, "localhost", 0, 0, 0);
+my ($chain_reply_to, $quiet, $suppress_from, $no_signed_off_cc) = (1, 0, 0, 0);
+my $smtp_server;
 
 # Example reply to:
 #$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
@@ -179,8 +180,14 @@ if (!defined $initial_reply_to && $promp
 	$initial_reply_to =~ s/(^\s+|\s+$)//g;
 }
 
-if (!defined $smtp_server) {
-	$smtp_server = "localhost";
+if (!$smtp_server) {
+	foreach (qw( /usr/sbin/sendmail /usr/lib/sendmail )) {
+		if (-x $_) {
+			$smtp_server = $_;
+			last;
+		}
+	}
+	$smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*
 }
 
 if ($compose) {
@@ -358,18 +365,39 @@ X-Mailer: git-send-email $gitversion
 ";
 	$header .= "In-Reply-To: $reply_to\n" if $reply_to;
 
-	$smtp ||= Net::SMTP->new( $smtp_server );
-	$smtp->mail( $from ) or die $smtp->message;
-	$smtp->to( @recipients ) or die $smtp->message;
-	$smtp->data or die $smtp->message;
-	$smtp->datasend("$header\n$message") or die $smtp->message;
-	$smtp->dataend() or die $smtp->message;
-	$smtp->ok or die "Failed to send $subject\n".$smtp->message;
+	if ($smtp_server =~ m#^/#) {
+		my $pid = open my $sm, '|-';
+		defined $pid or die $!;
+		if (!$pid) {
+			exec($smtp_server,'-i',@recipients) or die $!;
+		}
+		print $sm "$header\n$message";
+		close $sm or die $?;
+		if ($quiet) {
+			printf "Sent %s\n", $subject;
+		} else {
+			print "OK. Log says:
+Date: $date
+Sendmail: $smtp_server
+From: $from
+Subject: $subject
+Cc: $cc
+To: $to
 
-	if ($quiet) {
-		printf "Sent %s\n", $subject;
+Result: OK\n";
+		}
 	} else {
-		print "OK. Log says:
+		$smtp ||= Net::SMTP->new( $smtp_server );
+		$smtp->mail( $from ) or die $smtp->message;
+		$smtp->to( @recipients ) or die $smtp->message;
+		$smtp->data or die $smtp->message;
+		$smtp->datasend("$header\n$message") or die $smtp->message;
+		$smtp->dataend() or die $smtp->message;
+		$smtp->ok or die "Failed to send $subject\n".$smtp->message;
+		if ($quiet) {
+			printf "Sent %s\n", $subject;
+		} else {
+			print "OK. Log says:
 Date: $date
 Server: $smtp_server Port: 25
 From: $from
@@ -378,6 +406,7 @@ Cc: $cc
 To: $to
 
 Result: ", $smtp->code, ' ', ($smtp->message =~ /\n([^\n]+\n)$/s), "\n";
+		}
 	}
 }
 
-- 
1.3.2.g1c9b

^ permalink raw reply related


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