Git development
 help / color / mirror / Atom feed
* Re: [PATCH] git mv: Support moving submodules
From: Junio C Hamano @ 2008-09-12 22:19 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git
In-Reply-To: <20080912214129.14829.53058.stgit@localhost>

Petr Baudis <pasky@suse.cz> writes:

> diff --git a/builtin-mv.c b/builtin-mv.c
> index 4f65b5a..2970acc 100644
> --- a/builtin-mv.c
> +++ b/builtin-mv.c
> @@ -9,6 +9,7 @@
>  #include "cache-tree.h"
>  #include "string-list.h"
>  #include "parse-options.h"
> +#include "submodule.h"
>  
>  static const char * const builtin_mv_usage[] = {
>  	"git mv [options] <source>... <destination>",
> @@ -49,6 +50,24 @@ static const char *add_slash(const char *path)
>  	return path;
>  }
>  
> +static int ce_is_gitlink(int i)
> +{
> +	return i < 0 ? 0 : S_ISGITLINK(active_cache[i]->ce_mode);
> +}

This interface itself is ugly (why should a caller pass "it is unmerged or
does not exist" without checking?), and it also makes the hunk that begins
at 84/105 ugly.  Why not "path_is_gitlink(const char*)" and run
cache_name_pos() here instead?

The interface, even if it is internal, should be done with a better taste
than that, even though I understand that you wanted to reuse the cache_pos
for the source one while you check.

Oh, by the way, what should happen when you have an unmerged path in the
index and say "git mv path elsewhere" (this question is *not* limited to
submodules).  Compared to that, what _does_ happen with the current code,
and with your patch?

^ permalink raw reply

* Re: StGit question
From: Catalin Marinas @ 2008-09-12 22:18 UTC (permalink / raw)
  To: Clark Williams; +Cc: Karl Hasselström, git
In-Reply-To: <b0943d9e0809121515v53c6d593o8211b3cbbb8dfba4@mail.gmail.com>

On 12/09/2008, Catalin Marinas <catalin.marinas@gmail.com> wrote:
> On 12/09/2008, Clark Williams <clark.williams@gmail.com> wrote:
>  > Most of the time it's not more than one or two patches difference, so I think that it
>  >  can be handled manually for now. I'll definitely keep an eye on sync and merge though...
>
>
> As Karl said, we have some plans to allow collaboration between
>  multiple StGit repositories but we didn't have much time to look at it
>  recently. Karl's "merge" stuff looks promising though.
>
>  What "sync" does is that it allow the same set of patches between two
>  branches to be synchronised in case modifications happened on one of
>  these branches. In your situation, you would have to fetch the remote
>  branch, uncommit as in Karl's method and either import or sync the
>  remote patches with those on your local branch.

BTW, "sync" allows synchronisation with a series of patches stored in
a directory. So you can also share patches using exported repositories
with import and sync.

-- 
Catalin

^ permalink raw reply

* Re: StGit question
From: Catalin Marinas @ 2008-09-12 22:15 UTC (permalink / raw)
  To: Clark Williams; +Cc: Karl Hasselström, git
In-Reply-To: <48CA6367.9020300@gmail.com>

On 12/09/2008, Clark Williams <clark.williams@gmail.com> wrote:
> Most of the time it's not more than one or two patches difference, so I think that it
>  can be handled manually for now. I'll definitely keep an eye on sync and merge though...

As Karl said, we have some plans to allow collaboration between
multiple StGit repositories but we didn't have much time to look at it
recently. Karl's "merge" stuff looks promising though.

What "sync" does is that it allow the same set of patches between two
branches to be synchronised in case modifications happened on one of
these branches. In your situation, you would have to fetch the remote
branch, uncommit as in Karl's method and either import or sync the
remote patches with those on your local branch.

-- 
Catalin

^ permalink raw reply

* [StGit PATCH] Autosign newly created patches
From: Catalin Marinas @ 2008-09-12 21:55 UTC (permalink / raw)
  To: git; +Cc: Karl Hasselström

This patch adds the autosign configuration variable which is checked by
the "new" command to automatically sign the patch message.

Signed-off-by: Catalin Marinas <catalin.marinas@gmail.com>
---

BTW, what happened to the patchdescr.tmpl file? It doesn't seem to be
used anymore, however one can save a template file

 examples/gitconfig    |    3 +++
 stgit/commands/new.py |    8 +++++++-
 2 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/examples/gitconfig b/examples/gitconfig
index 4a36202..9efc089 100644
--- a/examples/gitconfig
+++ b/examples/gitconfig
@@ -14,6 +14,9 @@
 	# Automatically Bcc the address below
 	#autobcc = your.name@yourcompany.com
 
+	# Automatically sign newly created patches
+	#autosign = Signed-off-by
+
 	# Set to 'yes' if you don't want to use the 'resolved' command.
 	# 'refresh' will automatically mark the conflicts as resolved
 	#autoresolved = no
diff --git a/stgit/commands/new.py b/stgit/commands/new.py
index eb45e1b..4a58d52 100644
--- a/stgit/commands/new.py
+++ b/stgit/commands/new.py
@@ -21,6 +21,7 @@ from optparse import make_option
 from stgit import argparse, utils
 from stgit.commands import common
 from stgit.lib import git as gitlib, transaction
+from stgit.config import config
 
 help = 'create a new patch and make it the topmost one'
 usage = """%prog [options] [name]
@@ -72,8 +73,13 @@ def func(parser, options, args):
 
     # Add Signed-off-by: or similar.
     if options.sign_str != None:
+        sign_str = options.sign_str
+    else:
+        sign_str = config.get("stgit.autosign")
+
+    if sign_str != None:
         cd = cd.set_message(
-            utils.add_sign_line(cd.message, options.sign_str,
+            utils.add_sign_line(cd.message, sign_str,
                                 cd.committer.name, cd.committer.email))
 
     if options.save_template:

^ permalink raw reply related

* [StGit PATCH] Convert "sink" to the new infrastructure
From: Catalin Marinas @ 2008-09-12 22:01 UTC (permalink / raw)
  To: git; +Cc: Karl Hasselström

This patch converts the sink command to use stgit.lib. The behaviour
is also changed slightly so that it only allows to sink a set of
patches if there are applied once, otherwise it is equivalent to a
push. The new implementation also allows to bring a patch forward
towards the top based on the --to argument.

Signed-off-by: Catalin Marinas <catalin.marinas@gmail.com>
---

Before the final patch, I need to write a better test script.

I'm not sure about the conflict resolution. In this implementation, if
a conflict happens, the transaction is aborted. In case we allow
conflicts, I have to dig further on how to implement it with the new
transaction mechanism (I think "delete" does this).

An additional point - the transaction object supports functions like
pop_patches and push_patch. Should we change them for consistency and
simplicity? I.e., apart from current pop_patches with predicate add
functions that support popping a list or a single patch. The same goes
for push_patch.


stgit/commands/sink.py |   79 ++++++++++++++++++++++++++++++------------------
 1 files changed, 49 insertions(+), 30 deletions(-)

diff --git a/stgit/commands/sink.py b/stgit/commands/sink.py
index d8f79b4..cb94f99 100644
--- a/stgit/commands/sink.py
+++ b/stgit/commands/sink.py
@@ -16,13 +16,10 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 """
 
-import sys, os
-from optparse import OptionParser, make_option
-
-from stgit.commands.common import *
-from stgit.utils import *
-from stgit import stack, git
+from optparse import make_option
 
+from stgit.commands import common
+from stgit.lib import transaction
 
 help = 'send patches deeper down the stack'
 usage = """%prog [-t <target patch>] [-n] [<patches>]
@@ -32,7 +29,7 @@ push the specified <patches> (the current patch by default), and
 then push back into place the formerly-applied patches (unless -n
 is also given)."""
 
-directory = DirectoryGotoToplevel()
+directory = common.DirectoryHasRepositoryLib()
 options = [make_option('-n', '--nopush',
                        help = 'do not push the patches back after sinking',
                        action = 'store_true'),
@@ -42,33 +39,55 @@ options = [make_option('-n', '--nopush',
 def func(parser, options, args):
     """Sink patches down the stack.
     """
+    stack = directory.repository.current_stack
 
-    check_local_changes()
-    check_conflicts()
-    check_head_top_equal(crt_series)
-
-    oldapplied = crt_series.get_applied()
-    unapplied = crt_series.get_unapplied()
-    all = unapplied + oldapplied
-
-    if options.to and not options.to in oldapplied:
-        raise CmdException('Cannot sink below %s, since it is not applied'
-                           % options.to)
+    if not stack.patchorder.applied:
+        raise common.CmdException('No patches applied')
+    if options.to and not options.to in stack.patchorder.applied:
+        raise common.CmdException('Cannot sink below %s since it is not applied'
+                                  % options.to)
 
     if len(args) > 0:
-        patches = parse_patches(args, all)
+        patches = common.parse_patches(args, stack.patchorder.all)
     else:
-        current = crt_series.get_current()
-        if not current:
-            raise CmdException('No patch applied')
-        patches = [current]
+        # current patch
+        patches = stack.patchorder.applied[-1:]
+
+    if not patches:
+        raise common.CmdException('No patches to sink')
+    if options.to and options.to in patches:
+        raise common.CmdException('Cannot have a sinked patch as target')
+
+    trans = transaction.StackTransaction(stack, 'sink')
+
+    # pop any patches to be sinked in case they are applied
+    to_push = trans.pop_patches(lambda pn: pn in patches)
+
+    if options.to:
+        if options.to in to_push:
+            # this is the case where sinking actually brings some
+            # patches forward
+            for p in to_push:
+                if p == options.to:
+                    del to_push[:to_push.index(p)]
+                    break
+                trans.push_patch(p)
+        else:
+            # target patch below patches to be sinked
+            to_pop = trans.applied[trans.applied.index(options.to):]
+            to_push = to_pop + to_push
+            trans.pop_patches(lambda pn: pn in to_pop)
+    else:
+        # pop all the remaining patches
+        to_push = trans.applied + to_push
+        trans.pop_patches(lambda pn: True)
 
-    if oldapplied:
-        crt_series.pop_patch(options.to or oldapplied[0])
-    push_patches(crt_series, patches)
+    # push the sinked patches
+    for p in patches:
+        trans.push_patch(p)
 
     if not options.nopush:
-        newapplied = crt_series.get_applied()
-        def not_reapplied_yet(p):
-            return not p in newapplied
-        push_patches(crt_series, filter(not_reapplied_yet, oldapplied))
+        for p in to_push:
+            trans.push_patch(p)
+
+    trans.run()

^ permalink raw reply related

* Re: [PATCH 2/6] git rm: Support for removing submodules
From: Junio C Hamano @ 2008-09-12 21:59 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git
In-Reply-To: <7v8wtxniez.fsf@gitster.siamese.dyndns.org>

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

>> +{
>> +	char *key = submodule_by_path(name);
>> +	char *sectend = strrchr(key, '.');
>> +
>> +	assert(sectend);
>> +	*sectend = 0;
>
> Here is one caller I questioned in my comments on [1/6]...

Another thing --- can submodule_by_path() ever return NULL saying "I do
not see one in the configuration"?

^ permalink raw reply

* Re: [PATCH 1/6] submodule.*: Introduce simple C interface for submodule lookup by path
From: Petr Baudis @ 2008-09-12 21:58 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vsks5njmg.fsf@gitster.siamese.dyndns.org>

On Fri, Sep 12, 2008 at 02:23:51PM -0700, Junio C Hamano wrote:
> Petr Baudis <pasky@suse.cz> writes:
> 
> > +static int gitmodules_worker(const char *key, const char *value, void *info_)
> 
> Won't you ever have different kind of work in the future?
> find_submodule_by_path(), perhaps?

Good point.

> > +{
> > +	struct gitmodules_info *info = info_;
> > +	const char *subkey;
> > +
> > +	if (prefixcmp(key, "submodule."))
> > +		return 0;
> > +
> > +	subkey = strrchr(key, '.');
> > +	if (!subkey)
> > +		return 0;
> 
> This cannot happen; you made sure the thing begins with "submodule."
> already.
> 
> > +	if (strcmp(subkey, ".path"))
> > +		return 0;
> 
> This will miss a misconfigured "submodule.path" (two level).
> 
> I can understand if this part were:
> 
> 	subkey = strrchr(key, '.');
>         if (!subkey || subkey == key + strlen("submodule.") - 1)
>         	return 0;

This looks strange, but I think I see what do you mean. I will use

if (strcmp(subkey, ".path") || subkey == key + strlen("submodule.") - 1)

> > +	if (strcmp(value, info->path))
> > +		return 0;
> 
> This will segfault on a misconfigured:
> 
> 	[submodule "xyzzy"]
>         	path

Thanks.

> > +	/* Found the key to change. */
> > +	if (info->key) {
> > +		error("multiple submodules live at path `%s'", info->path);
> 
> Why is this "error()", not "warning()"?

Matter of taste, I suppose. I have changed this to warning(), though it
is dubious configuration at best.

> > +		/* The last one is supposed to win. */
> > +		free(info->key);
> > +	}
> > +	info->key = xstrdup(key);
> > +	return 0;
> 
> Have to wonder if it makes easier for the users if this function kept only
> "xyzzy" out of "submodule.xyzzy.path", not the whole thing.  Cannot judge
> without actual callers.

They follow up in the next patches. ;-)  They use the submodule name
only to access the configuration again, so this format is the most
convenient for them.

> > +}
> > +
> > +char *submodule_by_path(const char *path)
> > +{
> > +	struct gitmodules_info info = { path, NULL };
> > +
> > +	config_exclusive_filename = ".gitmodules";
> > +	if (git_config(gitmodules_worker, &info))
> > +		die("cannot process .gitmodules");
> > +	if (!info.key)
> > +		die("the submodule of `%s' not found in .gitmodules", path);
> > +	config_exclusive_filename = NULL;
> > +
> > +	return info.key;
> > +}
> > diff --git a/submodule.h b/submodule.h
> > new file mode 100644
> > index 0000000..bc74fa0
> > --- /dev/null
> > +++ b/submodule.h
> > @@ -0,0 +1,8 @@
> > +#ifndef SUBMODULE_H
> > +#define SUBMODULE_H
> > +
> > +/* Find submodule living at given path in .gitmodules and return the key
> > + * of its path config variable (dynamically allocated). */
> 
> Style?

Would you seriously find it prettier with the newline?

$ git grep '^[^/]*[a-z][^/]*\*/$' *.c | wc -l
37

-- 
				Petr "Pasky" Baudis
The next generation of interesting software will be done
on the Macintosh, not the IBM PC.  -- Bill Gates

^ permalink raw reply

* [StGit PATCH] Do not crash if a patch log ref is missing
From: Catalin Marinas @ 2008-09-12 21:54 UTC (permalink / raw)
  To: git; +Cc: Karl Hasselström

Since we'll get rid of the individual patch logs, StGit should ignore if
such a ref is missing when deleting the compatibility patch files.

Signed-off-by: Catalin Marinas <catalin.marinas@gmail.com>
---
 stgit/lib/stack.py |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/stgit/lib/stack.py b/stgit/lib/stack.py
index 9cb3967..1059955 100644
--- a/stgit/lib/stack.py
+++ b/stgit/lib/stack.py
@@ -68,7 +68,11 @@ class Patch(object):
             for f in os.listdir(self.__compat_dir):
                 os.remove(os.path.join(self.__compat_dir, f))
             os.rmdir(self.__compat_dir)
-        self.__stack.repository.refs.delete(self.__log_ref)
+        try:
+            # this compatibility log ref might not exist
+            self.__stack.repository.refs.delete(self.__log_ref)
+        except KeyError:
+            pass
     def set_commit(self, commit, msg):
         self.__write_compat_files(commit, msg)
         self.__stack.repository.refs.set(self.__ref, commit, msg)

^ permalink raw reply related

* Re: [PATCH 2/6] git rm: Support for removing submodules
From: Junio C Hamano @ 2008-09-12 21:49 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git, gitster
In-Reply-To: <20080912210902.31628.7325.stgit@localhost>

Petr Baudis <pasky@suse.cz> writes:

> @@ -20,7 +20,8 @@ and no updates to their contents can be staged in the index,
>  though that default behavior can be overridden with the `-f` option.
>  When '--cached' is given, the staged content has to
>  match either the tip of the branch or the file on disk,
> -allowing the file to be removed from just the index.
> +allowing the file to be removed from just the index;
> +this is always the case when removing submodules.

Sorry, I read this three times but "this" is unclear to me.  Different and
mutually incompatible interpretations I tried to understand it are:

 (1) When removing submodules, whether --cached or not, the index can
     match either HEAD or the work tree; this is different from removing
     regular blobs where the index must match with HEAD without --cached
     nor -f;

 (2) When removing submodules with --cached, the index can match either
     HEAD or the work tree and it is removed only from the index.  You
     cannot remove submodules without --cached;

 (3) When removing submodules, the index can match either HEAD or the work
     tree and it is removed only from the index, even if you did not give
     --cached;

It later becomes clear that you meant (3) in the second hunk, but the
first time reader of the resulting document (not this patch) won't be
reading from bottom to top.

This is a leftover issue from ealier documentation 25dc720 (Clarify and
fix English in "git-rm" documentation, 2008-04-16), but the description is
unclear what should happen while working towards the initial commit
(i.e. no HEAD yet).  I think check_local_mod() allows removal in such a
case.  Perhaps you can clarify the point while at it, please?

> diff --git a/builtin-rm.c b/builtin-rm.c
> index 6bd8211..7475de2 100644
> --- a/builtin-rm.c
> +++ b/builtin-rm.c
> ...
> -static void add_list(const char *name)
> +static void add_list(const char *name, int is_gitlink)
>  {
>  	if (list.nr >= list.alloc) {
>  		list.alloc = alloc_nr(list.alloc);
> -		list.name = xrealloc(list.name, list.alloc * sizeof(const char *));
> +		list.info = xrealloc(list.info, list.alloc * sizeof(*list.info));
>  	}

ALLOC_GROW()?

> @@ -38,6 +44,13 @@ static int remove_file(const char *name)
>  	if (ret && errno == ENOENT)
>  		/* The user has removed it from the filesystem by hand */
>  		ret = errno = 0;
> +	if (ret && errno == EISDIR) {
> +		/* This is a gitlink entry; try to remove at least the
> +		 * directory if the submodule is not checked out; we always
> +		 * leave the checked out ones as they are */

	/*
	 * Style?
         * for a multi-line comment.
         */

> +static void remove_submodule(const char *name)
> +{
> +	char *key = submodule_by_path(name);
> +	char *sectend = strrchr(key, '.');
> +
> +	assert(sectend);
> +	*sectend = 0;

Here is one caller I questioned in my comments on [1/6].  It is clear this
caller wants to use "submodule.xyzzy" out of "submodule.xyzzy.path".  The
function returning "submodule.xyzzy.path" does not feel like a clean and
reusable interface to me.  I'd suggest either returning "submodule.xyzzy"
(that's too specialized only for this caller to my taste, though), or just
"xyzzy" and have the caller synthesize whatever string it wants to use
(yes, it loses microoptimization but do we really care about it in this
codepath?), if you have other callers that want different strings around
"xyzzy".

> @@ -140,7 +169,7 @@ static struct option builtin_rm_options[] = {
>  
>  int cmd_rm(int argc, const char **argv, const char *prefix)
>  {
> -	int i, newfd;
> +	int i, newfd, subs;

Perhaps hoist "int removed" up one scope level and reuse it?  I misread
that you are counting the number of gitlinks in the index, not the number
of gitlinks that is being removed, on my first read.  The variable is used
for the latter.

Other than that I did not see anything questionable in [2/6].

^ permalink raw reply

* [PATCH] git mv: Support moving submodules
From: Petr Baudis @ 2008-09-12 21:42 UTC (permalink / raw)
  To: git; +Cc: gitster
In-Reply-To: <20080912210908.31628.50439.stgit@localhost>

This patch adds support for moving submodules to 'git mv', including
rewriting of the .gitmodules file to reflect the movement.

Signed-off-by: Petr Baudis <pasky@suse.cz>
---

I'm sorry, I was careless - this is the correct patch version, referring to
string_list_item.string instead of .path.

Also, the testsuite in patch 4 is for some reason marked as (c)'d by Dscho.
Not that it would be a big deal.

 builtin-mv.c |   37 +++++++++++++++++++++++++++++++++----
 1 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/builtin-mv.c b/builtin-mv.c
index 4f65b5a..2970acc 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -9,6 +9,7 @@
 #include "cache-tree.h"
 #include "string-list.h"
 #include "parse-options.h"
+#include "submodule.h"
 
 static const char * const builtin_mv_usage[] = {
 	"git mv [options] <source>... <destination>",
@@ -49,6 +50,24 @@ static const char *add_slash(const char *path)
 	return path;
 }
 
+static int ce_is_gitlink(int i)
+{
+	return i < 0 ? 0 : S_ISGITLINK(active_cache[i]->ce_mode);
+}
+
+static void rename_submodule(struct string_list_item *i)
+{
+	char *key = submodule_by_path(i->string);
+
+	config_exclusive_filename = ".gitmodules";
+	if (git_config_set(key, (const char *) i->util))
+		die("cannot update .gitmodules");
+	config_exclusive_filename = NULL;
+
+	free(key);
+}
+
+
 static struct lock_file lock_file;
 
 int cmd_mv(int argc, const char **argv, const char *prefix)
@@ -65,6 +84,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 	enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
 	struct stat st;
 	struct string_list src_for_dst = {NULL, 0, 0, 0};
+	/* .string is source path, .util is destination path */
+	struct string_list submodules = {NULL, 0, 0, 0};
 
 	git_config(git_default_config, NULL);
 
@@ -84,7 +105,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 		/* special case: "." was normalized to "" */
 		destination = copy_pathspec(dest_path[0], argv, argc, 1);
 	else if (!lstat(dest_path[0], &st) &&
-			S_ISDIR(st.st_mode)) {
+			S_ISDIR(st.st_mode) &&
+			!ce_is_gitlink(cache_name_pos(dest_path[0], strlen(dest_path[0])))) {
 		dest_path[0] = add_slash(dest_path[0]);
 		destination = copy_pathspec(dest_path[0], argv, argc, 1);
 	} else {
@@ -96,7 +118,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 	/* Checking */
 	for (i = 0; i < argc; i++) {
 		const char *src = source[i], *dst = destination[i];
-		int length, src_is_dir;
+		int length, src_is_dir, src_cache_pos;
 		const char *bad = NULL;
 
 		if (show_only)
@@ -111,7 +133,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 		} else if ((src_is_dir = S_ISDIR(st.st_mode))
 				&& lstat(dst, &st) == 0)
 			bad = "cannot move directory over file";
-		else if (src_is_dir) {
+		else if ((src_cache_pos = cache_name_pos(src, length)) < 0 && src_is_dir) {
 			const char *src_w_slash = add_slash(src);
 			int len_w_slash = length + 1;
 			int first, last;
@@ -177,7 +199,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 				} else
 					bad = "Cannot overwrite";
 			}
-		} else if (cache_name_pos(src, length) < 0)
+		} else if (src_cache_pos < 0)
 			bad = "not under version control";
 		else if (string_list_has_string(&src_for_dst, dst))
 			bad = "multiple sources for the same target";
@@ -214,10 +236,17 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 
 		pos = cache_name_pos(src, strlen(src));
 		assert(pos >= 0);
+		if (ce_is_gitlink(pos))
+			string_list_insert(src, &submodules)->util = (void *) dst;
 		if (!show_only)
 			rename_cache_entry_at(pos, dst);
 	}
 
+	for (i = 0; i < submodules.nr; i++)
+		rename_submodule(&submodules.items[i]);
+	if (submodules.nr > 0 && add_file_to_cache(".gitmodules", 0))
+		die("cannot add new .gitmodules to the index");
+
 	if (active_cache_changed) {
 		if (write_cache(newfd, active_cache, active_nr) ||
 		    commit_locked_index(&lock_file))

^ permalink raw reply related

* Re: [PATCH 1/6] submodule.*: Introduce simple C interface for submodule lookup by path
From: Jakub Narebski @ 2008-09-12 21:35 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Petr Baudis, git
In-Reply-To: <7vsks5njmg.fsf@gitster.siamese.dyndns.org>

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

> Petr Baudis <pasky@suse.cz> writes:

> > +{
> > +	struct gitmodules_info *info = info_;
> > +	const char *subkey;
> > +
> > +	if (prefixcmp(key, "submodule."))
> > +		return 0;
> > +
> > +	subkey = strrchr(key, '.');
> > +	if (!subkey)
> > +		return 0;
> 
> This cannot happen; you made sure the thing begins with "submodule."
> already.
[cut]

Are there any api to access and manipulate configuration,
including fqvn with the subsection part, instead of having
to do this again and again?

-- 
Jakub Narebski
Poland
ShadeHawk on #git

^ permalink raw reply

* Re: [PATCH 1/6] submodule.*: Introduce simple C interface for submodule lookup by path
From: Junio C Hamano @ 2008-09-12 21:23 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git
In-Reply-To: <20080912210857.31628.7605.stgit@localhost>

Petr Baudis <pasky@suse.cz> writes:

> +static int gitmodules_worker(const char *key, const char *value, void *info_)

Won't you ever have different kind of work in the future?
find_submodule_by_path(), perhaps?

> +{
> +	struct gitmodules_info *info = info_;
> +	const char *subkey;
> +
> +	if (prefixcmp(key, "submodule."))
> +		return 0;
> +
> +	subkey = strrchr(key, '.');
> +	if (!subkey)
> +		return 0;

This cannot happen; you made sure the thing begins with "submodule."
already.

> +	if (strcmp(subkey, ".path"))
> +		return 0;

This will miss a misconfigured "submodule.path" (two level).

I can understand if this part were:

	subkey = strrchr(key, '.');
        if (!subkey || subkey == key + strlen("submodule.") - 1)
        	return 0;

> +	if (strcmp(value, info->path))
> +		return 0;

This will segfault on a misconfigured:

	[submodule "xyzzy"]
        	path

> +	/* Found the key to change. */
> +	if (info->key) {
> +		error("multiple submodules live at path `%s'", info->path);

Why is this "error()", not "warning()"?

> +		/* The last one is supposed to win. */
> +		free(info->key);
> +	}
> +	info->key = xstrdup(key);
> +	return 0;

Have to wonder if it makes easier for the users if this function kept only
"xyzzy" out of "submodule.xyzzy.path", not the whole thing.  Cannot judge
without actual callers.

> +}
> +
> +char *submodule_by_path(const char *path)
> +{
> +	struct gitmodules_info info = { path, NULL };
> +
> +	config_exclusive_filename = ".gitmodules";
> +	if (git_config(gitmodules_worker, &info))
> +		die("cannot process .gitmodules");
> +	if (!info.key)
> +		die("the submodule of `%s' not found in .gitmodules", path);
> +	config_exclusive_filename = NULL;
> +
> +	return info.key;
> +}
> diff --git a/submodule.h b/submodule.h
> new file mode 100644
> index 0000000..bc74fa0
> --- /dev/null
> +++ b/submodule.h
> @@ -0,0 +1,8 @@
> +#ifndef SUBMODULE_H
> +#define SUBMODULE_H
> +
> +/* Find submodule living at given path in .gitmodules and return the key
> + * of its path config variable (dynamically allocated). */

Style?

> +extern char *submodule_by_path(const char *path);
> +
> +#endif

^ permalink raw reply

* [PATCH 6/6] git submodule add: Fix naming clash handling
From: Petr Baudis @ 2008-09-12 21:09 UTC (permalink / raw)
  To: git; +Cc: gitster
In-Reply-To: <20080912210817.31628.69014.stgit@localhost>

This patch fixes git submodule add behaviour when we add submodule
living at a same path as logical name of existing submodule. This
can happen e.g. in case the user git mv's the previous submodule away
and then git submodule add's another under the same name.

A test-case is obviously included.

This is not completely satisfactory since .git/config cross-commit
conflicts can still occur. A question is whether this is worth
handling, maybe it would be worth adding some kind of randomization
of the autogenerated submodule name, e.g. appending $$ or a timestamp.

Signed-off-by: Petr Baudis <pasky@suse.cz>
---

 git-submodule.sh           |   15 ++++++++++++---
 t/t7400-submodule-basic.sh |   11 +++++++++++
 2 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 1c39b59..3e4d839 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -201,10 +201,19 @@ cmd_add()
 	git add "$path" ||
 	die "Failed to add submodule '$path'"
 
-	git config -f .gitmodules submodule."$path".path "$path" &&
-	git config -f .gitmodules submodule."$path".url "$repo" &&
+	name="$path"
+	if git config -f .gitmodules submodule."$name".path; then
+		name="$path~"; i=1;
+		while git config -f .gitmodules submodule."$name".path; do
+			name="$path~$i"
+			i=$((i+1))
+		done
+	fi
+
+	git config -f .gitmodules submodule."$name".path "$path" &&
+	git config -f .gitmodules submodule."$name".url "$repo" &&
 	git add .gitmodules ||
-	die "Failed to register submodule '$path'"
+	die "Failed to register submodule '$path' (name '$name')"
 }
 
 #
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 8a002bc..0d12a37 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -235,4 +235,15 @@ test_expect_success 'submodule add -b' '
 
 '
 
+test_expect_success 'submodule add auto-naming clash' '
+
+	git submodule add "$(pwd)/init2/.git" example &&
+	test -d example/.git &&
+	[ "$(git config -f .gitmodules submodule.example.url)" = "$(pwd)/init2" ] &&
+	[ "$(git config -f .gitmodules submodule.example.path)" = "init" ]
+	[ "$(git config -f .gitmodules submodule.example~.url)" = "$(pwd)/init2/.git" ] &&
+	[ "$(git config -f .gitmodules submodule.example~.path)" = "example" ]
+
+'
+
 test_done

^ permalink raw reply related

* [PATCH 5/6] t7400: Add short "git submodule add" testsuite
From: Petr Baudis @ 2008-09-12 21:09 UTC (permalink / raw)
  To: git; +Cc: gitster
In-Reply-To: <20080912210817.31628.69014.stgit@localhost>

This patch introduces basic tests for

	git submodule add

covering the basic functionality and the -b parameter.

A trivial update --init test fix freeloads on this commit as well.

Signed-off-by: Petr Baudis <pasky@suse.cz>
---

 t/t7400-submodule-basic.sh |   28 +++++++++++++++++++++++++++-
 1 files changed, 27 insertions(+), 1 deletions(-)

diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index be73f7b..8a002bc 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -200,7 +200,7 @@ test_expect_success 'update --init' '
 
 	mv init init2 &&
 	git config -f .gitmodules submodule.example.url "$(pwd)/init2" &&
-	git config --remove-section submodule.example
+	git config --remove-section submodule.example &&
 	git submodule update init > update.out &&
 	grep "not initialized" update.out &&
 	test ! -d init/.git &&
@@ -209,4 +209,30 @@ test_expect_success 'update --init' '
 
 '
 
+test_expect_success 'submodule add' '
+
+	git submodule add "$(pwd)/init2" init-added &&
+	test -d init-added/.git &&
+	[ "$(git config -f .gitmodules submodule.init-added.url)" = "$(pwd)/init2" ] &&
+	[ "$(git config -f .gitmodules submodule.init-added.path)" = "init-added" ]
+
+'
+
+test_expect_success 'submodule add -b' '
+
+	(
+		cd init2 &&
+		git checkout -b branch &&
+		echo t >s &&
+		git add s &&
+		git commit -m "change branch" &&
+		git checkout master
+	) &&
+	git submodule add -b branch -- "$(pwd)/init2" init-added-b &&
+	test -d init-added-b/.git &&
+	[ "$(git config -f .gitmodules submodule.init-added-b.url)" = "$(pwd)/init2" ] &&
+	[ "$(cd init2 && git rev-parse branch)" = "$(cd init-added-b && git rev-parse HEAD)" ]
+
+'
+
 test_done

^ permalink raw reply related

* [PATCH 4/6] t7403: Submodule git mv, git rm testsuite
From: Petr Baudis @ 2008-09-12 21:09 UTC (permalink / raw)
  To: git; +Cc: gitster
In-Reply-To: <20080912210817.31628.69014.stgit@localhost>

The testsuite for newly added submodule support in git mv, git rm.

Signed-off-by: Petr Baudis <pasky@suse.cz>
---

 t/t7403-submodule-mvrm.sh |  242 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 242 insertions(+), 0 deletions(-)
 create mode 100755 t/t7403-submodule-mvrm.sh

diff --git a/t/t7403-submodule-mvrm.sh b/t/t7403-submodule-mvrm.sh
new file mode 100755
index 0000000..9b50d6a
--- /dev/null
+++ b/t/t7403-submodule-mvrm.sh
@@ -0,0 +1,242 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Johannes Schindelin
+#
+
+test_description='Test submodules support in git mv and git rm'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+	(mkdir sub-repo &&
+	 cd sub-repo &&
+	 git init &&
+	 echo file > file &&
+	 git add file &&
+	 git commit -m "sub initial") &&
+	(cp -r sub-repo sub2-repo &&
+	 cd sub2-repo &&
+	 echo file2 > file &&
+	 git add file &&
+	 git commit -m "sub commit2") &&
+	git submodule add "$(pwd)/sub-repo" sub &&
+	git submodule add "$(pwd)/sub2-repo" sub2 &&
+	git commit -m initial &&
+	test "$(git config -f .gitmodules submodule.sub.path)" = "sub" &&
+	test "$(git config -f .gitmodules submodule.sub2.path)" = "sub2"
+
+'
+
+test_expect_success 'git mv of a submodule' '
+
+	git mv sub sub.moved &&
+	! test -d sub &&
+	test -d sub.moved/.git &&
+	! git ls-files --error-unmatch sub &&
+	test "$(git ls-files --stage --error-unmatch sub.moved | cut -d " " -f 1)" = 160000 &&
+	test "$(git config -f .gitmodules submodule.sub.path)" = "sub.moved" &&
+	! git config -f .gitmodules submodule.sub.moved.path
+
+'
+
+test_expect_success 'git submodule add vs. git mv' '
+
+	! git submodule add "$(pwd)/sub2-repo" sub.moved &&
+	git submodule add "$(pwd)/sub2-repo" sub &&
+	test -d sub/.git &&
+	test "$(git config -f .gitmodules submodule.sub.url)" = "$(pwd)/sub-repo" &&
+	test "$(git config -f .gitmodules submodule.sub.path)" = "sub.moved" &&
+	test "$(git config -f .gitmodules submodule.sub~.path)" = "sub"
+
+'
+
+test_expect_success 'git mv onto existing file' '
+
+	echo file > file &&
+	git add file &&
+	! git mv sub.moved file &&
+	test -d sub.moved &&
+	! test -d file/.git &&
+	test "$(git ls-files --stage --error-unmatch file | cut -d " " -f 1)" = 100644 &&
+	test "$(git ls-files --stage --error-unmatch sub.moved | cut -d " " -f 1)" = 160000 &&
+	test "$(git config -f .gitmodules submodule.sub.path)" = "sub.moved"
+
+'
+
+test_expect_success 'git mv onto existing directory' '
+
+	mkdir -p dir &&
+	echo file > dir/file &&
+	git add dir/file &&
+	git mv sub.moved dir &&
+	! test -d sub.moved &&
+	test -d dir/sub.moved/.git &&
+	! git ls-files --error-unmatch sub.moved &&
+	test "$(git ls-files --stage --error-unmatch dir/sub.moved | cut -d " " -f 1)" = 160000 &&
+	test "$(git config -f .gitmodules submodule.sub.path)" = "dir/sub.moved" &&
+	git mv dir/sub.moved . &&
+	test "$(git config -f .gitmodules submodule.sub.path)" = "sub.moved"
+
+'
+
+test_expect_success 'git mv onto existing submodule' '
+
+	! git mv sub.moved sub2 &&
+	test -d sub.moved/.git &&
+	! test -d sub2/sub.moved &&
+	test "$(git ls-files --stage --error-unmatch sub2 | cut -d " " -f 1)" = 160000 &&
+	test "$(git ls-files --stage --error-unmatch sub.moved | cut -d " " -f 1)" = 160000 &&
+	test "$(git config -f .gitmodules submodule.sub.path)" = "sub.moved"
+
+'
+
+test_expect_success 'git mv of multiple submodules' '
+
+	mkdir -p dir &&
+	git mv sub.moved sub dir &&
+	! test -d sub.moved &&
+	! test -d sub &&
+	test -d dir/sub.moved/.git &&
+	test -d dir/sub/.git &&
+	! git ls-files --error-unmatch sub.moved sub &&
+	test "$(git ls-files --stage --error-unmatch dir/sub.moved dir/sub | cut -d " " -f 1 | uniq)" = 160000 &&
+	! git config -f .gitmodules submodule.dir.path &&
+	test "$(git config -f .gitmodules submodule.sub.path)" = "dir/sub.moved" &&
+	test "$(git config -f .gitmodules submodule.sub~.path)" = "dir/sub"
+
+'
+
+test_expect_success 'git mv of multiple submodules back from a subdir' '
+
+	(cd dir && git mv sub.moved sub .. && cd ..) &&
+	test -d sub.moved &&
+	test -d sub &&
+	! test -d dir/sub.moved/.git &&
+	! test -d dir/sub/.git &&
+	! git ls-files --error-unmatch dir/sub.moved dir/sub &&
+	test "$(git ls-files --stage --error-unmatch sub.moved sub | cut -d " " -f 1 | uniq)" = 160000 &&
+	test "$(git config -f .gitmodules submodule.sub.path)" = "sub.moved" &&
+	test "$(git config -f .gitmodules submodule.sub~.path)" = "sub"
+
+'
+
+test_expect_success 'git mv of non-checked-out submodules' '
+
+	git clone . clone &&
+	(cd clone &&
+	test -d sub &&
+	test -d sub2 &&
+	! test -d sub/.git &&
+	! test -d sub2/.git &&
+	git ls-files --stage --error-unmatch sub sub2 > ls-files.out &&
+	mkdir -p dir &&
+	git mv sub sub2 dir &&
+	! test -d sub &&
+	! test -d sub2 &&
+	test -d dir/sub &&
+	test -d dir/sub2 &&
+	! git ls-files --error-unmatch sub sub2 &&
+	test "$(git ls-files --stage --error-unmatch dir/sub dir/sub2 | cut -d " " -f 1 | uniq)" = 160000 &&
+	git ls-files --stage --error-unmatch dir/sub dir/sub2 | sed "s#dir/##g" | diff - ls-files.out &&
+	test "$(git config -f .gitmodules submodule.sub.path)" = "dir/sub" &&
+	test "$(git config -f .gitmodules submodule.sub2.path)" = "dir/sub2" &&
+	(cd dir && git mv sub2 .. && cd ..) &&
+	test -d sub2 &&
+	! test -d dir/sub2 &&
+	! git ls-files --error-unmatch dir/sub2 &&
+	test "$(git ls-files --stage --error-unmatch sub2 | cut -d " " -f 1)" = 160000 &&
+	test "$(git config -f .gitmodules submodule.sub2.path)" = "sub2")
+
+'
+
+test_expect_success 'checkpointing state with git commit' '
+
+	git commit -m"checkpoint" -a &&
+	(cd clone && git commit -m"clone checkpoint" -a)
+
+'
+
+test_expect_success 'git rm of a regular submodule' '
+
+	git rm sub2 &&
+	test -d sub2/.git &&
+	! git ls-files --error-unmatch sub2 &&
+	! git config -f .gitmodules submodule.sub2.path &&
+	! git config -f .gitmodules submodule.sub2.url
+
+'
+
+test_expect_success 'git rm of a submodule with name different from path' '
+
+	git rm sub.moved &&
+	test -d sub.moved/.git &&
+	! git ls-files --error-unmatch sub.moved &&
+	! git config -f .gitmodules submodule.sub.path &&
+	! git config -f .gitmodules submodule.sub.url
+
+'
+
+test_expect_success 'git rm of a modified submodule' '
+
+	git mv sub dir/sub && # more fun with richer path
+	(cd dir/sub &&
+	 echo mod > file &&
+	 git commit -m "sub mod" file) &&
+	git add dir/sub &&
+	! git rm dir/sub &&
+	test -d dir/sub/.git &&
+	test "$(git ls-files --stage --error-unmatch dir/sub | cut -d " " -f 1)" = "160000" &&
+	git config -f .gitmodules submodule.sub~.path &&
+	git config -f .gitmodules submodule.sub~.url &&
+	git rm -f dir/sub &&
+	test -d dir/sub/.git &&
+	! git ls-files --error-unmatch dir/sub &&
+	! git config -f .gitmodules submodule.sub~.path &&
+	! git config -f .gitmodules submodule.sub~.url
+
+'
+
+test_expect_success 'git rm of a submodule from within a subdirectory' '
+
+	git submodule add "$(pwd)/sub-repo" sub-torm &&
+	mkdir -p dir &&
+	# -f since we did not commit the submodule
+	(cd dir && git rm -f ../sub-torm && cd ..) &&
+	test -d sub-torm/.git &&
+	! git ls-files --error-unmatch sub-torm &&
+	! git config -f .gitmodules submodule.sub-torm.path &&
+	! git config -f .gitmodules submodule.sub-torm.url
+
+'
+
+test_expect_success 'git rm of a non-checked-out submodule' '
+
+	(cd clone &&
+	test -d dir/sub &&
+	! test -d dir/sub/.git &&
+	git rm dir/sub &&
+	! test -d dir/sub &&
+	! git ls-files --error-unmatch dir/sub &&
+	! git config -f .gitmodules submodule.sub.path &&
+	! git config -f .gitmodules submodule.sub.url)
+
+'
+
+test_expect_success 'git rm of a non-checked-out submodule w/ different working tree' '
+
+	(cd clone &&
+	rmdir sub2 &&
+	echo cunning > sub2 &&
+	! git rm sub2 &&
+	test -f sub2 &&
+	test "$(git ls-files --stage --error-unmatch sub2 | cut -d " " -f 1)" = "160000" &&
+	git rm -f sub2 &&
+	! test -e sub2 &&
+	! git ls-files --error-unmatch sub2 &&
+	! git config -f .gitmodules submodule.sub2.path &&
+	! git config -f .gitmodules submodule.sub2.url)
+
+'
+
+test_done

^ permalink raw reply related

* [PATCH 3/6] git mv: Support moving submodules
From: Petr Baudis @ 2008-09-12 21:09 UTC (permalink / raw)
  To: git; +Cc: gitster
In-Reply-To: <20080912210817.31628.69014.stgit@localhost>

This patch adds support for moving submodules to 'git mv', including
rewriting of the .gitmodules file to reflect the movement.

Signed-off-by: Petr Baudis <pasky@suse.cz>
---

 builtin-mv.c |   37 +++++++++++++++++++++++++++++++++----
 1 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/builtin-mv.c b/builtin-mv.c
index 4f65b5a..52e3ea5 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -9,6 +9,7 @@
 #include "cache-tree.h"
 #include "string-list.h"
 #include "parse-options.h"
+#include "submodule.h"
 
 static const char * const builtin_mv_usage[] = {
 	"git mv [options] <source>... <destination>",
@@ -49,6 +50,24 @@ static const char *add_slash(const char *path)
 	return path;
 }
 
+static int ce_is_gitlink(int i)
+{
+	return i < 0 ? 0 : S_ISGITLINK(active_cache[i]->ce_mode);
+}
+
+static void rename_submodule(struct string_list_item *i)
+{
+	char *key = submodule_by_path(i->path);
+
+	config_exclusive_filename = ".gitmodules";
+	if (git_config_set(key, (const char *) i->util))
+		die("cannot update .gitmodules");
+	config_exclusive_filename = NULL;
+
+	free(key);
+}
+
+
 static struct lock_file lock_file;
 
 int cmd_mv(int argc, const char **argv, const char *prefix)
@@ -65,6 +84,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 	enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
 	struct stat st;
 	struct string_list src_for_dst = {NULL, 0, 0, 0};
+	/* .path is source path, .util is destination path */
+	struct string_list submodules = {NULL, 0, 0, 0};
 
 	git_config(git_default_config, NULL);
 
@@ -84,7 +105,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 		/* special case: "." was normalized to "" */
 		destination = copy_pathspec(dest_path[0], argv, argc, 1);
 	else if (!lstat(dest_path[0], &st) &&
-			S_ISDIR(st.st_mode)) {
+			S_ISDIR(st.st_mode) &&
+			!ce_is_gitlink(cache_name_pos(dest_path[0], strlen(dest_path[0])))) {
 		dest_path[0] = add_slash(dest_path[0]);
 		destination = copy_pathspec(dest_path[0], argv, argc, 1);
 	} else {
@@ -96,7 +118,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 	/* Checking */
 	for (i = 0; i < argc; i++) {
 		const char *src = source[i], *dst = destination[i];
-		int length, src_is_dir;
+		int length, src_is_dir, src_cache_pos;
 		const char *bad = NULL;
 
 		if (show_only)
@@ -111,7 +133,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 		} else if ((src_is_dir = S_ISDIR(st.st_mode))
 				&& lstat(dst, &st) == 0)
 			bad = "cannot move directory over file";
-		else if (src_is_dir) {
+		else if ((src_cache_pos = cache_name_pos(src, length)) < 0 && src_is_dir) {
 			const char *src_w_slash = add_slash(src);
 			int len_w_slash = length + 1;
 			int first, last;
@@ -177,7 +199,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 				} else
 					bad = "Cannot overwrite";
 			}
-		} else if (cache_name_pos(src, length) < 0)
+		} else if (src_cache_pos < 0)
 			bad = "not under version control";
 		else if (string_list_has_string(&src_for_dst, dst))
 			bad = "multiple sources for the same target";
@@ -214,10 +236,17 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
 
 		pos = cache_name_pos(src, strlen(src));
 		assert(pos >= 0);
+		if (ce_is_gitlink(pos))
+			string_list_insert(src, &submodules)->util = (void *) dst;
 		if (!show_only)
 			rename_cache_entry_at(pos, dst);
 	}
 
+	for (i = 0; i < submodules.nr; i++)
+		rename_submodule(&submodules.items[i]);
+	if (submodules.nr > 0 && add_file_to_cache(".gitmodules", 0))
+		die("cannot add new .gitmodules to the index");
+
 	if (active_cache_changed) {
 		if (write_cache(newfd, active_cache, active_nr) ||
 		    commit_locked_index(&lock_file))

^ permalink raw reply related

* [PATCH 2/6] git rm: Support for removing submodules
From: Petr Baudis @ 2008-09-12 21:09 UTC (permalink / raw)
  To: git; +Cc: gitster
In-Reply-To: <20080912210817.31628.69014.stgit@localhost>

This patch adds support for removing submodules to 'git rm', including
appropriately editing the .gitmodules file to reflect this. Submodule
_checkouts_ are never removed; that can be potentially catastrophic
and the user should remove them manually, if really desired.

Signed-off-by: Petr Baudis <pasky@suse.cz>
---

 Documentation/git-rm.txt |    6 +++-
 builtin-rm.c             |   65 ++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 58 insertions(+), 13 deletions(-)

diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt
index 5afb1e7..0c92687 100644
--- a/Documentation/git-rm.txt
+++ b/Documentation/git-rm.txt
@@ -20,7 +20,8 @@ and no updates to their contents can be staged in the index,
 though that default behavior can be overridden with the `-f` option.
 When '--cached' is given, the staged content has to
 match either the tip of the branch or the file on disk,
-allowing the file to be removed from just the index.
+allowing the file to be removed from just the index;
+this is always the case when removing submodules.
 
 
 OPTIONS
@@ -57,7 +58,8 @@ OPTIONS
 --cached::
 	Use this option to unstage and remove paths only from the index.
 	Working tree files, whether modified or not, will be
-	left alone.
+	left alone.  Note that this is always assumed when removing
+	a checked-out submodule.
 
 --ignore-unmatch::
 	Exit with a zero status even if no files matched.
diff --git a/builtin-rm.c b/builtin-rm.c
index 6bd8211..7475de2 100644
--- a/builtin-rm.c
+++ b/builtin-rm.c
@@ -9,6 +9,7 @@
 #include "cache-tree.h"
 #include "tree-walk.h"
 #include "parse-options.h"
+#include "submodule.h"
 
 static const char * const builtin_rm_usage[] = {
 	"git rm [options] [--] <file>...",
@@ -17,16 +18,21 @@ static const char * const builtin_rm_usage[] = {
 
 static struct {
 	int nr, alloc;
-	const char **name;
+	struct {
+		const char *name;
+		int is_gitlink;
+	} *info;
 } list;
 
-static void add_list(const char *name)
+static void add_list(const char *name, int is_gitlink)
 {
 	if (list.nr >= list.alloc) {
 		list.alloc = alloc_nr(list.alloc);
-		list.name = xrealloc(list.name, list.alloc * sizeof(const char *));
+		list.info = xrealloc(list.info, list.alloc * sizeof(*list.info));
 	}
-	list.name[list.nr++] = name;
+	list.info[list.nr].name = name;
+	list.info[list.nr].is_gitlink = is_gitlink;
+	list.nr++;
 }
 
 static int remove_file(const char *name)
@@ -38,6 +44,13 @@ static int remove_file(const char *name)
 	if (ret && errno == ENOENT)
 		/* The user has removed it from the filesystem by hand */
 		ret = errno = 0;
+	if (ret && errno == EISDIR) {
+		/* This is a gitlink entry; try to remove at least the
+		 * directory if the submodule is not checked out; we always
+		 * leave the checked out ones as they are */
+		if (!rmdir(name) || errno == ENOTEMPTY)
+			ret = errno = 0;
+	}
 
 	if (!ret && (slash = strrchr(name, '/'))) {
 		char *n = xstrdup(name);
@@ -65,7 +78,7 @@ static int check_local_mod(unsigned char *head, int index_only)
 		struct stat st;
 		int pos;
 		struct cache_entry *ce;
-		const char *name = list.name[i];
+		const char *name = list.info[i].name;
 		unsigned char sha1[20];
 		unsigned mode;
 		int local_changes = 0;
@@ -83,7 +96,7 @@ static int check_local_mod(unsigned char *head, int index_only)
 			/* It already vanished from the working tree */
 			continue;
 		}
-		else if (S_ISDIR(st.st_mode)) {
+		else if (S_ISDIR(st.st_mode) && !S_ISGITLINK(ce->ce_mode)) {
 			/* if a file was removed and it is now a
 			 * directory, that is the same as ENOENT as
 			 * far as git is concerned; we do not track
@@ -122,6 +135,22 @@ static int check_local_mod(unsigned char *head, int index_only)
 	return errs;
 }
 
+static void remove_submodule(const char *name)
+{
+	char *key = submodule_by_path(name);
+	char *sectend = strrchr(key, '.');
+
+	assert(sectend);
+	*sectend = 0;
+
+	config_exclusive_filename = ".gitmodules";
+	if (git_config_rename_section(key, NULL) <= 0)
+		die("cannot remove section `%s' from .gitmodules", key);
+	config_exclusive_filename = NULL;
+
+	free(key);
+}
+
 static struct lock_file lock_file;
 
 static int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0;
@@ -140,7 +169,7 @@ static struct option builtin_rm_options[] = {
 
 int cmd_rm(int argc, const char **argv, const char *prefix)
 {
-	int i, newfd;
+	int i, newfd, subs;
 	const char **pathspec;
 	char *seen;
 
@@ -168,7 +197,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
 		struct cache_entry *ce = active_cache[i];
 		if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen))
 			continue;
-		add_list(ce->name);
+		add_list(ce->name, S_ISGITLINK(ce->ce_mode));
 	}
 
 	if (pathspec) {
@@ -216,9 +245,11 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
 	 * the index unless all of them succeed.
 	 */
 	for (i = 0; i < list.nr; i++) {
-		const char *path = list.name[i];
+		const char *path = list.info[i].name;
 		if (!quiet)
-			printf("rm '%s'\n", path);
+			printf("rm%s '%s'\n",
+				list.info[i].is_gitlink ? "dir" : "",
+				path);
 
 		if (remove_file_from_cache(path))
 			die("git rm: unable to remove %s", path);
@@ -238,7 +269,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
 	if (!index_only) {
 		int removed = 0;
 		for (i = 0; i < list.nr; i++) {
-			const char *path = list.name[i];
+			const char *path = list.info[i].name;
 			if (!remove_file(path)) {
 				removed = 1;
 				continue;
@@ -248,6 +279,18 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
 		}
 	}
 
+	/*
+	 * Get rid of stale submodule setup.
+	 */
+	subs = 0;
+	for (i = 0; i < list.nr; i++)
+		if (list.info[i].is_gitlink) {
+			remove_submodule(list.info[i].name);
+			subs++;
+		}
+	if (subs && add_file_to_cache(".gitmodules", 0))
+		die("cannot add new .gitmodules to the index");
+
 	if (active_cache_changed) {
 		if (write_cache(newfd, active_cache, active_nr) ||
 		    commit_locked_index(&lock_file))

^ permalink raw reply related

* [PATCH 1/6] submodule.*: Introduce simple C interface for submodule lookup by path
From: Petr Baudis @ 2008-09-12 21:08 UTC (permalink / raw)
  To: git; +Cc: gitster
In-Reply-To: <20080912210817.31628.69014.stgit@localhost>

The interface will be used for git-mv and git-rm submodule support.
So far, only the submodule_by_path() function is defined, however more
can be probably expected in the future if/when the git-submodule command
is ported from shell.

Signed-off-by: Petr Baudis <pasky@suse.cz>
---

 Makefile    |    2 ++
 submodule.c |   50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 submodule.h |    8 ++++++++
 3 files changed, 60 insertions(+), 0 deletions(-)
 create mode 100644 submodule.c
 create mode 100644 submodule.h

diff --git a/Makefile b/Makefile
index 247cd2d..c7c6478 100644
--- a/Makefile
+++ b/Makefile
@@ -384,6 +384,7 @@ LIB_H += run-command.h
 LIB_H += sha1-lookup.h
 LIB_H += sideband.h
 LIB_H += strbuf.h
+LIB_H += submodule.h
 LIB_H += tag.h
 LIB_H += transport.h
 LIB_H += tree.h
@@ -476,6 +477,7 @@ LIB_OBJS += sha1_name.o
 LIB_OBJS += shallow.o
 LIB_OBJS += sideband.o
 LIB_OBJS += strbuf.o
+LIB_OBJS += submodule.o
 LIB_OBJS += symlinks.o
 LIB_OBJS += tag.o
 LIB_OBJS += trace.o
diff --git a/submodule.c b/submodule.c
new file mode 100644
index 0000000..2883ae6
--- /dev/null
+++ b/submodule.c
@@ -0,0 +1,50 @@
+#include "cache.h"
+#include "submodule.h"
+
+
+struct gitmodules_info {
+	const char *path;
+	char *key;
+};
+
+static int gitmodules_worker(const char *key, const char *value, void *info_)
+{
+	struct gitmodules_info *info = info_;
+	const char *subkey;
+
+	if (prefixcmp(key, "submodule."))
+		return 0;
+
+	subkey = strrchr(key, '.');
+	if (!subkey)
+		return 0;
+
+	if (strcmp(subkey, ".path"))
+		return 0;
+
+	if (strcmp(value, info->path))
+		return 0;
+
+	/* Found the key to change. */
+	if (info->key) {
+		error("multiple submodules live at path `%s'", info->path);
+		/* The last one is supposed to win. */
+		free(info->key);
+	}
+	info->key = xstrdup(key);
+	return 0;
+}
+
+char *submodule_by_path(const char *path)
+{
+	struct gitmodules_info info = { path, NULL };
+
+	config_exclusive_filename = ".gitmodules";
+	if (git_config(gitmodules_worker, &info))
+		die("cannot process .gitmodules");
+	if (!info.key)
+		die("the submodule of `%s' not found in .gitmodules", path);
+	config_exclusive_filename = NULL;
+
+	return info.key;
+}
diff --git a/submodule.h b/submodule.h
new file mode 100644
index 0000000..bc74fa0
--- /dev/null
+++ b/submodule.h
@@ -0,0 +1,8 @@
+#ifndef SUBMODULE_H
+#define SUBMODULE_H
+
+/* Find submodule living at given path in .gitmodules and return the key
+ * of its path config variable (dynamically allocated). */
+extern char *submodule_by_path(const char *path);
+
+#endif

^ permalink raw reply related

* [PATCH 0/6] Submodule support for git mv and git rm
From: Petr Baudis @ 2008-09-12 21:08 UTC (permalink / raw)
  To: git; +Cc: gitster

This is a resend of the previously submitted series, with basically
no changes since the previous submission.

---

Petr Baudis (6):
      git submodule add: Fix naming clash handling
      t7400: Add short "git submodule add" testsuite
      t7403: Submodule git mv, git rm testsuite
      git mv: Support moving submodules
      git rm: Support for removing submodules
      submodule.*: Introduce simple C interface for submodule lookup by path


 Documentation/git-rm.txt   |    6 +
 Makefile                   |    2 
 builtin-mv.c               |   37 ++++++-
 builtin-rm.c               |   65 ++++++++++--
 git-submodule.sh           |   15 ++-
 submodule.c                |   50 +++++++++
 submodule.h                |    8 +
 t/t7400-submodule-basic.sh |   39 +++++++
 t/t7403-submodule-mvrm.sh  |  242 ++++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 443 insertions(+), 21 deletions(-)
 create mode 100644 submodule.c
 create mode 100644 submodule.h
 create mode 100755 t/t7403-submodule-mvrm.sh

^ permalink raw reply

* Re: [RFC] origin link for cherry-pick and revert
From: Stephen R. van den Berg @ 2008-09-12 20:56 UTC (permalink / raw)
  To: Theodore Tso; +Cc: Jeff King, git
In-Reply-To: <20080912184406.GB5082@mit.edu>

Theodore Tso wrote:
>On Fri, Sep 12, 2008 at 06:43:48PM +0200, Stephen R. van den Berg wrote:
>> On my system that results in 2ms per commit on average.  Not huge, but
>> not small either, I guess.  Running it results in real waiting time, it
>> all depends on how patient the user is.

>For a local clone, git could be taught to copy the cache file.  For a
>network-based clone, the percentage of time needed to download is
>roughly 2-3 times that (although that will obviously depend on your
>network connectivity).  Building this cache can be done in the
>background, though, or delayed until the first time the cache is
>needed.

Fair enough.  If noone beats me to it, I'll probably take a stab at
implementing something like this and see how it fares for my own
application.
-- 
Sincerely,
           Stephen R. van den Berg.

"Father's Day: Nine months before Mother's Day."

^ permalink raw reply

* [PATCH] Fix some manual typos.
From: Ralf Wildenhues @ 2008-09-12 19:10 UTC (permalink / raw)
  To: git

Signed-off-by: Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
---

Thanks for git!

Cheers,
Ralf

 Documentation/git-web--browse.txt |    2 +-
 Documentation/gitattributes.txt   |    2 +-
 Documentation/merge-config.txt    |    2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-web--browse.txt b/Documentation/git-web--browse.txt
index 36afad8..7f7a45b 100644
--- a/Documentation/git-web--browse.txt
+++ b/Documentation/git-web--browse.txt
@@ -77,7 +77,7 @@ the URLs passed as arguments.
 Note about konqueror
 --------------------
 
-When 'konqueror' is specified by the a command line option or a
+When 'konqueror' is specified by a command line option or a
 configuration variable, we launch 'kfmclient' to try to open the HTML
 man page on an already opened konqueror in a new tab if possible.
 
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 75124d2..6f3551d 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -313,7 +313,7 @@ patterns are available:
 
 - `html` suitable for HTML/XHTML documents.
 
-- `java` suitable for source code in the Java lanugage.
+- `java` suitable for source code in the Java language.
 
 - `pascal` suitable for source code in the Pascal/Delphi language.
 
diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt
index 00277e0..c735788 100644
--- a/Documentation/merge-config.txt
+++ b/Documentation/merge-config.txt
@@ -1,5 +1,5 @@
 merge.stat::
-	Whether to print the diffstat between ORIG_HEAD and merge result
+	Whether to print the diffstat between ORIG_HEAD and the merge result
 	at the end of the merge.  True by default.
 
 merge.log::
-- 
1.6.0.1.309.g48068

^ permalink raw reply related

* Re: CGit and repository list
From: Petr Baudis @ 2008-09-12 19:13 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git
In-Reply-To: <200809121940.43471.jnareb@gmail.com>

On Fri, Sep 12, 2008 at 07:40:43PM +0200, Jakub Narebski wrote:
> Dnia piątek 12. września 2008 18:05, Petr Baudis napisał:
> > On Fri, Sep 12, 2008 at 05:54:29PM +0200, Jakub Narebski wrote:
> >>
> >> P.S. Could you please gather some statistics to compare the period
> >> before and after installing "smart" HTTP server (and after smart
> >> clients became widespread).
> > 
> > What kind of statistics?
> 
> In the simplest case just some averaged system load (perhaps load 
> average from uptime, or from top, or from /proc) before and after.
> Perhaps bandwidth used per week or something like that too.

This statistics are already available at

	http://rover.dkm.cz/~yanek/stats/

> If you have time and interest, CPU load, disk IO, network IO or
> network bandwidth used, and average time to serve request (latency)
> for fetching via HTTP protocol, for "dumb" and "smart" clients,
> perhaps averaged over number of requests.  (I don't know unfortunately 
> how to get such data).
> 
> In short: check how "smart" HTTP protocol would improve things.

...and I don't know out of the top of my head how to best gather the
rest either. ;-) (If someone is really interested about all this, that's
fine, but they have to give me a pre-made cookbook of recipes how to
hook that up to RRD.)

-- 
				Petr "Pasky" Baudis
The next generation of interesting software will be done
on the Macintosh, not the IBM PC.  -- Bill Gates

^ permalink raw reply

* [RFC PATCH (GIT-GUI)] git-gui: Add more integration options to citool.
From: Alexander Gavrilov @ 2008-09-12 18:43 UTC (permalink / raw)
  To: git; +Cc: Shawn O. Pearce

- Make citool return nonzero exit code if it did not commit.
- Add a mode where it does not actually commit and simply
  exits with zero code. Commit message is either disabled,
  or simply dumped to GITGUI_EDITMSG before exiting.
- Add an option to immediately start it in amend mode.

Rationale:

1) Use 'git citool --nocommit' instead of mergetool in scripts.
2) Use 'git citool --amend' to edit commits while rebasing.

Signed-off-by: Alexander Gavrilov <angavrilov@gmail.com>
---

	I think this functionality might be useful, in particular for some of
	my own scripts. But I'm not sure if this is the best way to do it.

	-- Alexander


 git-gui.sh     |   81 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 lib/commit.tcl |    8 ++++-
 2 files changed, 83 insertions(+), 6 deletions(-)

diff --git a/git-gui.sh b/git-gui.sh
index fb43255..91457a2 100755
--- a/git-gui.sh
+++ b/git-gui.sh
@@ -961,10 +961,32 @@ blame {
 }
 citool {
 	enable_option singlecommit
+	enable_option retcode
 
 	disable_option multicommit
 	disable_option branch
 	disable_option transport
+
+	while {[llength $argv] > 0} {
+		set a [lindex $argv 0]
+		switch -- $a {
+		--amend {
+			enable_option initialamend
+		}
+		--nocommit {
+			enable_option nocommit
+			enable_option nocommitmsg
+		}
+		--commitmsg {
+			disable_option nocommitmsg
+		}
+		default {
+			break
+		}
+		}
+
+		set argv [lrange $argv 1 end]
+	}
 }
 }
 
@@ -1121,6 +1143,20 @@ proc PARENT {} {
 	return $empty_tree
 }
 
+proc force_amend {} {
+	global selected_commit_type
+	global HEAD PARENT MERGE_HEAD commit_type
+
+	repository_state newType newHEAD newMERGE_HEAD
+	set HEAD $newHEAD
+	set PARENT $newHEAD
+	set MERGE_HEAD $newMERGE_HEAD
+	set commit_type $newType
+
+	set selected_commit_type amend
+	do_select_commit_type
+}
+
 proc rescan {after {honor_trustmtime 1}} {
 	global HEAD PARENT MERGE_HEAD commit_type
 	global ui_index ui_workdir ui_comm
@@ -1767,11 +1803,19 @@ proc do_gitk {revs} {
 }
 
 set is_quitting 0
+set ret_code    1
 
-proc do_quit {} {
+proc terminate_me {win} {
+	global ret_code
+	if {$win ne {.}} return
+	exit $ret_code
+}
+
+proc do_quit {{rc {1}}} {
 	global ui_comm is_quitting repo_config commit_type
 	global GITGUI_BCK_exists GITGUI_BCK_i
 	global ui_comm_spell
+	global ret_code
 
 	if {$is_quitting} return
 	set is_quitting 1
@@ -1826,6 +1870,7 @@ proc do_quit {} {
 		}
 	}
 
+	set ret_code $rc
 	destroy .
 }
 
@@ -2228,6 +2273,14 @@ if {[is_enabled branch]} {
 
 # -- Commit Menu
 #
+proc commit_btn_caption {} {
+	if {[is_enabled nocommit]} {
+		return [mc "Done"]
+	} else {
+		return [mc Commit@@verb]
+	}
+}
+
 if {[is_enabled multicommit] || [is_enabled singlecommit]} {
 	menu .mbar.commit
 
@@ -2293,7 +2346,7 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {
 		-command do_signoff \
 		-accelerator $M1T-S
 
-	.mbar.commit add command -label [mc Commit@@verb] \
+	.mbar.commit add command -label [commit_btn_caption] \
 		-command do_commit \
 		-accelerator $M1T-Return
 	lappend disable_on_lock \
@@ -2621,7 +2674,7 @@ button .vpane.lower.commarea.buttons.signoff -text [mc "Sign Off"] \
 	-command do_signoff
 pack .vpane.lower.commarea.buttons.signoff -side top -fill x
 
-button .vpane.lower.commarea.buttons.commit -text [mc Commit@@verb] \
+button .vpane.lower.commarea.buttons.commit -text [commit_btn_caption] \
 	-command do_commit
 pack .vpane.lower.commarea.buttons.commit -side top -fill x
 lappend disable_on_lock \
@@ -2631,6 +2684,13 @@ button .vpane.lower.commarea.buttons.push -text [mc Push] \
 	-command do_push_anywhere
 pack .vpane.lower.commarea.buttons.push -side top -fill x
 
+if {[is_enabled nocommitmsg]} {
+	.vpane.lower.commarea.buttons.signoff configure -state disabled
+}
+if {[is_enabled nocommit]} {
+	.vpane.lower.commarea.buttons.push configure -state disabled
+}
+
 # -- Commit Message Buffer
 #
 frame .vpane.lower.commarea.buffer
@@ -3212,7 +3272,20 @@ lock_index begin-read
 if {![winfo ismapped .]} {
 	wm deiconify .
 }
-after 1 do_rescan
+after 1 {
+	if {[is_enabled initialamend]} {
+		force_amend
+	} else {
+		do_rescan
+	}
+
+	if {[is_enabled nocommitmsg]} {
+		$ui_comm configure -state disabled -background gray
+	}
+}
 if {[is_enabled multicommit]} {
 	after 1000 hint_gc
 }
+if {[is_enabled retcode]} {
+	bind . <Destroy> {+terminate_me %W}
+}
diff --git a/lib/commit.tcl b/lib/commit.tcl
index 2977315..3345149 100644
--- a/lib/commit.tcl
+++ b/lib/commit.tcl
@@ -168,7 +168,7 @@ File %s cannot be committed by this program.
 		}
 		}
 	}
-	if {!$files_ready && ![string match *merge $curType]} {
+	if {!$files_ready && ![string match *merge $curType] && ![is_enabled nocommit]} {
 		info_popup [mc "No changes to commit.
 
 You must stage at least 1 file before you can commit.
@@ -177,6 +177,8 @@ You must stage at least 1 file before you can commit.
 		return
 	}
 
+	if {[is_enabled nocommitmsg]} { do_quit 0 }
+
 	# -- A message is required.
 	#
 	set msg [string trim [$ui_comm get 1.0 end]]
@@ -212,6 +214,8 @@ A good commit message has the following format:
 	puts $msg_wt $msg
 	close $msg_wt
 
+	if {[is_enabled nocommit]} { do_quit 0 }
+
 	# -- Run the pre-commit hook.
 	#
 	set fd_ph [githook_read pre-commit]
@@ -410,7 +414,7 @@ A rescan will be automatically started now.
 		set ::GITGUI_BCK_exists 0
 	}
 
-	if {[is_enabled singlecommit]} do_quit
+	if {[is_enabled singlecommit]} { do_quit 0 }
 
 	# -- Update in memory status
 	#
-- 
1.6.0.20.g6148bc

^ permalink raw reply related

* Re: [RFC] origin link for cherry-pick and revert
From: Theodore Tso @ 2008-09-12 18:44 UTC (permalink / raw)
  To: Stephen R. van den Berg; +Cc: Jeff King, git
In-Reply-To: <20080912164348.GC2915@cuci.nl>

On Fri, Sep 12, 2008 at 06:43:48PM +0200, Stephen R. van den Berg wrote:
> >> True.  But repopulating this cache after cloning means that you have to
> >> calculate the patch-id of *every* commit in the repository.  It sounds
> >> like something to avoid, but maybe I'm overly concerned, I have only a
> >> vague idea on how computationally intensive this is.
> 
> >For a rough estimate, try:
> 
> >  time git log -p | git patch-id >/dev/null
> 
> On my system that results in 2ms per commit on average.  Not huge, but
> not small either, I guess.  Running it results in real waiting time, it
> all depends on how patient the user is.

For a local clone, git could be taught to copy the cache file.  For a
network-based clone, the percentage of time needed to download is
roughly 2-3 times that (although that will obviously depend on your
network connectivity).  Building this cache can be done in the
background, though, or delayed until the first time the cache is
needed.

						- Ted

^ permalink raw reply

* Re: [ANNOUNCE] TopGit v0.3
From: martin f krafft @ 2008-09-12 18:14 UTC (permalink / raw)
  To: Petr Baudis, Jan Nieuwenhuizen, git
In-Reply-To: <20080912131530.GZ10360@machine.or.cz>

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

also sprach Petr Baudis <pasky@suse.cz> [2008.09.12.1415 +0100]:
> I'm stopping to see any way how to sanely support dependency
> removal without history rewriting, since we rely on Git for our
> all changes propagation.

I've considered this question a lot before and could not come up
with anything; you cannot undo a merge.

-- 
martin | http://madduck.net/ | http://two.sentenc.es/
 
it may look like i'm just sitting here doing nothing.
but i'm really actively waiting
for all my problems to go away.
 
spamtraps: madduck.bogus@madduck.net

[-- Attachment #2: Digital signature (see http://martin-krafft.net/gpg/) --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ 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