Git development
 help / color / mirror / Atom feed
* Re: [PATCH 6/8] ls-tree: work from subdirectory.
From: Junio C Hamano @ 2005-11-28  1:07 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Petr Baudis, Git Mailing List
In-Reply-To: <Pine.LNX.4.64.0511271049090.13959@g5.osdl.org>

Linus Torvalds <torvalds@osdl.org> writes:

> On Sun, 27 Nov 2005, Petr Baudis wrote:
>> Ugh. That's really weird. Wouldn't a better approach be to fix
>> git-ls-files to behave more sanely? (That is, listing the entry for
>> drivers/char instead of drivers?)

It behaves sanely, just not in the way you are expecting.

> Well, it's not actually confusing if you see a path spec for
> what it is: it's not a filename, it's a _pattern_.

Well, that is confusing, although it may be sane.

> So you should always do
>
> 	git-ls-tree -r pattern
>
> (and yes, we could even hardcode "-r", because git-ls-tree without it 
> really is a pretty strange thing).

If you mean "in the presense of pathspec, default to -r", I
*might* agree, but I am not convinced yet.

Without pathspec, ls-tree is a pretty-printing version of
"git-cat-file tree", and that is how the command is used by the
git browsers like gitweb.  I have never looked at qgit source,
but I'd be surprised if it did not depend on the single-level
behaviour of ls-tree for that purpose.

It *is* "/bin/ls" after all, and you _would_ get annoyed if your
/bin/ls always recursed if you gave an argument.  Imagine going
to the kernel source and try "/bin/ls arch" with your version of
/bin/ls that always recurses, when you only wanted to get the
list of architectures you are supporting ;-).

> The _real_ strangeness in "git-ls-tree" is that it shows the tree nodes at 
> all, which no other git tool does when it recurses. 

Very true.  I do not think even git browsers need that but I may
be mistaken.

Having said all of the above, I do understand why we would
_also_ want the behaviour parallel to ls-files, not /bin/ls
behaviour.  Maybe we should have both?  Either rename the
current ls-tree to browse-tree, and make the one that parallels
ls-files the new ls-tree?

^ permalink raw reply

* Re: git-send-mail in sh
From: Ryan Anderson @ 2005-11-28  0:49 UTC (permalink / raw)
  To: Andreas Ericsson; +Cc: Git Mailing List
In-Reply-To: <43874415.8040302@op5.se>

[-- Attachment #1: Type: text/plain, Size: 1846 bytes --]

Andreas Ericsson wrote:
> Ryan Anderson wrote:
> 
>> On Fri, Nov 25, 2005 at 10:45:41AM +0100, Andreas Ericsson wrote:
>>
>>> Finally giving up on git-send-email (I won't install the 6
>>> perl-modules it requires and I don't know perl enough to remove the
>>> need for them), I hacked up a replacement in sh. It's more aptly
>>> named as well. ;)
>>
>> Scanning the list, 2 are related to option handling (one of which is
>> builtin), one isn't used (Data::Dumper), and two are related to sending
>> valid emails.
> 
> When I try to install Email::Valid (using apt) it wants an additional
> two modules. Mail::Sendmail wants one other, so that's Data::Dumper, the
> two actually used and the three those two use. Six, for short.

Can I ask why you aren't willing to install packages, such as those?  I
can understand a reluctance to install modules directly from CPAN, on an
otherwise package-managed system, but I'm afraid I must confess to
puzzlement over a reluctance to use pre-packaged modules.

The major flaw in git-send-email, from my perspective, was a lack of
support for SMTP AUTH, for situations like Junio's, where the local MTA
(and thus "mail" as well) are not configured to handle SMTP AUTH. Moving
to a purely shell based replacement seems to make this an even harder
feature to support.  (Though, admittedly, I haven't even made an attempt
to add it to the Perl version yet.)

>> The email address verification is ridiculously hard to get
>> correct, so using pre-written code for that seemed justified.
>>
> 
> But it isn't necessary to validate it to such exactness. Nothing worse
> will happen than the user chiding himself for his butterfingers if
> he/she makes a mistake.
> 
> Besides, I think typos are by far the most common error. Those are
> usually valid email addresses while still not being correct.

Fair enough.

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 256 bytes --]

^ permalink raw reply

* [PATCH 3/3] mailinfo: Use i18n.commitencoding
From: Junio C Hamano @ 2005-11-28  0:39 UTC (permalink / raw)
  To: git

This uses i18n.commitencoding configuration item to pick up the
default commit encoding for the repository when converting form
e-mail encoding to commit encoding (the default is utf8).

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

---

 * I am not very thrilled with doing this change to mailinfo;
   alternatively the wrapper could read the configuration and
   decide what encoding to pass with -u=encoding flag.

 mailinfo.c |   17 +++++++++--------
 1 files changed, 9 insertions(+), 8 deletions(-)

applies-to: dab00e61bbd43be526bce908d4142d7c80d7a325
f1f909e3185b5ee366e198042447afe749bfc813
diff --git a/mailinfo.c b/mailinfo.c
index 6d8c933..de105ac 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -8,6 +8,7 @@
 #include <string.h>
 #include <ctype.h>
 #include <iconv.h>
+#include "cache.h"
 
 #ifdef NO_STRCASESTR
 extern char *gitstrcasestr(const char *haystack, const char *needle);
@@ -718,27 +719,27 @@ static void handle_body(void)
 static const char mailinfo_usage[] =
 	"git-mailinfo [-k] [-u] msg patch <mail >info";
 
