Merge branch 'master' of git://repo.or.cz/alt-git

This commit is contained in:
Johannes Sixt
2008-03-19 12:46:28 +01:00
11 changed files with 207 additions and 37 deletions

View File

@@ -33,3 +33,10 @@ ours::
merge is always the current branch head. It is meant to
be used to supersede old development history of side
branches.
subtree::
This is a modified recursive strategy. When merging trees A and
B, if B corresponds to a subtree of A, B is first adjusted to
match the tree structure of A, instead of reading the trees at
the same level. This adjustment is also done to the common
ancestor tree.

View File

@@ -26,6 +26,8 @@ static const char fetch_pack_usage[] =
#define SEEN (1U << 3)
#define POPPED (1U << 4)
static int marked;
/*
* After sending this many "have"s if we do not get any new ACK , we
* give up traversing our history.
@@ -61,6 +63,16 @@ static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int
return 0;
}
static int clear_marks(const char *path, const unsigned char *sha1, int flag, void *cb_data)
{
struct object *o = deref_tag(parse_object(sha1), path, 0);
if (o && o->type == OBJ_COMMIT)
clear_commit_marks((struct commit *)o,
COMMON | COMMON_REF | SEEN | POPPED);
return 0;
}
/*
This function marks a rev and its ancestors as common.
In some cases, it is desirable to mark only the ancestors (for example
@@ -153,6 +165,10 @@ static int find_common(int fd[2], unsigned char *result_sha1,
unsigned in_vain = 0;
int got_continue = 0;
if (marked)
for_each_ref(clear_marks, NULL);
marked = 1;
for_each_ref(rev_list_insert_ref, NULL);
fetching = 0;

View File

@@ -218,7 +218,6 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
* to emulate by hand - much easier to let the system
* just do the right thing)
*/
unlink(path);
if (S_ISDIR(st.st_mode)) {
/* If it is a gitlink, leave it alone! */
if (S_ISGITLINK(ce->ce_mode))
@@ -226,7 +225,8 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
if (!state->force)
return error("%s is a directory", path);
remove_subtree(path);
}
} else if (unlink(path))
return error("unable to unlink old '%s' (%s)", path, strerror(errno));
} else if (state->not_new)
return 0;
create_directories(path, state);

View File

@@ -48,10 +48,11 @@ case "${1:-.}${2:-.}${3:-.}" in
;;
"..$3")
echo "Adding $4"
test -f "$4" || {
if test -f "$4"
then
echo "ERROR: untracked $4 is overwritten by the merge."
exit 1
}
fi
git update-index --add --cacheinfo "$7" "$3" "$4" &&
exec git checkout-index -u -f -- "$4"
;;

View File

