Git development
 help / color / mirror / Atom feed
* [PATCH 2/3] fetch, pull: ask config for remote information
From: Johannes Schindelin @ 2006-04-30 13:24 UTC (permalink / raw)
  To: git


Now you can say

[remote.junio]
	url = git://git.kernel.org/pub/scm/git/git.git
	pull = next:next

in your .git/config.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---

 git-parse-remote.sh |   55 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 51 insertions(+), 4 deletions(-)

5a1cf349639823183fce287be9f809d797f2cd84
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index c9b899e..8ce57c8 100755
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -4,13 +4,43 @@ # git-ls-remote could be called from out
 # this would fail in that case and would issue an error message.
 GIT_DIR=$(git-rev-parse --git-dir 2>/dev/null) || :;
 
+if [ -d "$GIT_DIR"/remotes -a "$GIT_REWRITE_REMOTES" = true ]; then
+	echo "Rewriting $GIT_DIR/remotes" >&2
+	error=0
+	# rewrite into config
+	{
+		cd "$GIT_DIR"/remotes
+		ls | while read f; do
+			name=$(echo -n "$f" | tr -c "A-Za-z0-9" ".")
+			sed -n \
+			-e "s/^URL: /remote.$name.url . /p" \
+			-e "s/^Pull: /remote.$name.pull ^$ /p" \
+			-e "s/^Push: /remote.$name.push ^$ /p" \
+			< "$f"
+		done
+		echo done
+	} | while read key regex value; do
+		case $key in
+		done)
+			if [ $error = 0 ]; then
+				mv "$GIT_DIR"/remotes "$GIT_DIR"/remotes.old
+			fi ;;
+		*)
+			git-repo-config $key "$value" $regex || error=1 ;;
+		esac
+	done
+fi
+
 get_data_source () {
 	case "$1" in
 	*/*)
 		# Not so fast.	This could be the partial URL shorthand...
 		token=$(expr "z$1" : 'z\([^/]*\)/')
 		remainder=$(expr "z$1" : 'z[^/]*/\(.*\)')
-		if test -f "$GIT_DIR/branches/$token"
+		if test "$(git-repo-config --get "remote.$token.url")"
+		then
+			echo config-partial
+		elif test -f "$GIT_DIR/branches/$token"
 		then
 			echo branches-partial
 		else
@@ -18,7 +48,10 @@ get_data_source () {
 		fi
 		;;
 	*)
-		if test -f "$GIT_DIR/remotes/$1"
+		if test "$(git-repo-config --get "remote.$1.url")"
+		then
+			echo config
+		elif test -f "$GIT_DIR/remotes/$1"
 		then
 			echo remotes
 		elif test -f "$GIT_DIR/branches/$1"
@@ -35,6 +68,15 @@ get_remote_url () {
 	case "$data_source" in
 	'')
 		echo "$1" ;;
+	config-partial)
+		token=$(expr "z$1" : '\([^/]*\)/')
+		remainder=$(expr "z$1" : '[^/]*/\(.*\)')
+		url=$(git-repo-config --get "remote.$token.url")
+		echo "$url/$remainder"
+		;;
+	config)
+		git-repo-config --get "remote.$1.url"
+		;;
 	remotes)
 		sed -ne '/^URL: */{
 			s///p
@@ -56,8 +98,10 @@ get_remote_url () {
 get_remote_default_refs_for_push () {
 	data_source=$(get_data_source "$1")
 	case "$data_source" in
-	'' | branches | branches-partial)
+	'' | config-partial | branches | branches-partial)
 		;; # no default push mapping, just send matching refs.
+	config)
+		git-repo-config --get-all "remote.$1.push" ;;
 	remotes)
 		sed -ne '/^Push: */{
 			s///p
@@ -111,8 +155,11 @@ # Returns list of src: (no store), or sr
 get_remote_default_refs_for_fetch () {
 	data_source=$(get_data_source "$1")
 	case "$data_source" in
-	'' | branches-partial)
+	'' | config-partial | branches-partial)
 		echo "HEAD:" ;;
+	config)
+		canon_refs_list_for_fetch \
+			$(git-repo-config --get-all "remote.$1.pull") ;;
 	branches)
 		remote_branch=$(sed -ne '/#/s/.*#//p' "$GIT_DIR/branches/$1")
 		case "$remote_branch" in '') remote_branch=master ;; esac
-- 
1.3.1.g38c00-dirty

^ permalink raw reply related

* [PATCH 1/3] builtin-push: also ask config for remote information
From: Johannes Schindelin @ 2006-04-30 13:23 UTC (permalink / raw)
  To: git


Now you can store your remote information in the config file like this:

[remote.upstream]
	url = me@company.com:the-project
	push = master:iceballs

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---

	Obviously, this is on top of the patch to parse Pull: lines, too.

 builtin-push.c |   33 +++++++++++++++++++++++++++++++++
 1 files changed, 33 insertions(+), 0 deletions(-)

e55eb69f6332087c45082e16ccbf4e510d721e29
diff --git a/builtin-push.c b/builtin-push.c
index 4e659f0..e3131ed 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -72,6 +72,36 @@ #define MAX_REFSPECS 10
 static int current_refspec = 0;
 static char *refspecs_[MAX_REFSPECS];
 
