Git development
 help / color / mirror / Atom feed
* Re: Multi-head pulling series
From: Junio C Hamano @ 2005-08-20 18:54 UTC (permalink / raw)
  To: Josef Weidendorfer; +Cc: git
In-Reply-To: <200508181245.58250.Josef.Weidendorfer@gmx.de>

Josef Weidendorfer <Josef.Weidendorfer@gmx.de> writes:

>> 	$ cat $GIT_DIR/remotes/www
>> 	URL: http://www.kernel.org/pub/scm/git/git.git/
>>	Pull: master:ko-master pu:ko-pu
>>	Push: master:master pu:pu foo:bar
>
> Isn't this mixing two kinds of information:
> 1) Some default/persistent mapping of local to remote heads
> 2) The default heads which are pulled/pushed when only giving the remote

I am not convinced myself that default/persistent mapping makes
much sense, and updating the stored mappings dynamically when
the user uses non-default mappings in push/pull as a one-shot
operation does not make any sense at all at least to me.  You
should rather consider that the current specification does not
deal with (1) at all.  The set of default pull/push refs does
not make much sense without mappings for them, so that is what
the file records.

^ permalink raw reply

* Re: gitweb "tag" display
From: Junio C Hamano @ 2005-08-20 19:09 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: git
In-Reply-To: <17158.27011.7426.577686@cargo.ozlabs.ibm.com>

Paul Mackerras <paulus@samba.org> writes:

> I did something a little easier - if you click on the tag, it now
> displays the contents of the tag in the details pane.  Is that good
> enough?

Looks very nice, and a lot more sensible than those unsolicited
popups I hate very much.

> I implemented these two.  There is now a "Reread references" button in
> the File menu.  References other than tags and heads get displayed in
> a light blue box.

Wonderful.

> Hmmm... now I suppose we want a way to use gitk to drive the git
> bisection process... :)

Yes!  That was the direction I was implying.

^ permalink raw reply

* Re: [RFC] Stgit - patch history / add extra parents
From: Catalin Marinas @ 2005-08-20 21:12 UTC (permalink / raw)
  To: Jan Veldeman; +Cc: git
In-Reply-To: <20050819194832.GA8562@fanta>

On Fri, 2005-08-19 at 21:48 +0200, Jan Veldeman wrote:
> I've quickly reread the threads about stg commit. Am I right to assume that
> _all_ history was being recorded? Because this is not what I want. The
> person controlling the archive should specify when to record the history.

True, I was talking about the full history, but I don't find the idea
much different. There was another mail on this issue -
http://article.gmane.org/gmane.comp.version-control.git/5191

> So for example, you only tag (freeze) the history when exporting the
> patches.  When an error is being reported on that version, it's easy to view
> it and also view the progress that was already been made on those patches.

I agree that it is a useful feature to be able to individually tag the
patches. The problem is how to do this best. Your approach looks to me
like it's not following the GIT DAG structure recommendation. Maybe the
GIT designers could further comment on this but a commit object with
multiple parents should be a result of a merge operation. A commit with
a single parent should represent a transition of the tree from one state
to another. With the freeze command you proposed, a commit with multiple
parents is no longer a result of a merge operation, but just a
convenience for tracking the patch history with gitk.

I tried your patch and test script but, if you try to reorder the
patches, the DAG structure become quite hard to understand and that's
only for a small set of frozen states.

I think the best approach would be to keep a list of tags for each
patch. They won't be browsable with gitk but the DAG structure would be
clean. We might get another tool like gquilt to be able to show all the
saved states of a patch.

Sorry for not including your patch but, while I agree with the general
idea of frozen patch states, I disagree with its implementation.

-- 
Catalin

^ permalink raw reply

* Re: [patch] possible memory leak in diff.c::diff_free_filepair()
From: Yasushi SHOJI @ 2005-08-21  7:14 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7v3bpapkmr.fsf@assigned-by-dhcp.cox.net>

At Mon, 15 Aug 2005 21:32:12 -0700,
Junio C Hamano wrote:
> 
> Yasushi SHOJI <yashi@atmark-techno.com> writes:
> 
> > parepare_temp_file() and diff_populate_filespec() has a lot in
> > similarity. so it'd be nice to refactor some. and re-introduce
> > diff_free_filespec_data() and call right after prep_temp_blob() in
> > prepare_temp_file().
> 
> Another thing that may (or may not) help would be to move that
> prepare_temp_file() and stuff to happen in the forked child
> process instead of the parent, so that we do not have to worry
> about freeing the buffer; it has been some time since I worked
> on that part of the code so this may not be an option to make
> things easier.

well, I couldn't figure out how to do it in child.  because the parent
need to know temp files in order to delete after child used it.

anyway, here is a patch to fix the problem in the simplest way.

regards,
--
          yashi

-----------
Make diff_flush a bit more system friendly.

This seems to be the simplest way to fix the peak time
high memory usage in diff_flush.  Don't wait all iteration
to free each filepair.

Signed-off-by: Yasushi SHOJI <yashi@atmark-techno.com>


---

 diff.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

e0f7f97ddc29a9172c2f6c1221eca936aa80835c
diff --git a/diff.c b/diff.c
--- a/diff.c
+++ b/diff.c
@@ -1010,9 +1010,8 @@ void diff_flush(int diff_output_style, i
 			diff_flush_name(p, line_termination);
 			break;
 		}
-	}
-	for (i = 0; i < q->nr; i++)
 		diff_free_filepair(q->queue[i]);
+	}
 	free(q->queue);
 	q->queue = NULL;
 	q->nr = q->alloc = 0;

^ permalink raw reply

* cg-update question.
From: Johnny Stenback @ 2005-08-21  7:17 UTC (permalink / raw)
  To: git

Hi all,

I hope it's ok to ask cogito questions on this list...

I just realized that if I've got an uncommitted local change in a tree 
and I update my tree with cg-update to merge in changes from a different 
tree... cg-update will pull the changes and do the merge. So that's all 
cool, but as it does the merge, it will re-write my local file that has 
the uncommitted change, even if that file didn't change in the 
repository I pulled from, i.e. nothing to merge for that file.

This is, to me at least, not the desired behavior, if there's no reason 
for cg-update to touch a file it shouldn't.

Thoughts? If someone points me in the right direction I'm willing to 
take a stab at fixing this myself...

-- 
jst

^ permalink raw reply

* [ANNOUNCE] Stacked GIT 0.6
From: Catalin Marinas @ 2005-08-21  8:12 UTC (permalink / raw)
  To: GIT

Stacked GIT 0.6 release is available from http://www.procode.org/stgit/

StGIT is a Python application providing similar functionality to Quilt
(i.e. pushing/popping patches to/from a stack) on top of GIT. These
operations are performed using GIT commands and the patches are stored
as GIT commit objects, allowing easy merging of the StGIT patches into
other repositories using standard GIT functionality.

A wiki page hosting the StGIT documentation is available at
http://wiki.procode.org/cgi-bin/wiki.cgi/StGIT. It only has a short
tutorial but please feel free to improve this page.

What's new in this release (the full ChangeLog is in the archive):

      * StGIT can now be installed in other directory than /usr (the
        default prefix is now $HOME). The '/etc/stgitrc' file is no
        longer installed since the defaults are hard-coded in StGIT
      * 'clone' command implemented
      * 'fold' command implemented. This command integrates a GNU diff
        patch into the current patch. It can also do a three-way merge
      * '--edit' option for 'import'. This option allows one to modify
        the patch description during the import operation
      * The '%(number)s' variable added to the e-mail templates which
        expands to ' number/total' if total > 1 or empty if total is 1
      * The README file is almost empty since the documentation moved to
        the web
      * Bug fixes

