Git development
 help / color / mirror / Atom feed
* [RFC, PATCH] Teach revision.c about renames
From: Fredrik Kuivinen @ 2006-05-15 20:37 UTC (permalink / raw)
  To: git; +Cc: junkio

Hi,

The attached patch is a work in progress to add support for rename
following to the revision walking code in revision.c.

When the rename following is enabled (with the new '--renames' flag)
any pathspecs given on the command line are interpreted as
filenames. Those filenames are then followed through the commit graph.

For example, 'git log --renames -- git-fetch.sh' will show us the
history of 'git-fetch.sh' till commit
215a7ad1ef790467a4cd3f0dcffbd6e5f04c38f7 where it was renamed from
git-fetch-script, we then get the history of git-fetch-script instead.

This works with all commands that use revision.c. So 'gitk --renames
git-fetch.sh' and 'git whatchanged --renames git-fetch.sh' also
work. Multiple filenames are supposed to work (e.g., 'gitk --renames
-- git-fetch.sh Documentation/technical/pack-protocol.txt')

The patch currently have a few issues (that I am aware of):

* A linked list is used to keep track of which filenames that we care
  about for each commit. A more efficient data structure may be a good
  idea.

* Memory leaks. In particular the struct path_lists are never freed.

* Pathspecs that aren't filenames cause assertion failures. (for
  example 'git log --renames -- Documentation/') I don't really know
  what we should do in this case. Should we interpret 'Documentation/'
  as if the user supplied us with all the files in the Documentation
  directory and then track those? Or, should we show commits that
  change anything under Documentation/ (i.e., the old non-rename
  following behaviour) and additionally track files that are moved
  from Documentation/ to some other location. Yet another alternative
  is to disallow non-filenames. Thoughts?

* Is '--renames' a good name for the flag? I considered
  '--follow-renames' first, but found it a bit too long.


Any comments would be greatly appreciated.

- Fredrik

Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>

---

 log-tree.c |    7 +
 revision.c |  347 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 revision.h |   30 +++++
 3 files changed, 381 insertions(+), 3 deletions(-)

