Git development
 help / color / mirror / Atom feed
* Re: logging disjoint sets of commits in a single command
From: Junio C Hamano @ 2012-02-01  0:48 UTC (permalink / raw)
  To: Bryan O'Sullivan; +Cc: git@vger.kernel.org
In-Reply-To: <CB4DC442.72F%bryano@fb.com>

"Bryan O'Sullivan" <bryano@fb.com> writes:

> Here's a sample command line against a kernel tree:
>
> git log 373af0c^..373af0c 590dfe2^..590dfe2

This command line is _defined_ to be the same as this.

	git log ^373af0c^ 373af0c ^590dfe2^ 590dfe2

Hence,

> Is there some way around this, or would a patch to fix it be acceptable?

the answer to the second question is "no, that is not a fix but is a
breakage for the *current* Git users".

The answer to the first question is that you may be able to do something
like this:

        (
            git rev-list 373af0c^..373af0c
            git rev-list 590dfe2^..590dfe2
        ) |
        sort -u |
        xargs git show

Having said all that, for users of Git 2.0, giving richer meaning to the
explicit range notation to make your original command line work just like
the above scripted way would be more intuitive.  While an unconditional
change to break the current users would totally be unacceptable, we would
want to see somebody come up with a clean migration path toward that goal
without hurting existing users in the longer term.

^ permalink raw reply

* Re: logging disjoint sets of commits in a single command
From: Carlos Martín Nieto @ 2012-02-01  0:39 UTC (permalink / raw)
  To: Bryan O'Sullivan; +Cc: git@vger.kernel.org
In-Reply-To: <CB4DC442.72F%bryano@fb.com>

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

On Wed, 2012-02-01 at 00:27 +0000, Bryan O'Sullivan wrote:
> On 2012-01-31 16:15 , "Bryan O'Sullivan" <bryano@fb.com> wrote:
> 
> >I'm trying to use "git log" to display only a handful of commits, where
> >the commits are not necessarily linearly related to each other.
> 
> And I beautifully fat-fingered the "send" key. Oops.
> 
> What I was *going* to say was that it looks like revision.c:limit_list is
> (whether intentionally or not) getting in the way of this.
> 
> Here's a sample command line against a kernel tree:
> 
> git log 373af0c^..373af0c 590dfe2^..590dfe2
> 
> I want git to log those two specific commits, but in fact it looks like
> limit_list is marking 590dfe2 as UNINTERESTING while processing 373af0c,
> and so it gets pruned.
> 
> Is there some way around this, or would a patch to fix it be acceptable?

From my reading of the manpage (and the way most git commands work) log
accepts one range of commits. They all get bunched up together.

You might find cat-file's --batch mode interesting.

    git rev-list 373af0c^..373af0c | git cat-file --batch
    git rev-list 590dfe2^..590dfe2 | git cat-file --batch

looks a lot like what you're looking for.

   cmn


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 490 bytes --]

^ permalink raw reply

* Re: [PATCH/RFC v3] grep: Add the option '--exclude'
From: Junio C Hamano @ 2012-02-01  0:31 UTC (permalink / raw)
  To: Albert Yale; +Cc: git, Nguyễn Thái Ngọc Duy
In-Reply-To: <1328021108-4662-1-git-send-email-surfingalbert@gmail.com>

Albert Yale <surfingalbert@gmail.com> writes:

> @@ -124,6 +125,12 @@ OPTIONS
>  	Use fixed strings for patterns (don't interpret pattern
>  	as a regex).
>  
> +-x <pattern>::
> +--exclude <pattern>::
> +	In addition to those found in .gitignore (per directory) and
> +	$GIT_DIR/info/exclude, also consider these patterns to be in the
> +	set of the ignore rules in effect.

That makes it sound as if "git grep" will not produce hits for a path that
was forcibly added despite it matches a pattern in .gitignore file, which
is not true at all.

>  -n::
>  --line-number::
>  	Prefix the line number to matching lines.
> diff --git a/builtin/grep.c b/builtin/grep.c
> index 9ce064a..e9e1ac1 100644
> --- a/builtin/grep.c
> +++ b/builtin/grep.c
> @@ -528,7 +528,8 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
>  		struct cache_entry *ce = active_cache[nr];
>  		if (!S_ISREG(ce->ce_mode))
>  			continue;
> -		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
> +		if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce),
> +					  0, NULL, 1))
>  			continue;
>  		/*
>  		 * If CE_VALID is on, we assume worktree file and its cache entry
> @@ -566,6 +567,11 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
>  	while (tree_entry(tree, &entry)) {
>  		int te_len = tree_entry_len(&entry);
>  
> +		if (match_pathspec_depth(pathspec->exclude,
> +					 entry.path, strlen(entry.path),
> +					 0, NULL, 0))
> +			continue;
> +

Why???

IOW, why isn't this

	if (!match_pathspec_depth(pathspec, ...))
		continue;	

My point of the two previous review messages was that it would be nice if
we can make it so that nobody outside match_pathspec_depth() should even
need to know existence of pathspec->exclude. Either that was ignored, or
perhaps you found a compelling reason why that is not a good idea, but if
so I'd like to know why.

I suspect that you do not need to add the extra 0 at the end (it makes the
caller even harder to read) if you go that route. The extra parameter
defeats the whole point of encapsulating the new "negative match" feature
behind match_pathspec_depth() implementation.

> +	if (obj->type == OBJ_BLOB) {
> +		const char *name_without_sha1 = strchr(name, ':') + 1;
> +
> +		if (match_pathspec_depth(pathspec->exclude,
> +					 name_without_sha1,
> +					 strlen(name_without_sha1),
> +					 0, NULL, 0))
> +			return 0;

Likewise.

> diff --git a/cache.h b/cache.h
> index 9bd8c2d..683458a 100644
> --- a/cache.h
> +++ b/cache.h
> @@ -533,9 +533,12 @@ struct pathspec {
>  		int len;
>  		unsigned int use_wildcard:1;
>  	} *items;
> +
> +	struct pathspec *exclude; /* This is never NULL. */
>  };

"This is never NULL" is blatantly wrong, as pathspec->exclude->exclude
will very likely be NULL.

I've been assuming that the resulting structure would be more like this: 

 struct pathspec_set {
         int nr;
         unsigned int has_wildcard:1;
         unsigned int recursive:1;
         struct pathspec_item {
                 const char *match;
                 int len;
                 unsigned int use_wildcard:1;
         } *items;
 };

 struct pathspec {
         const char **raw; /* get_pathspec() result, not freed by free_pathspec() */
         int max_depth;
         struct pathspec_set include;
         struct pathspec_set exclude;
 };
 
I am not including "raw" in the include/exclude because its use should be
deprecated away over time.

The various helpers used in match_pathspec_depth() that know _only_ about
matching and not about excluding will be changed to take a pointer to
"struct pathspec_set" (and possibly max_depth). The top-level callers
would not have to know any of these changes if we structure the API that
way, no?

I think something like that was more or less the structure we discussed
when Nguyễn brought up his negative pathspec work the last time.

^ permalink raw reply

* Re: logging disjoint sets of commits in a single command
From: Bryan O'Sullivan @ 2012-02-01  0:27 UTC (permalink / raw)
  To: git@vger.kernel.org
In-Reply-To: <CB4DC432.72D%bryano@fb.com>

On 2012-01-31 16:15 , "Bryan O'Sullivan" <bryano@fb.com> wrote:

>I'm trying to use "git log" to display only a handful of commits, where
>the commits are not necessarily linearly related to each other.

And I beautifully fat-fingered the "send" key. Oops.

What I was *going* to say was that it looks like revision.c:limit_list is
(whether intentionally or not) getting in the way of this.

Here's a sample command line against a kernel tree:

git log 373af0c^..373af0c 590dfe2^..590dfe2