-- 
Catalin

^ permalink raw reply

* [ANNOUNCE] qgit-0.93
From: Marco Costalba @ 2005-08-21  8:39 UTC (permalink / raw)
  To: git

Hi all,

On SF there is an update of qgit, a git GUI viewer (and lately also 
committer and patch exchanger ;-) )

	http://prdownloads.sourceforge.net/qgit/qgit-0.93.tar.bz2?download


This time I have added the interfaces to import and export patches by 
git-format-patch-script and git-applymbox.

As a side effect it is now possible to drag and drop a set of 
selected revisions between two instances of qgit (there is also the 
new menu entry 'open in a new window';-) )

Other updates include complete recursive search of refs under .git/refs/ and 
highlight according to type: current branch(HEAD), branch, tag, other.

And new is also graft support, thanks to Linus hint of --parents flag in git-rev-list 

Under the hood a reworked and much more powerful error handling and reporting 
code and a better commit.

As usual the shop is open for suggestions/requests and bug reports.


Marco



Complete ChangeLog from last announced release:

21/8/2005 qgit-0.93

- added drag and drop of selected revs between qgit instances: using  
  git-format-patch in dragging archive and git-applymbox in dropping 
  archive to transfer the revisions patches.
  Instances can be open with menu->file->'open in a new window' or simply 
  from the shell.

- added GUI interface to git-applymbox to import patches

- added refs highlight, now any reference found recursively under .git/refs/
  is highlighted according to its type: current branch(HEAD), branch, tag, other.

- added graft support using --parents flag in git-rev-list

- added custom options setting for commit dialog (interface to git-commit-script)

- added --signoff option to patch format

- reworked error reporting infrastructure, now much more powerful
  and informative in case of git command execution failure

- various small bug fixes and GUI tweaks


>From qgit-0.92
- fix a bad crash when running qgit --all on archives with
  branches.

- added 'Make Tag' menu entry

- a compile fix for Debian users, reported by Martin Langhoff

- various small tweaks to GUI

>From qgit-0.91
- fix a build problem on some platform, spotted and
  fixed by Bernhard Schiffner.

- added line and col number in commit viewer


__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 

^ permalink raw reply

* Re: [RFC] Stgit - patch history / add extra parents
From: Jan Veldeman @ 2005-08-21  9:40 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: git
In-Reply-To: <1124572356.7512.21.camel@localhost.localdomain>

Catalin Marinas wrote:

> > So for example, you only tag (freeze) the history when exporting the
> > patches.  When an error is being reported on that version, it's easy to view
> > it and also view the progress that was already been made on those patches.
> 
> I agree that it is a useful feature to be able to individually tag the
> patches. The problem is how to do this best. Your approach looks to me
> like it's not following the GIT DAG structure recommendation. Maybe the
> GIT designers could further comment on this but a commit object with
> multiple parents should be a result of a merge operation. A commit with
> a single parent should represent a transition of the tree from one state
> to another. With the freeze command you proposed, a commit with multiple
> parents is no longer a result of a merge operation, but just a
> convenience for tracking the patch history with gitk.

My interpretation of parents is broader than only merges, and reading the
README file, I believe it also the intension to do so (snippet from README
file):

A "commit" object ties such directory hierarchies together into
a DAG of revisions - each "commit" is associated with exactly one tree
(the directory hierarchy at the time of the commit). In addition, a
"commit" refers to one or more "parent" commit objects that describe the
history of how we arrived at that directory hierarchy.


Another advantage of this approach is when pushing the top of your
repository to others, less rebasing would be noticed:
When pushing the top of your stack out to others, the new one won't be a
(possibly indirect) child of the previous push. This makes updating such a
head more dificult. With this approach, the new head will be a (possibly
indirect) child of the previous one (except when the top patch has been
removed, but this corner case could also be solved).

Because of this less rebasing, this aproach also facilitates co-development
on stgit patch stacks: by using a base:top id pair, the stgit patch stack
could be initialized, including its exported history. By following the
parent/child relations, 2 patch stacks could be compared and merged.

> 
> I tried your patch and test script but, if you try to reorder the
> patches, the DAG structure become quite hard to understand and that's
> only for a small set of frozen states.

I acknowledge this problem, but the solution for this would be to give
gitk another way of viewing such history: only the latest description of a
patch should be visible and the history should become more horizontal
(because the older descriptions wouldn't be shown, the history of those
patches could be viewed on the line with the latest description)

But changing gitk would only be usefull when this approach would be taken.

> 
> I think the best approach would be to keep a list of tags for each
> patch. They won't be browsable with gitk but the DAG structure would be
> clean. We might get another tool like gquilt to be able to show all the
> saved states of a patch.
> 
> Sorry for not including your patch but, while I agree with the general
> idea of frozen patch states, I disagree with its implementation.
> 

I understand your objections when limiting parents only to merges, but I see
them broader. So as you said: we indeed need a git designer to clear this up
for us.

Best regards,
Jan

^ permalink raw reply

* [PATCH] sha1_name: do not accept .git/refs/snap/.
From: Junio C Hamano @ 2005-08-21  9:43 UTC (permalink / raw)
  To: git

I think Linus did a cut & paste from an early JIT code while
developing the current extended SHA1 notation, and left it there as a
courtesy, but the directory does not deserve to be treated any more
specially than, say, .git/refs/bisect.

If the subdirectories under .git/refs proliferate, we may want to
switch to scanning that hierarchy at runtime, instead of the current
hard-coded set, although I think that would be overkill.

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

---

 sha1_name.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

19b3a5f94a98d523272c5c19fc166e879ce517e0
diff --git a/sha1_name.c b/sha1_name.c
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -143,7 +143,6 @@ static int get_sha1_basic(const char *st
 		"refs",
 		"refs/tags",
 		"refs/heads",
-		"refs/snap",
 		NULL
 	};
 	const char **p;

^ permalink raw reply

* [PATCH] Add a new extended SHA1 syntax <name>:<num>
From: Junio C Hamano @ 2005-08-21  9:43 UTC (permalink / raw)
  To: git

The new notation is a short-hand for <name> followed by <num>
caret ('^') characters.  E.g. "master:4" is the fourth
generation ancestor of the current "master" branch head,
following the first parents; same as "master^^^^" but a bit more
readable.

This will be used in the updated "git show-branch" command.

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

---

 sha1_name.c |   41 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 41 insertions(+), 0 deletions(-)

3a371474bc20e192b0e9d3b48fb7c84ca107b818
diff --git a/sha1_name.c b/sha1_name.c
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -191,9 +191,29 @@ static int get_parent(const char *name, 
 	return -1;
 }
 