+static int repo_len = 0;
+static const char *repo_ = NULL;
+static int current_uri = 0;
+static const char **uri_;
+
+static int get_value(const char* key, const char* value)
+{
+	if (!strncmp(key, "remote.", 7) && !strncmp(key + 7, repo_, repo_len)) {
+		if (!strcmp(key + 7 + repo_len, ".url"))
+			uri_[current_uri++] = strdup(value);
+		else if (!strcmp(key + 7 + repo_len, ".push")
+				&& current_refspec < MAX_REFSPECS)
+			refspecs_[current_refspec++] = strdup(value);
+	}
+
+	return 0;
+}
+
+static int get_config_remotes_uri(const char *repo, const char *uri[MAX_URI])
+{
+	repo_len = strlen(repo);
+	repo_ = repo;
+	current_uri = 0;
+	uri_ = uri;
+
+	git_config(get_value);
+
+	return current_uri;
+}
+
 static int get_remotes_uri(const char *repo, const char *uri[MAX_URI])
 {
 	int n = 0;
@@ -153,6 +183,9 @@ static int get_uri(const char *repo, con
 	if (*repo != '/') {
 		current_refspec = 0;
 
+		n = get_config_remotes_uri(repo, uri);
+		if (n > 0)
+			return n;
 		n = get_remotes_uri(repo, uri);
 		if (n > 0)
 			return n;
-- 
1.3.1.g38c00-dirty

^ permalink raw reply related

* [PATCH] builtin-push: resurrect parsing of Push: lines
From: Johannes Schindelin @ 2006-04-30 12:05 UTC (permalink / raw)
  To: git


The C'ification of push left these behind.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---

 builtin-push.c |   26 +++++++++++++++++++++-----
 1 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/builtin-push.c b/builtin-push.c
index a0c1caa..4e659f0 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -68,6 +68,10 @@ static void set_refspecs(const char **re
 	expand_refspecs();
 }
 
+#define MAX_REFSPECS 10
+static int current_refspec = 0;
+static char *refspecs_[MAX_REFSPECS];
+
 static int get_remotes_uri(const char *repo, const char *uri[MAX_URI])
 {
 	int n = 0;
@@ -76,11 +80,17 @@ static int get_remotes_uri(const char *r
 	if (!f)
 		return -1;
 	while (fgets(buffer, BUF_SIZE, f)) {
+		int is_refspec;
 		char *s, *p;
 
-		if (strncmp("URL: ", buffer, 5))
+		if (!strncmp("URL: ", buffer, 5)) {
+			is_refspec = 0;
+			s = buffer + 5;
+		} else if (!strncmp("Push: ", buffer, 6)) {
+			is_refspec = 1;
+			s = buffer + 6;
+		} else
 			continue;
-		s = buffer + 5;
 
 		/* Remove whitespace at the head.. */
 		while (isspace(*s))
@@ -93,9 +103,10 @@ static int get_remotes_uri(const char *r
 		while (isspace(p[-1]))
 			*--p = 0;
 
-		uri[n++] = strdup(s);
-		if (n == MAX_URI)
-			break;
+		if (!is_refspec && n < MAX_URI)
+			uri[n++] = strdup(s);
+		else if (is_refspec && current_refspec < MAX_REFSPECS)
+			refspecs_[current_refspec++] = strdup(s);
 	}
 	fclose(f);
 	if (!n)
@@ -140,6 +151,8 @@ static int get_uri(const char *repo, con
 	int n;
 
 	if (*repo != '/') {
+		current_refspec = 0;
+
 		n = get_remotes_uri(repo, uri);
 		if (n > 0)
 			return n;
@@ -165,6 +178,9 @@ static int do_push(const char *repo)
 	if (n <= 0)
 		die("bad repository '%s'", repo);
 
+	if (refspec_nr == 0)
+		set_refspecs((const char**)refspecs_, current_refspec);
+
 	argv = xmalloc((refspec_nr + 10) * sizeof(char *));
 	argv[0] = "dummy-send-pack";
 	argc = 1;

^ permalink raw reply related

* Re: More qgit defects
From: Marco Costalba @ 2006-04-30 10:13 UTC (permalink / raw)
  To: Pavel Roskin; +Cc: ydirson, git
In-Reply-To: <1146390144.13634.9.camel@dv>

On 4/30/06, Pavel Roskin <proski@gnu.org> wrote:
> On Sun, 2006-04-30 at 05:26 -0400, Pavel Roskin wrote:
> > No, something still feels wrong.  I think even the gurus of GUI cannot
> > decide what to do if many frames need to be on screen.  Do you know that
> > many graphic designers hate GIMP for the overuse of dockable toplevel
> > windows?  Krita prefers dockable frames.  Photoshop uses non-dockable
> > child windows, I believe.
> >
> > The difference for qgit is that is generally wants bigger windows.
> > Whether the revision tree or the patch, having more space allows the
> > frame to present a better picture to the users.
>
> Replying to myself, sorry.  How about tabs?
>
> One tab for the main view.  Basically what we have now.
>
> Then tabs for revisions.  We can have more than one revision open, with
> the comment and with the patch, and and with affected files.  They will
> have the GUI centered on the change made by the revision.  StGIT commits
> would have an editable comment.
>
> Then tabs for files.  Again, possibly more than one.  Each tab about a
> specific file.  The file history, annotations, maybe even an editor for
> the file.
>
> The idea was inspired by Azureus.
>

Throwing in the tabs is a *very* big change, but, just to discuss....I
agree on the note that in qgit we have three different approaches:
fixed frames (revisions, file tree, affected files), detachable frames
(patch) and separate windows (annotations).

This is a bit strange and could give an odd GUI feeling.

I like the tab idea because it's clear and simple and fixes the 'many
approaches' problem. What I would suggest is, at least at first step,
do not change the main view and have only three tabs:

Tab1: Main view with revisions, file tree (hide able), affected files.
Tab2: Patch view with patch stat and diffs
Tab3: File history + file content/annotation view

In other words just put the frames/windows as are now in browse able
tabs. In this way main view still gives a good amount of information
without requiring changing the tab and the tabs are reserved for 'big
space' needed infos only.


   Marco

^ permalink raw reply

* Re: [PATCH] git builtin "push"
From: sean @ 2006-04-30  9:40 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: junkio, git
In-Reply-To: <Pine.LNX.4.64.0604292111570.9901@g5.osdl.org>

On Sat, 29 Apr 2006 21:22:49 -0700 (PDT)
Linus Torvalds <torvalds@osdl.org> wrote:

> Comments?  I wrote it so that it _should_ be fairly easy to re-use at 
> least the branches/remotes helper functions for a built-in "git fetch" as 
> well. But I didn't have the multi-URI issue with anything but pushing.


> +	if (strncmp(ref, "tags/", 5))
> +		return 0;
[...]
> +	for_each_ref(expand_one_ref);

How about a for_each_tag() function?


> +	int i, n = get_uri(repo, uri);
[...]
> +	n = get_uri(repo, uri);
> +	if (n <= 0)
> +		die("bad repository '%s'", repo);

get_uri() called twice.


The patch looks good and is easy to read, but wouldn't it be better
to require new c code to be thread safe and not leak memory?  Assuming
run-once-and-exit is making it difficult to push into a library.

Sean

builtin-push.c |   11 +++--------
refs.c         |    5 +++++
refs.h         |    1 +
3 files changed, 9 insertions(+), 8 deletions(-)

0e0e3cff71d65ac4cdc560ae143aded03acb4ceb
diff --git a/builtin-push.c b/builtin-push.c
index a0c1caa..0d74ed1 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -31,10 +31,6 @@ static int expand_one_ref(const char *re
 {
 	/* Ignore the "refs/" at the beginning of the refname */
 	ref += 5;
-
-	if (strncmp(ref, "tags/", 5))
-		return 0;
-
 	add_refspec(strdup(ref));
 	return 0;
 }
@@ -51,9 +47,8 @@ static void expand_refspecs(void)
 		 */
 		return;
 	}
-	if (!tags)
-		return;
-	for_each_ref(expand_one_ref);
+	if (tags)
+		for_each_tag(expand_one_ref);
 }
 
 static void set_refspecs(const char **refs, int nr)
@@ -156,7 +151,7 @@ static int get_uri(const char *repo, con
 static int do_push(const char *repo)
 {
 	const char *uri[MAX_URI];
-	int i, n = get_uri(repo, uri);
+	int i, n;
 	int remote;
 	const char **argv;
 	int argc;
diff --git a/refs.c b/refs.c
index 03398cc..c5a2dd0 100644
--- a/refs.c
+++ b/refs.c
@@ -178,6 +178,11 @@ int head_ref(int (*fn)(const char *path,
 	return 0;
 }
 
+int for_each_tag(int (*fn)(const char *path, const unsigned char *sha1))
+{
+	return do_for_each_ref("refs/tags", fn);
+}
+
 int for_each_ref(int (*fn)(const char *path, const unsigned char *sha1))
 {
 	return do_for_each_ref("refs", fn);
diff --git a/refs.h b/refs.h
index 2625596..b74cd4d 100644
--- a/refs.h
+++ b/refs.h
@@ -7,6 +7,7 @@ #define REFS_H
  */
 extern int head_ref(int (*fn)(const char *path, const unsigned char *sha1));
 extern int for_each_ref(int (*fn)(const char *path, const unsigned char *sha1));
+extern int for_each_tag(int (*fn)(const char *path, const unsigned char *sha1));
 
 /** Reads the refs file specified into sha1 **/
 extern int get_ref_sha1(const char *ref, unsigned char *sha1);
-- 
1.3.1.g9c203

^ permalink raw reply related

* Fwd: More qgit defects 2/2
From: Marco Costalba @ 2006-04-30  8:19 UTC (permalink / raw)
  To: git

I would like to forward this thread to the list in case someone find
it interesting and/or suggests improvements.

---------- Forwarded message ----------
From: Marco Costalba <mcostalba@gmail.com>
Date: Apr 30, 2006 10:11 AM
Subject: Re: More qgit defects
To: Pavel Roskin <proski@gnu.org>
Cc: ydirson@altern.org


Hi Pavel,
>
> I think the list items in the file window need a pop-up menu.  Without
> it, the users would not be able to discover what e.g. the double click
> would do.
>

yes, I agree.

> More generally, I feel that something is wrong with the user interface.
> I think gitk is doing it better with a single pane that has the comments
> and the diff.  Splitting the window horizontally in three panes seems to
> be too much, especially when one of the panes is used for diffs.
>

Please Pavel pull from latest qgit repo. I just pushed a patch that,
at least for my
browsing style, fixes this and IMHO is better then gitk.

Patch description is as follow:
"Usability enhancement: use 'P' key to quick toggle patch viewer

   One of the limitation of patch browsing in qgit is the use of two
   frames, one for revision logs and the other for patch viewer.

   If patch viewer is docked the space is normally limited by revision
   log frame. If patch viewer is undocked it is always at top level and
   hides main view and revision logs.

   So this patch adds a new key binding 'P' that hides/unhides diff
   viewer window.

   The intended use is simple: open patch viewer and undock it so to cover
   a good chunk of screen space, then press 'P' key and diff viewer will
   disappear.

   Now you can browse the revisions as usual and toggle diff viewer with 'P'
   key so to easily view both logs and patches without any space constrains.
"

After a little bit of using I have found this way very natural, quick
and, especially important for me, do not compromise patch view size.

What I do is to size the undocked patch viewer on my left screen, and
toggle the P key, but other adjustment are possible, see:

http://digilander.libero.it/mcostalba/qgit_P_1.png
http://digilander.libero.it/mcostalba/qgit_P_2.png

Tip: let your mouse be always over main list view so that patch view
does not steal the focus and you can browse only with keyboard arrows
as well with new key bindings (see F1).

Let me know what you think.

               Marco

^ permalink raw reply

* Fwd: More qgit defects 1/2
From: Marco Costalba @ 2006-04-30  8:19 UTC (permalink / raw)
  To: git

I would like to forward this thread to the list in case someone find
it interesting and/or suggests improvements.

---------- Forwarded message ----------
From: Pavel Roskin <proski@gnu.org>
Date: Apr 30, 2006 9:50 AM
Subject: Re: More qgit defects
To: Marco Costalba <mcostalba@gmail.com>
Cc: ydirson@altern.org


Hello, Marco!

On Fri, 2006-04-28 at 19:21 +0200, Marco Costalba wrote:
>   I have just pushed some patches according to your suggestions.

Thank you very much.

> If we don't find any issue/annoyance I would like to release 1.2 in
> the next couple of days, so to have a broader test base, and also
> because currently released 1.2rc2 has a bad crash bug.

I think it's good for the 1.2 release.

> So if you have any concerns or you would like to see something more
> added please let me know.

I think the list items in the file window need a pop-up menu.  Without
it, the users would not be able to discover what e.g. the double click
would do.

More generally, I feel that something is wrong with the user interface.
I think gitk is doing it better with a single pane that has the comments
and the diff.  Splitting the window horizontally in three panes seems to
be too much, especially when one of the panes is used for diffs.

Actually, qgit may be better for serious work, such as comparing the
description with the actual text.  But still, the panes are too small in
vertical direction, and if I tear off the diff, it will obscure
something.

The jumpiness of qgit has been largely fixed, but there are still cases
when mere selecting an item affect another window.

Is it really necessary to have a separate file window?  How different is
it from the main window with the "filter by tree" option on?  Can we
switch between diff and annotation?  More generally, what are the things
that the users are not normally viewing at the same time?

I'm not asking to fix anything, but qgit still feels odd to me.  I know
I'm not qualified to ask you to rearrange everything, because I'm not a
GUI specialist, and I don't see how qgit should work.

Maybe you could ask in the git list how to improve qgit?  I cannot find
any suitable forum about HIG (human interface guidelines), but if you
ask in the git list, maybe somebody will give you an idea where to ask.

--
Regards,
Pavel Roskin

^ permalink raw reply

* Re: [RFC] 'Download' stat
From: Junio C Hamano @ 2006-04-30  7:11 UTC (permalink / raw)
  To: Marco Costalba; +Cc: git
In-Reply-To: <e5bfff550604292159t5fac5436q73aecd5dbd56f516@mail.gmail.com>

"Marco Costalba" <mcostalba@gmail.com> writes:

> Hi all,
>
>     none is interested in (writing ;-)  ) a kind of 'download' summary stat?
>
> If git-daemon after a connection could save a record with fields like:
>
> - date
> - command requested (clone, pull, etc..)
> - current HEAD
>
> Perhaps would be possible to show nice stat/graph about repository
> activity and most downloaded repository content tags.

Perhaps "git-daemon --verbose --syslog".  Grep for loginfo in
daemon.c for details.

^ permalink raw reply

* Re: [PATCH] git builtin "push"
From: Junio C Hamano @ 2006-04-30  7:08 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0604292111570.9901@g5.osdl.org>

Linus Torvalds <torvalds@osdl.org> writes:

> Junio - I currently have a "push-all" script in each of the repos I 
> maintain. That has worked, but I'd just rather do something like
>
> 	git push all
>
> instead, and have it pick up the list of URI's from .git/remotes/all.

Makes sense.  I am still somewhat drunk (cachaça -- agua de
beber -- pretty good but strong stuff), so I will look at the
patch tomorrow, but...

> How do you do multi-targeted pushes?

I do not.  At least not that often.  I merge things up, test all
of "master", "maint", "next", and "pu" locally (the Meta/Doit
script, available after checking out "todo" branch in Meta/
subdirectory), then "git push ko-private" to push into ~/git of
the kernel.org machine and do "all branches" test again
(Meta/DoKernelOrg script).  Only after all that passes, I do a
"git push ko" from my local machine to push into the public
area, /pub/scm/git/git.git, of the kernel.org machine.

For Solaris and Cygwin testing, only occasionally, I do not push
but pull from the machines at work.  This is because I want to
catch breakage of pull side myself if there is one.

The only time I do multi-target push is just before cutting a
release.  In addition to "git push ko-private" to push into the
primary Opteron machine, I push to "git push ko-old-private" to
push into the i386 machine at kernel.org, "Meta/DoKernelOrg
master" (or "maint") to prepare RPMs for i386 there, and another
"Meta/DoKernelOrg master" (or "maint") on the Opteron to
prepare RPMs for x86-64.  So personally I never felt the need
for a multi-target push.

^ permalink raw reply

* [RFC] 'Download' stat
From: Marco Costalba @ 2006-04-30  4:59 UTC (permalink / raw)
  To: git

Hi all,

     none is interested in (writing ;-)  ) a kind of 'download' summary stat?

If git-daemon after a connection could save a record with fields like:

- date
- command requested (clone, pull, etc..)
- current HEAD

Perhaps would be possible to show nice stat/graph about repository
activity and most downloaded repository content tags.

Something like to know how many people has cloned/pulled  v2.6.17-rc2 
in date  2006/4/19

Perhaps is totally useless, just an idea.

    Marco

^ permalink raw reply

* [PATCH] git builtin "push"
From: Linus Torvalds @ 2006-04-30  4:22 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List


This adds a builtin "push" command, which is largely just a C'ification of 
the "git-push.sh" script.

Now, the reason I did it as a built-in is partly because it's yet another 
step on relying less on shell, but it's actually mostly because I've 
wanted to be able to push to _multiple_ repositories, and the most obvious 
and simplest interface for that would seem be to just have a "remotes" 
file that has multiple URL entries.

(For "pull", having multiple entries should either just select the first 
one, or you could fall back on the others on failure - your choice).

And quite frankly, it just became too damn messy to do that in shell. 
Besides, we actually have a fair amount of infrastructure in C, so it just 
wasn't that hard to do.

Of course, this is almost totally untested. It probably doesn't work for 
anything but the one trial I threw at it. "Simple" doesn't necessarily 
mean "obviously correct".

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

Comments?  I wrote it so that it _should_ be fairly easy to re-use at 
least the branches/remotes helper functions for a built-in "git fetch" as 
well. But I didn't have the multi-URI issue with anything but pushing.

Junio - I currently have a "push-all" script in each of the repos I 
maintain. That has worked, but I'd just rather do something like

	git push all

instead, and have it pick up the list of URI's from .git/remotes/all.

How do you do multi-targeted pushes?

diff --git a/Makefile b/Makefile
index 8ce27a6..9919992 100644
--- a/Makefile
+++ b/Makefile
@@ -214,7 +214,7 @@ LIB_OBJS = \
 	$(DIFF_OBJS)
 
 BUILTIN_OBJS = \
-	builtin-log.o builtin-help.o
+	builtin-log.o builtin-help.o builtin-push.o
 
 GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
 LIBS = $(GITLIBS) -lz
diff --git a/builtin-push.c b/builtin-push.c
new file mode 100644
index 0000000..a0c1caa
--- /dev/null
+++ b/builtin-push.c
@@ -0,0 +1,255 @@
+/*
+ * "git push"
+ */
+#include "cache.h"
+#include "refs.h"
+#include "run-command.h"
+#include "builtin.h"
+
+#define MAX_URI (16)
+
+static const char push_usage[] = "git push [--all] [--tags] [--force] <repository> [<refspec>...]";
+
+static int all = 0, tags = 0, force = 0, thin = 1;
+static const char *execute = NULL;
+
+#define BUF_SIZE (2084)
+static char buffer[BUF_SIZE];
+
+static const char **refspec = NULL;
+static int refspec_nr = 0;
+
+static void add_refspec(const char *ref)
+{
+	int nr = refspec_nr + 1;
+	refspec = xrealloc(refspec, nr * sizeof(char *));
+	refspec[nr-1] = ref;
+	refspec_nr = nr;
+}
+
+static int expand_one_ref(const char *ref, const unsigned char *sha1)
+{
+	/* Ignore the "refs/" at the beginning of the refname */
+	ref += 5;
+
+	if (strncmp(ref, "tags/", 5))
+		return 0;
+
+	add_refspec(strdup(ref));
+	return 0;
+}
+
+static void expand_refspecs(void)
+{
+	if (all) {
+		if (refspec_nr)
+			die("cannot mix '--all' and a refspec");
+
+		/*
+		 * No need to expand "--all" - we'll just use
+		 * the "--all" flag to send-pack
+		 */
+		return;
+	}
+	if (!tags)
+		return;
+	for_each_ref(expand_one_ref);
+}
+
+static void set_refspecs(const char **refs, int nr)
+{
+	if (nr) {
+		size_t bytes = nr * sizeof(char *);
+
+		refspec = xrealloc(refspec, bytes);
+		memcpy(refspec, refs, bytes);
+		refspec_nr = nr;
+	}
+	expand_refspecs();
+}
+
+static int get_remotes_uri(const char *repo, const char *uri[MAX_URI])
+{
+	int n = 0;
+	FILE *f = fopen(git_path("remotes/%s", repo), "r");
+
+	if (!f)
+		return -1;
+	while (fgets(buffer, BUF_SIZE, f)) {
+		char *s, *p;
+
+		if (strncmp("URL: ", buffer, 5))
+			continue;
+		s = buffer + 5;
+
+		/* Remove whitespace at the head.. */
+		while (isspace(*s))
+			s++;
+		if (!*s)
+			continue;
+
+		/* ..and at the end */
+		p = s + strlen(s);
+		while (isspace(p[-1]))
+			*--p = 0;
+
+		uri[n++] = strdup(s);
+		if (n == MAX_URI)
+			break;
+	}
+	fclose(f);
+	if (!n)
+		die("remote '%s' has no URL", repo);
+	return n;
+}
+
+static int get_branches_uri(const char *repo, const char *uri[MAX_URI])
+{
+	const char *slash = strchr(repo, '/');
+	int n = slash ? slash - repo : 1000;
+	FILE *f = fopen(git_path("branches/%.*s", n, repo), "r");
+	char *s, *p;
+	int len;
+
+	if (!f)
+		return 0;
+	s = fgets(buffer, BUF_SIZE, f);
+	fclose(f);
+	if (!s)
+		return 0;
+	while (isspace(*s))
+		s++;
+	if (!*s)
+		return 0;
+	p = s + strlen(s);
+	while (isspace(p[-1]))
+		*--p = 0;
+	len = p - s;
+	if (slash)
+		len += strlen(slash);
+	p = xmalloc(len + 1);
+	strcpy(p, s);
+	if (slash)
+		strcat(p, slash);
+	uri[0] = p;
+	return 1;
+}
+
+static int get_uri(const char *repo, const char *uri[MAX_URI])
+{
+	int n;
+
+	if (*repo != '/') {
+		n = get_remotes_uri(repo, uri);
+		if (n > 0)
+			return n;
+
+		n = get_branches_uri(repo, uri);
+		if (n > 0)
+			return n;
+	}
+
+	uri[0] = repo;
+	return 1;
+}
+
+static int do_push(const char *repo)
+{
+	const char *uri[MAX_URI];
+	int i, n = get_uri(repo, uri);
+	int remote;
+	const char **argv;
+	int argc;
+
+	n = get_uri(repo, uri);
+	if (n <= 0)
+		die("bad repository '%s'", repo);
+
+	argv = xmalloc((refspec_nr + 10) * sizeof(char *));
+	argv[0] = "dummy-send-pack";
+	argc = 1;
+	if (all)
+		argv[argc++] = "--all";
+	if (force)
+		argv[argc++] = "--force";
+	if (execute)
+		argv[argc++] = execute;
+	if (thin)
+		argv[argc++] = "--thin";
+	remote = argc;
+	argv[argc++] = "dummy-remote";
+	while (refspec_nr--)
+		argv[argc++] = *refspec++;
+	argv[argc] = NULL;
+
+	for (i = 0; i < n; i++) {
+		int error;
+		const char *dest = uri[i];
+		const char *sender = "git-send-pack";
+		if (!strncmp(dest, "http://", 7) ||
+		    !strncmp(dest, "https://", 8))
+			sender = "git-http-push";
+		argv[0] = sender;
+		argv[remote] = dest;
+		error = run_command_v(argc, argv);
+		if (!error)
+			continue;
+		switch (error) {
+		case -ERR_RUN_COMMAND_FORK:
+			die("unable to fork for %s", sender);
+		case -ERR_RUN_COMMAND_EXEC:
+			die("unable to exec %s", sender);
+		case -ERR_RUN_COMMAND_WAITPID:
+		case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
+		case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
+		case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
+			die("%s died with strange error", sender);
+		default:
+			return -error;
+		}
+	}
+	return 0;
+}
+
+int cmd_push(int argc, const char **argv, char **envp)
+{
+	int i;
+	const char *repo = "origin";	// default repository
+
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+
+		if (arg[0] != '-') {
+			repo = arg;
+			i++;
+			break;
+		}
+		if (!strcmp(arg, "--all")) {
+			all = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--tags")) {
+			tags = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--force")) {
+			force = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--thin")) {
+			thin = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--no-thin")) {
+			thin = 0;
+			continue;
+		}
+		if (!strncmp(arg, "--exec=", 7)) {
+			execute = arg;
+			continue;
+		}
+		usage(push_usage);
+	}
+	set_refspecs(argv + i, argc - i);
+	return do_push(repo);
+}
diff --git a/builtin.h b/builtin.h
index 47408a0..94fa9b5 100644
--- a/builtin.h
+++ b/builtin.h
@@ -20,4 +20,6 @@ extern int cmd_whatchanged(int argc, con
 extern int cmd_show(int argc, const char **argv, char **envp);
 extern int cmd_log(int argc, const char **argv, char **envp);
 
+extern int cmd_push(int argc, const char **argv, char **envp);
+
 #endif
diff --git a/git.c b/git.c
index 01b7e28..fd479e9 100644
--- a/git.c
+++ b/git.c
@@ -46,6 +46,7 @@ static void handle_internal_command(int 
 		{ "log", cmd_log },
 		{ "whatchanged", cmd_whatchanged },
 		{ "show", cmd_show },
+		{ "push", cmd_push },
 	};
 	int i;
 

^ permalink raw reply related

* Re: cg-clone not fetching all tags?
From: Junio C Hamano @ 2006-04-30  4:11 UTC (permalink / raw)
  To: Wolfgang Denk; +Cc: git, pasky
In-Reply-To: <20060429221114.557FC35288F@atlas.denx.de>

Wolfgang Denk <wd@denx.de> writes:

> In message <200604292342.16306.johannes.sixt@telecom.at> you wrote:
>>
>> There are two types of tags: They can point to
>> 1. a commit object
>> 2. a proper tag object (which in turn references the commit)
>> 
>> git-update-server-info seems to generate info only for case 2, and so are the 
>> only ones that http can fetch.
>
> And git-cvsimport (at least older versions of it)  imports  CVS  tags
> only as type 1 ?
>
> That would perfectly explain the situation. How can this be fixed?

I suspect there is no need to manufacture the tag.  Something
like this should do.

*WARNING* Since I do not do Porcelain, and I am not a Cogito
user, this is obviously untested.  In addition, I am seriously
drunk right now... 

-- >8 --
[PATCH] (cogito) Auto-follow lightweight tags as well.

---
diff --git a/cg-fetch b/cg-fetch
index 687e6b9..39764c7 100755
--- a/cg-fetch
+++ b/cg-fetch
@@ -218,7 +218,8 @@ fetch_tags()
 	git-ls-remote --tags "$uri" |
 		# SHA1 refs/tags/v0.99.8^{} --> SHA1 tags/v0.99.8
 		# where SHA1 is the object v0.99.8 tag points at.
-		sed -ne 's:\([^	]\)	refs/\(tags/.*\)^{}$:\1 \2:p' |
+		sed -n -e 's:\([^	]\)	refs/\(tags/.*\)^{}$:\1 \2:p' \
+		    -e 's:\([^	]\)	refs/\(tags/.*\)$:\1 \2:p|' \
 		while read sha1 tagname; do
 			# Do we have the tag itself?
 			[ -s "$_git/refs/$tagname" ] && continue

^ permalink raw reply related

* Re: cg-clone not fetching all tags?
From: Johannes Sixt @ 2006-04-29 22:54 UTC (permalink / raw)
  To: git
In-Reply-To: <20060429221114.557FC35288F@atlas.denx.de>

On Sunday 30 April 2006 00:11, Wolfgang Denk wrote:
> In message <200604292342.16306.johannes.sixt@telecom.at> you wrote:
> > There are two types of tags: They can point to
> > 1. a commit object
> > 2. a proper tag object (which in turn references the commit)
> >
> > git-update-server-info seems to generate info only for case 2, and so are
> > the only ones that http can fetch.
>
> And git-cvsimport (at least older versions of it)  imports  CVS  tags
> only as type 1 ?
>
> That would perfectly explain the situation. How can this be fixed?

Something like this tells you which one points to a commit or a tag:

for i in `find .git/refs/tags -type f`; do
  echo -n "$i "; git-cat-file -t $(cat $i);
done

Then for each commit-type $tag you do

git-tag -m ' ' $tag-new $tag
mv .git/refs/tags/$tag-new .git/refs/tags/$tag

(git-tag does not accept an empty tag message - if you dislike the 
single-blank-message, you have to manufacture your tags with git-mktag 
manually.)

-- Hannes

^ permalink raw reply

* Re: cg-clone not fetching all tags?
From: Wolfgang Denk @ 2006-04-29 22:11 UTC (permalink / raw)
  To: Johannes Sixt; +Cc: git, Petr Baudis
In-Reply-To: <200604292342.16306.johannes.sixt@telecom.at>

In message <200604292342.16306.johannes.sixt@telecom.at> you wrote:
>
> There are two types of tags: They can point to
> 1. a commit object
> 2. a proper tag object (which in turn references the commit)
> 
> git-update-server-info seems to generate info only for case 2, and so are the 
> only ones that http can fetch.

And git-cvsimport (at least older versions of it)  imports  CVS  tags
only as type 1 ?

That would perfectly explain the situation. How can this be fixed?

Best regards,
Viele Grüße,

Wolfgang Denk

-- 
Software Engineering:  Embedded and Realtime Systems,  Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
There is a multi-legged creature crawling on your shoulder.
	-- Spock, "A Taste of Armageddon", stardate 3193.9

^ permalink raw reply

* Re: cg-clone not fetching all tags?
From: Wolfgang Denk @ 2006-04-29 22:11 UTC (permalink / raw)
  To: Petr Baudis; +Cc: Git Mailing List
In-Reply-To: <20060429170542.GJ27689@pasky.or.cz>

Dear Petr,

in message <20060429170542.GJ27689@pasky.or.cz> you wrote:
> 
>   you need to run git-update-server-info every time you add or update a
> tag (or best every time you push). See the NOTES section of

I do this. Also, this does not seem to explain why  I  can  only  see
recent tags, but not old ones?

> cg-admin-setuprepo documentation for details on how to set it up to be
> called automagically at every push.

Actually I don't use push, but "cg-update" on the receiving  end.  Is
this a problem? 


Best regards,

Wolfgang Denk

-- 
Software Engineering:  Embedded and Realtime Systems,  Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
There's an old proverb that says just about whatever you want it to.

^ permalink raw reply

* [PATCH] cg-admin-rewritehist: fix reappearing files with --filter-tree.
From: Johannes Sixt @ 2006-04-29 21:45 UTC (permalink / raw)


With --filter-tree a working copy is checked out for each commit.
However, if a file is removed by a commit, the file is _not_ removed
from the working copy by git-checkout-index. This must be done explicitly,
otherwise the file becomes added back again.

Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at>

---

 cg-admin-rewritehist |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

26bb71a2d3d583d9eee10f4e950ff1b7d400e975
diff --git a/cg-admin-rewritehist b/cg-admin-rewritehist
index 7dd83cf..13ffb5d 100755
--- a/cg-admin-rewritehist
+++ b/cg-admin-rewritehist
@@ -213,10 +213,13 @@ while read commit; do
 
 	if [ "$filter_tree" ]; then
 		git-checkout-index -f -u -a
+		# files that $commit removed are now still in the working tree;
+		# remove them, else they would be added again
+		git-ls-files -z --others | xargs -0 rm -f
 		eval "$filter_tree"
 		git-diff-index -r $commit | cut -f 2- | tr '\n' '\0' | \
 			xargs -0 git-update-index --add --replace --remove
-		git-ls-files --others | tr '\n' '\0' | \
+		git-ls-files -z --others | \
 			xargs -0 git-update-index --add --replace --remove
 	fi
 
-- 
1.3.1.gaa6b

^ permalink raw reply related

* [PATCH] cg-admin-rewritehist: Seed the commit map with the parents specified with -r.
From: Johannes Sixt @ 2006-04-29 21:45 UTC (permalink / raw)


When the first commit is manufactured, its parents are looked up in the
commit map. However, without this patch the map is always empty at that time.
If the entire history is rewritten, this is no problem because the first
commit does not have any parents anyway. However, if -r is used to constrain
rewriting to only part of the history, this first commit is manufactured
incorrectly without parents because 'cat' fails.

Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at>

---

 cg-admin-rewritehist |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

977fc81815877a1e72040355b221fe8d62593eb7
diff --git a/cg-admin-rewritehist b/cg-admin-rewritehist
index 9fa4c2a..7dd83cf 100755
--- a/cg-admin-rewritehist
+++ b/cg-admin-rewritehist
@@ -141,6 +141,7 @@ _git_requires_root=1
 
 tempdir=.git-rewrite
 startrev=
+startrevparents=
 filter_env=
 filter_tree=
 filter_index=
@@ -152,6 +153,7 @@ while optparse; do
 		tempdir="$OPTARG"
 	elif optparse -r=; then
 		startrev="^$OPTARG^ $OPTARG $startrev"
+		startrevparents="$OPTARG^ $startrevparents"
 	elif optparse --env-filter=; then
 		filter_env="$OPTARG"
 	elif optparse --tree-filter=; then
@@ -186,6 +188,12 @@ ret=0
 
 mkdir ../map # map old->new commit ids for rewriting parents
 
+# seed with identity mappings for the parents where we start off
+for commit in $startrevparents; do
+	commit="$(git-rev-parse $commit)"
+	echo $commit > ../map/$commit
+done
+
 git-rev-list --topo-order HEAD $startrev | tac >../revs
 commits=$(cat ../revs | wc -l)
 
-- 
1.3.1.gaa6b

^ permalink raw reply related

* Re: cg-clone not fetching all tags?
From: Johannes Sixt @ 2006-04-29 21:42 UTC (permalink / raw)
  To: git
In-Reply-To: <20060429170542.GJ27689@pasky.or.cz>

On Saturday 29 April 2006 19:05, Petr Baudis wrote:
>   Hi,
>
> Dear diary, on Sat, Apr 29, 2006 at 04:00:42PM CEST, I got a letter
> where Wolfgang Denk <wd@denx.de> said that...
>
> > it seems that "cg-clone" does not fetch all tags any more - only  the
> > most  recent ones (modiufied in the last N days?) seem to be fetched?
> > [Eventually the "N days"  might  correspond  to  "changing  tools  to
> > version X", but I have no way to find out.]
> >
> > This happens only when using HTTP; using ssh  or  rsync  works  fine.
> > Also,  if  we follow the "cg-clone" by a "git-fetch -t" command, this
> > will load the missing tags.
> >
> > Is this intentional, or am I doing anything wrong?
> >
> > [For testing, try "cg-clone http://www.denx.de/git/u-boot.git"]
>
>   you need to run git-update-server-info every time you add or update a
> tag (or best every time you push). See the NOTES section of
> cg-admin-setuprepo documentation for details on how to set it up to be
> called automagically at every push.

There are two types of tags: They can point to
1. a commit object
2. a proper tag object (which in turn references the commit)

git-update-server-info seems to generate info only for case 2, and so are the 
only ones that http can fetch.

-- Hannes

^ permalink raw reply

* Re: Two gitweb feature requests
From: David Woodhouse @ 2006-04-29 21:38 UTC (permalink / raw)
  To: Ben Clifford; +Cc: Kay Sievers, git
In-Reply-To: <Pine.LNX.4.64.0604272250420.4963@mundungus.clifford.ac>

On Thu, 2006-04-27 at 22:54 +0000, Ben Clifford wrote:
> HTML has a <link> element which can be used to indicate alternate forms of 
> a page. Gitweb already generates one already to point people at the RSS 
> feeds.
> 
> Kinda messy to make all the git tools learn how to read HTML, though... 

They wouldn't necessarily need to. git-clone and git-pull attempt to use
URLs which wouldn't be used in normal gitweb usage -- for example, any
attempt to fetch http://git.infradead.org/?p=mtd-2.6.git/HEAD or
http://git.infradead.org/?p=mtd-2.6.git/refs/heads can be assumed to be
an attempt to clone or pull with git. So gitweb could be modified to
detect those URLs and give a simple textual redirect which the git tools
could understand.

-- 
dwmw2

^ permalink raw reply

* Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and
From: Jakub Narebski @ 2006-04-29 20:58 UTC (permalink / raw)
  To: git
In-Reply-To: <7viros1585.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:

> Jakub Narebski <jnareb@gmail.com> writes:
> 
>>  * "prior" - heads that represent topic branch merges
> 
> This is not any different from usual "parent" at all (but you
> have to think about it a bit to realize it).
[cut]
Thanks for an explanation.

I would say that "prior" is not THAT different from usual "parent",
rather than it is not ANY different.

My doubts about recording previous head of a "union" (pu-like) branch 
is that for merge (e.g. 'pu' to 'next', cherrypick to/from 'pu', 'pu'
rebase) is that for merge algorithm all parents are equivalent, with
eventual exception of first which can be treated special ('ours').

-- 
Jakub Narebski
Warsaw, Poland

^ permalink raw reply

* Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and
From: Junio C Hamano @ 2006-04-29 20:44 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git
In-Reply-To: <e30b48$ovk$1@sea.gmane.org>

Jakub Narebski <jnareb@gmail.com> writes:

>  * "prior" - heads that represent topic branch merges

This is not any different from usual "parent" at all (but you
have to think about it a bit to realize it).

Before talking about making a new commit object that links to
other related commits, let's first talk about what it means to
update the branch head ($GIT_DIR/refs/heads/<branch>) from
commit A to commit B.  Understanding what it means is more
fundamental.

A git "branch" points at the tip of one possible history of a
development.  As the often-used word "topic branch" tells you, a
"branch", i.e. that history, has a specific purpose.  The
purpose of my "master" branch is to give reasonably stable new
feature set and bugfixes, "next" to give testable ones, and "pu"
to collect remaining bits that are worthy of discussion.

When your branch head points at commit A and you update the head
to point at a different commit B, you are making this statement:

	The commit B suits the purpose of the branch better
	than the commit A.

Notice there may or may not be ancestry relation between these
two commits at this point of the discussion.  B may be a direct
child of commit A, a merge that has A as its first parent, a
merge that has A as its one of its parent (but not necessarily
the first), or a Nth-generation descendant if the update was a
fast forward merge from another branch.  It might even be an
ancestor if the update rewinds the history.

Among the above cases (and there may be others), in only two
cases you actually create a new commit to record that
statement [*1*].

The simplest case is when commit B is a direct, single-parent
child of commit A, and that statement is in your commit log
message.  "I started out from the commit A, and the result is
this tree.  The result suits what I am doing better than the
previous commit and I made the world a better place." -- the "I
started out from the commit A" part is on the parent header and
the rest is in the free-text.

When you are creating a merge of N parents, the principle is the
same.  Although in pure core-git terms all parents are equal, in
practice, the first parent has somewhat special meaning to you.
When the parents of commit B are A and X, you started out from
the commit A.  Then what are other parents?  You can read such a
commit this way:

	I started out from commit A and came up with this tree,
	which suits my purpose better.  While doing so, I have
	also considered what X has; and this result, commit B,
	suits my purpose better than X, too.

This is why a later merge with another branch that further
builds on top of X works so well.

    ----A----B
            /
       ----X----Y

If somebody built Y on X independently from us, when we merge
with Y, we say the merge base is X because B says "I've already
considered what X has" to do a 3-way merge.  While that is what
happens at the mechanical level, what is happening at the
philosophical level is we are taking "I consider that B is
better than X", part of the message seriously, which means "I
want to keep changes I made between X B".  Also the other person
who made Y made a similar statement that she considers Y is
better than X, and we try to preserve the changes between X and
Y in the automated part of the merge while preparing the tree to
commit the merge between B and Y.

Once you start reading the commit parent to mean " considering
what all of these commits have, what this new commit has suits
my purpose better", it becomes clear that the "previous" pointer
for a branch like my "pu" is just another "parent".

I rebuild "pu" from the tip of then-current "next", and merge
other topics in, and discard the previous "pu".  So it results
in this kind of graph:

                         o---o---o---o---o (updated "pu")
                        /   /   /   /  
        ---o---o---o---o
            \               \   \   \   \
             o---------------o---o---o---o (previous "pu")

But theoretically, I could include the previous "pu" tip as one
of the parents of the updated "pu" branch.

At the mechanical level, I start from then-current "next" and
merge each topic branch one-by-one on top of it.  But at the
philosophical level, what I am doing is to publish material that
shows a set of proposed changes that are more appropriate for
review by the curious than the previous round of "pu" head used
to have.  So the previous "pu" _is_ in the consideration while I
publish the updated "pu", although it is _not_ recorded anywhere.

After I come up with a fully merged tree, I could make a fake
Octopus that has the previous "pu" as its first parent and each
of the topic branch heads merged as second and subsequent
parents, with the resulting tree.  That would be more "honest"
at the philosophical level.

I am not going to actually suggest anybody doing this as a good
practice, but we can make such a commit with the current tool
like this:

        git checkout pu
	git tag -f prev-pu		;# remember where we were
	git reset --hard next		;# start at next
        git pull . topic-1		;# merge all remaining topics
        git pull . topic-2		;# ...
        git pull . topic-3
        ...
        git tag -f next-pu		;# this tree is what we want
        git reset --hard prev-pu	;# start from previous
        git pull --no-commit -s ours . next topic-1 topic-2 ...
	git read-tree -m -u next-pu	;# record a merge whose first
	git commit			;# parent is previous pu and
					;# has all the topics merged.
        

[Footnote]

*1* IOW, we _are_ losing some information by not recording the
fact that fast-forward was done while doing so.  

That record should _not_ be in the commit chain.  At the
mechanical level, recording that in the commit chain means two
criss-crossing branches never converge at the commit chain
level, which is already bad.  At the philosophical level, the
commit chain is a mesh of many possible "global" histories, and
the record that somebody (a particular branch in a particular
repository) was at what point in the mesh at given time does not
belong there.

But from the repository-owner's point of view, that _might_ be a
useful information to keep.  I am just saying this preemptively
so that if somebody wants to record it, that should not be
recorded in the commit object.

^ permalink raw reply

* Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and
From: Junio C Hamano @ 2006-04-29 19:30 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git
In-Reply-To: <e309vq$m2r$1@sea.gmane.org>

Jakub Narebski <jnareb@gmail.com> writes:

> IF (and that is big if) git commit header will be extended to have some
> extra "link" (enforcing connectivity) headers, like proposed "bind" for
> subprojects, "prev" for pu-like union branches, "merge-base" for merges,
> there would be repeated work on enforcing connectivity. Hence generic
> "link" header (formerly "related") proposal.

The "link <sha1> <type> <meta>" header extension was done
primarily for that reason this way.  I carried it in my "pu"
branch for a few days but Linus convinced me privately that it
was a bad idea, so it is not merged in "pu" anymore.  Just to
make it easy for people to view what we are discussing, I pushed
the branch head to jc/bind-2 topic branch, but the code will
_not_ be merged.

The code in commit.c to recognize and link the releated objects
pointed by the "link" header to the commit looked like below
(see 11bbee26 commit on that branch):

+       optr = &item->links;
+       while (!memcmp(bufptr, "link ", 5)) {
+               struct object *object;
+
+               if (!get_sha1_hex(bufptr + 5, parent) &&
+                   bufptr[45] == ' ' &&
+                   (object = lookup_unknown_object(parent)) != NULL) {
+                       struct object_list *l = xmalloc(sizeof(*l));
+                       l->item = object;
+                       l->next = *optr;
+                       l->name = NULL;
+                       *optr = l;
+                       optr = &l->next;
+                       n_refs++;
+                       bufptr += 45;
+               }
+               else
+                       return error("bad link in commit %s",
+                                    sha1_to_hex(item->object.sha1));
+               while (*bufptr++ != '\n')
+                       ; /* skip over subdirectory name */
+       }

But if your are going to introduce "merge-base" and similar
headers that have impact to connectivity traversal code, you can
easily change the !memcmp(buptr, "link ", 5) with a sequence of
"memcmp(foo) || memcmp(bar) || ...", and use the "l->name" field
to point at the header itself, so that the user of the resulting
commit object can easily tell what kind of link-like header it
is, and enforce further semantics that are specific to each kind
of such header on it.  The revision traversal change that was
done in a later commit (7091fd commit) does not have to change.

The code sharing aspect you brought up is a very important
issue.  This is revision traversal, which is really the central
part of git and needs deep thought to touch without breaking, so
we would like to avoid risking breaking it by repeatedly
touching it.  But that can be done without making the recorded
header something like "link <sha1> <type> <metainfo>" which is
too generic.

^ permalink raw reply

* Re: fatal: git-write-tree: not able to write tree
From: Junio C Hamano @ 2006-04-29 18:34 UTC (permalink / raw)
  To: colin; +Cc: junkio, git
In-Reply-To: <20060429132324.31638.qmail@science.horizon.com>

colin@horizon.com writes:

> diff --git a/git-am.sh b/git-am.sh
> index eab4aa8..872145b 100755
> --- a/git-am.sh
> +++ b/git-am.sh
> @@ -376,6 +376,13 @@ do
>  			echo "No changes - did you forget update-index?"
>  			stop_here $this
>  		fi
> +		unmerged=$(git-ls-files -u)
> +		if test -n "$unmerged"
> +		then
> +			echo "You still have unmerged paths in your index"
> +			echo "did you forget update-index?"
> +			stop_here $this
> +		fi
>  		apply_status=0
>  		;;
>  	esac
>
> Er... it's very non-obvious to me why you'd want to stick a workaround
> here when you could instead fix git-write-tree to do it.  That seems
> like The Right Thing.

As I said in an earlier message in the thread, I've considered
it, but that is a very risky thing to do, and write-tree is
definitely a wrong place to do it.  If we wanted to, the right
way would be to update-index using the output of "ls-files -u".

However, it would invite the user to mistakenly say --resolved
before resolving all paths.

> (It would also be helpful to mention at least one unmerged file by name.)

That is true.

^ permalink raw reply

* Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and
From: Jakub Narebski @ 2006-04-29 18:27 UTC (permalink / raw)
  To: git
In-Reply-To: <20060429165151.2570.qmail@science.horizon.com>

On Sat, 29 Apr 2006, linux@horizon.com wrote:
> 
> Well, the only reason that you need ANY commit in the repository is
> because it's part of history, and comparing it with other versions is
> meaningful.  So what trees, not already in the ancestry graph of a
> given commit, are useful to compare to?  In particular, useful for some
> automated process; manual comparisons can always be done manually.
> 
> Nothing's jumping out at me.  Any suggestions?

See below.

Not necessary all those require connectivity.
Most of them are not my ideas.

 * "prior" - heads that represent topic branch merges

    This is the "pu" branch case, where the head is a merge of several
    topic branches that is continually moved forward.

    topic branches     head
      ,___.   ,___.
     | TA1 | | TB1 |
      `---'   `---'    ,__.
         ^\_____^\____| H1 |
                       `--'

    + some topic branch changes and a republish:

      ,___.   ,___.
     | TA1 | | TB1 |
      `---'   `---'^   ,__.
        |^\_____^\____| H1 |
        |       |      `--'
      ,_|_.   ,_|_.      P
     | TA2 | | TB2 |     |
      `---'   `---'^     |
        ^       ^        |
      ,_|_.     |        |
     | TA3 |    |        |
      `---'     |      ,__.
         ^\______\____| H2 |
                       `--'

    key:  ^ = parent   P = prior


 * "bind" - for subprojects

   bind links from master project commit to externally managed embedded
   third-party project, for example Linux kernel for some mainly userspace
   project, or library or engine for some application. Additionally it
   provides root dir where to attach subproject.

 
 * "original" for rebase

   before rebase:

             A---B---C topic
            /
           /
          /
     D---E---F---G master

   after rebase

              ------A---B---C
             /      ^   ^   ^ 
            /       :   :   :
           /        A'--B'--C' topic
          /       /
     D---E---F---G master


   where ':' denotes "original" link. Note that old branch is not pointed by
   any head, and would be pruned without connectivity


 * "original" or "cherrypick" for cherry-picking

            A--------B---C bugfix
           /         ^
          /          :
     D---E---F---G---B'---H main


 * "revert" for reverting commits

-- 
Jakub Narebski

^ permalink raw reply

* Re: [RFC] [PATCH 0/5] Implement 'prior' commit object links (and
From: Jakub Narebski @ 2006-04-29 18:07 UTC (permalink / raw)
  To: git
In-Reply-To: <Pine.LNX.4.64.0604291006270.3701@g5.osdl.org>

Linus Torvalds wrote:

>  - Case 1: the
> 
>         merge-base <sha1>
[...]
>  - Case 2: the
> 
>         note merge-base <sha1>
[...]
>  - Case 3: the
> 
>         link <sha1> merge-base
[...]

> In short, the difference between three headers that on the face of it say
> exactly the same thing: "merge-base <sha1>", "note merge-base <sha1>", and
> "link merge-base <sha1>" is not that they have different syntax (hey, even
> the syntax itself is almost identical), but exactly the fact that they
> have different implications and _meaning_.
> 
> Two of the three have no unintended consequences. One ("note") has no
> technical "consequences" at _all_, by definition. The other "merge-base"
> has no technical "unintended" at all, because it's throught through, and
> has been fully defined.
> 
> The third? "unintended consequences". It doesn't have a clear definition
> ("It's cool. You can use it for any link you want"). So pretty much BY
> DESIGN, it's set up so that you don't know what the consequences of it
> will be for a project.
> 
> And that's why "case 3" it's bad. Even though it looks very much like the
> two other ones.

IF (and that is big if) git commit header will be extended to have some
extra "link" (enforcing connectivity) headers, like proposed "bind" for
subprojects, "prev" for pu-like union branches, "merge-base" for merges,
there would be repeated work on enforcing connectivity. Hence generic
"link" header (formerly "related") proposal. Having fsck report broken
links (or not), having purge removing commits (objects) reachable only via
"link" headers, having pull download commits via "link" headers... have I
forgot anything? It _seems_ that this part is common, and does not depend
on semantics.

But with "links" (connectivity headers) there always would be some other
consequences. For example info/grafts deals for now only with commit
parents, and extending the format could be difficult.

And of course if we want connectivity, this is for some reason, so the
"link" has some other consequences, for example "prev" and "merge-base" for
merging, "bind" for checkout, merge (but differently), etc.


I think that if it is 'helper' information (i.e. information which is
helpful, but we can do without it) and of no real importance to user then
use "note". If it is of importance to user (for example "cherrypick" or
"reverted") and of use to git, then repeat such info in "note" header to
avoid relying on parsing free-form part aka. commit comment. If
connectivity is needed... hmmm...

-- 
Jakub Narebski
Warsaw, Poland

^ 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