-static void usage(void) {
-	fprintf(stderr, "%s\n", mailinfo_usage);
-	exit(1);
-}
-
 int main(int argc, char **argv)
 {
+	/* NEEDSWORK: might want to do the optional .git/ directory
+	 * discovery
+	 */
+	git_config(git_default_config);
+
 	while (1 < argc && argv[1][0] == '-') {
 		if (!strcmp(argv[1], "-k"))
 			keep_subject = 1;
 		else if (!strcmp(argv[1], "-u"))
-			metainfo_charset = "utf-8";
+			metainfo_charset = git_commit_encoding;
 		else if (!strncmp(argv[1], "-u=", 3))
 			metainfo_charset = argv[1] + 3;
 		else
-			usage();
+			usage(mailinfo_usage);
 		argc--; argv++;
 	}
 
 	if (argc != 3)
-		usage();
+		usage(mailinfo_usage);
 	cmitmsg = fopen(argv[1], "w");
 	if (!cmitmsg) {
 		perror(argv[1]);
---
0.99.9.GIT

^ permalink raw reply related

* [PATCH 2/3] mailinfo: allow -u to fall back on latin1 to utf8 conversion.
From: Junio C Hamano @ 2005-11-28  0:39 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0511262006350.13959@g5.osdl.org>

When the message body does not identify what encoding it is in,
-u assumes it is in latin-1 and converts it to utf8, which is
the recommended encoding for git commit log messages.

With -u=<encoding>, the conversion is made into the specified
one, instead of utf8, to allow project-local policies.

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

---

 * This says [2/3] but does not use the first one in the series,
   to keep mailinfo less dependent on git.  [3/3] integrates it
   to git a bit further by using the configuration file.

 mailinfo.c |   59 +++++++++++++++++++++++++++++++++++------------------------
 1 files changed, 35 insertions(+), 24 deletions(-)

applies-to: dfac5ab58034e7129ba0d8096ca2bb6857df2242
650e4be59b9f385f56e5829d97d09e8440f174b8
diff --git a/mailinfo.c b/mailinfo.c
index cb853df..6d8c933 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -16,7 +16,7 @@ extern char *gitstrcasestr(const char *h
 static FILE *cmitmsg, *patchfile;
 
 static int keep_subject = 0;
-static int metainfo_utf8 = 0;
+static char *metainfo_charset = NULL;
 static char line[1000];
 static char date[1000];
 static char name[1000];
@@ -441,29 +441,38 @@ static int decode_b_segment(char *in, ch
 
 static void convert_to_utf8(char *line, char *charset)
 {
-	if (*charset) {
-		char *in, *out;
-		size_t insize, outsize, nrc;
-		char outbuf[4096]; /* cheat */
-		iconv_t conv = iconv_open("utf-8", charset);
-
-		if (conv == (iconv_t) -1) {
-			fprintf(stderr, "cannot convert from %s to utf-8\n",
-				charset);
+	char *in, *out;
+	size_t insize, outsize, nrc;
+	char outbuf[4096]; /* cheat */
+	static char latin_one[] = "latin-1";
+	char *input_charset = *charset ? charset : latin_one;
+	iconv_t conv = iconv_open(metainfo_charset, input_charset);
+
+	if (conv == (iconv_t) -1) {
+		static int warned_latin1_once = 0;
+		if (input_charset != latin_one) {
+			fprintf(stderr, "cannot convert from %s to %s\n",
+				input_charset, metainfo_charset);
 			*charset = 0;
-			return;
 		}
-		in = line;
-		insize = strlen(in);
-		out = outbuf;
-		outsize = sizeof(outbuf);
-		nrc = iconv(conv, &in, &insize, &out, &outsize);
-		iconv_close(conv);
-		if (nrc == (size_t) -1)
-			return;
-		*out = 0;
-		strcpy(line, outbuf);
+		else if (!warned_latin1_once) {
+			warned_latin1_once = 1;
+			fprintf(stderr, "tried to convert from %s to %s, "
+				"but your iconv does not work with it.\n",
+				input_charset, metainfo_charset);
+		}
+		return;
 	}
+	in = line;
+	insize = strlen(in);
+	out = outbuf;
+	outsize = sizeof(outbuf);
+	nrc = iconv(conv, &in, &insize, &out, &outsize);
+	iconv_close(conv);
+	if (nrc == (size_t) -1)
+		return;
+	*out = 0;
+	strcpy(line, outbuf);
 }
 
 static void decode_header_bq(char *it)
@@ -511,7 +520,7 @@ static void decode_header_bq(char *it)
 		}
 		if (sz < 0)
 			return;
-		if (metainfo_utf8)
+		if (metainfo_charset)
 			convert_to_utf8(piecebuf, charset_q);
 		strcpy(out, piecebuf);
 		out += strlen(out);
@@ -590,7 +599,7 @@ static int handle_commit_msg(void)
 		 * normalize the log message to UTF-8.
 		 */
 		decode_transfer_encoding(line);
-		if (metainfo_utf8)
+		if (metainfo_charset)
 			convert_to_utf8(line, charset);
 		fputs(line, cmitmsg);
 	} while (fgets(line, sizeof(line), stdin) != NULL);
@@ -720,7 +729,9 @@ int main(int argc, char **argv)
 		if (!strcmp(argv[1], "-k"))
 			keep_subject = 1;
 		else if (!strcmp(argv[1], "-u"))
-			metainfo_utf8 = 1;
+			metainfo_charset = "utf-8";
+		else if (!strncmp(argv[1], "-u=", 3))
+			metainfo_charset = argv[1] + 3;
 		else
 			usage();
 		argc--; argv++;
---
0.99.9.GIT

^ permalink raw reply related

* [PATCH 1/3] Introduce i18n.commitencoding.
From: Junio C Hamano @ 2005-11-28  0:39 UTC (permalink / raw)
  To: git

This is to hold what the project-local rule as to the
charset/encoding for the commit log message is.  Lack of it
defaults to utf-8.

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

---

 * This is not needed to make the gitk patch I just sent out
   work, because git-repo-config can do its own thing without
   the C-level integration like this.

   That may or may not be a good thing, though.  I wished either
   'git-var i18n.commitencoding' or 'git-repo-config --get
   i18n.commitencoding' in a vanilla repository to emit the
   default "utf-8".  Johannes?

 cache.h       |    3 +++
 config.c      |    5 +++++
 environment.c |    1 +
 3 files changed, 9 insertions(+), 0 deletions(-)

applies-to: 5596ac6f4661c80f823d93de7fa9aeec65ace1f1
4e72dcec89c7cda7022d4ec2dd686e77deb5376e
diff --git a/cache.h b/cache.h
index 61bf884..634b5aa 100644
--- a/cache.h
+++ b/cache.h
@@ -399,6 +399,9 @@ extern int check_repository_format_versi
 extern char git_default_email[MAX_GITNAME];
 extern char git_default_name[MAX_GITNAME];
 
+#define MAX_ENCODING_LENGTH 64
+extern char git_commit_encoding[MAX_ENCODING_LENGTH];
+
 /* Sane ctype - no locale, and works with signed chars */
 #undef isspace
 #undef isdigit
diff --git a/config.c b/config.c
index 0c43d76..152fa28 100644
--- a/config.c
+++ b/config.c
@@ -237,6 +237,11 @@ int git_default_config(const char *var, 
 		return 0;
 	}
 
+	if (!strcmp(var, "i18n.commitencoding")) {
+		strncpy(git_commit_encoding, value, sizeof(git_commit_encoding));
+		return 0;
+	}
+
 	/* Add other config variables here.. */
 	return 0;
 }
diff --git a/environment.c b/environment.c
index 3f19473..0886ad3 100644
--- a/environment.c
+++ b/environment.c
@@ -14,6 +14,7 @@ char git_default_name[MAX_GITNAME];
 int trust_executable_bit = 1;
 int only_use_symrefs = 0;
 int repository_format_version = 0;
+char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
 
 static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
 	*git_graft_file;
---
0.99.9.GIT

^ permalink raw reply related

* Re: git-send-mail in sh
From: Nikolai Weibull @ 2005-11-28  0:15 UTC (permalink / raw)
  To: git
In-Reply-To: <7v4q5xbvip.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:

> The ${parameter##word} syntax is in IEEE 1003.1-2001, and bash, ksh,
> and dash seem to work with it.

You can add Zsh to that list.

        nikolai

-- 
Nikolai Weibull: now available free of charge at http://bitwi.se/!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}

^ permalink raw reply

* Re: [PATCH] gitk: UTF-8 support
From: Junio C Hamano @ 2005-11-28  0:12 UTC (permalink / raw)
  To: Pavel Roskin; +Cc: Paul Mackerras, git
In-Reply-To: <20051124021231.nrg8448gk8w4owk8@webmail.spamcop.net>

Pavel Roskin <proski@gnu.org> writes:

>> And as I suggested in another message (in the died-out thread
>> about gitweb), we could have i18n.commitEncoding in the
>> configuration to help gitk and gitweb.  I think that is the same
>> as your "other option".
>
> Yes.  Then my patch needs to be changed to set encoding to that setting and only
> if it's present.

The following patch on top of your patch has seen only very
light testing, but it seems to do the right thing for my
repository with utf-8 commit messages and another with euc-jp
commit messages.  For the latter, I needed to do:

	$ git-repo-config i18n.commitencoding euc-jp

-- >8 --
[PATCH] gitk: Use i18n.commitencoding configuration item.

Hardcoding "utf-8" in the script breaks projects that use local
encoding, so allow setting i18n.commitEncoding.

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

---
diff --git a/gitk b/gitk
index b53a5c5..2242216 100755
--- a/gitk
+++ b/gitk
@@ -3669,7 +3669,14 @@ set datemode 0
 set boldnames 0
 set diffopts "-U 5 -p"
 set wrcomcmd "git-diff-tree --stdin -p --pretty"
-set gitencoding "utf-8"
+
+set gitencoding ""
+catch {
+    set gitencoding [exec git-repo-config --get i18n.commitencoding]
+}
+if {$gitencoding == ""} {
+	set gitencoding "utf-8"
+}
 
 set mainfont {Helvetica 9}
 set textfont {Courier 9}

^ permalink raw reply related

* Re: git-send-mail in sh
From: Andreas Ericsson @ 2005-11-27 23:34 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7v4q5xbvip.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:
> Andreas Ericsson <ae@op5.se> writes:
> 
>>            # single commit
>>            com1="${com1##*^}"
>>            range="$com1^1..$com1"
>>            ;;
> 
> 
> I wonder if you meant "${com1%^}" here, to remove the trailing '^'.
> 

I did/do/done. :)

> 
>>        ?*^[0-9]|?*^[0-9][0-9])
>>            # series of commits, ranging back from <commit-ish>
>>            range="$com1..${com1%%^*}"
>>            ;;
>>        ^[0-9]|^[0-9][0-9])
>>            # series of commits, ranging back from HEAD
>>            range="HEAD$com1..HEAD"
>>            ;;
> 
> 
> N generation back in extended SHA1 notation uses a tilde '~',


I just noticed that after sending the original email. I've changed it to 
take tilde instead.

> Also limiting to between 0 and 99
> generations misinterprets "HEAD~123".
> 
> Although checking only the letter that follows the tilde is a
> digit mistakenly accepts something like "master~1-bad-one", that
> is already malformed and whatever comes downstream would barf,
> so that may be fine.  How about something like:
> 
> 	?*'~'[1-9]*)
>         	range="$com1..${com1%~*}" ;;
> 	'~'[1-9]*)
>         	range="HEAD$com1..HEAD" ;;
> 

Fine by me, although that 99 patches limit was sort of semi-intentional. 
Doing it this way makes case order matter since
	?*'~'[1-9]*

will also match

	<commit>~3..HEAD

I'll stick with your way though and put a comment there so people don't 
touch the ordering.


Thanks for the expr lesson btw.

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

^ permalink raw reply

* Re: still unclear on setting up a repository
From: Petr Baudis @ 2005-11-27 23:15 UTC (permalink / raw)
  To: Randal L. Schwartz; +Cc: git
In-Reply-To: <86br0g883v.fsf@blue.stonehenge.com>

Dear diary, on Sun, Nov 20, 2005 at 01:40:20AM CET, I got a letter
where "Randal L. Schwartz" <merlyn@stonehenge.com> said that...
> This seems to report the right thing.  I have a branch "origin"
> that points at the remote repository.  So far, I think I'm understanding
> what's happening.  But now, go boom:
> 
>         % cg-push
>         cg-push: where to push to?
> 
> Huh?  How do I do the initial push?  Not this way?  Is it me, docs, or
> code that is broken here?

The code was broken, cg-push wouldn't default to origin unless you
already had an origin head, which you obviously can't have when you are
going to push for the first time. Thanks, fixed.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
VI has two modes: the one in which it beeps and the one in which
it doesn't.

^ permalink raw reply

* Re: Emacs mode for git
From: Junio C Hamano @ 2005-11-27 22:52 UTC (permalink / raw)
  To: Alexandre Julliard; +Cc: git
In-Reply-To: <87u0dx7mov.fsf@wine.dyndns.org>

Alexandre Julliard <julliard@winehq.org> writes:

> Here's the beginning of an Emacs mode for git. My primary goal at this
> point is to replicate the behavior of the pcl-cvs mode.

Sounds nice -- I might switch to this myself if it is easy to
use (currently my fingers are trained to run git from
compilation mode buffer, so I need to switch anyway).

I regularly use the vc interface for working with CVS and never
have used PCL-CVS myself.

^ permalink raw reply

* [PATCH] Fix gitk this->selected diffs
From: Yann Dirson @ 2005-11-27 22:29 UTC (permalink / raw)
  To: GIT list; +Cc: Paul Mackerras

The change made in 8b7e5d76e836396a097bb6f61cf930ea872a7bd3 to
accomodate dense revlists in single-commit diffs has broken computing
of diffs between arbitrary trees, which does need to consider two
commit ids.

This patch changes the two git-diff-tree calls to get the necessary
two ids in this case.  It does so by propagating a "singlecommit" flag
through all functions involved via an additional argument.

Signed-off-by: Yann Dirson <ydirson@altern.org>

---

this->selected diffs have been broken for a month now - I'd like it to
get fixed before 1.0 :)

A previous version of this patch was sent under the 'Make "gitk" work
better with dense revlists' thread.  I have done some minor cleanups
to it.  I'm still not comfortable with the number of funcs I had to
touch to propagate the information - any better idea ?

 gitk |   53 ++++++++++++++++++++++++++++++++---------------------
 1 files changed, 32 insertions(+), 21 deletions(-)

applies-to: 1dc0816b6c98ef90985d2761f1ab80739e4fbc7d
4664daceca4faac92f0e15d3e80824f172192d84
diff --git a/gitk b/gitk
index 3dd97e2..4841a80 100755
--- a/gitk
+++ b/gitk
@@ -2164,9 +2164,9 @@ proc selectline {l isnew} {
     $cflist delete 0 end
     $cflist insert end "Comments"
     if {$nparents($id) == 1} {
-	startdiff [concat $id $parents($id)]
+	startdiff [concat $id $parents($id)] 1
     } elseif {$nparents($id) > 1} {
-	mergediff $id
+	mergediff $id 1
     }
 }
 
