Git development
 help / color / mirror / Atom feed
* Re: [PATCH 2/4] Convert resolve_ref+xstrdup to new resolve_refdup function
From: Michael Haggerty @ 2011-12-13 14:09 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Nguyễn Thái Ngọc Duy, git, Jonathan Nieder
In-Reply-To: <7vpqft4qap.fsf@alter.siamese.dyndns.org>

On 12/12/2011 07:07 PM, Junio C Hamano wrote:
> Nguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:
> 
>> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> 
> Thanks.
> 
> The patch looks correct but I have a slight maintainability concern and a
> suggestion for possible improvement.
> 
>> ...
>> diff --git a/builtin/checkout.c b/builtin/checkout.c
>> index b7c6302..a66d3eb 100644
>> --- a/builtin/checkout.c
>> +++ b/builtin/checkout.c
>> @@ -696,17 +696,14 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
>>  {
>>  	int ret = 0;
>>  	struct branch_info old;
>> +	char *path;
>>  	unsigned char rev[20];
>>  	int flag;
>>  	memset(&old, 0, sizeof(old));
>> -	old.path = resolve_ref("HEAD", rev, 0, &flag);
>> -	if (old.path)
>> -		old.path = xstrdup(old.path);
>> +	old.path = path = resolve_refdup("HEAD", rev, 0, &flag);
> 
> This uses "one 'const char *' pointer that is used for reading data from
> and an extra 'char *' pointer that is used only for freeing" approach,
> which has two advantages and one disadvantage:
> [...]
> When naming a "for-freeing" pointer variable, the kind of data the area of
> memory happens to contain is of secondary importance. Being deliberately
> vague about what the area of memory may contain is a good thing, because
> it actively discourages the program from looking at the area via the
> pointer if the variable is named "to_free" or something that does not
> specify what it contains.

The to_free variable could even be declared void* to make it even less
(ab)usable.

Michael

-- 
Michael Haggerty
mhagger@alum.mit.edu
http://softwareswirl.blogspot.com/

^ permalink raw reply

* Re: Git blame only current branch
From: Vijay Lakshminarayanan @ 2011-12-13 14:09 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Stephen Bash, git discussion list
In-Reply-To: <7vobvdvx9c.fsf@alter.siamese.dyndns.org>

Junio C Hamano <gitster@pobox.com> writes:

> Vijay Lakshminarayanan <laksvij@gmail.com> writes:
>
>> The code reads fine when there's no numeral 1 around but now it doesn't
>> read well.  I think refactoring
>>
>>     struct commit_list *l
>>
>> to 
>>
>>     struct commit_list *lst
>>
>> is justified.  Thoughts?
>
> Not justified at all.
>
> What is "lst" and why is it not spelled "list"?  It is a disease to drop
> vowels when you do not have to.

lst is better than l in this particular context.  I think fried_chicken
is better than l in this particular context ;-)

> If I were to name a new variable that points at one element of a linked
> list and is used to walk the list (surprise!) "element" or perhaps "elem"
> for short, but in the context of that short function I honestly do not see
> much need for such a naming. The variable is extremely short-lived and
> there is no room for confusion.

Before the introduction of the numeral 1, I am in complete agreement
with you for the exact reasons you've mentioned above.  Post
introduction of "l ? 1 : 0" it warrants a refactoring.  It's possible
you're using a different font so you never encounter the issue, but this
definitely isn't a problem I alone face.  For instance, it is a
sufficiently common problem that it's one of the "Java Puzzlers" in Josh
Bloch's book of the same name.  (Yes, elem is better than lst.)

My $0.02.

-- 
Cheers
~vijay

Gnus should be more complicated.

^ permalink raw reply

* Re: [RFC/PATCH] add update to branch support for "floating submodules"
From: Phil Hord @ 2011-12-13 14:17 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Leif Gruenwoldt, git
In-Reply-To: <7vaa6x4m5l.fsf@alter.siamese.dyndns.org>

On Mon, Dec 12, 2011 at 2:36 PM, Junio C Hamano <gitster@pobox.com> wrote:
[...]
> Distro package dependency tracking is a poor analogy for many reasons, but
> I'll only touch a few.
[...]
> Naively, one might think that two branches, branch-1.0 and branch-2.0, can
> be defined in the repository of L, tell somebody (like "superproject that
> covers all the packages in the distro") that A wants branch-1.0 and B
> wants branch-2.0 of L respectively, to emulate this, but if one thinks
> further, one would realize that it is insufficient. For one thing, it is
> unclear what should happen when both A and B are asked to be checked out,
> but more importantly, in dependency requirements on real distro packaging,
> the application C could say "I want v1.0 API but v1.4 is broken and not
> compatible with me", which won't fit on the two-branches model. A
> workaround to add more branches to L could be devised but any workaround
> cannot be a good solution that allows a random application C among 47
> others to dictate how the branch structure of L project should look like.
>
> Fortunately, the dependency management is a solved problem by distro
> package management and build systems, and they do so without using
> anything from submodules. There is no point reinventing these logic in git
> submodules and emulating poorly.
>
> The only remotely plausible analogy around distro packaging would be a
> superproject full of all the packages in a distro as its submodules, and
> records exact versions of each and every package that goes on a release
> CD (or DVD). In that case, you do want to have a central registry that
> records what exact version of each package is used to cut the CD and the
> mother of all modules superproject could be one way to implement it. But
> that is not an example of floating, but is a direct opposite.
>
> This exchange convinced me further that anybody who wishes to use
> "floating" is better off either by doing one or both of the following:
>
>  - using "exact" but not updating religiously, as the interdepency
>   requirement in their project is not strict; or
>
>  - not using submodules at all, but merely keeping these unrelated A, B, C
>   and L as standalone repositories next to each other in the directory
>   structure.

My interdependency requirements are not so cut-and-dry.  We use
submodules to isolate controlled regions of code.  We may need to
share our project with a contractor who is allowed to see code
pertaining to "vendorA" but not that for "vendorB" or "VendorN".  But
our in-house developers want to have all the vendor code in one place
for convenient integration. Submodules do this nicely for us.  We can
give the contractor just the main modules and the VendorA modules and
he'll be fine.  In-house devs get all the submodules (using the
vendor-ALL superproject).

But this necessarily means there is too much coupling for comfort
between our submodules.   For example, when an API changes in the main
submodule, each of the vendor submodules is affected because they each
implement that API in a custom method.  Some of those vendor modules
belong to different people.  Submodule synchronization becomes a real
chore.

Floating would help, I think.  Instead I do this:

  git pull origin topic_foo && git submodule foreach 'git pull origin topic_foo'

  git submodule foreach 'git push origin topic_foo' && git push origin topic_foo

But not all my developers are git-gurus yet, and they sometimes mess
up their ad hoc scripts or miss important changes they forgot to push
in one submodule or another.  Or worse, their pull or push fails and
they can't see the problem for all the noise.  So they email it to me.

On my git server, I have a hook that automatically propagates each
push to "master" from the submodules into the superproject.  But this
is tedious and limited.  And it relies on a centralized server.

You may say this itch is all in my head, but it sure seems real to me.

Phil

^ permalink raw reply

* Re: Git blame only current branch
From: Frans Klaver @ 2011-12-13 14:18 UTC (permalink / raw)
  To: Junio C Hamano, Vijay Lakshminarayanan
  Cc: Jeff King, Stephen Bash, git discussion list
In-Reply-To: <87y5ugsguj.fsf@gmail.com>

On Tue, 13 Dec 2011 15:09:56 +0100, Vijay Lakshminarayanan  
<laksvij@gmail.com> wrote:

> Junio C Hamano <gitster@pobox.com> writes:
>
>> Vijay Lakshminarayanan <laksvij@gmail.com> writes:
>>
>>> The code reads fine when there's no numeral 1 around but now it doesn't
>>> read well.  I think refactoring
>>>
>>>     struct commit_list *l
>>>
>>> to
>>>
>>>     struct commit_list *lst
>>>
>>> is justified.  Thoughts?
>>
>> Not justified at all.
>>
>> What is "lst" and why is it not spelled "list"?  It is a disease to drop
>> vowels when you do not have to.
>
> lst is better than l in this particular context.  I think fried_chicken
> is better than l in this particular context ;-)

I tend to agree. If you casually look over the code it may look odd, and  
with several monospace fonts there really isn't a very big difference  
between 1?1:0 and l?1:0. You shouldn't have to squint to properly see the  
intention of the code.

If there's going to be a rename, there is no reason to leave out the i  
though.

^ permalink raw reply

* [PATCH] Convert resolve_ref+xstrdup to new resolve_refdup function
From: Nguyễn Thái Ngọc Duy @ 2011-12-13 14:17 UTC (permalink / raw)
  To: git, Michael Haggerty
  Cc: Junio C Hamano, Jonathan Nieder,
	Nguyễn Thái Ngọc Duy
In-Reply-To: <4EE75C88.5060700@alum.mit.edu>


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 2011/12/13 Michael Haggerty <mhagger@alum.mit.edu>:
 >> This uses "one 'const char *' pointer that is used for reading data from
 >> and an extra 'char *' pointer that is used only for freeing" approach,
 >> which has two advantages and one disadvantage:
 >> [...]
 >> When naming a "for-freeing" pointer variable, the kind of data the area of
 >> memory happens to contain is of secondary importance. Being deliberately
 >> vague about what the area of memory may contain is a good thing, because
 >> it actively discourages the program from looking at the area via the
 >> pointer if the variable is named "to_free" or something that does not
 >> specify what it contains.
 >
 > The to_free variable could even be declared void* to make it even less
 > (ab)usable.

 Good thinking. Here's the version with "char *foo_to_free" converted
 to "void *foo_to_free".

 builtin/branch.c        |   12 +++++-------
 builtin/checkout.c      |   15 +++++++--------
 builtin/fmt-merge-msg.c |    7 ++++---
 builtin/for-each-ref.c  |    7 ++-----
 builtin/merge.c         |   12 +++++-------
 builtin/notes.c         |    7 ++++---
 builtin/receive-pack.c  |    7 +++----
 builtin/show-branch.c   |    4 +---
 cache.h                 |    1 +
 reflog-walk.c           |   15 ++++++++-------
 refs.c                  |    6 ++++++
 wt-status.c             |    4 +---
 12 files changed, 47 insertions(+), 50 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index e1e486e..c459f0b 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -104,6 +104,7 @@ static int branch_merged(int kind, const char *name,
 	 */
 	struct commit *reference_rev = NULL;
 	const char *reference_name = NULL;
+	void *reference_name_to_free = NULL;
 	int merged;
 
 	if (kind == REF_LOCAL_BRANCH) {
@@ -114,11 +115,9 @@ static int branch_merged(int kind, const char *name,
 		    branch->merge &&
 		    branch->merge[0] &&
 		    branch->merge[0]->dst &&
-		    (reference_name =
-		     resolve_ref(branch->merge[0]->dst, sha1, 1, NULL)) != NULL) {
-			reference_name = xstrdup(reference_name);
+		    (reference_name = reference_name_to_free =
+		     resolve_refdup(branch->merge[0]->dst, sha1, 1, NULL)) != NULL)
 			reference_rev = lookup_commit_reference(sha1);
-		}
 	}
 	if (!reference_rev)
 		reference_rev = head_rev;
