Merge branch 'master' of .
This commit is contained in:
commit
4803c2802c
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
|
||||
|
2
Makefile
2
Makefile
@ -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 = \
|
||||
|
@ -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
|
||||
|
11
git-fetch.sh
11
git-fetch.sh
@ -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
|
||||
|
||||
|
@ -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 ;;
|
||||
|
@ -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)
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
# -----------------
|
||||
|
||||
|
15
read-tree.c
15
read-tree.c
@ -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
|
||||
|
||||
|
28
sha1_file.c
28
sha1_file.c
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user