+static int get_nth_ancestor(const char *name, int len,
+			    unsigned char *result, int generation)
+{
+	unsigned char sha1[20];
+	int ret = get_sha1_1(name, len, sha1);
+	if (ret)
+		return ret;
+
+	while (generation--) {
+		struct commit *commit = lookup_commit_reference(sha1);
+
+		if (!commit || parse_commit(commit) || !commit->parents)
+			return -1;
+		memcpy(sha1, commit->parents->item->object.sha1, 20);
+	}
+	memcpy(result, sha1, 20);
+	return 0;
+}
+
 static int get_sha1_1(const char *name, int len, unsigned char *sha1)
 {
 	int parent, ret;
+	const char *cp;
 
 	/* foo^[0-9] or foo^ (== foo^1); we do not do more than 9 parents. */
 	if (len > 2 && name[len-2] == '^' &&
@@ -210,6 +230,27 @@ static int get_sha1_1(const char *name, 
 	if (parent >= 0)
 		return get_parent(name, len, sha1, parent);
 
+	/* name:3 is name^^^,
+	 * name:12 is name^^^^^^^^^^^^, and
+	 * name: is name
+	 */
+	parent = 0;
+	for (cp = name + len - 1; name <= cp; cp--) {
+		int ch = *cp;
+		if ('0' <= ch && ch <= '9')
+			continue;
+		if (ch != ':')
+			parent = -1;
+		break;
+	}
+	if (!parent && *cp == ':') {
+		int len1 = cp - name;
+		cp++;
+		while (cp < name + len)
+			parent = parent * 10 + *cp++ - '0';
+		return get_nth_ancestor(name, len1, sha1, parent);
+	}
+
 	ret = get_sha1_basic(name, len, sha1);
 	if (!ret)
 		return 0;

^ permalink raw reply

* [PATCH] Add 'git show-branch'.
From: Junio C Hamano @ 2005-08-21  9:51 UTC (permalink / raw)
  To: git

The 'git show-branches' command turns out to be reasonably useful,
but painfully slow.  So rewrite it in C, using ideas from merge-base
while enhancing it a bit more.

 - Unlike show-branches, it can take --heads (show me all my
   heads), --tags (show me all my tags), or --all (both).

 - It can take --more=<number> to show beyond the merge-base.

 - It shows the short name for each commit in the extended SHA1
   syntax.

 - It can find merge-base for more than two heads.

Examples:

    $ git show-branch --more=6 HEAD

    is almost the same as "git log --pretty=oneline --max-count=6".

    $ git show-branch --merge-base master mhf misc

    finds the merge base of the three given heads.

    $ git show-branch --all --more=10

    is poor-man's gitk, showing all the tags and heads, and
    going back 10 commits beyond the merge base of those refs.

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

---

 Makefile      |    2 
 commit.c      |   21 +++-
 commit.h      |    2 
 show-branch.c |  325 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 343 insertions(+), 7 deletions(-)
 create mode 100644 show-branch.c

660c5d6332b541e2186c93374eef637e30894c62
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -85,7 +85,7 @@ PROG=   git-update-cache git-diff-files 
 	git-diff-stages git-rev-parse git-patch-id git-pack-objects \
 	git-unpack-objects git-verify-pack git-receive-pack git-send-pack \
 	git-prune-packed git-fetch-pack git-upload-pack git-clone-pack \
-	git-show-index git-daemon git-var git-peek-remote \
+	git-show-index git-daemon git-var git-peek-remote git-show-branch \
 	git-update-server-info git-show-rev-cache git-build-rev-cache
 
 ifndef NO_CURL
diff --git a/commit.c b/commit.c
--- a/commit.c
+++ b/commit.c
@@ -38,23 +38,32 @@ enum cmit_fmt get_commit_format(const ch
 	die("invalid --pretty format");
 }
 
-static struct commit *check_commit(struct object *obj, const unsigned char *sha1)
+static struct commit *check_commit(struct object *obj,
+				   const unsigned char *sha1,
+				   int quiet)
 {
 	if (obj->type != commit_type) {
-		error("Object %s is a %s, not a commit", 
-		      sha1_to_hex(sha1), obj->type);
+		if (!quiet)
+			error("Object %s is a %s, not a commit",
+			      sha1_to_hex(sha1), obj->type);
 		return NULL;
 	}
 	return (struct commit *) obj;
 }
 
-struct commit *lookup_commit_reference(const unsigned char *sha1)
+struct commit *lookup_commit_reference_gently(const unsigned char *sha1,
+					      int quiet)
 {
 	struct object *obj = deref_tag(parse_object(sha1));
 
 	if (!obj)
 		return NULL;
-	return check_commit(obj, sha1);
+	return check_commit(obj, sha1, quiet);
+}
+
+struct commit *lookup_commit_reference(const unsigned char *sha1)
+{
+	return lookup_commit_reference_gently(sha1, 0);
 }
 
 struct commit *lookup_commit(const unsigned char *sha1)
@@ -69,7 +78,7 @@ struct commit *lookup_commit(const unsig
 	}
 	if (!obj->type)
 		obj->type = commit_type;
-	return check_commit(obj, sha1);
+	return check_commit(obj, sha1, 0);
 }
 
 static unsigned long parse_commit_date(const char *buf)
diff --git a/commit.h b/commit.h
--- a/commit.h
+++ b/commit.h
@@ -21,6 +21,8 @@ extern const char *commit_type;
 
 struct commit *lookup_commit(const unsigned char *sha1);
 struct commit *lookup_commit_reference(const unsigned char *sha1);
+struct commit *lookup_commit_reference_gently(const unsigned char *sha1,
+					      int quiet);
 
 int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size);
 
diff --git a/show-branch.c b/show-branch.c
new file mode 100644
--- /dev/null
+++ b/show-branch.c
@@ -0,0 +1,325 @@
+#include <stdlib.h>
+#include "cache.h"
+#include "commit.h"
+#include "refs.h"
+
+static const char show_branch_usage[] =
+"git-show-branch [--all] [--heads] [--tags] [--more=count] [<refs>...]";
+
+#define UNINTERESTING	01
+
+#define REV_SHIFT	 2
+#define MAX_REVS	29 /* should not exceed bits_per_int - REV_SHIFT */
+
+static struct commit *interesting(struct commit_list *list)
+{
+	while (list) {
+		struct commit *commit = list->item;
+		list = list->next;
+		if (commit->object.flags & UNINTERESTING)
+			continue;
+		return commit;
+	}
+	return NULL;
+}
+
+static struct commit *pop_one_commit(struct commit_list **list_p)
+{
+	struct commit *commit;
+	struct commit_list *list;
+	list = *list_p;
+	commit = list->item;
+	*list_p = list->next;
+	free(list);
+	return commit;
+}
+
+struct commit_name {
+	int head_rev;	/* which head's ancestor? */
+	int generation;	/* how many parents away from head_rev */
+};
+
+/* Name the commit as nth generation ancestor of head_rev;
+ * we count only the first-parent relationship for naming purposes.
+ */
+static void name_commit(struct commit *commit, int head_rev, int nth)
+{
+	struct commit_name *name;
+	if (!commit->object.util)
+		commit->object.util = xmalloc(sizeof(struct commit_name));
+	name = commit->object.util;
+	name->head_rev = head_rev;
+	name->generation = nth;
+}
+
+/* Parent is the first parent of the commit.  We may name it
+ * as (n+1)th generation ancestor of the same head_rev as
+ * commit is nth generation ancestore of, if that generation
+ * number is better than the name it already has.
+ */
+static void name_parent(struct commit *commit, struct commit *parent)
+{
+	struct commit_name *commit_name = commit->object.util;
+	struct commit_name *parent_name = parent->object.util;
+	if (!commit_name)
+		return;
+	if (!parent_name ||
+	    commit_name->generation + 1 < parent_name->generation)
+		name_commit(parent, commit_name->head_rev,
+			    commit_name->generation + 1);
+}
+
+static int mark_seen(struct commit *commit, struct commit_list **seen_p)
+{
+	if (!commit->object.flags) {
+		insert_by_date(commit, seen_p);
+		return 1;
+	}
+	return 0;
+}
+
+static void join_revs(struct commit_list **list_p,
+		      struct commit_list **seen_p,
+		      int num_rev, int extra)
+{
+	int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
+	int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
+
+	while (*list_p) {
+		struct commit_list *parents;
+		struct commit *commit = pop_one_commit(list_p);
+		int flags = commit->object.flags & all_mask;
+		int nth_parent = 0;
+		int still_interesting = !!interesting(*list_p);
+
+		if (!still_interesting && extra < 0)
+			break;
+
+		mark_seen(commit, seen_p);
+		if ((flags & all_revs) == all_revs)
+			flags |= UNINTERESTING;
+		parents = commit->parents;
+
+		while (parents) {
+			struct commit *p = parents->item;
+			int this_flag = p->object.flags;
+			parents = parents->next;
+			nth_parent++;
+			if (nth_parent == 1)
+				name_parent(commit, p);
+
+			if ((this_flag & flags) == flags)
+				continue;
+			parse_commit(p);
+			if (mark_seen(p, seen_p) && !still_interesting)
+				extra--;
+			p->object.flags |= flags;
+			insert_by_date(p, list_p);
+		}
+	}
+}
+
+static void show_one_commit(struct commit *commit, char **head_name)
+{
+	char pretty[128], *cp;
+	struct commit_name *name = commit->object.util;
+	pretty_print_commit(CMIT_FMT_ONELINE, commit->buffer, ~0,
+			    pretty, sizeof(pretty));
+	if (!strncmp(pretty, "[PATCH] ", 8))
+		cp = pretty + 8;
+	else
+		cp = pretty;
+	if (name) {
+		printf("[%s", head_name[name->head_rev]);
+		if (name->generation)
+			printf(":%d", name->generation);
+		printf("] ");
+	}
+	puts(cp);
+}
+
+static char *ref_name[MAX_REVS + 1];
+static int ref_name_cnt;
+
+static int append_ref(const char *refname, const unsigned char *sha1)
+{
+	struct commit *commit = lookup_commit_reference_gently(sha1, 1);
+	if (!commit)
+		return 0;
+	if (MAX_REVS < ref_name_cnt) {
+		fprintf(stderr, "warning: ignoring %s; "
+			"cannot handle more than %d refs",
+			refname, MAX_REVS);
+		return 0;
+	}
+	ref_name[ref_name_cnt++] = strdup(refname);
+	ref_name[ref_name_cnt] = NULL;
+	return 0;
+}
+
+static int append_head_ref(const char *refname, const unsigned char *sha1)
+{
+	if (strncmp(refname, "refs/heads/", 11))
+		return 0;
+	return append_ref(refname + 5, sha1);
+}
+
+static int append_tag_ref(const char *refname, const unsigned char *sha1)
+{
+	if (strncmp(refname, "refs/tags/", 10))
+		return 0;
+	return append_ref(refname + 5, sha1);
+}
+
+static void snarf_refs(int head, int tag)
+{
+	if (head)
+		for_each_ref(append_head_ref);
+	if (tag)
+		for_each_ref(append_tag_ref);
+}
+
+static int rev_is_head(char *head_path, int headlen,
+		       char *name,
+		       unsigned char *head_sha1, unsigned char *sha1)
+{
+	int namelen;
+	if ((!head_path[0]) || memcmp(head_sha1, sha1, 20))
+		return 0;
+	namelen = strlen(name);
+	if ((headlen < namelen) ||
+	    memcmp(head_path + headlen - namelen, name, namelen))
+		return 0;
+	if (headlen == namelen ||
+	    head_path[headlen - namelen - 1] == '/')
+		return 1;
+	return 0;
+}
+
+static int show_merge_base(struct commit_list *seen, int num_rev)
+{
+	int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
+	int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
+
+	while (seen) {
+		struct commit *commit = pop_one_commit(&seen);
+		int flags = commit->object.flags & all_mask;
+		if (!(flags & UNINTERESTING) &&
+		    ((flags & all_revs) == all_revs)) {
+			puts(sha1_to_hex(commit->object.sha1));
+			return 0;
+		}
+	}
+	return 1;
+}
+
+int main(int ac, char **av)
+{
+	struct commit *rev[MAX_REVS], *commit;
+	struct commit_list *list = NULL, *seen = NULL;
+	int num_rev, i, extra = 0;
+	int all_heads = 0, all_tags = 0;
+	char head_path[128];
+	int head_path_len;
+	unsigned char head_sha1[20];
+	int merge_base = 0;
+
+	while (1 < ac && av[1][0] == '-') {
+		char *arg = av[1];
+		if (!strcmp(arg, "--all"))
+			all_heads = all_tags = 1;
+		else if (!strcmp(arg, "--heads"))
+			all_heads = 1;
+		else if (!strcmp(arg, "--tags"))
+			all_tags = 1;
+		else if (!strcmp(arg, "--more"))
+			extra = 1;
+		else if (!strncmp(arg, "--more=", 7)) {
+			extra = atoi(arg + 7);
+			if (extra < 0)
+				usage(show_branch_usage);
+		}
+		else if (!strcmp(arg, "--merge-base"))
+			merge_base = 1;
+		else
+			usage(show_branch_usage);
+		ac--; av++;
+	}
+	ac--; av++;
+
+	if (all_heads + all_tags)
+		snarf_refs(all_heads, all_tags);
+
+	while (0 < ac) {
+		unsigned char revkey[20];
+		if (get_sha1(*av, revkey))
+			die("bad sha1 reference %s", *av);
+		append_ref(*av, revkey);
+		ac--; av++;
+	}
+
+	/* If still no revs, then add heads */
+	if (!ref_name_cnt)
+		snarf_refs(1, 0);
+
+	for (num_rev = 0; ref_name[num_rev]; num_rev++) {
+		unsigned char revkey[20];
+
+		if (MAX_REVS <= num_rev)
+			die("cannot handle more than %d revs.", MAX_REVS);
+		if (get_sha1(ref_name[num_rev], revkey))
+			usage(show_branch_usage);
+		commit = lookup_commit_reference(revkey);
+		if (!commit)
+			die("cannot find commit %s (%s)",
+			    ref_name[num_rev], revkey);
+		parse_commit(commit);
+		if (!commit->object.util)
+			name_commit(commit, num_rev, 0);
+		mark_seen(commit, &seen);
+
+		/* rev#0 uses bit REV_SHIFT, rev#1 uses bit REV_SHIFT+1,
+		 * and so on.  REV_SHIFT bits from bit 0 are used for
+		 * internal bookkeeping.
+		 */
+		commit->object.flags |= 1u << (num_rev + REV_SHIFT);
+		insert_by_date(commit, &list);
+		rev[num_rev] = commit;
+	}
+	join_revs(&list, &seen, num_rev, extra);
+
+	head_path_len = readlink(".git/HEAD", head_path, sizeof(head_path)-1);
+	if ((head_path_len < 0) || get_sha1("HEAD", head_sha1))
+		head_path[0] = 0;
+	else
+		head_path[head_path_len] = 0;
+
+	if (merge_base)
+		return show_merge_base(seen, num_rev);
+
+	if (1 < num_rev)
+		for (i = 0; i < num_rev; i++) {
+			int j;
+			int is_head = rev_is_head(head_path,
+						  head_path_len,
+						  ref_name[i],
+						  head_sha1,
+						  rev[i]->object.sha1);
+			for (j = 0; j < i; j++)
+				putchar(' ');
+			printf("%c ", is_head ? '*' : '!');
+			show_one_commit(rev[i], ref_name);
+		}
+	while (seen) {
+		struct commit *commit = pop_one_commit(&seen);
+		int this_flag = commit->object.flags;
+		if ((this_flag & UNINTERESTING) && (--extra < 0))
+			break;
+		for (i = 0; i < num_rev; i++)
+			putchar((this_flag & (1u << (i + REV_SHIFT)))
+				? '+' : ' ');
+		putchar(' ');
+		show_one_commit(commit, ref_name);
+	}
+	return 0;
+}

^ permalink raw reply

* [ANNOUNCE] (H)gct 0.2
From: Fredrik Kuivinen @ 2005-08-21 14:58 UTC (permalink / raw)
  To: git

Version 0.2 of (H)gct, a GUI enabled commit tool, has been released
and can be downloaded from
http://www.cyd.liu.se/~freku045/gct/gct-0.2.tar.gz

There is also a Git repository for (H)gct at
http://www.cyd.liu.se/users/~freku045/gct/gct.git/ (and a gitweb for
this repository is available at
http://www.cyd.liu.se/users/~freku045/gct/gitweb.cgi)

Some screen shots can be found on the homepage at
http://www.cyd.liu.se/~freku045/gct


The major changes compared to v0.1 are:

* User interface enhancements: 
  - automatically add signoff to commit message
  - jump directly into an editor to modify files
  - ignore file (hg only)
  - preferences panel
  - revert changes
  - (un)select all changes
* Support for Mercurial (hg) repositories via the "hgct" command
* Generic SCM interface allows easy porting to other SCM systems
* Assorted small bugfixes and enhancements

Lots of thanks to Mark Williamson for the Hg support, patches and
ideas.

- Fredrik

^ permalink raw reply

* Make "git-ls-files" work in subdirectories
From: Linus Torvalds @ 2005-08-21 19:55 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List


This makes git-ls-files work inside a relative directory, and also adds
some rudimentary filename globbing support. For example, in the kernel you
can now do

	cd arch/i386
	git-ls-files

and it will show all files under that subdirectory (and it will have
removed the "arch/i386/" prefix unless you give it the "--full-name"  
option, so that you can feed the result to "xargs grep" or similar).

The filename globbing is kind of strange: it does _not_ follow normal 
globbing rules, although it does look "almost" like a normal file glob 
(and it uses the POSIX.2 "fnmatch()" function).

The glob pattern (there can be only one) is always split into a "directory 
part" and a "glob part", where the directory part is defined as any full 
directory path without any '*' or '?' characters. The "glob" part is 
whatever is left over.

For example, when doing

	git-ls-files 'arch/i386/p*/*.c'

the "directory part" is is "arch/i386/", and the "glob part" is "p*/*.c". 
The directory part will be added to the prefix, and handled efficiently 
(ie we will not be searching outside of that subdirectory), while the glob 
part (if anything is left over) will be used to trigger "fnmatch()" 
matches.

This is efficient and very useful, but can result in somewhat
non-intuitive behaviour.

For example:

	git-ls-files 'arch/i386/*.[ch]'

will find all .c and .h files under arch/i386/, _including_ things in
lower subdirectories (ie it will match "arch/i386/kernel/process.c",
because "kernel/process.c" will match the "*.c" specifier).

Also, while

	git-ls-files arch/i386/

will show all files under that subdirectory, doing the same without the
final slash would try to show the file "i386" under the "arch/"  
subdirectory, and since there is no such file (even if there is such a
_directory_) it will not match anything at all.

These semantics may not seem intuitive, but they are actually very
practical. In particular, it makes it very simple to do

	git-ls-files fs/*.c | xargs grep some_pattern

and it does what you want.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
[ Implementation note: the difference between "prefix_len" and 
  "prefix_offset" is that "prefix_len" is used for all the compare logic, 
  while "prefix_offset" is used to determine how much of the prefix not to
  print out. So "--full-name" just clears prefix_offset, which keeps all
  the comparisons the same, but prints out the full absolute git path,
  rather than the relative one.

  Also: unlike things like "git-diff-files" etc, we do _not_ handle 
  prefixes containint ".." and "./" etc gracefully. That's partly exactly 
  because the result of git-ls-files is normally a relative pathname, and
  it just makes it almost impossible to do what the git-diff-* functions 
  do efficiently and with sane semantics ]

---
diff --git a/ls-files.c b/ls-files.c
--- a/ls-files.c
+++ b/ls-files.c
@@ -19,6 +19,10 @@ static int show_unmerged = 0;
 static int show_killed = 0;
 static int line_terminator = '\n';
 
+static int prefix_len = 0, prefix_offset = 0;
+static const char *prefix = NULL;
+static const char *glob = NULL;
+
 static const char *tag_cached = "";
 static const char *tag_unmerged = "";
 static const char *tag_removed = "";
@@ -222,6 +226,7 @@ static void add_name(const char *pathnam
 	ent = xmalloc(sizeof(*ent) + len + 1);
 	ent->len = len;
 	memcpy(ent->name, pathname, len);
+	ent->name[len] = 0;
 	dir[nr_dir++] = ent;
 }
 
@@ -297,6 +302,20 @@ static int cmp_name(const void *p1, cons
 				  e2->name, e2->len);
 }
 
+static void show_dir_entry(const char *tag, struct nond_on_fs *ent)
+{
+	int len = prefix_len;
+	int offset = prefix_offset;
+
+	if (len >= ent->len)
+		die("git-ls-files: internal error - directory entry not superset of prefix");
+
+	if (glob && fnmatch(glob, ent->name + len, 0))
+		return;
+
+	printf("%s%s%c", tag, ent->name + offset, line_terminator);
+}
+
 static void show_killed_files(void)
 {
 	int i;
@@ -342,25 +361,48 @@ static void show_killed_files(void)
 			}
 		}
 		if (killed)
-			printf("%s%.*s%c", tag_killed,
-			       dir[i]->len, dir[i]->name,
-			       line_terminator);
+			show_dir_entry(tag_killed, dir[i]);
 	}
 }
 
+static void show_ce_entry(const char *tag, struct cache_entry *ce)
+{
+	int len = prefix_len;
+	int offset = prefix_offset;
+
+	if (len >= ce_namelen(ce))
+		die("git-ls-files: internal error - cache entry not superset of prefix");
+
+	if (glob && fnmatch(glob, ce->name + len, 0))
+		return;
+
+	if (!show_stage)
+		printf("%s%s%c", tag, ce->name + offset, line_terminator);
+	else
+		printf("%s%06o %s %d\t%s%c",
+		       tag,
+		       ntohl(ce->ce_mode),
+		       sha1_to_hex(ce->sha1),
+		       ce_stage(ce),
+		       ce->name + offset, line_terminator); 
+}
+
 static void show_files(void)
 {
 	int i;
 
 	/* For cached/deleted files we don't need to even do the readdir */
 	if (show_others || show_killed) {
-		read_directory(".", "", 0);
+		const char *path = ".", *base = "";
+		int baselen = prefix_len;
+
+		if (baselen)
+			path = base = prefix;
+		read_directory(path, base, baselen);
 		qsort(dir, nr_dir, sizeof(struct nond_on_fs *), cmp_name);
 		if (show_others)
 			for (i = 0; i < nr_dir; i++)
-				printf("%s%.*s%c", tag_other,
-				       dir[i]->len, dir[i]->name,
-				       line_terminator);
+				show_dir_entry(tag_other, dir[i]);
 		if (show_killed)
 			show_killed_files();
 	}
@@ -371,19 +413,7 @@ static void show_files(void)
 				continue;
 			if (show_unmerged && !ce_stage(ce))
 				continue;
-			if (!show_stage)
-				printf("%s%s%c",
-				       ce_stage(ce) ? tag_unmerged :
-				       tag_cached,
-				       ce->name, line_terminator);
-			else
-				printf("%s%06o %s %d\t%s%c",
-				       ce_stage(ce) ? tag_unmerged :
-				       tag_cached,
-				       ntohl(ce->ce_mode),
-				       sha1_to_hex(ce->sha1),
-				       ce_stage(ce),
-				       ce->name, line_terminator); 
+			show_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce);
 		}
 	}
 	if (show_deleted) {
@@ -394,9 +424,66 @@ static void show_files(void)
 				continue;
 			if (!lstat(ce->name, &st))
 				continue;
-			printf("%s%s%c", tag_removed, ce->name,
-			       line_terminator);
+			show_ce_entry(tag_removed, ce);
+		}
+	}
+}
+
+/*
+ * Prune the index to only contain stuff starting with "prefix"
+ */
+static void prune_cache(void)
+{
+	int pos = cache_name_pos(prefix, prefix_len);
+	unsigned int first, last;
+
+	if (pos < 0)
+		pos = -pos-1;
+	active_cache += pos;
+	active_nr -= pos;
+	first = 0;
+	last = active_nr;
+	while (last > first) {
+		int next = (last + first) >> 1;
+		struct cache_entry *ce = active_cache[next];
+		if (!strncmp(ce->name, prefix, prefix_len)) {
+			first = next+1;
+			continue;
 		}
+		last = next;
+	}
+	active_nr = last;
+}
+
+/*
+ * If the glob starts with a subdirectory, append it to
+ * the prefix instead, for more efficient operation.
+ *
+ * But we do not update the "prefix_offset", which tells
+ * how much of the name to ignore at printout.
+ */
+static void extend_prefix(void)
+{
+	const char *p, *slash;
+	char c;
+
+	p = glob;
+	slash = NULL;
+	while ((c = *p++) != '\0') {
+		if (c == '*')
+			break;
+		if (c == '/')
+			slash = p;
+	}
+	if (slash) {
+		int len = slash - glob;
+		char *newprefix = xmalloc(len + prefix_len + 1);
+		memcpy(newprefix, prefix, prefix_len);
+		memcpy(newprefix + prefix_len, glob, len);
+		prefix_len += len;
+		newprefix[prefix_len] = 0;
+		prefix = newprefix;
+		glob = *slash ? slash : NULL;
 	}
 }
 
