* Re: [PATCH] rebase -i: only automatically amend commit if HEAD did not change
From: Avery Pennarun @ 2008-07-23 15:53 UTC (permalink / raw)
To: Dmitry Potapov; +Cc: Johannes Schindelin, git, gitster
In-Reply-To: <20080723120104.GQ2925@dpotapov.dyndns.org>
On 7/23/08, Dmitry Potapov <dpotapov@gmail.com> wrote:
> On Tue, Jul 22, 2008 at 06:22:34PM -0400, Avery Pennarun wrote:
> > This patch is perhaps a symptom of something I've been meaning to ask
> > about for a while.
> >
> > Why doesn't "edit" just stage the commit and not auto-commit it at
> > all? That way an amend would *never* be necessary, and rebase
> > --continue would always do a commit -a (if there was anything left to
> > commit).
>
> Actually, it would be better to refuse to continue if there are unstaged
> changes in the work tree, and if all changes are staged then just do git
> commit.
I'm not sure about that. The auto-committing on --continue has never
annoyed me, and in fact I greatly appreciate that I can just "git
rebase --continue" after making changes and the expected thing will
happen. After all, if I screw it up and commit too much at once, I
can always just rebase one more time.
However, taking out the auto-commit wouldn't pain me too much if
others want it that way. It would be somewhat more typing, but at
least makes easy to understand exactly what's going on.
> It would not only save typing, but also help to avoid costly mistakes
> where users, being taught to use "git commit --amend" after editing
> during git-rebase, fire this command automatically after a conflict
> resolution and get two commits accidently squashed.
Yes! Good point. I forgot about this, but I've been bitten by it a
couple of times.
Have fun,
Avery
^ permalink raw reply
* Re: git-svn does not seems to work with crlf convertion enabled.
From: Avery Pennarun @ 2008-07-23 15:49 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Alexander Litvinov, git
In-Reply-To: <alpine.DEB.1.00.0807231356540.8986@racer>
On 7/23/08, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> On Wed, 23 Jul 2008, Alexander Litvinov wrote:
> > > On Wed, 23 Jul 2008, Alexander Litvinov wrote:
> > > > In short: I can't clone svn repo into git when crlf convertion is
> > > > activated.
> > >
> > > This is a known issue, but since nobody with that itch seems to care
> > > enough to fix it, I doubt it will ever be fixed.
> >
> > That is a bad news for me. Anyway I will spend some time at holidays
> > during digging this bug.
>
> Note that you will have to do your digging using msysGit (i.e. the
> developer's pack, not the installer for plain Git), since git-svn will be
> removed from the next official "Windows Git" release, due to lack of
> fixers.
Presumably cygwin git will work too, right?
Does this known issue apply only to msysGit, or both msys and Cygwin,
or all versions? ie. could it be debugged on Linux?
Thanks,
Avery
^ permalink raw reply
* Re: [RFC] Git User's Survey 2008
From: Matthias Kestenholz @ 2008-07-23 15:43 UTC (permalink / raw)
To: Dmitry Potapov; +Cc: Jakub Narebski, git, Stephan Beyer
In-Reply-To: <20080723143810.GR2925@dpotapov.dyndns.org>
On Wed, 2008-07-23 at 18:38 +0400, Dmitry Potapov wrote:
> On Wed, Jul 23, 2008 at 03:25:03AM +0200, Jakub Narebski wrote:
> > 02. What is your preferred non-programming language?
> > (or) What is the language you want computer communicate with you?
>
> IMHO, the later wording of the question is much better.
I think these are two separate questions. In my case the first is
(swiss) german, the second is english. I don't like localized software
too much, I always have to think what a certain german term might mean
in english to understand computing-specific texts.
That being said I think that the first question is irrelevant for the
git survey. Maybe we should use the term 'internationalization' or
'localization' somewhere to make clear what we are talking about. While
these terms might scare newbies away we can reasonably expect that they
are known by git users.
Matthias
^ permalink raw reply
* Re: [PATCH 2/2] sort_in_topological_order(): avoid setting a commit flag
From: Jon Loeliger @ 2008-07-23 15:39 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Johannes Schindelin, pasky, git
In-Reply-To: <7v7ibdifbp.fsf@gitster.siamese.dyndns.org>
Junio C Hamano wrote:
>
> Do people still actively use show-branch as a G/CUI, especially after that
> "log --graph" thing was introduced?
At the risk of sounding Old School, yes.
While the "log --graph" thing is Really Slick, it has
grumbly-factors, IMO. First, I have to set up an alias
all the time, as "git log --graph --pretty=oneline" is
grumpy typing. Second, I always have to widen my screen
to accommodate reasonable looking output or colrm it.
(Having it self-colrm to window-width would be nice.)
(Sure, --abbrev-commit too, but see "First," above. :-))
Finally, I frequently like seeing a self-limited history
when all the branches reach their common ancestor.
HTH,
jdl
^ permalink raw reply
* Re: [RFC PATCH 00/12] Sparse checkout
From: Nguyen Thai Ngoc Duy @ 2008-07-23 15:38 UTC (permalink / raw)
To: git
In-Reply-To: <20080723145518.GA29035@laptop>
Sorry list. Forgot --thread in format-patch :(
--
Duy
^ permalink raw reply
* Re: [PATCH] index-pack: never prune base_cache.
From: Pierre Habouzit @ 2008-07-23 15:30 UTC (permalink / raw)
To: Johannes Schindelin
Cc: Björn Steinbrink, spearce, Git ML, Junio C Hamano
In-Reply-To: <alpine.DEB.1.00.0807231537420.8986@racer>
[-- Attachment #1: Type: text/plain, Size: 1310 bytes --]
On Wed, Jul 23, 2008 at 02:41:14PM +0000, Johannes Schindelin wrote:
> Hi,
>
> On Wed, 23 Jul 2008, Björn Steinbrink wrote:
>
> > diff --git a/index-pack.c b/index-pack.c
> > index ac20a46..33ba8ef 100644
> > --- a/index-pack.c
> > +++ b/index-pack.c
> > @@ -699,6 +699,9 @@ static struct object_entry *append_obj_to_pack(
> > write_or_die(output_fd, header, n);
> > obj[0].idx.crc32 = crc32(0, Z_NULL, 0);
> > obj[0].idx.crc32 = crc32(obj[0].idx.crc32, header, n);
> > + obj[0].hdr_size = n;
> > + obj[0].type = type;
> > + obj[0].size = size;
> > obj[1].idx.offset = obj[0].idx.offset + n;
> > obj[1].idx.offset += write_compressed(output_fd, buf, size, &obj[0]..idx.crc32);
> > hashcpy(obj->idx.sha1, sha1);
>
> I confirm that the issues I saw went away with this patch, and it looks
> obviously like the correct approach.
>
> The only things valgrind is still complaining about (apart from libz,
> which I will not bother commenting about) are uninitialized parts of the
> data being written to disk, and a crc over them.
>
> Judging from the addresses, those are probably the bytes that are padded
> for 4- or 8-byte alignment, so they are probably fine.
I confirm this analysis having done the same independently and reached
the same conclusions.
[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
* Re: q: faster way to integrate/merge lots of topic branches?
From: Ingo Molnar @ 2008-07-23 15:06 UTC (permalink / raw)
To: Jay Soffian; +Cc: git
In-Reply-To: <20080723145622.GA23440@elte.hu>
* Ingo Molnar <mingo@elte.hu> wrote:
> > Shouldn't this be:
> >
> > [ -f "$CACHE" -a "$CACHE" -nt .git/refs/heads/$BRANCH ] && {
> >
> > ?
>
> yeah, i just figured it out too ... the hard way :)
>
> Updated script below. This works fine across resets in the master
> branch.
>
> While it's fast in the empty-merge case, it's not as fast as i'd like
> it to be in the almost-empty-merge case.
When i update a topic branch, i first get a relatively fast run:
earth4:~/tip> time todo-merge-all
merging all branches ...
Auto-merged arch/x86/kernel/genx2apic_uv_x.c
Merge made by recursive.
arch/x86/kernel/genx2apic_uv_x.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
... merge done.
real 0m6.625s
user 0m3.740s
sys 0m2.563s
Then on the next run it's slower:
earth4:~/tip> time todo-merge-all
merging all branches ...
... merge done.
real 0m30.823s
user 0m23.403s
sys 0m7.545s
that's unfortunate. The freshly updated topic branch was at the end of
the run, now all other topic branches will have to run slow at least
once until they become cached again.
Perhaps the cache should update all other current topics to the new
sha1, to establish the fact that they were not merged this time. (and
that they are still not to be merged)
(It's still much faster than completely uncached though, because of the
overlap in sha1's.)
Third (empty) run is fast again, because it's fully cached:
earth4:~/tip> time todo-merge-all
merging all branches ...
... merge done.
real 0m3.036s
user 0m1.360s
sys 0m1.782s
But it would be nice if the cache worked more intelligently in the
one-topic-updated-only case as well.
Ingo
^ permalink raw reply
* [PATCH 12/12] git-status: print sparse checkout status
From: Nguyễn Thái Ngọc Duy @ 2008-07-23 14:58 UTC (permalink / raw)
To: git
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
wt-status.c | 12 +++++++++---
1 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/wt-status.c b/wt-status.c
index 889e50f..28add31 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -361,12 +361,18 @@ void wt_status_print(struct wt_status *s)
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "# Initial commit");
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
- wt_status_print_initial(s);
}
- else {
- wt_status_print_updated(s);
+
+ if (get_sparse_prefix()) {
+ color_fprintf(s->fp, color(WT_STATUS_HEADER), "# Sparse checkout: ");
+ color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), get_sparse_prefix_str());
}
+ if (s->is_initial)
+ wt_status_print_initial(s);
+ else
+ wt_status_print_updated(s);
+
wt_status_print_changed(s);
if (wt_status_submodule_summary)
wt_status_print_submodule_summary(s);
--
1.5.5.GIT
^ permalink raw reply related
* [PATCH 10/12] git-checkout: support --full and --path to manipulate sparse checkout
From: Nguyễn Thái Ngọc Duy @ 2008-07-23 14:57 UTC (permalink / raw)
To: git
"git checkout --full" will quit sparse checkout mode while
"git checkout --sparse=prefix" will turn on sparse checkout or
update sparse prefix.
twoway_merge has been updated to deal with sparse checkout update.
Files that are in old sparse prefix only will get removed while
files that are in new sparse prefix only will get added.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
builtin-checkout.c | 44 +++++++++++++++++++
cache.h | 2 +
unpack-trees.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++----
unpack-trees.h | 3 +-
4 files changed, 160 insertions(+), 9 deletions(-)
diff --git a/builtin-checkout.c b/builtin-checkout.c
index eec1bde..410a53a 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -160,6 +160,9 @@ struct checkout_opts {
char *new_branch;
int new_branch_log;
enum branch_track track;
+
+ char *sparse_prefix;
+ int no_sparse_checkout;
};
static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree)
@@ -255,7 +258,25 @@ static int merge_working_tree(struct checkout_opts *opts,
tree = parse_tree_indirect(new->commit->object.sha1);
init_tree_desc(&trees[1], tree->buffer, tree->size);
+ if (opts->no_sparse_checkout)
+ topts.new_sparse_prefix = 1;
+
+ if (opts->sparse_prefix) {
+ char **new_sparse_prefix = split_prefix(opts->sparse_prefix);
+
+ if (!new_sparse_prefix) {
+ error("new sparse prefix invalid");
+ return 1;
+ }
+ topts.new_sparse_prefix = 1;
+ topts.unpack_data = new_sparse_prefix;
+ }
+
ret = unpack_trees(2, trees, &topts);
+
+ if (topts.new_sparse_prefix && topts.unpack_data)
+ free_prefix_list((char **)topts.unpack_data);
+
if (ret == -1) {
/*
* Unpack couldn't do a trivial merge; either
@@ -299,6 +320,14 @@ static int merge_working_tree(struct checkout_opts *opts,
commit_locked_index(lock_file))
die("unable to write new index file");
+ /*
+ * update sparse checkout accordingly
+ * show_local_changes will need it
+ */
+ if (opts->no_sparse_checkout)
+ free_prefix_list(save_sparse_prefix());
+ if (opts->sparse_prefix)
+ set_sparse_prefix(opts->sparse_prefix);
if (!opts->force)
show_local_changes(&new->commit->object);
@@ -409,6 +438,13 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
update_refs_for_switch(opts, &old, new);
+ /* now save new sparse prefix */
+ if (opts->no_sparse_checkout)
+ git_config_set("core.sparsecheckout", NULL);
+
+ if (opts->sparse_prefix)
+ git_config_set("core.sparsecheckout", opts->sparse_prefix);
+
ret = post_checkout_hook(old.commit, new->commit, 1);
return ret || opts->writeout_error;
}
@@ -428,6 +464,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
BRANCH_TRACK_EXPLICIT),
OPT_BOOLEAN('f', NULL, &opts.force, "force"),
OPT_BOOLEAN('m', NULL, &opts.merge, "merge"),
+ OPT_STRING(0, "path", &opts.sparse_prefix, "prefixes", "update sparse checkout"),
+ OPT_BOOLEAN(0, "full", &opts.no_sparse_checkout, "quit sparse checkout"),
OPT_END(),
};
@@ -468,6 +506,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
if (!opts.new_branch && (opts.track != git_branch_track))
die("git checkout: --track and --no-track require -b");
+ if (opts.no_sparse_checkout && opts.sparse_prefix)
+ die("git checkout: --path and --full are incompatible");
+
if (opts.force && opts.merge)
die("git checkout: -f and -m are incompatible");
@@ -486,6 +527,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
}
}
+ if (opts.no_sparse_checkout || opts.sparse_prefix)
+ die("git checkout: updating paths is incompatible with setting sparse checkout");
+
return checkout_paths(source_tree, pathspec);
}
diff --git a/cache.h b/cache.h
index b9a1d96..9e7f146 100644
--- a/cache.h
+++ b/cache.h
@@ -138,6 +138,8 @@ struct cache_entry {
#define CE_HASHED (0x100000)
#define CE_UNHASHED (0x200000)
+#define CE_WD_REMOVE (0x400000)
+
/*
* Copy the sha1 and stat state of a cache entry from one to
* another. But we never change the name, or the hash state!
diff --git a/unpack-trees.c b/unpack-trees.c
index 0a30d68..a88c53f 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -105,13 +105,29 @@ static int check_updates(struct unpack_trees_options *o)
struct index_state *index = &o->result;
int i;
int errs = 0;
+ char **old_sparse_prefix = NULL;
+ char **new_sparse_prefix = NULL;
+
+ /*
+ * for sparse checkout update, we need to widen the prefix a bit
+ * so that updating in new sparse prefix won't get caught by
+ * sparse prefix checks
+ */
+ if (o->new_sparse_prefix) {
+ old_sparse_prefix = save_sparse_prefix();
+ if (o->unpack_data) {
+ new_sparse_prefix = o->unpack_data;
+ new_sparse_prefix = combine_prefix_list(old_sparse_prefix, new_sparse_prefix);
+ restore_sparse_prefix(new_sparse_prefix);
+ }
+ }
if (o->update && o->verbose_update) {
for (total = cnt = 0; cnt < index->cache_nr; cnt++) {
struct cache_entry *ce = index->cache[cnt];
if (outside_sparse_prefix(ce->name))
continue;
- if (ce->ce_flags & (CE_UPDATE | CE_REMOVE))
+ if (ce->ce_flags & (CE_UPDATE | CE_REMOVE | CE_WD_REMOVE))
total++;
}
@@ -125,12 +141,14 @@ static int check_updates(struct unpack_trees_options *o)
if (outside_sparse_prefix(ce->name))
continue;
- if (ce->ce_flags & CE_REMOVE) {
+ if (ce->ce_flags & (CE_REMOVE | CE_WD_REMOVE)) {
display_progress(progress, ++cnt);
if (o->update)
unlink_entry(ce);
- remove_index_entry_at(&o->result, i);
- i--;
+ if (ce->ce_flags & CE_REMOVE) {
+ remove_index_entry_at(&o->result, i);
+ i--;
+ }
continue;
}
}
@@ -149,6 +167,10 @@ static int check_updates(struct unpack_trees_options *o)
}
}
stop_progress(&progress);
+ if (o->new_sparse_prefix) {
+ restore_sparse_prefix(old_sparse_prefix);
+ free_prefix_list(new_sparse_prefix);
+ }
return errs != 0;
}
@@ -680,8 +702,8 @@ static int verify_absent(struct cache_entry *ce, const char *action,
return 0;
}
-static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
- struct unpack_trees_options *o)
+static int merged_entry_internal(struct cache_entry *merge, struct cache_entry *old,
+ struct unpack_trees_options *o, int set, int clear)
{
int update = CE_UPDATE;
@@ -708,10 +730,28 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
invalidate_ce_path(merge, o);
}
- add_entry(o, merge, update, CE_STAGEMASK);
+ add_entry(o, merge, (update & (~clear)) | set, CE_STAGEMASK);
return 1;
}
+static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
+ struct unpack_trees_options *o)
+{
+ return merged_entry_internal(merge, old, o, 0, 0);
+}
+
+static int merged_entry_and_no_add(struct cache_entry *merge, struct cache_entry *old,
+ struct unpack_trees_options *o)
+{
+ return merged_entry_internal(merge, old, o, 0, CE_UPDATE);
+}
+
+static int merged_entry_and_add(struct cache_entry *merge, struct cache_entry *old,
+ struct unpack_trees_options *o)
+{
+ return merged_entry_internal(merge, old, o, CE_UPDATE, 0);
+}
+
static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
struct unpack_trees_options *o)
{
@@ -734,6 +774,20 @@ static int keep_entry(struct cache_entry *ce, struct unpack_trees_options *o)
return 1;
}
+static int keep_entry_and_add(struct cache_entry *ce, struct unpack_trees_options *o)
+{
+ add_entry(o, ce, CE_UPDATE, 0);
+ return 1;
+}
+
+static int keep_entry_and_remove(struct cache_entry *ce, struct unpack_trees_options *o)
+{
+ if (verify_uptodate(ce, o))
+ return -1;
+ add_entry(o, ce, CE_WD_REMOVE, 0);
+ return 1;
+}
+
#if DBRT_DEBUG
static void show_stage_entry(FILE *o,
const char *label, const struct cache_entry *ce)
@@ -918,12 +972,31 @@ int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o)
* over a merge failure when it makes sense. For details of the
* "carry forward" rule, please see <Documentation/git-read-tree.txt>.
*
+ * Two-way merge with sparse prefix update.
+ *
+ * The rules are as same as plain two-way merge, except:
+ * 1) if it's in old sparse checkout, but not the new one, mark it CE_WD_REMOVE
+ * 2) if it's in the new one, but not the old one, mark it CE_UPDATE
+ * 3) otherwise, let old two-way merge take it
+ *
+ * case 1)
+ * keep index implies CE_WD_REMOVE (remove workdir only, keep file in index)
+ * use M implies no CE_UPDATE
+ * if index is not clean, fail
+ *
+ * case 2)
+ * keep index implies CE_UPDATE
+ * use M implies CE_UPDATE
+ * index can't be unclean, so ignore this
+ *
*/
int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o)
{
struct cache_entry *current = src[0];
struct cache_entry *oldtree = src[1];
struct cache_entry *newtree = src[2];
+ int remove = 0, add = 0;
+ char **new_sparse_prefix = (char **)o->unpack_data;
if (o->merge_size != 2)
return error("Cannot do a twoway merge of %d trees",
@@ -935,6 +1008,13 @@ int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o)
newtree = NULL;
if (current) {
+ if (o->new_sparse_prefix) {
+ remove = !outside_sparse_prefix(current->name) &&
+ outside_prefix_list(new_sparse_prefix, current->name);
+ add = outside_sparse_prefix(current->name) &&
+ !outside_prefix_list(new_sparse_prefix, current->name);
+ }
+
if ((!oldtree && !newtree) || /* 4 and 5 */
(!oldtree && newtree &&
same(current, newtree)) || /* 6 and 7 */
@@ -943,6 +1023,12 @@ int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o)
(oldtree && newtree &&
!same(oldtree, newtree) && /* 18 and 19 */
same(current, newtree))) {
+ if (o->new_sparse_prefix) {
+ if (remove)
+ return keep_entry_and_remove(current, o);
+ if (add)
+ return keep_entry_and_add(current, o);
+ }
return keep_entry(current, o);
}
else if (oldtree && !newtree && same(current, oldtree)) {
@@ -952,6 +1038,12 @@ int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o)
else if (oldtree && newtree &&
same(current, oldtree) && !same(current, newtree)) {
/* 20 or 21 */
+ if (o->new_sparse_prefix) {
+ if (remove)
+ return merged_entry_and_no_add(newtree, current, o);
+ if (add)
+ return merged_entry_and_add(newtree, current, o);
+ }
return merged_entry(newtree, current, o);
}
else {
@@ -965,8 +1057,20 @@ int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o)
return -1;
}
}
- else if (newtree)
+ else if (newtree) {
+ if (o->new_sparse_prefix) {
+ remove = !outside_sparse_prefix(newtree->name) &&
+ outside_prefix_list(new_sparse_prefix, newtree->name);
+ add = outside_sparse_prefix(newtree->name) &&
+ !outside_prefix_list(new_sparse_prefix, newtree->name);
+
+ if (remove)
+ return merged_entry_and_no_add(newtree, current, o);
+ if (add)
+ return merged_entry_and_add(newtree, current, o);
+ }
return merged_entry(newtree, current, o);
+ }
return deleted_entry(oldtree, current, o);
}
diff --git a/unpack-trees.h b/unpack-trees.h
index a1b46f9..5a29fc4 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -27,7 +27,8 @@ struct unpack_trees_options {
aggressive:1,
skip_unmerged:1,
gently:1,
- check_index_prefix:1;
+ check_index_prefix:1,
+ new_sparse_prefix:1; /* unpack_data must contain new prefix */
const char *prefix;
int pos;
struct dir_struct *dir;
--
1.5.5.GIT
^ permalink raw reply related
* [PATCH 11/12] tests for checkout [--full|--path]
From: Nguyễn Thái Ngọc Duy @ 2008-07-23 14:57 UTC (permalink / raw)
To: git
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
t/t2010-checkout-sparse.sh | 71 ++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 71 insertions(+), 0 deletions(-)
create mode 100755 t/t2010-checkout-sparse.sh
diff --git a/t/t2010-checkout-sparse.sh b/t/t2010-checkout-sparse.sh
new file mode 100755
index 0000000..5bb82ae
--- /dev/null
+++ b/t/t2010-checkout-sparse.sh
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+test_description='sparse checkout'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+ mkdir work1 work2 work3
+ touch one two three
+ touch work1/one work2/two work3/three
+ git add one work1/one
+ git commit -m work1
+ git add two work2/two
+ git commit -m work2
+ git add three work3/three
+ git commit -m work3
+'
+
+test_expect_success '--full on no-sparse checkout' '
+ git checkout --full
+'
+
+test_expect_success '--full and --path incompatible' '
+ test_must_fail git checkout --full --path=work1
+'
+
+test_expect_success 'limit worktree to work1 and work2' '
+ git checkout --path=work1:work2 &&
+ test work1:work2 = "$(git rev-parse --show-sparse-prefix)" &&
+ test -f work1/one &&
+ test -f work2/two &&
+ ! test -f work3/three
+'
+
+test_expect_success 'update worktree to work2 and work3' '
+ git checkout --path=work2:work3 &&
+ test work2:work3 = "$(git rev-parse --show-sparse-prefix)" &&
+ ! test -f work1/one &&
+ test -f work2/two &&
+ test -f work3/three
+'
+
+test_expect_success 'update sparse prefix with modification' '
+ echo modified >> work2/two &&
+ git checkout --path=work1:work2 &&
+ test work1:work2 = "$(git rev-parse --show-sparse-prefix)" &&
+ test -f work1/one &&
+ test -f work2/two &&
+ ! test -f work3/three &&
+ grep -q modified work2/two
+'
+
+test_expect_success 'update sparse should not lose modification' '
+ ! git checkout --path=work1:work3 &&
+ test work1:work2 = "$(git rev-parse --show-sparse-prefix)" &&
+ test -f work1/one &&
+ test -f work2/two &&
+ ! test -f work3/three &&
+ grep -q modified work2/two
+'
+
+test_expect_success 'exit sparse checkout' '
+ git checkout --full &&
+ test -z "$(git rev-parse --show-sparse-prefix)" &&
+ test -f work1/one &&
+ test -f work2/two &&
+ test -f work3/three &&
+ test one
+'
+
+test_done
--
1.5.5.GIT
^ permalink raw reply related
* [PATCH 09/12] tests for sparse clone
From: Nguyễn Thái Ngọc Duy @ 2008-07-23 14:57 UTC (permalink / raw)
To: git
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
t/t5703-clone-sparse.sh | 40 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 40 insertions(+), 0 deletions(-)
create mode 100755 t/t5703-clone-sparse.sh
diff --git a/t/t5703-clone-sparse.sh b/t/t5703-clone-sparse.sh
new file mode 100755
index 0000000..012ead0
--- /dev/null
+++ b/t/t5703-clone-sparse.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+test_description='sparse clone'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+ rm -fr .git &&
+ test_create_repo src &&
+ (
+ cd src
+ mkdir -p work/sub/dir
+ touch untracked tracked modified added
+ touch work/untracked work/tracked work/modified work/added
+ git add tracked work/tracked
+ git add modified work/modified
+ git commit -m initial
+ )
+
+'
+
+test_expect_success 'sparse clone incompatible with --bare' '
+ rm -fr dst &&
+ test_must_fail git clone --path=work --bare src dst
+'
+
+test_expect_success 'sparse clone incompatible with --no-checkout' '
+ rm -fr dst &&
+ test_must_fail git clone --path=work -n src dst
+'
+
+test_expect_success 'clone with --path' '
+ rm -fr dst &&
+ git clone --path=work src dst &&
+ cd dst &&
+ test work = "$(git rev-parse --show-sparse-prefix)" &&
+ test -z "$(git ls-files | grep -v ^work/)"
+'
+
+test_done
--
1.5.5.GIT
^ permalink raw reply related
* [PATCH 08/12] git-clone: support --path to do sparse clone
From: Nguyễn Thái Ngọc Duy @ 2008-07-23 14:57 UTC (permalink / raw)
To: git
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
builtin-clone.c | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/builtin-clone.c b/builtin-clone.c
index 3522245..229f2e2 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -36,6 +36,7 @@ static const char * const builtin_clone_usage[] = {
static int option_quiet, option_no_checkout, option_bare;
static int option_local, option_no_hardlinks, option_shared;
static char *option_template, *option_reference, *option_depth;
+static char *option_sparse_prefix;
static char *option_origin = NULL;
static char *option_upload_pack = "git-upload-pack";
@@ -43,6 +44,8 @@ static struct option builtin_clone_options[] = {
OPT__QUIET(&option_quiet),
OPT_BOOLEAN('n', "no-checkout", &option_no_checkout,
"don't create a checkout"),
+ OPT_STRING(0, "path", &option_sparse_prefix, "prefixes",
+ "limit checkout to specified paths (sparse checkout)"),
OPT_BOOLEAN(0, "bare", &option_bare, "create a bare repository"),
OPT_BOOLEAN(0, "naked", &option_bare, "create a bare repository"),
OPT_BOOLEAN('l', "local", &option_local,
@@ -364,9 +367,14 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
die("--bare and --origin %s options are incompatible.",
option_origin);
option_no_checkout = 1;
+ if (option_sparse_prefix)
+ die("--bare and --path options are incompatible.");
use_separate_remote = 0;
}
+ if (option_no_checkout && option_sparse_prefix)
+ die("--no-checkout and --path options are incompatible.");
+
if (!option_origin)
option_origin = "origin";
@@ -549,6 +557,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
/* We need to be in the new work tree for the checkout */
setup_work_tree();
+ if (option_sparse_prefix) {
+ git_config_set("core.sparsecheckout", option_sparse_prefix);
+ set_sparse_prefix(option_sparse_prefix);
+ }
+
fd = hold_locked_index(lock_file, 1);
memset(&opts, 0, sizeof opts);
--
1.5.5.GIT
^ permalink raw reply related
* [PATCH 07/12] tests for sparse checkout, worktree protection
From: Nguyễn Thái Ngọc Duy @ 2008-07-23 14:57 UTC (permalink / raw)
To: git
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
t/t2302-sparse-worktree.sh | 113 ++++++++++++++
t/t2302/add-u.expected | 1 +
t/t2302/add.expected | 2 +
t/t2302/commit.expected | 14 ++
t/t2302/diff-1.expected | 7 +
t/t2302/diff-cc.expected | 9 +
t/t2302/grep-work.expected | 2 +
t/t2302/grep.expected | 2 +
t/t2302/ls-files.expected | 2 +
t/t2303-sparse-worktree-apply.sh | 62 ++++++++
t/t2303/apply-initial.patch | 14 ++
t/t2303/apply-inside.patch | 7 +
t/t2303/apply-leading-dirs.patch | 3 +
t/t2303/apply-outside.patch | 7 +
t/t2303/apply-remove.patch | 7 +
t/t2303/apply-rename.expected | 13 ++
t/t2303/apply-rename.patch | 4 +
t/t2304-sparse-worktree-merge-recursive.sh | 233 ++++++++++++++++++++++++++++
18 files changed, 502 insertions(+), 0 deletions(-)
create mode 100755 t/t2302-sparse-worktree.sh
create mode 100644 t/t2302/add-u.expected
create mode 100644 t/t2302/add.expected
create mode 100644 t/t2302/commit.expected
create mode 100644 t/t2302/diff-1.expected
create mode 100644 t/t2302/diff-cc.expected
create mode 100644 t/t2302/grep-work.expected
create mode 100644 t/t2302/grep.expected
create mode 100644 t/t2302/ls-files.expected
create mode 100755 t/t2303-sparse-worktree-apply.sh
create mode 100644 t/t2303/apply-initial.patch
create mode 100644 t/t2303/apply-inside.patch
create mode 100644 t/t2303/apply-leading-dirs.patch
create mode 100644 t/t2303/apply-outside.patch
create mode 100644 t/t2303/apply-remove.patch
create mode 100644 t/t2303/apply-rename.expected
create mode 100644 t/t2303/apply-rename.patch
create mode 100755 t/t2304-sparse-worktree-merge-recursive.sh
diff --git a/t/t2302-sparse-worktree.sh b/t/t2302-sparse-worktree.sh
new file mode 100755
index 0000000..0aaee3e
--- /dev/null
+++ b/t/t2302-sparse-worktree.sh
@@ -0,0 +1,113 @@
+#!/bin/sh
+
+test_description='sparse checkout -- worktree update
+
+This test makes sure all commands that will not write
+worktree outside sparse prefix, once set.
+'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ test_tick &&
+ mkdir work &&
+ echo one > tracked &&
+ cp tracked work/tracked &&
+ cp tracked untracked &&
+ cp tracked work/untracked &&
+ cp tracked modified &&
+ cp tracked work/modified &&
+ git add tracked modified work/tracked work/modified &&
+ echo two >> modified &&
+ echo two >> work/modified &&
+ git commit -m initial &&
+ git config core.sparsecheckout work'
+
+test_expect_success 'rev-parse --show-sparse-prefix' '
+ test "$(git rev-parse --show-sparse-prefix)" = "work"
+'
+
+test_expect_success 'ls-files' '
+ git ls-files | cmp ../t2302/ls-files.expected &&
+ test "$(git ls-files -o)" = work/untracked &&
+ test "$(git ls-files -o .)" = work/untracked &&
+ test "$(git ls-files -m)" = work/modified
+
+'
+
+test_expect_success 'grep' 'git grep -l --no-external-grep one | cmp ../t2302/grep.expected'
+
+test_expect_success 'grep' '
+ (
+ cd work &&
+ git grep -l --no-external-grep one | cmp ../../t2302/grep-work.expected
+ )
+'
+
+test_expect_success 'checkout-index' '! git checkout-index tracked'
+
+test_expect_success 'checkout-index -a' '
+ mv work/modified work/modified.old &&
+ git checkout-index -a &&
+ mv work/modified.old work/modified
+'
+
+test_expect_success 'checkout tracked' '! git checkout tracked'
+
+test_expect_success 'checkout work/tracked' 'rm work/tracked && git checkout work/tracked'
+
+test_expect_success 'clean' 'test "$(git clean -n)" = "Would remove work/untracked"'
+
+test_expect_success 'rm' '! git rm tracked && test -f tracked'
+
+test_expect_success 'add' '
+ git add -n . | cmp ../t2302/add.expected &&
+ git add -n -u | cmp ../t2302/add-u.expected &&
+ ! git add -n modified
+'
+
+test_expect_success 'commit' '
+ test_tick &&
+ echo one > work/one &&
+ git add work/one
+ echo two >> work/one &&
+ git commit -m one work/one &&
+ git show HEAD > commit.result &&
+ cmp commit.result ../t2302/commit.expected &&
+ rm commit.result
+'
+
+null_sha1=0000000000000000000000000000000000000000
+one_sha1=$(echo one|git hash-object --stdin)
+onethree_sha1=$(echo -e "one\nthree"|git hash-object -w --stdin)
+onefour_sha1=$(echo -e "one\nfour"|git hash-object -w --stdin)
+
+diff_expected=":100644 100644 $one_sha1 $null_sha1 M work/modified"
+external_diff_pattern="^work/modified [^ ]* $one_sha1 100644 work/modified $null_sha1 100644\$"
+
+cat >index.info <<EOF
+0 $null_sha1 work/modified
+100644 $onethree_sha1 2 work/modified
+100644 $onefour_sha1 3 work/modified
+EOF
+
+test_expect_success 'diff-files' '
+ test "$(git diff-files)" = "$diff_expected" &&
+ test "$(git diff-files -- work/modified)" = "$diff_expected"
+ cp .git/index .git/index.save &&
+ git update-index --index-info < index.info &&
+ git diff-files --cc | diff - ../t2302/diff-cc.expected &&
+ mv .git/index.save .git/index
+'
+
+test_expect_success 'diff-index' '
+ test "$(git diff-index HEAD)" = "$diff_expected"
+'
+
+test_expect_success 'diff' '
+ git diff HEAD | cmp ../t2302/diff-1.expected &&
+ git diff | cmp ../t2302/diff-1.expected &&
+ GIT_EXTERNAL_DIFF=echo git diff --ext-diff HEAD | grep -q "$external_diff_pattern" &&
+ GIT_EXTERNAL_DIFF=echo git diff --ext-diff | grep -q "$external_diff_pattern"
+'
+
+test_done
diff --git a/t/t2302/add-u.expected b/t/t2302/add-u.expected
new file mode 100644
index 0000000..e0d6f54
--- /dev/null
+++ b/t/t2302/add-u.expected
@@ -0,0 +1 @@
+add 'work/modified'
diff --git a/t/t2302/add.expected b/t/t2302/add.expected
new file mode 100644
index 0000000..4ee7b0d
--- /dev/null
+++ b/t/t2302/add.expected
@@ -0,0 +1,2 @@
+add 'work/modified'
+add 'work/untracked'
diff --git a/t/t2302/commit.expected b/t/t2302/commit.expected
new file mode 100644
index 0000000..7e629aa
--- /dev/null
+++ b/t/t2302/commit.expected
@@ -0,0 +1,14 @@
+commit 33ce2cea204feebac3994cd4520cca60657e65de
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:14:13 2005 -0700
+
+ one
+
+diff --git a/work/one b/work/one
+new file mode 100644
+index 0000000..814f4a4
+--- /dev/null
++++ b/work/one
+@@ -0,0 +1,2 @@
++one
++two
diff --git a/t/t2302/diff-1.expected b/t/t2302/diff-1.expected
new file mode 100644
index 0000000..67be4fb
--- /dev/null
+++ b/t/t2302/diff-1.expected
@@ -0,0 +1,7 @@
+diff --git a/work/modified b/work/modified
+index 5626abf..814f4a4 100644
+--- a/work/modified
++++ b/work/modified
+@@ -1 +1,2 @@
+ one
++two
diff --git a/t/t2302/diff-cc.expected b/t/t2302/diff-cc.expected
new file mode 100644
index 0000000..8ca66dd
--- /dev/null
+++ b/t/t2302/diff-cc.expected
@@ -0,0 +1,9 @@
+diff --cc work/modified
+index 4c7442b,a9c7698..0000000
+--- a/work/modified
++++ b/work/modified
+@@@ -1,2 -1,2 +1,2 @@@
+ one
+- three
+ -four
+++two
diff --git a/t/t2302/grep-work.expected b/t/t2302/grep-work.expected
new file mode 100644
index 0000000..c081ddd
--- /dev/null
+++ b/t/t2302/grep-work.expected
@@ -0,0 +1,2 @@
+modified
+tracked
diff --git a/t/t2302/grep.expected b/t/t2302/grep.expected
new file mode 100644
index 0000000..4ddbe70
--- /dev/null
+++ b/t/t2302/grep.expected
@@ -0,0 +1,2 @@
+work/modified
+work/tracked
diff --git a/t/t2302/ls-files.expected b/t/t2302/ls-files.expected
new file mode 100644
index 0000000..4ddbe70
--- /dev/null
+++ b/t/t2302/ls-files.expected
@@ -0,0 +1,2 @@
+work/modified
+work/tracked
diff --git a/t/t2303-sparse-worktree-apply.sh b/t/t2303-sparse-worktree-apply.sh
new file mode 100755
index 0000000..4aeaf53
--- /dev/null
+++ b/t/t2303-sparse-worktree-apply.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+test_description='git-apply in subtree checkout'
+
+. ./test-lib.sh
+
+mkdir work
+
+test_apply() {
+ test_expect_success "$1" '
+ git checkout . &&
+ git config core.sparsecheckout work &&
+ git apply ../t2303/apply-'$2'.patch &&
+ git config --unset core.sparsecheckout &&
+ git diff > apply.result &&
+ cmp apply.result ../t2303/apply-'$2'.patch
+ '
+}
+
+test_expect_success 'apply on empty tree' '
+ git config core.sparsecheckout work &&
+ ! git apply ../t2303/apply-initial.patch &&
+ git config --unset core.sparsecheckout
+'
+
+test_expect_success 'apply successfully without sparse checkout' '
+ git apply ../t2303/apply-initial.patch &&
+ git apply --cached ../t2303/apply-initial.patch
+'
+
+test_expect_success 'apply on modified tree outside' '
+ git checkout . &&
+ git config core.sparsecheckout work &&
+ ! git apply ../t2303/apply-outside.patch &&
+ git config --unset core.sparsecheckout
+'
+
+test_apply 'apply on modified tree' inside
+
+test_apply 'apply removing file' remove
+
+test_expect_success 'apply creating leading directories' '
+ git config core.sparsecheckout work &&
+ git apply ../t2303/apply-leading-dirs.patch &&
+ git config --unset core.sparsecheckout &&
+ test -f work/for/me/now
+'
+
+test_expect_success 'apply renaming file' '
+ git checkout . &&
+ touch a &&
+ empty_sha1=$(git hash-object -w a) &&
+ rm a &&
+ git update-index --add --cacheinfo 100644 $empty_sha1 work/two &&
+ git config core.sparsecheckout work &&
+ git apply ../t2303/apply-rename.patch &&
+ git config --unset core.sparsecheckout &&
+ git diff > apply.result &&
+ cmp apply.result ../t2303/apply-rename.expected
+'
+
+test_done
diff --git a/t/t2303/apply-initial.patch b/t/t2303/apply-initial.patch
new file mode 100644
index 0000000..72bfd82
--- /dev/null
+++ b/t/t2303/apply-initial.patch
@@ -0,0 +1,14 @@
+diff --git a/one b/one
+new file mode 100644
+index 0000000..5626abf
+--- /dev/null
++++ b/one
+@@ -0,0 +1 @@
++one
+diff --git a/work/one b/work/one
+new file mode 100644
+index 0000000..da327ae
+--- /dev/null
++++ b/work/one
+@@ -0,0 +1 @@
++work/one
diff --git a/t/t2303/apply-inside.patch b/t/t2303/apply-inside.patch
new file mode 100644
index 0000000..4f5c310
--- /dev/null
+++ b/t/t2303/apply-inside.patch
@@ -0,0 +1,7 @@
+diff --git a/work/one b/work/one
+index da327ae..6317017 100644
+--- a/work/one
++++ b/work/one
+@@ -1 +1,2 @@
+ work/one
++more
diff --git a/t/t2303/apply-leading-dirs.patch b/t/t2303/apply-leading-dirs.patch
new file mode 100644
index 0000000..b55809f
--- /dev/null
+++ b/t/t2303/apply-leading-dirs.patch
@@ -0,0 +1,3 @@
+diff --git a/work/for/me/now b/work/for/me/now
+new file mode 100644
+index 0000000..e69de29
diff --git a/t/t2303/apply-outside.patch b/t/t2303/apply-outside.patch
new file mode 100644
index 0000000..8a8d625
--- /dev/null
+++ b/t/t2303/apply-outside.patch
@@ -0,0 +1,7 @@
+diff --git a/one b/one
+index 5626abf..9a72323 100644
+--- a/one
++++ b/one
+@@ -1 +1,2 @@
+ one
++more
diff --git a/t/t2303/apply-remove.patch b/t/t2303/apply-remove.patch
new file mode 100644
index 0000000..781c743
--- /dev/null
+++ b/t/t2303/apply-remove.patch
@@ -0,0 +1,7 @@
+diff --git a/work/one b/work/one
+deleted file mode 100644
+index da327ae..0000000
+--- a/work/one
++++ /dev/null
+@@ -1 +0,0 @@
+-work/one
diff --git a/t/t2303/apply-rename.expected b/t/t2303/apply-rename.expected
new file mode 100644
index 0000000..d19f719
--- /dev/null
+++ b/t/t2303/apply-rename.expected
@@ -0,0 +1,13 @@
+diff --git a/work/one b/work/one
+deleted file mode 100644
+index da327ae..0000000
+--- a/work/one
++++ /dev/null
+@@ -1 +0,0 @@
+-work/one
+diff --git a/work/two b/work/two
+index e69de29..da327ae 100644
+--- a/work/two
++++ b/work/two
+@@ -0,0 +1 @@
++work/one
diff --git a/t/t2303/apply-rename.patch b/t/t2303/apply-rename.patch
new file mode 100644
index 0000000..6f21947
--- /dev/null
+++ b/t/t2303/apply-rename.patch
@@ -0,0 +1,4 @@
+diff --git a/work/one b/work/two
+similarity index 100%
+rename from work/one
+rename to work/two
diff --git a/t/t2304-sparse-worktree-merge-recursive.sh b/t/t2304-sparse-worktree-merge-recursive.sh
new file mode 100755
index 0000000..b1708d4
--- /dev/null
+++ b/t/t2304-sparse-worktree-merge-recursive.sh
@@ -0,0 +1,233 @@
+#!/bin/sh
+
+test_description='merge-recursive backend test'
+
+. ./test-lib.sh
+
+test_expect_success 'setup 1' '
+
+ echo hello >a &&
+ o0=$(git hash-object a) &&
+ cp a b &&
+ cp a c &&
+ mkdir d &&
+ cp a d/e &&
+
+ test_tick &&
+ git add a b c d/e &&
+ git commit -m initial &&
+ c0=$(git rev-parse --verify HEAD) &&
+ git branch noconflict &&
+ git branch conflict &&
+ git branch conflict-inside &&
+
+ echo hello >>a &&
+ cp a d/e &&
+ o1=$(git hash-object a) &&
+
+ git add a d/e &&
+
+ test_tick &&
+ git commit -m "master modifies a and d/e" &&
+ c1=$(git rev-parse --verify HEAD) &&
+ ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+ (
+ echo "100644 blob $o1 a"
+ echo "100644 blob $o0 b"
+ echo "100644 blob $o0 c"
+ echo "100644 blob $o1 d/e"
+ echo "100644 $o1 0 a"
+ echo "100644 $o0 0 b"
+ echo "100644 $o0 0 c"
+ echo "100644 $o1 0 d/e"
+ ) >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'setup 2' '
+
+ rm -rf [abcd] &&
+ git checkout conflict &&
+ ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+ (
+ echo "100644 blob $o0 a"
+ echo "100644 blob $o0 b"
+ echo "100644 blob $o0 c"
+ echo "100644 blob $o0 d/e"
+ echo "100644 $o0 0 a"
+ echo "100644 $o0 0 b"
+ echo "100644 $o0 0 c"
+ echo "100644 $o0 0 d/e"
+ ) >expected &&
+ test_cmp expected actual &&
+
+ echo goodbye >>a &&
+ o2=$(git hash-object a) &&
+
+ git add a &&
+
+ test_tick &&
+ git commit -m "conflict modifies a" &&
+ c2=$(git rev-parse --verify HEAD) &&
+ ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+ (
+ echo "100644 blob $o2 a"
+ echo "100644 blob $o0 b"
+ echo "100644 blob $o0 c"
+ echo "100644 blob $o0 d/e"
+ echo "100644 $o2 0 a"
+ echo "100644 $o0 0 b"
+ echo "100644 $o0 0 c"
+ echo "100644 $o0 0 d/e"
+ ) >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'setup 3' '
+
+ rm -rf [abcd] &&
+ git checkout noconflict &&
+ ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+ (
+ echo "100644 blob $o0 a"
+ echo "100644 blob $o0 b"
+ echo "100644 blob $o0 c"
+ echo "100644 blob $o0 d/e"
+ echo "100644 $o0 0 a"
+ echo "100644 $o0 0 b"
+ echo "100644 $o0 0 c"
+ echo "100644 $o0 0 d/e"
+ ) >expected &&
+ test_cmp expected actual &&
+
+ echo hello >>a &&
+ o3=$(git hash-object a) &&
+
+ git add a &&
+
+ test_tick &&
+ git commit -m "noconflict modifies a" &&
+ c3=$(git rev-parse --verify HEAD) &&
+ ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+ (
+ echo "100644 blob $o3 a"
+ echo "100644 blob $o0 b"
+ echo "100644 blob $o0 c"
+ echo "100644 blob $o0 d/e"
+ echo "100644 $o3 0 a"
+ echo "100644 $o0 0 b"
+ echo "100644 $o0 0 c"
+ echo "100644 $o0 0 d/e"
+ ) >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'setup 4' '
+
+ rm -rf [abcd] &&
+ git checkout conflict-inside &&
+ ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+ (
+ echo "100644 blob $o0 a"
+ echo "100644 blob $o0 b"
+ echo "100644 blob $o0 c"
+ echo "100644 blob $o0 d/e"
+ echo "100644 $o0 0 a"
+ echo "100644 $o0 0 b"
+ echo "100644 $o0 0 c"
+ echo "100644 $o0 0 d/e"
+ ) >expected &&
+ test_cmp expected actual &&
+
+ mkdir d &&
+ echo goodbye >>d/e &&
+ o4=$(git hash-object d/e) &&
+
+ git add d/e &&
+
+ test_tick &&
+ git commit -m "conflict-inside modifies d/e" &&
+ c4=$(git rev-parse --verify HEAD) &&
+ ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+ (
+ echo "100644 blob $o0 a"
+ echo "100644 blob $o0 b"
+ echo "100644 blob $o0 c"
+ echo "100644 blob $o4 d/e"
+ echo "100644 $o0 0 a"
+ echo "100644 $o0 0 b"
+ echo "100644 $o0 0 c"
+ echo "100644 $o4 0 d/e"
+ ) >expected &&
+ test_cmp expected actual
+'
+
+echo "gitdir: $(pwd)/.git" > gitfile
+
+test_expect_success 'merge-recursive conflict inside' '
+
+ rm -fr [abcd] &&
+ git checkout -f "$c4" &&
+
+ cp gitfile d/.git && cd d/
+ git config core.sparsecheckout d
+ git-merge-recursive "$c0" -- "$c4" "$c1"
+ status=$?
+ git config --unset core.sparsecheckout
+ rm .git && cd ..
+ case "$status" in
+ 1)
+ : happy
+ ;;
+ *)
+ echo >&2 "why status $status!!!"
+ false
+ ;;
+ esac
+'
+
+test_expect_success 'merge-recursive no conflict outside' '
+
+ rm -fr [abcd] &&
+ git checkout -f "$c3" &&
+
+ cp gitfile d/.git && cd d
+ git config core.sparsecheckout d
+ git-merge-recursive "$c0" -- "$c3" "$c1"
+ status=$?
+ git config --unset core.sparsecheckout
+ rm .git && cd ..
+ case "$status" in
+ 0)
+ : happy
+ ;;
+ *)
+ echo >&2 "why status $status!!!"
+ false
+ ;;
+ esac
+'
+
+test_expect_success 'merge-recursive conflict outside' '
+
+ rm -fr [abcd] &&
+ git checkout -f "$c2" &&
+
+ cp gitfile d/.git && cd d
+ git config core.sparsecheckout d
+ git-merge-recursive "$c0" -- "$c2" "$c1"
+ status=$?
+ git config --unset core.sparsecheckout
+ rm .git && cd ..
+ case "$status" in
+ 128)
+ : happy
+ ;;
+ *)
+ echo >&2 "why status $status!!!"
+ false
+ ;;
+ esac
+'
+
+test_done
--
1.5.5.GIT
^ permalink raw reply related
* Re: q: faster way to integrate/merge lots of topic branches?
From: Miklos Vajna @ 2008-07-23 14:57 UTC (permalink / raw)
To: Andreas Ericsson; +Cc: Ingo Molnar, git
In-Reply-To: <488734D9.9070703@op5.se>
[-- Attachment #1: Type: text/plain, Size: 172 bytes --]
On Wed, Jul 23, 2008 at 03:40:41PM +0200, Andreas Ericsson <ae@op5.se> wrote:
> With the builtin merge (which is in next)
Just a small correction: it's already in master.
[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
* [PATCH 06/12] Avoid accessing working directory outside sparse prefix
From: Nguyễn Thái Ngọc Duy @ 2008-07-23 14:56 UTC (permalink / raw)
To: git
Low-level functions such as checkout_entry() will refuse to write
outside sparse prefix. Other functions need lstat() will simply
assume files are good. The rest should die()
On UI side, all pathspec input will be filtered by filter_pathspec()
or filter_pathspec_1() to:
- keep pathspec if it's inside sparse prefix
- expand pathspec if it's outside sparse prefix, but is a parent
directory of sparse prefix
- otherwise, die()
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
builtin-add.c | 4 +-
builtin-apply.c | 5 ++
builtin-checkout-index.c | 2 +
builtin-checkout.c | 2 +-
builtin-clean.c | 3 +
builtin-commit.c | 2 +-
builtin-grep.c | 26 +++++++------
builtin-ls-files.c | 4 +-
builtin-ls-tree.c | 2 +-
builtin-merge-recursive.c | 2 +-
builtin-mv.c | 2 +-
builtin-rm.c | 7 +++-
builtin-update-index.c | 37 ++++++++++++++----
cache.h | 3 +
diff-lib.c | 2 +-
diff.c | 3 +-
entry.c | 3 +
read-cache.c | 5 ++
setup.c | 90 ++++++++++++++++++++++++++++++++++++++++++++-
sha1_file.c | 3 +
unpack-trees.c | 29 +++++++++++++-
21 files changed, 199 insertions(+), 37 deletions(-)
diff --git a/builtin-add.c b/builtin-add.c
index fc3f96e..8f6efca 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -151,7 +151,7 @@ static void refresh(int verbose, const char **pathspec)
static const char **validate_pathspec(int argc, const char **argv, const char *prefix)
{
- const char **pathspec = get_pathspec(prefix, argv);
+ const char **pathspec = get_filtered_pathspec(prefix, argv);
return pathspec;
}
@@ -278,7 +278,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
fprintf(stderr, "Maybe you wanted to say 'git add .'?\n");
return 0;
}
- pathspec = get_pathspec(prefix, argv);
+ pathspec = get_filtered_pathspec(prefix, argv);
/*
* If we are adding new files, we need to scan the working
diff --git a/builtin-apply.c b/builtin-apply.c
index 2216a0b..25d3523 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -2389,6 +2389,9 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s
if (!old_name)
return 0;
+ if (outside_sparse_prefix(old_name))
+ return error("%s: could not apply outside sparse checkout", old_name);
+
assert(patch->is_new <= 0);
if (!(patch->is_copy || patch->is_rename) &&
@@ -2491,6 +2494,8 @@ static int check_patch(struct patch *patch)
cache_name_pos(new_name, strlen(new_name)) >= 0 &&
!ok_if_exists)
return error("%s: already exists in index", new_name);
+ if (outside_sparse_prefix(new_name))
+ return error("%s: could not apply outside sparse checkout", new_name);
if (!cached) {
int err = check_to_create_blob(new_name, ok_if_exists);
if (err)
diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c
index 71ebabf..f0e829c 100644
--- a/builtin-checkout-index.c
+++ b/builtin-checkout-index.c
@@ -134,6 +134,8 @@ static void checkout_all(const char *prefix, int prefix_length)
(ce_namelen(ce) <= prefix_length ||
memcmp(prefix, ce->name, prefix_length)))
continue;
+ if (outside_sparse_prefix(ce->name))
+ continue;
if (last_ce && to_tempfile) {
if (ce_namelen(last_ce) != ce_namelen(ce)
|| memcmp(last_ce->name, ce->name, ce_namelen(ce)))
diff --git a/builtin-checkout.c b/builtin-checkout.c
index fbd5105..eec1bde 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -472,7 +472,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
die("git checkout: -f and -m are incompatible");
if (argc) {
- const char **pathspec = get_pathspec(prefix, argv);
+ const char **pathspec = get_filtered_pathspec(prefix, argv);
if (!pathspec)
die("invalid path specification");
diff --git a/builtin-clean.c b/builtin-clean.c
index 48bf29f..5f0a632 100644
--- a/builtin-clean.c
+++ b/builtin-clean.c
@@ -76,6 +76,9 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
setup_standard_excludes(&dir);
pathspec = get_pathspec(prefix, argv);
+ pathspec = filter_pathspec(pathspec);
+ if (!pathspec && sparse_checkout_enabled())
+ pathspec = (const char **)get_sparse_prefix();
read_cache();
/*
diff --git a/builtin-commit.c b/builtin-commit.c
index f2d301a..aaa208d 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -237,7 +237,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
die("index file corrupt");
if (*argv)
- pathspec = get_pathspec(prefix, argv);
+ pathspec = get_filtered_pathspec(prefix, argv);
/*
* Non partial, non as-is commit.
diff --git a/builtin-grep.c b/builtin-grep.c
index ee96d01..c9dc30a 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -776,19 +776,21 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
verify_filename(prefix, argv[j]);
}
- if (i < argc) {
- paths = get_pathspec(prefix, argv + i);
- if (opt.prefix_length && opt.relative) {
- /* Make sure we do not get outside of paths */
- for (i = 0; paths[i]; i++)
- if (strncmp(prefix, paths[i], opt.prefix_length))
- die("git-grep: cannot generate relative filenames containing '..'");
- }
- }
+ if (i < argc)
+ paths = get_filtered_pathspec(prefix, argv + i);
else if (prefix) {
- paths = xcalloc(2, sizeof(const char *));
- paths[0] = prefix;
- paths[1] = NULL;
+ static const char *fake_argv[2];
+ fake_argv[0] = prefix;
+ fake_argv[1] = NULL;
+ paths = get_filtered_pathspec(NULL, fake_argv);
+ }
+ if (!paths && sparse_checkout_enabled())
+ paths = (const char **)get_sparse_prefix();
+ if (paths && opt.prefix_length && opt.relative) {
+ /* Make sure we do not get outside of paths */
+ for (i = 0; paths[i]; i++)
+ if (strncmp(prefix, paths[i], opt.prefix_length))
+ die("git-grep: cannot generate relative filenames containing '..'");
}
if (!list.nr)
diff --git a/builtin-ls-files.c b/builtin-ls-files.c
index 4d18873..37041cd 100644
--- a/builtin-ls-files.c
+++ b/builtin-ls-files.c
@@ -571,7 +571,9 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
if (require_work_tree && !is_inside_work_tree())
setup_work_tree();
- pathspec = get_pathspec(prefix, argv + i);
+ pathspec = get_filtered_pathspec(prefix, argv + i);
+ if (!pathspec && sparse_checkout_enabled())
+ pathspec = (const char **)get_sparse_prefix();
/* Verify that the pathspec matches the prefix */
if (pathspec)
diff --git a/builtin-ls-tree.c b/builtin-ls-tree.c
index d25767a..45b1ef5 100644
--- a/builtin-ls-tree.c
+++ b/builtin-ls-tree.c
@@ -185,7 +185,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
if (get_sha1(argv[1], sha1))
die("Not a valid object name %s", argv[1]);
- pathspec = get_pathspec(prefix, argv + 2);
+ pathspec = get_filtered_pathspec(prefix, argv + 2);
tree = parse_tree_indirect(sha1);
if (!tree)
die("not a tree object");
diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c
index 7ce015b..5c62743 100644
--- a/builtin-merge-recursive.c
+++ b/builtin-merge-recursive.c
@@ -526,7 +526,7 @@ static void update_file_flags(const unsigned char *sha,
if (index_only)
update_wd = 0;
- if (update_wd) {
+ if (update_wd && !outside_sparse_prefix(path)) {
enum object_type type;
void *buf;
unsigned long size;
diff --git a/builtin-mv.c b/builtin-mv.c
index 736a0b8..0591aa2 100644
--- a/builtin-mv.c
+++ b/builtin-mv.c
@@ -33,7 +33,7 @@ static const char **copy_pathspec(const char *prefix, const char **pathspec,
result[i] = last_slash + 1;
}
}
- return get_pathspec(prefix, result);
+ return get_filtered_pathspec(prefix, result);
}
static void show_list(const char *label, struct string_list *list)
diff --git a/builtin-rm.c b/builtin-rm.c
index ee8247b..082dd95 100644
--- a/builtin-rm.c
+++ b/builtin-rm.c
@@ -158,7 +158,10 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (read_cache() < 0)
die("index file corrupt");
- pathspec = get_pathspec(prefix, argv);
+ pathspec = get_filtered_pathspec(prefix, argv);
+ if (!pathspec)
+ return 0;
+
seen = NULL;
for (i = 0; pathspec[i] ; i++)
/* nothing */;
@@ -166,6 +169,8 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i];
+ if (outside_sparse_prefix(ce->name))
+ continue;
if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen))
continue;
add_list(ce->name);
diff --git a/builtin-update-index.c b/builtin-update-index.c
index 38eb53c..25e3e98 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -242,6 +242,9 @@ static void chmod_path(int flip, const char *path)
struct cache_entry *ce;
unsigned int mode;
+ if (outside_sparse_prefix(path))
+ die("%s: cannot update sparse outside %s", path, get_sparse_prefix_str());
+
pos = cache_name_pos(path, strlen(path));
if (pos < 0)
goto fail;
@@ -521,7 +524,7 @@ static int do_reupdate(int ac, const char **av,
*/
int pos;
int has_head = 1;
- const char **pathspec = get_pathspec(prefix, av + 1);
+ const char **pathspec = get_filtered_pathspec(prefix, av + 1);
if (read_ref("HEAD", head_sha1))
/* If there is no HEAD, that means it is an initial
@@ -582,7 +585,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
for (i = 1 ; i < argc; i++) {
const char *path = argv[i];
- const char *p;
+ const char *p, **pathspec;
if (allow_options && *path == '-') {
if (!strcmp(path, "--")) {
@@ -703,9 +706,17 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
die("unknown option %s", path);
}
p = prefix_path(prefix, prefix_length, path);
- update_one(p, NULL, 0);
- if (set_executable_bit)
- chmod_path(set_executable_bit, p);
+ pathspec = filter_pathspec_1(p);
+ if (pathspec) {
+ const char **pp = pathspec;
+ while (*pp) {
+ update_one(*pp, NULL, 0);
+ if (set_executable_bit)
+ chmod_path(set_executable_bit, *pp);
+ pp ++;
+ }
+ free(pathspec);
+ }
if (p < path || p > path + strlen(path))
free((char*)p);
}
@@ -715,7 +726,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
strbuf_init(&buf, 0);
strbuf_init(&nbuf, 0);
while (strbuf_getline(&buf, stdin, line_termination) != EOF) {
- const char *p;
+ const char *p, **pathspec;
if (line_termination && buf.buf[0] == '"') {
strbuf_reset(&nbuf);
if (unquote_c_style(&nbuf, buf.buf, NULL))
@@ -723,9 +734,17 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
strbuf_swap(&buf, &nbuf);
}
p = prefix_path(prefix, prefix_length, buf.buf);
- update_one(p, NULL, 0);
- if (set_executable_bit)
- chmod_path(set_executable_bit, p);
+ pathspec = filter_pathspec_1(p);
+ if (pathspec) {
+ const char **pp = pathspec;
+ while (*pp) {
+ update_one(*pp, NULL, 0);
+ if (set_executable_bit)
+ chmod_path(set_executable_bit, *pp);
+ pp++;
+ }
+ free(pathspec);
+ }
if (p < buf.buf || p > buf.buf + buf.len)
free((char *)p);
}
diff --git a/cache.h b/cache.h
index f6bbadc..b9a1d96 100644
--- a/cache.h
+++ b/cache.h
@@ -336,6 +336,9 @@ extern int check_index_prefix(const struct index_state *index, int is_merge);
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
extern const char **get_pathspec(const char *prefix, const char **pathspec);
+extern const char **filter_pathspec(const char **pathspec);
+extern const char **filter_pathspec_1(const char *path);
+extern const char **get_filtered_pathspec(const char *prefix, const char **pathspec);
extern void setup_work_tree(void);
extern const char *setup_git_directory_gently(int *);
extern const char *setup_git_directory(void);
diff --git a/diff-lib.c b/diff-lib.c
index 2908146..9382114 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -356,7 +356,7 @@ static void do_oneway_diff(struct unpack_trees_options *o,
* But with the revision flag parsing, that's found in
* "!revs->ignore_merges".
*/
- cached = o->index_only;
+ cached = outside_sparse_prefix(idx->name) || o->index_only;
match_missing = !revs->ignore_merges;
if (cached && idx && ce_stage(idx)) {
diff --git a/diff.c b/diff.c
index a07812c..e344916 100644
--- a/diff.c
+++ b/diff.c
@@ -1721,7 +1721,8 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
* If ce matches the file in the work tree, we can reuse it.
*/
if (ce_uptodate(ce) ||
- (!lstat(name, &st) && !ce_match_stat(ce, &st, 0)))
+ (!outside_sparse_prefix(name) &&
+ !lstat(name, &st) && !ce_match_stat(ce, &st, 0)))
return 1;
return 0;
diff --git a/entry.c b/entry.c
index 222aaa3..e2921c2 100644
--- a/entry.c
+++ b/entry.c
@@ -201,6 +201,9 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
memcpy(path, state->base_dir, len);
strcpy(path + len, ce->name);
+ if (outside_sparse_prefix(path))
+ die("%s: unable to checkout entry outside sparse checkout", path);
+
if (!lstat(path, &st)) {
unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
diff --git a/read-cache.c b/read-cache.c
index 4fea40e..dd42c7c 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -232,6 +232,8 @@ int ie_match_stat(const struct index_state *istate,
int ignore_valid = options & CE_MATCH_IGNORE_VALID;
int assume_racy_is_modified = options & CE_MATCH_RACY_IS_DIRTY;
+ if (outside_sparse_prefix(ce->name))
+ return 0;
/*
* If it's marked as always valid in the index, it's
* valid whatever the checked-out copy says.
@@ -953,6 +955,9 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
return ce;
}
+ if (outside_sparse_prefix(ce->name))
+ return ce;
+
if (lstat(ce->name, &st) < 0) {
if (err)
*err = errno;
diff --git a/setup.c b/setup.c
index 6cf9094..4ae68fd 100644
--- a/setup.c
+++ b/setup.c
@@ -164,7 +164,7 @@ void verify_filename(const char *prefix, const char *arg)
if (*arg == '-')
die("bad flag '%s' used after filename", arg);
name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg;
- if (!lstat(name, &st))
+ if (!outside_sparse_prefix(name) && !lstat(name, &st))
return;
if (errno == ENOENT)
die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
@@ -187,7 +187,7 @@ void verify_non_filename(const char *prefix, const char *arg)
if (*arg == '-')
return; /* flag */
name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg;
- if (!lstat(name, &st))
+ if (!outside_sparse_prefix(name) && !lstat(name, &st))
die("ambiguous argument '%s': both revision and filename\n"
"Use '--' to separate filenames from revisions", arg);
if (errno != ENOENT && errno != ENOTDIR)
@@ -229,6 +229,92 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
}
/*
+ * if path is inside sparse prefix, leave it as-is
+ * if path is parent of sparse prefix, expand it to sparse prefix
+ * if path is outside sparse prefix, die()
+ */
+static void filter_pathspec_internal(const char *path, const char ***dst, int *dst_alloc, int *dst_nr)
+{
+ char **iprefix;
+ int filtered = 1;
+
+ for (iprefix = get_sparse_prefix(); *iprefix; iprefix++) {
+ const char *new_dst = NULL;
+ if (!prefixcmp(path, *iprefix))
+ new_dst = path;
+ else if (!prefixcmp(*iprefix, path))
+ new_dst = *iprefix;
+
+ if (!new_dst)
+ continue;
+
+ if (*dst_alloc <= *dst_nr) {
+ *dst_alloc = alloc_nr(*dst_alloc);
+ *dst = xrealloc(*dst, *dst_alloc * sizeof(**dst));
+ }
+ (*dst)[(*dst_nr)++] = new_dst;
+ filtered = 0;
+
+ /*
+ * if it's inside sparse prefix,
+ * no need to search more
+ */
+ if (new_dst == path)
+ break;
+ }
+ if (filtered)
+ die("pathspec %s is outside sparse checkout %s", path, get_sparse_prefix_str());
+}
+
+const char **filter_pathspec(const char **pathspec)
+{
+ const char **src, **dst;
+ int dst_alloc = 0;
+ int dst_nr = 0;
+
+ if (!sparse_checkout_enabled())
+ return pathspec;
+ if (!pathspec || !*pathspec)
+ return NULL;
+
+ src = pathspec;
+ dst = NULL;
+ while (*src) {
+ filter_pathspec_internal(*src, &dst, &dst_alloc, &dst_nr);
+ src++;
+ }
+ if (!dst)
+ return NULL;
+ dst[dst_nr] = NULL;
+ return dst;
+}
+
+const char **filter_pathspec_1(const char *path)
+{
+ int dst_alloc = 0, dst_nr = 0;
+ const char **dst = NULL;
+
+ if (!path)
+ return NULL;
+ if (!sparse_checkout_enabled()) {
+ dst = xmalloc(2*sizeof(*dst));
+ dst[0] = path;
+ dst[1] = NULL;
+ return dst;
+ }
+ filter_pathspec_internal(path, &dst, &dst_alloc, &dst_nr);
+ if (!dst)
+ return NULL;
+ dst[dst_nr] = NULL;
+ return dst;
+}
+
+const char **get_filtered_pathspec(const char *prefix, const char **pathspec)
+{
+ return filter_pathspec(get_pathspec(prefix,pathspec));
+}
+
+/*
* Test if it looks like we're at a git directory.
* We want to see:
*
diff --git a/sha1_file.c b/sha1_file.c
index e281c14..60f9e2a 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -2422,6 +2422,9 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, int write
char *target;
size_t len;
+ if (outside_sparse_prefix(path))
+ die("%s: cannot index a file outside sparse checkout", path);
+
switch (st->st_mode & S_IFMT) {
case S_IFREG:
fd = open(path, O_RDONLY);
diff --git a/unpack-trees.c b/unpack-trees.c
index 0a6723b..0a30d68 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -84,6 +84,19 @@ static void unlink_entry(struct cache_entry *ce)
}
}
+static int check_sparse_checkout(struct unpack_trees_options *o)
+{
+ unsigned cnt = 0;
+ struct index_state *index = &o->result;
+
+ for (cnt = 0; cnt < index->cache_nr; cnt++) {
+ struct cache_entry *ce = index->cache[cnt];
+ if (ce_stage(ce) && outside_sparse_prefix(ce->name))
+ return 0;
+ }
+ return 1;
+}
+
static struct checkout state;
static int check_updates(struct unpack_trees_options *o)
{
@@ -96,6 +109,8 @@ static int check_updates(struct unpack_trees_options *o)
if (o->update && o->verbose_update) {
for (total = cnt = 0; cnt < index->cache_nr; cnt++) {
struct cache_entry *ce = index->cache[cnt];
+ if (outside_sparse_prefix(ce->name))
+ continue;
if (ce->ce_flags & (CE_UPDATE | CE_REMOVE))
total++;
}
@@ -108,6 +123,8 @@ static int check_updates(struct unpack_trees_options *o)
for (i = 0; i < index->cache_nr; i++) {
struct cache_entry *ce = index->cache[i];
+ if (outside_sparse_prefix(ce->name))
+ continue;
if (ce->ce_flags & CE_REMOVE) {
display_progress(progress, ++cnt);
if (o->update)
@@ -121,6 +138,8 @@ static int check_updates(struct unpack_trees_options *o)
for (i = 0; i < index->cache_nr; i++) {
struct cache_entry *ce = index->cache[i];
+ if (outside_sparse_prefix(ce->name))
+ continue;
if (ce->ce_flags & CE_UPDATE) {
display_progress(progress, ++cnt);
ce->ce_flags &= ~CE_UPDATE;
@@ -411,6 +430,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
if (o->check_index_prefix && !check_index_prefix(&o->result, o->merge && !o->prefix))
return unpack_failed(o, "Merge outside index prefix");
+ if (sparse_checkout_enabled() && !check_sparse_checkout(o))
+ return unpack_failed(o, "Merge conflicts outside sparse checkout");
+
o->src_index = NULL;
ret = check_updates(o) ? (-2) : 0;
if (o->dst_index)
@@ -445,7 +467,7 @@ static int verify_uptodate(struct cache_entry *ce,
{
struct stat st;
- if (o->index_only || o->reset)
+ if (o->index_only || o->reset || outside_sparse_prefix(ce->name))
return 0;
if (!lstat(ce->name, &st)) {
@@ -583,7 +605,7 @@ static int verify_absent(struct cache_entry *ce, const char *action,
{
struct stat st;
- if (o->index_only || o->reset || !o->update)
+ if (o->index_only || o->reset || !o->update || outside_sparse_prefix(ce->name))
return 0;
if (has_symlink_leading_path(ce_namelen(ce), ce->name))
@@ -994,7 +1016,8 @@ int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o)
int update = 0;
if (o->reset) {
struct stat st;
- if (lstat(old->name, &st) ||
+ if (outside_sparse_prefix(old->name) ||
+ lstat(old->name, &st) ||
ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID))
update |= CE_UPDATE;
}
--
1.5.5.GIT
^ permalink raw reply related
* [PATCH 05/12] tests for sparse checkout, index protection
From: Nguyễn Thái Ngọc Duy @ 2008-07-23 14:56 UTC (permalink / raw)
To: git
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
t/t2300-sparse-index.sh | 156 +++++++++++++++++++++
t/t2300/diff-index-sub.expected | 3 +
t/t2300/log.expected | 64 +++++++++
t/t2301-sparse-index-merge-recursive.sh | 226 +++++++++++++++++++++++++++++++
4 files changed, 449 insertions(+), 0 deletions(-)
create mode 100755 t/t2300-sparse-index.sh
create mode 100644 t/t2300/diff-index-sub.expected
create mode 100644 t/t2300/log.expected
create mode 100755 t/t2301-sparse-index-merge-recursive.sh
diff --git a/t/t2300-sparse-index.sh b/t/t2300-sparse-index.sh
new file mode 100755
index 0000000..8b9d61f
--- /dev/null
+++ b/t/t2300-sparse-index.sh
@@ -0,0 +1,156 @@
+#!/bin/sh
+
+test_description='sparse checkout -- index update
+
+This test makes sure all commands that touch index will not
+be able to write outside sparse prefix, once set.
+
+It also makes sure some full index operation like git-checkout
+or git-read-tree can function even with index prefix set.
+'
+
+. ./test-lib.sh
+
+setup_repo() {
+ test "$#" = 1 ||
+ error 'bug in the test script: not 1 parameter to setup_repo'
+ test_create_repo "$1" &&
+ (
+ cd "$1" &&
+ mkdir -p work/sub/dir &&
+ touch untracked tracked modified added &&
+ touch work/untracked work/tracked work/modified work/added &&
+ git add tracked work/tracked &&
+ git add modified work/modified &&
+ git commit -m initial &&
+ git add added work/added &&
+ echo modified > modified &&
+ echo work/modified > work/modified
+ )
+}
+
+# this prevent sparse checkout's worktree protection
+# so you can access everything in worktree
+# index modification is limited though
+export GIT_SPARSE_CHECKOUT_INDEX_ONLY=1
+
+test_expect_success 'setup update-index and --show-parse-prefix' '
+ setup_repo update-index &&
+ cd update-index &&
+ git config core.sparsecheckout work:nonwork &&
+ test nonwork:work = "$(git rev-parse --show-sparse-prefix)" &&
+ git config core.sparsecheckout work &&
+ test work = "$(git rev-parse --show-sparse-prefix)"
+'
+
+test_expect_success 'ls-files --with-tree does not bail out' '
+ git ls-files --with-tree=HEAD
+'
+
+test_expect_success 'update-index --refresh with new mtime outside index prefix' '
+ touch tracked &&
+ test -z "$(git update-index --refresh 2>&1 >/dev/null)"
+'
+
+test_expect_success 'update inside' 'git update-index work/modified'
+test_expect_success 'remove inside' 'git update-index --force-remove work/tracked'
+test_expect_success 'add inside' 'git update-index --add work/untracked'
+
+test_expect_success 'update outside' '! git update-index modified'
+test_expect_success 'remove outside' '! git update-index --force-remove modified'
+test_expect_success 'add outside' '! git update-index --add untracked'
+
+test_expect_success 'setup add' '
+ cd .. &&
+ setup_repo add &&
+ cd add
+ git config core.sparsecheckout work &&
+ test work = "$(git rev-parse --show-sparse-prefix)"
+'
+
+test_expect_success 'add inside' 'git add work/modified'
+test_expect_success 'add outside' '! git add untracked'
+
+test_expect_success 'setup rm' '
+ cd .. &&
+ setup_repo rm &&
+ cd rm &&
+ git config core.sparsecheckout work
+ test work = "$(git rev-parse --show-sparse-prefix)"
+'
+
+test_expect_success 'inside: rm' 'git rm work/tracked'
+test_expect_success 'outside: rm' '! git rm tracked'
+
+test_expect_success 'setup apply' '
+ cd .. &&
+ test_create_repo apply &&
+ cd apply &&
+ mkdir -p work/sub/dir &&
+ touch modified work/modified &&
+ git add modified work/modified &&
+ git config core.sparsecheckout work &&
+ test work = "$(git rev-parse --show-sparse-prefix)"
+'
+
+cat <<EOF > outside.patch
+diff --git a/modified b/modified
+index e69de29..2e09960 100644
+--- a/modified
++++ b/modified
+@@ -0,0 +1 @@
++modified
+EOF
+
+cat <<EOF > inside.patch
+diff --git a/work/modified b/work/modified
+index e69de29..4bd2893 100644
+--- a/work/modified
++++ b/work/modified
+@@ -0,0 +1 @@
++work/modified
+EOF
+
+
+test_expect_success 'inside: apply --cached' 'git apply --cached inside.patch'
+test_expect_success 'outside: apply --cached' '! git apply --cached outside.patch'
+
+test_expect_success 'setup read-tree (clean worktree)' '
+ cd ..
+ test_create_repo read-tree &&
+ cd read-tree &&
+ test_tick &&
+ mkdir -p work/sub/dir &&
+ echo one > one && git add one && git commit -m one &&
+ echo two >> one && git add one && git commit -m two &&
+ echo one > work/one && git add work/one && git commit -m work/one &&
+ echo two >> work/one && git add work/one && git commit -m work/two &&
+ echo one > work/sub/one && git add work/sub/one && git commit -m work/sub/one &&
+ echo two >> work/sub/one && git add work/sub/one && git commit -m work/sub/two &&
+ echo one > work/sub/dir/one && echo three >> work/one &&
+ git add work/sub/dir/one work/one &&
+ git commit -m work/sub/dir/one &&
+ echo two >> work/sub/dir/one &&
+ git add work/sub/dir/one &&
+ git commit -m work/sub/dir/two &&
+ git log --raw > ../log.result &&
+ cmp ../../t2300/log.expected ../log.result &&
+ git config core.sparsecheckout work/sub &&
+ test work/sub = "$(git rev-parse --show-sparse-prefix)"
+'
+
+test_expect_success 'read-tree inside index prefix' '
+ git read-tree 47b2996ef7d1dd7d5fd146c520ed90995e2d7e0d &&
+ test -z "$(git diff-index --cached 47b2996ef7d1dd7d5fd146c520ed90995e2d7e0d)"'
+
+test_expect_success 'read-tree outside index prefix' '
+ ! git read-tree b64ae04f6be47b3d729f731de1ce804223f45113'
+
+test_expect_success 'read-tree with --prefix outside' '
+ ! git read-tree --prefix=work/newsub/ b64ae04f6be47b3d729f731de1ce804223f45113'
+
+test_expect_success 'read-tree with --prefix inside' '
+ git read-tree --prefix=work/sub/dir/newsub/ b64ae04f6be47b3d729f731de1ce804223f45113 &&
+ git diff-index --cached 47b2996ef7d1dd7d5fd146c520ed90995e2d7e0d|cmp ../../t2300/diff-index-sub.expected'
+
+test_done
diff --git a/t/t2300/diff-index-sub.expected b/t/t2300/diff-index-sub.expected
new file mode 100644
index 0000000..49b1a47
--- /dev/null
+++ b/t/t2300/diff-index-sub.expected
@@ -0,0 +1,3 @@
+:000000 100644 0000000000000000000000000000000000000000 814f4a422927b82f5f8a43f8fab6d3839e3983f2 A work/sub/dir/newsub/one
+:000000 100644 0000000000000000000000000000000000000000 814f4a422927b82f5f8a43f8fab6d3839e3983f2 A work/sub/dir/newsub/work/one
+:000000 100644 0000000000000000000000000000000000000000 5626abf0f72e58d7a153368ba57db4c673c0e171 A work/sub/dir/newsub/work/sub/one
diff --git a/t/t2300/log.expected b/t/t2300/log.expected
new file mode 100644
index 0000000..58b69bd
--- /dev/null
+++ b/t/t2300/log.expected
@@ -0,0 +1,64 @@
+commit 69798ebb265c266292b4919f7a943bc30d72dfa3
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:13:13 2005 -0700
+
+ work/sub/dir/two
+
+:100644 100644 5626abf... 814f4a4... M work/sub/dir/one
+
+commit 47b2996ef7d1dd7d5fd146c520ed90995e2d7e0d
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:13:13 2005 -0700
+
+ work/sub/dir/one
+
+:100644 100644 814f4a4... 4cb29ea... M work/one
+:000000 100644 0000000... 5626abf... A work/sub/dir/one
+
+commit dd5fc8b46ac73c49bb046e16b0d9980a8142de51
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:13:13 2005 -0700
+
+ work/sub/two
+
+:100644 100644 5626abf... 814f4a4... M work/sub/one
+
+commit b64ae04f6be47b3d729f731de1ce804223f45113
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:13:13 2005 -0700
+
+ work/sub/one
+
+:000000 100644 0000000... 5626abf... A work/sub/one
+
+commit 69da5948890ae9caff70388451ba5ede78b77d08
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:13:13 2005 -0700
+
+ work/two
+
+:100644 100644 5626abf... 814f4a4... M work/one
+
+commit e63957619e33be2985dacdbb077f4c2ca7210319
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:13:13 2005 -0700
+
+ work/one
+
+:000000 100644 0000000... 5626abf... A work/one
+
+commit e6742a1800d08c749ebbc01d1f4ca03b66ff44e1
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:13:13 2005 -0700
+
+ two
+
+:100644 100644 5626abf... 814f4a4... M one
+
+commit 1c60dc5aa63dc2956ceb3ccc399d04245bc2cc1b
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:13:13 2005 -0700
+
+ one
+
+:000000 100644 0000000... 5626abf... A one
diff --git a/t/t2301-sparse-index-merge-recursive.sh b/t/t2301-sparse-index-merge-recursive.sh
new file mode 100755
index 0000000..61b3766
--- /dev/null
+++ b/t/t2301-sparse-index-merge-recursive.sh
@@ -0,0 +1,226 @@
+#!/bin/sh
+
+test_description='merge-recursive backend test'
+
+. ./test-lib.sh
+
+# this prevent sparse checkout's worktree protection
+# so you can access everything in worktree
+# index modification is limited though
+export GIT_SPARSE_CHECKOUT_INDEX_ONLY=1
+
+test_expect_success 'setup 1' '
+
+ echo hello >a &&
+ o0=$(git hash-object a) &&
+ cp a b &&
+ cp a c &&
+ mkdir d &&
+ cp a d/e &&
+
+ test_tick &&
+ git add a b c d/e &&
+ git commit -m initial &&
+ c0=$(git rev-parse --verify HEAD) &&
+ git branch noconflict &&
+ git branch conflict &&
+ git branch conflict-inside &&
+
+ echo hello >>a &&
+ cp a d/e &&
+ o1=$(git hash-object a) &&
+
+ git add a d/e &&
+
+ test_tick &&
+ git commit -m "master modifies a and d/e" &&
+ c1=$(git rev-parse --verify HEAD) &&
+ ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+ (
+ echo "100644 blob $o1 a"
+ echo "100644 blob $o0 b"
+ echo "100644 blob $o0 c"
+ echo "100644 blob $o1 d/e"
+ echo "100644 $o1 0 a"
+ echo "100644 $o0 0 b"
+ echo "100644 $o0 0 c"
+ echo "100644 $o1 0 d/e"
+ ) >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'setup 2' '
+
+ rm -rf [abcd] &&
+ git checkout conflict &&
+ ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+ (
+ echo "100644 blob $o0 a"
+ echo "100644 blob $o0 b"
+ echo "100644 blob $o0 c"
+ echo "100644 blob $o0 d/e"
+ echo "100644 $o0 0 a"
+ echo "100644 $o0 0 b"
+ echo "100644 $o0 0 c"
+ echo "100644 $o0 0 d/e"
+ ) >expected &&
+ test_cmp expected actual &&
+
+ echo goodbye >>a &&
+ o2=$(git hash-object a) &&
+
+ git add a &&
+
+ test_tick &&
+ git commit -m "conflict modifies a" &&
+ c2=$(git rev-parse --verify HEAD) &&
+ ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+ (
+ echo "100644 blob $o2 a"
+ echo "100644 blob $o0 b"
+ echo "100644 blob $o0 c"
+ echo "100644 blob $o0 d/e"
+ echo "100644 $o2 0 a"
+ echo "100644 $o0 0 b"
+ echo "100644 $o0 0 c"
+ echo "100644 $o0 0 d/e"
+ ) >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'setup 3' '
+
+ rm -rf [abcd] &&
+ git checkout noconflict &&
+ ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+ (
+ echo "100644 blob $o0 a"
+ echo "100644 blob $o0 b"
+ echo "100644 blob $o0 c"
+ echo "100644 blob $o0 d/e"
+ echo "100644 $o0 0 a"
+ echo "100644 $o0 0 b"
+ echo "100644 $o0 0 c"
+ echo "100644 $o0 0 d/e"
+ ) >expected &&
+ test_cmp expected actual &&
+
+ echo hello >>a &&
+ o3=$(git hash-object a) &&
+
+ git add a &&
+
+ test_tick &&
+ git commit -m "noconflict modifies a" &&
+ c3=$(git rev-parse --verify HEAD) &&
+ ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+ (
+ echo "100644 blob $o3 a"
+ echo "100644 blob $o0 b"
+ echo "100644 blob $o0 c"
+ echo "100644 blob $o0 d/e"
+ echo "100644 $o3 0 a"
+ echo "100644 $o0 0 b"
+ echo "100644 $o0 0 c"
+ echo "100644 $o0 0 d/e"
+ ) >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'setup 4' '
+
+ rm -rf [abcd] &&
+ git checkout conflict-inside &&
+ ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+ (
+ echo "100644 blob $o0 a"
+ echo "100644 blob $o0 b"
+ echo "100644 blob $o0 c"
+ echo "100644 blob $o0 d/e"
+ echo "100644 $o0 0 a"
+ echo "100644 $o0 0 b"
+ echo "100644 $o0 0 c"
+ echo "100644 $o0 0 d/e"
+ ) >expected &&
+ test_cmp expected actual &&
+
+ mkdir d &&
+ echo goodbye >>d/e &&
+ o4=$(git hash-object d/e) &&
+
+ git add d/e &&
+
+ test_tick &&
+ git commit -m "conflict-inside modifies d/e" &&
+ c4=$(git rev-parse --verify HEAD) &&
+ ( git ls-tree -r HEAD ; git ls-files -s ) >actual &&
+ (
+ echo "100644 blob $o0 a"
+ echo "100644 blob $o0 b"
+ echo "100644 blob $o0 c"
+ echo "100644 blob $o4 d/e"
+ echo "100644 $o0 0 a"
+ echo "100644 $o0 0 b"
+ echo "100644 $o0 0 c"
+ echo "100644 $o4 0 d/e"
+ ) >expected &&
+ test_cmp expected actual
+'
+
+export GIT_INDEX_PREFIX=d/
+
+test_expect_success 'merge-recursive conflict inside' '
+
+ rm -fr [abcd] &&
+ git checkout -f "$c4" &&
+
+ git-merge-recursive "$c0" -- "$c4" "$c1"
+ status=$?
+ case "$status" in
+ 1)
+ : happy
+ ;;
+ *)
+ echo >&2 "why status $status!!!"
+ false
+ ;;
+ esac
+'
+
+test_expect_success 'merge-recursive no conflict outside' '
+
+ rm -fr [abcd] &&
+ git checkout -f "$c3" &&
+
+ git-merge-recursive "$c0" -- "$c3" "$c1"
+ status=$?
+ case "$status" in
+ 0)
+ : happy
+ ;;
+ *)
+ echo >&2 "why status $status!!!"
+ false
+ ;;
+ esac
+'
+
+test_expect_success 'merge-recursive conflict outside' '
+
+ rm -fr [abcd] &&
+ git checkout -f "$c2" &&
+
+ git-merge-recursive "$c0" -- "$c2" "$c1"
+ status=$?
+ case "$status" in
+ 1)
+ : happy
+ ;;
+ *)
+ echo >&2 "why status $status!!!"
+ false
+ ;;
+ esac
+'
+
+test_done
--
1.5.5.GIT
^ permalink raw reply related
* [PATCH 04/12] Protect index with sparse prefix
From: Nguyễn Thái Ngọc Duy @ 2008-07-23 14:56 UTC (permalink / raw)
To: git
This ensures no one can write to index outside sparse prefix.
Protection is usually applied to the_index only. For more
complicated cases where temporary index is required, thorough
check will be done by check_index_prefix()
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
builtin-commit.c | 11 +++++
builtin-ls-files.c | 2 +
builtin-merge-recursive.c | 4 +-
builtin-read-tree.c | 5 ++
cache.h | 1 +
diff-lib.c | 3 +
read-cache.c | 107 ++++++++++++++++++++++++++++++++++++++++++++-
unpack-trees.c | 3 +
unpack-trees.h | 3 +-
9 files changed, 135 insertions(+), 4 deletions(-)
diff --git a/builtin-commit.c b/builtin-commit.c
index 97e64de..f2d301a 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -223,6 +223,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
int fd;
struct string_list partial;
const char **pathspec = NULL;
+ char **saved_sparse_prefix;
if (interactive) {
interactive_add(argc, argv, prefix);
@@ -306,6 +307,13 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
memset(&partial, 0, sizeof(partial));
partial.strdup_strings = 1;
+
+ /*
+ * this code modifies index but won't write down anything
+ * so it's safe to turn of sparse_prefix protection for a while
+ */
+ saved_sparse_prefix = save_sparse_prefix();
+
if (list_paths(&partial, initial_commit ? NULL : "HEAD", prefix, pathspec))
exit(1);
@@ -313,6 +321,9 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
if (read_cache() < 0)
die("cannot read the index");
+ /* re-enable sparse_prefix again */
+ restore_sparse_prefix(saved_sparse_prefix);
+
fd = hold_locked_index(&index_lock, 1);
add_remove_files(&partial);
refresh_cache(REFRESH_QUIET);
diff --git a/builtin-ls-files.c b/builtin-ls-files.c
index e8d568e..4d18873 100644
--- a/builtin-ls-files.c
+++ b/builtin-ls-files.c
@@ -606,6 +606,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
*/
if (show_stage || show_unmerged)
die("ls-files --with-tree is incompatible with -s or -u");
+ /* no need to restore as ls-files never writes index */
+ save_sparse_prefix();
overlay_tree_on_cache(with_tree, prefix);
}
show_files(&dir, prefix);
diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c
index 43e55bf..7ce015b 100644
--- a/builtin-merge-recursive.c
+++ b/builtin-merge-recursive.c
@@ -201,8 +201,10 @@ static int git_merge_trees(int index_only,
memset(&opts, 0, sizeof(opts));
if (index_only)
opts.index_only = 1;
- else
+ else {
opts.update = 1;
+ opts.check_index_prefix = 1;
+ }
opts.merge = 1;
opts.head_idx = 2;
opts.fn = threeway_merge;
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index 72a6de3..0883b41 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -218,6 +218,11 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
opts.head_idx = 1;
}
+ if (get_sparse_prefix()) {
+ read_cache();
+ opts.check_index_prefix = 1;
+ }
+
for (i = 0; i < nr_trees; i++) {
struct tree *tree = trees[i];
parse_tree(tree);
diff --git a/cache.h b/cache.h
index 4687096..f6bbadc 100644
--- a/cache.h
+++ b/cache.h
@@ -331,6 +331,7 @@ extern char **split_prefix(const char *env);
extern char **combine_prefix_list(char **p1, char **p2);
extern void free_prefix_list(char **prefix_list);
extern int outside_prefix_list(char **iprefix, const char *prefix);
+extern int check_index_prefix(const struct index_state *index, int is_merge);
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
diff --git a/diff-lib.c b/diff-lib.c
index e7eaff9..2908146 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -73,6 +73,9 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
struct cache_entry *ce = active_cache[i];
int changed;
+ if (index_outside_sparse_prefix(ce->name))
+ continue;
+
if (DIFF_OPT_TST(&revs->diffopt, QUIET) &&
DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
break;
diff --git a/read-cache.c b/read-cache.c
index a50a851..4fea40e 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -23,6 +23,11 @@
struct index_state the_index;
+static int outside_cache_prefix(const struct index_state *istate, const char *ce_name)
+{
+ return istate == &the_index && index_outside_sparse_prefix(ce_name);
+}
+
static void set_index_entry(struct index_state *istate, int nr, struct cache_entry *ce)
{
istate->cache[nr] = ce;
@@ -396,6 +401,8 @@ int remove_index_entry_at(struct index_state *istate, int pos)
{
struct cache_entry *ce = istate->cache[pos];
+ if (outside_cache_prefix(istate, ce->name))
+ die("%s: cannot remove from index outside %s", ce->name, get_sparse_prefix_str());
remove_name_hash(ce);
istate->cache_changed = 1;
istate->cache_nr--;
@@ -410,6 +417,10 @@ int remove_index_entry_at(struct index_state *istate, int pos)
int remove_file_from_index(struct index_state *istate, const char *path)
{
int pos = index_name_pos(istate, path, strlen(path));
+
+ if (outside_cache_prefix(istate, path))
+ die("%s: cannot remove from index from outside %s", path, get_sparse_prefix_str());
+
if (pos < 0)
pos = -pos-1;
cache_tree_invalidate_path(istate->cache_tree, path);
@@ -809,21 +820,43 @@ static int check_file_directory_conflict(struct index_state *istate,
return retval + has_dir_name(istate, ce, pos, ok_to_replace);
}
+/*
+ * ce_compare only considers stuff that will be written to a tree object
+ * or index stages
+ *
+ * On CE_* flags CE_HASHED, CE_UNHASHED and CE_UPTODATE are out because they
+ * are in-core only, will not be written out
+ */
+#define CE_COMPARE_MASK (CE_STATE_MASK | CE_UPTODATE)
+static int ce_compare(const struct cache_entry *ce1, const struct cache_entry *ce2)
+{
+ return ce1->ce_mode == ce2->ce_mode &&
+ ((ce1->ce_flags ^ ce2->ce_flags) & ~CE_COMPARE_MASK) == 0 &&
+ !memcmp(ce1->sha1, ce2->sha1, 20) &&
+ !strcmp(ce1->name, ce2->name);
+}
+
static int add_index_entry_with_check(struct index_state *istate, struct cache_entry *ce, int option)
{
int pos;
int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;
+ int is_outside = outside_cache_prefix(istate, ce->name);
cache_tree_invalidate_path(istate->cache_tree, ce->name);
pos = index_name_pos(istate, ce->name, ce->ce_flags);
/* existing match? Just replace it. */
if (pos >= 0) {
+ if (is_outside && !ce_compare(istate->cache[pos], ce))
+ die("%s: cannot add to index outside %s", ce->name, get_sparse_prefix_str());
replace_index_entry(istate, pos, ce);
return 0;
}
+
+ if (is_outside)
+ die("%s: cannot add to index outside %s", ce->name, get_sparse_prefix_str());
pos = -pos-1;
/*
@@ -858,9 +891,11 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti
{
int pos;
- if (option & ADD_CACHE_JUST_APPEND)
+ if (option & ADD_CACHE_JUST_APPEND) {
+ if (outside_cache_prefix(istate, ce->name))
+ die("%s: cannot add to index outside %s", ce->name, get_sparse_prefix_str());
pos = istate->cache_nr;
- else {
+ } else {
int ret;
ret = add_index_entry_with_check(istate, ce, option);
if (ret <= 0)
@@ -1444,3 +1479,71 @@ int read_index_unmerged(struct index_state *istate)
istate->cache_nr = dst - istate->cache;
return !!last;
}
+
+int check_index_prefix(const struct index_state *index, int is_merge)
+{
+ unsigned i;
+ char **index_prefix = get_sparse_prefix();
+
+ if (!index_prefix)
+ return 1;
+
+ /* Check for unmerged entries first */
+ for (i = 0; i < index->cache_nr; i++) {
+ struct cache_entry *ce = index->cache[i];
+ if (ce_stage(ce) && index_outside_sparse_prefix(ce->name))
+ return 0;
+ }
+
+ /*
+ * if is_merge is true, caller has decided that there
+ * could be changes outside index prefix, return now
+ */
+ if (is_merge)
+ return 1;
+ else {
+ const struct index_state *idx[2];
+ int prefix_i[2];
+ int index_prefix_nr;
+ unsigned entry_i[2];
+
+ idx[0] = &the_index;
+ idx[1] = index;
+ prefix_i[0] = prefix_i[1] = 0;
+ entry_i[0] = entry_i[1] = 0;
+ index_prefix_nr = 0;
+ while (index_prefix[index_prefix_nr])
+ index_prefix_nr++;
+
+ while (entry_i[0] < idx[0]->cache_nr &&
+ entry_i[1] < idx[1]->cache_nr) {
+ /* ignore anything inside index prefix */
+ int what_index;
+ for (what_index = 0; what_index < 2; what_index++) {
+ const struct index_state *idx_p = idx[what_index];
+ const char *prefix = index_prefix[prefix_i[what_index]];
+ unsigned *entry_ip = entry_i+what_index;
+ if (prefix_i[what_index] < index_prefix_nr &&
+ !prefixcmp(idx_p->cache[*entry_ip]->name, prefix)) {
+ while (*entry_ip < idx_p->cache_nr &&
+ !prefixcmp(idx_p->cache[*entry_ip]->name, prefix))
+ entry_ip[0]++;
+ prefix_i[what_index]++;
+ }
+ }
+
+ if (entry_i[0] == idx[0]->cache_nr || entry_i[1] == idx[1]->cache_nr)
+ break;
+
+ /* does not match */
+ if (!ce_compare(idx[0]->cache[entry_i[0]], idx[1]->cache[entry_i[1]]))
+ return 0;
+
+ entry_i[0]++;
+ entry_i[1]++;
+ }
+
+ return entry_i[0] == idx[0]->cache_nr &&
+ entry_i[1] == idx[1]->cache_nr;
+ }
+}
diff --git a/unpack-trees.c b/unpack-trees.c
index cba0aca..0a6723b 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -408,6 +408,9 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
if (o->trivial_merges_only && o->nontrivial_merge)
return unpack_failed(o, "Merge requires file-level merging");
+ if (o->check_index_prefix && !check_index_prefix(&o->result, o->merge && !o->prefix))
+ return unpack_failed(o, "Merge outside index prefix");
+
o->src_index = NULL;
ret = check_updates(o) ? (-2) : 0;
if (o->dst_index)
diff --git a/unpack-trees.h b/unpack-trees.h
index 94e5672..a1b46f9 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -26,7 +26,8 @@ struct unpack_trees_options {
verbose_update:1,
aggressive:1,
skip_unmerged:1,
- gently:1;
+ gently:1,
+ check_index_prefix:1;
const char *prefix;
int pos;
struct dir_struct *dir;
--
1.5.5.GIT
^ permalink raw reply related
* Re: q: faster way to integrate/merge lots of topic branches?
From: Ingo Molnar @ 2008-07-23 14:56 UTC (permalink / raw)
To: Jay Soffian; +Cc: git
In-Reply-To: <76718490807230747w5d0350b8v6feba00fb8837617@mail.gmail.com>
* Jay Soffian <jaysoffian@gmail.com> wrote:
> > CACHE=$MERGECACHE/$HEAD_SHA1/$BRANCH_SHA1
> >
> > [ -f "$CACHE" -a "$CACHE" -nt .git/refs/heads/$BRANCH_SHA1 ] && {
>
> Shouldn't this be:
>
> [ -f "$CACHE" -a "$CACHE" -nt .git/refs/heads/$BRANCH ] && {
>
> ?
yeah, i just figured it out too ... the hard way :)
Updated script below. This works fine across resets in the master
branch.
While it's fast in the empty-merge case, it's not as fast as i'd like it
to be in the almost-empty-merge case.
Ingo
--------------{ git-fastmerge }-------------------->
#!/bin/bash
usage () {
echo 'usage: tip-fastmerge <refspec>..'
exit -1
}
[ $# = 0 ] && usage
BRANCH=$1
MERGECACHE=.git/mergecache
[ ! -d $MERGECACHE ] && { mkdir $MERGECACHE || usage; }
HEADREF=.git/$(cut -d' ' -f2 .git/HEAD)
HEAD_SHA1=$(git-log -1 --pretty=format:"%H")
BRANCH_SHA1=$(git-log -1 --pretty=format:"%H" $BRANCH)
CACHE=$MERGECACHE/$HEAD_SHA1/$BRANCH_SHA1
[ -f "$CACHE" -a "$CACHE" -nt "$HEADREF" ] && {
# echo "merge-cache hit on HEAD <= $1"
exit 0
}
git-merge $1 && {
mkdir -p $(dirname $CACHE)
touch $CACHE
}
^ permalink raw reply
* [PATCH 03/12] Introduce sparse prefix
From: Nguyễn Thái Ngọc Duy @ 2008-07-23 14:56 UTC (permalink / raw)
To: git
Sparse prefix is actually a list of prefixes separated by colons,
that will limit worktree usage within it.
This patch adds core.sparsecheckout and
"git rev-parse --show-sparse-prefix". This also adds manipulation
functions that will get used later.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
builtin-rev-parse.c | 4 +
cache.h | 13 +++
config.c | 7 ++
environment.c | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 245 insertions(+), 0 deletions(-)
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index aa71f4a..4200f14 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -499,6 +499,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
puts(prefix);
continue;
}
+ if (!strcmp(arg, "--show-sparse-prefix")) {
+ puts(get_sparse_prefix_str());
+ continue;
+ }
if (!strcmp(arg, "--show-cdup")) {
const char *pfx = prefix;
if (!is_inside_work_tree()) {
diff --git a/cache.h b/cache.h
index 38985aa..4687096 100644
--- a/cache.h
+++ b/cache.h
@@ -319,6 +319,19 @@ extern const char *get_git_work_tree(void);
extern const char *read_gitfile_gently(const char *path);
extern void set_git_work_tree(const char *tree);
+extern int sparse_checkout_enabled();
+extern char **get_sparse_prefix(void);
+extern const char *get_sparse_prefix_str(void);
+extern char **save_sparse_prefix();
+extern char **restore_sparse_prefix(char **prefix);
+extern int outside_sparse_prefix(const char *prefix);
+extern int index_outside_sparse_prefix(const char *prefix);
+extern void set_sparse_prefix(const char *prefix);
+extern char **split_prefix(const char *env);
+extern char **combine_prefix_list(char **p1, char **p2);
+extern void free_prefix_list(char **prefix_list);
+extern int outside_prefix_list(char **iprefix, const char *prefix);
+
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
extern const char **get_pathspec(const char *prefix, const char **pathspec);
diff --git a/config.c b/config.c
index 1e066c7..e7b457b 100644
--- a/config.c
+++ b/config.c
@@ -467,6 +467,13 @@ static int git_default_core_config(const char *var, const char *value)
return 0;
}
+ if (!strcmp(var, "core.sparsecheckout")) {
+ if (!value)
+ return config_error_nonbool(var);
+ set_sparse_prefix(value);
+ return 0;
+ }
+
/* Add other config variables here and to Documentation/config.txt. */
return 0;
}
diff --git a/environment.c b/environment.c
index 4a88a17..94e39b8 100644
--- a/environment.c
+++ b/environment.c
@@ -46,9 +46,132 @@ enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
char *git_work_tree_cfg;
static char *work_tree;
+static char **sparse_prefix;
+
static const char *git_dir;
static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;
+static char *append_slash(const char *prefix, int len)
+{
+ char *new_prefix;
+
+ if (!*prefix)
+ return NULL;
+
+ if (prefix[len-1] == '/')
+ return xstrndup(prefix, len);
+
+ new_prefix = xmalloc(len+2);
+ memcpy(new_prefix, prefix, len);
+ new_prefix[len] = '/';
+ new_prefix[len+1] = '\0';
+ return new_prefix;
+}
+
+/* this should be sorted as same order as index */
+static int prefix_compare(const void *prefix1_, const void *prefix2_)
+{
+ const char *prefix1 = *(const char**)prefix1_;
+ const char *prefix2 = *(const char**)prefix2_;
+ int len1 = strlen(prefix1);
+ int len2 = strlen(prefix2);
+ int len = len1 < len2 ? len1 : len2;
+ int cmp = memcmp(prefix1, prefix2, len);
+ if (cmp)
+ return cmp;
+ if (len1 < len2)
+ return -1;
+ if (len1 > len2)
+ return 1;
+ return 0;
+}
+
+void free_prefix_list(char **prefix_list)
+{
+ char **prefix = prefix_list;
+
+ if (!prefix)
+ return;
+
+ while (*prefix) {
+ free(*prefix);
+ prefix++;
+ }
+ free(prefix_list);
+}
+
+char **split_prefix(const char *env)
+{
+ int prefix_nr = 0;
+ int prefix_alloc = 0;
+ char **prefix_list = NULL;
+
+ if (!env)
+ return NULL;
+
+ do {
+ const char *sep = strchr(env, ':');
+ int len = sep ? sep - env : strlen(env);
+ if (prefix_alloc <= prefix_nr+1) {
+ prefix_alloc = alloc_nr(prefix_alloc);
+ prefix_list = xrealloc(prefix_list,
+ prefix_alloc * sizeof(*prefix_list));
+ }
+ prefix_list[prefix_nr++] = append_slash(env, len);
+ env += sep ? len+1 : len;
+ } while (*env);
+ prefix_list[prefix_nr] = NULL;
+ qsort(prefix_list, prefix_nr, sizeof(*prefix_list), prefix_compare);
+ return prefix_list;
+}
+
+char **combine_prefix_list(char **p1, char **p2)
+{
+ int len1 = 0, len2 = 0;
+ char **p, **p12, *last_prefix;
+ char **result, **result_p;
+
+ /*
+ * if either of them is null, full access,
+ * combining them would give full access as well
+ */
+ if (!p1 || !p2)
+ return NULL;
+
+ for (p = p1; *p; p++)
+ len1++;
+ for (p = p2; *p; p++)
+ len2++;
+
+ p12 = xmalloc((len1+len2+1)*sizeof(*p12));
+ result = xmalloc((len1+len2+1)*sizeof(*result));
+ memcpy(p12, p1, len1*sizeof(*p12));
+ memcpy(p12+len1, p2, (len2+1)*sizeof(*p12));
+ qsort(p12, len1+len2, sizeof(*p12), prefix_compare);
+
+ p = p12;
+ last_prefix = *p;
+ p++;
+ result_p = result;
+ *result_p = xstrdup(last_prefix);
+ result_p++;
+ while (*p) {
+ if (!strcmp(*p, last_prefix)) {
+ p++;
+ continue;
+ }
+ if (!prefixcmp(*p, last_prefix)) {
+ p++;
+ continue;
+ }
+ *result_p = xstrdup(*p);
+ result_p++;
+ p++;
+ }
+ *result_p = NULL;
+ return result;
+}
+
static void setup_git_env(void)
{
git_dir = getenv(GIT_DIR_ENVIRONMENT);
@@ -122,6 +245,104 @@ const char *get_git_work_tree(void)
return work_tree;
}
+void set_sparse_prefix(const char *flat_sparse_prefix)
+{
+ free_prefix_list(sparse_prefix);
+ sparse_prefix = split_prefix(flat_sparse_prefix);
+}
+
+char **get_sparse_prefix()
+{
+ return sparse_prefix;
+}
+
+const char *get_sparse_prefix_str()
+{
+ static char **sparse_prefix = NULL;
+ static char *sparse_prefix_str = NULL;
+ int len;
+ char **prefix;
+
+ if (sparse_prefix == get_sparse_prefix())
+ return sparse_prefix ? sparse_prefix_str : "";
+
+ sparse_prefix = get_sparse_prefix();
+
+ if (!sparse_prefix)
+ return "";
+
+ len = 0;
+ for (prefix = sparse_prefix; *prefix; prefix++)
+ len += strlen(*prefix)+1;
+ if (sparse_prefix_str)
+ free(sparse_prefix_str);
+ sparse_prefix_str = xmalloc(len);
+
+ prefix = sparse_prefix;
+ len = strlen(*prefix);
+ if ((*prefix)[len-1] == '/')
+ len--;
+ memcpy(sparse_prefix_str, *prefix, len);
+ prefix++;
+ while (*prefix) {
+ int len2 = strlen(*prefix);
+ sparse_prefix_str[len++] = ':';
+ if ((*prefix)[len2-1] == '/')
+ len2--;
+ memcpy(sparse_prefix_str+len, *prefix, len2);
+ len += len2;
+ prefix++;
+ }
+ sparse_prefix_str[len] = 0;
+ return sparse_prefix_str;
+}
+
+char **save_sparse_prefix()
+{
+ char **prefix = sparse_prefix;
+ sparse_prefix = NULL;
+ return prefix;
+}
+
+char **restore_sparse_prefix(char **prefix)
+{
+ char **old_prefix = sparse_prefix;
+ sparse_prefix = prefix;
+ return old_prefix;
+}
+
+int outside_prefix_list(char **iprefix, const char *prefix)
+{
+ if (!iprefix)
+ return 0;
+
+ while (*iprefix) {
+ if (!prefixcmp(prefix, *iprefix))
+ return 0;
+ iprefix++;
+ }
+ return 1;
+}
+
+int sparse_checkout_enabled()
+{
+ static int disable_sparse_checkout = -1;
+ if (disable_sparse_checkout == -1)
+ disable_sparse_checkout = getenv("GIT_SPARSE_CHECKOUT_INDEX_ONLY") != NULL;
+ return !disable_sparse_checkout && get_sparse_prefix();
+}
+
+
+int outside_sparse_prefix(const char *prefix)
+{
+ return sparse_checkout_enabled() && outside_prefix_list(sparse_prefix, prefix);
+}
+
+int index_outside_sparse_prefix(const char *prefix)
+{
+ return outside_prefix_list(sparse_prefix, prefix);
+}
+
char *get_object_directory(void)
{
if (!git_object_dir)
--
1.5.5.GIT
^ permalink raw reply related
* [PATCH 02/12] git-grep: support --no-external-grep
From: Nguyễn Thái Ngọc Duy @ 2008-07-23 14:55 UTC (permalink / raw)
To: git
this one is mainly for testing builtin grep
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
builtin-grep.c | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/builtin-grep.c b/builtin-grep.c
index cc9ba6b..ee96d01 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -20,6 +20,8 @@
#endif
#endif
+static int no_external_grep;
+
/*
* git grep pathspecs are somewhat different from diff-tree pathspecs;
* pathname wildcards are allowed.
@@ -386,7 +388,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
* we grep through the checked-out files. It tends to
* be a lot more optimized
*/
- if (!cached) {
+ if (!cached && !no_external_grep) {
hit = external_grep(opt, paths, cached);
if (hit >= 0)
return hit;
@@ -544,6 +546,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
cached = 1;
continue;
}
+ if (!strcmp("--no-external-grep", arg)) {
+ no_external_grep = 1;
+ continue;
+ }
if (!strcmp("-a", arg) ||
!strcmp("--text", arg)) {
opt.binary = GREP_BINARY_TEXT;
--
1.5.5.GIT
^ permalink raw reply related
* [PATCH 01/12] git-grep: read config
From: Nguyễn Thái Ngọc Duy @ 2008-07-23 14:55 UTC (permalink / raw)
To: git
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
builtin-grep.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/builtin-grep.c b/builtin-grep.c
index 631129d..cc9ba6b 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -517,6 +517,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
const char **paths = NULL;
int i;
+ git_config(git_default_config, NULL);
+
memset(&opt, 0, sizeof(opt));
opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
opt.relative = 1;
--
1.5.5.GIT
^ permalink raw reply related
* [RFC PATCH 00/12] Sparse checkout
From: Nguyễn Thái Ngọc Duy @ 2008-07-23 14:55 UTC (permalink / raw)
To: git
I have not looked at non-builtin commands yet, but I think it's not
a big deal. We have several rounds before this series is good enough ;)
So in short, sparse prefix will be stored in config, core.sparsecheckout.
you have three new commands to enter/update/leave sparse checkout:
git clone --path=prefix # clone with sparse checkout
git checkout --path=prefix # limit/update checkout paths
git checkout --full # stop sparse checkout
Other operations should be normal. User attempts to do anything outside
sparse checkout will get flagged. Git itself should not touch anything
outside sparse checkout.
One more thing. As files outside sparse checkout will not be checking
out, .gitignore and .gitattributes from parent directories (outside
sparse checkout) will be gone too. This may lead to surprise.
Comments are welcome.
Nguyễn Thái Ngọc Duy (12):
git-grep: read config
git-grep: support --no-external-grep
Introduce sparse prefix
Protect index with sparse prefix
tests for sparse checkout, index protection
Avoid accessing working directory outside sparse prefix
tests for sparse checkout, worktree protection
git-clone: support --path to do sparse clone
tests for sparse clone
git-checkout: support --full and --path to manipulate sparse checkout
tests for checkout [--full|--path]
git-status: print sparse checkout status
builtin-add.c | 4 +-
builtin-apply.c | 5 +
builtin-checkout-index.c | 2 +
builtin-checkout.c | 46 ++++++-
builtin-clean.c | 3 +
builtin-clone.c | 13 ++
builtin-commit.c | 13 ++-
builtin-grep.c | 36 +++--
builtin-ls-files.c | 6 +-
builtin-ls-tree.c | 2 +-
builtin-merge-recursive.c | 6 +-
builtin-mv.c | 2 +-
builtin-read-tree.c | 5 +
builtin-rev-parse.c | 4 +
builtin-rm.c | 7 +-
builtin-update-index.c | 37 ++++-
cache.h | 19 +++
config.c | 7 +
diff-lib.c | 5 +-
diff.c | 3 +-
entry.c | 3 +
environment.c | 221 ++++++++++++++++++++++++++
read-cache.c | 112 +++++++++++++-
setup.c | 90 +++++++++++-
sha1_file.c | 3 +
t/t2010-checkout-sparse.sh | 71 +++++++++
t/t2300-sparse-index.sh | 156 +++++++++++++++++++
t/t2300/diff-index-sub.expected | 3 +
t/t2300/log.expected | 64 ++++++++
t/t2301-sparse-index-merge-recursive.sh | 226 +++++++++++++++++++++++++++
t/t2302-sparse-worktree.sh | 113 ++++++++++++++
t/t2302/add-u.expected | 1 +
t/t2302/add.expected | 2 +
t/t2302/commit.expected | 14 ++
t/t2302/diff-1.expected | 7 +
t/t2302/diff-cc.expected | 9 +
t/t2302/grep-work.expected | 2 +
t/t2302/grep.expected | 2 +
t/t2302/ls-files.expected | 2 +
t/t2303-sparse-worktree-apply.sh | 62 ++++++++
t/t2303/apply-initial.patch | 14 ++
t/t2303/apply-inside.patch | 7 +
t/t2303/apply-leading-dirs.patch | 3 +
t/t2303/apply-outside.patch | 7 +
t/t2303/apply-remove.patch | 7 +
t/t2303/apply-rename.expected | 13 ++
t/t2303/apply-rename.patch | 4 +
t/t2304-sparse-worktree-merge-recursive.sh | 233 ++++++++++++++++++++++++++++
t/t5703-clone-sparse.sh | 40 +++++
unpack-trees.c | 152 +++++++++++++++++--
unpack-trees.h | 4 +-
wt-status.c | 12 +-
52 files changed, 1831 insertions(+), 53 deletions(-)
create mode 100755 t/t2010-checkout-sparse.sh
create mode 100755 t/t2300-sparse-index.sh
create mode 100644 t/t2300/diff-index-sub.expected
create mode 100644 t/t2300/log.expected
create mode 100755 t/t2301-sparse-index-merge-recursive.sh
create mode 100755 t/t2302-sparse-worktree.sh
create mode 100644 t/t2302/add-u.expected
create mode 100644 t/t2302/add.expected
create mode 100644 t/t2302/commit.expected
create mode 100644 t/t2302/diff-1.expected
create mode 100644 t/t2302/diff-cc.expected
create mode 100644 t/t2302/grep-work.expected
create mode 100644 t/t2302/grep.expected
create mode 100644 t/t2302/ls-files.expected
create mode 100755 t/t2303-sparse-worktree-apply.sh
create mode 100644 t/t2303/apply-initial.patch
create mode 100644 t/t2303/apply-inside.patch
create mode 100644 t/t2303/apply-leading-dirs.patch
create mode 100644 t/t2303/apply-outside.patch
create mode 100644 t/t2303/apply-remove.patch
create mode 100644 t/t2303/apply-rename.expected
create mode 100644 t/t2303/apply-rename.patch
create mode 100755 t/t2304-sparse-worktree-merge-recursive.sh
create mode 100755 t/t5703-clone-sparse.sh
^ permalink raw reply
* Re: [RFC] Git User's Survey 2008
From: Dmitry Potapov @ 2008-07-23 14:54 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Jakub Narebski, git, Stephan Beyer
In-Reply-To: <alpine.DEB.1.00.0807231128090.2830@eeepc-johanness>
On Wed, Jul 23, 2008 at 11:53:27AM +0200, Johannes Schindelin wrote:
>
> On Wed, 23 Jul 2008, Jakub Narebski wrote:
>
>
> > 11. Why did you choose Git? (if you use Git)
> > What do you like about using Git?
> > (free form, not to be tabulated)
>
> Again, to avoid hassles with free-form:
>
> Mandatory: work, mandatory: open source project I am participating
> in, speed, scalability, It's What Linus Uses, Other.
If we move away from free-form, it should be much more choices here.
- Ability to work offline
- Cryptographic authentication of history.
- Distributed development (pull/push from/to more than one remote repo)
- Easy to extend functionality through scripting
- Efficient storage model
- Elegant design
- Fast
- Good community support
- Rewriting patches before publishing (git rebase, commit --amend)
- Scalability (Efficient handling of large projects)
- Strong support for non-linear development
- Support of wide range of protocols for synchronization.
...
Dmitry
^ permalink raw reply
* Re: [RFC] Git User's Survey 2008
From: Robin Rosenberg @ 2008-07-23 14:54 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Jakub Narebski, git
In-Reply-To: <alpine.DEB.1.00.0807231414480.8986@racer>
onsdagen den 23 juli 2008 15.18.40 skrev Johannes Schindelin:
> Hi,
>
> On Wed, 23 Jul 2008, Jakub Narebski wrote:
>
> > On Wed, 23 Jul 2008, Johannes Schindelin wrote:
> > > On Wed, 23 Jul 2008, Jakub Narebski wrote:
> > >
> > > Some people prefer to stay anonymous, so I think email is out.
> > >
> > > > 04. Which programming languages you are proficient with?
> > > > (The choices include programming languages used by git)
> > > > (zero or more: multiple choice)
> > > > - C, shell, Perl, Python, Tcl/Tk
> > > > + (should we include other languages, like C++, Java, PHP,
> > > > Ruby,...?)
> > >
> > > Yes, I think this should be a long list.
> >
> > I'd rather not have a "laundry list" of languages. I have put C++
> > because QGit uses it, Java because of egit/jgit, PHP for web
> > interfaces, Ruby because of GitHub and because of Ruby comminity
> > choosing Git. I should perhaps add Emacs Lisp, HTML+CSS and
> > JavaScript here. What other languages should be considered?
>
> C# at least, since we had one (pretty unsuccessful) attempt at
> reimplementing Git in it.
What is the reason for the question? Do we want to know what languages
people would like to contribute to Git in or do we want to know what "kind"
of programmers are attracted by Git? Making it a long list should make
it easier to tabulate the responses.
-- robin
^ permalink raw reply
* Re: [PATCH] Rename ".dotest/" to ".git/rebase" and ".dotest-merge" to "rebase-merge"
From: Olivier Marin @ 2008-07-23 14:54 UTC (permalink / raw)
To: Stephan Beyer
Cc: Junio C Hamano, Theodore Tso, Nanako Shiraishi,
Johannes Schindelin, René Scharfe, Joe Fiorini, git,
Jari Aalto
In-Reply-To: <20080723011341.GE5904@leksak.fem-net>
Stephan Beyer a écrit :
>
>>> Perhaps I am confused, but ...
I can understand. ;-)
>>> Why is there "HEAD" and "ORIG_HEAD" and not only "ORIG_HEAD"?
>> Just being a bit defensive -- in this case I think it might be Ok to say
>> "read-tree --reset -u ORIG_HEAD", but I haven't checked in a conflicted
>> case.
git read-tree --reset -u ORIG_HEAD clears local changes which is not good.
> Well, the test suite fails:
> * FAIL 4: am --abort goes back after failed am
>
> git-am --abort &&
> git rev-parse HEAD >actual &&
> git rev-parse initial >expect &&
> test_cmp expect actual &&
> here> test_cmp file-2-expect file-2 &&
Local changes have been lost.
> The reason of my question was that I *blindly* incorporated the change into
> sequencer to make it able to work on a dirty working tree and thus to be
> able to migrate am onto it without losing the ability to apply patches
> on a dirty working tree....
Are you talking about your seq-proto-dev3 branch?
> All am tests applied afterwards, but the sequencer and the rebase-i
> test suite failed in a place where I didn't expect it. I *then* had
> a deeper look at the read-tree line and I was wondering what the "HEAD"
> should achieve.
> I removed it and all tests passed. (I didn't have t4151 in my branch
> at that point.)
>
> Now, because t4151 does not pass, I am wondering what's the best thing
> I could do...
I looked at your code. You use reset_almost_hard() instead of "reset --hard",
it's fine but you does not update require_clean_work_tree() to be less
restrictive and let the sequencer work with local modifications. Those two
lines must be removed, I think:
git update-index --ignore-submodules --refresh &&
git diff-files --quiet --ignore-submodules &&
Try that with the original read-tree line and t4151 should pass.
Ah, you should change "Applying 6" with "Applying \"6\"" in t4151-am-abort.sh
too.
Olivier.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox