diff options
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/completion/git-completion.bash | 78 | ||||
-rwxr-xr-x | contrib/remote-helpers/git-remote-bzr | 9 | ||||
-rwxr-xr-x | contrib/remote-helpers/git-remote-hg | 125 | ||||
-rwxr-xr-x | contrib/remote-helpers/test-hg-bidi.sh | 11 | ||||
-rwxr-xr-x | contrib/remote-helpers/test-hg-hg-git.sh | 8 | ||||
-rwxr-xr-x | contrib/remote-helpers/test-hg.sh | 36 |
6 files changed, 189 insertions, 78 deletions
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 2ba1461422..6df62c2173 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -53,19 +53,6 @@ __gitdir () fi } -__gitcomp_1 () -{ - local c IFS=$' \t\n' - for c in $1; do - c="$c$2" - case $c in - --*=*|*.) ;; - *) c="$c " ;; - esac - printf '%s\n' "$c" - done -} - # The following function is based on code from: # # bash_completion - programmable completion functions for bash 3.2+ @@ -195,8 +182,18 @@ _get_comp_words_by_ref () } fi -# Generates completion reply with compgen, appending a space to possible -# completion words, if necessary. +__gitcompadd () +{ + local i=0 + for x in $1; do + if [[ "$x" == "$3"* ]]; then + COMPREPLY[i++]="$2$x$4" + fi + done +} + +# Generates completion reply, appending a space to possible completion words, +# if necessary. # It accepts 1 to 4 arguments: # 1: List of possible completion words. # 2: A prefix to be added to each possible completion word (optional). @@ -208,19 +205,25 @@ __gitcomp () case "$cur_" in --*=) - COMPREPLY=() ;; *) - local IFS=$'\n' - COMPREPLY=($(compgen -P "${2-}" \ - -W "$(__gitcomp_1 "${1-}" "${4-}")" \ - -- "$cur_")) + local c i=0 IFS=$' \t\n' + for c in $1; do + c="$c${4-}" + if [[ $c == "$cur_"* ]]; then + case $c in + --*=*|*.) ;; + *) c="$c " ;; + esac + COMPREPLY[i++]="${2-}$c" + fi + done ;; esac } -# Generates completion reply with compgen from newline-separated possible -# completion words by appending a space to all of them. +# Generates completion reply from newline-separated possible completion words +# by appending a space to all of them. # It accepts 1 to 4 arguments: # 1: List of possible completion words, separated by a single newline. # 2: A prefix to be added to each possible completion word (optional). @@ -231,7 +234,7 @@ __gitcomp () __gitcomp_nl () { local IFS=$'\n' - COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$1" -- "${3-$cur}")) + __gitcompadd "$1" "${2-}" "${3-$cur}" "${4- }" } # Generates completion reply with compgen from newline-separated possible @@ -614,7 +617,6 @@ __git_complete_remote_or_refspec () case "$cmd" in push) no_complete_refspec=1 ;; fetch) - COMPREPLY=() return ;; *) ;; @@ -630,7 +632,6 @@ __git_complete_remote_or_refspec () return fi if [ $no_complete_refspec = 1 ]; then - COMPREPLY=() return fi [ "$remote" = "." ] && remote= @@ -951,7 +952,6 @@ _git_am () " return esac - COMPREPLY=() } _git_apply () @@ -971,7 +971,6 @@ _git_apply () " return esac - COMPREPLY=() } _git_add () @@ -1031,7 +1030,6 @@ _git_bisect () __gitcomp_nl "$(__git_refs)" ;; *) - COMPREPLY=() ;; esac } @@ -1124,9 +1122,14 @@ _git_cherry () _git_cherry_pick () { + local dir="$(__gitdir)" + if [ -f "$dir"/CHERRY_PICK_HEAD ]; then + __gitcomp "--continue --quit --abort" + return + fi case "$cur" in --*) - __gitcomp "--edit --no-commit" + __gitcomp "--edit --no-commit --signoff --strategy= --mainline" ;; *) __gitcomp_nl "$(__git_refs)" @@ -1170,7 +1173,6 @@ _git_clone () return ;; esac - COMPREPLY=() } _git_commit () @@ -1354,7 +1356,6 @@ _git_fsck () return ;; esac - COMPREPLY=() } _git_gc () @@ -1365,7 +1366,6 @@ _git_gc () return ;; esac - COMPREPLY=() } _git_gitk () @@ -1442,7 +1442,6 @@ _git_init () return ;; esac - COMPREPLY=() } _git_ls_files () @@ -1578,7 +1577,6 @@ _git_mergetool () return ;; esac - COMPREPLY=() } _git_merge_base () @@ -1831,7 +1829,7 @@ _git_config () local remote="${prev#remote.}" remote="${remote%.fetch}" if [ -z "$cur" ]; then - COMPREPLY=("refs/heads/") + __gitcompadd "refs/heads/" "" "" "" return fi __gitcomp_nl "$(__git_refs_remotes "$remote")" @@ -1891,7 +1889,6 @@ _git_config () return ;; *.*) - COMPREPLY=() return ;; esac @@ -2272,7 +2269,6 @@ _git_remote () __gitcomp "$c" ;; *) - COMPREPLY=() ;; esac } @@ -2388,8 +2384,6 @@ _git_stash () *) if [ -z "$(__git_find_on_cmdline "$save_opts")" ]; then __gitcomp "$subcommands" - else - COMPREPLY=() fi ;; esac @@ -2402,14 +2396,12 @@ _git_stash () __gitcomp "--index --quiet" ;; show,--*|drop,--*|branch,--*) - COMPREPLY=() ;; show,*|apply,*|drop,*|pop,*|branch,*) __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \ | sed -n -e 's/:.*//p')" ;; *) - COMPREPLY=() ;; esac fi @@ -2526,7 +2518,6 @@ _git_svn () __gitcomp "--revision= --parent" ;; *) - COMPREPLY=() ;; esac fi @@ -2551,13 +2542,10 @@ _git_tag () case "$prev" in -m|-F) - COMPREPLY=() ;; -*|tag) if [ $f = 1 ]; then __gitcomp_nl "$(__git_tags)" - else - COMPREPLY=() fi ;; *) diff --git a/contrib/remote-helpers/git-remote-bzr b/contrib/remote-helpers/git-remote-bzr index bd25e08202..aa7bc97bee 100755 --- a/contrib/remote-helpers/git-remote-bzr +++ b/contrib/remote-helpers/git-remote-bzr @@ -249,7 +249,7 @@ def export_files(tree, files): return final def export_branch(branch, name): - global prefix, dirname + global prefix ref = '%s/heads/%s' % (prefix, name) tip = marks.get_tip(name) @@ -335,8 +335,10 @@ def export_branch(branch, name): marks.set_tip(name, revid) def export_tag(repo, name): - global tags - print "reset refs/tags/%s" % name + global tags, prefix + + ref = '%s/tags/%s' % (prefix, name) + print "reset %s" % ref print "from :%u" % rev_to_mark(tags[name]) print @@ -649,6 +651,7 @@ def do_capabilities(parser): print "import" print "export" print "refspec refs/heads/*:%s/heads/*" % prefix + print "refspec refs/tags/*:%s/tags/*" % prefix path = os.path.join(dirname, 'marks-git') diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg index 328c2dc76d..548133121d 100755 --- a/contrib/remote-helpers/git-remote-hg +++ b/contrib/remote-helpers/git-remote-hg @@ -8,8 +8,11 @@ # Just copy to your ~/bin, or anywhere in your $PATH. # Then you can clone with: # git clone hg::/path/to/mercurial/repo/ +# +# For remote repositories a local clone is stored in +# "$GIT_DIR/hg/origin/clone/.hg/". -from mercurial import hg, ui, bookmarks, context, util, encoding +from mercurial import hg, ui, bookmarks, context, util, encoding, node, error import re import sys @@ -18,11 +21,22 @@ import json import shutil import subprocess import urllib +import atexit # # 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 +# +# If you don't want to force pushes (and thus risk creating new remote heads): +# 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: # Sensible defaults for git. # hg bookmarks are exported as git branches, hg branches are prefixed @@ -56,6 +70,9 @@ def hgmode(mode): m = { '100755': 'x', '120000': 'l' } return m.get(mode, '') +def hghex(node): + return hg.node.hex(node) + def get_config(config): cmd = ['git', 'config', '--get', config] process = subprocess.Popen(cmd, stdout=subprocess.PIPE) @@ -188,9 +205,15 @@ class Parser: tz = ((tz / 100) * 3600) + ((tz % 100) * 60) return (user, int(date), -tz) +def fix_file_path(path): + if not os.path.isabs(path): + return path + return os.path.relpath(path, '/') + def export_file(fc): d = fc.data() - print "M %s inline %s" % (gitmode(fc.flags()), fc.path()) + path = fix_file_path(fc.path()) + print "M %s inline %s" % (gitmode(fc.flags()), path) print "data %d" % len(d) print d @@ -267,17 +290,30 @@ def get_repo(url, alias): myui = ui.ui() 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 hg.islocal(url): repo = hg.repository(myui, url) else: local_path = os.path.join(dirname, 'clone') if not os.path.exists(local_path): - peer, dstpeer = hg.clone(myui, {}, url, local_path, update=False, pull=True) + try: + peer, dstpeer = hg.clone(myui, {}, url, local_path, update=True, pull=True) + except: + die('Repository error') repo = dstpeer.local() else: repo = hg.repository(myui, local_path) - peer = hg.peer(myui, {}, url) + try: + peer = hg.peer(myui, {}, url) + except: + die('Repository error') repo.pull(peer, heads=None, force=True) return repo @@ -326,6 +362,8 @@ def export_ref(repo, name, kind, head): else: modified, removed = get_filechanges(repo, c, parents[0]) + desc += '\n' + if mode == 'hg': extra_msg = '' @@ -349,7 +387,6 @@ def export_ref(repo, name, kind, head): else: extra_msg += "extra : %s : %s\n" % (key, urllib.quote(value)) - desc += '\n' if extra_msg: desc += '\n--HG--\n' + extra_msg @@ -371,7 +408,7 @@ def export_ref(repo, name, kind, head): for f in modified: export_file(c.filectx(f)) for f in removed: - print "D %s" % (f) + print "D %s" % (fix_file_path(f)) print count += 1 @@ -531,7 +568,6 @@ def parse_blob(parser): data = parser.get_data() blob_marks[mark] = data parser.next() - return def get_merge_files(repo, p1, p2, files): for e in repo[p1].files(): @@ -542,7 +578,7 @@ def get_merge_files(repo, p1, p2, files): files[e] = f def parse_commit(parser): - global marks, blob_marks, bmarks, parsed_refs + global marks, blob_marks, parsed_refs global mode from_mark = merge_mark = None @@ -575,7 +611,7 @@ def parse_commit(parser): mark = int(mark_ref[1:]) f = { 'mode' : hgmode(m), 'data' : blob_marks[mark] } elif parser.check('D'): - t, path = line.split(' ') + t, path = line.split(' ', 1) f = { 'deleted' : True } else: die('Unknown file command: %s' % line) @@ -618,11 +654,15 @@ def parse_commit(parser): if merge_mark: get_merge_files(repo, p1, p2, files) + # Check if the ref is supposed to be a named branch + if ref.startswith('refs/heads/branches/'): + extra['branch'] = ref[len('refs/heads/branches/'):] + if mode == 'hg': i = data.find('\n--HG--\n') if i >= 0: tmp = data[i + len('\n--HG--\n'):].strip() - for k, v in [e.split(' : ') for e in tmp.split('\n')]: + for k, v in [e.split(' : ', 1) for e in tmp.split('\n')]: if k == 'rename': old, new = v.split(' => ', 1) files[new]['rename'] = old @@ -647,10 +687,11 @@ def parse_commit(parser): rev = repo[node].rev() parsed_refs[ref] = node - marks.new_mark(rev, commit_mark) def parse_reset(parser): + global parsed_refs + ref = parser[1] parser.next() # ugh @@ -680,6 +721,8 @@ def parse_tag(parser): def do_export(parser): global parsed_refs, bmarks, peer + p_bmarks = [] + parser.next() for line in parser.each_block('done'): @@ -698,28 +741,55 @@ def do_export(parser): for ref, node in parsed_refs.iteritems(): if ref.startswith('refs/heads/branches'): - pass + print "ok %s" % ref elif ref.startswith('refs/heads/'): bmark = ref[len('refs/heads/'):] - if bmark in bmarks: - old = bmarks[bmark].hex() - else: - old = '' - if not bookmarks.pushbookmark(parser.repo, bmark, old, node): - continue + p_bmarks.append((bmark, node)) + continue elif ref.startswith('refs/tags/'): tag = ref[len('refs/tags/'):] - parser.repo.tag([tag], node, None, True, None, {}) + if mode == 'git': + msg = 'Added tag %s for changeset %s' % (tag, hghex(node[:6])); + parser.repo.tag([tag], node, msg, False, None, {}) + else: + parser.repo.tag([tag], node, None, True, None, {}) + print "ok %s" % ref else: # transport-helper/fast-export bugs continue + + if peer: + parser.repo.push(peer, force=force_push) + + # handle bookmarks + for bmark, node in p_bmarks: + ref = 'refs/heads/' + bmark + new = hghex(node) + + if bmark in bmarks: + old = bmarks[bmark].hex() + else: + old = '' + + if bmark == 'master' and 'master' not in parser.repo._bookmarks: + # fake bookmark + pass + elif bookmarks.pushbookmark(parser.repo, bmark, old, new): + # updated locally + pass + else: + print "error %s" % ref + continue + + if peer: + if not peer.pushkey('bookmarks', bmark, old, new): + print "error %s" % ref + continue + print "ok %s" % ref print - if peer: - parser.repo.push(peer, force=False) - def fix_path(alias, repo, orig_url): repo_url = util.url(repo.url()) url = util.url(orig_url) @@ -732,7 +802,7 @@ def main(args): global prefix, dirname, branches, bmarks global marks, blob_marks, parsed_refs global peer, mode, bad_mail, bad_name - global track_branches + global track_branches, force_push, is_tmp alias = args[1] url = args[2] @@ -740,12 +810,16 @@ def main(args): 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 @@ -770,6 +844,7 @@ def main(args): bmarks = {} blob_marks = {} parsed_refs = {} + marks = None repo = get_repo(url, alias) prefix = 'refs/hg/%s' % alias @@ -797,9 +872,13 @@ def main(args): die('unhandled command: %s' % line) sys.stdout.flush() +def bye(): + if not marks: + return if not is_tmp: marks.store() else: shutil.rmtree(dirname) +atexit.register(bye) sys.exit(main(sys.argv)) diff --git a/contrib/remote-helpers/test-hg-bidi.sh b/contrib/remote-helpers/test-hg-bidi.sh index 1d61982436..f36895311e 100755 --- a/contrib/remote-helpers/test-hg-bidi.sh +++ b/contrib/remote-helpers/test-hg-bidi.sh @@ -22,7 +22,6 @@ fi # clone to a git repo git_clone () { - hg -R $1 bookmark -f -r tip master && git clone -q "hg::$PWD/$1" $2 } @@ -30,6 +29,7 @@ git_clone () { hg_clone () { ( hg init $2 && + hg -R $2 bookmark -i master && cd $1 && git push -q "hg::$PWD/../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' ) && @@ -50,7 +50,8 @@ hg_push () { } hg_log () { - hg -R $1 log --graph --debug | grep -v 'tag: *default/' + hg -R $1 log --graph --debug >log && + grep -v 'tag: *default/' log } setup () { @@ -62,6 +63,8 @@ setup () { echo "commit = -d \"0 0\"" echo "debugrawcommit = -d \"0 0\"" echo "tag = -d \"0 0\"" + echo "[extensions]" + echo "graphlog =" ) >> "$HOME"/.hgrc && git config --global remote-hg.hg-git-compat true @@ -200,8 +203,8 @@ test_expect_success 'hg branch' ' hg_push hgrepo gitrepo && hg_clone gitrepo hgrepo2 && - : TODO, avoid "master" bookmark && - (cd hgrepo2 && hg checkout gamma) && + : Back to the common revision && + (cd hgrepo && hg checkout default) && hg_log hgrepo > expected && hg_log hgrepo2 > actual && diff --git a/contrib/remote-helpers/test-hg-hg-git.sh b/contrib/remote-helpers/test-hg-hg-git.sh index 3f253b7de7..253e65aaa8 100755 --- a/contrib/remote-helpers/test-hg-hg-git.sh +++ b/contrib/remote-helpers/test-hg-hg-git.sh @@ -27,7 +27,6 @@ fi # clone to a git repo with git git_clone_git () { - hg -R $1 bookmark -f -r tip master && git clone -q "hg::$PWD/$1" $2 } @@ -35,6 +34,7 @@ git_clone_git () { hg_clone_git () { ( hg init $2 && + hg -R $2 bookmark -i master && cd $1 && git push -q "hg::$PWD/../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' ) && @@ -47,7 +47,7 @@ git_clone_hg () { ( git init -q $2 && cd $1 && - hg bookmark -f -r tip master && + hg bookmark -i -f -r tip master && hg -q push -r master ../$2 || true ) } @@ -78,7 +78,8 @@ hg_push_hg () { } hg_log () { - hg -R $1 log --graph --debug | grep -v 'tag: *default/' + hg -R $1 log --graph --debug >log && + grep -v 'tag: *default/' log } git_log () { @@ -97,6 +98,7 @@ setup () { echo "[extensions]" echo "hgext.bookmarks =" echo "hggit =" + echo "graphlog =" ) >> "$HOME"/.hgrc && git config --global receive.denycurrentbranch warn git config --global remote-hg.hg-git-compat true diff --git a/contrib/remote-helpers/test-hg.sh b/contrib/remote-helpers/test-hg.sh index 7bb81f2f8e..d5b873051f 100755 --- a/contrib/remote-helpers/test-hg.sh +++ b/contrib/remote-helpers/test-hg.sh @@ -118,4 +118,40 @@ test_expect_success 'update bookmark' ' hg -R hgrepo bookmarks | egrep "devel[ ]+3:" ' +author_test () { + echo $1 >> content && + hg commit -u "$2" -m "add $1" && + echo "$3" >> ../expected +} + +test_expect_success 'authors' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + ( + hg init hgrepo && + cd hgrepo && + + touch content && + hg add content && + + author_test alpha "" "H G Wells <wells@example.com>" && + author_test beta "test" "test <unknown>" && + author_test beta "test <test@example.com> (comment)" "test <unknown>" && + author_test gamma "<test@example.com>" "Unknown <test@example.com>" && + author_test delta "name<test@example.com>" "name <test@example.com>" && + author_test epsilon "name <test@example.com" "name <unknown>" && + author_test zeta " test " "test <unknown>" && + author_test eta "test < test@example.com >" "test <test@example.com>" && + author_test theta "test >test@example.com>" "test <unknown>" && + author_test iota "test < test <at> example <dot> com>" "test <unknown>" && + author_test kappa "test@example.com" "test@example.com <unknown>" + ) && + + git clone "hg::$PWD/hgrepo" gitrepo && + git --git-dir=gitrepo/.git log --reverse --format="%an <%ae>" > actual && + + test_cmp expected actual +' + test_done |