@@ -410,54 +497,94 @@ int main(int argc, char **argv)
 	int i;
 	int exc_given = 0;
 
+	prefix = setup_git_directory();
+	if (prefix)
+		prefix_offset = prefix_len = strlen(prefix);
+
 	for (i = 1; i < argc; i++) {
 		char *arg = argv[i];
 
 		if (!strcmp(arg, "-z")) {
 			line_terminator = 0;
-		} else if (!strcmp(arg, "-t")) {
+			continue;
+		}
+		if (!strcmp(arg, "-t")) {
 			tag_cached = "H ";
 			tag_unmerged = "M ";
 			tag_removed = "R ";
 			tag_other = "? ";
 			tag_killed = "K ";
-		} else if (!strcmp(arg, "-c") || !strcmp(arg, "--cached")) {
+			continue;
+		}
+		if (!strcmp(arg, "-c") || !strcmp(arg, "--cached")) {
 			show_cached = 1;
-		} else if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) {
+			continue;
+		}
+		if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) {
 			show_deleted = 1;
-		} else if (!strcmp(arg, "-o") || !strcmp(arg, "--others")) {
+			continue;
+		}
+		if (!strcmp(arg, "-o") || !strcmp(arg, "--others")) {
 			show_others = 1;
-		} else if (!strcmp(arg, "-i") || !strcmp(arg, "--ignored")) {
+			continue;
+		}
+		if (!strcmp(arg, "-i") || !strcmp(arg, "--ignored")) {
 			show_ignored = 1;
-		} else if (!strcmp(arg, "-s") || !strcmp(arg, "--stage")) {
+			continue;
+		}
+		if (!strcmp(arg, "-s") || !strcmp(arg, "--stage")) {
 			show_stage = 1;
-		} else if (!strcmp(arg, "-k") || !strcmp(arg, "--killed")) {
+			continue;
+		}
+		if (!strcmp(arg, "-k") || !strcmp(arg, "--killed")) {
 			show_killed = 1;
-		} else if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) {
+			continue;
+		}
+		if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) {
 			/* There's no point in showing unmerged unless
 			 * you also show the stage information.
 			 */
 			show_stage = 1;
 			show_unmerged = 1;
-		} else if (!strcmp(arg, "-x") && i+1 < argc) {
+			continue;
+		}
+		if (!strcmp(arg, "-x") && i+1 < argc) {
 			exc_given = 1;
 			add_exclude(argv[++i], "", 0, &exclude_list[EXC_CMDL]);
-		} else if (!strncmp(arg, "--exclude=", 10)) {
+			continue;
+		}
+		if (!strncmp(arg, "--exclude=", 10)) {
 			exc_given = 1;
 			add_exclude(arg+10, "", 0, &exclude_list[EXC_CMDL]);
-		} else if (!strcmp(arg, "-X") && i+1 < argc) {
+			continue;
+		}
+		if (!strcmp(arg, "-X") && i+1 < argc) {
 			exc_given = 1;
 			add_excludes_from_file(argv[++i]);
-		} else if (!strncmp(arg, "--exclude-from=", 15)) {
+			continue;
+		}
+		if (!strncmp(arg, "--exclude-from=", 15)) {
 			exc_given = 1;
 			add_excludes_from_file(arg+15);
-		} else if (!strncmp(arg, "--exclude-per-directory=", 24)) {
+			continue;
+		}
+		if (!strncmp(arg, "--exclude-per-directory=", 24)) {
 			exc_given = 1;
 			exclude_per_dir = arg + 24;
-		} else
+			continue;
+		}
+		if (!strcmp(arg, "--full-name")) {
+			prefix_offset = 0;
+			continue;
+		}
+		if (glob || *arg == '-')
 			usage(ls_files_usage);