I want git to log those two specific commits, but in fact it looks like
limit_list is marking 590dfe2 as UNINTERESTING while processing 373af0c,
and so it gets pruned.

Is there some way around this, or would a patch to fix it be acceptable?

^ permalink raw reply

* logging disjoint sets of commits in a single command
From: Bryan O'Sullivan @ 2012-02-01  0:15 UTC (permalink / raw)
  To: git@vger.kernel.org

I'm trying to use "git log" to display only a handful of commits, where
the commits are not necessarily linearly related to each other.

^ permalink raw reply

* Re: [PATCH] pack-objects: convert to use parse_options()
From: Junio C Hamano @ 2012-01-31 23:29 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git
In-Reply-To: <1328017702-14489-1-git-send-email-pclouds@gmail.com>

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> @@ -2305,183 +2300,140 @@ static void get_object_list(int ac, const char **av)
>  		loosen_unused_packed_objects(&revs);
>  }
>  
> +static int option_parse_index_version(const struct option *opt,
> +				      const char *arg, int unset)
> +{
> +	char *c;
> +	const char *val = arg;
> +	pack_idx_opts.version = strtoul(val, &c, 10);
> +	if (pack_idx_opts.version > 2)
> +		die("unsupported index version %s", val);

Dying may have been the appropriate error path in the custom option
parser, but is it still so for a callback in the parse-options framework?

Or should this be a 'return error(_("..."), val)'?

> +	if (*c == ',' && c[1])
> +		pack_idx_opts.off32_limit = strtoul(c+1, &c, 0);

I do not think the original had this extra "&& c[1]" check and I didn't
see any explanation of this change in the log message, either.

> +static int option_parse_ulong(const struct option *opt,
> +			      const char *arg, int unset)
> +{
> +	if (unset)
> +		die("option %s does not accept negative form",
> +		    opt->long_name);
> +
> +	if (!git_parse_ulong(arg, opt->value))
> +		die("unable to parse value '%s' for option %s",
> +		    arg, opt->long_name);
> +	return 0;
> +}

Likewise on "die()".

> +#define OPT_ULONG(s, l, v, h) \
> +	{ OPTION_CALLBACK, (s), (l), (v), "n", (h),	\
> +	  PARSE_OPT_NONEG, option_parse_ulong }
> +
>  int cmd_pack_objects(int argc, const char **argv, const char *prefix)
>  {
>  	int use_internal_rev_list = 0;
>  	int thin = 0;
>  	int all_progress_implied = 0;
> -	uint32_t i;
> -	const char **rp_av;
> -	int rp_ac_alloc = 64;
> -	int rp_ac;
> +	const char *rp_av[6];

Nice stackframe shrinkage.

> +	int rp_ac = 0;
> +	int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
> +	struct option pack_objects_options[] = {
> +		OPT_SET_INT('q', "quiet", &progress,
> +			    "do not show progress meter", 0),
> +		OPT_SET_INT(0, "progress", &progress,
> +			    "show progress meter", 1),
> +		OPT_SET_INT(0, "all-progress", &progress,
> +			    "show progress meter during object writing phase", 2),

Sounds as if the progress is not shown during the counting phase.
Nothing ", too" at the end could not fix, though.

> +		OPT_BOOL(0, "all-progress-implied",
> +			 &all_progress_implied,
> +			 "similar to --all-progress when progress meter is shown"),

Hrm, interesting wording.

> +		{ OPTION_CALLBACK, 0, "index-version", NULL, "version",
> +		  "force generating pack index at a particular version",
> +		  0, option_parse_index_version },

Sounds as if you can generate a pack index at HEAD~24, but that is not
what you meant. "version" is too loaded a word that needs qualification.

Perhaps "write the pack index file in the specified idx format version".

"index" is also a loaded word, and our documentation tries to use "idx"
when we talk about the pack index (we say "index" when we mean the
dircache).

> +		OPT_INTEGER(0, "window", &window,
> +			    "limit pack window by objects"),
> +		OPT_ULONG(0, "window-memory", &window_memory_limit,
> +			  "limit pack window by memory"),
> +		OPT_INTEGER(0, "depth", &depth,
> +			    "limit pack window by maximum delta depth"),

These descriptions are somewhat interesting.

The "pack window" is limited by number of objects given by --window (and
by default this is set to 10), but if you give --window-memory, it could
further dynamically shrink it under memory pressure. If the logic were to
use this dynamic shrinkage without any limit on the number of objects in
flight when --window-memory and no --window is given, then you could say
"limit by memory" as if the "pack window" is counted in terms of number of
bytes in the window instead of number of objects and the description would
be accurate. But that is not quite the case as far as I know.

And --depth does not affect the size of the pack window at all. It rejects
an object with deep enough delta chain as a delta-base candidate to limit
the run-time performance penalty for the user of the resulting pack, but
does not stop the caller from trying the next object in the window.
"maximum length of delta chain allowed in the resulting pack", perhaps?

> +		OPT_BOOL(0, "reuse-delta", &reuse_delta,
> +			 "reusing existing deltas"),
> +		OPT_BOOL(0, "reuse-object", &reuse_object,
> +			 "reusing existing objects"),

s/reusing/reuse/???

> +		OPT_BOOL(0, "delta-base-offset", &allow_ofs_delta,
> +			 "use OFS_DELTA objects"),
> +		OPT_INTEGER(0, "threads", &delta_search_threads,
> +			    "use threads when searching for best delta matches"),
> +		OPT_BOOL(0, "non-empty", &non_empty,
> +			 "only create if it would contain at least one object"),

create what? "do not create an empty pack output"?

> +		OPT_BOOL(0, "revs", &use_internal_rev_list,
> +			 "read revision arguments from standard output"),

s/output/input/???

> +		{ OPTION_SET_INT, 0, "unpacked", &rev_list_unpacked, NULL,
> +		  "limit the objects to those that are not already packed",
> +		  PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },

s/already/yet/???

> +		{ OPTION_SET_INT, 0, "all", &rev_list_all, NULL,
> +		  "include all refs under $GIT_DIR/refs directory",
> +		  PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
> +		{ OPTION_SET_INT, 0, "reflog", &rev_list_reflog, NULL,
> +		  "include objects referred by reflog entries",
> +		  PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },

The latter is more correct---packfile does not pack refs, it packs
objects.

Perhaps former should match: "include objects reachable from any
reference". I would also prefer to avoid "$GIT_DIR/refs _directory_"
to discourage people from running "ls -R .git/refs/".

> +		OPT_BOOL(0, "stdout", &pack_to_stdout,
> +			 "output pack to stdout"),
> +		OPT_BOOL(0, "include-tag", &include_tag,
> +			 "include unasked-for annotated tags"),

"include tag objects that refer to objects to be packed"?

> +		OPT_BOOL(0, "keep-unreachable", &keep_unreachable,
> +			 "keep unreachable objects"),

What does this option mean these days (aka "where are they kept")?

IIRC, this was meant to be used in conjunction with the --unpacked= and
later with --kept-pack-only (see 03a9683d22) and then was later further
modified by 4d6acb70411.

I *think* this meant to include objects that are in packfiles that are not
marked with .keep even when they are not in the revision range to be
packed, so that we won't lose them during gc.

But I think --unpack-unreachable introduced by ca11b21 (let pack-objects
do the writing of unreachable objects as loose objects, 2008-05-14) that
writes these unreachable objects out of the pack to loose form made this
option unnecessary, and it remains unused ever since. It may not be a bad
idea to deprecate this option.

Obviously it is outside of the scope of this patch.

> +		OPT_BOOL(0, "unpack-unreachable", &unpack_unreachable,
> +			 "unpack unreachable objects"),
> +		OPT_BOOL(0, "thin", &thin,
> +			 "create thin packs"),
> +		OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep,
> +			 "ignore packs that have companion .keep file"),
> +		OPT_INTEGER(0, "compression", &pack_compression_level,
> +			    "pack compression level"),
> +		OPT_SET_INT(0, "keep-true-parents", &grafts_replace_parents,
> +			    "do not hide commits by grafts", 0),

It is noteworthy that this is truly "do not hide".

A graft entry can also add extra commits, but this option will not prevent
the command from including them, so that the result of repacking will keep
the union of parents in the real history (i.e. in commit objects) and
parents in the pretend history (i.e. added by grafts).

> +		OPT_END(),
> +	};
>  
>  	read_replace_refs = 0;
> ...
> -			continue;
> -		}
> -		usage(pack_usage);
> +	if (rev_list_unpacked) {
> +		use_internal_rev_list = 1;
> +		rp_av[rp_ac++] = "--unpacked";
> +	}
> +	if (rev_list_all) {
> +		use_internal_rev_list = 1;
> +		rp_av[rp_ac++] = "--all";
> +	}
> +	if (rev_list_reflog) {
> +		use_internal_rev_list = 1;
> +		rp_av[rp_ac++] = "--reflog";
>  	}

I'd prefer to have "unpacked" the last, to match the order of parameters
in which the typical caller, i.e. repack, calls us, but that is minor.

> @@ -2497,12 +2449,25 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
>  	 * walker.
>  	 */
>  
> -	if (!pack_to_stdout)
> -		base_name = argv[i++];
> -
> -	if (pack_to_stdout != !base_name)
> -		usage(pack_usage);
> +	if (!pack_to_stdout) {
> +		if (!argc)
> +			die("base name required if --stdout is not given");
> +		base_name = argv[0];
> +		argc--;
> +	}
> +	if (argc)
> +		die("base name or --stdout are mutually exclusive");

Doesn't this change regress the most basic, i.e.

	$ git pack-objects
        usage: ...

Other than that, thanks for a pleasant and thought-provoking read.

^ permalink raw reply

* Re: Alternates corruption issue
From: Jonathan Nieder @ 2012-01-31 22:59 UTC (permalink / raw)
  To: Jeff King
  Cc: Junio C Hamano, Richard Purdie, GIT Mailing-list, Hart, Darren,
	Ashfield, Bruce
In-Reply-To: <20120131224240.GA3844@sigill.intra.peff.net>

Jeff King wrote:
> On Tue, Jan 31, 2012 at 04:22:58PM -0600, Jonathan Nieder wrote:

>> I admit part of the reason I care is that just putting "" first would
>> probably taken care of the more important part of
>> <http://bugs.debian.org/399041>.
>
> Would that fix it? If I understand it, the repo in question is bare with
> a ".git" directory inside it.

The layout was foo/.git/.git.  The real repository was made with plain
"git init" or "git clone", and then "git svn init" or similar was run
from within .git, creating a .git subdirectory.  (Something more must
have happened, actually, since the tree was weirdly sparse:

	$ find .git/.git
	.git/.git
	.git/.git/svn
	.git/.git/svn/git-svn
	.git/.git/svn/git-svn/.rev_db

)

In the current scheme, to access such a broken repository remotely,
you have to use a URL ".../foo".  URLs pointing to foo/.git (like gitk
once used) end up rewritten as .git/.git.  Of course, your patch with
the is_git_directory() will fix this specific case. :)