@@ -143,7 +142,7 @@ static int branch_merged(int kind, const char *name,
 				"         '%s', even though it is merged to HEAD."),
 				name, reference_name);
 	}
-	free((char *)reference_name);
+	free(reference_name_to_free);
 	return merged;
 }
 
@@ -731,10 +730,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 
 	track = git_branch_track;
 
-	head = resolve_ref("HEAD", head_sha1, 0, NULL);
+	head = resolve_refdup("HEAD", head_sha1, 0, NULL);
 	if (!head)
 		die(_("Failed to resolve HEAD as a valid ref."));
-	head = xstrdup(head);
 	if (!strcmp(head, "HEAD")) {
 		detached = 1;
 	} else {
diff --git a/builtin/checkout.c b/builtin/checkout.c
index b7c6302..00740bd 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -696,17 +696,14 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
 {
 	int ret = 0;
 	struct branch_info old;
+	void *path_to_free;
 	unsigned char rev[20];
 	int flag;
 	memset(&old, 0, sizeof(old));
-	old.path = resolve_ref("HEAD", rev, 0, &flag);
-	if (old.path)
-		old.path = xstrdup(old.path);
+	old.path = path_to_free = resolve_refdup("HEAD", rev, 0, &flag);
 	old.commit = lookup_commit_reference_gently(rev, 1);
-	if (!(flag & REF_ISSYMREF)) {
-		free((char *)old.path);
+	if (!(flag & REF_ISSYMREF))
 		old.path = NULL;
-	}
 
 	if (old.path && !prefixcmp(old.path, "refs/heads/"))
 		old.name = old.path + strlen("refs/heads/");
@@ -720,8 +717,10 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
 	}
 
 	ret = merge_working_tree(opts, &old, new);
-	if (ret)
+	if (ret) {
+		free(path_to_free);
 		return ret;
+	}
 
 	if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
 		orphaned_commit_warning(old.commit);
@@ -729,7 +728,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
 	update_refs_for_switch(opts, &old, new);
 
 	ret = post_checkout_hook(old.commit, new->commit, 1);
-	free((char *)old.path);
+	free(path_to_free);
 	return ret || opts->writeout_error;
 }
 
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index bdfa0ea..c81a7fe 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -372,14 +372,15 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
 	int i = 0, pos = 0;
 	unsigned char head_sha1[20];
 	const char *current_branch;
+	void *current_branch_to_free;
 
 	/* get current branch */
-	current_branch = resolve_ref("HEAD", head_sha1, 1, NULL);
+	current_branch = current_branch_to_free =
+		resolve_refdup("HEAD", head_sha1, 1, NULL);
 	if (!current_branch)
 		die("No current branch");
 	if (!prefixcmp(current_branch, "refs/heads/"))
 		current_branch += 11;
-	current_branch = xstrdup(current_branch);
 
 	/* get a line */
 	while (pos < in->len) {
@@ -421,7 +422,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
 	}
 
 	strbuf_complete_line(out);
-	free((char *)current_branch);
+	free(current_branch_to_free);
 	return 0;
 }
 
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index d90e5d2..b01d76a 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -628,11 +628,8 @@ static void populate_value(struct refinfo *ref)
 
 	if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) {
 		unsigned char unused1[20];
-		const char *symref;
-		symref = resolve_ref(ref->refname, unused1, 1, NULL);
-		if (symref)
-			ref->symref = xstrdup(symref);
-		else
+		ref->symref = resolve_refdup(ref->refname, unused1, 1, NULL);
+		if (!ref->symref)
 			ref->symref = "";
 	}
 
diff --git a/builtin/merge.c b/builtin/merge.c
index a1c8534..a3cd5e8 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -1096,6 +1096,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	struct commit_list *common = NULL;
 	const char *best_strategy = NULL, *wt_strategy = NULL;
 	struct commit_list **remotes = &remoteheads;
+	void *branch_to_free;
 
 	if (argc == 2 && !strcmp(argv[1], "-h"))
 		usage_with_options(builtin_merge_usage, builtin_merge_options);
@@ -1104,12 +1105,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	 * Check if we are _not_ on a detached HEAD, i.e. if there is a
 	 * current branch.
 	 */
-	branch = resolve_ref("HEAD", head_sha1, 0, &flag);
-	if (branch) {
-		if (!prefixcmp(branch, "refs/heads/"))
-			branch += 11;
-		branch = xstrdup(branch);
-	}
+	branch = branch_to_free = resolve_refdup("HEAD", head_sha1, 0, &flag);
+	if (branch && !prefixcmp(branch, "refs/heads/"))
+		branch += 11;
 	if (!branch || is_null_sha1(head_sha1))
 		head_commit = NULL;
 	else
@@ -1520,6 +1518,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		ret = suggest_conflicts(option_renormalize);
 
 done:
-	free((char *)branch);
+	free(branch_to_free);
 	return ret;
 }
diff --git a/builtin/notes.c b/builtin/notes.c
index 10b8bc7..667e20a 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -804,6 +804,7 @@ static int merge_commit(struct notes_merge_options *o)
 	struct notes_tree *t;
 	struct commit *partial;
 	struct pretty_print_context pretty_ctx;
+	void *local_ref_to_free;
 	int ret;
 
 	/*
@@ -826,10 +827,10 @@ static int merge_commit(struct notes_merge_options *o)
 	t = xcalloc(1, sizeof(struct notes_tree));
 	init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
 
-	o->local_ref = resolve_ref("NOTES_MERGE_REF", sha1, 0, NULL);
+	o->local_ref = local_ref_to_free =
+		resolve_refdup("NOTES_MERGE_REF", sha1, 0, NULL);
 	if (!o->local_ref)
 		die("Failed to resolve NOTES_MERGE_REF");
-	o->local_ref = xstrdup(o->local_ref);
 
 	if (notes_merge_commit(o, t, partial, sha1))
 		die("Failed to finalize notes merge");
@@ -846,7 +847,7 @@ static int merge_commit(struct notes_merge_options *o)
 	free_notes(t);
 	strbuf_release(&msg);
 	ret = merge_abort(o);
-	free((char *)o->local_ref);
+	free(local_ref_to_free);
 	return ret;
 }
 
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index b6d957c..62afac3 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -37,6 +37,7 @@ static int prefer_ofs_delta = 1;
 static int auto_update_server_info;
 static int auto_gc = 1;
 static const char *head_name;
+static void *head_name_to_free;
 static int sent_capabilities;
 
 static enum deny_action parse_deny_action(const char *var, const char *value)
@@ -695,10 +696,8 @@ static void execute_commands(struct command *commands, const char *unpacker_erro
 
 	check_aliased_updates(commands);
 
-	free((char *)head_name);
-	head_name = resolve_ref("HEAD", sha1, 0, NULL);
-	if (head_name)
-		head_name = xstrdup(head_name);
+	free(head_name_to_free);
+	head_name = head_name_to_free = resolve_refdup("HEAD", sha1, 0, NULL);
 
 	for (cmd = commands; cmd; cmd = cmd->next)
 		if (!cmd->skip_update)
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 4b480d7..a1f148e 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -726,10 +726,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
 
 		if (ac == 0) {
 			static const char *fake_av[2];
-			const char *refname;
 
-			refname = resolve_ref("HEAD", sha1, 1, NULL);
-			fake_av[0] = xstrdup(refname);
+			fake_av[0] = resolve_refdup("HEAD", sha1, 1, NULL);
 			fake_av[1] = NULL;
 			av = fake_av;
 			ac = 1;
diff --git a/cache.h b/cache.h
index 8c98d05..4887a3e 100644
--- a/cache.h
+++ b/cache.h
@@ -866,6 +866,7 @@ extern int read_ref(const char *filename, unsigned char *sha1);
  * errno is sometimes set on errors, but not always.
  */
 extern const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag);
+extern char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag);
 
 extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
 extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