+		glob = arg;
 	}
 
+	if (glob)
+		extend_prefix();
+
 	if (show_ignored && !exc_given) {
 		fprintf(stderr, "%s: --ignored needs some exclude pattern\n",
 			argv[0]);
@@ -469,6 +596,8 @@ int main(int argc, char **argv)
 		show_cached = 1;
 
 	read_cache();
+	if (prefix)
+		prune_cache();
 	show_files();
 	return 0;
 }

^ permalink raw reply

* "git reset" and newly created files.
From: Junio C Hamano @ 2005-08-21 19:31 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

When you made a mistake and committed a set of incomplete
changes, the "git reset" command comes handy.

    ... Edit, compile, and test.
    $ git commit -s -m 'The perfect change.'
    ... Test again, OOPS it fails --- it was not perfect.
    $ git reset HEAD^
    foo: needs update
    bar: needs update

The commit object name for the botched commit is kept in the
$GIT_DIR/ORIG_HEAD file, the HEAD commit and the index file are
"reset" to the commit before ORIG_HEAD.  The files in the
working tree are not touched and they are the same as what are
in ORIG_HEAD.  The command tells which files in the working tree
are different from the HEAD commit.

So you would naturally be tempted to do this:

    ... Re-edit, compile, and test.  This time it is perfect.
    $ git commit -a -C ORIG_HEAD