Not a huge deal, especially since "git svn init" prints out where it
is writing these days.

^ permalink raw reply

* Rebase regression in v1.7.9?
From: Felipe Contreras @ 2012-01-31 22:56 UTC (permalink / raw)
  To: git

Hi,

Try the following steps:

% git checkout -b tmp v1.7.9
% git cherry-pick 6e1c9bb^2^
% git rebase -i --onto 6e1c9bb HEAD^
% git rebase --continue

The rebase will finish, but there will be a .git/CHERRY_PICK_HEAD file.

This doesn't happen if you run rebase without -i, or do rebase --skip instead.

IIRC correctly rebase --continue used to work fine.

Cheers.

-- 
Felipe Contreras

^ permalink raw reply

* Re: [RFC/PATCH] add update to branch support for "floating submodules"
From: Phil Hord @ 2012-01-31 22:50 UTC (permalink / raw)
  To: Jens Lehmann; +Cc: Junio C Hamano, Leif Gruenwoldt, git
In-Reply-To: <4F28554D.9090107@web.de>

On Tue, Jan 31, 2012 at 3:55 PM, Jens Lehmann <Jens.Lehmann@web.de> wrote:
> Am 30.01.2012 22:15, schrieb Phil Hord:
>> I lost my grip on this thread over the holidays...
>>
>> On Tue, Dec 13, 2011 at 4:09 PM, Jens Lehmann <Jens.Lehmann@web.de> wrote:
>>> Am 13.12.2011 15:17, schrieb Phil Hord:
>>>>   git pull origin topic_foo && git submodule foreach 'git pull origin topic_foo'
>>>>
>>>>   git submodule foreach 'git push origin topic_foo' && git push origin topic_foo
>>>
>>> This sounds to me like you would need the "--recurse-submodules" option
>>> implemented for "git pull" and "git push", no?
>>
>> Only if I have nested submodules, but yes, we do use --recurs* in our scripts.
>
> I'm confused, push doesn't know the "--recurse-submodules" option
> at all yet while pull only does a deep fetch when it is given, the
> submodule work trees are not updated to the merge result right now.

Sorry.  I type faster than I think sometimes.

I meant that I do use something like this:
    git submodule foreach --recursive 'git checkout master' && git
checkout master

And I expect to use something like this:
    git submodule foreach --recursive 'git push origin topic_foo' &&
git push origin topic_foo

>>> And I miss to see how
>>> floating would help when the tips of some submodules are not ready to
>>> work with other submodules tips ...
>>
>> By project policy, for any branch, all submodules' tips of the
>> same-named branch should be interoperable.  The CI server looks after
>> this, as much as he can.
>
> We do the same thing on our CI server, but it can only test some
> combinations (even though that tends to show most problems pretty
> early). But in the end every superproject is responsible to use a
> working set of submodule commits, and I would rather bet on a
> combination the CI server tested than on what happens to be on the
> current tips.

Yes, I see what you mean.  In our case, what "happens to be on the
tips" should also have been vetted by our Gerrit+Jenkins code review
dance (for each branch * each superproject), and so it should always
be good.  If it's not, we have the Jenkins-maintained gitlink history
we can use to bisect.

>> I think of branch names as sticky notes (extra-lightweight tags,
>> sometimes).  We have linear history in many of our vendor submodules,
>> but multiple "branches" indicate where each superproject branch has
>> presumably finished integration.
>
> We also add a branch in submodules every time a superproject needs
> to move away from the submodules master (so the commits won't get
> lost by accident).

Good idea.  Gerrit sees to this for us also, but we do share code on
ancillary git servers and we follow the same practice.

>>>> But not all my developers are git-gurus yet, and they sometimes mess
>>>> up their ad hoc scripts or miss important changes they forgot to push
>>>> in one submodule or another.
>>>
>>> Sure, even though current git should help you some by showing changes
>>> in the submodules.
>>
>> Real newbies may not even remember to use 'git status' strategically.
>
> Hmm, but then they will screw up things in the superproject too, no?

What I mean is that a developer may be completely focused on one
particular submodule (his domain).  He does his work in this module,
and when it's ready he commits and pushes to the server.  'git status'
shows him that his directory is clean.  But this is only because he
doesn't really know where the submodules top-directories are, so he
doesn't realize that he has changes in another submodule that he has
not committed.  He has to know to run 'git status' from somewhere in
the superproject (ostensibly in the root directory of that
superproject).  But he may forget since 'git status' already assured
him he was done.

Like this:

#-- Setup
mkdir super && cd super && git init
mkdir A && touch A/foo
git add .
git submodule add gerrit:iptv/iptv_scripts B
git commit -m "Initial commit"