diff --git a/log-tree.c b/log-tree.c
index b90ba67..8ed500a 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -84,11 +84,12 @@ int log_tree_diff_flush(struct rev_info 
 }
 
 static int diff_root_tree(struct rev_info *opt,
-			  const unsigned char *new, const char *base)
+			  struct commit* commit, const char *base)
 {
 	int retval;
 	void *tree;
 	struct tree_desc empty, real;
+	const unsigned char* new = commit->object.sha1;
 
 	tree = read_object_with_reference(new, tree_type, &real.size, NULL);
 	if (!tree)
@@ -97,6 +98,7 @@ static int diff_root_tree(struct rev_inf
 
 	empty.buf = "";
 	empty.size = 0;
+	rev_setup_diffopt_paths(opt, commit, NULL);
 	retval = diff_tree(&empty, &real, base, &opt->diffopt);
 	free(tree);
 	log_tree_diff_flush(opt);
@@ -129,7 +131,7 @@ static int log_tree_diff(struct rev_info
 	parents = commit->parents;
 	if (!parents) {
 		if (opt->show_root_diff)
-			diff_root_tree(opt, sha1, "");
+			diff_root_tree(opt, commit, "");
 		return !opt->loginfo;
 	}
 
@@ -148,6 +150,7 @@ static int log_tree_diff(struct rev_info
 	for (;;) {
 		struct commit *parent = parents->item;
 
+		rev_setup_diffopt_paths(opt, commit, parent);
 		diff_tree_sha1(parent->object.sha1, sha1, "", &opt->diffopt);
 		log_tree_diff_flush(opt);
 
diff --git a/revision.c b/revision.c
index 2294b16..523ab29 100644
--- a/revision.c
+++ b/revision.c
@@ -1,12 +1,17 @@
+#include <assert.h>
+
 #include "cache.h"
 #include "tag.h"
 #include "blob.h"
 #include "tree.h"
 #include "commit.h"
 #include "diff.h"
+#include "diffcore.h"
 #include "refs.h"
 #include "revision.h"
 
+#define DEBUG 0
+
 static char *path_name(struct name_path *path, const char *name)
 {
 	struct name_path *p;
@@ -507,6 +512,320 @@ static int add_parents_only(struct rev_i
 	return 1;
 }
 
+/* Rename following code */
+const struct path_list* path_list_find(const struct path_list* list,
+					      const char* path)
+{
+	for(; list; list = list->next) {
+		if (!strcmp(path, list->item))
+			return list;
+	}
+
+	return NULL;
+}
+
+struct path_list* path_list_insert(char *item, struct path_list **list_p)
+{
+	struct path_list *new_list = xmalloc(sizeof(struct path_list));
+	new_list->item = item;
+	new_list->next = *list_p;
+	*list_p = new_list;
+	return new_list;
+}
+
+void path_list_print(FILE* file, struct path_list* list)
+{
+	for(; list; list = list->next)
+		fprintf(file, "%s ", list->item);
+	fputc('\n', file);
+}
+
+void free_path_list(struct path_list *list)
+{
+	while (list) {
+		struct path_list *temp = list;
+		list = temp->next;
+		free(temp);
+	}
+}
+
+const char** convert_to_pathspec(struct path_list* l1, struct path_list* l2)
+{
+	struct path_list* l;
+	const char** ret;
+	int i, len = 0;
+
+	for(l = l1; l; l = l->next, len++)
+		;
+	for(l = l2; l; l = l->next, len++)
+		;
+
+	ret = xmalloc((len+1)*sizeof(char*));
+	for(i = 0; l1; l1 = l1->next, i++)
+		ret[i] = l1->item;
+ 	for(; l2; l2 = l2->next, i++)
+		ret[i] = l2->item;
+
+	ret[len] = NULL;
+	return ret;
+}
+
+static struct rev_commit_info* get_util(struct commit *commit)
+{
+	struct rev_commit_info *util = commit->object.util;
+
+	if (util)
+		return util;
+
+	util = xmalloc(sizeof(struct rev_commit_info));
+	util->paths = NULL;
+	util->topo_data = NULL;
+	commit->object.util = util;
+	return util;
+}
+
+void rev_setup_diffopt_paths(struct rev_info* revs,
+			     struct commit* commit,
+			     struct commit* parent)
+{
+	const char** pathspec =
+		convert_to_pathspec(get_util(commit)->paths,
+				    parent ? get_util(parent)->paths : NULL);
+
+	/* FIXME we can't free revs->diffopt.paths here because the
+	 * initial value of that variable isn't necessarily allocated
+	 * by malloc.
+	 *
+	 * free(revs->diffopt.paths); */
+	diff_tree_release_paths(&revs->diffopt);
+	diff_tree_setup_paths(pathspec, &revs->diffopt);
+}
+
+
+static void topo_setter(struct commit* c, void* data)
+{
+	struct rev_commit_info* util = c->object.util;
+	util->topo_data = data;
+}
+
+static void* topo_getter(struct commit* c)
+{
+	struct rev_commit_info* util = c->object.util;
+	return util->topo_data;
+}
+
+
+static int same_tree_as_empty_paths(struct rev_info *revs, struct tree* t1,
+				    struct path_list* paths)
+{
+	int ret;
+
+	const char** pathspec = convert_to_pathspec(paths, NULL);
+	diff_tree_setup_paths(pathspec, &revs->pruning);
+	ret = rev_same_tree_as_empty(revs, t1);
+	diff_tree_release_paths(&revs->pruning);
+	free(pathspec);
+	return ret;
+}
+
+
+static struct path_list* file_removals;
+static void file_add_remove_ren(struct diff_options *options,
+				int addremove, unsigned mode,
+				const unsigned char *sha1,
+				const char *base, const char *path)
+{
+	if (DEBUG)
+		printf("%c base: '%s' path: '%s'\n", addremove, base, path);
+
+	if (addremove == '-') {
+		char* p = xmalloc(strlen(base) + strlen(path) + 1);
+		strcpy(p, base);
+		strcat(p, path);
+		path_list_insert(p, &file_removals);
+		tree_difference = REV_TREE_NEW;
+	} else {
+		assert(0);
+	}
+}
+
+static void file_change_ren(struct diff_options *options,
+			    unsigned old_mode, unsigned new_mode,
+			    const unsigned char *old_sha1,
+			    const unsigned char *new_sha1,
+			    const char *base, const char *path)
+{
+	if (tree_difference == REV_TREE_SAME)
+		tree_difference = REV_TREE_DIFFERENT;
+}
+
+static int compare_tree_paths(struct rev_info* revs,
+			      struct commit* parent, struct commit* commit,
+			      struct path_list** added)
+{
+	const char** pathspec;
+	struct diff_options dopts;
+
+	diff_setup(&dopts);
+	dopts.recursive = 1;
+	dopts.add_remove = file_add_remove_ren;
+	dopts.change = file_change_ren;
+	dopts.output_format = DIFF_FORMAT_NO_OUTPUT;
+
+	pathspec = convert_to_pathspec(get_util(commit)->paths, NULL);
+	diff_tree_setup_paths(pathspec, &dopts);
+
+	if (diff_setup_done(&dopts) < 0)
+		die("diff_setup_done failed");
+
+	file_removals = NULL;
+	tree_difference = REV_TREE_SAME;
+
+	diff_tree_sha1(commit->tree->object.sha1, parent->tree->object.sha1,
+		       "", &dopts);
+
+	diff_flush(&dopts);
+	diff_tree_release_paths(&dopts);
+	free(pathspec);
+
+	*added = file_removals;
+	return tree_difference;
+}
+
+static struct path_list* find_renames(struct commit* commit,
+				      struct commit* parent,
+				      struct path_list* paths)
+{
+	int i;
+	struct diff_options dopts;
+	struct path_list* ret = NULL;
+
+	if (DEBUG) {
+		printf("find_renames commit: %s ",
+		       sha1_to_hex(commit->object.sha1));
+		puts(sha1_to_hex(parent->object.sha1));
+		printf("rename from paths: ");
+		path_list_print(stdout, paths);
+	}
+
+	diff_setup(&dopts);
+	dopts.recursive = 1;
+	dopts.detect_rename = DIFF_DETECT_RENAME;
+	dopts.output_format = DIFF_FORMAT_NO_OUTPUT;
+
+	if (diff_setup_done(&dopts) < 0)
+		die("diff_setup_done failed");
+
+	diff_tree_sha1(commit->tree->object.sha1, parent->tree->object.sha1,
+		       "", &dopts);
+	diffcore_std(&dopts);
+
+	for (i = 0; i < diff_queued_diff.nr; i++) {
+		struct diff_filepair *p = diff_queued_diff.queue[i];
+
+		if (0 && p->status == 'R' && DEBUG)
+			printf("rename %s -> %s\n", p->one->path, p->two->path);
+
+		if (p->status == 'R' && path_list_find(paths, p->one->path)) {
+			if (DEBUG)
+				printf("rename %s -> %s\n",
+				       p->one->path, p->two->path);
+			path_list_insert(strdup(p->two->path), &ret);
+		}
+	}
+	diff_flush(&dopts);
+
+	if (DEBUG) {
+		printf("rename result: ");
+		path_list_print(stdout, ret);
+	}
+	return ret;
+}
+
+static struct path_list* rewrite_paths(struct rev_info *revs,
+				       struct commit* commit,
+				       struct commit* parent,
+				       struct path_list* removed)
+{
+	struct path_list* new_paths = find_renames(commit, parent, removed);
+	struct path_list* cpaths = get_util(commit)->paths;
+	for(; cpaths; cpaths = cpaths->next) {
+		if (!path_list_find(removed, cpaths->item))
+			path_list_insert(cpaths->item, &new_paths);
+	}
+	return new_paths;
+}
+
+static void simplify_commit_rename(struct rev_info *revs,
+				   struct commit *commit)
+{
+	struct commit_list **pp, *parent;
+
+	if (!commit->tree)
+		return;
+
+	{
+		struct rev_commit_info* util = get_util(commit);
+		if (!util->paths) {
+			util->paths = revs->initial_paths;
+			if (DEBUG)
+				printf("NULL paths\n");
+		}
+	}
+
+	if (!commit->parents) {
+		struct rev_commit_info* util = commit->object.util;
+		if (!same_tree_as_empty_paths(revs, commit->tree,
+					      util->paths))
+			commit->object.flags |= TREECHANGE;
+		return;
+	}
+
+	pp = &commit->parents;
+	while ((parent = *pp) != NULL) {
+		struct commit *p = parent->item;
+		struct path_list* removed;
+
+		if (p->object.flags & UNINTERESTING) {
+			pp = &parent->next;
+			continue;
+		}
+
+		parse_commit(p);
+		switch (compare_tree_paths(revs, p, commit, &removed)) {
+		case REV_TREE_SAME:
+			parent->next = NULL;
+			commit->parents = parent;
+			get_util(p)->paths = get_util(commit)->paths;
+			return;
+
+		case REV_TREE_NEW:
+		{
+			struct path_list* new_paths =
+				rewrite_paths(revs, commit, p, removed);
+			if (new_paths) {
+				struct rev_commit_info* putil = get_util(p);
+				if (!putil->paths)
+					putil->paths = new_paths;
+			} else {
+				*pp = parent->next;
+				continue;
+			}
+		}
+
+		/* fallthrough */
+		case REV_TREE_DIFFERENT:
+			pp = &parent->next;
+			if (!get_util(p)->paths)
+				get_util(p)->paths = get_util(commit)->paths;
+			continue;
+		}
+		die("bad tree compare for commit %s",
+		    sha1_to_hex(commit->object.sha1));
+	}
+	commit->object.flags |= TREECHANGE;
+}
+
 void init_revisions(struct rev_info *revs)
 {
 	memset(revs, 0, sizeof(*revs));
@@ -742,6 +1061,11 @@ int setup_revisions(int argc, const char
 				revs->full_diff = 1;
 				continue;
 			}
+			if (!strcmp(arg, "--renames")) {
+				revs->follow_renames = 1;
+				continue;
+			}
+
 			opts = diff_opt_parse(&revs->diffopt, argv+i, argc-i);
 			if (opts > 0) {
 				revs->diff = 1;
@@ -841,6 +1165,29 @@ int setup_revisions(int argc, const char
 		    (revs->diffopt.output_format != DIFF_FORMAT_DIFFSTAT))
 			revs->diffopt.output_format = DIFF_FORMAT_PATCH;
 	}
+	if (revs->follow_renames && revs->prune_data) {
+		if (revs->remove_empty_trees)
+			die("--renames and --remove-empty are currently "
+			    "mutually exclusive");
+		revs->prune_fn = simplify_commit_rename;
+		revs->topo_setter = topo_setter;
+		revs->topo_getter = topo_getter;
+		revs->limited = 1;
+
+		{
+			char** p;
+			for(p = revs->prune_data; *p; p++) {
+				if (DEBUG)
+					printf("filename: %s\n", *p);
+				path_list_insert(strdup(*p),
+						 &revs->initial_paths);
+			}
+		}
+
+		if (DEBUG)
+			printf("prefix: %s\n", revs->prefix);
+	}
+
 	revs->diffopt.abbrev = revs->abbrev;
 	diff_setup_done(&revs->diffopt);
 
diff --git a/revision.h b/revision.h
index 48d7b4c..e73a327 100644
--- a/revision.h
+++ b/revision.h
@@ -39,7 +39,8 @@ struct rev_info {
 			limited:1,
 			unpacked:1,
 			boundary:1,
-			parents:1;
+			parents:1,
+			follow_renames:1;
 
 	/* Diff flags */
 	unsigned int	diff:1,
@@ -68,6 +69,9 @@ struct rev_info {
 	struct diff_options diffopt;
 	struct diff_options pruning;
 
+	/* Rename following */
+	struct path_list* initial_paths;
+
 	topo_sort_set_fn_t topo_setter;
 	topo_sort_get_fn_t topo_getter;
 };
@@ -99,4 +103,28 @@ extern struct object_list **add_object(s
 				       struct name_path *path,
 				       const char *name);
 
+
+
+struct path_list {
+	char* item;
+	struct path_list *next;
+};
+
+struct rev_commit_info {
+	struct path_list* paths;
+	void* topo_data;
+};
+
+extern const struct path_list*
+path_list_find(const struct path_list* list, const char* path);
+extern struct path_list*
+path_list_insert(char *item, struct path_list **list_p);
+extern void path_list_print(FILE*, struct path_list* list);
+extern void free_path_list(struct path_list *list);
+extern const char** convert_to_pathspec(struct path_list* l1,
+					struct path_list* l2);
+extern void rev_setup_diffopt_paths(struct rev_info* revs,
+				    struct commit* commit,
+				    struct commit* parent);
+
 #endif

^ permalink raw reply related

* Re: [PATCH] send-email: allow sendmail binary to be used instead of SMTP
From: Junio C Hamano @ 2006-05-15 21:13 UTC (permalink / raw)
  To: Ryan Anderson; +Cc: git
In-Reply-To: <20060515210110.GR32076@h4x0r5.com>

Ryan Anderson <ryan@michonline.com> writes:

> I think, in practice, that /usr/lib/sendmail will exist anywhere you hve
> something running on port 25, at least on unixy machines.  In my
> searches at an old job, that appeared to be the canonical place to call
> sendmail from, and every MTA appears to provide an appropriate binary
> there.
>
> So, I'm not overly worried about it.

exim, postfix and friends?

I used to know somebody who port-forwarded 25/tcp to central
smtp server from smaller machines in her intranet installation,
but I would say that is rare.  I am not worried about it either;
I just wanted to make sure _somebody_ thought the potential
issues through and agreed with the change the patch makes.

^ permalink raw reply

* Re: The git newbie experience
From: Junio C Hamano @ 2006-05-15 21:10 UTC (permalink / raw)
  To: Carl Worth; +Cc: git
In-Reply-To: <877j4nvx2w.wl%cworth@cworth.org>

Carl Worth <cworth@cworth.org> writes:

> In particular, when using checkout to change branches, unless I've
> specifically stated with "-m" that I want to carry my changes along, I
> would like git to stash my working tree "into" the branch I'm
> switching away from.
>
> Similarly, when switching to a branch, I'd like to have the working
> tree restored to what it was the last time I switched away from that
> branch.
>
> Does that seem unreasonable to anyone?

I would not call it unreasonable to want to have an easy access
to that mode of operation _as_ _well_, as an option.

If you were suggesting to make it the only way for future git to
work (I think you are not), then it sounds very unreasonable to
me.

The implementation behind the scene does not matter, but I think 
set of "stashes" that can be attached to each branch would work
well for what you would want.  OTOH, isn't it called stgit?

The reason why I want it to stay as an option is because I often
do a throw-away patch on top of whatever branch is checked out
in my working tree while reading the list traffic to compose a
response with an alternative patch.  Usually I follow that by a
"git reset" once the message is sent out, but when I like the
idea well enough, I do "checkout -b jc/that-topic master" to
switch to a new branch with the dirty state carried along, to
work on it further.  I do not want that workflow to require -m
flag, which means something different (-m means "I accept the
possibility of the three-way merge failing while doing this
switch that needs a merge").  Instead, I want "checkout -b" to
try carrying state forward and stop if it cannot without
file-level merging (i.e. the current behaviour).  Then I can
think if I want to do a stash with "git diff", or if I want to
do the temporary branch not based on "master" but the current
branch (which is guaranteed to work without -m) and deal with
the mess later.

^ permalink raw reply

* Re: [PATCH] send-email: allow sendmail binary to be used instead of SMTP
From: Ryan Anderson @ 2006-05-15 21:01 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Eric Wong, git
In-Reply-To: <7vmzdjtya4.fsf@assigned-by-dhcp.cox.net>

On Mon, May 15, 2006 at 02:47:31AM -0700, Junio C Hamano wrote:
> Eric Wong <normalperson@yhbt.net> writes:
> 
> > I believe this is what Martin wanted.  I think it's a good idea since
> > sendmail binaries tend to be more flexible, but I'm ok with it either
> > way.
> 
> I am not opposed to have an option to run a local submission
> agent binary (I said I like that if(){}else{} there, didn't I?).
> The ability to do so is a good thing.  I am not however sure
> about changing the default when no option is specified on the
> command line.

I think, in practice, that /usr/lib/sendmail will exist anywhere you hve
something running on port 25, at least on unixy machines.  In my
searches at an old job, that appeared to be the canonical place to call
sendmail from, and every MTA appears to provide an appropriate binary
there.

So, I'm not overly worried about it.

^ permalink raw reply

* Re: [PATCH] commit: allow --pretty= args to be abbreviated
From: Junio C Hamano @ 2006-05-15 20:47 UTC (permalink / raw)
  To: Eric Wong; +Cc: git
In-Reply-To: <20060515003405.GA5533@localdomain>

Eric Wong <normalperson@yhbt.net> writes:

> Unlike the original one, this one only does prefix matches, so
> you can't do --pretty=er anymore :)

Sounds good.  But then you know how long the unique prefix
are for each candidate, so wouldn't this rather be redundant, I
wonder?

> +
> +	/* look for abbreviations */
> +	len = strlen(arg);
> +	found = -1;
> +	for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
> +		if (!strncmp(cmt_fmts[i].n, arg, len)) {
> +			if (found >= 0)
> +				die("invalid --pretty format: %s", arg);
> +			found = i;
> +		}
> +	}
> +	if (found >= 0)
> +		return cmt_fmts[found].v;
> +	die("invalid --pretty format: %s", arg);
>  }

It would probably be better to say "ambiguous" not "invalid" in
the die() message.

^ permalink raw reply

* Re: The git newbie experience
From: Junio C Hamano @ 2006-05-15 20:47 UTC (permalink / raw)
  To: Carl Baldwin; +Cc: Tommi Virtanen, Shawn Pearce, git
In-Reply-To: <20060515164610.GA24295@hpsvcnb.fc.hp.com>

Carl Baldwin <cnb@fc.hp.com> writes:

> My implementation actually wrote the working file state into the object
> store as a tree and stored a reference to the tree under something like
> .git/refs/undo (or .git/refs/stash).  Redo was a simple merge of this
> tree back onto the current working files.
>
> I think I would like something like this better than the 'generate
> binary patch and reapply the patch later.

When you think of the "binary patch" as a human readable
representation of your (hierarchical set of) tree objects, you
would realize that these two approaches aren't that much
different at the tree merge level, and it's just a matter of
which representation is more convenient and human readable.

Pros and cons I see are:

 * Branch approach needs to teach users only one thing -- create
   a branch, merge with it, throw it away.  Which is something
   the user needs to know anyway, so it is a plus.

 * Branch approach needs to store a full postimage tree and the
   base commit (so you can use it as a merge base); the
   postimage tree includes paths that are not involved in the
   change being stashed.

 * Patch records only the object names of paths that are relevant
   to the stash.  Instead of keeping the full postimage tree, it
   creates one on the fly when you actually do the unstashing.

 * Patch is human readable and can be used for purposes other
   than falling back to a three-way merge.  When cleanly applies
   apply + write-tree is faster than a tree merge.

 * Patch could be verbose if the change being stashed is large;
   after all the primary information used are the object names
   recorded on the "index" lines and the patch text itself is a
   waste from storage point of view.  This is a disadvantage of
   the "patch" approach, but its readability might offset it.
   If a change being stashed is large, the user had better be
   doing it on a separate topic branch anyway, so this might not
   be a big issue.

^ permalink raw reply

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

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

On Mon, 15 May 2006 01:39:08 -0700, Junio C Hamano wrote:
>  - Jack stashes away what he has been working on and cleans up
>    his mess.
> 
>    git checkout -b stash ;# risks error when "stash" exists
>    git commit -a -m 'Stashing WIP'
>    git checkout master ;# assuming that was where he was

I really like the proposal made elsewhere to implement a new:

	commit -b <newbranch>

which would then allow for a single command to achieve at least the
first two commands above:

	git commit -a -b stash -m 'Stashing WIP'

It might even make sense for this command to effectively perform all
three of the above commands. That is, should "commit -b" also checkout
the newly created branch or should it leave HEAD unchanged. I'm not
sure.

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

I threw out a simple git-stash earlier, (which stashed to a branch
rather than to a file). I've spent some time using it, and am now
quite sure it's the wrong thing, and the above problems outline the
defect quite well:

1) Naming.

   Here, git-stash is doing too much. I prefer the idea of a stash
   command using a branch rather than a patch file, (and allowing one
   stash per branch rather than one stash per repository). But the
   namespace of branches is something the user owns, and we should
   avoid adding commands that steal from it unnecessarily. So my
   git-stash fails on this point, while "commit -b <newbranch>" is
   much better.

2) Cleanup and --no-commit pull

   Here, git-stash is doing too little. It's really only performing
   one piece of what needs to be done in order to switch back and
   forth between different topics of work.

So here are my thoughts on what I'd like instead:

In git, a branch is what we use to name a topic of work.

Historically, a branch has been extremely lightweight, (a name and
reference to a parent for subsequent commits). But there's been a
recent trend (in proposals at least) to add other, useful things to a
branch, (as in the discussions of branch-specific configuration).

In my work, I've found that the uncommitted state of my working tree
is something that I associate very strongly with my "current topic"
and expect the branch-changing commands respected that.

In particular, when using checkout to change branches, unless I've
specifically stated with "-m" that I want to carry my changes along, I
would like git to stash my working tree "into" the branch I'm
switching away from.

Similarly, when switching to a branch, I'd like to have the working
tree restored to what it was the last time I switched away from that
branch.

Does that seem unreasonable to anyone?

The only snag I've imagined is that when using "checkout -m" to switch
to a branch that also had a stashed working tree, then there's a merge
to be performed and that could obviously conflict. I've intentionally
not mentioned how the stashing/restoring should be implemented, since
the user shouldn't care. But a merge conflict is one case where the
implementation might leak out to the user. The wimpy thing to do would
be to refuse to allow "checkout -m" to a branch with stashed changes.

-Carl

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCH] Add "--branches", "--tags" and "--remotes" options to git-rev-parse.
From: Jakub Narebski @ 2006-05-15 20:11 UTC (permalink / raw)
  To: git
In-Reply-To: <BAYC1-PASMTP043948149786B7EE06DED3AEA20@CEZ.ICE>

Sean Estabrooks wrote:

> On Sat, 13 May 2006 10:38:23 -0700
> Junio C Hamano <junkio@cox.net> wrote:
> 
>> Makes sense perhaps.
>> 
>> I understand you added --tags for completeness.  Probably it
>> would make sense to add --remotes if you are shooting for that.
[...]

> +--remotes::
> +     Show tag refs found in `$GIT_DIR/refs/remotes`.
> +

In `Documentation/repository-layout.txt' there is information about
`$GIT_DIR/remotes' not `$GIT_DIR/refs/remotes` so either the patch should
be amended, or the layout documentation should be updated, or the layout
repository should be changed.

-- 
Jakub Narebski
Warsaw, Poland

^ permalink raw reply

* RE: how to display file history?
From: Brown, Len @ 2006-05-15 19:04 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Junio C Hamano, git

 
>> >	git log --stat -- A
>> 
>> very handy indeed.
>> 
>> I was surprised on initial use that --stat is
>> limited to the file specified in "A" and doesn't
>> expand to describe the entire commit that touches "A".
>> (ie. the stat output is a subset of what is associated
>> with the displayed commit comments).
>> 
>> This, of course, is clear now, it just isn't what
>> I expected on first use.
>
>Well,  you can obviously have your cake and eat it too (ie 
>"--full-diff").
>
>I don't often end up using the "--full-diff" thing. It's almost never 
>actually worth it until I find the diff that I actually start caring 
>about, and the full diff just makes it harder to see the part 
>I explicitly told git I was interested in.

sounds good.

>So the default "show only diffs for the files asked for" 
>behaviour is in my opinion much superior (and it used to be the only
one),
>because the "show the whole thing" part ends up being something you use
only once 
>you've already skimmed the default case and decide to go deeper.

I agree.

>Of course, "gitk" ends up using the full diff by default in its diff 
>window. I'm not convinced that's the right thing, but usually 
>when I use gitk I'm primarily looking at the history and the commit
>messages to decide if it's a relevant one, not the diff, so I don't
think 
>it matters.

Yeah, I agree that gitk is fine how it is.

The only part I don't agree with above is the word "obviously".
'--full-diff --stats' didn't jump out at me from the man page.

To be fair, yes, I should probably take the time to read the docs
through
and not rely on the man pages, they've changed a lot since I last
looked.

-Len

^ permalink raw reply

* Re: [PATCH] send-email: allow sendmail binary to be used instead of SMTP
From: Eric Wong @ 2006-05-15 19:10 UTC (permalink / raw)
  To: Martin Langhoff; +Cc: Junio C Hamano, git
In-Reply-To: <46a038f90605150337l3357ce3by22834823eee7b87c@mail.gmail.com>

Martin Langhoff <martin.langhoff@gmail.com> wrote:
> Thanks Eric! git-send-email used to default to using local binaries.
> It was only with the switch to Net::SMTP that the default changed to
> localhost:25.

You're welcome.

That's odd, though, looking at Mail::Sendmail, I don't think it actually
uses the sendmail binary, either.  The FAQ
<http://alma.ch/perl/Mail-Sendmail-FAQ.html> confirms this, too.

Of course documentation may be lying and the code I'm looking at may be
*very* well obfuscated :D

-- 
Eric Wong

^ permalink raw reply

* Re: how to display file history?
From: Linus Torvalds @ 2006-05-15 18:51 UTC (permalink / raw)
  To: Marco Costalba; +Cc: Eric W. Biederman, Junio C Hamano, Brown, Len, git
In-Reply-To: <e5bfff550605151132s4605a241sd3132aaeb2de6a39@mail.gmail.com>



On Mon, 15 May 2006, Marco Costalba wrote:
> 
> $ git-rev-list --topo-order --after="Apr 10" --before="Apr 11" HEAD |wc
>     14      14     574
> $ git-rev-list --topo-order --boundary --after="Apr 10" --before="Apr
> 11" HEAD |wc
>     18      18     742
> 
> Boundary revisions in this case are _not_ passed through search
> filtering. Using --boundary option we get revisions ouside given
> filter range.

Right. And the commit counting is a special filter, and "boundary" is 
special in that it doesn't normally honor some other filters (it _does_ 
honor path-based ones, though, I think).

So you really should see "--boundary" as a heuristic, and as a hack to 
help you close the loop on uninteresting commits _faster_. But if 
something else has closed it for other reasons, you shouldn't depend on 
it.

		Linus

^ permalink raw reply

* Re: how to display file history?
From: Marco Costalba @ 2006-05-15 18:32 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Eric W. Biederman, Junio C Hamano, Brown, Len, git
In-Reply-To: <Pine.LNX.4.64.0605151055080.3866@g5.osdl.org>

On 5/15/06, Linus Torvalds <torvalds@osdl.org> wrote:
>
>
> qgit would seem to prefer to have the commit counting only affect the
> "primary" commits, and not the "boundary" ones at all. Which might be
> sensible, but it's not the semantics it has now.
>
> gitk doesn't care, because it uses the boundary commits just as hints.
>

$ git-rev-list --topo-order --after="Apr 10" --before="Apr 11" HEAD |wc
     14      14     574
$ git-rev-list --topo-order --boundary --after="Apr 10" --before="Apr
11" HEAD |wc
     18      18     742

Boundary revisions in this case are _not_ passed through search
filtering. Using --boundary option we get revisions ouside given
filter range.

This does not apply to our previous example. So at least --boundary
behaviour it's a little bit inconsistent at the moment.

        Marco

^ permalink raw reply

* gateway status?
From: David Lang @ 2006-05-15 18:26 UTC (permalink / raw)
  To: git

I seem to remember seeing discussion of gateways to cvs/svn that would let 
a project use a git repository and allow clients to use cvs/svn clients to 
retreive data.

am I remembering correctly, and are these tools ready for production use? 
the popfile project is getting ready to abandon sourceforge and move to 
self-hosting, but before I suggest that they use git I need to know the 
current status of these projects (I think the ability to export directly 
into the other interfaces is a significant advantage)

David Lang

-- 
There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies.
  -- C.A.R. Hoare

^ permalink raw reply

* Re: how to display file history?
From: Linus Torvalds @ 2006-05-15 18:03 UTC (permalink / raw)
  To: Marco Costalba; +Cc: Eric W. Biederman, Junio C Hamano, Brown, Len, git
In-Reply-To: <e5bfff550605151022m7b9ddcd9y53cd745e16ff6b22@mail.gmail.com>



On Mon, 15 May 2006, Marco Costalba wrote:
> 
> Well, it works but the nice boundary circles are not shown, and qgit
> always adds  --boundary to command line args to feed git-rev-list, but
> in this case it seems the --boundary option didn't do his job.

Well, it did do it's job, but you expected different counting priorities 
than git-rev-list actually gives you.

For the "limit by number" case, the commit counting counts _both_ 
"primary" commits and "boundary" commits, and will limit the total output 
to the number specified.

qgit would seem to prefer to have the commit counting only affect the 
"primary" commits, and not the "boundary" ones at all. Which might be 
sensible, but it's not the semantics it has now.

gitk doesn't care, because it uses the boundary commits just as hints.

I _think_ gitk is correct here, and qgit is being too strict in its 
semantic understanding of what the boundary commits mean. But I think so 
mostly because it would actually be pretty hard to do otherwise (ie the 
git-rev-list commit counting is largely defined by it's _implementation_, 
not necessarily by what you want it to do ;)

		Linus

^ permalink raw reply

* Re: how to display file history?
From: J. Bruce Fields @ 2006-05-15 17:55 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Linus Torvalds, Junio C Hamano, Brown, Len, git
In-Reply-To: <m164k76ylb.fsf@ebiederm.dsl.xmission.com>

On Mon, May 15, 2006 at 10:29:20AM -0600, Eric W. Biederman wrote:
> Sure.  If it gets included in a tutorial is great, but existing
> users aren't likely to read through a tutorial if they think they
> know what is going on.
> 
> Having it documented in the man pages (i.e. the reference
> documentation) which is where people look to check up on the fine
> points of a command is more likely to matter.

Looks like the current git-log man page refers you to the git-rev-list
page for that, and the use of path names is documented there.

I think that's a pretty reasonable approach for reference
documentation, which should be concise.  Duplicating the git-rev-list
documentation (even some of it) to every man page to which it's relevant
would add a lot of text.

The current git-log man page is misleading, though--it suggests that
git-log accepts (and git-rev-list documents) only options, which might
discourage a reader from tracking down information about non-option
arguments.

I also agree about the tutorial--the "Keeping track of history" section
would be a good place to introduce this and git-grep with some fun
examples.  It's on my todo list, but may take a while, so maybe someone
else can beat me to it....

--b.

^ permalink raw reply

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



On Mon, 15 May 2006, Brown, Len wrote:
>
> >	git log --stat -- A
> 
> very handy indeed.
> 
> I was surprised on initial use that --stat is
> limited to the file specified in "A" and doesn't
> expand to describe the entire commit that touches "A".
> (ie. the stat output is a subset of what is associated
> with the displayed commit comments).
> 
> This, of course, is clear now, it just isn't what
> I expected on first use.

Well,  you can obviously have your cake and eat it too (ie "--full-diff").

I don't often end up using the "--full-diff" thing. It's almost never 
actually worth it until I find the diff that I actually start caring 
about, and the full diff just makes it harder to see the part I explicitly 
told git I was interested in.

So the default "show only diffs for the files asked for" behaviour is in 
my opinion much superior (and it used to be the only one), because the 
"show the whole thing" part ends up being something you use only once 
you've already skimmed the default case and decide to go deeper.

Of course, "gitk" ends up using the full diff by default in its diff 
window. I'm not convinced that's the right thing, but usually when I use 
gitk I'm primarily looking at the history and the commit messages to 
decide if it's a relevant one, not the diff, so I don't think it matters.

			Linus

^ permalink raw reply

* [PATCH] pack-object: slightly more efficient
From: Nicolas Pitre @ 2006-05-15 17:47 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Avoid creating a delta index for objects with maximum depth since they 
are not going to be used as delta base anyway.  This also reduce peak 
memory usage slightly as the current object's delta index is not useful 
until the next object in the loop is considered for deltification. This 
saves a bit more than 1% on CPU usage.

Signed-off-by: Nicolas Pitre <nico@cam.org>

---

diff --git a/delta.h b/delta.h
index 727ae30..7b3f86d 100644
--- a/delta.h
+++ b/delta.h
@@ -18,6 +18,8 @@ create_delta_index(const void *buf, unsi
 
 /*
  * free_delta_index: free the index created by create_delta_index()
+ *
+ * Given pointer must be what create_delta_index() returned, or NULL.
  */
 extern void free_delta_index(struct delta_index *index);
 
diff --git a/pack-objects.c b/pack-objects.c
index b0388d7..9daf1c1 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -1104,17 +1104,14 @@ static void find_deltas(struct object_en
 
 		if (entry->size < 50)
 			continue;
-		if (n->index)
-			free_delta_index(n->index);
+		free_delta_index(n->index);
+		n->index = NULL;
 		free(n->data);
 		n->entry = entry;
 		n->data = read_sha1_file(entry->sha1, type, &size);
 		if (size != entry->size)
 			die("object %s inconsistent object length (%lu vs %lu)",
 			    sha1_to_hex(entry->sha1), size, entry->size);
-		n->index = create_delta_index(n->data, size);
-		if (!n->index)
-			die("out of memory");
 
 		j = window;
 		while (--j > 0) {
@@ -1134,6 +1131,11 @@ static void find_deltas(struct object_en
 		 */
 		if (entry->delta && depth <= entry->depth)
 			continue;
+
+		n->index = create_delta_index(n->data, size);
+		if (!n->index)
+			die("out of memory");
+
 		idx++;
 		if (idx >= window)
 			idx = 0;
@@ -1143,8 +1145,7 @@ static void find_deltas(struct object_en
 		fputc('\n', stderr);
 
 	for (i = 0; i < window; ++i) {
-		if (array[i].index)
-			free_delta_index(array[i].index);
+		free_delta_index(array[i].index);
 		free(array[i].data);
 	}
 	free(array);

^ permalink raw reply related

* RE: how to display file history?
From: Brown, Len @ 2006-05-15 17:24 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

>	git log --stat -- A

very handy indeed.

I was surprised on initial use that --stat is
limited to the file specified in "A" and doesn't
expand to describe the entire commit that touches "A".
(ie. the stat output is a subset of what is associated
with the displayed commit comments).

This, of course, is clear now, it just isn't what
I expected on first use.

thanks,
-Len

^ permalink raw reply

* git lines of code
From: Marco Costalba @ 2006-05-15 17:33 UTC (permalink / raw)
  To: git

I have run a code lines counter utility on today git tree.

Detailed results are here:
http://digilander.libero.it/mcostalba/git_loc.htm

Summary is git have almost 57.000 lines of code (no blank lines, no
comments), not bad for a stupid content tracker. :-)

    Marco

^ permalink raw reply

* Re: how to display file history?
From: Marco Costalba @ 2006-05-15 17:22 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Eric W. Biederman, Junio C Hamano, Brown, Len, git
In-Reply-To: <Pine.LNX.4.64.0605150900510.3866@g5.osdl.org>

>
> So
>
>         gitk --all --since=1.month -15 -- t/
>
> will show at most fifteen commits from _any_ branch that changed the
> test subdirectory in the last month.
>
> And yeah, maybe that isn't a very interesting query, but it's easy to
> explain and understand, so it's worth explaining early.
>
> And it should be equally obvious to everybody that if it works for "gitk",
> that means that it works for "qgit", "git log" and "git whatchanged" too,

For qgit it doesn't work :-)

Well, it works but the nice boundary circles are not shown, and qgit
always adds  --boundary to command line args to feed git-rev-list, but
in this case it seems the --boundary option didn't do his job.

$git-rev-list --topo-order --boundary --parents --all --since=1.month -15 -- t/
ea892b27b15fbc46a3bb3ad2ddce737dc6590ae5
b0121fb3f279a9cf13aff9da060e742aef3a83fa
8d48ad62a902556b523ee892a3fbe4206d576d3f
8d48ad62a902556b523ee892a3fbe4206d576d3f
2c49009dbe98a26505891d3c680da73baf0b4f81
d14f776402d9f7040cc71ff6e3b992b2e019526a
b0121fb3f279a9cf13aff9da060e742aef3a83fa
7f498065e9bf85f6f3e954ec57dedf56fec29e01
6bd20358a9b831b3b545284188871bc844245c25
6bd20358a9b831b3b545284188871bc844245c25
9af0b8dbe2fb252262412a11254e2bcc6ffb87bb
7f498065e9bf85f6f3e954ec57dedf56fec29e01
c2b9e6994d044b218e59abf6d19f7751c4aa13e3
dd05ea1799656024a45017238bbd4857b5256370
c2b9e6994d044b218e59abf6d19f7751c4aa13e3
aadc81c13bbb103e7db759ba9a98a6f9509831f1
bd886fd3ea49b726493255d4adf5d20b31681713
aadc81c13bbb103e7db759ba9a98a6f9509831f1
42d0ee8302c361a0e3bde7bc59858eda94bc13a4
22293b9c41778bb60f3b07355e1b8e421a503702
2c49009dbe98a26505891d3c680da73baf0b4f81
143f4d94c6e2188a6bedfdfa268e66b579e3fbf9
dd05ea1799656024a45017238bbd4857b5256370
dd05ea1799656024a45017238bbd4857b5256370
fd60acaced6de16ebfb66959067e2b29f99a133e
143f4d94c6e2188a6bedfdfa268e66b579e3fbf9
2fc240a7b21c060529c1d2e19d6b483361f81f2a
22293b9c41778bb60f3b07355e1b8e421a503702
22293b9c41778bb60f3b07355e1b8e421a503702
83e77a25dc194933c0fb7908ab6d9fb84a5045e2
83e77a25dc194933c0fb7908ab6d9fb84a5045e2
2fa9a0fb31cbf01e8318a02c3e222d7fd3fd0a83
2fc240a7b21c060529c1d2e19d6b483361f81f2a
fd60acaced6de16ebfb66959067e2b29f99a133e
42d0ee8302c361a0e3bde7bc59858eda94bc13a4
42d0ee8302c361a0e3bde7bc59858eda94bc13a4
2fa9a0fb31cbf01e8318a02c3e222d7fd3fd0a83
fd60acaced6de16ebfb66959067e2b29f99a133e
bd886fd3ea49b726493255d4adf5d20b31681713
cf9dc65368113caa28f2829e2ada5477fbb031ec


       Marco

^ permalink raw reply

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

Junio,

This seems a lot like what I tried to do with git-undo/git-redo quite a
while back.

My implementation actually wrote the working file state into the object
store as a tree and stored a reference to the tree under something like
.git/refs/undo (or .git/refs/stash).  Redo was a simple merge of this
tree back onto the current working files.

I think I would like something like this better than the 'generate
binary patch and reapply the patch later.

If these commands were added to git I think they would be better if the
commands chose a temporary branch name, committed the current state to
that branch and did everything else that someone more experienced would
do using branches having chosen a temporary branch name.

The redo or unstash operation could just pick the most recent tempory
branch name (top of stack) and merge changes into the working copy.

Carl

On Mon, May 15, 2006 at 01:39:08AM -0700, Junio C Hamano wrote:
> Shawn Pearce <spearce@spearce.org> writes:
> 
> >> I'd rather do that with a diff file that can be used to do a
> >> 3-way (see how rebase does it with --full-index diff with am -3).
> >> No point creating and forgetting to remove a throw away branch
> >> and getting more complaints.
> >
> > How is a quick stash different from a topic branch?
> 
> The original version of my message in response to TV looked like
> this.
> 
>  - Jack is a beginning user of git and does not (want to) understand
>    the index (right now).
> 
>  - Jack works on branch X, say his HEAD points to X1. He has an edited,
>    uncommitted files with the names A, B and C.
> 
>  - Jack wants to pull new changes made by others to his branch.
>    But "git merge" invoked from "git pull" says he needs to stash
>    away the local changes to do the merge.
> 
>  - Jack stashes away what he has been working on and cleans up
>    his mess.
> 
>    git checkout -b stash ;# risks error when "stash" exists
>    git commit -a -m 'Stashing WIP'
>    git checkout master ;# assuming that was where he was
> 
>  - Jack then pulls.  There are merge conflicts in files D, E, ..., Z.
> 
>  - Jack resolves the merge conflicts and is ready to commit the resulting
>    merge. Note files A, B and C do not have his unfinished work.
> 
>    There is no "if Jack does this or that" problem; he says "git
>    commit -a" because that is the only "commit" command he knows
>    about.
> 
>  - Jack then reapplies what he stashed away, and keeps working.
> 
>    git pull . --no-commit stash
>    git branch -D stash
> 
> You have to teach the new user to (1) name something, only to
> immediately discard it when he returns to what he was in the
> middle of, (2) remember to clean up the temporary thing once he
> is done lest he forgets to clean it up (and common names like
> "stash", "tmp" will be reused by accident causing grief next
> time he needs to do another stash), and (3) use of --no-commit
> pull.
> 
> On the other hand, "git stash/unstash" workflow would be quite
> simple:
> 
> 	$ git stash >my.precious.state
>         ... do whatever you want to deviate to
>         $ git unstash <my.precious.state
> 
> Merge resolve might be needed while unstashing, but 
> we are talking about pulling somebody else's work in "do
> whatever" part, so that is something the user knows how to
> perform anyway.
> 
> A quick and dirty stash implementation would go like this:
> 
> Stash is easy.
> 
>         #!/bin/sh
>         # git stash
>         git diff --binary HEAD
>         git reset --hard
> 
> Unstash is a bit involved.
> 
>         #!/bin/sh
>         # git unstash
>         . git-sh-setup
>         O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
>         O_DIR=`cd "$GIT_DIR" && pwd`
>         stash="$O_DIR/.stash$$"
>         rm -fr "$stash.*"
>         trap 'rm -rf $stash.*' 0
>         cat >"$stash.patch"
>         git-apply -z --index-info <"$stash.patch" >"$stash.list"
>         GIT_INDEX_FILE="$stash.index"  \
>         GIT_OBJECT_DIRECTORY="$O_OBJECT" \
>         (
>                 mkdir -p "$stash.tmp" &&
>                 git-update-index -z --index-info <"$stash.list" &&
>                 git-write-tree >"$stash.base" &&
>                 cd "$stash.tmp" &&
>                 git-apply --binary --index <"$stash.patch" &&
>                 git-write-tree >"$stash.his"
>         )
>         his_tree=$(cat "$stash.his")
>         orig_tree=$(cat "$stash.base")
>         rm -fr "$stash.*"
>         git-merge-resolve $orig_tree -- HEAD $his_tree
> 
> This is essentially the core of "am -3" logic; if you are going
> to use this for real, you would probably want to see if the
> patch applies cleanly before falling back on the three-way
> merge, though.
> 
> 
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

-- 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Carl Baldwin                        RADCAD (R&D CAD)
 Hewlett Packard Company
 MS 88                               work: 970 898-1523
 3404 E. Harmony Rd.                 work: Carl.N.Baldwin@hp.com
 Fort Collins, CO 80525              home: Carl@ecBaldwin.net
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

^ permalink raw reply

* Re: how to display file history?
From: Linus Torvalds @ 2006-05-15 16:45 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Junio C Hamano, Brown, Len, git
In-Reply-To: <m164k76ylb.fsf@ebiederm.dsl.xmission.com>



On Mon, 15 May 2006, Eric W. Biederman wrote:
>
> Having it documented in the man pages (i.e. the reference
> documentation) which is where people look to check up on the fine
> points of a command is more likely to matter.

Somehow I really doubt that.

Check out the current man-page for "git log" or "git whatchanged".

In particular, check the "examples" section.

Yes, it's right there. And no, people apparently don't read the man-pages.

		Linus

^ permalink raw reply

* Re: how to display file history?
From: Eric W. Biederman @ 2006-05-15 16:29 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Junio C Hamano, Brown, Len, git
In-Reply-To: <Pine.LNX.4.64.0605150900510.3866@g5.osdl.org>

Linus Torvalds <torvalds@osdl.org> writes:

> On Mon, 15 May 2006, Eric W. Biederman wrote:
>> 
>> So that it has a chance of being remembered, and eventually fixed
>> the man pages of git-whatchanged and git-log only sort of tell you
>> that this is even possible.
>
> I don't think this is a man-page issue. I think this is a very basic 
> tutorial issue. 
>
> People still don't seem to realize how flexible (and powerful) the git 
> revision specifications are. It's not just limiting by path, all of these 
> work on _all_ of the "history tools" (whether they be gitk, qgit, "git 
> log", "git whatchanged" or your own home-cooked stuff):
>
>  - "revision based limiting"
>
> 	"a..b", but also "a ^b ^c ^d" or "a --not b c d" for the more 
> 	complex case where you're interested in one (or more) commit, but 
> 	not anything that flows from any of a number of other commits.
>
> 	"--all".
>
>  - "commit date based limiting"
>
> 	"--since=2.weeks.ago" "--since=aug.5th"
>
>  - "limit by number of hits"
>
> 	"-15"
>
>  - "limit by type or state"
>
> 	"--no-merges" and "--unpacked"
>
> And finally
>
>  - "limit by pathname"
>
> and you can combine all of these.
>
> So
>
> 	gitk --all --since=1.month -15 -- t/
>
> will show at most fifteen commits from _any_ branch that changed the 
> test subdirectory in the last month.
>
> And yeah, maybe that isn't a very interesting query, but it's easy to 
> explain and understand, so it's worth explaining early.
>
> And it should be equally obvious to everybody that if it works for "gitk", 
> that means that it works for "qgit", "git log" and "git whatchanged" too, 
> ie this is a very core concept, and not just some tacked-on thing for one 
> special tool.

Sure.  If it gets included in a tutorial is great, but existing
users aren't likely to read through a tutorial if they think they
know what is going on.

Having it documented in the man pages (i.e. the reference
documentation) which is where people look to check up on the fine
points of a command is more likely to matter.  Plus it doesn't
take any creativity to write a man page you just need to describe
what is, which makes man-pages easier to write than documentation
where you aren't certain of who your audience is.

Since it isn't specific to one command we probably need to document
the query limiting in a single file like the diff options are
and then just included it in all of the different man pages.

But regardless of where we put it, it needs to be documented someplace
besides in the email so you don't need to read the code to see that
the option is there. 

Eric

^ permalink raw reply

* Re: [PATCH] send-email: allow sendmail binary to be used instead of SMTP
From: Junio C Hamano @ 2006-05-15 16:25 UTC (permalink / raw)
  To: Martin Langhoff; +Cc: Eric Wong, Junio C Hamano, git
In-Reply-To: <46a038f90605150337l3357ce3by22834823eee7b87c@mail.gmail.com>

"Martin Langhoff" <martin.langhoff@gmail.com> writes:

> On 5/15/06, Eric Wong <normalperson@yhbt.net> wrote:
>> Junio C Hamano <junkio@cox.net> wrote:
>> > I am not opposed to have an option to run a local submission
>> > agent binary (I said I like that if(){}else{} there, didn't I?).
>> > The ability to do so is a good thing.  I am not however sure
>> > about changing the default when no option is specified on the
>> > command line.
>>
>> By "I believe this is what Martin wanted", I meant changing the default to
>> sendmail: <46a038f90604271804j195d62f3x93ae816e809f4ffd@mail.gmail.com>
>>
>>         > Oh, it should just work with sendmail if it's there and we don't
>
> Thanks Eric! git-send-email used to default to using local binaries.
> It was only with the switch to Net::SMTP that the default changed to
> localhost:25.

Thanks, and I think it makes sense.

^ permalink raw reply

* Re: how to display file history?
From: Linus Torvalds @ 2006-05-15 16:15 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Junio C Hamano, Brown, Len, git
In-Reply-To: <m1ejyv7077.fsf@ebiederm.dsl.xmission.com>



On Mon, 15 May 2006, Eric W. Biederman wrote:
> 
> So that it has a chance of being remembered, and eventually fixed
> the man pages of git-whatchanged and git-log only sort of tell you
> that this is even possible.

I don't think this is a man-page issue. I think this is a very basic 
tutorial issue. 

People still don't seem to realize how flexible (and powerful) the git 
revision specifications are. It's not just limiting by path, all of these 
work on _all_ of the "history tools" (whether they be gitk, qgit, "git 
log", "git whatchanged" or your own home-cooked stuff):

 - "revision based limiting"

	"a..b", but also "a ^b ^c ^d" or "a --not b c d" for the more 
	complex case where you're interested in one (or more) commit, but 
	not anything that flows from any of a number of other commits.

	"--all".

 - "commit date based limiting"

	"--since=2.weeks.ago" "--since=aug.5th"

 - "limit by number of hits"

	"-15"

 - "limit by type or state"

	"--no-merges" and "--unpacked"

And finally

 - "limit by pathname"

and you can combine all of these.

So

	gitk --all --since=1.month -15 -- t/

will show at most fifteen commits from _any_ branch that changed the 
test subdirectory in the last month.

And yeah, maybe that isn't a very interesting query, but it's easy to 
explain and understand, so it's worth explaining early.

And it should be equally obvious to everybody that if it works for "gitk", 
that means that it works for "qgit", "git log" and "git whatchanged" too, 
ie this is a very core concept, and not just some tacked-on thing for one 
special tool.

			Linus

^ 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