diff options
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/completion/git-completion.bash | 49 | ||||
-rw-r--r-- | contrib/completion/git-completion.zsh | 163 | ||||
-rw-r--r-- | contrib/completion/git-prompt.sh | 21 | ||||
-rwxr-xr-x | contrib/remote-helpers/git-remote-bzr | 330 | ||||
-rwxr-xr-x | contrib/remote-helpers/git-remote-hg | 53 | ||||
-rwxr-xr-x | contrib/remote-helpers/test-bzr.sh | 110 | ||||
-rwxr-xr-x | contrib/remote-helpers/test-hg-hg-git.sh | 3 | ||||
-rwxr-xr-x | contrib/subtree/git-subtree.sh | 3 |
8 files changed, 577 insertions, 155 deletions
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index edb7428266..91234d47ad 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1237,11 +1237,12 @@ _git_fetch () } __git_format_patch_options=" - --stdout --attach --no-attach --thread --thread= --output-directory + --stdout --attach --no-attach --thread --thread= --no-thread --numbered --start-number --numbered-files --keep-subject --signoff --signature --no-signature --in-reply-to= --cc= --full-index --binary --not --all --cover-letter --no-prefix --src-prefix= --dst-prefix= --inline --suffix= --ignore-if-in-upstream --subject-prefix= + --output-directory --reroll-count --to= --quiet --notes " _git_format_patch () @@ -1733,7 +1734,7 @@ __git_config_get_set_variables () _git_config () { case "$prev" in - branch.*.remote) + branch.*.remote|branch.*.pushremote) __gitcomp_nl "$(__git_remotes)" return ;; @@ -1741,11 +1742,19 @@ _git_config () __gitcomp_nl "$(__git_refs)" return ;; + branch.*.rebase) + __gitcomp "false true" + return + ;; + remote.pushdefault) + __gitcomp_nl "$(__git_remotes)" + return + ;; remote.*.fetch) local remote="${prev#remote.}" remote="${remote%.fetch}" if [ -z "$cur" ]; then - __gitcompadd "refs/heads/" "" "" "" + __gitcomp_nl "refs/heads/" "" "" "" return fi __gitcomp_nl "$(__git_refs_remotes "$remote")" @@ -1780,6 +1789,10 @@ _git_config () " return ;; + diff.submodule) + __gitcomp "log short" + return + ;; help.format) __gitcomp "man info web html" return @@ -1821,7 +1834,7 @@ _git_config () ;; branch.*.*) local pfx="${cur%.*}." cur_="${cur##*.}" - __gitcomp "remote merge mergeoptions rebase" "$pfx" "$cur_" + __gitcomp "remote pushremote merge mergeoptions rebase" "$pfx" "$cur_" return ;; branch.*) @@ -1974,13 +1987,14 @@ _git_config () core.whitespace core.worktree diff.autorefreshindex - diff.statGraphWidth diff.external diff.ignoreSubmodules diff.mnemonicprefix diff.noprefix diff.renameLimit diff.renames + diff.statGraphWidth + diff.submodule diff.suppressBlankEmpty diff.tool diff.wordRegex @@ -2115,6 +2129,7 @@ _git_config () receive.fsckObjects receive.unpackLimit receive.updateserverinfo + remote.pushdefault remotes. repack.usedeltabaseoffset rerere.autoupdate @@ -2359,7 +2374,7 @@ _git_svn () --no-metadata --use-svm-props --use-svnsync-props --log-window-size= --no-checkout --quiet --repack-flags --use-log-author --localtime - --ignore-paths= $remote_opts + --ignore-paths= --include-paths= $remote_opts " local init_opts=" --template= --shared= --trunk= --tags= @@ -2571,7 +2586,7 @@ if [[ -n ${ZSH_VERSION-} ]]; then --*=*|*.) ;; *) c="$c " ;; esac - array[$#array+1]="$c" + array+=("$c") done compset -P '*[=:]' compadd -Q -S '' -p "${2-}" -a -- array && _ret=0 @@ -2597,22 +2612,14 @@ if [[ -n ${ZSH_VERSION-} ]]; then compadd -Q -p "${2-}" -f -- ${=1} && _ret=0 } - __git_zsh_helper () - { - emulate -L ksh - local cur cword prev - cur=${words[CURRENT-1]} - prev=${words[CURRENT-2]} - let cword=CURRENT-1 - __${service}_main - } - _git () { - emulate -L zsh - local _ret=1 - __git_zsh_helper - let _ret && _default -S '' && _ret=0 + local _ret=1 cur cword prev + cur=${words[CURRENT]} + prev=${words[CURRENT-1]} + let cword=CURRENT-1 + emulate ksh -c __${service}_main + let _ret && _default && _ret=0 return _ret } diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh index cf8116d477..fac5e711eb 100644 --- a/contrib/completion/git-completion.zsh +++ b/contrib/completion/git-completion.zsh @@ -2,18 +2,19 @@ # zsh completion wrapper for git # -# You need git's bash completion script installed somewhere, by default on the -# same directory as this script. +# Copyright (c) 2012-2013 Felipe Contreras <felipe.contreras@gmail.com> # -# If your script is on ~/.git-completion.sh instead, you can configure it on -# your ~/.zshrc: +# You need git's bash completion script installed somewhere, by default it +# would be the location bash-completion uses. +# +# If your script is somewhere else, you can configure it on your ~/.zshrc: # # zstyle ':completion:*:*:git:*' script ~/.git-completion.sh # -# The recommended way to install this script is to copy to -# '~/.zsh/completion/_git', and then add the following to your ~/.zshrc file: +# The recommended way to install this script is to copy to '~/.zsh/_git', and +# then add the following to your ~/.zshrc file: # -# fpath=(~/.zsh/completion $fpath) +# fpath=(~/.zsh $fpath) complete () { @@ -21,8 +22,23 @@ complete () return 0 } +zstyle -T ':completion:*:*:git:*' tag-order && \ + zstyle ':completion:*:*:git:*' tag-order 'common-commands' + zstyle -s ":completion:*:*:git:*" script script -test -z "$script" && script="$(dirname ${funcsourcetrace[1]%:*})"/git-completion.bash +if [ -z "$script" ]; then + local -a locations + local e + locations=( + '/etc/bash_completion.d/git' # fedora, old debian + '/usr/share/bash-completion/completions/git' # arch, ubuntu, new debian + '/usr/share/bash-completion/git' # gentoo + $(dirname ${funcsourcetrace[1]%:*})/git-completion.bash + ) + for e in $locations; do + test -f $e && script="$e" && break + done +fi ZSH_VERSION='' . "$script" __gitcomp () @@ -69,18 +85,131 @@ __gitcomp_file () compadd -Q -p "${2-}" -f -- ${=1} && _ret=0 } +__git_zsh_bash_func () +{ + emulate -L ksh + + local command=$1 + + local completion_func="_git_${command//-/_}" + declare -f $completion_func >/dev/null && $completion_func && return + + local expansion=$(__git_aliased_command "$command") + if [ -n "$expansion" ]; then + completion_func="_git_${expansion//-/_}" + declare -f $completion_func >/dev/null && $completion_func + fi +} + +__git_zsh_cmd_common () +{ + local -a list + list=( + add:'add file contents to the index' + bisect:'find by binary search the change that introduced a bug' + branch:'list, create, or delete branches' + checkout:'checkout a branch or paths to the working tree' + clone:'clone a repository into a new directory' + commit:'record changes to the repository' + diff:'show changes between commits, commit and working tree, etc' + fetch:'download objects and refs from another repository' + grep:'print lines matching a pattern' + init:'create an empty Git repository or reinitialize an existing one' + log:'show commit logs' + merge:'join two or more development histories together' + mv:'move or rename a file, a directory, or a symlink' + pull:'fetch from and merge with another repository or a local branch' + push:'update remote refs along with associated objects' + rebase:'forward-port local commits to the updated upstream head' + reset:'reset current HEAD to the specified state' + rm:'remove files from the working tree and from the index' + show:'show various types of objects' + status:'show the working tree status' + tag:'create, list, delete or verify a tag object signed with GPG') + _describe -t common-commands 'common commands' list && _ret=0 +} + +__git_zsh_cmd_alias () +{ + local -a list + list=(${${${(0)"$(git config -z --get-regexp '^alias\.')"}#alias.}%$'\n'*}) + _describe -t alias-commands 'aliases' list $* && _ret=0 +} + +__git_zsh_cmd_all () +{ + local -a list + emulate ksh -c __git_compute_all_commands + list=( ${=__git_all_commands} ) + _describe -t all-commands 'all commands' list && _ret=0 +} + +__git_zsh_main () +{ + local curcontext="$curcontext" state state_descr line + typeset -A opt_args + local -a orig_words + + orig_words=( ${words[@]} ) + + _arguments -C \ + '(-p --paginate --no-pager)'{-p,--paginate}'[pipe all output into ''less'']' \ + '(-p --paginate)--no-pager[do not pipe git output into a pager]' \ + '--git-dir=-[set the path to the repository]: :_directories' \ + '--bare[treat the repository as a bare repository]' \ + '(- :)--version[prints the git suite version]' \ + '--exec-path=-[path to where your core git programs are installed]:: :_directories' \ + '--html-path[print the path where git''s HTML documentation is installed]' \ + '--info-path[print the path where the Info files are installed]' \ + '--man-path[print the manpath (see `man(1)`) for the man pages]' \ + '--work-tree=-[set the path to the working tree]: :_directories' \ + '--namespace=-[set the git namespace]' \ + '--no-replace-objects[do not use replacement refs to replace git objects]' \ + '(- :)--help[prints the synopsis and a list of the most commonly used commands]: :->arg' \ + '(-): :->command' \ + '(-)*:: :->arg' && return + + case $state in + (command) + _alternative \ + 'alias-commands:alias:__git_zsh_cmd_alias' \ + 'common-commands:common:__git_zsh_cmd_common' \ + 'all-commands:all:__git_zsh_cmd_all' && _ret=0 + ;; + (arg) + local command="${words[1]}" __git_dir + + if (( $+opt_args[--bare] )); then + __git_dir='.' + else + __git_dir=${opt_args[--git-dir]} + fi + + (( $+opt_args[--help] )) && command='help' + + words=( ${orig_words[@]} ) + + __git_zsh_bash_func $command + ;; + esac +} + _git () { local _ret=1 - () { - emulate -L ksh - local cur cword prev - cur=${words[CURRENT-1]} - prev=${words[CURRENT-2]} - let cword=CURRENT-1 - __${service}_main - } - let _ret && _default -S '' && _ret=0 + local cur cword prev + + cur=${words[CURRENT]} + prev=${words[CURRENT-1]} + let cword=CURRENT-1 + + if (( $+functions[__${service}_zsh_main] )); then + __${service}_zsh_main + else + emulate ksh -c __${service}_main + fi + + let _ret && _default && _ret=0 return _ret } diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh index 054c52e90a..eaf5c369aa 100644 --- a/contrib/completion/git-prompt.sh +++ b/contrib/completion/git-prompt.sh @@ -263,14 +263,21 @@ __git_ps1 () else local r="" local b="" - if [ -f "$g/rebase-merge/interactive" ]; then - r="|REBASE-i" - b="$(cat "$g/rebase-merge/head-name")" - elif [ -d "$g/rebase-merge" ]; then - r="|REBASE-m" + local step="" + local total="" + if [ -d "$g/rebase-merge" ]; then b="$(cat "$g/rebase-merge/head-name")" + step=$(cat "$g/rebase-merge/msgnum") + total=$(cat "$g/rebase-merge/end") + if [ -f "$g/rebase-merge/interactive" ]; then + r="|REBASE-i" + else + r="|REBASE-m" + fi else if [ -d "$g/rebase-apply" ]; then + step=$(cat "$g/rebase-apply/next") + total=$(cat "$g/rebase-apply/last") if [ -f "$g/rebase-apply/rebasing" ]; then r="|REBASE" elif [ -f "$g/rebase-apply/applying" ]; then @@ -308,6 +315,10 @@ __git_ps1 () } fi + if [ -n "$step" ] && [ -n "$total" ]; then + r="$r $step/$total" + fi + local w="" local i="" local s="" diff --git a/contrib/remote-helpers/git-remote-bzr b/contrib/remote-helpers/git-remote-bzr index c19ed0e26b..10300c63d1 100755 --- a/contrib/remote-helpers/git-remote-bzr +++ b/contrib/remote-helpers/git-remote-bzr @@ -13,6 +13,9 @@ # or # % git clone bzr::lp:myrepo # +# If you want to specify which branches you want track (per repo): +# git config remote-bzr.branches 'trunk, devel, test' +# import sys @@ -27,6 +30,8 @@ import bzrlib.generate_ids import bzrlib.transport import bzrlib.errors import bzrlib.ui +import bzrlib.urlutils +import bzrlib.branch import sys import os @@ -37,6 +42,7 @@ import atexit, shutil, hashlib, urlparse, subprocess NAME_RE = re.compile('^([^<>]+)') AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]*)>$') +EMAIL_RE = re.compile('^([^<>]+[^ \\\t<>])?\\b(?:[ \\t<>]*?)\\b([^ \\t<>]+@[^ \\t<>]+)') RAW_AUTHOR_RE = re.compile('^(\w+) (.+)? <(.*)> (\d+) ([+-]\d+)') def die(msg, *args): @@ -49,6 +55,12 @@ def warn(msg, *args): def gittz(tz): return '%+03d%02d' % (tz / 3600, tz % 3600 / 60) +def get_config(config): + cmd = ['git', 'config', '--get', config] + process = subprocess.Popen(cmd, stdout=subprocess.PIPE) + output, _ = process.communicate() + return output + class Marks: def __init__(self, path): @@ -84,7 +96,7 @@ class Marks: return self.marks[rev] def to_rev(self, mark): - return self.rev_marks[mark] + return str(self.rev_marks[mark]) def next_mark(self): self.last_mark += 1 @@ -174,9 +186,19 @@ def fixup_user(user): name = m.group(1) mail = m.group(2).strip() else: - m = NAME_RE.match(user) + m = EMAIL_RE.match(user) if m: - name = m.group(1).strip() + name = m.group(1) + mail = m.group(2) + else: + m = NAME_RE.match(user) + if m: + name = m.group(1).strip() + + if not name: + name = 'unknown' + if not mail: + mail = 'Unknown' return '%s <%s>' % (name, mail) @@ -250,22 +272,32 @@ def export_files(tree, files): return final -def export_branch(branch, name): +def export_branch(repo, name): global prefix ref = '%s/heads/%s' % (prefix, name) tip = marks.get_tip(name) + branch = bzrlib.branch.Branch.open(branches[name]) repo = branch.repository - repo.lock_read() + + branch.lock_read() revs = branch.iter_merge_sorted_revisions(None, tip, 'exclude', 'forward') - count = 0 + try: + tip_revno = branch.revision_id_to_revno(tip) + last_revno, _ = branch.last_revision_info() + total = last_revno - tip_revno + except bzrlib.errors.NoSuchRevision: + tip_revno = 0 + total = 0 - revs = [revid for revid, _, _, _ in revs if not marks.is_marked(revid)] + for revid, _, seq, _ in revs: - for revid in revs: + if marks.is_marked(revid): + continue rev = repo.get_revision(revid) + revno = seq[0] parents = rev.parent_ids time = rev.timestamp @@ -320,12 +352,18 @@ def export_branch(branch, name): print "M %s :%u %s" % f print - count += 1 - if (count % 100 == 0): - print "progress revision %s (%d/%d)" % (revid, count, len(revs)) - print "#############################################################" + if len(seq) > 1: + # let's skip branch revisions from the progress report + continue + + progress = (revno - tip_revno) + if (progress % 100 == 0): + if total: + print "progress revision %d '%s' (%d/%d)" % (revno, name, progress, total) + else: + print "progress revision %d '%s' (%d)" % (revno, name, progress) - repo.unlock() + branch.unlock() revid = branch.last_revision() @@ -347,23 +385,24 @@ def export_tag(repo, name): def do_import(parser): global dirname - branch = parser.repo + repo = parser.repo path = os.path.join(dirname, 'marks-git') print "feature done" if os.path.exists(path): print "feature import-marks=%s" % path print "feature export-marks=%s" % path + print "feature force" sys.stdout.flush() while parser.check('import'): ref = parser[1] if ref.startswith('refs/heads/'): name = ref[len('refs/heads/'):] - export_branch(branch, name) + export_branch(repo, name) if ref.startswith('refs/tags/'): name = ref[len('refs/tags/'):] - export_tag(branch, name) + export_tag(repo, name) parser.next() print 'done' @@ -382,23 +421,21 @@ def parse_blob(parser): class CustomTree(): - def __init__(self, repo, revid, parents, files): + def __init__(self, branch, revid, parents, files): global files_cache - self.repo = repo - self.revid = revid - self.parents = parents self.updates = {} + self.branch = branch def copy_tree(revid): files = files_cache[revid] = {} - tree = repo.repository.revision_tree(revid) - repo.lock_read() + branch.lock_read() + tree = branch.repository.revision_tree(revid) try: for path, entry in tree.iter_entries_by_dir(): - files[path] = entry.file_id + files[path] = [entry.file_id, None] finally: - repo.unlock() + branch.unlock() return files if len(parents) == 0: @@ -411,12 +448,18 @@ class CustomTree(): self.base_files = copy_tree(self.base_id) self.files = files_cache[revid] = self.base_files.copy() + self.rev_files = {} + + for path, data in self.files.iteritems(): + fid, mark = data + self.rev_files[fid] = [path, mark] for path, f in files.iteritems(): - fid = self.files.get(path, None) + fid, mark = self.files.get(path, [None, None]) if not fid: fid = bzrlib.generate_ids.gen_file_id(path) f['path'] = path + self.rev_files[fid] = [path, mark] self.updates[fid] = f def last_revision(self): @@ -426,16 +469,16 @@ class CustomTree(): changes = [] def get_parent(dirname, basename): - parent_fid = self.base_files.get(dirname, None) + parent_fid, mark = self.base_files.get(dirname, [None, None]) if parent_fid: return parent_fid - parent_fid = self.files.get(dirname, None) + parent_fid, mark = self.files.get(dirname, [None, None]) if parent_fid: return parent_fid if basename == '': return None fid = bzrlib.generate_ids.gen_file_id(path) - d = add_entry(fid, dirname, 'directory') + add_entry(fid, dirname, 'directory') return fid def add_entry(fid, path, kind, mode = None): @@ -456,9 +499,8 @@ class CustomTree(): (None, basename), (None, kind), (None, executable)) - self.files[path] = change[0] + self.files[path] = [change[0], None] changes.append(change) - return change def update_entry(fid, path, kind, mode = None): dirname, basename = os.path.split(path) @@ -478,9 +520,8 @@ class CustomTree(): (None, basename), (None, kind), (None, executable)) - self.files[path] = change[0] + self.files[path] = [change[0], None] changes.append(change) - return change def remove_entry(fid, path, kind): dirname, basename = os.path.split(path) @@ -495,7 +536,6 @@ class CustomTree(): (None, None)) del self.files[path] changes.append(change) - return change for fid, f in self.updates.iteritems(): path = f['path'] @@ -509,13 +549,30 @@ class CustomTree(): else: add_entry(fid, path, 'file', f['mode']) + self.files[path][1] = f['mark'] + self.rev_files[fid][1] = f['mark'] + return changes + def get_content(self, file_id): + path, mark = self.rev_files[file_id] + if mark: + return blob_marks[mark] + + # last resort + tree = self.branch.repository.revision_tree(self.base_id) + return tree.get_file_text(file_id) + def get_file_with_stat(self, file_id, path=None): - return (StringIO.StringIO(self.updates[file_id]['data']), None) + content = self.get_content(file_id) + return (StringIO.StringIO(content), None) def get_symlink_target(self, file_id): - return self.updates[file_id]['data'] + return self.get_content(file_id) + + def id2path(self, file_id): + path, mark = self.rev_files[file_id] + return path def c_style_unescape(string): if string[0] == string[-1] == '"': @@ -531,8 +588,11 @@ def parse_commit(parser): ref = parser[1] parser.next() - if ref != 'refs/heads/master': - die("bzr doesn't support multiple branches; use 'master'") + if ref.startswith('refs/heads/'): + name = ref[len('refs/heads/'):] + branch = bzrlib.branch.Branch.open(branches[name]) + else: + die('unknown ref') commit_mark = parser.get_mark() parser.next() @@ -559,7 +619,7 @@ def parse_commit(parser): if parser.check('M'): t, m, mark_ref, path = line.split(' ', 3) mark = int(mark_ref[1:]) - f = { 'mode' : m, 'data' : blob_marks[mark] } + f = { 'mode' : m, 'mark' : mark } elif parser.check('D'): t, path = line.split(' ') f = { 'deleted' : True } @@ -568,20 +628,18 @@ def parse_commit(parser): path = c_style_unescape(path).decode('utf-8') files[path] = f - repo = parser.repo - committer, date, tz = committer - parents = [str(mark_to_rev(p)) for p in parents] + parents = [mark_to_rev(p) for p in parents] revid = bzrlib.generate_ids.gen_revision_id(committer, date) props = {} - props['branch-nick'] = repo.nick + props['branch-nick'] = branch.nick - mtree = CustomTree(repo, revid, parents, files) + mtree = CustomTree(branch, revid, parents, files) changes = mtree.iter_changes() - repo.lock_write() + branch.lock_write() try: - builder = repo.get_commit_builder(parents, None, date, tz, committer, props, revid) + builder = branch.get_commit_builder(parents, None, date, tz, committer, props, revid) try: list(builder.record_iter_changes(mtree, mtree.last_revision(), changes)) builder.finish_inventory() @@ -590,7 +648,7 @@ def parse_commit(parser): builder.abort() raise finally: - repo.unlock() + branch.unlock() parsed_refs[ref] = revid marks.new_mark(revid, commit_mark) @@ -601,9 +659,6 @@ def parse_reset(parser): ref = parser[1] parser.next() - if ref != 'refs/heads/master': - die("bzr doesn't support multiple branches; use 'master'") - # ugh if parser.check('commit'): parse_commit(parser) @@ -616,7 +671,7 @@ def parse_reset(parser): parsed_refs[ref] = mark_to_rev(from_mark) def do_export(parser): - global parsed_refs, dirname, peer + global parsed_refs, dirname parser.next() @@ -634,20 +689,33 @@ def do_export(parser): else: die('unhandled export command: %s' % line) - repo = parser.repo - for ref, revid in parsed_refs.iteritems(): - if ref == 'refs/heads/master': - repo.generate_revision_history(revid, marks.get_tip('master')) - if peer: + if ref.startswith('refs/heads/'): + name = ref[len('refs/heads/'):] + branch = bzrlib.branch.Branch.open(branches[name]) + branch.generate_revision_history(revid, marks.get_tip(name)) + + if name in peers: + peer = bzrlib.branch.Branch.open(peers[name]) try: - repo.push(peer, stop_revision=revid) + peer.bzrdir.push_branch(branch, revision_id=revid) except bzrlib.errors.DivergedBranches: print "error %s non-fast forward" % ref continue - else: - wt = repo.bzrdir.open_workingtree() + + try: + wt = branch.bzrdir.open_workingtree() wt.update() + except bzrlib.errors.NoWorkingTree: + pass + elif ref.startswith('refs/tags/'): + # TODO: implement tag push + print "error %s pushing tags not supported" % ref + continue + else: + # transport-helper/fast-export bugs + continue + print "ok %s" % ref print @@ -673,9 +741,15 @@ def ref_is_valid(name): def do_list(parser): global tags - print "? refs/heads/%s" % 'master' - branch = parser.repo + master_branch = None + + for name in branches: + if not master_branch: + master_branch = name + print "? refs/heads/%s" % name + + branch = bzrlib.branch.Branch.open(branches[master_branch]) branch.lock_read() for tag, revid in branch.tags.get_tag_dict().items(): try: @@ -687,36 +761,124 @@ def do_list(parser): print "? refs/tags/%s" % tag tags[tag] = revid branch.unlock() - print "@refs/heads/%s HEAD" % 'master' + + print "@refs/heads/%s HEAD" % master_branch print +def get_remote_branch(origin, remote_branch, name): + global dirname, peers + + branch_path = os.path.join(dirname, 'clone', name) + if os.path.exists(branch_path): + # pull + d = bzrlib.bzrdir.BzrDir.open(branch_path) + branch = d.open_branch() + try: + branch.pull(remote_branch, [], None, False) + except bzrlib.errors.DivergedBranches: + # use remote branch for now + return remote_branch + else: + # clone + d = origin.sprout(branch_path, None, + hardlink=True, create_tree_if_local=False, + force_new_repo=False, + source_branch=remote_branch) + branch = d.open_branch() + + return branch + +def find_branches(repo, wanted): + transport = repo.bzrdir.root_transport + + for fn in transport.iter_files_recursive(): + if not fn.endswith('.bzr/branch-format'): + continue + + name = subdir = fn[:-len('/.bzr/branch-format')] + name = name if name != '' else 'master' + name = name.replace('/', '+') + + if wanted and not name in wanted: + continue + + try: + cur = transport.clone(subdir) + branch = bzrlib.branch.Branch.open_from_transport(cur) + except bzrlib.errors.NotBranchError: + continue + else: + yield name, branch + def get_repo(url, alias): - global dirname, peer + global dirname, peer, branches + normal_url = bzrlib.urlutils.normalize_url(url) origin = bzrlib.bzrdir.BzrDir.open(url) - branch = origin.open_branch() + is_local = isinstance(origin.transport, bzrlib.transport.local.LocalTransport) + + shared_path = os.path.join(gitdir, 'bzr') + try: + shared_dir = bzrlib.bzrdir.BzrDir.open(shared_path) + except bzrlib.errors.NotBranchError: + shared_dir = bzrlib.bzrdir.BzrDir.create(shared_path) + try: + shared_repo = shared_dir.open_repository() + except bzrlib.errors.NoRepositoryPresent: + shared_repo = shared_dir.create_repository(shared=True) - if not isinstance(origin.transport, bzrlib.transport.local.LocalTransport): + if not is_local: clone_path = os.path.join(dirname, 'clone') - remote_branch = branch - if os.path.exists(clone_path): - # pull - d = bzrlib.bzrdir.BzrDir.open(clone_path) - branch = d.open_branch() - result = branch.pull(remote_branch, [], None, False) + if not os.path.exists(clone_path): + os.mkdir(clone_path) + else: + # check and remove old organization + try: + bdir = bzrlib.bzrdir.BzrDir.open(clone_path) + bdir.destroy_repository() + except bzrlib.errors.NotBranchError: + pass + except bzrlib.errors.NoRepositoryPresent: + pass + + try: + repo = origin.open_repository() + if not repo.user_transport.listable(): + # this repository is not usable for us + raise bzrlib.errors.NoRepositoryPresent(repo.bzrdir) + except bzrlib.errors.NoRepositoryPresent: + # branch + + name = 'master' + remote_branch = origin.open_branch() + + if not is_local: + peers[name] = remote_branch.base + branch = get_remote_branch(origin, remote_branch, name) else: - # clone - d = origin.sprout(clone_path, None, - hardlink=True, create_tree_if_local=False, - source_branch=remote_branch) - branch = d.open_branch() - branch.bind(remote_branch) - - peer = remote_branch + branch = remote_branch + + branches[name] = branch.base + + return branch.repository else: - peer = None + # repository - return branch + wanted = get_config('remote-bzr.branches').rstrip().split(', ') + # stupid python + wanted = [e for e in wanted if e] + + for name, remote_branch in find_branches(repo, wanted): + + if not is_local: + peers[name] = remote_branch.base + branch = get_remote_branch(origin, remote_branch, name) + else: + branch = remote_branch + + branches[name] = branch.base + + return repo def fix_path(alias, orig_url): url = urlparse.urlparse(orig_url, 'file') @@ -727,12 +889,13 @@ def fix_path(alias, orig_url): subprocess.call(cmd) def main(args): - global marks, prefix, dirname + global marks, prefix, gitdir, dirname global tags, filenodes global blob_marks global parsed_refs global files_cache global is_tmp + global branches, peers alias = args[1] url = args[2] @@ -743,6 +906,8 @@ def main(args): parsed_refs = {} files_cache = {} marks = None + branches = {} + peers = {} if alias[5:] == url: is_tmp = True @@ -760,7 +925,8 @@ def main(args): if not os.path.exists(dirname): os.makedirs(dirname) - bzrlib.ui.ui_factory.be_quiet(True) + if hasattr(bzrlib.ui.ui_factory, 'be_quiet'): + bzrlib.ui.ui_factory.be_quiet(True) repo = get_repo(url, alias) diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg index 06920f28f2..1dd3d7030e 100755 --- a/contrib/remote-helpers/git-remote-hg +++ b/contrib/remote-helpers/git-remote-hg @@ -25,9 +25,6 @@ import atexit import urlparse, hashlib # -# If you want to switch to hg-git compatibility mode: -# git config --global remote-hg.hg-git-compat true -# # If you are not in hg-git-compat mode and want to disable the tracking of # named branches: # git config --global remote-hg.track-branches false @@ -36,7 +33,10 @@ import urlparse, hashlib # git config --global remote-hg.force-push false # # If you want the equivalent of hg's clone/pull--insecure option: -# git config remote-hg.insecure true +# git config --global remote-hg.insecure true +# +# If you want to switch to hg-git compatibility mode: +# git config --global remote-hg.hg-git-compat true # # git: # Sensible defaults for git. @@ -87,6 +87,15 @@ def get_config(config): output, _ = process.communicate() return output +def get_config_bool(config, default=False): + value = get_config(config).rstrip('\n') + if value == "true": + return True + elif value == "false": + return False + else: + return default + class Marks: def __init__(self, path): @@ -327,11 +336,8 @@ def get_repo(url, alias): myui.setconfig('ui', 'interactive', 'off') myui.fout = sys.stderr - try: - if get_config('remote-hg.insecure') == 'true\n': - myui.setconfig('web', 'cacerts', '') - except subprocess.CalledProcessError: - pass + if get_config_bool('remote-hg.insecure'): + myui.setconfig('web', 'cacerts', '') try: mod = extensions.load(myui, 'hgext.schemes', None) @@ -453,7 +459,6 @@ def export_ref(repo, name, kind, head): count += 1 if (count % 100 == 0): print "progress revision %d '%s' (%d/%d)" % (rev, name, count, len(revs)) - print "#############################################################" # make sure the ref is updated print "reset %s/%s" % (prefix, ename) @@ -539,7 +544,7 @@ def list_head(repo, cur): g_head = (head, node) def do_list(parser): - global branches, bmarks, mode, track_branches + global branches, bmarks, track_branches repo = parser.repo for bmark, node in bookmarks.listbookmarks(repo).iteritems(): @@ -851,7 +856,7 @@ def do_export(parser): continue if peer: - parser.repo.push(peer, force=force_push) + parser.repo.push(peer, force=force_push, newbranch=True) # handle bookmarks for bmark, node in p_bmarks: @@ -868,7 +873,8 @@ def do_export(parser): if bmark == 'master' and 'master' not in parser.repo._bookmarks: # fake bookmark - pass + print "ok %s" % ref + continue elif bookmarks.pushbookmark(parser.repo, bmark, old, new): # updated locally pass @@ -907,20 +913,9 @@ def main(args): url = args[2] peer = None - hg_git_compat = False - track_branches = True - force_push = True - - try: - if get_config('remote-hg.hg-git-compat') == 'true\n': - hg_git_compat = True - track_branches = False - if get_config('remote-hg.track-branches') == 'false\n': - track_branches = False - if get_config('remote-hg.force-push') == 'false\n': - force_push = False - except subprocess.CalledProcessError: - pass + hg_git_compat = get_config_bool('remote-hg.hg-git-compat') + track_branches = get_config_bool('remote-hg.track-branches', True) + force_push = get_config_bool('remote-hg.force-push') if hg_git_compat: mode = 'hg' @@ -959,6 +954,10 @@ def main(args): marks_path = os.path.join(dirname, 'marks-hg') marks = Marks(marks_path) + if sys.platform == 'win32': + import msvcrt + msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) + parser = Parser(repo) for line in parser: if parser.check('capabilities'): diff --git a/contrib/remote-helpers/test-bzr.sh b/contrib/remote-helpers/test-bzr.sh index 34666e1d0f..5dfa070b64 100755 --- a/contrib/remote-helpers/test-bzr.sh +++ b/contrib/remote-helpers/test-bzr.sh @@ -228,4 +228,114 @@ test_expect_success 'push utf-8 filenames' ' test_cmp expected actual ' +test_expect_success 'pushing a merge' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + ( + bzr init bzrrepo && + cd bzrrepo && + echo one > content && + bzr add content && + bzr commit -m one + ) && + + git clone "bzr::$PWD/bzrrepo" gitrepo && + + ( + cd bzrrepo && + echo two > content && + bzr commit -m two + ) && + + ( + cd gitrepo && + echo three > content && + git commit -a -m three && + git fetch && + git merge origin/master || true && + echo three > content && + git commit -a --no-edit && + git push + ) && + + echo three > expected && + cat bzrrepo/content > actual && + test_cmp expected actual +' + +cat > expected <<EOF +origin/HEAD +origin/branch +origin/trunk +EOF + +test_expect_success 'proper bzr repo' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + bzr init-repo bzrrepo && + + bzr init bzrrepo/trunk && + ( + cd bzrrepo/trunk && + echo one >> content && + bzr add content && + bzr commit -m one + ) && + + bzr branch bzrrepo/trunk bzrrepo/branch && + ( + cd bzrrepo/branch && + echo two >> content && + bzr commit -m one + ) && + + git clone "bzr::$PWD/bzrrepo" gitrepo && + ( + cd gitrepo && + git for-each-ref --format "%(refname:short)" refs/remotes/origin > ../actual + ) && + + test_cmp ../expected actual +' + +test_expect_success 'strip' ' + # Do not imitate this style; always chdir inside a subshell instead + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + ( + bzr init bzrrepo && + cd bzrrepo && + + echo one >> content && + bzr add content && + bzr commit -m one && + + echo two >> content && + bzr commit -m two + ) && + + git clone "bzr::$PWD/bzrrepo" gitrepo && + + ( + cd bzrrepo && + bzr uncommit --force && + + echo three >> content && + bzr commit -m three && + + echo four >> content && + bzr commit -m four && + bzr log --line | sed -e "s/^[0-9][0-9]*: //" > ../expected + ) && + + (cd gitrepo && + git fetch && + git log --format="%an %ad %s" --date=short origin/master > ../actual) && + + test_cmp expected actual +' + test_done diff --git a/contrib/remote-helpers/test-hg-hg-git.sh b/contrib/remote-helpers/test-hg-hg-git.sh index 84403415f8..7f579c8436 100755 --- a/contrib/remote-helpers/test-hg-hg-git.sh +++ b/contrib/remote-helpers/test-hg-hg-git.sh @@ -102,6 +102,7 @@ setup () { ) >> "$HOME"/.hgrc && git config --global receive.denycurrentbranch warn git config --global remote-hg.hg-git-compat true + git config --global remote-hg.track-branches false HGEDITOR=/usr/bin/true @@ -455,8 +456,6 @@ test_expect_success 'hg author' ' git_log gitrepo-$x > git-log-$x done && - test_cmp git-log-hg git-log-git && - test_cmp hg-log-hg hg-log-git && test_cmp git-log-hg git-log-git ' diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh index 8a23f58ba0..10daa8b0eb 100755 --- a/contrib/subtree/git-subtree.sh +++ b/contrib/subtree/git-subtree.sh @@ -715,7 +715,8 @@ cmd_push() repository=$1 refspec=$2 echo "git push using: " $repository $refspec - git push $repository $(git subtree split --prefix=$prefix):refs/heads/$refspec + localrev=$(git subtree split --prefix="$prefix") || die + git push $repository $localrev:refs/heads/$refspec else die "'$dir' must already exist. Try 'git subtree add'." fi |