#-- Work flow
cd A && echo changes > foo
cd ../B && echo changes > foo
git add . && git commit -m "Made some changes"
git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
nothing to commit (working directory clean)

So git just told my new-to-git developer that his workdir is clean
because he happened to run it from super/B.  But if he ran it from
super/A (or super) it would tell him otherwise.

I guess what would help here is something like the opposite of 'git
status' showing the status of descendant submodules;  it would help if
it showed the status of sibling submodules and the superproject as
well.

>>>>  Or worse, their pull or push fails and
>>>> they can't see the problem for all the noise.  So they email it to me.
>>>
>>> We circumvent that by not pulling, but fetching and merging in the
>>> submodule first and after that in the superproject. You have much more
>>> control about what is going wrong where (and can have more
>>> git-experienced people help with - or even do - the merges).
>>
>> I do that, too, and I wish I didn't have to.  I wish I could safely
>> and sanely recover from a conflicted "git pull --recurse-submodules"
>> pull from the superproject.
>
> That's what my recursive checkout work is aiming at. Me thinks after
> that we will also need some good ideas on how to present and help
> solving submodule merge conflicts.
>
>> That is, I wish doing so were as
>> straightforward as recovering from the same condition would be if all
>> my code were in one repository instead of in submodules.
>>
>> Which is the gist -- I wish submodules did not make git more
>> complicated than it already is.
>
> I think we can make working with submodule much easier than it is
> now, the next step being updating all submodule work trees as git
> updates the superproject's work tree. Even though I suspect that in
> the long run submodules will always be a bit more complicated than
> having everything in one repository, I'm confident that will be by
> far outweighed by the advantages they bring.

I'm really looking forward to it.

Thanks,
Phil

^ permalink raw reply

* Project structure of .NET-Projects using git submodule or something different
From: Harald Heigl @ 2012-01-31 22:41 UTC (permalink / raw)
  To: git

Hi, I'm searching for an adequate Project-structure for our .NET-Projects,
but I think the problem isn't specific to .NET-Programs, it's more "how can
I nest submodules toghether".

Let's assume following Project structure (Dependencies and Subdependencies
are submodules and submodules of the submodules)
Project
	Dependency 1
		Dependency 2
		Dependency 3
	Dependency 4
	Dependency 2


The problem is if I want to build them I need to build 2+3, then 1, 4 and 2
again and then the project. As you may see project 2 is a submodule of
dependency 1 and also of project. I don't feel comfortable with this setup.
What do you think?
I've also thought about symlinks (though I'm mainly on Windows ), but with
symlinks I'll lose the tight coupling of git submodules by SHA1-revision.
I could also add Dependency 1-4 to my main project, not loading submodule
2-3 within  dependency 1, but then the Project-Files of .NET for dependency1
may change depending if I clone Dependency1 on its own or if I clone my
superproject.

Sometimes I have longer chains (project - submodule - subsubmodule - . ), so
it could easily be that I clone a superproject and 10 subprojects, even
though there are only 3-5 really different subprojects, rest would be
duplicates.

How would you handle this? Git submodules? Something different? 

Thanks in advance,
Harald

^ permalink raw reply

* Re: Alternates corruption issue
From: Jeff King @ 2012-01-31 22:42 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Junio C Hamano, Richard Purdie, GIT Mailing-list, Hart, Darren,
	Ashfield, Bruce
In-Reply-To: <20120131222258.GG13252@burratino>

On Tue, Jan 31, 2012 at 04:22:58PM -0600, Jonathan Nieder wrote:

> Forgetting the algorithms:
> 
>  (A) means "find what repository we are in the worktree for, or,
>  barring that, what bare repository we are in".
> 
>  (B) means "find which repository the user pointed to.  To be extra
>  nice, we allow a '.git' extension to be left out, so the URL used
>  doesn't have to include the redundant information that this is a
>  git repository, and we even allow pointing to the toplevel of a
>  worktree instead of a repository, too."

I can see that as a plausible interpretation. But I think your "means"
is kind of vague.  In other words, we are assigning a meaning that is
not actually documented anywhere, and which we are hoping matches user
expectations. So the correct behavior kind of depends on your mental
model. IOW, I find your mental model plausible, but it is not the one
that I had.

But like I said, I'm OK either way. I'll prepare this fix with the least
behavior change possible. Then doing your change on top should be a
trivial rearrangement of the lookup arrays (the "hard" part for your
proposed change is adding in the is_git_directory() calls[1], but I'll
do that as part of mine).

> I admit part of the reason I care is that just putting "" first would
> probably taken care of the more important part of
> <http://bugs.debian.org/399041>.

Would that fix it? If I understand it, the repo in question is bare with
a ".git" directory inside it. Your proposed change would make "git
ls-remote foo" work, but wouldn't "cd foo && git log" still be broken?
At the very least, it would show a completely different repo than
ls-remote.

-Peff

[1] Without the is_git_directory() check, the ordering you propose
    breaks things very badly. Because if I point to a non-bare directory
    "foo", we say "OK, foo exists" and never look at "foo/.git". So
    instead, we have to say "OK, foo exists, but hey, it looks nothing
    like a .git directory" and keep trying.

^ permalink raw reply

* Re: Alternates corruption issue
From: Jonathan Nieder @ 2012-01-31 22:22 UTC (permalink / raw)
  To: Jeff King
  Cc: Junio C Hamano, Richard Purdie, GIT Mailing-list, Hart, Darren,
	Ashfield, Bruce
In-Reply-To: <20120131220510.GA3253@sigill.intra.peff.net>

Jeff King wrote:

> True. But I consider that to make the walk-backwards-from-pwd case
> simply a superset. That is, in (A) we are walking backwards and trying
> to apply the lookup rule from (B) individually to each directory we
> consider (though even that is not entirely true, as we don't look for
> parallel "$PWD.git" directories in the walk).

That parenthesis is important.  Although in a nicer world maybe we
would want some symmetry like this, (A) and (B) really have nothing to
do with each other.

Forgetting the algorithms:

 (A) means "find what repository we are in the worktree for, or,
 barring that, what bare repository we are in".

 (B) means "find which repository the user pointed to.  To be extra
 nice, we allow a '.git' extension to be left out, so the URL used
 doesn't have to include the redundant information that this is a
 git repository, and we even allow pointing to the toplevel of a
 worktree instead of a repository, too."

Notice that the above description does not exactly match the actual
behavior of git.  For example, if someone has a directory layout like
this:

  repo-manipulator/
     .git/
     src/
     testcases/
       repo1.git/
       repo2.git/

and git is run from repo1.git, according to the description above, the
naive user _wanted_ git commands to apply to the toplevel repository.
And in practice, I think that's often true, though changing the
behavior of git to match that would not be worth the downsides.

> I'll admit I don't care that much, though. This is extremely unlikely to
> come up.

I admit part of the reason I care is that just putting "" first would
probably taken care of the more important part of
<http://bugs.debian.org/399041>.

Anyway, thanks for explaining.  Hopefully I can get to this soon and
factor out a common function for get_repo_path and enter_repo to call
so playing with the ordering becomes a little less scary. ;-)

Jonathan

^ permalink raw reply

* Re: Alternates corruption issue
From: Jeff King @ 2012-01-31 22:05 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Junio C Hamano, Richard Purdie, GIT Mailing-list, Hart, Darren,
	Ashfield, Bruce
In-Reply-To: <20120131215501.GF13252@burratino>

On Tue, Jan 31, 2012 at 03:55:01PM -0600, Jonathan Nieder wrote:

> >>  2) As a naive user, I would expect (A) to give a different result
> >>     from (B).
> >
> > Why?
> 
> Normally git commands expect me to be in (possibly a deeply nested
> subdirectory) of the worktree.  The typical case is a non-bare
> repository.  I have been taught that it walks to the toplevel and
> finds a ".git" directory.
> 
> By contrast, the path passed to git transport commands like "git fetch
> otherhost:/foo/bar/baz.git" is a path to the git repository metadata.
> I am not allowed to pass a path to a subdirectory, for example.