@@ -2235,7 +2235,7 @@ proc goforw {} {
     }
 }
 
-proc mergediff {id} {
+proc mergediff {id singlecommit} {
     global parents diffmergeid diffmergegca mergefilelist diffpindex
 
     set diffmergeid $id
@@ -2246,7 +2246,7 @@ proc mergediff {id} {
 	    showmergediff
 	}
     } else {
-	contmergediff {}
+	contmergediff {} $singlecommit
     }
 }
 
@@ -2266,7 +2266,7 @@ proc findgca {ids} {
     return $gca
 }
 
-proc contmergediff {ids} {
+proc contmergediff {ids singlecommit} {
     global diffmergeid diffpindex parents nparents diffmergegca
     global treediffs mergefilelist diffids treepending
 
@@ -2283,7 +2283,7 @@ proc contmergediff {ids} {
 	if {![info exists treediffs($ids)]} {
 	    set diffids $ids
 	    if {![info exists treepending]} {
-		gettreediffs $ids
+		gettreediffs $ids $singlecommit
 	    }
 	    return
 	}
@@ -2761,39 +2761,45 @@ proc similarity {pnum l nlc f events} {
     return [expr {200 * $same / (2 * $same + $diff)}]
 }
 
-proc startdiff {ids} {
+proc startdiff {ids singlecommit} {
     global treediffs diffids treepending diffmergeid
 
     set diffids $ids
     catch {unset diffmergeid}
     if {![info exists treediffs($ids)]} {
 	if {![info exists treepending]} {
-	    gettreediffs $ids
+	    gettreediffs $ids $singlecommit
 	}
     } else {
-	addtocflist $ids
+	addtocflist $ids $singlecommit
     }
 }
 
-proc addtocflist {ids} {
+proc addtocflist {ids singlecommit} {
     global treediffs cflist
     foreach f $treediffs($ids) {
 	$cflist insert end $f
     }
-    getblobdiffs $ids
+    getblobdiffs $ids $singlecommit
 }
 
-proc gettreediffs {ids} {
+proc gettreediffs {ids singlecommit} {
     global treediff parents treepending
     set treepending $ids
     set treediff {}
     set id [lindex $ids 0]
-    if [catch {set gdtf [open "|git-diff-tree --no-commit-id -r $id" r]}] return
+    if {$singlecommit == 1} {
+	set range "$id"
+    } else {
+	set p [lindex $ids 1]
+	set range "$p $id"
+    }
+    if [catch {set gdtf [open "|git-diff-tree --no-commit-id -r $range" r]}] return
     fconfigure $gdtf -blocking 0
-    fileevent $gdtf readable [list gettreediffline $gdtf $ids]
+    fileevent $gdtf readable [list gettreediffline $gdtf $ids $singlecommit]
 }
 
-proc gettreediffline {gdtf ids} {
+proc gettreediffline {gdtf ids singlecommit} {
     global treediff treediffs treepending diffids diffmergeid
 
     set n [gets $gdtf line]
@@ -2803,12 +2809,12 @@ proc gettreediffline {gdtf ids} {
 	set treediffs($ids) $treediff
 	unset treepending
 	if {$ids != $diffids} {
-	    gettreediffs $diffids
+	    gettreediffs $diffids $singlecommit
 	} else {
 	    if {[info exists diffmergeid]} {
-		contmergediff $ids
+		contmergediff $ids $singlecommit
 	    } else {
-		addtocflist $ids
+		addtocflist $ids $singlecommit
 	    }
 	}
 	return
@@ -2817,13 +2823,18 @@ proc gettreediffline {gdtf ids} {
     lappend treediff $file
 }
 
-proc getblobdiffs {ids} {
+proc getblobdiffs {ids singlecommit} {
     global diffopts blobdifffd diffids env curdifftag curtagstart
     global difffilestart nextupdate diffinhdr treediffs
 
     set id [lindex $ids 0]
     set env(GIT_DIFF_OPTS) $diffopts
-    set cmd [list | git-diff-tree --no-commit-id -r -p -C $id]
+    if {$singlecommit == 1} {
+	set cmd [list | git-diff-tree --no-commit-id -r -p -C $id]
+    } else {
+	set p [lindex $ids 1]
+	set cmd [list | git-diff-tree --no-commit-id -r -p -C $p $id]
+    }
     if {[catch {set bdf [open $cmd r]} err]} {
 	puts "error getting diffs: $err"
 	return
@@ -3340,7 +3351,7 @@ proc doseldiff {oldid newid} {
     $ctext conf -state disabled
     $ctext tag delete Comments
     $ctext tag remove found 1.0 end
-    startdiff [list $newid $oldid]
+    startdiff [list $newid $oldid] 0
 }
 
 proc mkpatch {} {
---
0.99.9.GIT

-- 
Yann Dirson    <ydirson@altern.org> |
Debian-related: <dirson@debian.org> |   Support Debian GNU/Linux:
                                    |  Freedom, Power, Stability, Gratis
     http://ydirson.free.fr/        | Check <http://www.debian.org/>

^ permalink raw reply related

* Emacs mode for git
From: Alexandre Julliard @ 2005-11-27 22:25 UTC (permalink / raw)
  To: git

[-- Attachment #1: Type: text/plain, Size: 455 bytes --]

Here's the beginning of an Emacs mode for git. My primary goal at this
point is to replicate the behavior of the pcl-cvs mode.

Most basic functions are implemented (diff, commit, revert, add/remove
files, .gitignore, etc.) There is currently no support for multiple
branches or file merges. The code has been tested only on Emacs 21, it
will probably need some tweaking to run on XEmacs.

Feedback welcome...

-- 
Alexandre Julliard
julliard@winehq.org


[-- Attachment #2: git.el --]
[-- Type: text/plain, Size: 32271 bytes --]

;;; git.el --- A user interface for git

;; Copyright (C) 2005 Alexandre Julliard <julliard@winehq.org>

;; Version: 0.1

;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation; either version 2 of
;; the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be
;; useful, but WITHOUT ANY WARRANTY; without even the implied
;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
;; PURPOSE.  See the GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public
;; License along with this program; if not, write to the Free
;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
;; MA 02111-1307 USA

;;; Commentary:

;; This file contains an interface for the git version control
;; system. It provides easy access to the most frequently used git
;; commands. The user interface is as far as possible identical to
;; that of the PCL-CVS mode.
;;
;; To install: put this file on the load-path and place the following
;; in your .emacs file:
;;
;;    (require 'git)
;;
;; To start: `M-x git-status'
;;
;; TODO
;;  - better handling of subprocess errors
;;  - GIT_DIR support
;;  - hook into file save (after-save-hook)
;;  - diff against other branch
;;  - commands for renaming files
;;  - fetch and merge
;;

(eval-when-compile (require 'cl))
(require 'ewoc)


;;;; Faces
;;;; ------------------------------------------------------------

(defface git-status-face
  '((((class color) (background light)) (:foreground "purple")))
  "Git mode face used to highlight renamed files.")

(defface git-unmerged-face
  '((((class color) (background light)) (:foreground "red" :bold t)))
  "Git mode face used to highlight unmerged files.")

(defface git-unknown-face
  '((((class color) (background light)) (:foreground "goldenrod" :bold t)))
  "Git mode face used to highlight unknown files.")

(defface git-uptodate-face
  '((((class color) (background light)) (:foreground "grey60")))
  "Git mode face used to highlight up-to-date files.")

(defface git-ignored-face
  '((((class color) (background light)) (:foreground "grey60")))
  "Git mode face used to highlight ignored files.")

(defface git-mark-face
  '((((class color) (background light)) (:foreground "red" :bold t)))
  "Git mode face used for the file marks.")

(defface git-header-face
  '((((class color) (background light)) (:foreground "blue")))
  "Git mode face used for commit headers.")

(defface git-separator-face
  '((((class color) (background light)) (:foreground "brown")))
  "Git mode face used for commit separator.")

(defface git-permission-face
  '((((class color) (background light)) (:foreground "green" :bold t)))
  "Git mode face used for permission changes.")

(defvar git-committer-name nil
  "*User name to use for commits.
If not set, fall back to `add-log-full-name' and then `user-full-name'.")

(defvar git-committer-email nil
  "*Email address to use for commits.
If not set, fall back to `add-log-mailing-address' and then `user-mail-address'.")

(defconst git-log-msg-separator "--- log message follows this line ---")

(defconst git-per-dir-ignore-file ".gitignore"
  "Name of the per-directory ignore file.")


;;;; Utilities
;;;; ------------------------------------------------------------

(defun git-get-env-strings (env)
  "Build a list of NAME=VALUE strings from a list of environment strings."
  (mapcar (lambda (entry) (concat (car entry) "=" (cdr entry))) env))

(defun git-call-process-env (program infile buffer display env &rest args)
  "Wrapper for call-process that sets environment strings."
  (let ((coding-system-for-read 'utf-8)
        (coding-system-for-write 'utf-8))
    (if env
        (apply #'call-process "env" infile buffer display
               (append (git-get-env-strings env) (list program) args))
      (apply #'call-process program infile buffer display args))))

(defun git-run-process-region (buffer start end args)
  "Run a git process with a buffer region as input."
  (let ((output-buffer (current-buffer))
        (dir default-directory))
    (with-current-buffer buffer
      (let ((coding-system-for-read 'utf-8)  ; FIXME: should be configurable
            (coding-system-for-write 'utf-8))
        (cd dir)
        (apply #'call-process-region start end (car args)
               nil (list output-buffer nil) nil (cdr args))))))

(defun git-run-command-buffer (buffer-name &rest args)
  "Run a git command, sending the output to a buffer named BUFFER-NAME."
  (let ((dir default-directory)
        (buffer (get-buffer-create buffer-name)))
    (message "Running %s..." (car args))
    (with-current-buffer buffer
      (let ((default-directory dir)
            (buffer-read-only nil))
        (erase-buffer)
        (apply #'git-call-process-env (car args) nil buffer nil nil (cdr args))))
    (message "Running %s...done" (car args))
    buffer))

(defun git-run-command (buffer env &rest args)
  (message "Running %s..." (car args))
  (apply #'git-call-process-env (car args) nil buffer nil env (cdr args))
  (message "Running %s...done" (car args)))

(defun git-run-command-region (buffer start end env &rest args)
  "Run a git command with specified buffer region as input."
  (message "Running %s..." (car args))
  (unless (eq 0 (git-run-process-region
                 buffer start end
                 (if env (append (list "env") (git-get-env-strings env) args) args)))
    (error "Failed to run \"%s\":\n%s" (mapconcat (lambda (x) x) args " ") (buffer-string)))
  (message "Running %s...done" (car args)))

(defun git-get-buffer-sha1 (buffer)
  "Read a SHA1 string from the specified buffer."
  (with-current-buffer buffer
    (goto-char (point-min))
    (and (re-search-forward "[0-9a-f]\\{40\\}")
         (match-string 0))))

(defun git-get-string-sha1 (string)
  "Read a SHA1 from the specified string."
  (let ((pos (string-match "[0-9a-f]\\{40\\}" string)))
    (and pos (substring string pos (match-end 0)))))

(defun git-get-committer-name ()
  "Return the name to use as GIT_COMMITTER_NAME."
  ; copied from log-edit
  (or git-committer-name
      (and (boundp 'add-log-full-name) add-log-full-name)
      (and (fboundp 'user-full-name) (user-full-name))
      (and (boundp 'user-full-name) user-full-name)))

(defun git-get-committer-email ()
  "Return the email address to use as GIT_COMMITTER_EMAIL."
  ; copied from log-edit
  (or git-committer-email
      (and (boundp 'add-log-mailing-address) add-log-mailing-address)
      (and (fboundp 'user-mail-address) (user-mail-address))
      (and (boundp 'user-mail-address) user-mail-address)))

(defun git-escape-file-name (name)
  "Escape a file name if necessary."
  (if (string-match "[\n\t\"\\]" name)
      (concat "\""
              (mapconcat (lambda (c)
                   (case c
                     (?\n "\\n")
                     (?\t "\\t")
                     (?\\ "\\\\")
                     (?\" "\\\"")
                     (t (char-to-string c))))
                 name "")
              "\"")
    name))

;stolen from pcl-cvs
(defun git-append-to-ignore (file)
  "Add a file name to the ignore file in its directory."
  (let* ((fullname (expand-file-name file))
         (dir (file-name-directory fullname))
         (name (file-name-nondirectory fullname)))
  (save-window-excursion
    (set-buffer (find-file-noselect (expand-file-name git-per-dir-ignore-file dir)))
    (goto-char (point-max))
    (unless (zerop (current-column)) (insert "\n"))
    (insert name "\n")
    (sort-lines nil (point-min) (point-max))
    (save-buffer))))


;;;; Wrappers for basic git commands
;;;; ------------------------------------------------------------

(defun git-rev-parse (rev)
  "Parse a revision name and return its SHA1."
  (git-get-string-sha1
   (with-output-to-string
     (with-current-buffer standard-output
       (git-call-process-env "git-rev-parse" nil t nil nil rev)))))

(defun git-symbolic-ref (ref)
  "Wrapper for the git-symbolic-ref command."
  (car
   (split-string
    (with-output-to-string
      (with-current-buffer standard-output
        (git-call-process-env "git-symbolic-ref" nil t nil nil ref)))
    "\n")))

(defun git-update-ref (ref val &optional oldval)
  "Update a reference by calling git-update-ref."
  (apply #'git-call-process-env "git-update-ref" nil nil nil nil ref val (if oldval (list oldval))))

(defun git-read-tree (tree &optional index-file)
  "Read a tree into the index file."
  (apply #'git-call-process-env
         "git-read-tree" nil nil nil
         (if index-file `(("GIT_INDEX_FILE" . ,index-file)) nil)
         (if tree (list tree))))

(defun git-write-tree (&optional index-file)
  "Call git-write-tree and return the resulting tree SHA1 as a string."
  (git-get-string-sha1
   (with-output-to-string
     (with-current-buffer standard-output
       (git-call-process-env
        "git-write-tree" nil t nil
        (if index-file `(("GIT_INDEX_FILE" . ,index-file)) nil))))))

(defun git-commit-tree (buffer tree parents)
  "Call git-commit-tree with buffer as input and return the resulting commit SHA1."
  (let ((author-name (git-get-committer-name))
        (author-email (git-get-committer-email))
        author-date log-start log-end args)
    (with-current-buffer buffer
      (goto-char (point-min))
      (if
          (setq log-start (re-search-forward (concat "^" git-log-msg-separator "\n") nil t))
          (progn
            (goto-char (point-min))
            (when (re-search-forward "^Author: +\\(.*?\\) *<\\(.*\\)> *$" nil t)
              (setq author-name (match-string 1)
                    author-email (match-string 2)))
            (goto-char (point-min))
            (when (re-search-forward "^Date: +\\(.*\\)$" nil t)
              (setq author-date (match-string 1))))
        (setq log-start (point-min)))
      (setq log-end (point-max)))
    (dolist (p parents)
      (push "-p" args)
      (push p args))
    (git-get-string-sha1
     (with-output-to-string
       (with-current-buffer standard-output
         (let ((env `(("GIT_AUTHOR_NAME" . ,author-name)
                      ("GIT_AUTHOR_EMAIL" . ,author-email)
                      ("GIT_COMMITTER_NAME" . ,(git-get-committer-name))
                      ("GIT_COMMITTER_EMAIL" . ,(git-get-committer-email)))))
           (when author-date (push `("GIT_AUTHOR_DATE" . ,author-date) env))
           (apply #'git-run-command-region
                  buffer log-start log-end env
                  "git-commit-tree" tree (nreverse args))))))))

(defun git-empty-db-p ()
  "Check if the git db is empty (no commit done yet)."
  (not (file-exists-p ".git/HEAD")))


;;;; File info structure
;;;; ------------------------------------------------------------

; fileinfo structure stolen from pcl-cvs
(defstruct (git-fileinfo
            (:copier nil)
            (:constructor git-create-fileinfo (state name &optional old-perm new-perm rename-state orig-name marked))
            (:conc-name git-fileinfo->))
  marked              ;; t/nil
  state               ;; current state
  name                ;; file name
  old-perm new-perm   ;; permission flags
  rename-state        ;; rename or copy state
  orig-name           ;; original name for renames or copies
  needs-refresh)      ;; whether file needs to be refreshed

(defvar git-status nil)

(defun git-clear-status (status)
  "Remove everything from the status list."
  (ewoc-filter status (lambda (info) nil)))

(defun git-set-files-state (files state)
  "Set the state of a list of files."
  (dolist (info files)
    (unless (eq (git-fileinfo->state info) state)
      (setf (git-fileinfo->state info) state)
      (setf (git-fileinfo->rename-state info) nil)
      (setf (git-fileinfo->orig-name info) nil)
      (setf (git-fileinfo->needs-refresh info) t))))

(defun git-state-code (code)
  "Convert from a string to a added/deleted/modified state."
  (case (string-to-char code)
    (?M 'modified)
    (?? 'unknown)
    (?A 'added)
    (?D 'deleted)
    (?U 'unmerged)
    (t nil)))

(defun git-status-code-as-string (code)
  "Format a git status code as string."
  (case code
    ('modified (propertize "Modified" 'face 'git-status-face))
    ('unknown  (propertize "Unknown " 'face 'git-unknown-face))
    ('added    (propertize "Added   " 'face 'git-status-face))
    ('deleted  (propertize "Deleted " 'face 'git-status-face))
    ('unmerged (propertize "Unmerged" 'face 'git-unmerged-face))
    ('uptodate (propertize "Uptodate" 'face 'git-uptodate-face))
    ('ignored  (propertize "Ignored " 'face 'git-ignored-face))
    (t "?       ")))

(defun git-rename-as-string (info)
  "Return a string describing the copy or rename associated with INFO, or an empty string if none."
  (let ((state (git-fileinfo->rename-state info)))
    (if state
        (propertize
         (concat "   ("
                 (if (eq state 'copy) "copied from "
                   (if (eq (git-fileinfo->state info) 'added) "renamed to "
                     "renamed from "))
                 (git-escape-file-name (git-fileinfo->orig-name info))
                 ")") 'face 'git-status-face)
      "")))

(defun git-permissions-as-string (old-perm new-perm)
  "Format a permission change as string."
  (propertize
   (if (or (not old-perm)
           (not new-perm)
           (eq 0 (logand #O111 (logxor old-perm new-perm))))
       "  "
     (if (eq 0 (logand #O111 old-perm)) "+x" "-x"))
  'face 'git-permission-face))

(defun git-fileinfo-prettyprint (info)
  "Pretty-printer for the git-fileinfo structure."
  (insert (format "   %s %s %s  %s%s"
                  (if (git-fileinfo->marked info) (propertize "*" 'face 'git-mark-face) " ")
                  (git-status-code-as-string (git-fileinfo->state info))
                  (git-permissions-as-string (git-fileinfo->old-perm info) (git-fileinfo->new-perm info))
                  (git-escape-file-name (git-fileinfo->name info))
                  (git-rename-as-string info))))

(defun git-parse-status (status)
  "Parse the output of git-diff-index in the current buffer."
  (goto-char (point-min))
  (while (re-search-forward
          ":\\([0-7]\\{6\\}\\) \\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} [0-9a-f]\\{40\\} \\(\\([ADMU]\\)\0\\([^\0]+\\)\\|\\([CR]\\)[0-9]*\0\\([^\0]+\\)\0\\([^\0]+\\)\\)\0"
          nil t 1)
    (let ((old-perm (string-to-number (match-string 1) 8))
          (new-perm (string-to-number (match-string 2) 8))
          (state (or (match-string 4) (match-string 6)))
          (name (or (match-string 5) (match-string 7)))
          (new-name (match-string 8)))
      (if new-name  ; copy or rename
          (if (eq ?C (string-to-char state))
              (ewoc-enter-last status (git-create-fileinfo 'added new-name old-perm new-perm 'copy name))
            (ewoc-enter-last status (git-create-fileinfo 'deleted name 0 0 'rename new-name))
            (ewoc-enter-last status (git-create-fileinfo 'added new-name old-perm new-perm 'rename name)))
        (ewoc-enter-last status (git-create-fileinfo (git-state-code state) name old-perm new-perm))))))

(defun git-find-status-file (status file)
  "Find a given file in the status ewoc and return its node."
  (let ((node (ewoc-nth status 0)))
    (while (and node (not (string= file (git-fileinfo->name (ewoc-data node)))))
      (setq node (ewoc-next status node)))
    node))

(defun git-parse-ls-files (status default-state &optional skip-existing)
  "Parse the output of git-ls-files in the current buffer."
  (goto-char (point-min))
  (while (re-search-forward "\\([HMRCK?]\\) \\([^\0]*\\)\0" nil t 1)
    (let ((state (match-string 1))
          (name (match-string 2))
          infolist)
      (unless (and skip-existing (git-find-status-file status name))
        (push (git-create-fileinfo (or (git-state-code state) default-state) name) infolist))
      (dolist (info infolist)
          (ewoc-enter-last status info)))))

(defun git-add-status-file (state name &optional old-perm new-perm)
  "Add a new file to the status list (if not existing already) and return its node."
  (unless git-status (error "Not in git-status buffer."))
  (or (git-find-status-file git-status name)
      (ewoc-enter-last git-status (git-create-fileinfo state name))))

(defun git-marked-files ()
  "Return a list of all marked files, or if none a list containing just the file at cursor position."
  (unless git-status (error "Not in git-status buffer."))
  (or (ewoc-collect git-status (lambda (info) (git-fileinfo->marked info)))
      (list (ewoc-data (ewoc-locate git-status)))))

(defun git-marked-files-state (&rest states)
  "Return marked files that are in the specified states."
  (let ((files (git-marked-files))
        result)
    (dolist (info files)
      (when (memq (git-fileinfo->state info) states)
        (push info result)))
    result))

(defun git-refresh-files ()
  "Refresh all files that need it and clear the needs-refresh flag."
  (unless git-status (error "Not in git-status buffer."))
  (ewoc-map
   (lambda (info)
     (let ((refresh (git-fileinfo->needs-refresh info)))
       (setf (git-fileinfo->needs-refresh info) nil)
       refresh))
   git-status)
  ; move back to goal column
  (when goal-column (move-to-column goal-column)))

(defun git-refresh-ewoc-hf (status)
  "Refresh the ewoc header and footer."
  (ewoc-set-hf status
               (format "Directory:  %s\nBranch:     %s\nHead:       %s\n"
                       default-directory
                       (git-symbolic-ref "HEAD")
                       (if (git-empty-db-p) "Nothing committed yet" (git-rev-parse "HEAD")))
               (if (ewoc-nth status 0) "" "    No changes.")))

(defun git-check-exclude-file ()
  "Check for non empty .git/info/exclude file like git-status does."
  (when (file-readable-p ".git/info/exclude")
    (with-temp-buffer
      (insert-file-contents ".git/info/exclude" nil nil nil t)
      (goto-char (point-min))
      (re-search-forward "^[^#]" nil t))))

(defun git-get-filenames (files)
  (mapcar (lambda (info) (git-fileinfo->name info)) files))

(defun git-update-index (index-file files)
  "Run git-update-index on a list of files."
  (let ((env (and index-file `(("GIT_INDEX_FILE" . ,index-file))))
        added deleted modified)
    (dolist (info files)
      (case (git-fileinfo->state info)
        ('added (push info added))
        ('deleted (push info deleted))
        ('modified (push info modified))))
    (when added
      (apply #'git-run-command nil env "git-update-index" "--add" "--" (git-get-filenames added)))
    (when deleted
      (apply #'git-run-command nil env "git-update-index" "--remove" "--" (git-get-filenames deleted)))
    (when modified
      (apply #'git-run-command nil env "git-update-index" "--" (git-get-filenames modified)))))

(defun git-do-commit ()
  "Perform the actual commit using the current buffer as log message."
  (interactive)
  (let ((buffer (current-buffer))
        (index-file (make-temp-file "gitidx")))
    (with-current-buffer log-edit-parent-buffer
      (unwind-protect
          (let ((files (git-marked-files-state 'added 'deleted 'modified))
                head head-tree)
            (unless (git-empty-db-p)
              (setq head (git-rev-parse "HEAD")
                    head-tree (git-rev-parse "HEAD^{tree}")))
            (if files
                (progn
                  (git-read-tree head-tree index-file)
                  (git-update-index nil files)         ;update both the default index
                  (git-update-index index-file files)  ;and the temporary one
                  (let ((tree (git-write-tree index-file)))
                    (if (or (not (string-equal tree head-tree))
                            (yes-or-no-p "The tree was not modified, do you really want to perform an empty commit? "))
                        (let ((commit (git-commit-tree buffer tree (if head (list head)))))
                          (git-update-ref "HEAD" commit head)
                          (git-set-files-state files 'uptodate)
                          (git-refresh-files)
                          (git-refresh-ewoc-hf git-status)
                          (message "Committed %s." commit))
                      (message "Commit aborted."))))
              (message "No files to commit.")))
        (delete-file index-file)))))


;;;; Interactive functions
;;;; ------------------------------------------------------------

(defun git-mark-file ()
  "Mark the file that the cursor is on and move to the next one."
  (interactive)
  (unless git-status (error "Not in git-status buffer."))
  (let* ((pos (ewoc-locate git-status))
         (info (ewoc-data pos)))
    (setf (git-fileinfo->marked info) t)
    (ewoc-invalidate git-status pos)
    (ewoc-goto-next git-status 1)))

(defun git-unmark-file ()
  "Unmark the file that the cursor is on and move to the next one."
  (interactive)
  (unless git-status (error "Not in git-status buffer."))
  (let* ((pos (ewoc-locate git-status))
         (info (ewoc-data pos)))
    (setf (git-fileinfo->marked info) nil)
    (ewoc-invalidate git-status pos)
    (ewoc-goto-next git-status 1)))

(defun git-unmark-file-up ()
  "Unmark the file that the cursor is on and move to the previous one."
  (interactive)
  (unless git-status (error "Not in git-status buffer."))
  (let* ((pos (ewoc-locate git-status))
         (info (ewoc-data pos)))
    (setf (git-fileinfo->marked info) nil)
    (ewoc-invalidate git-status pos)
    (ewoc-goto-prev git-status 1)))

(defun git-mark-all ()
  "Mark all files."
  (interactive)
  (unless git-status (error "Not in git-status buffer."))
  (ewoc-map (lambda (info) (setf (git-fileinfo->marked info) t) t) git-status)
  ; move back to goal column after invalidate
  (when goal-column (move-to-column goal-column)))

(defun git-unmark-all ()
  "Unmark all files."
  (interactive)
  (unless git-status (error "Not in git-status buffer."))
  (ewoc-map (lambda (info) (setf (git-fileinfo->marked info) nil) t) git-status)
  ; move back to goal column after invalidate
  (when goal-column (move-to-column goal-column)))

(defun git-toggle-all-marks ()
  "Toggle all file marks."
  (interactive)
  (unless git-status (error "Not in git-status buffer."))
  (ewoc-map (lambda (info) (setf (git-fileinfo->marked info) (not (git-fileinfo->marked info))) t) git-status)
  ; move back to goal column after invalidate
  (when goal-column (move-to-column goal-column)))

(defun git-next-file (&optional n)
  "Move the selection down N files."
  (interactive "p")
  (unless git-status (error "Not in git-status buffer."))
  (ewoc-goto-next git-status n))

(defun git-prev-file (&optional n)
  "Move the selection up N files."
  (interactive "p")
  (unless git-status (error "Not in git-status buffer."))
  (ewoc-goto-prev git-status n))

(defun git-add-file ()
  "Add marked file(s) to the index cache."
  (interactive)
  (let ((files (git-marked-files-state 'unknown)))
    (unless files
      (push (ewoc-data
             (git-add-status-file 'added (file-relative-name
                                          (read-file-name "File to add: " nil nil t))))
            files))
    (apply #'git-run-command nil nil "git-update-index" "--info-only" "--add" "--" (git-get-filenames files))
    (git-set-files-state files 'added)
    (git-refresh-files)))

(defun git-ignore-file ()
  "Add marked file(s) to the ignore list."
  (interactive)
  (let ((files (git-marked-files-state 'unknown)))
    (unless files
      (push (ewoc-data
             (git-add-status-file 'unknown (file-relative-name
                                            (read-file-name "File to ignore: " nil nil t))))
            files))
    (dolist (info files) (git-append-to-ignore (git-fileinfo->name info)))
    (git-set-files-state files 'ignored)
    (git-refresh-files)))

(defun git-remove-file ()
  "Remove the marked file(s)."
  (interactive)
  (let ((files (git-marked-files-state 'added 'modified 'unknown 'uptodate)))
    (unless files
      (push (ewoc-data
             (git-add-status-file 'unknown (file-relative-name
                                            (read-file-name "File to remove: " nil nil t))))
            files))
    (if (yes-or-no-p
         (format "Remove %d file%s? " (length files) (if (> (length files) 1) "s" "")))
        (progn
          (dolist (info files)
            (let ((name (git-fileinfo->name info)))
              (when (file-exists-p name) (delete-file name))))
          (apply #'git-run-command nil nil "git-update-index" "--info-only" "--remove" "--" (git-get-filenames files))
          ; remove unknown files from the list, set the others to deleted
          (ewoc-filter git-status
                       (lambda (info files)
                         (not (and (memq info files) (eq (git-fileinfo->state info) 'unknown))))
                       files)
          (git-set-files-state files 'deleted)
          (git-refresh-files))
      (message "Aborting"))))

(defun git-revert-file ()
  "Revert changes to the marked file(s)."
  (interactive)
  (let ((files (git-marked-files))
        added deleted modified)
    (when (and files
               (yes-or-no-p
                (format "Revert %d file%s? " (length files) (if (> (length files) 1) "s" ""))))
      (dolist (info files)
        (case (git-fileinfo->state info)
          ('added (push info added))
          ('deleted (push info deleted))
          ('modified (push info modified))))
          ; FIXME: unmerged state
      (when added
          (apply #'git-run-command nil nil "git-update-index" "--force-remove" "--" (git-get-filenames added))
          (git-set-files-state added 'unknown))
      (when modified
          (apply #'git-run-command nil nil "git-checkout-index" "-f" "-u" "--" (git-get-filenames modified))
          (git-set-files-state modified 'uptodate))
      (when deleted
        (error "revert for deleted files not implemented yet"))
      (git-refresh-files))))

(defun git-remove-handled ()
  "Remove handled files from the status list."
  (interactive)
  (ewoc-filter git-status
               (lambda (info)
                 (not (or (eq (git-fileinfo->state info) 'ignored)
                          (eq (git-fileinfo->state info) 'uptodate))))))

(defun git-diff-file ()
  "Diff the marked file(s) against HEAD."
  (interactive)
  (let* ((files (git-marked-files))
         (buffer (apply #'git-run-command-buffer "*git-diff*" "git-diff-index" "-p" "-M" "HEAD" "--" (git-get-filenames files))))
    (with-current-buffer buffer
      (diff-mode)
      (goto-char (point-min))
      (setq buffer-read-only t))
    (display-buffer buffer)))

(defun git-log-file ()
  "Display a log of changes to the marked file(s)."
  (interactive)
  (let* ((files (git-marked-files))
         (buffer (apply #'git-run-command-buffer "*git-log*" "git-rev-list" "--pretty" "HEAD" "--" (git-get-filenames files))))
    (with-current-buffer buffer
      ; (git-log-mode)  FIXME: implement log mode
      (goto-char (point-min))
      (setq buffer-read-only t))
    (display-buffer buffer)))

(defun git-commit-file (arg)
  "Commit the marked file(s), asking for a commit message. With prefix arg, add Author and Date fields for easy editing."
  (interactive "P")
  (let ((buffer (get-buffer-create "*git-commit*")))
    (with-current-buffer buffer
      (when arg
        ; FIXME: should get these from the merge info if any
        (erase-buffer)
        (insert
         (propertize
          (format "Author: %s <%s>\nDate: %s"
                  (git-get-committer-name)
                  (git-get-committer-email)
                  (current-time-string))
          'face 'git-header-face)
         "\n"
         (propertize git-log-msg-separator 'face 'git-separator-face)
         "\n")))
    (log-edit #'git-do-commit nil nil buffer)))

(defun git-find-file ()
  "Visit the current file in its own buffer."
  (interactive)
  (unless git-status (error "Not in git-status buffer."))
  (let ((info (ewoc-data (ewoc-locate git-status))))
    (find-file (git-fileinfo->name info))))

(defun git-view-file ()
  "View the current file in its own buffer."
  (interactive)
  (unless git-status (error "Not in git-status buffer."))
  (let ((info (ewoc-data (ewoc-locate git-status))))
    (view-file (git-fileinfo->name info))))

(defun git-refresh-status ()
  "Refresh the git status buffer."
  (interactive)
  (let* ((status git-status)
         (pos (ewoc-locate status))
         (cur-name (and pos (git-fileinfo->name (ewoc-data pos)))))
    (unless status (error "Not in git-status buffer."))
    (git-clear-status status)
    (git-run-command nil nil "git-update-index" "--info-only" "--refresh")
    (if (git-empty-db-p)
        ; we need some special handling for an empty db
        (with-temp-buffer
          (git-run-command t nil "git-ls-files" "-z" "-t" "-c")
          (git-parse-ls-files status 'added))
      (with-temp-buffer
        (git-run-command t nil "git-diff-index" "-z" "-M" "HEAD")
        (git-parse-status status)))
    (when (git-check-exclude-file)
      (with-temp-buffer
        (git-run-command t nil "git-ls-files" "-z" "-t" "-o"
                         "--exclude-from=.git/info/exclude"
                         (concat "--exclude-per-directory=" git-per-dir-ignore-file))
        (git-parse-ls-files status 'unknown)))
    (git-refresh-files)
    (git-refresh-ewoc-hf status)
    ; move point to the current file name if any
    (let ((node (and cur-name (git-find-status-file status cur-name))))
      (when node (ewoc-goto-node status node)))))

(defun git-status-quit ()
  "Quit git-status mode."
  (interactive)
  (bury-buffer))

;;;; Major Mode
;;;; ------------------------------------------------------------

(defvar git-status-mode-hook nil
  "Run after `git-status-mode' is setup.")

(defvar git-status-mode-map nil
  "Keymap for git major mode.")

(defvar git-status nil
  "List of all files managed by the git-status mode.")

(unless git-status-mode-map
  (let ((map (make-keymap)))
    (suppress-keymap map)
    (define-key map " "   'git-next-file)
    (define-key map "a"   'git-add-file)
    (define-key map "c"   'git-commit-file)
    (define-key map "d"   'git-diff-file)
    (define-key map "="   'git-diff-file)
    (define-key map "f"   'git-find-file)
    (define-key map [RET] 'git-find-file)
    (define-key map "g"   'git-refresh-status)
    (define-key map "i"   'git-ignore-file)
    (define-key map "l"   'git-log-file)
    (define-key map "m"   'git-mark-file)
    (define-key map "M"   'git-mark-all)
    (define-key map "n"   'git-next-file)
    (define-key map "p"   'git-prev-file)
    (define-key map "q"   'git-status-quit)
    (define-key map "r"   'git-remove-file)
    (define-key map "T"   'git-toggle-all-marks)
    (define-key map "u"   'git-unmark-file)
    (define-key map "U"   'git-revert-file)
    (define-key map "v"   'git-view-file)
    (define-key map "x"   'git-remove-handled)
    (define-key map "\C-?" 'git-unmark-file-up)
    (define-key map "\M-\C-?" 'git-unmark-all)
    (setq git-status-mode-map map)))

;; git mode should only run in the *git status* buffer
(put 'git-status-mode 'mode-class 'special)

(defun git-status-mode ()
  "Major mode for interacting with Git.
Commands:
\\{git-status-mode-map}"
  (kill-all-local-variables)
  (buffer-disable-undo)
  (setq mode-name "git status"
        major-mode 'git-status-mode
        goal-column 17
        buffer-read-only t)
  (use-local-map git-status-mode-map)
  (let ((buffer-read-only nil))
    (erase-buffer)
  (let ((status (ewoc-create 'git-fileinfo-prettyprint "" "")))
    (set (make-local-variable 'git-status) status))
  (run-hooks 'git-status-mode-hook)))

(defun git-status (dir)
  "Entry point into git-status mode."
  (interactive "DSelect directory: ")
  (if (file-directory-p (concat (file-name-as-directory dir) ".git"))
      (let ((buffer (create-file-buffer (expand-file-name "*git-status*" dir))))
        (switch-to-buffer buffer)
        (git-status-mode)
        (cd dir)
        (git-refresh-status)
        (goto-char (point-min)))
    (message "%s is not a git working tree." dir)))

(provide 'git)
;;; git.el ends here

^ permalink raw reply

* Re: [PATCH 1/8] git-apply: work from subdirectory.
From: Junio C Hamano @ 2005-11-27 22:12 UTC (permalink / raw)
  To: Lars Magne Ingebrigtsen; +Cc: git
In-Reply-To: <m3fyph7q14.fsf@quimbies.gnus.org>

Lars Magne Ingebrigtsen <larsi@gnus.org> writes:

> Egads!  It's all my fault -- there's some code in the mail-to-news
> script that's truncating long header lines, and nobody's noticed up
> 'till now.  I've now twiddled it slightly; it should stop mangling
> References headers now...

Thanks, it looks good now --- checked with your message I am
responding to ;-).

^ permalink raw reply

* Re: git-send-mail in sh
From: Junio C Hamano @ 2005-11-27 22:01 UTC (permalink / raw)
  To: Andreas Ericsson; +Cc: git
In-Reply-To: <4388E33A.8000004@op5.se>

Andreas Ericsson <ae@op5.se> writes:

> Here's what I have on disk right now. The ${var##*^} syntax was decided 
> to be portable in some earlier discussion, so I'm sticking with it 
> (mostly because I don't know how to do it with expr and Junio pokes me 
> when I do it with sed. Enlightenment welcome).

The ${parameter##word} syntax is in IEEE 1003.1-2001, and bash,
ksh, and dash seem to work with it.  That does not necessarily
mean it is "portable" but I won't be so worried about shells
that do not grok this.  Input from people on non-Linux platforms
are appreciated.

> if [ "$com2" ]; then
>     range="$com1..$com2"
> else
>     case "$com1" in
>...
>         ?*^)
>             # single commit
>             com1="${com1##*^}"
>             range="$com1^1..$com1"
>             ;;

I wonder if you meant "${com1%^}" here, to remove the trailing '^'.

>         ?*^[0-9]|?*^[0-9][0-9])
>             # series of commits, ranging back from <commit-ish>
>             range="$com1..${com1%%^*}"
>             ;;
>         ^[0-9]|^[0-9][0-9])
>             # series of commits, ranging back from HEAD
>             range="HEAD$com1..HEAD"
>             ;;

N generation back in extended SHA1 notation uses a tilde '~',
e.g. "HEAD~5" is five commits back from the current HEAD, so I'd
prefer being consistent with that (HEAD^5 means the fifth parent
of an octopus merge commit).  Also limiting to between 0 and 99
generations misinterprets "HEAD~123".

Although checking only the letter that follows the tilde is a
digit mistakenly accepts something like "master~1-bad-one", that
is already malformed and whatever comes downstream would barf,
so that may be fine.  How about something like:

	?*'~'[1-9]*)
        	range="$com1..${com1%~*}" ;;
	'~'[1-9]*)
        	range="HEAD$com1..HEAD" ;;

I do not have aversion against echo piped to sed in general, by
the way.  I *would* redicule people who write something like
this, though:

	case "$git" in
        */.git)	printname=`echo "$git" | sed -e 's/\/\.git$//'` ;;
        *)	printname=$git ;;
	esac

It should be spelled `expr "$git" : '\(.*\)/\.git$'` (or
"${git%/.git}" if we know the shell is POSIX), for this
particular one, since we already know it ends with "/.git".  But
if all you want to do is to drop an *optional* trailing "/.git"
(i.e. your input may or may not end with "/.git"), a single:

	printname=`echo "$git" | sed -e 's/\/\.git$//'`

without surrounding case may be adequate; it forks sed when it
does not have the optional /.git part, though.  And if you are
dropping optional /.git or .git (think of prettyprinting
uemacs/.git and git.git), then echo-to-sed without surrounding
"case" is probably easier to read:

	printname=`echo "$git" | sed -e 's/\/*\.git$//'`

unless you want to avoid fork, in which case it would be:

	case "$git" in
        */.git) printname=${git%/.git} ;;
        *.git) printname=${git%.git} ;;
        *) printname=$git ;;
	esac

^ permalink raw reply

* Re: Problem merging
From: H. Peter Anvin @ 2005-11-27 21:24 UTC (permalink / raw)
  To: Ben Clifford; +Cc: Johannes Schindelin, Git Mailing List
In-Reply-To: <D8B7EF65-9D0C-4706-B248-4B7C118C16BF@hawaga.org.uk>

Ben Clifford wrote:
> On 24 Nov 2005, at 00:49, Johannes Schindelin wrote:
> 
>>
>> I think nobody is. Since there are infinitely many files having the  same
>> SHA1 (pigeon-hole principle),
> 
> hmm... pigeon-hole principle is just that there exists two files that  
> have the same SHA-1 as each other... doesn't say anything about *all*  
> SHA-1s, though?
> 

There are an infinite number of possible files (specifically, 
aleph-null.)  There are a finite number of possible SHA-1's 
(specifically, 1461501637330902918203684832716283019655932542976.) 
Therefore the pidgeon-hole principle tells you there must be at least 
one SHA-1 value that hashes an infinite number of files (aleph-null, again.)

Given that SHA-1 is believed to be uniformly distributed, it's quite 
likely *ALL* SHA-1's hash an infinite number of files, but the 
pigeon-hole principle can't tell you that.

	-hpa

^ permalink raw reply

* Re: [PATCH 1/8] git-apply: work from subdirectory.
From: Lars Magne Ingebrigtsen @ 2005-11-27 21:13 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vy839dfzk.fsf@assigned-by-dhcp.cox.net>

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

> It may be that news.gmane.org doesn't chop, but somebody between
> vger.kernel.org mailing list manager and what comes out of the
> newsserver does. 

Egads!  It's all my fault -- there's some code in the mail-to-news
script that's truncating long header lines, and nobody's noticed up
'till now.  I've now twiddled it slightly; it should stop mangling
References headers now...

-- 
(domestic pets only, the antidote for overdose, milk.)
  larsi@gnus.org * Lars Magne Ingebrigtsen

^ permalink raw reply

* Re: [PATCH] Reference technical/trivial-merge.txt in git-read-tree documentation
From: Junio C Hamano @ 2005-11-27 21:16 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git
In-Reply-To: <20051127124108.GB22159@pasky.or.cz>

Petr Baudis <pasky@suse.cz> writes:

> Dear diary, on Fri, Nov 11, 2005 at 09:51:40PM CET, I got a letter
> where Petr Baudis <pasky@suse.cz> said that...
>> That file, with the so valuable (and so confusing) tables describing
>> the precise resolution rules git-read-tree follows, silently sat in
>> the corner and almost noone knew about it (well, I didn't, at least).
>> This references it from the git-read-tree documentation, so that there
>> is some chance that interested people will find it.
>> 
>> Signed-off-by: Petr Baudis <pasky@suse.cz>
>
> Any gripes, or just forgotten?

What happened was that I thought I'd apply after rewording the
sarcasm and maybe moving the existing table to the one in
technical/ (or just removing the old table), and forgot about it.

One thing I do not like the table in technical/ is that it is
harder to read as the "case table" than the original.
Admittedly, it is meant to describe more complex situation, so
it _is_ harder to understand, but a major difference is that the
original table was designed to decribe things orthogonally and
you did not have to read from top to bottom (any situation would
have fallen in one case no matter what order you checked the
condition for each case), while the updated table in technical/
_must_ be read from top to bottom and take the first match, and
that was what made me feel reluctant to remove the existing one
from the original document.

^ permalink raw reply

* [PATCH] git-mv: follow -k request even on failing renames
From: Josef Weidendorfer @ 2005-11-27 21:11 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

-k requests to keep running on an error condition.
Previously, git-mv stopped on failing renames even with -k.

There are some error conditions which are not checked in the
first phase of git-mv, eg. 'permission denied'. Still, option
-k should work.

Signed-off-by: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>

---

 git-mv.perl |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

applies-to: 6ff4820f59a60e776e7a853cbe0fdbb908f3d8af
190f908c52de643bcb05a11d8537551bd1df067f
diff --git a/git-mv.perl b/git-mv.perl
index 8d294d6..65b1dcf 100755
--- a/git-mv.perl
+++ b/git-mv.perl
@@ -151,6 +151,11 @@ while(scalar @srcs > 0) {
     if (!$opt_n) {
 	if (!rename($src,$dst)) {
 	    $bad = "renaming '$src' failed: $!";
+	    if ($opt_k) {
+		print "Warning: skipped: $bad\n";
+		$bad = "";
+		next;
+	    }
 	    last;
 	}
     }
---
0.99.9.GIT

^ permalink raw reply related

* Re: What's in master and pu (aka when will 1.0rc4 be out)
From: Junio C Hamano @ 2005-11-27 21:08 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Timo Hirvonen, git
In-Reply-To: <Pine.LNX.4.64.0511271106360.13959@g5.osdl.org>

Linus Torvalds <torvalds@osdl.org> writes:

> The syntax is
>
> 	git bisect start <pathspec>
>
> followed by all the normal "git bisect good/bad" stuff.

I love how I can just say "this might be interesting" and 
find your message in my mailbox next morning [*1*] ;-).

This would be useful to cut down the number of bisection needed
to reach the culprit if the initial guess is correct as to which
part of the tree is involved.

[Reference]
*1* http://marc.theaimsgroup.com/?l=git&m=111669620826189

^ permalink raw reply

* [PATCH] Small fixes in Documentation/git-mv.txt
From: Josef Weidendorfer @ 2005-11-27 21:08 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

The two synopsis lines have to be prefixed with a space
so that asciidoc inserts a line break inbetween for the
manual page.

Signed-off-by: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>

---

 Documentation/git-mv.txt |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

applies-to: 5b67c88670a5872520b05d5e2b1fd7fb586e99a1
dd7084033c36b92ada34192502ffe38b26a2f969
diff --git a/Documentation/git-mv.txt b/Documentation/git-mv.txt
index f2d5882..3013b8d 100644
--- a/Documentation/git-mv.txt
+++ b/Documentation/git-mv.txt
@@ -8,14 +8,14 @@ git-mv - Script used to move or rename a
 
 SYNOPSIS
 --------
-'git-mv' [-f] [-n] <source> <destination>
-'git-mv' [-f] [-k] [-n] <source> ... <destination directory>
+ 'git-mv' [-f] [-n] <source> <destination>
+ 'git-mv' [-f] [-n] [-k] <source> ... <destination directory>
 
 DESCRIPTION
 -----------
 This script is used to move or rename a file, directory or symlink.
 In the first form, it renames <source>, which must exist and be either
-a file, symlink or directory, to <destination>, which must not exist.
+a file, symlink or directory, to <destination>.
 In the second form, the last argument has to be an existing
 directory; the given sources will be moved into this directory.
 
@@ -25,7 +25,7 @@ committed.
 OPTIONS
 -------
 -f::
-	Force renaming or moving even targets exist
+	Force renaming or moving of a file even if the target exists
 -k::
         Skip move or rename actions which would lead to an error
 	condition. An error happens when a source is neither existing nor
---
0.99.9.GIT

^ permalink raw reply related

* git-mv: fully detect 'directory moved into itself'
From: Josef Weidendorfer @ 2005-11-27 21:06 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

This gives a better error message when trying to move a directory
into some subdirectory of itself; ie. no real bug fix: renaming
already failed before, but with a strange "invalid argument".

Signed-off-by: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
---

 git-mv.perl |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

applies-to: 5d83477de7a407ab0ef183c6676114e1a507cf86
29b01f820bf24c4b697765a2a117c880a730b205
diff --git a/git-mv.perl b/git-mv.perl
index ac19876..8d294d6 100755
--- a/git-mv.perl
+++ b/git-mv.perl
@@ -108,7 +108,7 @@ while(scalar @srcArgs > 0) {
 	}
     }
     
-    if (($bad eq "") && ($src eq $dstDir)) {
+    if (($bad eq "") && ($dst =~ /^$src\//)) {
 	$bad = "can not move directory '$src' into itself";
     }
 
---
0.99.9.GIT

^ permalink raw reply related

* git-mv: keep git index consistent with file system on failed rename
From: Josef Weidendorfer @ 2005-11-27 21:04 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

When doing multiple renames, and a rename in the middle fails,
git-mv did not store the successful renames in the git index;
this is fixed by delaying the error message on a failed rename
to after the git updating.

Signed-off-by: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
---
This is actually independent from the just sent patch, but
the context lines shows it applied...

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

applies-to: 8acd56ea24d565996dc4618f7d7e4fa152d8623c
81f4a3e528094e5e2b0221fd6e76edd205c8e56d
diff --git a/git-mv.perl b/git-mv.perl
index 990bec5..ac19876 100755
--- a/git-mv.perl
+++ b/git-mv.perl
@@ -142,14 +142,17 @@ while(scalar @srcArgs > 0) {
 
 # Final pass: rename/move
 my (@deletedfiles,@addedfiles,@changedfiles);
+$bad = "";
 while(scalar @srcs > 0) {
     $src = shift @srcs;
     $dst = shift @dsts;
 
     if ($opt_n || $opt_v) { print "Renaming $src to $dst\n"; }
     if (!$opt_n) {
-	rename($src,$dst)
-	    or die "rename failed: $!";
+	if (!rename($src,$dst)) {
+	    $bad = "renaming '$src' failed: $!";
+	    last;
+	}
     }
 
     $safesrc = quotemeta($src);
@@ -209,3 +212,8 @@ else {
 	close(H);
     }
 }
+
+if ($bad ne "") {
+    print "Error: $bad\n";
+    exit(1);
+}
---
0.99.9.GIT

^ permalink raw reply related

* [PATCH] git-mv: shrink usage, no usage on error
From: Josef Weidendorfer @ 2005-11-27 20:58 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Small fixes to be consistent with other git scripts:
- usage message is only about options and arguments
- on error, exit(1) without the usage message

Additionally, "beautifies" output with -n a little bit

Signed-off-by: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>

---
This conflicts with Johannes's (and Junio's corrected)
 [PATCH] Make git-mv work in subdirectories, too
so this should be changed accordingly.
Otherwise, I can acknowlegde that your correction to this
patch (make git-mv work in subdirs) works for me.
What is the correct way to "Ack" a patch?

Josef

 git-mv.perl |   46 +++++++++++++++++++---------------------------
 1 files changed, 19 insertions(+), 27 deletions(-)

applies-to: 1dc0816b6c98ef90985d2761f1ab80739e4fbc7d
58d858a354c10c3be0b9eae68cabdce8a3d87f27
diff --git a/git-mv.perl b/git-mv.perl
index b2eace5..990bec5 100755
--- a/git-mv.perl
+++ b/git-mv.perl
@@ -13,22 +13,8 @@ use Getopt::Std;
 
 sub usage() {
 	print <<EOT;
-$0 [-f] [-n] <source> <dest>
-$0 [-f] [-k] [-n] <source> ... <dest directory>
-
-In the first form, source must exist and be either a file,
-symlink or directory, dest must not exist. It renames source to dest.
-In the second form, the last argument has to be an existing
-directory; the given sources will be moved into this directory.
-
-Updates the git cache to reflect the change.
-Use "git commit" to make the change permanently.
-
-Options:
-  -f   Force renaming/moving, even if target exists
-  -k   Continue on error by skipping
-       not-existing or not revision-controlled source
-  -n   Do nothing; show what would happen
+$0 [-f] [-n] <source> <destination>
+$0 [-f] [-n] [-k] <source> ... <destination directory>
 EOT
 	exit(1);
 }
@@ -38,8 +24,8 @@ my $GIT_DIR = $ENV{'GIT_DIR'} || ".git";
 
 unless ( -d $GIT_DIR && -d $GIT_DIR . "/objects" && 
 	-d $GIT_DIR . "/objects/" && -d $GIT_DIR . "/refs") {
-    print "Git repository not found.";
-    usage();
+    print "Error: git repository not found.";
+    exit(1);
 }
 
 
@@ -70,7 +56,7 @@ else {
 	print "Error: moving to directory '"
 	    . $ARGV[$argCount-1]
 	    . "' not possible; not exisiting\n";
-	usage;
+	exit(1);
     }
     @srcArgs = ($ARGV[0]);
     @dstArgs = ($ARGV[1]);
@@ -148,7 +134,7 @@ while(scalar @srcArgs > 0) {
 	    next;
 	}
 	print "Error: $bad\n";
-	usage();
+	exit(1);
     }
     push @srcs, $src;
     push @dsts, $dst;
@@ -187,33 +173,39 @@ while(scalar @srcs > 0) {
 }
 
 if ($opt_n) {
+    if (@changedfiles) {
 	print "Changed  : ". join(", ", @changedfiles) ."\n";
+    }
+    if (@addedfiles) {
 	print "Adding   : ". join(", ", @addedfiles) ."\n";
+    }
+    if (@deletedfiles) {
 	print "Deleting : ". join(", ", @deletedfiles) ."\n";
-	exit(1);
+    }
 }
-	
-if (@changedfiles) {
+else {
+    if (@changedfiles) {
 	open(H, "| git-update-index -z --stdin")
 		or die "git-update-index failed to update changed files with code $!\n";
 	foreach my $fileName (@changedfiles) {
 		print H "$fileName\0";
 	}
 	close(H);
-}
-if (@addedfiles) {
+    }
+    if (@addedfiles) {
 	open(H, "| git-update-index --add -z --stdin")
 		or die "git-update-index failed to add new names with code $!\n";
 	foreach my $fileName (@addedfiles) {
 		print H "$fileName\0";
 	}
 	close(H);
-}
-if (@deletedfiles) {
+    }
+    if (@deletedfiles) {
 	open(H, "| git-update-index --remove -z --stdin")
 		or die "git-update-index failed to remove old names with code $!\n";
 	foreach my $fileName (@deletedfiles) {
 		print H "$fileName\0";
 	}
 	close(H);
+    }
 }
---
0.99.9.GIT

^ permalink raw reply related

* [PATCH] t9105-fetch-local: quote path created with pwd
From: Jonas Fonseca @ 2005-11-27 20:05 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git

Small fix to let it work when pwd contains spaces.

Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
diff --git a/t/t9105-fetch-local.sh b/t/t9105-fetch-local.sh
index a309693..35e2778 100755
--- a/t/t9105-fetch-local.sh
+++ b/t/t9105-fetch-local.sh
@@ -35,7 +35,7 @@ test_expect_success 'symlinked clone of 
 rm -rf repo2
 mkdir repo2
 test_expect_success 'clone in-current-dir repo2 from $(pwd)/../repo1/../repo1.git/' \
-	'(cd repo2 && cg-clone -s $(pwd)/../repo1/../repo1.git/)'
+	'(cd repo2 && cg-clone -s "$(pwd)/../repo1/../repo1.git/")'
 
 echo file1v2 >repo1/file1
 test_expect_success 'commit in repo1' \
 
-- 
Jonas Fonseca

^ permalink raw reply related

* Re: What's in master and pu (aka when will 1.0rc4 be out)
From: Linus Torvalds @ 2005-11-27 19:32 UTC (permalink / raw)
  To: Timo Hirvonen; +Cc: Junio C Hamano, git
In-Reply-To: <20051127151134.0eac7019.tihirvon@gmail.com>



On Sun, 27 Nov 2005, Timo Hirvonen wrote:
> 
> Hmm.. would something like 
> 
>     git-bisect --include drivers/char/drm/ --include include/ ...
> 
> be easy to implement?  That command would limit bisecting to only the
> commits that have changed files under those two directories.

Heh.

It was surprisingly easy to do.

The syntax is

	git bisect start <pathspec>

followed by all the normal "git bisect good/bad" stuff.

Almost totally untested, and I guarantee that if your pathnames have 
spaces in them (or your GIT_DIR has spaces in it) this won't work. I don't 
know how to fix that, my shell programming isn't good enough.

This involves small changes to make "git-rev-list --bisect" work in the 
presense of a pathspec limiter, and then truly trivial (and that's the 
broken part) changes to make "git bisect" save away and use the pathspec.

I tried one bisection, and a "git bisect visualize", and it all looked 
correct. But hey, don't be surprised if it has problems.

		Linus

---
diff --git a/git-bisect.sh b/git-bisect.sh
index d92993b..2455f00 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -33,7 +33,6 @@ bisect_autostart() {
 }
 
 bisect_start() {
-        case "$#" in 0) ;; *) usage ;; esac
 	#
 	# Verify HEAD. If we were bisecting before this, reset to the
 	# top-of-line master first!
@@ -57,7 +56,8 @@ bisect_start() {
 	rm -f "$GIT_DIR/refs/heads/bisect"
 	rm -rf "$GIT_DIR/refs/bisect/"
 	mkdir "$GIT_DIR/refs/bisect"
-	echo "git-bisect start" >"$GIT_DIR/BISECT_LOG"
+	echo "git-bisect start $@" >"$GIT_DIR/BISECT_LOG"
+	echo "$@" > "$GIT_DIR/BISECT_NAMES"
 }
 
 bisect_bad() {
@@ -121,7 +121,7 @@ bisect_next() {
 	bad=$(git-rev-parse --verify refs/bisect/bad) &&
 	good=$(git-rev-parse --sq --revs-only --not \
 		$(cd "$GIT_DIR" && ls refs/bisect/good-*)) &&
-	rev=$(eval "git-rev-list --bisect $good $bad") || exit
+	rev=$(eval "git-rev-list --bisect $good $bad -- $(cat $GIT_DIR/BISECT_NAMES)") || exit
 	if [ -z "$rev" ]; then
 	    echo "$bad was both good and bad"
 	    exit 1
@@ -131,7 +131,7 @@ bisect_next() {
 	    git-diff-tree --pretty $rev
 	    exit 0
 	fi
-	nr=$(eval "git-rev-list $rev $good" | wc -l) || exit
+	nr=$(eval "git-rev-list $rev $good -- $(cat $GIT_DIR/BISECT_NAMES)" | wc -l) || exit
 	echo "Bisecting: $nr revisions left to test after this"
 	echo "$rev" > "$GIT_DIR/refs/heads/new-bisect"
 	git checkout new-bisect || exit
@@ -142,7 +142,7 @@ bisect_next() {
 
 bisect_visualize() {
 	bisect_next_check fail
-	gitk bisect/bad --not `cd "$GIT_DIR/refs" && echo bisect/good-*`
+	gitk bisect/bad --not `cd "$GIT_DIR/refs" && echo bisect/good-*` -- $(cat $GIT_DIR/BISECT_NAMES)
 }
 
 bisect_reset() {
diff --git a/rev-list.c b/rev-list.c
index e17f928..8020d97 100644
--- a/rev-list.c
+++ b/rev-list.c
@@ -350,7 +350,8 @@ static int count_distance(struct commit_
 
 		if (commit->object.flags & (UNINTERESTING | COUNTED))
 			break;
-		nr++;
+		if (!paths || (commit->object.flags & TREECHANGE))
+			nr++;
 		commit->object.flags |= COUNTED;
 		p = commit->parents;
 		entry = p;
@@ -362,6 +363,7 @@ static int count_distance(struct commit_
 			}
 		}
 	}
+
 	return nr;
 }
 
@@ -382,15 +384,20 @@ static struct commit_list *find_bisectio
 	nr = 0;
 	p = list;
 	while (p) {
-		nr++;
+		if (!paths || (p->item->object.flags & TREECHANGE))
+			nr++;
 		p = p->next;
 	}
 	closest = 0;
 	best = list;
 
-	p = list;
-	while (p) {
-		int distance = count_distance(p);
+	for (p = list; p; p = p->next) {
+		int distance;
+
+		if (paths && !(p->item->object.flags & TREECHANGE))
+			continue;
+
+		distance = count_distance(p);
 		clear_distance(list);
 		if (nr - distance < distance)
 			distance = nr - distance;
@@ -398,7 +405,6 @@ static struct commit_list *find_bisectio
 			best = p;
 			closest = distance;
 		}
-		p = p->next;
 	}
 	if (best)
 		best->next = NULL;

^ 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