Well, not really.  You can lose any file newly created in
ORIG_HEAD this way.  Instead, you need to do this:

    ... Re-edit, compile, and test.  This time it is perfect.
    $ git add <whatever file you have changed>
    $ git commit -a -C ORIG_HEAD

Do people find this a big problem?

Technically, what "git reset" does is correct, because its
definition says the index file is reset to what was in HEAD,
which did not know about the files added by the ORIG_HEAD, and
there is no way for it to keep an eye on the file you wanted to
add in the botched ORIG_HEAD commit.

But it does not _feel_ right.

This relates to the fact that there currently is no way to
record "intent to add" (aka "please keep an eye on") in the
index file.  I think we could solve this with something like
this:

    $ git-update-cache --add-maybe foo
    $ git status
    # Changed but not updated:
    #   (use git-update-cache to mark for commit)
    #
    #       new file: foo
    $ git-update-cache --refresh
    foo: needs update
    $ git-update-cache foo
    $ git status
    # Updated but not checked in:
    #   (will commit)
    #
    #       new file: foo

The "git reset" command should be able to detect the paths found
in ORIG_HEAD but lacking in HEAD, reset the index to HEAD and
say "git-update-cache --add-maybe" for such paths.

Hmm?

^ permalink raw reply

* Re: [PATCH] Add a new extended SHA1 syntax <name>:<num>
From: Junio C Hamano @ 2005-08-21 18:37 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0508212025350.15353@wgmdd8.biozentrum.uni-wuerzburg.de>

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> This might confuse some people with the <src>:<dest> notation of the 
> renaming fetch...