True. But I consider that to make the walk-backwards-from-pwd case
simply a superset. That is, in (A) we are walking backwards and trying
to apply the lookup rule from (B) individually to each directory we
consider (though even that is not entirely true, as we don't look for
parallel "$PWD.git" directories in the walk).

I'll admit I don't care that much, though. This is extremely unlikely to
come up. The real issue is fixing the fact that we prefer "foo.git" to
"foo", even when the user told us "foo". I am content to leave the rest
of it as-is, which is what my original patch did.

-Peff

^ permalink raw reply

* Re: Alternates corruption issue
From: Jonathan Nieder @ 2012-01-31 21:55 UTC (permalink / raw)
  To: Jeff King
  Cc: Junio C Hamano, Richard Purdie, GIT Mailing-list, Hart, Darren,
	Ashfield, Bruce
In-Reply-To: <20120131214740.GA2465@sigill.intra.peff.net>

Jeff King wrote:

> Right. But would you expect:
>
>   git ls-remote foo
>
> to behave the same as:
>
>   cd foo
>   git ls-remote .
>
> and would you furthermore expect that to behave the same as:
>
>   cd foo
>   git rev-parse --git-dir
>
> ?

Nah.  I never run "git ls-remote .". ;-)

[...]
>>  2) As a naive user, I would expect (A) to give a different result
>>     from (B).
>
> Why?

Normally git commands expect me to be in (possibly a deeply nested
subdirectory) of the worktree.  The typical case is a non-bare
repository.  I have been taught that it walks to the toplevel and
finds a ".git" directory.

By contrast, the path passed to git transport commands like "git fetch
otherhost:/foo/bar/baz.git" is a path to the git repository metadata.
I am not allowed to pass a path to a subdirectory, for example.

As a user, when would the distinction ever come up?  One is a fuzzy
"which repository am I working in", and the other is a precise "point
me to the metadata directory, but I allow you to abbreviate a little
by leaving out the trailing .git".

^ permalink raw reply

* Re: Alternates corruption issue
From: Jeff King @ 2012-01-31 21:47 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Junio C Hamano, Richard Purdie, GIT Mailing-list, Hart, Darren,
	Ashfield, Bruce
In-Reply-To: <20120131214047.GA13547@burratino>

On Tue, Jan 31, 2012 at 03:40:47PM -0600, Jonathan Nieder wrote:

> Jeff King wrote:
> 
> > No, it does not match. While the sequence I outlined above makes the
> > most sense to me, it does not match what setup_git_directory does, which
> > prefers "foo/.git" to using "foo" as a bare repo. I think being
> > consistent between all of the lookup points makes sense. The patch took
> > the least-invasive approach and aligned clone and enter_repo with
> > setup_git_directory.
> >
> > However, we could also tweak setup_git_directory to prefer bare repos
> > over ".git" to keep things consistent. While it makes me feel good from
> > a theoretical standpoint (because the rules above seem simple and
> > intuitive to me), I'm not sure it's a good idea in practice.
> 
> Wait, don't these two functions serve two completely different purposes?

Yes, but I would expect the lookup to be the same.

> One is the implementation of (A):
> 
> 	cd foo
> 	git rev-parse --git-dir
> 
> The other implements (B):
> 
> 	git ls-remote foo

Right. But would you expect:

  git ls-remote foo

to behave the same as:

  cd foo
  git ls-remote .

and would you furthermore expect that to behave the same as:

  cd foo
  git rev-parse --git-dir

?

Maybe I am crazy, but I see all of them as ways of specifying "I am
interested in repository foo", and any lookup magic should be the same
in all cases.

> If "foo" is actually a bare repository that moonlights as a worktree for
> a non-bare repository, then:
> 
>  1) Whoever set up these directories is completely insane[*].  Maybe we
>     should emit a warning.

Yes, I think we are dealing with an insane corner case.

>  2) As a naive user, I would expect (A) to give a different result
>     from (B).

Why?

-Peff

^ permalink raw reply

* Re: Alternates corruption issue
From: Jonathan Nieder @ 2012-01-31 21:40 UTC (permalink / raw)
  To: Jeff King
  Cc: Junio C Hamano, Richard Purdie, GIT Mailing-list, Hart, Darren,
	Ashfield, Bruce
In-Reply-To: <20120131204417.GA30969@sigill.intra.peff.net>

Jeff King wrote:

> No, it does not match. While the sequence I outlined above makes the
> most sense to me, it does not match what setup_git_directory does, which
> prefers "foo/.git" to using "foo" as a bare repo. I think being
> consistent between all of the lookup points makes sense. The patch took
> the least-invasive approach and aligned clone and enter_repo with
> setup_git_directory.
>
> However, we could also tweak setup_git_directory to prefer bare repos
> over ".git" to keep things consistent. While it makes me feel good from
> a theoretical standpoint (because the rules above seem simple and
> intuitive to me), I'm not sure it's a good idea in practice.

Wait, don't these two functions serve two completely different purposes?

One is the implementation of (A):

	cd foo
	git rev-parse --git-dir

The other implements (B):

	git ls-remote foo

If "foo" is actually a bare repository that moonlights as a worktree for
a non-bare repository, then:

 1) Whoever set up these directories is completely insane[*].  Maybe we
    should emit a warning.

 2) As a naive user, I would expect (A) to give a different result
    from (B).

Hope that helps,
Jonathan

[*] ok, ok, they can be confused instead of insane:
http://bugs.debian.org/399041

^ permalink raw reply

* Re: [RFC/PATCH] add update to branch support for "floating submodules"
From: Jens Lehmann @ 2012-01-31 20:55 UTC (permalink / raw)
  To: Phil Hord; +Cc: Junio C Hamano, Leif Gruenwoldt, git
In-Reply-To: <CABURp0pDoS1wgJ+Fs3XFX=A_EuR4Gzi4mHLiQP+-icT_d3J+WQ@mail.gmail.com>

Am 30.01.2012 22:15, schrieb Phil Hord:
> I lost my grip on this thread over the holidays...
> 
> On Tue, Dec 13, 2011 at 4:09 PM, Jens Lehmann <Jens.Lehmann@web.de> wrote:
>> Am 13.12.2011 15:17, schrieb Phil Hord:
>>>   git pull origin topic_foo && git submodule foreach 'git pull origin topic_foo'
>>>
>>>   git submodule foreach 'git push origin topic_foo' && git push origin topic_foo
>>
>> This sounds to me like you would need the "--recurse-submodules" option
>> implemented for "git pull" and "git push", no?
> 
> Only if I have nested submodules, but yes, we do use --recurs* in our scripts.

I'm confused, push doesn't know the "--recurse-submodules" option
at all yet while pull only does a deep fetch when it is given, the
submodule work trees are not updated to the merge result right now.

>> And I miss to see how
>> floating would help when the tips of some submodules are not ready to
>> work with other submodules tips ...
> 
> By project policy, for any branch, all submodules' tips of the
> same-named branch should be interoperable.  The CI server looks after
> this, as much as he can.

We do the same thing on our CI server, but it can only test some
combinations (even though that tends to show most problems pretty
early). But in the end every superproject is responsible to use a
working set of submodule commits, and I would rather bet on a
combination the CI server tested than on what happens to be on the
current tips.

> I think of branch names as sticky notes (extra-lightweight tags,
> sometimes).  We have linear history in many of our vendor submodules,
> but multiple "branches" indicate where each superproject branch has
> presumably finished integration.

We also add a branch in submodules every time a superproject needs
to move away from the submodules master (so the commits won't get
lost by accident).

>>> But not all my developers are git-gurus yet, and they sometimes mess
>>> up their ad hoc scripts or miss important changes they forgot to push
>>> in one submodule or another.
>>
>> Sure, even though current git should help you some by showing changes
>> in the submodules.
> 
> Real newbies may not even remember to use 'git status' strategically.

