Merge branch 'master' of .

This commit is contained in:
Junio C Hamano 2005-09-13 22:30:13 -07:00
commit 4803c2802c
11 changed files with 134 additions and 81 deletions

2
.gitignore vendored
View File

@ -44,10 +44,10 @@ git-mailinfo
git-mailsplit
git-merge
git-merge-base
git-merge-fredrik
git-merge-index
git-merge-octopus
git-merge-one-file
git-merge-recursive
git-merge-resolve
git-merge-stupid
git-mktag

View File

@ -83,7 +83,7 @@ SCRIPT_PERL = \
git-rename.perl git-shortlog.perl
SCRIPT_PYTHON = \
git-merge-fredrik.py
git-merge-recursive.py
# The ones that do not have to link with lcrypto nor lz.
SIMPLE_PROGRAMS = \

View File

@ -5,6 +5,9 @@
#
# Clone a repository into a different directory that does not yet exist.
# See git-sh-setup why.
unset CDPATH
usage() {
echo >&2 "* git clone [-l [-s]] [-q] [-u <upload-pack>] <repo> <dir>"
exit 1

View File

@ -205,9 +205,16 @@ case "$remote" in
http://* | https://* | rsync://* )
;; # we are already done.
*)
git-fetch-pack "$remote" $rref |
(
git-fetch-pack "$remote" $rref || echo failed "$remote"
) |
while read sha1 remote_name
do
case "$sha1" in
failed)
echo >&2 "Fetch failure: $remote"
exit 1 ;;
esac
found=
single_force=
for ref in $refs
@ -225,7 +232,7 @@ http://* | https://* | rsync://* )
local_name=$(expr "$found" : '[^:]*:\(.*\)')
append_fetch_head "$sha1" "$remote" "$remote_name" "$remote_nick" "$local_name"
done
done || exit
;;
esac

View File