True.  How about using a tilde '~'?

^ permalink raw reply

* 1dfcfbce2d643b7c7b56dc828f36ced9de2bf9f2
From: Junio C Hamano @ 2005-08-21 18:49 UTC (permalink / raw)
  To: git

A couple of people noticed that the latest commit in the
"master" branch seems, eh, odd.

It was not a screw-up of any of the git tools, just me screwing
up in an early morning/late night editing session when checking
things in.

    $ git whatchanged -p --max-count=1 <that commit>

shows the true story.  The commit message has the excess, but
the patch for the commit has exactly the thing I wanted it to
have and nothing else.

My policy is not to rewind "master" and "rc" once it hits the
public repository; otherwise it would make pulling from these
branches unnecessarily confusing for other people.

Although it is embarrassing, the screw-up this case is only the
commit log message, and running "git revert" once and then "git
revert" again would not make it less confusing, so I will keep
things as they are.

^ permalink raw reply

* Re: [PATCH] Add a new extended SHA1 syntax <name>:<num>
From: Johannes Schindelin @ 2005-08-21 18:26 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vll2viq05.fsf@assigned-by-dhcp.cox.net>

Hi,

On Sun, 21 Aug 2005, Junio C Hamano wrote:

> The new notation is a short-hand for <name> followed by <num>
> caret ('^') characters.  E.g. "master:4" is the fourth
> generation ancestor of the current "master" branch head,
> following the first parents; same as "master^^^^" but a bit more
> readable.

This might confuse some people with the <src>:<dest> notation of the 
renaming fetch...

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH] Add a new extended SHA1 syntax <name>:<num>
From: Johannes Schindelin @ 2005-08-21 18:41 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vr7cngmq4.fsf@assigned-by-dhcp.cox.net>

Hi,

On Sun, 21 Aug 2005, Junio C Hamano wrote:

> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > This might confuse some people with the <src>:<dest> notation of the 
> > renaming fetch...
> 
> True.  How about using a tilde '~'?

I like it.

Ciao,
Dscho

^ permalink raw reply

* Re: "git reset" and newly created files.
From: Sam Ravnborg @ 2005-08-21 21:46 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Linus Torvalds, git
In-Reply-To: <7vbr3rccjc.fsf@assigned-by-dhcp.cox.net>

> 
> So you would naturally be tempted to do this:
> 
>     ... Re-edit, compile, and test.  This time it is perfect.
>     $ git commit -a -C ORIG_HEAD
> 
> Well, not really.  You can lose any file newly created in
> ORIG_HEAD this way.  Instead, you need to do this:
> 
>     ... Re-edit, compile, and test.  This time it is perfect.
>     $ git add <whatever file you have changed>
>     $ git commit -a -C ORIG_HEAD
> 
> Do people find this a big problem?

I often do some maybe not that brilliant changes in my tree,
and when I then ask git to reset these I expect git to reset
everything.

After a git-reset HEAD^ I really expect git to have rewinded back till
where I started with no files added whatsoever.

>From the matter of least suprise git should not remember files added,
one have to do that by themself again if needed.

	Sam

^ permalink raw reply

* Re: Make "git-ls-files" work in subdirectories
From: Chris Wedgwood @ 2005-08-21 22:46 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Junio C Hamano, Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0508211210500.3317@g5.osdl.org>

On Sun, Aug 21, 2005 at 12:55:33PM -0700, Linus Torvalds wrote:

> -		} else if (!strcmp(arg, "-t")) {
> +			continue;
> +		}
> +		if (!strcmp(arg, "-t")) {
>  			tag_cached = "H ";
>  			tag_unmerged = "M ";
>  			tag_removed = "R ";
>  			tag_other = "? ";
>  			tag_killed = "K ";
> -		} else if (!strcmp(arg, "-c") || !strcmp(arg, "--cached")) {
> +			continue;
> +		}
> +		if (!strcmp(arg, "-c") || !strcmp(arg, "--cached")) {
>  			show_cached = 1;
> -		} else if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) {
> +			continue;
> +		}
> +		if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) {
>  			show_deleted = 1;
> -		} else if (!strcmp(arg, "-o") || !strcmp(arg, "--others")) {
> +			continue;
> +		}
> +		if (!strcmp(arg, "-o") || !strcmp(arg, "--others")) {
>  			show_others = 1;
> -		} else if (!strcmp(arg, "-i") || !strcmp(arg, "--ignored")) {
> +			continue;
> +		}
> +		if (!strcmp(arg, "-i") || !strcmp(arg, "--ignored")) {
>  			show_ignored = 1;
> -		} else if (!strcmp(arg, "-s") || !strcmp(arg, "--stage")) {
> +			continue;
> +		}
> +		if (!strcmp(arg, "-s") || !strcmp(arg, "--stage")) {
>  			show_stage = 1;
> -		} else if (!strcmp(arg, "-k") || !strcmp(arg, "--killed")) {
> +			continue;
> +		}
> +		if (!strcmp(arg, "-k") || !strcmp(arg, "--killed")) {
>  			show_killed = 1;
> -		} else if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) {
> +			continue;
> +		}
> +		if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) {
>  			/* There's no point in showing unmerged unless
>  			 * you also show the stage information.
>  			 */
>  			show_stage = 1;
>  			show_unmerged = 1;
> -		} else if (!strcmp(arg, "-x") && i+1 < argc) {
> +			continue;
> +		}
> +		if (!strcmp(arg, "-x") && i+1 < argc) {
>  			exc_given = 1;
>  			add_exclude(argv[++i], "", 0, &exclude_list[EXC_CMDL]);
> -		} else if (!strncmp(arg, "--exclude=", 10)) {
> +			continue;
> +		}
> +		if (!strncmp(arg, "--exclude=", 10)) {
>  			exc_given = 1;
>  			add_exclude(arg+10, "", 0, &exclude_list[EXC_CMDL]);
> -		} else if (!strcmp(arg, "-X") && i+1 < argc) {
> +			continue;
> +		}
> +		if (!strcmp(arg, "-X") && i+1 < argc) {
>  			exc_given = 1;
>  			add_excludes_from_file(argv[++i]);
> -		} else if (!strncmp(arg, "--exclude-from=", 15)) {
> +			continue;
> +		}
> +		if (!strncmp(arg, "--exclude-from=", 15)) {
>  			exc_given = 1;
>  			add_excludes_from_file(arg+15);
> -		} else if (!strncmp(arg, "--exclude-per-directory=", 24)) {
> +			continue;
> +		}
> +		if (!strncmp(arg, "--exclude-per-directory=", 24)) {
>  			exc_given = 1;
>  			exclude_per_dir = arg + 24;
> -		} else
> +			continue;
> +		}
> +		if (!strcmp(arg, "--full-name")) {
> +			prefix_offset = 0;
> +			continue;
> +		}
> +		if (glob || *arg == '-')
>  			usage(ls_files_usage);
> +		glob = arg;