Hmm, but then they will screw up things in the superproject too, no?

>>>  Or worse, their pull or push fails and
>>> they can't see the problem for all the noise.  So they email it to me.
>>
>> We circumvent that by not pulling, but fetching and merging in the
>> submodule first and after that in the superproject. You have much more
>> control about what is going wrong where (and can have more
>> git-experienced people help with - or even do - the merges).
> 
> I do that, too, and I wish I didn't have to.  I wish I could safely
> and sanely recover from a conflicted "git pull --recurse-submodules"
> pull from the superproject.

That's what my recursive checkout work is aiming at. Me thinks after
that we will also need some good ideas on how to present and help
solving submodule merge conflicts.

> That is, I wish doing so were as
> straightforward as recovering from the same condition would be if all
> my code were in one repository instead of in submodules.
>
> Which is the gist -- I wish submodules did not make git more
> complicated than it already is.

I think we can make working with submodule much easier than it is
now, the next step being updating all submodule work trees as git
updates the superproject's work tree. Even though I suspect that in
the long run submodules will always be a bit more complicated than
having everything in one repository, I'm confident that will be by
far outweighed by the advantages they bring.

^ permalink raw reply

* Re: Alternates corruption issue
From: Jeff King @ 2012-01-31 20:44 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Richard Purdie, GIT Mailing-list, Hart, Darren, Ashfield, Bruce
In-Reply-To: <7v1uqf8vqu.fsf@alter.siamese.dyndns.org>

On Tue, Jan 31, 2012 at 12:25:45PM -0800, Junio C Hamano wrote:

> Jeff King <peff@peff.net> writes:
> 
> > I believe that would work in your case, but it seems like the most
> > correct thing would actually be:
> >
> >   { "", "/.git", ".git" }
> >
> > That is:
> >
> >   1. Try the literal path the user gave as a repo
> >
> >   2. Otherwise, try it as the root of a working tree (containing .git)
> >
> >   3. Otherwise, assume they were too lazy to type ".git" and include it
> 
> That sounds sensible, together with this, to which I agree with:
> [...]
> ... but ...
> [...]
> > -	static char *suffix[] = { "/.git", ".git", "" };
> > +	static char *suffix[] = { "/.git", "", ".git" };
> 
> ... this does not match that simple and clear guideline.
> 
> Shouldn't this simply be { "", "/.git", ".git" }?

No, it does not match. While the sequence I outlined above makes the
most sense to me, it does not match what setup_git_directory does, which
prefers "foo/.git" to using "foo" as a bare repo. I think being
consistent between all of the lookup points makes sense. The patch took
the least-invasive approach and aligned clone and enter_repo with
setup_git_directory.

However, we could also tweak setup_git_directory to prefer bare repos
over ".git" to keep things consistent. While it makes me feel good from
a theoretical standpoint (because the rules above seem simple and
intuitive to me), I'm not sure it's a good idea in practice.

The case we would "catch" with such a change is when you have a ".git"
directory inside a bare repo. Right now, we prefer the ".git" inside it,
and ignore the containing bare repo. With such a change, we would prefer
the outer bare repo. Which makes sense to me. It does break a use
case like this:

  # make a new repo
  git init
  cd .git
  # now track parts of the repo
  git init
  git add config
  git commit -m 'tracking our repo config'

but I'm not sure if that is sane or not.

But also consider false positives. What if you have a repository that
looks like a git repo (i.e., has "objects", "refs", and "HEAD" in it),
but also has ".git". Right now we say "Oh, it has .git, that must be the
repo". But with the proposed change, we could accidentally find the
enclosing repo.

Now, the chances of is_git_directory being wrong seem quite slim to me.
But then, the chances of somebody actually have a repo with a ".git"
_inside_ it seem pretty slim to me. So I think we are really dealing
with a tiny corner case, and it is perhaps anybody's guess whether
anyone is depending on the current behavior in the wild. I don't overly
care either way, but when in doubt, I tend to stick with the existing
behavior.