@@ -396,6 +396,7 @@ static void read_config(void)
struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)
{
int i;
int st;
struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec);
for (i = 0; i < nr_refspec; i++) {
const char *sp, *ep, *gp;
@@ -404,13 +405,15 @@ struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)
rs[i].force = 1;
sp++;
}
gp = strchr(sp, '*');
gp = strstr(sp, "/*");
ep = strchr(sp, ':');
if (gp && ep && gp > ep)
gp = NULL;
if (ep) {
if (ep[1]) {
const char *glob = strchr(ep + 1, '*');
const char *glob = strstr(ep + 1, "/*");
if (glob && glob[2])
glob = NULL;
if (!glob)
gp = NULL;
if (gp)
@@ -422,11 +425,24 @@ struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)
} else {
ep = sp + strlen(sp);
}
if (gp && gp + 2 != ep)
gp = NULL;
if (gp) {
rs[i].pattern = 1;
ep = gp;
}
rs[i].src = xstrndup(sp, ep - sp);
if (*rs[i].src) {
st = check_ref_format(rs[i].src);
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
die("Invalid refspec '%s'", refspec[i]);
}
if (rs[i].dst && *rs[i].dst) {
st = check_ref_format(rs[i].dst);
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
die("Invalid refspec '%s'", refspec[i]);
}
}
return rs;
}
@@ -543,7 +559,8 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec)
if (!fetch->dst)
continue;
if (fetch->pattern) {
if (!prefixcmp(needle, key)) {
if (!prefixcmp(needle, key) &&
needle[strlen(key)] == '/') {
*result = xmalloc(strlen(value) +
strlen(needle) -
strlen(key) + 1);
@@ -790,7 +807,9 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
{
int i;
for (i = 0; i < rs_nr; i++) {
if (rs[i].pattern && !prefixcmp(src->name, rs[i].src))
if (rs[i].pattern &&
!prefixcmp(src->name, rs[i].src) &&
src->name[strlen(rs[i].src)] == '/')
return rs + i;
}
return NULL;
@@ -989,7 +1008,7 @@ int get_fetch_map(const struct ref *remote_refs,
struct ref ***tail,
int missing_ok)
{
struct ref *ref_map, *rm;
struct ref *ref_map, **rmp;
if (refspec->pattern) {
ref_map = get_expanded_map(remote_refs, refspec);
@@ -1006,10 +1025,20 @@ int get_fetch_map(const struct ref *remote_refs,
}
}
for (rm = ref_map; rm; rm = rm->next) {
if (rm->peer_ref && check_ref_format(rm->peer_ref->name + 5))
die("* refusing to create funny ref '%s' locally",
rm->peer_ref->name);
for (rmp = &ref_map; *rmp; ) {
if ((*rmp)->peer_ref) {
int st = check_ref_format((*rmp)->peer_ref->name + 5);
if (st && st != CHECK_REF_FORMAT_ONELEVEL) {
struct ref *ignore = *rmp;
error("* Ignoring funny ref '%s' locally",
(*rmp)->peer_ref->name);
*rmp = (*rmp)->next;
free(ignore->peer_ref);
free(ignore);
continue;
}
}
rmp = &((*rmp)->next);
}
if (ref_map)

View File

@@ -564,14 +564,39 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
free_patch_ids(&ids);
}
static void add_to_list(struct commit_list **p, struct commit *commit, struct commit_list *n)
/* How many extra uninteresting commits we want to see.. */
#define SLOP 5
static int still_interesting(struct commit_list *src, unsigned long date, int slop)
{
p = &commit_list_insert(commit, p)->next;
*p = n;
/*
* No source list at all? We're definitely done..
*/
if (!src)
return 0;
/*
* Does the destination list contain entries with a date
* before the source list? Definitely _not_ done.
*/
if (date < src->item->date)
return SLOP;
/*
* Does the source list still have interesting commits in
* it? Definitely not done..
*/
if (!everybody_uninteresting(src))
return SLOP;
/* Ok, we're closing in.. */
return slop-1;
}
static int limit_list(struct rev_info *revs)
{
int slop = SLOP;
unsigned long date = ~0ul;
struct commit_list *list = revs->commits;
struct commit_list *newlist = NULL;
struct commit_list **p = &newlist;
@@ -591,16 +616,19 @@ static int limit_list(struct rev_info *revs)
return -1;
if (obj->flags & UNINTERESTING) {
mark_parents_uninteresting(commit);
if (everybody_uninteresting(list)) {
if (revs->show_all)
add_to_list(p, commit, list);
break;
}
if (!revs->show_all)
if (revs->show_all)
p = &commit_list_insert(commit, p)->next;
slop = still_interesting(list, date, slop);
if (slop)
continue;
/* If showing all, add the whole pending list to the end */
if (revs->show_all)
*p = list;
break;
}
if (revs->min_age != -1 && (commit->date > revs->min_age))
continue;
date = commit->date;
p = &commit_list_insert(commit, p)->next;
show = show_early_output;

View File

@@ -157,4 +157,85 @@ test_expect_success '3-way not overwriting local changes (their side)' '
'
test_expect_success 'funny symlink in work tree' '
git reset --hard &&
git checkout -b sym-b side-b &&
mkdir -p a &&
>a/b &&
git add a/b &&
git commit -m "side adds a/b" &&
rm -fr a &&
git checkout -b sym-a side-a &&
mkdir -p a &&
ln -s ../b a/b &&
git add a/b &&
git commit -m "we add a/b" &&
git read-tree -m -u sym-a sym-a sym-b
'
test_expect_success 'funny symlink in work tree, un-unlink-able' '
rm -fr a b &&
git reset --hard &&
git checkout sym-a &&
chmod a-w a &&
test_must_fail git read-tree -m -u sym-a sym-a sym-b
'
# clean-up from the above test
chmod a+w a
rm -fr a b
test_expect_success 'D/F setup' '
git reset --hard &&
git checkout side-a &&
rm -f subdir/file2 &&
mkdir subdir/file2 &&
echo qfwfq >subdir/file2/another &&
git add subdir/file2/another &&
test_tick &&
git commit -m "side-a changes file2 to directory"
'
test_expect_success 'D/F' '
git checkout side-b &&
git read-tree -m -u branch-point side-b side-a &&
git ls-files -u >actual &&
(
a=$(git rev-parse branch-point:subdir/file2)
b=$(git rev-parse side-a:subdir/file2/another)
echo "100644 $a 1 subdir/file2"
echo "100644 $a 2 subdir/file2"
echo "100644 $b 3 subdir/file2/another"
) >expect &&
test_cmp actual expect
'
test_expect_success 'D/F resolve' '
git reset --hard &&
git checkout side-b &&
git merge-resolve branch-point -- side-b side-a
'
test_expect_success 'D/F recursive' '
git reset --hard &&
git checkout side-b &&
git merge-recursive branch-point -- side-b side-a
'
test_done

View File

@@ -155,16 +155,6 @@ test_expect_success 'test tracking setup via config' \
test $(git config branch.my3.remote) = local &&
test $(git config branch.my3.merge) = refs/heads/master'
test_expect_success 'avoid ambiguous track' '
git config branch.autosetupmerge true &&
git config remote.ambi1.url = lalala &&
git config remote.ambi1.fetch = refs/heads/lalala:refs/heads/master &&
git config remote.ambi2.url = lilili &&
git config remote.ambi2.fetch = refs/heads/lilili:refs/heads/master &&
git branch all1 master &&
test -z "$(git config branch.all1.merge)"
'
test_expect_success 'test overriding tracking setup via --no-track' \
'git config branch.autosetupmerge true &&
git config remote.local.url . &&
@@ -226,4 +216,14 @@ test_expect_success \
test -f .git/logs/refs/heads/g/h/i &&
diff expect .git/logs/refs/heads/g/h/i'
test_expect_success 'avoid ambiguous track' '
git config branch.autosetupmerge true &&
git config remote.ambi1.url lalala &&
git config remote.ambi1.fetch refs/heads/lalala:refs/heads/master &&
git config remote.ambi2.url lilili &&
git config remote.ambi2.fetch refs/heads/lilili:refs/heads/master &&
git branch all1 master &&
test -z "$(git config branch.all1.merge)"
'
test_done

View File

@@ -27,7 +27,7 @@ test_expect_success setup '
git log --pretty=oneline --abbrev-commit
'
test_expect_failure 'one is ancestor of others and should not be shown' '
test_expect_success 'one is ancestor of others and should not be shown' '
git rev-list one --not four >result &&
>expect &&

View File

@@ -396,7 +396,12 @@ fi
# Test repository
test=trash
rm -fr "$test"
rm -fr "$test" || {
trap - exit
echo >&5 "FATAL: Cannot prepare test area"
exit 1
}
test_create_repo $test
cd "$test"

View File

@@ -54,13 +54,14 @@ static void unlink_entry(char *name, char *last_symlink)
}
static struct checkout state;
static void check_updates(struct unpack_trees_options *o)
static int check_updates(struct unpack_trees_options *o)
{
unsigned cnt = 0, total = 0;
struct progress *progress = NULL;
char last_symlink[PATH_MAX];
struct index_state *index = &o->result;
int i;
int errs = 0;
if (o->update && o->verbose_update) {
for (total = cnt = 0; cnt < index->cache_nr; cnt++) {
@@ -90,12 +91,13 @@ static void check_updates(struct unpack_trees_options *o)
if (ce->ce_flags & CE_UPDATE) {
ce->ce_flags &= ~CE_UPDATE;
if (o->update) {
checkout_entry(ce, &state, NULL);
errs |= checkout_entry(ce, &state, NULL);
*last_symlink = '\0';
}
}
}
stop_progress(&progress);
return errs != 0;
}
static inline int call_unpack_fn(struct cache_entry **src, struct unpack_trees_options *o)
@@ -369,7 +371,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
return unpack_failed(o, "Merge requires file-level merging");
o->src_index = NULL;
check_updates(o);
if (check_updates(o))
return -1;
if (o->dst_index)
*o->dst_index = o->result;
return 0;