is there some aversion to getopt or similar get?

^ permalink raw reply

* Re: Make "git-ls-files" work in subdirectories
From: Linus Torvalds @ 2005-08-21 23:17 UTC (permalink / raw)
  To: Chris Wedgwood; +Cc: Junio C Hamano, Git Mailing List
In-Reply-To: <20050821224622.GB26241@taniwha.stupidest.org>



On Sun, 21 Aug 2005, Chris Wedgwood wrote:
> 
> is there some aversion to getopt or similar get?

getopt() is too limited, and getopt_long() is very glibc-specific and thus
inherently evil. And the complexity of doing autoconf or similar is worse
than just doing it by hand.

I've considered doing a small library that could just be contained withing 
the git sources to avoid duplication, but it just hasn't been worth it.

If somebody wants to do it, go wild. The rules are
 - anything that is not expected of "modern unix" is too unportable (glibc 
   is not a realistic expectation, but a lot of GNU tools _are_ realistic)
 - autoconf and its ilk are worse than the disease they are trying to fix

		Linus

^ permalink raw reply

* Re: Make "git-ls-files" work in subdirectories
From: Chris Wedgwood @ 2005-08-21 23:45 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Junio C Hamano, Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0508211613340.3317@g5.osdl.org>

On Sun, Aug 21, 2005 at 04:17:52PM -0700, Linus Torvalds wrote:

> getopt() is too limited, and getopt_long() is very glibc-specific
> and thus inherently evil. And the complexity of doing autoconf or
> similar is worse than just doing it by hand.

what about libpopt?

^ permalink raw reply

* Re: [ANNOUNCE] (H)gct 0.2
From: Mark Williamson @ 2005-08-21 23:44 UTC (permalink / raw)
  To: git; +Cc: Fredrik Kuivinen, pasky
In-Reply-To: <20050821145851.GA24034@c165.ib.student.liu.se>

Any chance a link to the (h)gct homepage could be added to the git homepage 
under "porcelain"?

Cheers,
Mark

On Sunday 21 August 2005 15:58, Fredrik Kuivinen wrote:
> Version 0.2 of (H)gct, a GUI enabled commit tool, has been released
> and can be downloaded from
> http://www.cyd.liu.se/~freku045/gct/gct-0.2.tar.gz
>
> There is also a Git repository for (H)gct at
> http://www.cyd.liu.se/users/~freku045/gct/gct.git/ (and a gitweb for
> this repository is available at
> http://www.cyd.liu.se/users/~freku045/gct/gitweb.cgi)
>
> Some screen shots can be found on the homepage at
> http://www.cyd.liu.se/~freku045/gct
>
>
> The major changes compared to v0.1 are:
>
> * User interface enhancements:
>   - automatically add signoff to commit message
>   - jump directly into an editor to modify files
>   - ignore file (hg only)
>   - preferences panel
>   - revert changes
>   - (un)select all changes
> * Support for Mercurial (hg) repositories via the "hgct" command
> * Generic SCM interface allows easy porting to other SCM systems
> * Assorted small bugfixes and enhancements
>
> Lots of thanks to Mark Williamson for the Hg support, patches and
> ideas.
>
> - Fredrik
> -
> 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

^ permalink raw reply

* Re: Make "git-ls-files" work in subdirectories
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2005-08-21 23:50 UTC (permalink / raw)
  To: torvalds; +Cc: cw, junkio, git, yoshfuji
In-Reply-To: <Pine.LNX.4.58.0508211613340.3317@g5.osdl.org>

In article <Pine.LNX.4.58.0508211613340.3317@g5.osdl.org> (at Sun, 21 Aug 2005 16:17:52 -0700 (PDT)), Linus Torvalds <torvalds@osdl.org> says:

> getopt() is too limited, and getopt_long() is very glibc-specific and thus
> inherently evil. And the complexity of doing autoconf or similar is worse
> than just doing it by hand.

(I'm not against having our own getopt_long()
or alike, but anyway...)

Well, not really "glibc-specific" now.

NetBSD (>=1.5) has thir own implementation of getopt_long()
(w/ 4-clause BSD licence, which is not compatible w/ GPL2).
OpenBSD (>=3.3), FreeBSD (>=5.0), too.
Solaris (>=9?) seems to have one, too.

NetBSD: http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/stdlib/getopt_long.c
OpenBSD: http://www.openbsd.org/cgi-bin/cvsweb.cgi/src/lib/libc/stdlib/getopt_long.c
FreeBSD: http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/stdlib/getopt_long.c
Solaris: http://iforce.sun.com/protected/solaris10/adoptionkit/general/getopt_long.txt

--yoshfuji

^ permalink raw reply

* suggestion: store the URL somewhere in .git/
From: Jeff Carr @ 2005-08-22 20:08 UTC (permalink / raw)
  To: git

It would be nice if the URL could be stored somewhere in .git/ This
makes it a lot easier to update repositories because you don't always
have to go and track down where you got it in the first place. Something
like this perhaps:

~$ cat .git/location
rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git/
~$ git-pull-script

Then something like below could be added to handle that easy enough.

Jeff


--- git-pull-script.orig	2005-07-31 22:23:50.000000000 -0700
+++ git-pull-script	2005-08-22 13:01:22.000000000 -0700
@@ -4,13 +4,24 @@
 # cogito.]
 #

+LOCATION="$@"
+
+if [ ! $LOCATION ]
+then
+	if [ -f .git/location ]
+	then
+		LOCATION=`cat .git/location`
+	fi
+fi
+
 . git-sh-setup-script || die "Not a git archive"
-. git-parse-remote "$@"
+. git-parse-remote "$LOCATION"
 merge_name="$_remote_name"

-git-fetch-script "$@" || exit 1
+git-fetch-script "$LOCATION" || exit 1

 git-resolve-script \
 	"$(cat "$GIT_DIR"/HEAD)" \
 	"$(cat "$GIT_DIR"/FETCH_HEAD)" \
 	"Merge $merge_name"
+

^ 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