> >  	if (!strict) {
> >  		static const char *suffix[] = {
> > -			".git/.git", "/.git", ".git", "", NULL,
> > +			"/.git", "", ".git/.git", ".git", NULL,
> >  		};
> 
> Neither does this.
> 
> Shouldn't this be { "", "/.git", ".git", ".git/.git", NULL }?

Right, same case.

> I must be missing something from your description...

I mentioned the issue in my original message, but perhaps didn't
emphasize it very well.

-Peff

^ permalink raw reply

* Re: Alternates corruption issue
From: Junio C Hamano @ 2012-01-31 20:25 UTC (permalink / raw)
  To: Jeff King; +Cc: Richard Purdie, GIT Mailing-list, Hart, Darren, Ashfield, Bruce
In-Reply-To: <20120131193922.GA31551@sigill.intra.peff.net>

Jeff King <peff@peff.net> writes:

> I believe that would work in your case, but it seems like the most
> correct thing would actually be:
>
>   { "", "/.git", ".git" }
>
> That is:
>
>   1. Try the literal path the user gave as a repo
>
>   2. Otherwise, try it as the root of a working tree (containing .git)
>
>   3. Otherwise, assume they were too lazy to type ".git" and include it

That sounds sensible, together with this, to which I agree with:

> One way of dealing with that would be to make get_repo_path a little
> more robust by only selecting paths which actually look like git
> directories.

... but ...

> diff --git a/builtin/clone.c b/builtin/clone.c
> index 9084feb..0fbbae9 100644
> --- a/builtin/clone.c
> +++ b/builtin/clone.c
> @@ -108,7 +108,7 @@ static const char *argv_submodule[] = {
>  
>  static char *get_repo_path(const char *repo, int *is_bundle)
>  {
> -	static char *suffix[] = { "/.git", ".git", "" };
> +	static char *suffix[] = { "/.git", "", ".git" };

... this does not match that simple and clear guideline.

Shouldn't this simply be { "", "/.git", ".git" }?

> diff --git a/path.c b/path.c
> index b6f71d1..1ca6567 100644
> --- a/path.c
> +++ b/path.c
> @@ -293,7 +293,7 @@ const char *enter_repo(const char *path, int strict)
>  
>  	if (!strict) {
>  		static const char *suffix[] = {
> -			".git/.git", "/.git", ".git", "", NULL,
> +			"/.git", "", ".git/.git", ".git", NULL,
>  		};

Neither does this.

Shouldn't this be { "", "/.git", ".git", ".git/.git", NULL }?

I must be missing something from your description...

^ permalink raw reply

* Re: [PATCH] vcs-svn: Fix some compiler warnings
From: Junio C Hamano @ 2012-01-31 20:14 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: Ramsay Jones, David Barr, GIT Mailing-list
In-Reply-To: <20120131192053.GC12443@burratino>

Jonathan Nieder <jrnieder@gmail.com> writes:

> 		off_t delta_len = off_t_or_die(len, "enormous delta");
> 		postimage_len = apply_delta(delta_len, input, ...);
>
> What do you think?

Another possibility would be to make the "die" part responsibility of the
caller of the helper function, e.g.

	if (value_out_of_range(off_t, len))
		die("enormous delta");

which may make the caller easier to follow and the helper easier to reuse.

^ permalink raw reply

* Re: [PATCH] Fix an "variable might be used uninitialized" gcc warning
From: Jonathan Nieder @ 2012-01-31 19:43 UTC (permalink / raw)
  To: Ramsay Jones; +Cc: Junio C Hamano, GIT Mailing-list
In-Reply-To: <4F2834AD.20004@ramsay1.demon.co.uk>

Ramsay Jones wrote:

> The versions which complain are 3.4.4 and 4.1.2, whereas 4.4.0 compiles
> the code without complaint. So, gcc *may* be getting more sane, but I wouldn't
> bet on it! :-P
>
> I've had examples of this kind of warning, which relies heavily on the
> analysis performed primarily for the optimizer, come-and-go in gcc before

Yep, judging from the commit message, Junio found the same warning
in 4.6.2.

[...]
> Having said that, unless you are going to decree that the project only
> supports gcc (and presumably only some particular versions of gcc), then you
> may well find similar warnings triggered when using other compilers anyway ...

Sure, when the control flow grows too complicated, that's probably worth
fixing anyway, for the sake of humans especially.

Sometimes gcc is the only crazy one, though. ;-)

Thanks for the update.
Jonathan

^ permalink raw reply

* Re: Alternates corruption issue
From: Jeff King @ 2012-01-31 19:39 UTC (permalink / raw)
  To: Richard Purdie; +Cc: GIT Mailing-list, Hart, Darren, Ashfield, Bruce
In-Reply-To: <1328018729.13744.26.camel@ted>

On Tue, Jan 31, 2012 at 02:05:29PM +0000, Richard Purdie wrote:

> I have a problem with git clone commands using alternates failing by
> mixing up different repositories. I have a situation where I could end
> up with both:
> 
> /srv/mirrors/repo
> /srv/mirrors/repo.git

I think the alternates thing is just a side effect. The real problem is
that clone is picking the wrong repo to clone from! So a simple complete
test would be something like:

    # make confusing bare repos
    git init --bare bare &&
    git init --bare bare.git &&

    # now make some commits; after this
    # segment, "bare" should have its tip
    # at commit "one", and "bare.git" should
    # be at "two".
    git init source &&
    (cd source &&
     echo content >file &&
     git add file &&
     git commit -m one &&
     git push ../bare HEAD &&
     echo content >>file &&
     git commit -a -m two &&
     git push ../bare.git HEAD
    ) &&

    # now try to clone bare and see which one we get;
    # we would expect the tip to be at "one", but it's not
    git clone bare clone &&
    cd clone &&
    echo one >expect &&
    git log -1 --format=%s >actual &&
    diff -u expect actual

    # we cloned the wrong repository!

> Looking at the code, the cause seems to be
> 
> clone.c:get_repo_path():
> 
> 	static char *suffix[] = { "/.git", ".git", "" };
> 
> since its looking in order for:
>  repo/.git (fails)
>  repo.git (suceeds, incorrect)
>  repo (never looked at)

Yeah, this seems brain-dead. It's good that git looks through a magic
list to guess what I meant, but shouldn't the first thing it tries be
the literal string that I gave, and only _then_ kick in the magic?

But even weirder, this doesn't match the lookup in other parts of git. I
see four distinct places in git where we do repository lookup:

  1. get_repo_path used by clone (i.e., this)

  2. enter_repo used by upload-pack, receive-pack, and git-daemon; this
     looks first for ".git/.git", to find a non-bare repo which is named
     like a bare one.

  3. setup_git_directory_*, used by most git programs. This starts
     looking in the current directory and going up, looking first for
     ".git", and then checking for a bare repo. So if you were to do
     "cd bare && git foo", then we would correctly find the current
     directory, not "bare.git".

  4. setup_explicit_git_dir, which gets called if you use --git-dir or
     set GIT_DIR. This expects to find the repo directly in the
     directory you specified, with no magic.

So I think (3) and (4) are sensible, but I tend to think that (1) and
(2) are wrong, and should prefer the directory you gave before the
magic.

> I'm not sure what would break if that order were to change, swapping the
> last two options.

I believe that would work in your case, but it seems like the most
correct thing would actually be:

  { "", "/.git", ".git" }

That is:

  1. Try the literal path the user gave as a repo

  2. Otherwise, try it as the root of a working tree (containing .git)

  3. Otherwise, assume they were too lazy to type ".git" and include it

If you simply swap the last two, then there is one obscure case you
would miss: a bare repo which contains a .git directory. Of course, that
seems like an insane thing to have, but if you did have it, I would
expect git to follow the rules I outlined above. That being said,
if you follow the rules in setup_git_directory_gently_1, it actually
prefers "/.git" to a bare repo. So probably your swap is better, as it
matches the lookup here with the regular setup_git_directory one.

One slight complication is that get_repo_path only checks whether the
paths exist, not whether they are actually git repositories. So by
simply swapping the order, you are breaking some other obscure cases,
like where a "foo" directory exists but is _not_ a git repo, and a
"foo.git" exists alongside it (which sounds a bit crazy, but I could see
somebody using that scheme if they wanted didn't want the git repository
to live inside the worktree for some reason).

One way of dealing with that would be to make get_repo_path a little
more robust by only selecting paths which actually look like git
directories.

The patch below does this, and makes my test above pass. But I think
before talking too much about code, it would be best to decide on what
the lookup order _should_ be, and then we can write tests and implement
to them.

-Peff

---
diff --git a/builtin/clone.c b/builtin/clone.c
index 9084feb..0fbbae9 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -108,7 +108,7 @@ static const char *argv_submodule[] = {
 
 static char *get_repo_path(const char *repo, int *is_bundle)
 {
-	static char *suffix[] = { "/.git", ".git", "" };
+	static char *suffix[] = { "/.git", "", ".git" };
 	static char *bundle_suffix[] = { ".bundle", "" };
 	struct stat st;
 	int i;
@@ -118,7 +118,7 @@ static char *get_repo_path(const char *repo, int *is_bundle)
 		path = mkpath("%s%s", repo, suffix[i]);
 		if (stat(path, &st))
 			continue;
-		if (S_ISDIR(st.st_mode)) {
+		if (S_ISDIR(st.st_mode) && is_git_directory(path)) {
 			*is_bundle = 0;
 			return xstrdup(absolute_path(path));
 		} else if (S_ISREG(st.st_mode) && st.st_size > 8) {
diff --git a/cache.h b/cache.h
index 9bd8c2d..7b2857f 100644
--- a/cache.h
+++ b/cache.h
@@ -436,6 +436,7 @@ extern char *get_object_directory(void);
 extern char *get_index_file(void);
 extern char *get_graft_file(void);
 extern int set_git_dir(const char *path);
+extern int is_git_directory(const char *path);
 extern const char *get_git_namespace(void);
 extern const char *strip_namespace(const char *namespaced_ref);
 extern const char *get_git_work_tree(void);
diff --git a/path.c b/path.c
index b6f71d1..1ca6567 100644
--- a/path.c
+++ b/path.c
@@ -293,7 +293,7 @@ const char *enter_repo(const char *path, int strict)
 
 	if (!strict) {
 		static const char *suffix[] = {
-			".git/.git", "/.git", ".git", "", NULL,
+			"/.git", "", ".git/.git", ".git", NULL,
 		};
 		const char *gitfile;
 		int len = strlen(path);
@@ -324,8 +324,11 @@ const char *enter_repo(const char *path, int strict)
 			return NULL;
 		len = strlen(used_path);
 		for (i = 0; suffix[i]; i++) {
+			struct stat st;
 			strcpy(used_path + len, suffix[i]);
-			if (!access(used_path, F_OK)) {
+			if (!stat(used_path, &st) &&
+			    (S_ISREG(st.st_mode) ||
+			     (S_ISDIR(st.st_mode) && is_git_directory(used_path)))) {
 				strcat(validated_path, suffix[i]);
 				break;
 			}
diff --git a/setup.c b/setup.c
index 61c22e6..7a3618f 100644
--- a/setup.c
+++ b/setup.c
@@ -247,7 +247,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
  *    a proper "ref:", or a regular file HEAD that has a properly
  *    formatted sha1 object name.
  */
-static int is_git_directory(const char *suspect)
+int is_git_directory(const char *suspect)
 {
 	char path[PATH_MAX];
 	size_t len = strlen(suspect);

^ permalink raw reply related

* Re: [PATCH v2] find_pack_entry(): do not keep packed_git pointer locally
From: Nicolas Pitre @ 2012-01-31 19:28 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Nguyễn Thái Ngọc Duy, git
In-Reply-To: <7vr4yf92dg.fsf@alter.siamese.dyndns.org>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1509 bytes --]

On Tue, 31 Jan 2012, Junio C Hamano wrote:

> Nguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:
> 
> > +		/*
> > +		 * p can be NULL from the else clause above, if initial
> > +		 * f_p_e_last_found value (i.e. INVALID_PACK) is NULL, we may
> > +		 * advance p again to an imaginary pack in invalid memory
> > +		 */

Ah!  OK so that's why I initially came up with that (void*)1 value.

> But I think the real issue is that the original loop is written in an
> obscure way.

Can't disagree with that, especially when the original author (myself) 
doesn't see clearly through it anymore.

> The conversion in f7c22cc (always start looking up objects in the last 
> used pack first, 2007-05-30) wanted to turn the traversal that always 
> went from the tip of a linked list to instead first probe the 
> promising one, and then scan the list from the tip like it used to do, 
> except that it did not want to probe the one it thought promising 
> again.

Exact.

> So perhaps restructuring the loop by making the logic to probe into a
> single pack into a helper function, e.g.
> 
> static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
> {
> 	if (last_found) {
> 		if (find_one(sha1, e, last_found))
> 			return 1;
> 	}
>         for (p = packed_git; p; p = p->next) {
>         	if (p == last_found || !find_one(sha1, e, p))
> 			continue;
> 		last_found = p;
> 		return 1;
> 	}
>         return 0;
> }
> 
> would make the resulting flow far easier to follow, no?

Indeed.


Nicolas

^ permalink raw reply

* Re: [PATCH] vcs-svn: Fix some compiler warnings
From: Jonathan Nieder @ 2012-01-31 19:20 UTC (permalink / raw)
  To: Ramsay Jones; +Cc: David Barr, Junio C Hamano, GIT Mailing-list
In-Reply-To: <4F28378F.6080108@ramsay1.demon.co.uk>

Hi,

Ramsay Jones wrote:

> In particular, some versions of gcc complains as follows:
> 
>         CC vcs-svn/sliding_window.o
>     vcs-svn/sliding_window.c: In function `check_overflow':
>     vcs-svn/sliding_window.c:36: warning: comparison is always false \
>         due to limited range of data type

Yuck.  Suppressing this warning would presumably also suppress the
optimization that notices the comparison is always false.

The -Wtype-limits warning also triggers in some other perfectly
reasonable situations: see <http://gcc.gnu.org/PR51712>.  I wonder if
we should keep a list of unreliable warnings somewhere (e.g.,
Meta/Make).

[...]
> Note that the "some versions of gcc" which complain includes 3.4.4 and
> 4.1.2, whereas gcc version 4.4.0 compiles the code without complaint.

Thanks for tracking this down.  Interesting.  -Wtype-limits was split
out from the default set of warnings (!) in gcc 4.3 to address
<http://gcc.gnu.org/PR12963>, among other bugs (r124875, 2007-05-20).

[...]
> --- a/vcs-svn/fast_export.c
> +++ b/vcs-svn/fast_export.c
> @@ -300,7 +300,8 @@ void fast_export_blob_delta(uint32_t mode,
>  				uint32_t len, struct line_buffer *input)
>  {
>  	long postimage_len;
> -	if (len > maximum_signed_value_of_type(off_t))
> +	uintmax_t delta_len = (uintmax_t) len;
> +	if (delta_len > maximum_signed_value_of_type(off_t))
>  		die("enormous delta");
>  	postimage_len = apply_delta((off_t) len, input, old_data, old_mode);

Is there some less ugly way to write the condition "if this value is
not representable in this type"?

I guess I could live with something like the following (please don't
take the names too seriously):

	static inline off_t off_t_or_die(uintmax_t val, const char *msg_if_bad)
	{
		if (val > maximum_signed_value_of_type(off_t))
			die("%s", msg_if_bad);
		return (off_t) val;
	}

	...

		off_t delta_len = off_t_or_die(len, "enormous delta");
		postimage_len = apply_delta(delta_len, input, ...);

What do you think?

Jonathan

^ permalink raw reply

* [PATCH] vcs-svn: Fix some compiler warnings
From: Ramsay Jones @ 2012-01-31 18:48 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: david.barr, Junio C Hamano, GIT Mailing-list


In particular, some versions of gcc complains as follows:

        CC vcs-svn/sliding_window.o
    vcs-svn/sliding_window.c: In function `check_overflow':
    vcs-svn/sliding_window.c:36: warning: comparison is always false \
        due to limited range of data type

        CC vcs-svn/fast_export.o
    vcs-svn/fast_export.c: In function `fast_export_blob_delta':
    vcs-svn/fast_export.c:303: warning: comparison is always false due \
        to limited range of data type

Simply casting the (limited range unsigned) variable in the comparison
to an uintmax_t does not suppress the warning, however, since gcc is
"smart" enough to know that the cast does not change anything regarding
the value of the casted expression. In order to suppress the warning, we
replace the variable with a new uintmax_t variable initialized with the
value of the original variable.

Note that the "some versions of gcc" which complain includes 3.4.4 and
4.1.2, whereas gcc version 4.4.0 compiles the code without complaint.

Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
---

Hi Jonathan,

When I wrote this patch, your "jn/svn-fe" branch was still in pu, so I was
going to ask you to squash this, or some variant, into any re-roll ...

Note, in the original version of this patch, the change to check_overflow()
was much simpler; it was effectively the same 2-line change (modulo some
variable names) which is applied to fast_export_blob_delta(). But it just
didn't look right (not sure why!), which prompted the renaming of the
function parameter names. This is, obviously, an unrelated change, so maybe
the change to sliding_window.c should be reverted to the 2-line change ...

ATB,
Ramsay Jones

 vcs-svn/fast_export.c    |    3 ++-
 vcs-svn/sliding_window.c |   11 ++++++-----
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
index 19d7c34..6edd37e 100644
--- a/vcs-svn/fast_export.c
+++ b/vcs-svn/fast_export.c
@@ -300,7 +300,8 @@ void fast_export_blob_delta(uint32_t mode,
 				uint32_t len, struct line_buffer *input)
 {
 	long postimage_len;
-	if (len > maximum_signed_value_of_type(off_t))
+	uintmax_t delta_len = (uintmax_t) len;
+	if (delta_len > maximum_signed_value_of_type(off_t))
 		die("enormous delta");
 	postimage_len = apply_delta((off_t) len, input, old_data, old_mode);
 	if (mode == REPO_MODE_LNK) {
diff --git a/vcs-svn/sliding_window.c b/vcs-svn/sliding_window.c
index 1bac7a4..49a7293 100644
--- a/vcs-svn/sliding_window.c
+++ b/vcs-svn/sliding_window.c
@@ -31,15 +31,16 @@ static int read_to_fill_or_whine(struct line_buffer *file,
 	return 0;
 }
 
-static int check_overflow(off_t a, size_t b)
+static int check_overflow(off_t offset, size_t len)
 {
-	if (b > maximum_signed_value_of_type(off_t))
+	uintmax_t delta_len = (uintmax_t) len;
+	if (delta_len > maximum_signed_value_of_type(off_t))
 		return error("unrepresentable length in delta: "
-				"%"PRIuMAX" > OFF_MAX", (uintmax_t) b);
-	if (signed_add_overflows(a, (off_t) b))
+				"%"PRIuMAX" > OFF_MAX", delta_len);
+	if (signed_add_overflows(offset, (off_t) len))
 		return error("unrepresentable offset in delta: "
 				"%"PRIuMAX" + %"PRIuMAX" > OFF_MAX",
-				(uintmax_t) a, (uintmax_t) b);
+				(uintmax_t) offset, delta_len);
 	return 0;
 }
 
-- 
1.7.9

^ permalink raw reply related


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