diff --git a/reflog-walk.c b/reflog-walk.c
index da71a85..64c677f 100644
--- a/reflog-walk.c
+++ b/reflog-walk.c
@@ -50,11 +50,12 @@ static struct complete_reflogs *read_complete_reflog(const char *ref)
 	for_each_reflog_ent(ref, read_one_reflog, reflogs);
 	if (reflogs->nr == 0) {
 		unsigned char sha1[20];
-		const char *name = resolve_ref(ref, sha1, 1, NULL);
+		const char *name;
+		void *name_to_free;
+		name = name_to_free = resolve_refdup(ref, sha1, 1, NULL);
 		if (name) {
-			name = xstrdup(name);
 			for_each_reflog_ent(name, read_one_reflog, reflogs);
-			free((char *)name);
+			free(name_to_free);
 		}
 	}
 	if (reflogs->nr == 0) {
@@ -171,11 +172,11 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
 	else {
 		if (*branch == '\0') {
 			unsigned char sha1[20];
-			const char *head = resolve_ref("HEAD", sha1, 0, NULL);
-			if (!head)
-				die ("No current branch");
 			free(branch);
-			branch = xstrdup(head);
+			branch = resolve_refdup("HEAD", sha1, 0, NULL);
+			if (!branch)
+				die ("No current branch");
+
 		}
 		reflogs = read_complete_reflog(branch);
 		if (!reflogs || reflogs->nr == 0) {
diff --git a/refs.c b/refs.c
index f5cb297..8ffb32f 100644
--- a/refs.c
+++ b/refs.c
@@ -605,6 +605,12 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
 	return ref;
 }
 
+char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, int *flag)
+{
+	const char *ret = resolve_ref(ref, sha1, reading, flag);
+	return ret ? xstrdup(ret) : NULL;
+}
+
 /* The argument to filter_refs */
 struct ref_filter {
 	const char *pattern;
diff --git a/wt-status.c b/wt-status.c
index 70fdb76..9ffc535 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -111,7 +111,6 @@ void status_printf_more(struct wt_status *s, const char *color,
 void wt_status_prepare(struct wt_status *s)
 {
 	unsigned char sha1[20];
-	const char *head;
 
 	memset(s, 0, sizeof(*s));
 	memcpy(s->color_palette, default_wt_status_colors,
@@ -119,8 +118,7 @@ void wt_status_prepare(struct wt_status *s)
 	s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
 	s->use_color = -1;
 	s->relative_paths = 1;
-	head = resolve_ref("HEAD", sha1, 0, NULL);
-	s->branch = head ? xstrdup(head) : NULL;
+	s->branch = resolve_refdup("HEAD", sha1, 0, NULL);
 	s->reference = "HEAD";
 	s->fp = stdout;
 	s->index_file = get_index_file();
-- 
1.7.8.36.g69ee2

^ permalink raw reply related

* migrating from svn: How to clean up history?
From: Hartmut Goebel @ 2011-12-13 14:53 UTC (permalink / raw)
  To: git

Hello,

I'm one of the developers of www.pyinstaller.org, a tool for 
bundling/packagin Python scripts and al required modules into a single 
executable for easy distribution. We are in the process of migrating 
from Subversion to git.

Our SVN-Repo contains some stuff we do not want or do not need in the 
git repo. How can we clean this up?

1) Useless commits e.g. tagging -> I want to remove these
2) copy or move mistakes -> I want to "correct" the copy

Example for 1): This occurs e.g. if this is done

svn cp trunk tags/v0.1 -m 'release v0.1' <<<--- this on in not needed
svn rm tags/v0.1 -m 'release v0.1'
svn cp trunk tags/v0.1 -m 'release v0.1'

In this case I want to completely eliminate the first commit.

Example for 2): This occurs e.g. if this is done

svn cp trunk tags/v0.1 -m 'release v0.1'
svn cp trunk tags/v0.1 -m 'release v0.1' <<-- actually copies to 
tags/v0.1/trunk

In this case I want to change eliminate the first commit (this is he 
same as case 1) and rewrite commit 2 to rewrite the path.

I already did some experiments with `git filter-branch` without success. 
(I manage renaming the tags, though.)

Any hints how to to this clean-up?

-- 
Schönen Gruß - Regards
Hartmut Goebel
Dipl.-Informatiker (univ.), CISSP, CSSLP

Goebel Consult
Spezialist für IT-Sicherheit in komplexen Umgebungen
http://www.goebel-consult.de

Monatliche Kolumne: http://www.cissp-gefluester.de/
Goebel Consult ist Mitglied bei http://www.7-it.de

^ permalink raw reply

* Re: [PATCH/RFC] Makefile: add 'help' target for target summary
From: Jakub Narebski @ 2011-12-13 15:00 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git
In-Reply-To: <1323782164-11759-1-git-send-email-pclouds@gmail.com>

乧畹ễ渠周á椠乧ọ挠䑵礠‼灣汯畤獀杭慩氮捯派⁷物瑥猺ഊഊ㸠䤠晩湤⁴桩猠≭慫攠桥汰∠癥特⁨敬灦畬
慴⁷潲欬渠愠摩晦敲敮琍ਾ⁰牯橥捴⤮⁗楴栠瑨楳⁉⁤潮❴⁨慶攠瑯⁣牡睬⁴桲潵杨⁍慫敦楬攠睨敮⁉敥損ਾ⁳潭整桩湧⁢畴⁣慮湯琠牥浥浢敲⁷桡琧猠瑨攠瑡牧整慭攮⁉琠獨潵汤⁡汳漍ਾ⁨敬瀠摩獣潶敲敷⁴慲来瑳⸍ਾ‍ਾ⁗攠浡礠慬獯⁨慶攠≭慫攠癡牳∠⡯爠獯浥瑨楮朠汩步⁴桡琩⁴桡琠獨潷猠汩獴ഊ㸠潦⁵獥爭捯湦楧畲慢汥⁶慲楡扬敳Ⱐ扡獩捡汬礠愠捯湶敲獩潮映瑨攠扩服ਾ⁣潭浥湴⁢汯捫敡爠瑨攠浡步晩汥❳⁴潰⁩湴漠愠灲楮瑡扬攠瑡牧整⸍ਾ‍ਾ⁉⁤潮❴⁷潲欠睩瑨⁴桩猠䵡步晩汥畣栬⁳漠瑨楳⁩猠橵獴⁡渠楤敡⸠䅮祯湥ഊ㸠異⁴漠瑵牮⁩琠瑯⁳潭整桩湧⁡捴畡汬礠畳敦畬㼍਍੓桯畬搠瑨楳⁢攠楮⁣潭浩琠浥獳慧攬爠楮⁣潭浥湴猠⡢敬潷•ⴭⵜ渢⤿ഊഊ乢⸠瑨敲攠睡猠慴敡獴湥⁡瑴敭灴⁴漠慤搠≭慫攠桥汰∠畳楮服੩渭䵡步晩汥 慮湯瑡瑩潮獟Ⱐ獯⁴桡琠≭慫攠桥汰∠睯畬摮❴⁧整⁢慤汹畴ഊ潦⁳祮挮⸮ഊഊ㸠卩杮敤ⵯ晦ⵢ示⁎杵秾>앮⁔棾＀⁎柾>쵣⁄畹‼灣汯畤獀杭慩氮捯派ഊ㸠ⴭⴍਾ†䵡步晩汥⁼†‱㐠⬫⬫⬫⬫⬫⬫⬫ഊ㸠‱⁦楬敳⁣桡湧敤Ⱐㄴ⁩湳敲瑩潮猨⬩Ⱐ〠摥汥瑩潮猨⴩ഊ㸠ഊ㸠摩晦‭ⵧ楴⁡⽍慫敦楬攠戯䵡步晩汥ഊ㸠楮摥砠敤㠲㌲〮⹡扦㙣昹‱〰㘴㐍ਾ‭ⴭ⁡⽍慫敦楬攍ਾ‫⬫⁢⽍慫敦楬攍ਾ⁀䀠ⴲ㘰㌬㌠⬲㘰㌬ㄷ⁀䀠灲潦楬攭慬氺⁰牯晩汥ⵣ汥慮ഊ㸠 ␨䵁䭅⤠䍆䱁䝓㴢␨偒但䥌䕟䝅也䍆䱁䝓⤢⁡汬ഊ㸠 ␨䵁䭅⤠䍆䱁䝓㴢␨偒但䥌䕟䝅也䍆䱁䝓⤢‭樱⁴敳琍ਾ†त⡍䅋䔩⁃䙌䅇匽∤⡐剏䙉䱅录卅彃䙌䅇匩∠慬氍ਾ‫ഊ㸠⬮偈低夺⁨敬瀍ਾ‫ഊ㸠⭨敬瀺ഊ㸠⬉䁥捨漠≴敳琉॒畮⁴桥⁴敳琠獵楴攢ഊ㸠⬉䁥捨漠≣潶敲慧攉䉵楬搠杩琠睩瑨⁣潶敲慧攠獵灰潲琢ഊ㸠⬉䁥捨漠≣潶敲彤戉䝥湥牡瑥⁣潶敲慧攠摡瑡扡獥⁦牯洠⨮杣潶∍ਾ‫ी散桯•捯癥牟摢彨瑭氉䝥湥牡瑥⁣潶敲慧攠牥灯牴∍ਾ‫ी散桯•灲潦楬攭慬氉䉵楬搠杩琠睩瑨⁰牯晩汩湧⁳異灯牴∍ਾ‫ी散桯•捬敡渉ृ汥慮⁩湴敲浥摩慴攠晩汥猢ഊ㸠⬉䁥捨漠≤楳瑣汥慮ृ汥慮⁥癥渠浯牥⁦潲⁤楳琠灡捫慧楮朢ഊ㸠⬉䁥捨漠≳灡牳攉॒畮⁧楴⁷楴栠獰慲獥∍ਾ‫ी散桯•捳捯灥उ䝥湥牡瑥⁣獣潰攠獹浢潬⁤慴慢慳攢ഊ㸠⬉䁥捨漠≣桥捫ⵤ潣猉䍨散欠摯捵浥湴慴楯渢ഊ㸠ⴭ‍ਾ‱⸷⸸⸳㘮朶㥥攲ഊ㸠ഊഊⴭ‍੊慫畢⁎慲ę扳歩ഊ

^ permalink raw reply

* [PATCH 0/2 v2] run-command: Add eacces diagnostics
From: Frans Klaver @ 2011-12-13 15:08 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano
In-Reply-To: <op.v5e8mgbc0aolir@keputer>

This replaces $gmane/186388

I had a lot of short stints incorporating the review remarks, so I might just
have missed something.

[PATCH 1/2] run-command: Add checks after execvp fails with EACCES
[PATCH 2/2] run-command: Add interpreter permissions check

run-command.c          |  130 ++++++++++++++++++++++++++++++++++++++++++++++++
t/t0061-run-command.sh |   38 ++++++++++++++-
2 files changed, 167 insertions(+), 1 deletions(-)

^ permalink raw reply

* [PATCH 1/2] run-command: Add checks after execvp fails with EACCES
From: Frans Klaver @ 2011-12-13 15:08 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Frans Klaver
In-Reply-To: <1323788917-4141-1-git-send-email-fransklaver@gmail.com>

execvp returns ENOENT if a command was not found after searching PATH.
If path contains a directory that current user has insufficient
privileges to, EACCES is returned. This may still mean the program
wasn't found and may cause confusion to the user, especially when the
file mentioned doesn't exist -- that is, the user would expect NOENT to
be returned -- and the user was actually hoping for an alias to be executed.

To help users track down the core issue more easily, perform some checks
on the path and file permissions involved. Output errors when paths or
files don't have enough permissions.

Signed-off-by: Frans Klaver <fransklaver@gmail.com>
---
 run-command.c          |   79 ++++++++++++++++++++++++++++++++++++++++++++++++
 t/t0061-run-command.sh |   16 +++++++++-
 2 files changed, 94 insertions(+), 1 deletions(-)

diff --git a/run-command.c b/run-command.c
index 1c51043..3f136f4 100644
--- a/run-command.c
+++ b/run-command.c
@@ -2,6 +2,7 @@
 #include "run-command.h"
 #include "exec_cmd.h"
 #include "argv-array.h"
+#include "dir.h"
 
 static inline void close_pair(int fd[2])
 {
@@ -134,6 +135,80 @@ static int wait_or_whine(pid_t pid, const char *argv0, int silent_exec_failure)
 	return code;
 }
 
+#ifndef WIN32
+static int have_read_execute_permissions(const char *path)
+{
+	if (access(path, R_OK|X_OK) == 0)
+		return 1;
+
+	if (errno == EACCES)
+		return 0;
+
+	trace_printf("could not determine permissions for '%s': %s\n", path,
+				strerror(errno));
+	return 0;
+}
+
+static void diagnose_execvp_eacces(const char *cmd, const char **argv)
+{
+	/*
+	 * man 2 execve states that EACCES is returned for:
+	 * - Search permission is denied on a component of the path prefix
+	 *   of cmd or the name of a script interpreter
+	 * - The file or script interpreter is not a regular file
+	 * - Execute permission is denied for the file, script or ELF
+	 *   interpreter
+	 * - The file system is mounted noexec
+	 */
+	struct strbuf sb = STRBUF_INIT;
+	char *path;
+	char *next;
+
+	if (strchr(cmd, '/')) {
+		if (!have_read_execute_permissions(cmd))
+			error("no read/execute permissions on '%s'\n", cmd);
+		return;
+	}
+
+	path = getenv("PATH");
+	while (path) {
+		next = strchrnul(path, ':');
+		if (path < next)
+			strbuf_add(&sb, path, next - path);
+		else
+			strbuf_addch(&sb, '.');
+
+		if (!*next)
+			path = NULL;
+		else
+			path = next + 1;
+
+		if (!have_read_execute_permissions(sb.buf)) {
+			error("no read/execute permissions on '%s'\n", sb.buf);
+			strbuf_release(&sb);
+			continue;
+		}
+
+		if (sb.len && sb.buf[sb.len - 1] != '/')
+			strbuf_addch(&sb, '/');
+		strbuf_addstr(&sb, cmd);
+
+		if (file_exists(sb.buf)) {
+			if (!have_read_execute_permissions(sb.buf))
+				error("no read/execute permissions on '%s'\n",
+						sb.buf);
+			else
+				warning("file '%s' exists and permissions "
+				"seem OK.\nIf this is a script, see if you "
+				"have sufficient privileges to run the "
+				"interpreter", sb.buf);
+		}
+
+		strbuf_release(&sb);
+	}
+}
+#endif
+
 int start_command(struct child_process *cmd)
 {
 	int need_in, need_out, need_err;
@@ -285,6 +360,10 @@ fail_pipe:
 				error("cannot run %s: %s", cmd->argv[0],
 					strerror(ENOENT));
 			exit(127);
+		} else if (errno == EACCES) {
+			diagnose_execvp_eacces(cmd->argv[0], cmd->argv);
+			die("cannot exec '%s': %s", cmd->argv[0],
+				strerror(EACCES));
 		} else {
 			die_errno("cannot exec '%s'", cmd->argv[0]);
 		}
diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh
index 8d4938f..b39bd16 100755
--- a/t/t0061-run-command.sh
+++ b/t/t0061-run-command.sh
@@ -26,7 +26,7 @@ test_expect_success 'run_command can run a command' '
 	test_cmp empty err
 '
 
-test_expect_success POSIXPERM 'run_command reports EACCES' '
+test_expect_success POSIXPERM 'run_command reports EACCES, file permissions' '
 	cat hello-script >hello.sh &&
 	chmod -x hello.sh &&
 	test_must_fail test-run-command run-command ./hello.sh 2>err &&
@@ -34,4 +34,18 @@ test_expect_success POSIXPERM 'run_command reports EACCES' '
 	grep "fatal: cannot exec.*hello.sh" err
 '
 
+test_expect_success POSIXPERM 'run_command reports EACCES, search path permisions' '
+	mkdir -p inaccessible &&
+	PATH=$(pwd)/inaccessible:$PATH &&
+	export PATH &&
+
+	cat hello-script >inaccessible/hello.sh &&
+	chmod 400 inaccessible &&
+	test_must_fail test-run-command run-command hello.sh 2>err &&
+	chmod 755 inaccessible &&
+
+	grep "fatal: cannot exec.*hello.sh" err &&
+	grep "no read/execute permissions on" err
+'
+
 test_done
-- 
1.7.8

^ permalink raw reply related

* [PATCH 2/2] run-command: Add interpreter permissions check
From: Frans Klaver @ 2011-12-13 15:08 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Frans Klaver
In-Reply-To: <1323788917-4141-1-git-send-email-fransklaver@gmail.com>

If a script is started and the interpreter of that script given in the
shebang cannot be started due to permissions, we can get a rather
obscure situation. All permission checks pass for the script itself,
but we still get EACCES from execvp.

Try to find out if the above is the case and warn the user about it.

Signed-off-by: Frans Klaver <fransklaver@gmail.com>
---
 run-command.c          |   59 ++++++++++++++++++++++++++++++++++++++++++++---
 t/t0061-run-command.sh |   22 ++++++++++++++++++
 2 files changed, 77 insertions(+), 4 deletions(-)

diff --git a/run-command.c b/run-command.c
index 3f136f4..9ddd409 100644
--- a/run-command.c
+++ b/run-command.c
@@ -149,6 +149,55 @@ static int have_read_execute_permissions(const char *path)
 	return 0;
 }
 