@ -42,12 +42,16 @@ http://* | https://* )
if [ -n "$GIT_SSL_NO_VERIFY" ]; then
curl_extra_args="-k"
fi
curl -nsf $curl_extra_args "$peek_repo/info/refs" || exit 1
curl -nsf $curl_extra_args "$peek_repo/info/refs" ||
echo "failed slurping"
;;
rsync://* )
mkdir $tmpdir
rsync -rq "$peek_repo/refs" $tmpdir || exit 1
rsync -rq "$peek_repo/refs" $tmpdir || {
echo "failed slurping"
exit
}
(cd $tmpdir && find refs -type f) |
while read path
do
@ -58,12 +62,17 @@ rsync://* )
;;
* )
git-peek-remote "$peek_repo"
git-peek-remote "$peek_repo" ||
echo "failed slurping"
;;
esac |
sort -t ' ' -k 2 |
while read sha1 path
do
case "$sha1" in
failed)
die "Failed to find remote refs"
esac
case "$path" in
refs/heads/*)
group=heads ;;

View File

@ -7,11 +7,25 @@ from sets import Set
sys.path.append('@@GIT_PYTHON_PATH@@')
from gitMergeCommon import *
alwaysWriteTree = False
# The actual merge code
# ---------------------
originalIndexFile = os.environ.get('GIT_INDEX_FILE',
os.environ.get('GIT_DIR', '.git') + '/index')
temporaryIndexFile = os.environ.get('GIT_DIR', '.git') + \
'/merge-recursive-tmp-index'
def setupIndex(temporary):
try:
os.unlink(temporaryIndexFile)
except OSError:
pass
if temporary:
newIndex = temporaryIndexFile
os.environ
else:
newIndex = originalIndexFile
os.environ['GIT_INDEX_FILE'] = newIndex
def merge(h1, h2, branch1Name, branch2Name, graph, callDepth=0):
'''Merge the commits h1 and h2, return the resulting virtual
commit object and a flag indicating the cleaness of the merge.'''
@ -41,24 +55,16 @@ def merge(h1, h2, branch1Name, branch2Name, graph, callDepth=0):
assert(isinstance(Ms, Commit))
if callDepth == 0:
if len(ca) > 1:
runProgram(['git-read-tree', h1.tree()])
runProgram(['git-update-cache', '-q', '--refresh'])
# Use the original index if we only have one common ancestor
updateWd = True
if alwaysWriteTree:
cleanCache = True
else:
cleanCache = False
setupIndex(False)
cleanCache = False
else:
setupIndex(True)
runProgram(['git-read-tree', h1.tree()])
updateWd = False
cleanCache = True
[shaRes, clean] = mergeTrees(h1.tree(), h2.tree(), Ms.tree(),
branch1Name, branch2Name,
cleanCache, updateWd)
cleanCache)
if clean or cleanCache:
res = Commit(None, [h1, h2], tree=shaRes)
@ -68,7 +74,7 @@ def merge(h1, h2, branch1Name, branch2Name, graph, callDepth=0):
return [res, clean]
getFilesRE = re.compile('([0-9]+) ([a-z0-9]+) ([0-9a-f]{40})\t(.*)')
getFilesRE = re.compile(r'^([0-7]+) (\S+) ([0-9a-f]{40})\t(.*)$', re.S)
def getFilesAndDirs(tree):
files = Set()
dirs = Set()
@ -93,7 +99,7 @@ class CacheEntry:
self.stages = [Stage(), Stage(), Stage()]
self.path = path
unmergedRE = re.compile('^([0-9]+) ([0-9a-f]{40}) ([1-3])\t(.*)$')
unmergedRE = re.compile(r'^([0-7]+) ([0-9a-f]{40}) ([1-3])\t(.*)$', re.S)
def unmergedCacheEntries():
'''Create a dictionary mapping file names to CacheEntry
objects. The dictionary contains one entry for every path with a
@ -125,7 +131,7 @@ def unmergedCacheEntries():
return res
def mergeTrees(head, merge, common, branch1Name, branch2Name,
cleanCache, updateWd):
cleanCache):
'''Merge the trees 'head' and 'merge' with the common ancestor
'common'. The name of the head branch is 'branch1Name' and the name of
the merge branch is 'branch2Name'. Return a tuple (tree, cleanMerge)
@ -138,10 +144,11 @@ def mergeTrees(head, merge, common, branch1Name, branch2Name,
print 'Already uptodate!'
return [head, True]
if updateWd:
updateArg = '-u'
else:
if cleanCache:
updateArg = '-i'
else:
updateArg = '-u'
runProgram(['git-read-tree', updateArg, '-m', common, head, merge])
cleanMerge = True
@ -157,7 +164,7 @@ def mergeTrees(head, merge, common, branch1Name, branch2Name,
entries = unmergedCacheEntries()
for name in entries:
if not processEntry(entries[name], branch1Name, branch2Name,
files, dirs, cleanCache, updateWd):
files, dirs, cleanCache):
cleanMerge = False
if cleanMerge or cleanCache:
@ -169,29 +176,25 @@ def mergeTrees(head, merge, common, branch1Name, branch2Name,
return [tree, cleanMerge]
def processEntry(entry, branch1Name, branch2Name, files, dirs,
cleanCache, updateWd):
def processEntry(entry, branch1Name, branch2Name, files, dirs, cleanCache):
'''Merge one cache entry. 'files' is a Set with the files in both of
the heads that we are going to merge. 'dirs' contains the
corresponding data for directories. If 'cleanCache' is True no
non-zero stages will be left in the cache for the path
corresponding to the entry 'entry'.'''
# cleanCache == True => Don't leave any non-stage 0 entries in the cache.
# False => Leave unmerged entries
# updateWd == True => Update the working directory to correspond to the cache
# False => Leave the working directory unchanged
# cleanCache == True => Don't leave any non-stage 0 entries in the cache and
# don't update the working directory
# False => Leave unmerged entries and update the working directory
# clean == True => non-conflict case
# False => conflict case
# If cleanCache == False then the cache shouldn't be updated if clean == False
def updateFile(clean, sha, mode, path):
if cleanCache or (not cleanCache and clean):
runProgram(['git-update-cache', '--add', '--cacheinfo',
'0%o' % mode, sha, path])
def updateFile(clean, sha, mode, path, onlyWd=False):
updateCache = not onlyWd and (cleanCache or (not cleanCache and clean))
updateWd = onlyWd or (not cleanCache and clean)
if updateWd:
prog = ['git-cat-file', 'blob', sha]
@ -213,13 +216,18 @@ def processEntry(entry, branch1Name, branch2Name, files, dirs,
os.symlink(linkTarget, path)
else:
assert(False)
runProgram(['git-update-cache', '--', path])
if updateWd and updateCache:
runProgram(['git-update-index', '--add', '--', path])
elif updateCache:
runProgram(['git-update-index', '--add', '--cacheinfo',
'0%o' % mode, sha, path])
def removeFile(clean, path):
if cleanCache or (not cleanCache and clean):
runProgram(['git-update-cache', '--force-remove', '--', path])
runProgram(['git-update-index', '--force-remove', '--', path])
if updateWd:
if not cleanCache and clean:
try:
os.unlink(path)
except OSError, e:
@ -235,8 +243,7 @@ def processEntry(entry, branch1Name, branch2Name, files, dirs,
files.add(newPath)
return newPath
debug('processing', entry.path, 'clean cache:', cleanCache,
'wd:', updateWd)
debug('processing', entry.path, 'clean cache:', cleanCache)
cleanMerge = True
@ -327,9 +334,9 @@ def processEntry(entry, branch1Name, branch2Name, files, dirs,
if aMode != bMode:
cleanMerge = False
print 'CONFLICT: File "' + path + \
'" added identically in both branches,'
print 'CONFLICT: but permissions conflict', '0%o' % aMode, \
'->', '0%o' % bMode
'" added identically in both branches,', \
'but permissions conflict', '0%o' % aMode, '->', \
'0%o' % bMode
print 'CONFLICT: adding with permission:', '0%o' % aMode
updateFile(False, aSha, aMode, path)
@ -341,8 +348,7 @@ def processEntry(entry, branch1Name, branch2Name, files, dirs,
newPath1 = uniquePath(path, branch1Name)
newPath2 = uniquePath(path, branch2Name)
print 'CONFLICT (add/add): File "' + path + \
'" added non-identically in both branches.', \
'Adding "' + newPath1 + '" and "' + newPath2 + '" instead.'
'" added non-identically in both branches.'
removeFile(False, path)
updateFile(False, aSha, aMode, newPath1)
updateFile(False, bSha, bMode, newPath2)
@ -372,7 +378,12 @@ def processEntry(entry, branch1Name, branch2Name, files, dirs,
if ret != 0:
cleanMerge = False
print 'CONFLICT (content): Merge conflict in "' + path + '".'
updateFile(False, sha, mode, path)
if cleanCache:
updateFile(False, sha, mode, path)
else:
updateFile(True, aSha, aMode, path)
updateFile(False, sha, mode, path, True)
else:
updateFile(True, sha, mode, path)
@ -425,5 +436,4 @@ except:
if clean:
sys.exit(0)
else:
print 'Automatic merge failed, fix up by hand'
sys.exit(1)

View File

@ -12,9 +12,9 @@ usage () {
die "git-merge [-n] [-s <strategy>]... <merge-message> <head> <remote>+"
}
# all_strategies='resolve fredrik stupid octopus'
# all_strategies='resolve recursive stupid octopus'
all_strategies='fredrik octopus resolve stupid'
all_strategies='recursive octopus resolve stupid'
default_strategies='resolve octopus'
use_strategies=
@ -43,7 +43,7 @@ do
case "$#,$1" in
*,*=*)
strategy=`expr "$1" : '-[^=]*=\(.*\)'` ;;
0,*)
1,*)
usage ;;
*)
strategy="$2"

View File

@ -6,6 +6,12 @@
: ${GIT_DIR=.git}
: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
# Having this variable in your environment would break scripts because
# you would cause "cd" to be be taken to unexpected places. If you
# like CDPATH, define it for your interactive shell sessions without
# exporting it.
unset CDPATH
die() {
echo "$@" >&2
exit 1

View File

@ -1,19 +1,24 @@
import sys, re, os, traceback
from sets import Set
if sys.version_info[0] < 2 or \
(sys.version_info[0] == 2 and sys.version_info[1] < 4):
print 'Python version 2.4 required, found', \
str(sys.version_info[0])+'.'+str(sys.version_info[1])+'.'+ \
str(sys.version_info[2])
sys.exit(1)
import subprocess
def die(*args):
printList(args, sys.stderr)
sys.exit(2)
def printList(list, file=sys.stdout):
for x in list:
file.write(str(x))
file.write(' ')
file.write('\n')
if sys.version_info[0] < 2 or \
(sys.version_info[0] == 2 and sys.version_info[1] < 4):
die('Python version 2.4 required, found', \
str(sys.version_info[0])+'.'+str(sys.version_info[1])+'.'+ \
str(sys.version_info[2]))
import subprocess
# Debugging machinery
# -------------------
@ -32,12 +37,6 @@ def debug(*args):
if funcName in functionsToDebug:
printList(args)
def printList(list, file=sys.stdout):
for x in list:
file.write(str(x))
file.write(' ')
file.write('\n')
# Program execution
# -----------------

View File

@ -362,12 +362,15 @@ static int keep_entry(struct cache_entry *ce)
static void show_stage_entry(FILE *o,
const char *label, const struct cache_entry *ce)
{
fprintf(stderr, "%s%06o %s %d\t%s\n",
label,
ntohl(ce->ce_mode),
sha1_to_hex(ce->sha1),
ce_stage(ce),
ce->name);
if (!ce)
fprintf(o, "%s (missing)\n", label);
else
fprintf(o, "%s%06o %s %d\t%s\n",
label,
ntohl(ce->ce_mode),
sha1_to_hex(ce->sha1),
ce_stage(ce),
ce->name);
}
#endif

View File

@ -240,10 +240,12 @@ static struct alternate_object_database **alt_odb_tail;
* SHA1, an extra slash for the first level indirection, and the
* terminating NUL.
*/
static void link_alt_odb_entries(const char *alt, const char *ep, int sep)
static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
const char *relative_base)
{
const char *cp, *last;
struct alternate_object_database *ent;
int base_len = -1;
last = alt;
while (last < ep) {
@ -261,12 +263,25 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep)
int pfxlen = cp - last;
int entlen = pfxlen + 43;
if (*last != '/' && relative_base) {
/* Relative alt-odb */
if (base_len < 0)
base_len = strlen(relative_base) + 1;
entlen += base_len;
pfxlen += base_len;
}
ent = xmalloc(sizeof(*ent) + entlen);
*alt_odb_tail = ent;
alt_odb_tail = &(ent->next);
ent->next = NULL;
memcpy(ent->base, last, pfxlen);
if (*last != '/' && relative_base) {
memcpy(ent->base, relative_base, base_len - 1);
ent->base[base_len - 1] = '/';
memcpy(ent->base + base_len,
last, cp - last);
}
else
memcpy(ent->base, last, pfxlen);
ent->name = ent->base + pfxlen + 1;
ent->base[pfxlen] = ent->base[pfxlen + 3] = '/';
ent->base[entlen-1] = 0;
@ -288,12 +303,12 @@ void prepare_alt_odb(void)
alt = getenv(ALTERNATE_DB_ENVIRONMENT);
if (!alt) alt = "";
sprintf(path, "%s/info/alternates", get_object_directory());
if (alt_odb_tail)
return;
alt_odb_tail = &alt_odb_list;
link_alt_odb_entries(alt, alt + strlen(alt), ':');
link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL);
sprintf(path, "%s/info/alternates", get_object_directory());
fd = open(path, O_RDONLY);
if (fd < 0)
return;
@ -306,7 +321,8 @@ void prepare_alt_odb(void)
if (map == MAP_FAILED)
return;
link_alt_odb_entries(map, map + st.st_size, '\n');
link_alt_odb_entries(map, map + st.st_size, '\n',
get_object_directory());
munmap(map, st.st_size);
}