+static void check_interpreter(const char *cmd)
+{
+	FILE *f;
+	struct strbuf sb = STRBUF_INIT;
+	/*
+	 * bash reads an 80 character line when determining the interpreter.
+	 * BSD apparently only allows 32 characters, as it is the size of
+	 * your average binary executable header.
+	 */
+	char firstline[80];
+	size_t s, start, end;
+
+	f = fopen(cmd, "r");
+	if (!f) {
+		error("cannot open file '%s': %s\n", cmd, strerror(errno));
+		return;
+	}
+
+	s = fread(firstline, 1, sizeof(firstline), f);
+	if (s < 2) {
+		trace_printf("cannot determine file type");
+		fclose(f);
+		return;
+	}
+
+	if (firstline[0] != '#' || firstline[1] != '!') {
+		trace_printf("file '%s' is not a script or"
+				" is a script without '#!'", cmd);
+		fclose(f);
+		return;
+	}
+
+	/* see if the given path has the executable bit set */
+	start = strspn(&firstline[2], " \t") + 2;
+	end = strcspn(&firstline[start], " \t\r\n") + start;
+	if (start >= end) {
+		error("could not determine interpreter\n");
+		return;
+	}
+
+	strbuf_add(&sb, &firstline[start], end - start);
+
+	if (!have_read_execute_permissions(sb.buf))
+		error("bad interpreter: no read/execute permissions on '%s'\n",
+				sb.buf);
+
+	strbuf_release(&sb);
+}
+
 static void diagnose_execvp_eacces(const char *cmd, const char **argv)
 {
 	/*
@@ -167,6 +216,8 @@ static void diagnose_execvp_eacces(const char *cmd, const char **argv)
 	if (strchr(cmd, '/')) {
 		if (!have_read_execute_permissions(cmd))
 			error("no read/execute permissions on '%s'\n", cmd);
+		else
+			check_interpreter(cmd);
 		return;
 	}
 
@@ -197,11 +248,11 @@ static void diagnose_execvp_eacces(const char *cmd, const char **argv)
 			if (!have_read_execute_permissions(sb.buf))
 				error("no read/execute permissions on '%s'\n",
 						sb.buf);
+			else if (access(sb.buf, R_OK) == 0)
+				check_interpreter(sb.buf);
 			else
-				warning("file '%s' exists and permissions "
-				"seem OK.\nIf this is a script, see if you "
-				"have sufficient privileges to run the "
-				"interpreter", sb.buf);
+				trace_printf("cannot determine interpreter "
+						"on '%s'\n", sb.buf);
 		}
 
 		strbuf_release(&sb);
diff --git a/t/t0061-run-command.sh b/t/t0061-run-command.sh
index b39bd16..39bfaef 100755
--- a/t/t0061-run-command.sh
+++ b/t/t0061-run-command.sh
@@ -13,6 +13,18 @@ cat >hello-script <<-EOF
 EOF
 >empty
 
+cat >someinterpreter <<-EOF
+	#!$SHELL_PATH
+	cat hello-script
+EOF
+>empty
+
+cat >incorrect-interpreter-script <<-EOF
+	#!someinterpreter
+	cat hello-script
+EOF
+>empty
+
 test_expect_success 'start_command reports ENOENT' '
 	test-run-command start-command-ENOENT ./does-not-exist
 '
@@ -48,4 +60,14 @@ test_expect_success POSIXPERM 'run_command reports EACCES, search path permision
 	grep "no read/execute permissions on" err
 '
 
+test_expect_success POSIXPERM 'run_command reports EACCES, interpreter fails' '
+	cat incorrect-interpreter-script >hello.sh &&
+	chmod +x hello.sh &&
+	chmod -x someinterpreter &&
+	test_must_fail test-run-command run-command ./hello.sh 2>err &&
+
+	grep "fatal: cannot exec.*hello.sh" err &&
+	grep "bad interpreter" err
+'
+
 test_done
-- 
1.7.8

^ permalink raw reply related

* Re: migrating from svn: How to clean up history?
From: Jakub Narebski @ 2011-12-13 15:12 UTC (permalink / raw)
  To: Hartmut Goebel; +Cc: git
In-Reply-To: <4EE766D5.5040702@goebel-consult.de>

Hartmut Goebel <h.goebel@goebel-consult.de> writes:

> I'm one of the developers of www.pyinstaller.org, a tool for
> bundling/packagin Python scripts and al required modules into a single
> executable for easy distribution. We are in the process of migrating
> from Subversion to git.
> 
> Our SVN-Repo contains some stuff we do not want or do not need in the
> git repo. How can we clean this up?
> 
> 1) Useless commits e.g. tagging -> I want to remove these
> 2) copy or move mistakes -> I want to "correct" the copy
[...]

> Any hints how to to this clean-up?

You can try "gitsvnparse" command from 'reposurgeon' tool to
automatically correct some conversion mistakes, and use this tool to
do further fixes

  http://www.catb.org/esr/dvcs-migration-guide.html
  http://www.catb.org/~esr/reposurgeon/

HTH
-- 
Jakub Narebski

^ permalink raw reply

* [PATCH] gitk: use a tabbed dialog to edit preferences
From: Pat Thoyts @ 2011-12-13 14:56 UTC (permalink / raw)
  To: Git; +Cc: Paul Mackerras

This commit converts the user preferences dialog into a tabbed property
sheet grouping general properties, colours and font selections onto
separate pages. The previous implementation was exceeding the screen
height on some systems and this avoids such problems and permits extension
using new pages in the future.

If themed Tk is unavailable or undesired a reasonable facsimile of the
tabbed notebook widget is used instead.

Signed-off-by: Pat Thoyts <patthoyts@users.sourceforge.net>
---

I have done this patch against the git-core version of gitk as gitk's
own repository on kernel.org has not re-appeared. Is this likely to get
resurrected or should I perhaps make a github fork for any future work
on gitk?

Cheers,
Pat.

 gitk-git/gitk |  264 +++++++++++++++++++++++++++++++++++----------------------
 1 files changed, 164 insertions(+), 100 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 2a92e20..8d95bfc 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -10770,6 +10770,139 @@ proc chg_fontparam {v sub op} {
     font config sample -$sub $fontparam($sub)
 }
 
+# Create a property sheet tab page
+proc create_prefs_page {w} {
+    global NS
+    set parent [join [lrange [split $w .] 0 end-1] .]
+    if {[winfo class $parent] eq "TNotebook"} {
+	${NS}::frame $w
+    } else {
+	${NS}::labelframe $w
+    }
+}
+
+proc prefspage_general {notebook} {
+    global NS maxwidth maxgraphpct showneartags showlocalchanges
+    global tabstop limitdiffs autoselect autosellen extdifftool perfile_attrs
+    global hideremotes want_ttk have_ttk
+
+    set page [create_prefs_page $notebook.general]
+
+    ${NS}::label $page.ldisp -text [mc "Commit list display options"]
+    grid $page.ldisp - -sticky w -pady 10
+    ${NS}::label $page.spacer -text " "
+    ${NS}::label $page.maxwidthl -text [mc "Maximum graph width (lines)"]
+    spinbox $page.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
+    grid $page.spacer $page.maxwidthl $page.maxwidth -sticky w
+    ${NS}::label $page.maxpctl -text [mc "Maximum graph width (% of pane)"]
+    spinbox $page.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
+    grid x $page.maxpctl $page.maxpct -sticky w
+    ${NS}::checkbutton $page.showlocal -text [mc "Show local changes"] \
+	-variable showlocalchanges
+    grid x $page.showlocal -sticky w
+    ${NS}::checkbutton $page.autoselect -text [mc "Auto-select SHA1 (length)"] \
+	-variable autoselect
+    spinbox $page.autosellen -from 1 -to 40 -width 4 -textvariable autosellen
+    grid x $page.autoselect $page.autosellen -sticky w
+    ${NS}::checkbutton $page.hideremotes -text [mc "Hide remote refs"] \
+	-variable hideremotes
+    grid x $page.hideremotes -sticky w
+
+    ${NS}::label $page.ddisp -text [mc "Diff display options"]
+    grid $page.ddisp - -sticky w -pady 10
+    ${NS}::label $page.tabstopl -text [mc "Tab spacing"]
+    spinbox $page.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
+    grid x $page.tabstopl $page.tabstop -sticky w
+    ${NS}::checkbutton $page.ntag -text [mc "Display nearby tags"] \
+	-variable showneartags
+    grid x $page.ntag -sticky w
+    ${NS}::checkbutton $page.ldiff -text [mc "Limit diffs to listed paths"] \
+	-variable limitdiffs
+    grid x $page.ldiff -sticky w
+    ${NS}::checkbutton $page.lattr -text [mc "Support per-file encodings"] \
+	-variable perfile_attrs
+    grid x $page.lattr -sticky w
+
+    ${NS}::entry $page.extdifft -textvariable extdifftool
+    ${NS}::frame $page.extdifff
+    ${NS}::label $page.extdifff.l -text [mc "External diff tool" ]
+    ${NS}::button $page.extdifff.b -text [mc "Choose..."] -command choose_extdiff
+    pack $page.extdifff.l $page.extdifff.b -side left
+    pack configure $page.extdifff.l -padx 10
+    grid x $page.extdifff $page.extdifft -sticky ew
+
+    ${NS}::label $page.lgen -text [mc "General options"]
+    grid $page.lgen - -sticky w -pady 10
+    ${NS}::checkbutton $page.want_ttk -variable want_ttk \
+	-text [mc "Use themed widgets"]
+    if {$have_ttk} {
+	${NS}::label $page.ttk_note -text [mc "(change requires restart)"]
+    } else {
+	${NS}::label $page.ttk_note -text [mc "(currently unavailable)"]
+    }
+    grid x $page.want_ttk $page.ttk_note -sticky w
+    return $page
+}
+
+proc prefspage_colors {notebook} {
+    global NS uicolor bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor
+
+    set page [create_prefs_page $notebook.colors]
+
+    ${NS}::label $page.cdisp -text [mc "Colors: press to choose"]
+    grid $page.cdisp - -sticky w -pady 10
+    label $page.ui -padx 40 -relief sunk -background $uicolor
+    ${NS}::button $page.uibut -text [mc "Interface"] \
+       -command [list choosecolor uicolor {} $page.ui [mc "interface"] setui]
+    grid x $page.uibut $page.ui -sticky w
+    label $page.bg -padx 40 -relief sunk -background $bgcolor
+    ${NS}::button $page.bgbut -text [mc "Background"] \
+	-command [list choosecolor bgcolor {} $page.bg [mc "background"] setbg]
+    grid x $page.bgbut $page.bg -sticky w
+    label $page.fg -padx 40 -relief sunk -background $fgcolor
+    ${NS}::button $page.fgbut -text [mc "Foreground"] \
+	-command [list choosecolor fgcolor {} $page.fg [mc "foreground"] setfg]
+    grid x $page.fgbut $page.fg -sticky w
+    label $page.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
+    ${NS}::button $page.diffoldbut -text [mc "Diff: old lines"] \
+	-command [list choosecolor diffcolors 0 $page.diffold [mc "diff old lines"] \
+		      [list $ctext tag conf d0 -foreground]]
+    grid x $page.diffoldbut $page.diffold -sticky w
+    label $page.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
+    ${NS}::button $page.diffnewbut -text [mc "Diff: new lines"] \
+	-command [list choosecolor diffcolors 1 $page.diffnew [mc "diff new lines"] \
+		      [list $ctext tag conf dresult -foreground]]
+    grid x $page.diffnewbut $page.diffnew -sticky w
+    label $page.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
+    ${NS}::button $page.hunksepbut -text [mc "Diff: hunk header"] \
+	-command [list choosecolor diffcolors 2 $page.hunksep \
+		      [mc "diff hunk header"] \
+		      [list $ctext tag conf hunksep -foreground]]
+    grid x $page.hunksepbut $page.hunksep -sticky w
+    label $page.markbgsep -padx 40 -relief sunk -background $markbgcolor
+    ${NS}::button $page.markbgbut -text [mc "Marked line bg"] \
+	-command [list choosecolor markbgcolor {} $page.markbgsep \
+		      [mc "marked line background"] \
+		      [list $ctext tag conf omark -background]]
+    grid x $page.markbgbut $page.markbgsep -sticky w
+    label $page.selbgsep -padx 40 -relief sunk -background $selectbgcolor
+    ${NS}::button $page.selbgbut -text [mc "Select bg"] \
+	-command [list choosecolor selectbgcolor {} $page.selbgsep [mc "background"] setselbg]
+    grid x $page.selbgbut $page.selbgsep -sticky w
+    return $page
+}
+
+proc prefspage_fonts {notebook} {
+    global NS
+    set page [create_prefs_page $notebook.fonts]
+    ${NS}::label $page.cfont -text [mc "Fonts: press to choose"]
+    grid $page.cfont - -sticky w -pady 10
+    mkfontdisp mainfont $page [mc "Main font"]
+    mkfontdisp textfont $page [mc "Diff display font"]
+    mkfontdisp uifont $page [mc "User interface font"]
+    return $page
+}
+
 proc doprefs {} {
     global maxwidth maxgraphpct use_ttk NS
     global oldprefs prefstop showneartags showlocalchanges
@@ -10790,106 +10923,37 @@ proc doprefs {} {
     ttk_toplevel $top
     wm title $top [mc "Gitk preferences"]
     make_transient $top .
-    ${NS}::label $top.ldisp -text [mc "Commit list display options"]
-    grid $top.ldisp - -sticky w -pady 10
-    ${NS}::label $top.spacer -text " "
-    ${NS}::label $top.maxwidthl -text [mc "Maximum graph width (lines)"]
-    spinbox $top.maxwidth -from 0 -to 100 -width 4 -textvariable maxwidth
-    grid $top.spacer $top.maxwidthl $top.maxwidth -sticky w
-    ${NS}::label $top.maxpctl -text [mc "Maximum graph width (% of pane)"]
-    spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
-    grid x $top.maxpctl $top.maxpct -sticky w
-    ${NS}::checkbutton $top.showlocal -text [mc "Show local changes"] \
-	-variable showlocalchanges
-    grid x $top.showlocal -sticky w
-    ${NS}::checkbutton $top.autoselect -text [mc "Auto-select SHA1 (length)"] \
-	-variable autoselect
-    spinbox $top.autosellen -from 1 -to 40 -width 4 -textvariable autosellen
-    grid x $top.autoselect $top.autosellen -sticky w
-    ${NS}::checkbutton $top.hideremotes -text [mc "Hide remote refs"] \
-	-variable hideremotes
-    grid x $top.hideremotes -sticky w
-
-    ${NS}::label $top.ddisp -text [mc "Diff display options"]
-    grid $top.ddisp - -sticky w -pady 10
-    ${NS}::label $top.tabstopl -text [mc "Tab spacing"]
-    spinbox $top.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
-    grid x $top.tabstopl $top.tabstop -sticky w
-    ${NS}::checkbutton $top.ntag -text [mc "Display nearby tags"] \
-	-variable showneartags
-    grid x $top.ntag -sticky w
-    ${NS}::checkbutton $top.ldiff -text [mc "Limit diffs to listed paths"] \
-	-variable limitdiffs
-    grid x $top.ldiff -sticky w
-    ${NS}::checkbutton $top.lattr -text [mc "Support per-file encodings"] \
-	-variable perfile_attrs
-    grid x $top.lattr -sticky w
-
-    ${NS}::entry $top.extdifft -textvariable extdifftool
-    ${NS}::frame $top.extdifff
-    ${NS}::label $top.extdifff.l -text [mc "External diff tool" ]
-    ${NS}::button $top.extdifff.b -text [mc "Choose..."] -command choose_extdiff
-    pack $top.extdifff.l $top.extdifff.b -side left
-    pack configure $top.extdifff.l -padx 10
-    grid x $top.extdifff $top.extdifft -sticky ew
-
-    ${NS}::label $top.lgen -text [mc "General options"]
-    grid $top.lgen - -sticky w -pady 10
-    ${NS}::checkbutton $top.want_ttk -variable want_ttk \
-	-text [mc "Use themed widgets"]
-    if {$have_ttk} {
-	${NS}::label $top.ttk_note -text [mc "(change requires restart)"]
+
+    if {[set use_notebook [expr {$use_ttk && [info command ::ttk::notebook] ne ""}]]} {
+	set notebook [ttk::notebook $top.notebook]
     } else {
-	${NS}::label $top.ttk_note -text [mc "(currently unavailable)"]
-    }
-    grid x $top.want_ttk $top.ttk_note -sticky w
-
-    ${NS}::label $top.cdisp -text [mc "Colors: press to choose"]
-    grid $top.cdisp - -sticky w -pady 10
-    label $top.ui -padx 40 -relief sunk -background $uicolor
-    ${NS}::button $top.uibut -text [mc "Interface"] \
-       -command [list choosecolor uicolor {} $top.ui [mc "interface"] setui]
-    grid x $top.uibut $top.ui -sticky w
-    label $top.bg -padx 40 -relief sunk -background $bgcolor
-    ${NS}::button $top.bgbut -text [mc "Background"] \
-	-command [list choosecolor bgcolor {} $top.bg [mc "background"] setbg]
-    grid x $top.bgbut $top.bg -sticky w
-    label $top.fg -padx 40 -relief sunk -background $fgcolor
-    ${NS}::button $top.fgbut -text [mc "Foreground"] \
-	-command [list choosecolor fgcolor {} $top.fg [mc "foreground"] setfg]
-    grid x $top.fgbut $top.fg -sticky w
-    label $top.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
-    ${NS}::button $top.diffoldbut -text [mc "Diff: old lines"] \
-	-command [list choosecolor diffcolors 0 $top.diffold [mc "diff old lines"] \
-		      [list $ctext tag conf d0 -foreground]]
-    grid x $top.diffoldbut $top.diffold -sticky w
-    label $top.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
-    ${NS}::button $top.diffnewbut -text [mc "Diff: new lines"] \
-	-command [list choosecolor diffcolors 1 $top.diffnew [mc "diff new lines"] \
-		      [list $ctext tag conf dresult -foreground]]
-    grid x $top.diffnewbut $top.diffnew -sticky w
-    label $top.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
-    ${NS}::button $top.hunksepbut -text [mc "Diff: hunk header"] \
-	-command [list choosecolor diffcolors 2 $top.hunksep \
-		      [mc "diff hunk header"] \
-		      [list $ctext tag conf hunksep -foreground]]
-    grid x $top.hunksepbut $top.hunksep -sticky w
-    label $top.markbgsep -padx 40 -relief sunk -background $markbgcolor
-    ${NS}::button $top.markbgbut -text [mc "Marked line bg"] \
-	-command [list choosecolor markbgcolor {} $top.markbgsep \
-		      [mc "marked line background"] \
-		      [list $ctext tag conf omark -background]]
-    grid x $top.markbgbut $top.markbgsep -sticky w
-    label $top.selbgsep -padx 40 -relief sunk -background $selectbgcolor
-    ${NS}::button $top.selbgbut -text [mc "Select bg"] \
-	-command [list choosecolor selectbgcolor {} $top.selbgsep [mc "background"] setselbg]
-    grid x $top.selbgbut $top.selbgsep -sticky w
-
-    ${NS}::label $top.cfont -text [mc "Fonts: press to choose"]
-    grid $top.cfont - -sticky w -pady 10
-    mkfontdisp mainfont $top [mc "Main font"]
-    mkfontdisp textfont $top [mc "Diff display font"]
-    mkfontdisp uifont $top [mc "User interface font"]
+	set notebook [${NS}::frame $top.notebook -borderwidth 0 -relief flat]
+    }
+
+    lappend pages [prefspage_general $notebook] [mc "General"]
+    lappend pages [prefspage_colors $notebook] [mc "Colors"]
+    lappend pages [prefspage_fonts $notebook] [mc "Fonts"]
+    foreach {page title} $pages {
+	if {$use_notebook} {
+	    $notebook add $page -text $title
+	} else {
+	    set btn [${NS}::button $notebook.b_[string map {. X} $page] \
+			 -text $title -command [list raise $page]]
+	    $page configure -text $title
+	    grid $btn -row 0 -column [incr col] -sticky w
+	    grid $page -row 1 -column 0 -sticky news -columnspan 100
+	}
+    }
+
+    if {!$use_notebook} {
+	grid columnconfigure $notebook 0 -weight 1
+	grid rowconfigure $notebook 1 -weight 1
+	raise [lindex $pages 0]
+    }
+
+    grid $notebook -sticky news -padx 2 -pady 2
+    grid rowconfigure $top 0 -weight 1
+    grid columnconfigure $top 0 -weight 1
 
     ${NS}::frame $top.buts
     ${NS}::button $top.buts.ok -text [mc "OK"] -command prefsok -default active
@@ -10901,7 +10965,7 @@ proc doprefs {} {
     grid columnconfigure $top.buts 1 -weight 1 -uniform a
     grid $top.buts - - -pady 10 -sticky ew
     grid columnconfigure $top 2 -weight 1
-    bind $top <Visibility> "focus $top.buts.ok"
+    bind $top <Visibility> [list focus $top.buts.ok]
 }
 
 proc choose_extdiff {} {
-- 
1.7.8.msysgit.0

^ permalink raw reply related

* Re: [RFC/PATCH] add update to branch support for "floating submodules"
From: Marc Branchaud @ 2011-12-13 15:35 UTC (permalink / raw)
  To: Phil Hord; +Cc: Leif Gruenwoldt, Andreas T.Auer, Junio C Hamano, git
In-Reply-To: <CABURp0rFOGQ9kAbAn65W3UAHTWbk5prH7spjJnFvL5fqzbFp1w@mail.gmail.com>

On 11-12-12 05:56 PM, Phil Hord wrote:
> On Mon, Dec 12, 2011 at 2:13 PM, Leif Gruenwoldt <leifer@gmail.com> wrote:
>> On Mon, Dec 12, 2011 at 1:42 PM, Andreas T.Auer
>> <andreas.t.auer_gtml_37453@ursus.ath.cx> wrote:
>>
>>> The next question is: Wouldn't you like to have the new stable branch only
>>> pulled in, when the projectX (as the superproject) is currently on that new
>>> development branch (maybe master)?
>>>
>>> But if you checkout that fixed released version 1.2.9.8, wouldn't it be
>>> better that in that case the gitlinked version of the submodule is checked
>>> out instead of some unrelated new version? I mean, when the gitlinks are
>>> tracked with the projectX commits, this should work well.
>>>
>>> And what about a maintenance branch, which is not a fixed version but a
>>> quite stable branch which should only have bugfixes. Shouldn't the auto-pull
>>> be disabled in that case, too?
>>>
>>> I think the "auto-pull" behavior should depend on the currently checked out
>>> branch. So the configuration options should allow the definition of one or
>>> more mappings.
>>
>> Yes. I think you nailed it. The floating behaviour would best be
>> configured per branch.
> 
> Yes, I think you nailed it too.  I've been thinking the same thing for
> a while now, but I didn't know how to express it completely.  Some of
> the discussion on here last week gelled the last bits in my mind.
> 
> To wit, I think I would want something like this in my project:
> 
> Use gitlinks when the superproject HEAD is one of these:
>     refs/heads/maint/*
>     refs/heads/svn/*     (historic branches)
>     refs/tags/*
>     <SHA1> (detached)
> 
> Float on the rest, using the branch given in .gitmodules (which may be
> * to mean "use the same branch as the superproject".)
> 
> But maybe it is foolish of me to keep branches where I really want
> lightweight tags.  If so, I could get away with this:
> 
>    Float if .git/HEAD begins with "refs/heads"
>    Else, use the SHA1.

Wouldn't this break creating a bugfix topic branch based on an earlier
revision of the repo?  I wouldn't want such a branch to automatically give me
the latest submodules.

I'd prefer to have floating be explicitly configured on a per-branch (or
per-branch-glob) basis.  So in addition to what Jens described yesterday [1]
to configure an individual submodule's floating branch, I suggest there also
be a new section in the .gitmodules file for configuring the super-repo's
floating branches, e.g.

	[super]
		floaters = refs/heads/master refs/heads/dev*

	[submodule "Sub1"]
		path = foo/bar
		branch = maint
		url = ...

	[submodule "Sub2"]
		path = other/place
		url = ...

This would mean that whenever the super-repo checks out either the "master"
branch or a branch whose name starts with "dev" (assuming recursive checkouts
are on):

  * The Sub1 submodule automatically checks out the tip of its
    "maint" branch.

  * The Sub2 submodule (lacking a "branch" variable) would not float
    and would check out the commit recorded in the super-repo.

A super-repo recursive-checkout that doesn't match a floaters pattern would
work in the regular, non-floating way.

		M.

[1] http://article.gmane.org/gmane.comp.version-control.git/186969

^ permalink raw reply

* [PATCH] gitk: fix the display of files when filtered by path
From: Pat Thoyts @ 2011-12-13 16:50 UTC (permalink / raw)
  To: Git; +Cc: Paul Mackerras, msysGit, Johannes Schindelin

Launching 'gitk -- .' or 'gitk -- ..\t' restricts the display to files
under the given directory but the file list is left empty. This is because
the path_filter function fails to match the filenames which are relative
to the working tree to the filter which is filessytem relative.
This solves the problem by making both names fully qualified filesystem
paths before performing the comparison.

Signed-off-by: Pat Thoyts <patthoyts@users.sourceforge.net>
---
 gitk-git/gitk |   38 +++++++++++++++++++++++++++-----------
 1 files changed, 27 insertions(+), 11 deletions(-)

diff --git a/gitk-git/gitk b/gitk-git/gitk
index 2a92e20..b728345 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -18,6 +18,26 @@ proc gitdir {} {
     }
 }
 
+proc gitworktree {} {
+    variable _gitworktree
+    if {[info exists _gitworktree]} {
+	return $_gitworktree
+    }
+    # v1.7.0 introduced --show-toplevel to return the canonical work-tree
+    if {[catch {set _gitworktree [exec git rev-parse --show-toplevel]}]} {
+        # try to set work tree from environment, core.worktree or use
+        # cdup to obtain a relative path to the top of the worktree. If
+        # run from the top, the ./ prefix ensures normalize expands pwd.
+        if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} {
+	    catch {set _gitworktree [exec git config --get core.worktree]}
+	    if {$_gitworktree eq ""} {
+		set _gitworktree [file normalize ./[exec git rev-parse --show-cdup]]
+	    }
+        }
+    }
+    return $_gitworktree
+}
+
 # A simple scheduler for compute-intensive stuff.
 # The aim is to make sure that event handlers for GUI actions can
 # run at least every 50-100 ms.  Unfortunately fileevent handlers are
@@ -7376,19 +7396,15 @@ proc startdiff {ids} {
     }
 }
 
+# If the filename (name) is under any of the passed filter paths
+# then return true to include the file in the listing.
 proc path_filter {filter name} {
+    set worktree [gitworktree]
     foreach p $filter {
-	set l [string length $p]
-	if {[string index $p end] eq "/"} {
-	    if {[string compare -length $l $p $name] == 0} {
-		return 1
-	    }
-	} else {
-	    if {[string compare -length $l $p $name] == 0 &&
-		([string length $name] == $l ||
-		 [string index $name $l] eq "/")} {
-		return 1
-	    }
+	set fq_p [file normalize $p]
+	set fq_n [file normalize [file join $worktree $name]]
+	if {[string match [file normalize $fq_p]* $fq_n]} {
+	    return 1
 	}
     }
     return 0
-- 
1.7.8.msysgit.0

^ permalink raw reply related

* Re: Git blame only current branch
From: Junio C Hamano @ 2011-12-13 17:25 UTC (permalink / raw)
  To: Vijay Lakshminarayanan; +Cc: Jeff King, Stephen Bash, git discussion list
In-Reply-To: <87y5ugsguj.fsf@gmail.com>

Vijay Lakshminarayanan <laksvij@gmail.com> writes:

> Before the introduction of the numeral 1, I am in complete agreement
> with you for the exact reasons you've mentioned above.  Post
> introduction of "l ? 1 : 0" it warrants a refactoring.

If your main point is that "return l ? 1 : 0;", then a better thing to do
would be to use a well-known idiom to turn anything into a boolean, i.e.

	return !!l;

and your problem is solved without any renaming (we are not talking about
any "refactoring" that changes code structure).

I've seen enough bikeshedding, so I'd stop after pointing you in the right
direction by mentioning "git grep -e '<lst>'" and "git grep -e '<elem>'".

^ permalink raw reply

* Re: [PATCH resend] Do not create commits whose message contains NUL
From: Jeff King @ 2011-12-13 17:59 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git
In-Reply-To: <1323777368-19697-1-git-send-email-pclouds@gmail.com>

On Tue, Dec 13, 2011 at 06:56:08PM +0700, Nguyen Thai Ngoc Duy wrote:

> We assume that the commit log messages are uninterpreted sequences of
> non-NUL bytes (see Documentation/i18n.txt). However the assumption
> does not really stand out and it's quite easy to set an editor to save
> in a NUL-included encoding. Currently we silently cut at the first NUL
> we see.
> 
> Make it more obvious that NUL is not welcome by refusing to create
> such commits. Those who deliberately want to create them can still do
> with hash-object.
> 
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  This is from UTF-16 in commit message discussion [1] a few months
>  ago. I don't want to resurrect the discussion again. However I think
>  it's a good idea to stop users from shooting themselves in this case,
>  especially at porcelain level.
>
>  There were no comments on this patch previously. So, any comments
>  this time ? Should I drop it?

I think this is a sane thing to do. Having thought about and
experimented a little with utf-16 in the past few months, I really don't
see how you could be disrupting anybody's workflow. utf-16 messages get
butchered so badly already; we are much better off letting the user know
of the problem as soon as possible.

It looks like we already have a check for is_utf8, and this is not
failing that check. I guess because is_utf8 takes a NUL-terminated
buffer, so it simply sees the truncated result (i.e., depending on
endianness, "foo" in utf16 is something like "f\0o\0o\0", so we check
only "f"). We could make is_utf8 take a length parameter to be more
accurate, and then it would catch this.

However, I think that's not quite what we want. We only check is_utf8 if
the encoding field is not set. And really, we want to reject NULs no
matter _which_ encoding they've set, because git simply doesn't handle
them properly.

> diff --git a/commit.c b/commit.c
> index d67b8c7..0775eec 100644
> --- a/commit.c
> +++ b/commit.c
> @@ -855,6 +855,9 @@ int commit_tree(const char *msg, size_t msg_len, unsigned char *tree,

Hmm. My version of commit_tree does not have a "msg_len" parameter, nor
do I have d67b8c7. Is there some refactoring patch this is based on that
I missed?

> +	if (strlen(msg) < msg_len)
> +		die(_("cannot commit with NUL in commit message"));
> +

Two nits:

  1. For some reason, checking strlen(msg) seems a subtle way of looking
     for NULs in a buffer. I would have found:

         if (memchr(msg, '\0', msglen))

     much more obvious. But perhaps it is just me. Certainly not a big
     deal either way.

  2. The error message could be a little friendlier. The likely reason
     for NULs is a bogus encoding setting in the user's editor. We
     already have a nice "your message isn't utf-8" message. Though it
     does suggest setting i18n.commitencoding, which probably _isn't_
     the solution here (since their encoding clearly isn't supported).
     But maybe it would be nicer to say something like:

       error: your commit message contains NUL characters.
       hint: This is often caused by using multibyte encodings such as
       hint: UTF-16. Please check your editor settings.

     We could even go further and detect some common NUL-containing
     encodings, but I don't think it's worth the effort.

> diff --git a/t/t3900/UTF-16.txt b/t/t3900/UTF-16.txt
> new file mode 100644
> index 0000000000000000000000000000000000000000..53296be684253f40964c0604be7fa7ff12e200cb
> GIT binary patch
> literal 32
> mcmezOpWz6@X@-jo=NYasZ~@^#h9rjP3@HpR7}6Nh8Mpw;r3yp<

I was disappointed not to find a secret message. :)

-Peff

^ permalink raw reply

* Re: [PATCH/RFC 1/2] wrapper: supply xsetenv
From: Jeff King @ 2011-12-13 18:16 UTC (permalink / raw)
  To: Erik Faye-Lund; +Cc: git
In-Reply-To: <1323778227-1664-1-git-send-email-kusmabite@gmail.com>

On Tue, Dec 13, 2011 at 01:10:26PM +0100, Erik Faye-Lund wrote:

> +int xsetenv(const char *name, const char *val, int overwrite)
> +{
> +	if (setenv(name, val, overwrite))
> +		die_errno("setenv failed");
> +}

It probably doesn't matter, because the error condition is almost
certainly just "oops, we ran out of memory". But you could also print
the name of the variable being set, which may give the user a clue to
some misconfiguration (e.g., trying to put some extremely long value
into the environment).

-Peff

^ permalink raw reply

* Re: [PATCH/RFC 2/2] change all unchecked calls to setenv to xsetenv
From: Jeff King @ 2011-12-13 18:19 UTC (permalink / raw)
  To: Erik Faye-Lund; +Cc: git
In-Reply-To: <1323778227-1664-2-git-send-email-kusmabite@gmail.com>

On Tue, Dec 13, 2011 at 01:10:27PM +0100, Erik Faye-Lund wrote:

> While reviewing some patches for Git for Windows, I realized that
> we almost never check the return-value from setenv. This can lead
> to quite surprising errors in unusual sitations. Mostly, an error
> would probably be preferred. So here we go.
> 
> However, I'm not at all convinced myself that all of these make
> sense; in particular settings like GIT_EDITOR and GIT_PAGER could
> perhaps benefit from having a warning printed rather than a hard
> error.
> 
> Thoughts?

I wrote almost the same patch once[1], but failed to actually push it
through to acceptance. There weren't any objections, just that nobody
really cared.  I think it's a reasonable thing to do. The chances of
setenv failing are very low, but the consequences could be quite bad.

There is also a call to putenv in git.c which should be checked (or
could arguably just be converted to setenv).

-Peff

[1] http://thread.gmane.org/gmane.comp.version-control.git/134466

^ permalink raw reply

* [PATCH 0/3] use constants for sideband communication channels
From: iheffner @ 2011-12-13 18:28 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Junio C Hamano, Dave Olszewski

In order to make more clear how the different channels in sidechannel.c
are to be used, I'm proposing some macros/constants which can be used in
place of the "magic numbers" that mean little or nothing to someone not
familiar with the protocol.

In working on a script to handle archiving from a bare repository a
project which contained submodules, I had a difficult time determining
how to talk between my git-upload-archive replacement and git-archive.
It did not occur to me to look at documentation for git-send-pack or
git-receive-pack when trying to understand the communication protocol.
But looking through the code and poking at an implementation, I finally
understood that I needed to send a channel identifier to say what type
of communication I was sending. I determined that there were three
possible channels. I could easily tell that channel three (3) was for
catastrophic errors on the server side.  But it was not clear what the
difference between channel 1 and channel 2 were.  Because channel 2 was
the one that appeared to be read and parsed in some manner, I assumed
that this was the "important" data channel and tried sending my data on
that channel.

I was confused and frustrated when it appeared that git-archive treated
data coming from my --exec'd git-upload-archive replacement differently
than it did when receiving data from the real git-upload-archive.
Eventually I figured out that channel 1 was for data, channel 2 was for
non-fatal messages, and channel 3 was for fatal error communications.
Having comments in sidechannel.h would have helped. But constants or
macros would have helped as well and makes the code that uses them more
clear.

Ivan


 [PATCH 1/3] add constants for sideband communication channels
 [PATCH 2/3] switch sideband communication to use constants
 [PATCH 3/3] use SIDEBAND_*_ERROR constants in pack protocol

 builtin/fetch-pack.c     |    2 +-
 builtin/receive-pack.c   |    6 +++---
 builtin/send-pack.c      |    4 ++--
 builtin/upload-archive.c |    6 +++---
 sideband.c               |    6 +++---
 sideband.h               |    6 +++++-
 upload-pack.c            |   22 +++++++++++-----------
 7 files changed, 28 insertions(+), 24 deletions(-)

^ permalink raw reply

* [PATCH 1/3] add constants for sideband communication channels
From: iheffner @ 2011-12-13 18:28 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Junio C Hamano, Dave Olszewski, Ivan Heffner
In-Reply-To: <1323800931-37123-1-git-send-email-iheffner@gmail.com>

From: Ivan Heffner <iheffner@gmail.com>

Add constants for sideband channel identifiers.

* SIDEBAND_CHAN_PACK     => 1
* SIDEBAND_CHAN_PROGRESS => 2
* SIDEBAND_CHAN_ERROR    => 3

Signed-off-by: Ivan Heffner <iheffner@gmail.com>
---
 sideband.h |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/sideband.h b/sideband.h
index d72db35..2954979 100644
--- a/sideband.h
+++ b/sideband.h
@@ -2,7 +2,11 @@
 #define SIDEBAND_H
 
 #define SIDEBAND_PROTOCOL_ERROR -2
-#define SIDEBAND_REMOTE_ERROR -1
+#define SIDEBAND_REMOTE_ERROR   -1
+#define SIDEBAND_CHAN_PACK       1
+#define SIDEBAND_CHAN_PROGRESS   2
+#define SIDEBAND_CHAN_ERROR      3
+
 
 #define DEFAULT_PACKET_MAX 1000
 #define LARGE_PACKET_MAX 65520
-- 
1.7.6.553.g917d7.dirty

^ permalink raw reply related

* [PATCH 2/3] switch sideband communication to use constants
From: iheffner @ 2011-12-13 18:28 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Junio C Hamano, Dave Olszewski, Ivan Heffner
In-Reply-To: <1323800931-37123-1-git-send-email-iheffner@gmail.com>

From: Ivan Heffner <iheffner@gmail.com>

Found all uses of magic numbers for sideband channel indicators and
changed them to use the new SIDEBAND_CHAN_* constants.

Signed-off-by: Ivan Heffner <iheffner@gmail.com>
---
 builtin/receive-pack.c   |    6 +++---
 builtin/upload-archive.c |    6 +++---
 sideband.c               |    6 +++---
 upload-pack.c            |   22 +++++++++++-----------
 4 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 7ec68a1..43f7a55 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -179,7 +179,7 @@ static void report_message(const char *prefix, const char *err, va_list params)
 	msg[sz++] = '\n';
 
 	if (use_sideband)
-		send_sideband(1, 2, msg, sz, use_sideband);
+		send_sideband(1, SIDEBAND_CHAN_PROGRESS, msg, sz, use_sideband);
 	else
 		xwrite(2, msg, sz);
 }
@@ -207,7 +207,7 @@ static int copy_to_sideband(int in, int out, void *arg)
 		ssize_t sz = xread(in, data, sizeof(data));
 		if (sz <= 0)
 			break;
-		send_sideband(1, 2, data, sz, use_sideband);
+		send_sideband(1, SIDEBAND_CHAN_PROGRESS, data, sz, use_sideband);
 	}
 	close(in);
 	return 0;
@@ -851,7 +851,7 @@ static void report(struct command *commands, const char *unpack_status)
 	packet_buf_flush(&buf);
 
 	if (use_sideband)
-		send_sideband(1, 1, buf.buf, buf.len, use_sideband);
+		send_sideband(1, SIDEBAND_CHAN_PACK, buf.buf, buf.len, use_sideband);
 	else
 		safe_write(1, buf.buf, buf.len);
 	strbuf_release(&buf);
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
index 2d0b383..4ac7984 100644
--- a/builtin/upload-archive.c
+++ b/builtin/upload-archive.c
@@ -77,7 +77,7 @@ static void error_clnt(const char *fmt, ...)
 	va_start(params, fmt);
 	len = vsprintf(buf, fmt, params);
 	va_end(params);
-	send_sideband(1, 3, buf, len, LARGE_PACKET_MAX);
+	send_sideband(1, SIDEBAND_CHAN_ERROR, buf, len, LARGE_PACKET_MAX);
 	die("sent error to the client: %s", buf);
 }
 
@@ -149,11 +149,11 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
 		}
 		if (pfd[1].revents & POLLIN)
 			/* Status stream ready */
-			if (process_input(pfd[1].fd, 2))
+			if (process_input(pfd[1].fd, SIDEBAND_CHAN_PROGRESS))
 				continue;
 		if (pfd[0].revents & POLLIN)
 			/* Data stream ready */
-			if (process_input(pfd[0].fd, 1))
+			if (process_input(pfd[0].fd, SIDEBAND_CHAN_PACK))
 				continue;
 
 		if (waitpid(writer, &status, 0) < 0)
diff --git a/sideband.c b/sideband.c
index d5ffa1c..4b4199a 100644
--- a/sideband.c
+++ b/sideband.c
@@ -47,12 +47,12 @@ int recv_sideband(const char *me, int in_stream, int out)
 		band = buf[pf] & 0xff;
 		len--;
 		switch (band) {
-		case 3:
+		case SIDEBAND_CHAN_ERROR:
 			buf[pf] = ' ';
 			buf[pf+1+len] = '\0';
 			fprintf(stderr, "%s\n", buf);
 			return SIDEBAND_REMOTE_ERROR;
-		case 2:
+		case SIDEBAND_CHAN_PROGRESS:
 			buf[pf] = ' ';
 			do {
 				char *b = buf;
@@ -107,7 +107,7 @@ int recv_sideband(const char *me, int in_stream, int out)
 				memmove(buf + pf+1, b + brk, len);
 			} while (len);
 			continue;
-		case 1:
+		case SIDEBAND_CHAN_PACK:
 			safe_write(out, buf + pf+1, len);
 			continue;
 		default:
diff --git a/upload-pack.c b/upload-pack.c
index 470cffd..98c2542 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -56,19 +56,19 @@ static int strip(char *line, int len)
 	return len;
 }
 
-static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
+static ssize_t send_client_data(int chan, const char *data, ssize_t sz)
 {
 	if (use_sideband)
-		return send_sideband(1, fd, data, sz, use_sideband);
-	if (fd == 3)
+		return send_sideband(1, chan, data, sz, use_sideband);
+	if (chan == SIDEBAND_CHAN_ERROR)
 		/* emergency quit */
-		fd = 2;
-	if (fd == 2) {
+		chan = SIDEBAND_CHAN_PROGRESS;
+	if (chan == SIDEBAND_CHAN_PROGRESS) {
 		/* XXX: are we happy to lose stuff here? */
-		xwrite(fd, data, sz);
+		xwrite(chan, data, sz);
 		return sz;
 	}
-	return safe_write(fd, data, sz);
+	return safe_write(chan, data, sz);
 }
 
 static FILE *pack_pipe = NULL;
@@ -243,7 +243,7 @@ static void create_pack_file(void)
 			sz = xread(pack_objects.err, progress,
 				  sizeof(progress));
 			if (0 < sz)
-				send_client_data(2, progress, sz);
+				send_client_data(SIDEBAND_CHAN_PROGRESS, progress, sz);
 			else if (sz == 0) {
 				close(pack_objects.err);
 				pack_objects.err = -1;
@@ -286,7 +286,7 @@ static void create_pack_file(void)
 			}
 			else
 				buffered = -1;
-			sz = send_client_data(1, data, sz);
+			sz = send_client_data(SIDEBAND_CHAN_PACK, data, sz);
 			if (sz < 0)
 				goto fail;
 		}
@@ -302,7 +302,7 @@ static void create_pack_file(void)
 	/* flush the data */
 	if (0 <= buffered) {
 		data[0] = buffered;
-		sz = send_client_data(1, data, 1);
+		sz = send_client_data(SIDEBAND_CHAN_PACK, data, 1);
 		if (sz < 0)
 			goto fail;
 		fprintf(stderr, "flushed.\n");
@@ -312,7 +312,7 @@ static void create_pack_file(void)
 	return;
 
  fail:
-	send_client_data(3, abort_msg, sizeof(abort_msg));
+	send_client_data(SIDEBAND_CHAN_ERROR, abort_msg, sizeof(abort_msg));
 	die("git upload-pack: %s", abort_msg);
 }
 
-- 
1.7.6.553.g917d7.dirty

^ permalink raw reply related

* [PATCH 3/3] use SIDEBAND_*_ERROR constants in pack protocol
From: iheffner @ 2011-12-13 18:28 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Junio C Hamano, Dave Olszewski, Ivan Heffner
In-Reply-To: <1323800931-37123-1-git-send-email-iheffner@gmail.com>

From: Ivan Heffner <iheffner@gmail.com>

Switched calls to send_sideband() for pack protocol errors to use
SIDEBAND_PROTOCOL_ERROR and SIDEBAND_REMOTE_ERROR in place of the
sideband magic numbers of -2 and -1, respectively.

Signed-off-by: Ivan Heffner <iheffner@gmail.com>
---
 builtin/fetch-pack.c |    2 +-
 builtin/send-pack.c  |    4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index c6bc8eb..63e9ac4 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -245,7 +245,7 @@ static enum ack_type get_ack(int fd, unsigned char *result_sha1)
 static void send_request(int fd, struct strbuf *buf)
 {
 	if (args.stateless_rpc) {
-		send_sideband(fd, -1, buf->buf, buf->len, LARGE_PACKET_MAX);
+		send_sideband(fd, SIDEBAND_REMOTE_ERROR, buf->buf, buf->len, LARGE_PACKET_MAX);
 		packet_flush(fd);
 	} else
 		safe_write(fd, buf->buf, buf->len);
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index e0b8030..67c9fe5 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -96,7 +96,7 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
 			ssize_t n = xread(po.out, buf, LARGE_PACKET_MAX);
 			if (n <= 0)
 				break;
-			send_sideband(fd, -1, buf, n, LARGE_PACKET_MAX);
+			send_sideband(fd, SIDEBAND_REMOTE_ERROR, buf, n, LARGE_PACKET_MAX);
 		}
 		free(buf);
 		close(po.out);
@@ -320,7 +320,7 @@ int send_pack(struct send_pack_args *args,
 	if (args->stateless_rpc) {
 		if (!args->dry_run && cmds_sent) {
 			packet_buf_flush(&req_buf);
-			send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
+			send_sideband(out, SIDEBAND_REMOTE_ERROR, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
 		}
 	} else {
 		safe_write(out, req_buf.buf, req_buf.len);
-- 
1.7.6.553.g917d7.dirty

^ permalink raw reply related

* Re: [PATCH/RFC 2/2] change all unchecked calls to setenv to xsetenv
From: Junio C Hamano @ 2011-12-13 18:33 UTC (permalink / raw)
  To: Jeff King; +Cc: Erik Faye-Lund, git
In-Reply-To: <20111213181946.GC1663@sigill.intra.peff.net>

Jeff King <peff@peff.net> writes:

> On Tue, Dec 13, 2011 at 01:10:27PM +0100, Erik Faye-Lund wrote:
>
>> While reviewing some patches for Git for Windows, I realized that
>> we almost never check the return-value from setenv. This can lead
>> to quite surprising errors in unusual sitations. Mostly, an error
>> would probably be preferred. So here we go.
>> 
>> However, I'm not at all convinced myself that all of these make
>> sense; in particular settings like GIT_EDITOR and GIT_PAGER could
>> perhaps benefit from having a warning printed rather than a hard
>> error.
>> 
>> Thoughts?
>
> I wrote almost the same patch once[1], but failed to actually push it
> through to acceptance.

In both cases, the patches are _designed_ to fail to attract any
attention.  Your earlier one had this preamble:

  Here is a patch. I still feel a little silly writing this. The chances
  that you will run out of memory doing setenv but _not_ doing any of the
  other git operations seems very low.

which rather *loudly* says "ignore me, please!" ;-)

Erik's patch this round is no better; if its log message said something
like "On platform X, the environment space is merely nKB and setenv has
much higher chance of failing than on typical Linux boxes", it would have
been a no brainer for me to respond with "makes perfect sense but don't we
also use putenv?" immediately.

^ permalink raw reply

* Re: [PATCH/RFC 1/2] wrapper: supply xsetenv
From: Junio C Hamano @ 2011-12-13 18:34 UTC (permalink / raw)
  To: Jeff King; +Cc: Erik Faye-Lund, git
In-Reply-To: <20111213181602.GB1663@sigill.intra.peff.net>

Jeff King <peff@peff.net> writes:

> On Tue, Dec 13, 2011 at 01:10:26PM +0100, Erik Faye-Lund wrote:
>
>> +int xsetenv(const char *name, const char *val, int overwrite)
>> +{
>> +	if (setenv(name, val, overwrite))
>> +		die_errno("setenv failed");
>> +}
>
> It probably doesn't matter, because the error condition is almost
> certainly just "oops, we ran out of memory". But you could also print
> the name of the variable being set, which may give the user a clue to
> some misconfiguration (e.g., trying to put some extremely long value
> into the environment).

Do we have enough memory to format that message in that situation ;-)?

^ permalink raw reply

* Re: [PATCH/RFC 1/2] wrapper: supply xsetenv
From: Erik Faye-Lund @ 2011-12-13 18:52 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git
In-Reply-To: <7vwra0uxqo.fsf@alter.siamese.dyndns.org>

On Tue, Dec 13, 2011 at 7:34 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Jeff King <peff@peff.net> writes:
>
>> On Tue, Dec 13, 2011 at 01:10:26PM +0100, Erik Faye-Lund wrote:
>>
>>> +int xsetenv(const char *name, const char *val, int overwrite)
>>> +{
>>> +    if (setenv(name, val, overwrite))
>>> +            die_errno("setenv failed");
>>> +}
>>
>> It probably doesn't matter, because the error condition is almost
>> certainly just "oops, we ran out of memory". But you could also print
>> the name of the variable being set, which may give the user a clue to
>> some misconfiguration (e.g., trying to put some extremely long value
>> into the environment).
>
> Do we have enough memory to format that message in that situation ;-)?

We could. Running out of environment space is not the same as running
out of memory. For instance, Windows has a maximum environment size of
32 kB. Older Linux kernels maxed out at 128 kB.

So I think it's a good idea to at least try. The worst that can happen
is another, less descriptive error, no?

^ permalink raw reply


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