diff options
Diffstat (limited to 'contrib')
40 files changed, 1112 insertions, 1645 deletions
diff --git a/contrib/buildsystems/engine.pl b/contrib/buildsystems/engine.pl index 23da787dc5..23da787dc5 100644..100755 --- a/contrib/buildsystems/engine.pl +++ b/contrib/buildsystems/engine.pl diff --git a/contrib/buildsystems/generate b/contrib/buildsystems/generate index bc10f25ff2..bc10f25ff2 100644..100755 --- a/contrib/buildsystems/generate +++ b/contrib/buildsystems/generate diff --git a/contrib/buildsystems/parse.pl b/contrib/buildsystems/parse.pl index c9656ece99..c9656ece99 100644..100755 --- a/contrib/buildsystems/parse.pl +++ b/contrib/buildsystems/parse.pl diff --git a/contrib/ciabot/INSTALL b/contrib/ciabot/INSTALL deleted file mode 100644 index 7222961d35..0000000000 --- a/contrib/ciabot/INSTALL +++ /dev/null @@ -1,54 +0,0 @@ -= Installation instructions = - -Two scripts are included. The Python one (ciabot.py) is faster and -more capable; the shell one (ciabot.sh) is a fallback in case Python -gives your git hosting site indigestion. (I know of no such sites.) - -It is no longer necessary to modify the script in order to put it -in place; in fact, this is now discouraged. It is entirely -configurable with the following git config variables: - -ciabot.project = name of the project -ciabot.repo = name of the project repo for gitweb/cgit purposes -ciabot.xmlrpc = if true, ship notifications via XML-RPC -ciabot.revformat = format in which the revision is shown - -The revformat variable may have the following values -raw -> full hex ID of commit -short -> first 12 chars of hex ID -describe -> describe relative to last tag, falling back to short - -ciabot.project defaults to the directory name of the repository toplevel. -ciabot.repo defaults to ciabot.project lowercased. -ciabot.xmlrpc defaults to True -ciabot.revformat defaults to 'describe'. - -This means that in the normal case you need not do any configuration at all, -however setting ciabot.project will allow the hook to run slightly faster. - -Once you've set these variables, try your script with -n to see the -notification message dumped to stdout and verify that it looks sane. - -To live-test these scripts, your project needs to have been registered with -the CIA site. Here are the steps: - -1. Open an IRC window on irc://freenode/commits or your registered - project IRC channel. - -2. Run ciabot.py and/or ciabot.sh from any directory under git - control. - -You should see a notification on the channel for your most recent commit. - -After verifying correct function, install one of these scripts either -in a post-commit hook or in an update hook. - -In post-commit, run it without arguments. It will query for -current HEAD and the latest commit ID to get the information it -needs. - -In update, call it with a refname followed by a list of commits: -You want to reverse the order git rev-list emits because it lists -from most recent to oldest. - -/path/to/ciabot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac) diff --git a/contrib/ciabot/README b/contrib/ciabot/README deleted file mode 100644 index 2dfe1f91f5..0000000000 --- a/contrib/ciabot/README +++ /dev/null @@ -1,11 +0,0 @@ -These are hook scripts for the CIA notification service at <http://cia.vc/> - -They are maintained by Eric S. Raymond <esr@thyrsus.com>. There is an -upstream resource page for them at <http://www.catb.org/esr/ciabot/>, -but they are unlikely to change rapidly. - -You probably want the Python version; it's faster, more capable, and -better documented. The shell version is maintained only as a fallback -for use on hosting sites that don't permit Python hook scripts. - -See the file INSTALL for installation instructions. diff --git a/contrib/ciabot/ciabot.py b/contrib/ciabot/ciabot.py deleted file mode 100755 index befa0c3967..0000000000 --- a/contrib/ciabot/ciabot.py +++ /dev/null @@ -1,255 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2010 Eric S. Raymond <esr@thyrsus.com> -# Distributed under BSD terms. -# -# This script contains porcelain and porcelain byproducts. -# It's Python because the Python standard libraries avoid portability/security -# issues raised by callouts in the ancestral Perl and sh scripts. It should -# be compatible back to Python 2.1.5 -# -# usage: ciabot.py [-V] [-n] [-p projectname] [refname [commits...]] -# -# This script is meant to be run either in a post-commit hook or in an -# update hook. Try it with -n to see the notification mail dumped to -# stdout and verify that it looks sane. With -V it dumps its version -# and exits. -# -# In post-commit, run it without arguments. It will query for -# current HEAD and the latest commit ID to get the information it -# needs. -# -# In update, call it with a refname followed by a list of commits: -# You want to reverse the order git rev-list emits because it lists -# from most recent to oldest. -# -# /path/to/ciabot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac) -# -# Configuration variables affecting this script: -# -# ciabot.project = name of the project -# ciabot.repo = name of the project repo for gitweb/cgit purposes -# ciabot.xmlrpc = if true (default), ship notifications via XML-RPC -# ciabot.revformat = format in which the revision is shown -# -# ciabot.project defaults to the directory name of the repository toplevel. -# ciabot.repo defaults to ciabot.project lowercased. -# -# This means that in the normal case you need not do any configuration at all, -# but setting the project name will speed it up slightly. -# -# The revformat variable may have the following values -# raw -> full hex ID of commit -# short -> first 12 chars of hex ID -# describe = -> describe relative to last tag, falling back to short -# The default is 'describe'. -# -# Note: the CIA project now says only XML-RPC is reliable, so -# we default to that. -# - -import sys -if sys.hexversion < 0x02000000: - # The limiter is the xml.sax module - sys.stderr.write("ciabot.py: requires Python 2.0.0 or later.\n") - sys.exit(1) - -import os, commands, socket, urllib -from xml.sax.saxutils import escape - -# Changeset URL prefix for your repo: when the commit ID is appended -# to this, it should point at a CGI that will display the commit -# through gitweb or something similar. The defaults will probably -# work if you have a typical gitweb/cgit setup. -# -#urlprefix="http://%(host)s/cgi-bin/gitweb.cgi?p=%(repo)s;a=commit;h=" -urlprefix="http://%(host)s/cgi-bin/cgit.cgi/%(repo)s/commit/?id=" - -# The service used to turn your gitwebbish URL into a tinyurl so it -# will take up less space on the IRC notification line. -tinyifier = "http://tinyurl.com/api-create.php?url=" - -# The template used to generate the XML messages to CIA. You can make -# visible changes to the IRC-bot notification lines by hacking this. -# The default will produce a notification line that looks like this: -# -# ${project}: ${author} ${repo}:${branch} * ${rev} ${files}: ${logmsg} ${url} -# -# By omitting $files you can collapse the files part to a single slash. -xml = '''\ -<message> - <generator> - <name>CIA Python client for Git</name> - <version>%(version)s</version> - <url>%(generator)s</url> - </generator> - <source> - <project>%(project)s</project> - <branch>%(repo)s:%(branch)s</branch> - </source> - <timestamp>%(ts)s</timestamp> - <body> - <commit> - <author>%(author)s</author> - <revision>%(rev)s</revision> - <files> - %(files)s - </files> - <log>%(logmsg)s %(url)s</log> - <url>%(url)s</url> - </commit> - </body> -</message> -''' - -# -# No user-serviceable parts below this line: -# - -# Where to ship e-mail notifications. -toaddr = "cia@cia.vc" - -# Identify the generator script. -# Should only change when the script itself gets a new home and maintainer. -generator = "http://www.catb.org/~esr/ciabot.py" -version = "3.6" - -def do(command): - return commands.getstatusoutput(command)[1] - -def report(refname, merged, xmlrpc=True): - "Generate a commit notification to be reported to CIA" - - # Try to tinyfy a reference to a web view for this commit. - try: - url = open(urllib.urlretrieve(tinyifier + urlprefix + merged)[0]).read() - except: - url = urlprefix + merged - - branch = os.path.basename(refname) - - # Compute a description for the revision - if revformat == 'raw': - rev = merged - elif revformat == 'short': - rev = '' - else: # revformat == 'describe' - rev = do("git describe %s 2>/dev/null" % merged) - if not rev: - rev = merged[:12] - - # Extract the meta-information for the commit - files=do("git diff-tree -r --name-only '"+ merged +"' | sed -e '1d' -e 's-.*-<file>&</file>-'") - metainfo = do("git log -1 '--pretty=format:%an <%ae>%n%at%n%s' " + merged) - (author, ts, logmsg) = metainfo.split("\n") - logmsg = escape(logmsg) - - # This discards the part of the author's address after @. - # Might be be nice to ship the full email address, if not - # for spammers' address harvesters - getting this wrong - # would make the freenode #commits channel into harvester heaven. - author = escape(author.replace("<", "").split("@")[0].split()[-1]) - - # This ignores the timezone. Not clear what to do with it... - ts = ts.strip().split()[0] - - context = locals() - context.update(globals()) - - out = xml % context - mail = '''\ -Message-ID: <%(merged)s.%(author)s@%(project)s> -From: %(fromaddr)s -To: %(toaddr)s -Content-type: text/xml -Subject: DeliverXML - -%(out)s''' % locals() - - if xmlrpc: - return out - else: - return mail - -if __name__ == "__main__": - import getopt - - # Get all config variables - revformat = do("git config --get ciabot.revformat") - project = do("git config --get ciabot.project") - repo = do("git config --get ciabot.repo") - xmlrpc = do("git config --get ciabot.xmlrpc") - xmlrpc = not (xmlrpc and xmlrpc == "false") - - host = socket.getfqdn() - fromaddr = "CIABOT-NOREPLY@" + host - - try: - (options, arguments) = getopt.getopt(sys.argv[1:], "np:xV") - except getopt.GetoptError, msg: - print "ciabot.py: " + str(msg) - raise SystemExit, 1 - - notify = True - for (switch, val) in options: - if switch == '-p': - project = val - elif switch == '-n': - notify = False - elif switch == '-x': - xmlrpc = True - elif switch == '-V': - print "ciabot.py: version", version - sys.exit(0) - - # The project variable defaults to the name of the repository toplevel. - if not project: - here = os.getcwd() - while True: - if os.path.exists(os.path.join(here, ".git")): - project = os.path.basename(here) - break - elif here == '/': - sys.stderr.write("ciabot.py: no .git below root!\n") - sys.exit(1) - here = os.path.dirname(here) - - if not repo: - repo = project.lower() - - urlprefix = urlprefix % globals() - - # The script wants a reference to head followed by the list of - # commit ID to report about. - if len(arguments) == 0: - refname = do("git symbolic-ref HEAD 2>/dev/null") - merges = [do("git rev-parse HEAD")] - else: - refname = arguments[0] - merges = arguments[1:] - - if notify: - if xmlrpc: - import xmlrpclib - server = xmlrpclib.Server('http://cia.vc/RPC2'); - else: - import smtplib - server = smtplib.SMTP('localhost') - - for merged in merges: - message = report(refname, merged, xmlrpc) - if not notify: - print message - elif xmlrpc: - try: - # RPC server is flaky, this can fail due to timeout. - server.hub.deliver(message) - except socket.error, e: - sys.stderr.write("%s\n" % e) - else: - server.sendmail(fromaddr, [toaddr], message) - - if notify: - if not xmlrpc: - server.quit() - -#End diff --git a/contrib/ciabot/ciabot.sh b/contrib/ciabot/ciabot.sh deleted file mode 100755 index dfb71a1a15..0000000000 --- a/contrib/ciabot/ciabot.sh +++ /dev/null @@ -1,233 +0,0 @@ -#!/bin/sh -# Distributed under the terms of the GNU General Public License v2 -# Copyright (c) 2006 Fernando J. Pereda <ferdy@gentoo.org> -# Copyright (c) 2008 Natanael Copa <natanael.copa@gmail.com> -# Copyright (c) 2010 Eric S. Raymond <esr@thyrsus.com> -# Assistance and review by Petr Baudis, author of ciabot.pl, -# is gratefully acknowledged. -# -# This is a version 3.x of ciabot.sh; use -V to find the exact -# version. Versions 1 and 2 were shipped in 2006 and 2008 and are not -# version-stamped. The version 2 maintainer has passed the baton. -# -# Note: This script should be considered obsolete. -# There is a faster, better-documented rewrite in Python: find it as ciabot.py -# Use this only if your hosting site forbids Python hooks. -# It requires: git(1), hostname(1), cut(1), sendmail(1), and wget(1). -# -# Originally based on Git ciabot.pl by Petr Baudis. -# This script contains porcelain and porcelain byproducts. -# -# usage: ciabot.sh [-V] [-n] [-p projectname] [refname commit] -# -# This script is meant to be run either in a post-commit hook or in an -# update hook. Try it with -n to see the notification mail dumped to -# stdout and verify that it looks sane. With -V it dumps its version -# and exits. -# -# In post-commit, run it without arguments. It will query for -# current HEAD and the latest commit ID to get the information it -# needs. -# -# In update, you have to call it once per merged commit: -# -# refname=$1 -# oldhead=$2 -# newhead=$3 -# for merged in $(git rev-list ${oldhead}..${newhead} | tac) ; do -# /path/to/ciabot.sh ${refname} ${merged} -# done -# -# The reason for the tac call is that git rev-list emits commits from -# most recent to least - better to ship notifications from oldest to newest. -# -# Configuration variables affecting this script: -# -# ciabot.project = name of the project -# ciabot.repo = name of the project repo for gitweb/cgit purposes -# ciabot.revformat = format in which the revision is shown -# -# ciabot.project defaults to the directory name of the repository toplevel. -# ciabot.repo defaults to ciabot.project lowercased. -# -# This means that in the normal case you need not do any configuration at all, -# but setting the project name will speed it up slightly. -# -# The revformat variable may have the following values -# raw -> full hex ID of commit -# short -> first 12 chars of hex ID -# describe = -> describe relative to last tag, falling back to short -# The default is 'describe'. -# -# Note: the shell ancestors of this script used mail, not XML-RPC, in -# order to avoid stalling until timeout when the CIA XML-RPC server is -# down. It is unknown whether this is still an issue in 2010, but -# XML-RPC would be annoying to do from sh in any case. (XML-RPC does -# have the advantage that it guarantees notification of multiple commits -# shipped from an update in their actual order.) -# - -# The project as known to CIA. You can set this with a -p option, -# or let it default to the directory name of the repo toplevel. -project=$(git config --get ciabot.project) - -if [ -z $project ] -then - here=`pwd`; - while :; do - if [ -d $here/.git ] - then - project=`basename $here` - break - elif [ $here = '/' ] - then - echo "ciabot.sh: no .git below root!" - exit 1 - fi - here=`dirname $here` - done -fi - -# Name of the repo for gitweb/cgit purposes -repo=$(git config --get ciabot.repo) -[ -z $repo] && repo=$(echo "${project}" | tr '[A-Z]' '[a-z]') - -# What revision format do we want in the summary? -revformat=$(git config --get ciabot.revformat) - -# Fully qualified domain name of the repo host. You can hardwire this -# to make the script faster. The -f option works under Linux and FreeBSD, -# but not OpenBSD and NetBSD. But under OpenBSD and NetBSD, -# hostname without options gives the FQDN. -if hostname -f >/dev/null 2>&1 -then - hostname=`hostname -f` -else - hostname=`hostname` -fi - -# Changeset URL prefix for your repo: when the commit ID is appended -# to this, it should point at a CGI that will display the commit -# through gitweb or something similar. The defaults will probably -# work if you have a typical gitweb/cgit setup. -#urlprefix="http://${host}/cgi-bin/gitweb.cgi?p=${repo};a=commit;h=" -urlprefix="http://${host}/cgi-bin/cgit.cgi/${repo}/commit/?id=" - -# -# You probably will not need to change the following: -# - -# Identify the script. The 'generator' variable should change only -# when the script itself gets a new home and maintainer. -generator="http://www.catb.org/~esr/ciabot/ciabot.sh" -version=3.5 - -# Addresses for the e-mail -from="CIABOT-NOREPLY@${hostname}" -to="cia@cia.vc" - -# SMTP client to use - may need to edit the absolute pathname for your system -sendmail="sendmail -t -f ${from}" - -# -# No user-serviceable parts below this line: -# - -# Should include all places sendmail is likely to lurk. -PATH="$PATH:/usr/sbin/" - -mode=mailit -while getopts pnV opt -do - case $opt in - p) project=$2; shift ; shift ;; - n) mode=dumpit; shift ;; - V) echo "ciabot.sh: version $version"; exit 0; shift ;; - esac -done - -# Cough and die if user has not specified a project -if [ -z "$project" ] -then - echo "ciabot.sh: no project specified, bailing out." >&2 - exit 1 -fi - -if [ $# -eq 0 ] ; then - refname=$(git symbolic-ref HEAD 2>/dev/null) - merged=$(git rev-parse HEAD) -else - refname=$1 - merged=$2 -fi - -# This tries to turn your gitwebbish URL into a tinyurl so it will take up -# less space on the IRC notification line. Some repo sites (I'm looking at -# you, berlios.de!) forbid wget calls for security reasons. On these, -# the code will fall back to the full un-tinyfied URL. -longurl=${urlprefix}${merged} -url=$(wget -O - -q http://tinyurl.com/api-create.php?url=${longurl} 2>/dev/null) -if [ -z "$url" ]; then - url="${longurl}" -fi - -refname=${refname##refs/heads/} - -case $revformat in -raw) rev=$merged ;; -short) rev='' ;; -*) rev=$(git describe ${merged} 2>/dev/null) ;; -esac -[ -z ${rev} ] && rev=$(echo "$merged" | cut -c 1-12) - -# We discard the part of the author's address after @. -# Might be nice to ship the full email address, if not -# for spammers' address harvesters - getting this wrong -# would make the freenode #commits channel into harvester heaven. -author=$(git log -1 '--pretty=format:%an <%ae>' $merged) -author=$(echo "$author" | sed -n -e '/^.*<\([^@]*\).*$/s--\1-p') - -logmessage=$(git log -1 '--pretty=format:%s' $merged) -ts=$(git log -1 '--pretty=format:%at' $merged) -files=$(git diff-tree -r --name-only ${merged} | sed -e '1d' -e 's-.*-<file>&</file>-') - -out=" -<message> - <generator> - <name>CIA Shell client for Git</name> - <version>${version}</version> - <url>${generator}</url> - </generator> - <source> - <project>${project}</project> - <branch>$repo:${refname}</branch> - </source> - <timestamp>${ts}</timestamp> - <body> - <commit> - <author>${author}</author> - <revision>${rev}</revision> - <files> - ${files} - </files> - <log>${logmessage} ${url}</log> - <url>${url}</url> - </commit> - </body> -</message>" - -if [ "$mode" = "dumpit" ] -then - sendmail=cat -fi - -${sendmail} << EOM -Message-ID: <${merged}.${author}@${project}> -From: ${from} -To: ${to} -Content-type: text/xml -Subject: DeliverXML -${out} -EOM - -# vim: set tw=70 : diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index e1b7313072..87de809d23 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1,5 +1,3 @@ -#!bash -# # bash/zsh completion support for core Git. # # Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org> @@ -180,9 +178,9 @@ _get_comp_words_by_ref () } fi -__gitcompadd () +__gitcompappend () { - local i=0 + local i=${#COMPREPLY[@]} for x in $1; do if [[ "$x" == "$3"* ]]; then COMPREPLY[i++]="$2$x$4" @@ -190,6 +188,12 @@ __gitcompadd () done } +__gitcompadd () +{ + COMPREPLY=() + __gitcompappend "$@" +} + # Generates completion reply, appending a space to possible completion words, # if necessary. # It accepts 1 to 4 arguments: @@ -220,6 +224,14 @@ __gitcomp () esac } +# Variation of __gitcomp_nl () that appends to the existing list of +# completion candidates, COMPREPLY. +__gitcomp_nl_append () +{ + local IFS=$'\n' + __gitcompappend "$1" "${2-}" "${3-$cur}" "${4- }" +} + # Generates completion reply from newline-separated possible completion words # by appending a space to all of them. # It accepts 1 to 4 arguments: @@ -231,8 +243,8 @@ __gitcomp () # appended. __gitcomp_nl () { - local IFS=$'\n' - __gitcompadd "$1" "${2-}" "${3-$cur}" "${4- }" + COMPREPLY=() + __gitcomp_nl_append "$@" } # Generates completion reply with compgen from newline-separated possible @@ -673,7 +685,6 @@ __git_list_porcelain_commands () index-pack) : plumbing;; init-db) : deprecated;; local-fetch) : plumbing;; - lost-found) : infrequent;; ls-files) : plumbing;; ls-remote) : plumbing;; ls-tree) : plumbing;; @@ -687,14 +698,12 @@ __git_list_porcelain_commands () pack-refs) : plumbing;; parse-remote) : plumbing;; patch-id) : plumbing;; - peek-remote) : plumbing;; prune) : plumbing;; prune-packed) : plumbing;; quiltimport) : import;; read-tree) : plumbing;; receive-pack) : plumbing;; remote-*) : transport;; - repo-config) : deprecated;; rerere) : plumbing;; rev-list) : plumbing;; rev-parse) : plumbing;; @@ -707,7 +716,6 @@ __git_list_porcelain_commands () ssh-*) : transport;; stripspace) : plumbing;; symbolic-ref) : plumbing;; - tar-tree) : deprecated;; unpack-file) : plumbing;; unpack-objects) : plumbing;; update-index) : plumbing;; @@ -901,7 +909,7 @@ _git_add () esac # XXX should we check for --update and --all options ? - __git_complete_index_file "--others --modified" + __git_complete_index_file "--others --modified --directory --no-empty-directory" } _git_archive () @@ -1063,7 +1071,7 @@ _git_clean () esac # XXX should we check for -x option ? - __git_complete_index_file "--others" + __git_complete_index_file "--others --directory" } _git_clone () @@ -1188,7 +1196,7 @@ _git_diff () __git_complete_revlist_file } -__git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff +__git_mergetools_common="diffuse diffmerge ecmerge emerge kdiff3 meld opendiff tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 codecompare " @@ -1213,14 +1221,20 @@ _git_difftool () __git_complete_revlist_file } +__git_fetch_recurse_submodules="yes on-demand no" + __git_fetch_options=" --quiet --verbose --append --upload-pack --force --keep --depth= - --tags --no-tags --all --prune --dry-run + --tags --no-tags --all --prune --dry-run --recurse-submodules= " _git_fetch () { case "$cur" in + --recurse-submodules=*) + __gitcomp "$__git_fetch_recurse_submodules" "" "${cur##--recurse-submodules=}" + return + ;; --*) __gitcomp "$__git_fetch_options" return @@ -1491,6 +1505,12 @@ _git_mergetool () _git_merge_base () { + case "$cur" in + --*) + __gitcomp "--octopus --independent --is-ancestor --fork-point" + return + ;; + esac __gitcomp_nl "$(__git_refs)" } @@ -1569,6 +1589,10 @@ _git_pull () __git_complete_strategy && return case "$cur" in + --recurse-submodules=*) + __gitcomp "$__git_fetch_recurse_submodules" "" "${cur##--recurse-submodules=}" + return + ;; --*) __gitcomp " --rebase --no-rebase @@ -1581,6 +1605,8 @@ _git_pull () __git_complete_remote_or_refspec } +__git_push_recurse_submodules="check on-demand" + _git_push () { case "$prev" in @@ -1593,10 +1619,15 @@ _git_push () __gitcomp_nl "$(__git_remotes)" "" "${cur##--repo=}" return ;; + --recurse-submodules=*) + __gitcomp "$__git_push_recurse_submodules" "" "${cur##--recurse-submodules=}" + return + ;; --*) __gitcomp " --all --mirror --tags --dry-run --force --verbose --receive-pack= --repo= --set-upstream + --recurse-submodules= " return ;; @@ -1623,7 +1654,7 @@ _git_rebase () --preserve-merges --stat --no-stat --committer-date-is-author-date --ignore-date --ignore-whitespace --whitespace= - --autosquash + --autosquash --fork-point --no-fork-point " return @@ -1833,6 +1864,7 @@ _git_config () branch.*) local pfx="${cur%.*}." cur_="${cur#*.}" __gitcomp_nl "$(__git_heads)" "$pfx" "$cur_" "." + __gitcomp_nl_append $'autosetupmerge\nautosetuprebase\n' "$pfx" "$cur_" return ;; guitool.*.*) @@ -1875,6 +1907,7 @@ _git_config () remote.*) local pfx="${cur%.*}." cur_="${cur#*.}" __gitcomp_nl "$(__git_remotes)" "$pfx" "$cur_" "." + __gitcomp_nl_append "pushdefault" "$pfx" "$cur_" return ;; url.*.*) @@ -1997,6 +2030,7 @@ _git_config () fetch.unpackLimit format.attach format.cc + format.coverLetter format.headers format.numbered format.pretty diff --git a/contrib/completion/git-completion.tcsh b/contrib/completion/git-completion.tcsh index eaacaf0c3e..6104a42a23 100644 --- a/contrib/completion/git-completion.tcsh +++ b/contrib/completion/git-completion.tcsh @@ -1,5 +1,3 @@ -#!tcsh -# # tcsh completion support for core Git. # # Copyright (C) 2012 Marc Khouzam <marc.khouzam@gmail.com> diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh index fac5e711eb..6b77968572 100644 --- a/contrib/completion/git-completion.zsh +++ b/contrib/completion/git-completion.zsh @@ -30,10 +30,10 @@ if [ -z "$script" ]; then local -a locations local e locations=( + $(dirname ${funcsourcetrace[1]%:*})/git-completion.bash '/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 @@ -76,6 +76,14 @@ __gitcomp_nl () compadd -Q -S "${4- }" -p "${2-}" -- ${=1} && _ret=0 } +__gitcomp_nl_append () +{ + emulate -L zsh + + local IFS=$'\n' + compadd -Q -S "${4- }" -p "${2-}" -- ${=1} && _ret=0 +} + __gitcomp_file () { emulate -L zsh diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh index 998722cf7f..7b732d2aeb 100644 --- a/contrib/completion/git-prompt.sh +++ b/contrib/completion/git-prompt.sh @@ -60,6 +60,7 @@ # of values: # # verbose show number of commits ahead/behind (+/-) upstream +# name if verbose, then also show the upstream abbrev name # legacy don't use the '--count' option available in recent # versions of git-rev-list # git always compare HEAD to @{upstream} @@ -94,7 +95,7 @@ __git_ps1_show_upstream () { local key value local svn_remote svn_url_pattern count n - local upstream=git legacy="" verbose="" + local upstream=git legacy="" verbose="" name="" svn_remote=() # get some config options from git-config @@ -122,6 +123,7 @@ __git_ps1_show_upstream () git|svn) upstream="$option" ;; verbose) verbose=1 ;; legacy) legacy=1 ;; + name) name=1 ;; esac done @@ -204,6 +206,9 @@ __git_ps1_show_upstream () *) # diverged from upstream p=" u+${count#* }-${count% *}" ;; esac + if [[ -n "$count" && -n "$name" ]]; then + p="$p $(git rev-parse --abbrev-ref "$upstream" 2>/dev/null)" + fi fi } diff --git a/contrib/contacts/git-contacts b/contrib/contacts/git-contacts index d80f7d1b6e..dbe2abf277 100755 --- a/contrib/contacts/git-contacts +++ b/contrib/contacts/git-contacts @@ -59,11 +59,11 @@ sub import_commits { } sub get_blame { - my ($commits, $source, $start, $len, $from) = @_; - $len = 1 unless defined($len); - return if $len == 0; + my ($commits, $source, $from, $ranges) = @_; + return unless @$ranges; open my $f, '-|', - qw(git blame --porcelain -C), '-L', "$start,+$len", + qw(git blame --porcelain -C), + map({"-L$_->[0],+$_->[1]"} @$ranges), '--since', $since, "$from^", '--', $source or die; while (<$f>) { if (/^([0-9a-f]{40}) \d+ \d+ \d+$/) { @@ -76,8 +76,17 @@ sub get_blame { close $f; } +sub blame_sources { + my ($sources, $commits) = @_; + for my $s (keys %$sources) { + for my $id (keys %{$sources->{$s}}) { + get_blame($commits, $s, $id, $sources->{$s}{$id}); + } + } +} + sub scan_patches { - my ($commits, $id, $f) = @_; + my ($sources, $id, $f) = @_; my $source; while (<$f>) { if (/^From ([0-9a-f]{40}) Mon Sep 17 00:00:00 2001$/) { @@ -87,10 +96,9 @@ sub scan_patches { next unless $id; if (m{^--- (?:a/(.+)|/dev/null)$}) { $source = $1; - } elsif (/^--- /) { - die "Cannot parse hunk source: $_\n"; } elsif (/^@@ -(\d+)(?:,(\d+))?/ && $source) { - get_blame($commits, $source, $1, $2, $id); + my $len = defined($2) ? $2 : 1; + push @{$sources->{$source}{$id}}, [$1, $len] if $len; } } } @@ -163,13 +171,20 @@ for (@ARGV) { } } -my %commits; +my %sources; for (@files) { - scan_patch_file(\%commits, $_); + scan_patch_file(\%sources, $_); } if (@rev_args) { - scan_rev_args(\%commits, \@rev_args) + scan_rev_args(\%sources, \@rev_args) } + +my $toplevel = `git rev-parse --show-toplevel`; +chomp $toplevel; +chdir($toplevel) or die "chdir failure: $toplevel: $!\n"; + +my %commits; +blame_sources(\%sources, \%commits); import_commits(\%commits); my $contacts = {}; diff --git a/contrib/credential/gnome-keyring/Makefile b/contrib/credential/gnome-keyring/Makefile index e6561d8db6..c3c7c98aa1 100644 --- a/contrib/credential/gnome-keyring/Makefile +++ b/contrib/credential/gnome-keyring/Makefile @@ -8,8 +8,8 @@ CFLAGS = -g -O2 -Wall -include ../../../config.mak.autogen -include ../../../config.mak -INCS:=$(shell pkg-config --cflags gnome-keyring-1) -LIBS:=$(shell pkg-config --libs gnome-keyring-1) +INCS:=$(shell pkg-config --cflags gnome-keyring-1 glib-2.0) +LIBS:=$(shell pkg-config --libs gnome-keyring-1 glib-2.0) SRCS:=$(MAIN).c OBJS:=$(SRCS:.c=.o) diff --git a/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c b/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c index f2cdefee60..2a317fca44 100644 --- a/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c +++ b/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c @@ -25,135 +25,148 @@ #include <stdio.h> #include <string.h> -#include <stdarg.h> #include <stdlib.h> -#include <errno.h> +#include <glib.h> #include <gnome-keyring.h> -/* - * This credential struct and API is simplified from git's credential.{h,c} - */ -struct credential -{ - char *protocol; - char *host; - unsigned short port; - char *path; - char *username; - char *password; -}; +#ifdef GNOME_KEYRING_DEFAULT -#define CREDENTIAL_INIT \ - { NULL,NULL,0,NULL,NULL,NULL } + /* Modern gnome-keyring */ -void credential_init(struct credential *c); -void credential_clear(struct credential *c); -int credential_read(struct credential *c); -void credential_write(const struct credential *c); +#include <gnome-keyring-memory.h> -typedef int (*credential_op_cb)(struct credential*); +#else -struct credential_operation -{ - char *name; - credential_op_cb op; -}; + /* + * Support ancient gnome-keyring, circ. RHEL 5.X. + * GNOME_KEYRING_DEFAULT seems to have been introduced with Gnome 2.22, + * and the other features roughly around Gnome 2.20, 6 months before. + * Ubuntu 8.04 used Gnome 2.22 (I think). Not sure any distro used 2.20. + * So the existence/non-existence of GNOME_KEYRING_DEFAULT seems like + * a decent thing to use as an indicator. + */ -#define CREDENTIAL_OP_END \ - { NULL,NULL } +#define GNOME_KEYRING_DEFAULT NULL /* - * Table with operation callbacks is defined in concrete - * credential helper implementation and contains entries - * like { "get", function_to_get_credential } terminated - * by CREDENTIAL_OP_END. + * ancient gnome-keyring returns DENIED when an entry is not found. + * Setting NO_MATCH to DENIED will prevent us from reporting DENIED + * errors during get and erase operations, but we will still report + * DENIED errors during a store. */ -struct credential_operation const credential_helper_ops[]; +#define GNOME_KEYRING_RESULT_NO_MATCH GNOME_KEYRING_RESULT_DENIED -/* ---------------- common helper functions ----------------- */ +#define gnome_keyring_memory_alloc g_malloc +#define gnome_keyring_memory_free gnome_keyring_free_password +#define gnome_keyring_memory_strdup g_strdup -static inline void free_password(char *password) +static const char *gnome_keyring_result_to_message(GnomeKeyringResult result) { - char *c = password; - if (!password) - return; - - while (*c) *c++ = '\0'; - free(password); + switch (result) { + case GNOME_KEYRING_RESULT_OK: + return "OK"; + case GNOME_KEYRING_RESULT_DENIED: + return "Denied"; + case GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON: + return "No Keyring Daemon"; + case GNOME_KEYRING_RESULT_ALREADY_UNLOCKED: + return "Already UnLocked"; + case GNOME_KEYRING_RESULT_NO_SUCH_KEYRING: + return "No Such Keyring"; + case GNOME_KEYRING_RESULT_BAD_ARGUMENTS: + return "Bad Arguments"; + case GNOME_KEYRING_RESULT_IO_ERROR: + return "IO Error"; + case GNOME_KEYRING_RESULT_CANCELLED: + return "Cancelled"; + case GNOME_KEYRING_RESULT_ALREADY_EXISTS: + return "Already Exists"; + default: + return "Unknown Error"; + } } -static inline void warning(const char *fmt, ...) +/* + * Support really ancient gnome-keyring, circ. RHEL 4.X. + * Just a guess for the Glib version. Glib 2.8 was roughly Gnome 2.12 ? + * Which was released with gnome-keyring 0.4.3 ?? + */ +#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 8 + +static void gnome_keyring_done_cb(GnomeKeyringResult result, gpointer user_data) { - va_list ap; + gpointer *data = (gpointer *)user_data; + int *done = (int *)data[0]; + GnomeKeyringResult *r = (GnomeKeyringResult *)data[1]; - va_start(ap, fmt); - fprintf(stderr, "warning: "); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n" ); - va_end(ap); + *r = result; + *done = 1; } -static inline void error(const char *fmt, ...) +static void wait_for_request_completion(int *done) { - va_list ap; - - va_start(ap, fmt); - fprintf(stderr, "error: "); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n" ); - va_end(ap); + GMainContext *mc = g_main_context_default(); + while (!*done) + g_main_context_iteration(mc, TRUE); } -static inline void die(const char *fmt, ...) +static GnomeKeyringResult gnome_keyring_item_delete_sync(const char *keyring, guint32 id) { - va_list ap; + int done = 0; + GnomeKeyringResult result; + gpointer data[] = { &done, &result }; - va_start(ap,fmt); - error(fmt, ap); - va_end(ap); - exit(EXIT_FAILURE); -} + gnome_keyring_item_delete(keyring, id, gnome_keyring_done_cb, data, + NULL); -static inline void die_errno(int err) -{ - error("%s", strerror(err)); - exit(EXIT_FAILURE); + wait_for_request_completion(&done); + + return result; } -static inline char *xstrdup(const char *str) -{ - char *ret = strdup(str); - if (!ret) - die_errno(errno); +#endif +#endif - return ret; -} +/* + * This credential struct and API is simplified from git's credential.{h,c} + */ +struct credential { + char *protocol; + char *host; + unsigned short port; + char *path; + char *username; + char *password; +}; + +#define CREDENTIAL_INIT { NULL, NULL, 0, NULL, NULL, NULL } + +typedef int (*credential_op_cb)(struct credential *); + +struct credential_operation { + char *name; + credential_op_cb op; +}; + +#define CREDENTIAL_OP_END { NULL, NULL } /* ----------------- GNOME Keyring functions ----------------- */ /* create a special keyring option string, if path is given */ -static char* keyring_object(struct credential *c) +static char *keyring_object(struct credential *c) { - char* object = NULL; - if (!c->path) - return object; + return NULL; - object = (char*) malloc(strlen(c->host)+strlen(c->path)+8); - if(!object) - die_errno(errno); + if (c->port) + return g_strdup_printf("%s:%hd/%s", c->host, c->port, c->path); - if(c->port) - sprintf(object,"%s:%hd/%s",c->host,c->port,c->path); - else - sprintf(object,"%s/%s",c->host,c->path); - - return object; + return g_strdup_printf("%s/%s", c->host, c->path); } -int keyring_get(struct credential *c) +static int keyring_get(struct credential *c) { - char* object = NULL; + char *object = NULL; GList *entries; GnomeKeyringNetworkPasswordData *password_data; GnomeKeyringResult result; @@ -173,7 +186,7 @@ int keyring_get(struct credential *c) c->port, &entries); - free(object); + g_free(object); if (result == GNOME_KEYRING_RESULT_NO_MATCH) return EXIT_SUCCESS; @@ -182,18 +195,18 @@ int keyring_get(struct credential *c) return EXIT_SUCCESS; if (result != GNOME_KEYRING_RESULT_OK) { - error("%s",gnome_keyring_result_to_message(result)); + g_critical("%s", gnome_keyring_result_to_message(result)); return EXIT_FAILURE; } /* pick the first one from the list */ - password_data = (GnomeKeyringNetworkPasswordData *) entries->data; + password_data = (GnomeKeyringNetworkPasswordData *)entries->data; - free_password(c->password); - c->password = xstrdup(password_data->password); + gnome_keyring_memory_free(c->password); + c->password = gnome_keyring_memory_strdup(password_data->password); if (!c->username) - c->username = xstrdup(password_data->user); + c->username = g_strdup(password_data->user); gnome_keyring_network_password_list_free(entries); @@ -201,10 +214,11 @@ int keyring_get(struct credential *c) } -int keyring_store(struct credential *c) +static int keyring_store(struct credential *c) { guint32 item_id; - char *object = NULL; + char *object = NULL; + GnomeKeyringResult result; /* * Sanity check that what we are storing is actually sensible. @@ -219,7 +233,7 @@ int keyring_store(struct credential *c) object = keyring_object(c); - gnome_keyring_set_network_password_sync( + result = gnome_keyring_set_network_password_sync( GNOME_KEYRING_DEFAULT, c->username, NULL /* domain */, @@ -231,13 +245,20 @@ int keyring_store(struct credential *c) c->password, &item_id); - free(object); + g_free(object); + + if (result != GNOME_KEYRING_RESULT_OK && + result != GNOME_KEYRING_RESULT_CANCELLED) { + g_critical("%s", gnome_keyring_result_to_message(result)); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; } -int keyring_erase(struct credential *c) +static int keyring_erase(struct credential *c) { - char *object = NULL; + char *object = NULL; GList *entries; GnomeKeyringNetworkPasswordData *password_data; GnomeKeyringResult result; @@ -265,7 +286,7 @@ int keyring_erase(struct credential *c) c->port, &entries); - free(object); + g_free(object); if (result == GNOME_KEYRING_RESULT_NO_MATCH) return EXIT_SUCCESS; @@ -273,23 +294,21 @@ int keyring_erase(struct credential *c) if (result == GNOME_KEYRING_RESULT_CANCELLED) return EXIT_SUCCESS; - if (result != GNOME_KEYRING_RESULT_OK) - { - error("%s",gnome_keyring_result_to_message(result)); + if (result != GNOME_KEYRING_RESULT_OK) { + g_critical("%s", gnome_keyring_result_to_message(result)); return EXIT_FAILURE; } /* pick the first one from the list (delete all matches?) */ - password_data = (GnomeKeyringNetworkPasswordData *) entries->data; + password_data = (GnomeKeyringNetworkPasswordData *)entries->data; result = gnome_keyring_item_delete_sync( password_data->keyring, password_data->item_id); gnome_keyring_network_password_list_free(entries); - if (result != GNOME_KEYRING_RESULT_OK) - { - error("%s",gnome_keyring_result_to_message(result)); + if (result != GNOME_KEYRING_RESULT_OK) { + g_critical("%s", gnome_keyring_result_to_message(result)); return EXIT_FAILURE; } @@ -300,9 +319,8 @@ int keyring_erase(struct credential *c) * Table with helper operation callbacks, used by generic * credential helper main function. */ -struct credential_operation const credential_helper_ops[] = -{ - { "get", keyring_get }, +static struct credential_operation const credential_helper_ops[] = { + { "get", keyring_get }, { "store", keyring_store }, { "erase", keyring_erase }, CREDENTIAL_OP_END @@ -310,67 +328,70 @@ struct credential_operation const credential_helper_ops[] = /* ------------------ credential functions ------------------ */ -void credential_init(struct credential *c) +static void credential_init(struct credential *c) { memset(c, 0, sizeof(*c)); } -void credential_clear(struct credential *c) +static void credential_clear(struct credential *c) { - free(c->protocol); - free(c->host); - free(c->path); - free(c->username); - free_password(c->password); + g_free(c->protocol); + g_free(c->host); + g_free(c->path); + g_free(c->username); + gnome_keyring_memory_free(c->password); credential_init(c); } -int credential_read(struct credential *c) +static int credential_read(struct credential *c) { - char buf[1024]; - ssize_t line_len = 0; - char *key = buf; - char *value; + char *buf; + size_t line_len; + char *key; + char *value; - while (fgets(buf, sizeof(buf), stdin)) - { + key = buf = gnome_keyring_memory_alloc(1024); + + while (fgets(buf, 1024, stdin)) { line_len = strlen(buf); - if(buf[line_len-1]=='\n') - buf[--line_len]='\0'; + if (line_len && buf[line_len-1] == '\n') + buf[--line_len] = '\0'; - if(!line_len) + if (!line_len) break; - value = strchr(buf,'='); - if(!value) { - warning("invalid credential line: %s", key); + value = strchr(buf, '='); + if (!value) { + g_warning("invalid credential line: %s", key); + gnome_keyring_memory_free(buf); return -1; } *value++ = '\0'; if (!strcmp(key, "protocol")) { - free(c->protocol); - c->protocol = xstrdup(value); + g_free(c->protocol); + c->protocol = g_strdup(value); } else if (!strcmp(key, "host")) { - free(c->host); - c->host = xstrdup(value); - value = strrchr(c->host,':'); + g_free(c->host); + c->host = g_strdup(value); + value = strrchr(c->host, ':'); if (value) { *value++ = '\0'; c->port = atoi(value); } } else if (!strcmp(key, "path")) { - free(c->path); - c->path = xstrdup(value); + g_free(c->path); + c->path = g_strdup(value); } else if (!strcmp(key, "username")) { - free(c->username); - c->username = xstrdup(value); + g_free(c->username); + c->username = g_strdup(value); } else if (!strcmp(key, "password")) { - free_password(c->password); - c->password = xstrdup(value); - while (*value) *value++ = '\0'; + gnome_keyring_memory_free(c->password); + c->password = gnome_keyring_memory_strdup(value); + while (*value) + *value++ = '\0'; } /* * Ignore other lines; we don't know what they mean, but @@ -378,17 +399,20 @@ int credential_read(struct credential *c) * learn new lines, and the helpers are updated to match. */ } + + gnome_keyring_memory_free(buf); + return 0; } -void credential_write_item(FILE *fp, const char *key, const char *value) +static void credential_write_item(FILE *fp, const char *key, const char *value) { if (!value) return; fprintf(fp, "%s=%s\n", key, value); } -void credential_write(const struct credential *c) +static void credential_write(const struct credential *c) { /* only write username/password, if set */ credential_write_item(stdout, "username", c->username); @@ -398,16 +422,16 @@ void credential_write(const struct credential *c) static void usage(const char *name) { struct credential_operation const *try_op = credential_helper_ops; - const char *basename = strrchr(name,'/'); + const char *basename = strrchr(name, '/'); basename = (basename) ? basename + 1 : name; fprintf(stderr, "usage: %s <", basename); - while(try_op->name) { - fprintf(stderr,"%s",(try_op++)->name); - if(try_op->name) - fprintf(stderr,"%s","|"); + while (try_op->name) { + fprintf(stderr, "%s", (try_op++)->name); + if (try_op->name) + fprintf(stderr, "%s", "|"); } - fprintf(stderr,"%s",">\n"); + fprintf(stderr, "%s", ">\n"); } int main(int argc, char *argv[]) @@ -415,23 +439,25 @@ int main(int argc, char *argv[]) int ret = EXIT_SUCCESS; struct credential_operation const *try_op = credential_helper_ops; - struct credential cred = CREDENTIAL_INIT; + struct credential cred = CREDENTIAL_INIT; if (!argv[1]) { usage(argv[0]); - goto out; + exit(EXIT_FAILURE); } + g_set_application_name("Git Credential Helper"); + /* lookup operation callback */ - while(try_op->name && strcmp(argv[1], try_op->name)) + while (try_op->name && strcmp(argv[1], try_op->name)) try_op++; /* unsupported operation given -- ignore silently */ - if(!try_op->name || !try_op->op) + if (!try_op->name || !try_op->op) goto out; ret = credential_read(&cred); - if(ret) + if (ret) goto out; /* perform credential operation */ diff --git a/contrib/credential/netrc/git-credential-netrc b/contrib/credential/netrc/git-credential-netrc index 6c51c43885..1571a7b269 100755 --- a/contrib/credential/netrc/git-credential-netrc +++ b/contrib/credential/netrc/git-credential-netrc @@ -369,7 +369,9 @@ sub find_netrc_entry { { my $entry_text = join ', ', map { "$_=$entry->{$_}" } keys %$entry; foreach my $check (sort keys %$query) { - if (defined $query->{$check}) { + if (!defined $entry->{$check}) { + log_debug("OK: entry has no $check token, so any value satisfies check $check"); + } elsif (defined $query->{$check}) { log_debug("compare %s [%s] to [%s] (entry: %s)", $check, $entry->{$check}, diff --git a/contrib/examples/git-log.sh b/contrib/examples/git-log.sh new file mode 100755 index 0000000000..c2ea71cf14 --- /dev/null +++ b/contrib/examples/git-log.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# +# Copyright (c) 2005 Linus Torvalds +# + +USAGE='[--max-count=<n>] [<since>..<limit>] [--pretty=<format>] [git-rev-list options]' +SUBDIRECTORY_OK='Yes' +. git-sh-setup + +revs=$(git-rev-parse --revs-only --no-flags --default HEAD "$@") || exit +[ "$revs" ] || { + die "No HEAD ref" +} +git-rev-list --pretty $(git-rev-parse --default HEAD "$@") | +LESS=-S ${PAGER:-less} diff --git a/contrib/examples/git-merge.sh b/contrib/examples/git-merge.sh index 7b922c3948..a5e42a9f01 100755 --- a/contrib/examples/git-merge.sh +++ b/contrib/examples/git-merge.sh @@ -263,7 +263,7 @@ fi # This could be traditional "merge <msg> HEAD <commit>..." and the # way we can tell it is to see if the second token is HEAD, but some -# people might have misused the interface and used a committish that +# people might have misused the interface and used a commit-ish that # is the same as HEAD there instead. Traditional format never would # have "-m" so it is an additional safety measure to check for it. diff --git a/contrib/examples/git-repack.sh b/contrib/examples/git-repack.sh new file mode 100755 index 0000000000..757933174e --- /dev/null +++ b/contrib/examples/git-repack.sh @@ -0,0 +1,194 @@ +#!/bin/sh +# +# Copyright (c) 2005 Linus Torvalds +# + +OPTIONS_KEEPDASHDASH= +OPTIONS_SPEC="\ +git repack [options] +-- +a pack everything in a single pack +A same as -a, and turn unreachable objects loose +d remove redundant packs, and run git-prune-packed +f pass --no-reuse-delta to git-pack-objects +F pass --no-reuse-object to git-pack-objects +n do not run git-update-server-info +q,quiet be quiet +l pass --local to git-pack-objects +unpack-unreachable= with -A, do not loosen objects older than this + Packing constraints +window= size of the window used for delta compression +window-memory= same as the above, but limit memory size instead of entries count +depth= limits the maximum delta depth +max-pack-size= maximum size of each packfile +" +SUBDIRECTORY_OK='Yes' +. git-sh-setup + +no_update_info= all_into_one= remove_redundant= unpack_unreachable= +local= no_reuse= extra= +while test $# != 0 +do + case "$1" in + -n) no_update_info=t ;; + -a) all_into_one=t ;; + -A) all_into_one=t + unpack_unreachable=--unpack-unreachable ;; + --unpack-unreachable) + unpack_unreachable="--unpack-unreachable=$2"; shift ;; + -d) remove_redundant=t ;; + -q) GIT_QUIET=t ;; + -f) no_reuse=--no-reuse-delta ;; + -F) no_reuse=--no-reuse-object ;; + -l) local=--local ;; + --max-pack-size|--window|--window-memory|--depth) + extra="$extra $1=$2"; shift ;; + --) shift; break;; + *) usage ;; + esac + shift +done + +case "`git config --bool repack.usedeltabaseoffset || echo true`" in +true) + extra="$extra --delta-base-offset" ;; +esac + +PACKDIR="$GIT_OBJECT_DIRECTORY/pack" +PACKTMP="$PACKDIR/.tmp-$$-pack" +rm -f "$PACKTMP"-* +trap 'rm -f "$PACKTMP"-*' 0 1 2 3 15 + +# There will be more repacking strategies to come... +case ",$all_into_one," in +,,) + args='--unpacked --incremental' + ;; +,t,) + args= existing= + if [ -d "$PACKDIR" ]; then + for e in `cd "$PACKDIR" && find . -type f -name '*.pack' \ + | sed -e 's/^\.\///' -e 's/\.pack$//'` + do + if [ -e "$PACKDIR/$e.keep" ]; then + : keep + else + existing="$existing $e" + fi + done + if test -n "$existing" -a -n "$unpack_unreachable" -a \ + -n "$remove_redundant" + then + # This may have arbitrary user arguments, so we + # have to protect it against whitespace splitting + # when it gets run as "pack-objects $args" later. + # Fortunately, we know it's an approxidate, so we + # can just use dots instead. + args="$args $(echo "$unpack_unreachable" | tr ' ' .)" + fi + fi + ;; +esac + +mkdir -p "$PACKDIR" || exit + +args="$args $local ${GIT_QUIET:+-q} $no_reuse$extra" +names=$(git pack-objects --keep-true-parents --honor-pack-keep --non-empty --all --reflog $args </dev/null "$PACKTMP") || + exit 1 +if [ -z "$names" ]; then + say Nothing new to pack. +fi + +# Ok we have prepared all new packfiles. + +# First see if there are packs of the same name and if so +# if we can move them out of the way (this can happen if we +# repacked immediately after packing fully. +rollback= +failed= +for name in $names +do + for sfx in pack idx + do + file=pack-$name.$sfx + test -f "$PACKDIR/$file" || continue + rm -f "$PACKDIR/old-$file" && + mv "$PACKDIR/$file" "$PACKDIR/old-$file" || { + failed=t + break + } + rollback="$rollback $file" + done + test -z "$failed" || break +done + +# If renaming failed for any of them, roll the ones we have +# already renamed back to their original names. +if test -n "$failed" +then + rollback_failure= + for file in $rollback + do + mv "$PACKDIR/old-$file" "$PACKDIR/$file" || + rollback_failure="$rollback_failure $file" + done + if test -n "$rollback_failure" + then + echo >&2 "WARNING: Some packs in use have been renamed by" + echo >&2 "WARNING: prefixing old- to their name, in order to" + echo >&2 "WARNING: replace them with the new version of the" + echo >&2 "WARNING: file. But the operation failed, and" + echo >&2 "WARNING: attempt to rename them back to their" + echo >&2 "WARNING: original names also failed." + echo >&2 "WARNING: Please rename them in $PACKDIR manually:" + for file in $rollback_failure + do + echo >&2 "WARNING: old-$file -> $file" + done + fi + exit 1 +fi + +# Now the ones with the same name are out of the way... +fullbases= +for name in $names +do + fullbases="$fullbases pack-$name" + chmod a-w "$PACKTMP-$name.pack" + chmod a-w "$PACKTMP-$name.idx" + mv -f "$PACKTMP-$name.pack" "$PACKDIR/pack-$name.pack" && + mv -f "$PACKTMP-$name.idx" "$PACKDIR/pack-$name.idx" || + exit +done + +# Remove the "old-" files +for name in $names +do + rm -f "$PACKDIR/old-pack-$name.idx" + rm -f "$PACKDIR/old-pack-$name.pack" +done + +# End of pack replacement. + +if test "$remove_redundant" = t +then + # We know $existing are all redundant. + if [ -n "$existing" ] + then + ( cd "$PACKDIR" && + for e in $existing + do + case " $fullbases " in + *" $e "*) ;; + *) rm -f "$e.pack" "$e.idx" "$e.keep" ;; + esac + done + ) + fi + git prune-packed ${GIT_QUIET:+-q} +fi + +case "$no_update_info" in +t) : ;; +*) git update-server-info ;; +esac diff --git a/contrib/examples/git-whatchanged.sh b/contrib/examples/git-whatchanged.sh new file mode 100755 index 0000000000..2edbdc6d99 --- /dev/null +++ b/contrib/examples/git-whatchanged.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +USAGE='[-p] [--max-count=<n>] [<since>..<limit>] [--pretty=<format>] [-m] [git-diff-tree options] [git-rev-list options]' +SUBDIRECTORY_OK='Yes' +. git-sh-setup + +diff_tree_flags=$(git-rev-parse --sq --no-revs --flags "$@") || exit +case "$0" in +*whatchanged) + count= + test -z "$diff_tree_flags" && + diff_tree_flags=$(git config --get whatchanged.difftree) + diff_tree_default_flags='-c -M --abbrev' ;; +*show) + count=-n1 + test -z "$diff_tree_flags" && + diff_tree_flags=$(git config --get show.difftree) + diff_tree_default_flags='--cc --always' ;; +esac +test -z "$diff_tree_flags" && + diff_tree_flags="$diff_tree_default_flags" + +rev_list_args=$(git-rev-parse --sq --default HEAD --revs-only "$@") && +diff_tree_args=$(git-rev-parse --sq --no-revs --no-flags "$@") && + +eval "git-rev-list $count $rev_list_args" | +eval "git-diff-tree --stdin --pretty -r $diff_tree_flags $diff_tree_args" | +LESS="$LESS -S" ${PAGER:-less} diff --git a/contrib/git-resurrect.sh b/contrib/git-resurrect.sh index a4ed4c3c62..d7e97bbc76 100755 --- a/contrib/git-resurrect.sh +++ b/contrib/git-resurrect.sh @@ -10,6 +10,7 @@ is rather slow but allows you to resurrect other people's topic branches." OPTIONS_KEEPDASHDASH= +OPTIONS_STUCKLONG= OPTIONS_SPEC="\ git resurrect $USAGE -- diff --git a/contrib/gitview/gitview b/contrib/gitview/gitview index 4c99dfb903..4e23c650fe 100755 --- a/contrib/gitview/gitview +++ b/contrib/gitview/gitview @@ -1205,7 +1205,7 @@ class GitView(object): #The first parent always continue on the same line try: - # check we alreay have the value + # check we already have the value tmp_node_pos = self.nodepos[commit.parent_sha1[0]] except KeyError: self.colours[commit.parent_sha1[0]] = colour diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email index 153115029d..8747b84334 100755 --- a/contrib/hooks/post-receive-email +++ b/contrib/hooks/post-receive-email @@ -22,7 +22,6 @@ # For example, on debian the hook is stored in # /usr/share/git-core/contrib/hooks/post-receive-email: # -# chmod a+x post-receive-email # cd /path/to/your/repository.git # ln -sf /usr/share/git-core/contrib/hooks/post-receive-email hooks/post-receive # @@ -242,6 +241,9 @@ generate_email_header() cat <<-EOF To: $recipients Subject: ${emailprefix}$projectdesc $refname_type $short_refname ${change_type}d. $describe + MIME-Version: 1.0 + Content-Type: text/plain; charset=utf-8 + Content-Transfer-Encoding: 8bit X-Git-Refname: $refname X-Git-Reftype: $refname_type X-Git-Oldrev: $oldrev @@ -471,7 +473,7 @@ generate_delete_branch_email() echo " was $oldrev" echo "" echo $LOGBEGIN - git show -s --pretty=oneline $oldrev + git diff-tree -s --always --encoding=UTF-8 --pretty=oneline $oldrev echo $LOGEND } @@ -547,11 +549,11 @@ generate_atag_email() # performed on them if [ -n "$prevtag" ]; then # Show changes since the previous release - git rev-list --pretty=short "$prevtag..$newrev" | git shortlog + git shortlog "$prevtag..$newrev" else # No previous tag, show all the changes since time # began - git rev-list --pretty=short $newrev | git shortlog + git shortlog $newrev fi ;; *) @@ -571,7 +573,7 @@ generate_delete_atag_email() echo " was $oldrev" echo "" echo $LOGBEGIN - git show -s --pretty=oneline $oldrev + git diff-tree -s --always --encoding=UTF-8 --pretty=oneline $oldrev echo $LOGEND } @@ -617,7 +619,7 @@ generate_general_email() echo "" if [ "$newrev_type" = "commit" ]; then echo $LOGBEGIN - git show --no-color --root -s --pretty=medium $newrev + git diff-tree -s --always --encoding=UTF-8 --pretty=medium $newrev echo $LOGEND else # What can we do here? The tag marks an object that is not @@ -636,7 +638,7 @@ generate_delete_general_email() echo " was $oldrev" echo "" echo $LOGBEGIN - git show -s --pretty=oneline $oldrev + git diff-tree -s --always --encoding=UTF-8 --pretty=oneline $oldrev echo $LOGEND } diff --git a/contrib/hooks/pre-auto-gc-battery b/contrib/hooks/pre-auto-gc-battery index 1f914c94aa..9d0c2d1990 100644..100755 --- a/contrib/hooks/pre-auto-gc-battery +++ b/contrib/hooks/pre-auto-gc-battery @@ -13,7 +13,6 @@ # For example, if the hook is stored in # /usr/share/git-core/contrib/hooks/pre-auto-gc-battery: # -# chmod a+x pre-auto-gc-battery # cd /path/to/your/repository.git # ln -sf /usr/share/git-core/contrib/hooks/pre-auto-gc-battery \ # hooks/pre-auto-gc diff --git a/contrib/hooks/setgitperms.perl b/contrib/hooks/setgitperms.perl index 2770a1b1d2..2770a1b1d2 100644..100755 --- a/contrib/hooks/setgitperms.perl +++ b/contrib/hooks/setgitperms.perl diff --git a/contrib/hooks/update-paranoid b/contrib/hooks/update-paranoid index d18b317b2f..d18b317b2f 100644..100755 --- a/contrib/hooks/update-paranoid +++ b/contrib/hooks/update-paranoid diff --git a/contrib/mw-to-git/Makefile b/contrib/mw-to-git/Makefile index 76fcd4defc..a4b6f7a2cd 100644 --- a/contrib/mw-to-git/Makefile +++ b/contrib/mw-to-git/Makefile @@ -18,14 +18,25 @@ SCRIPT_PERL+=git-mw.perl GIT_ROOT_DIR=../.. HERE=contrib/mw-to-git/ +INSTALL = install + SCRIPT_PERL_FULL=$(patsubst %,$(HERE)/%,$(SCRIPT_PERL)) INSTLIBDIR=$(shell $(MAKE) -C $(GIT_ROOT_DIR)/perl \ -s --no-print-directory instlibdir) +DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) +INSTLIBDIR_SQ = $(subst ','\'',$(INSTLIBDIR)) all: build +test: all + $(MAKE) -C t + +check: perlcritic test + install_pm: - install $(GIT_MEDIAWIKI_PM) $(INSTLIBDIR)/$(GIT_MEDIAWIKI_PM) + $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(INSTLIBDIR_SQ)/Git' + $(INSTALL) -m 644 $(GIT_MEDIAWIKI_PM) \ + '$(DESTDIR_SQ)$(INSTLIBDIR_SQ)/$(GIT_MEDIAWIKI_PM)' build: $(MAKE) -C $(GIT_ROOT_DIR) SCRIPT_PERL="$(SCRIPT_PERL_FULL)" \ @@ -38,7 +49,9 @@ install: install_pm clean: $(MAKE) -C $(GIT_ROOT_DIR) SCRIPT_PERL="$(SCRIPT_PERL_FULL)" \ clean-perl-script - rm $(INSTLIBDIR)/$(GIT_MEDIAWIKI_PM) perlcritic: - perlcritic -2 *.perl + perlcritic -5 $(SCRIPT_PERL) + -perlcritic -2 $(SCRIPT_PERL) + +.PHONY: all test check install_pm install clean perlcritic diff --git a/contrib/mw-to-git/git-remote-mediawiki.perl b/contrib/mw-to-git/git-remote-mediawiki.perl index 85d0c42296..3f8d993afa 100755 --- a/contrib/mw-to-git/git-remote-mediawiki.perl +++ b/contrib/mw-to-git/git-remote-mediawiki.perl @@ -590,6 +590,9 @@ sub mw_capabilities { print {*STDOUT} "import\n"; print {*STDOUT} "list\n"; print {*STDOUT} "push\n"; + if ($dumb_push) { + print {*STDOUT} "no-private-update\n"; + } print {*STDOUT} "\n"; return; } @@ -1221,7 +1224,6 @@ sub mw_push_revision { } if (!$dumb_push) { run_git(qq(notes --ref=${remotename}/mediawiki add -f -m "mediawiki_revision: ${mw_revision}" ${sha1_commit})); - run_git(qq(update-ref -m "Git-MediaWiki push" refs/mediawiki/${remotename}/master ${sha1_commit} ${sha1_child})); } } @@ -1313,7 +1315,7 @@ sub get_mw_namespace_id { # Store "notANameSpace" as special value for inexisting namespaces my $store_id = ($id || 'notANameSpace'); - # Store explicitely requested namespaces on disk + # Store explicitly requested namespaces on disk if (!exists $cached_mw_namespace_id{$name}) { run_git(qq(config --add remote.${remotename}.namespaceCache "${name}:${store_id}")); $cached_mw_namespace_id{$name} = 1; diff --git a/contrib/mw-to-git/t/test-gitmw-lib.sh b/contrib/mw-to-git/t/test-gitmw-lib.sh index ca6860ff30..3372b2af34 100755 --- a/contrib/mw-to-git/t/test-gitmw-lib.sh +++ b/contrib/mw-to-git/t/test-gitmw-lib.sh @@ -91,7 +91,7 @@ test_diff_directories () { # Check that <dir> contains exactly <N> files test_contains_N_files () { if test `ls -- "$1" | wc -l` -ne "$2"; then - echo "directory $1 sould contain $2 files" + echo "directory $1 should contain $2 files" echo "it contains these files:" ls "$1" false diff --git a/contrib/mw-to-git/t/test.config b/contrib/mw-to-git/t/test.config index 4cfebe9c69..5ba0684162 100644 --- a/contrib/mw-to-git/t/test.config +++ b/contrib/mw-to-git/t/test.config @@ -12,7 +12,7 @@ SERVER_ADDR=localhost TMP=/tmp DB_FILE=wikidb.sqlite -# If LIGHTTPD is not set to true, the script will use the defaut +# If LIGHTTPD is not set to true, the script will use the default # web server running in WIKI_DIR_INST. WIKI_DIR_INST=/var/www diff --git a/contrib/p4import/README b/contrib/p4import/README deleted file mode 100644 index b9892b6793..0000000000 --- a/contrib/p4import/README +++ /dev/null @@ -1 +0,0 @@ -Please see contrib/fast-import/git-p4 for a better Perforce importer. diff --git a/contrib/p4import/git-p4import.py b/contrib/p4import/git-p4import.py deleted file mode 100644 index 593d6a0682..0000000000 --- a/contrib/p4import/git-p4import.py +++ /dev/null @@ -1,365 +0,0 @@ -#!/usr/bin/env python -# -# This tool is copyright (c) 2006, Sean Estabrooks. -# It is released under the Gnu Public License, version 2. -# -# Import Perforce branches into Git repositories. -# Checking out the files is done by calling the standard p4 -# client which you must have properly configured yourself -# - -import marshal -import os -import sys -import time -import getopt - -if sys.hexversion < 0x02020000: - # The behavior of the marshal module changed significantly in 2.2 - sys.stderr.write("git-p4import.py: requires Python 2.2 or later.\n") - sys.exit(1) - -from signal import signal, \ - SIGPIPE, SIGINT, SIG_DFL, \ - default_int_handler - -signal(SIGPIPE, SIG_DFL) -s = signal(SIGINT, SIG_DFL) -if s != default_int_handler: - signal(SIGINT, s) - -def die(msg, *args): - for a in args: - msg = "%s %s" % (msg, a) - print "git-p4import fatal error:", msg - sys.exit(1) - -def usage(): - print "USAGE: git-p4import [-q|-v] [--authors=<file>] [-t <timezone>] [//p4repo/path <branch>]" - sys.exit(1) - -verbosity = 1 -logfile = "/dev/null" -ignore_warnings = False -stitch = 0 -tagall = True - -def report(level, msg, *args): - global verbosity - global logfile - for a in args: - msg = "%s %s" % (msg, a) - fd = open(logfile, "a") - fd.writelines(msg) - fd.close() - if level <= verbosity: - print msg - -class p4_command: - def __init__(self, _repopath): - try: - global logfile - self.userlist = {} - if _repopath[-1] == '/': - self.repopath = _repopath[:-1] - else: - self.repopath = _repopath - if self.repopath[-4:] != "/...": - self.repopath= "%s/..." % self.repopath - f=os.popen('p4 -V 2>>%s'%logfile, 'rb') - a = f.readlines() - if f.close(): - raise - except: - die("Could not find the \"p4\" command") - - def p4(self, cmd, *args): - global logfile - cmd = "%s %s" % (cmd, ' '.join(args)) - report(2, "P4:", cmd) - f=os.popen('p4 -G %s 2>>%s' % (cmd,logfile), 'rb') - list = [] - while 1: - try: - list.append(marshal.load(f)) - except EOFError: - break - self.ret = f.close() - return list - - def sync(self, id, force=False, trick=False, test=False): - if force: - ret = self.p4("sync -f %s@%s"%(self.repopath, id))[0] - elif trick: - ret = self.p4("sync -k %s@%s"%(self.repopath, id))[0] - elif test: - ret = self.p4("sync -n %s@%s"%(self.repopath, id))[0] - else: - ret = self.p4("sync %s@%s"%(self.repopath, id))[0] - if ret['code'] == "error": - data = ret['data'].upper() - if data.find('VIEW') > 0: - die("Perforce reports %s is not in client view"% self.repopath) - elif data.find('UP-TO-DATE') < 0: - die("Could not sync files from perforce", self.repopath) - - def changes(self, since=0): - try: - list = [] - for rec in self.p4("changes %s@%s,#head" % (self.repopath, since+1)): - list.append(rec['change']) - list.reverse() - return list - except: - return [] - - def authors(self, filename): - f=open(filename) - for l in f.readlines(): - self.userlist[l[:l.find('=')].rstrip()] = \ - (l[l.find('=')+1:l.find('<')].rstrip(),l[l.find('<')+1:l.find('>')]) - f.close() - for f,e in self.userlist.items(): - report(2, f, ":", e[0], " <", e[1], ">") - - def _get_user(self, id): - if not self.userlist.has_key(id): - try: - user = self.p4("users", id)[0] - self.userlist[id] = (user['FullName'], user['Email']) - except: - self.userlist[id] = (id, "") - return self.userlist[id] - - def _format_date(self, ticks): - symbol='+' - name = time.tzname[0] - offset = time.timezone - if ticks[8]: - name = time.tzname[1] - offset = time.altzone - if offset < 0: - offset *= -1 - symbol = '-' - localo = "%s%02d%02d %s" % (symbol, offset / 3600, offset % 3600, name) - tickso = time.strftime("%a %b %d %H:%M:%S %Y", ticks) - return "%s %s" % (tickso, localo) - - def where(self): - try: - return self.p4("where %s" % self.repopath)[-1]['path'] - except: - return "" - - def describe(self, num): - desc = self.p4("describe -s", num)[0] - self.msg = desc['desc'] - self.author, self.email = self._get_user(desc['user']) - self.date = self._format_date(time.localtime(long(desc['time']))) - return self - -class git_command: - def __init__(self): - try: - self.version = self.git("--version")[0][12:].rstrip() - except: - die("Could not find the \"git\" command") - try: - self.gitdir = self.get_single("rev-parse --git-dir") - report(2, "gdir:", self.gitdir) - except: - die("Not a git repository... did you forget to \"git init\" ?") - try: - self.cdup = self.get_single("rev-parse --show-cdup") - if self.cdup != "": - os.chdir(self.cdup) - self.topdir = os.getcwd() - report(2, "topdir:", self.topdir) - except: - die("Could not find top git directory") - - def git(self, cmd): - global logfile - report(2, "GIT:", cmd) - f=os.popen('git %s 2>>%s' % (cmd,logfile), 'rb') - r=f.readlines() - self.ret = f.close() - return r - - def get_single(self, cmd): - return self.git(cmd)[0].rstrip() - - def current_branch(self): - try: - testit = self.git("rev-parse --verify HEAD")[0] - return self.git("symbolic-ref HEAD")[0][11:].rstrip() - except: - return None - - def get_config(self, variable): - try: - return self.git("config --get %s" % variable)[0].rstrip() - except: - return None - - def set_config(self, variable, value): - try: - self.git("config %s %s"%(variable, value) ) - except: - die("Could not set %s to " % variable, value) - - def make_tag(self, name, head): - self.git("tag -f %s %s"%(name,head)) - - def top_change(self, branch): - try: - a=self.get_single("name-rev --tags refs/heads/%s" % branch) - loc = a.find(' tags/') + 6 - if a[loc:loc+3] != "p4/": - raise - return int(a[loc+3:][:-2]) - except: - return 0 - - def update_index(self): - self.git("ls-files -m -d -o -z | git update-index --add --remove -z --stdin") - - def checkout(self, branch): - self.git("checkout %s" % branch) - - def repoint_head(self, branch): - self.git("symbolic-ref HEAD refs/heads/%s" % branch) - - def remove_files(self): - self.git("ls-files | xargs rm") - - def clean_directories(self): - self.git("clean -d") - - def fresh_branch(self, branch): - report(1, "Creating new branch", branch) - self.git("ls-files | xargs rm") - os.remove(".git/index") - self.repoint_head(branch) - self.git("clean -d") - - def basedir(self): - return self.topdir - - def commit(self, author, email, date, msg, id): - self.update_index() - fd=open(".msg", "w") - fd.writelines(msg) - fd.close() - try: - current = self.get_single("rev-parse --verify HEAD") - head = "-p HEAD" - except: - current = "" - head = "" - tree = self.get_single("write-tree") - for r,l in [('DATE',date),('NAME',author),('EMAIL',email)]: - os.environ['GIT_AUTHOR_%s'%r] = l - os.environ['GIT_COMMITTER_%s'%r] = l - commit = self.get_single("commit-tree %s %s < .msg" % (tree,head)) - os.remove(".msg") - self.make_tag("p4/%s"%id, commit) - self.git("update-ref HEAD %s %s" % (commit, current) ) - -try: - opts, args = getopt.getopt(sys.argv[1:], "qhvt:", - ["authors=","help","stitch=","timezone=","log=","ignore","notags"]) -except getopt.GetoptError: - usage() - -for o, a in opts: - if o == "-q": - verbosity = 0 - if o == "-v": - verbosity += 1 - if o in ("--log"): - logfile = a - if o in ("--notags"): - tagall = False - if o in ("-h", "--help"): - usage() - if o in ("--ignore"): - ignore_warnings = True - -git = git_command() -branch=git.current_branch() - -for o, a in opts: - if o in ("-t", "--timezone"): - git.set_config("perforce.timezone", a) - if o in ("--stitch"): - git.set_config("perforce.%s.path" % branch, a) - stitch = 1 - -if len(args) == 2: - branch = args[1] - git.checkout(branch) - if branch == git.current_branch(): - die("Branch %s already exists!" % branch) - report(1, "Setting perforce to ", args[0]) - git.set_config("perforce.%s.path" % branch, args[0]) -elif len(args) != 0: - die("You must specify the perforce //depot/path and git branch") - -p4path = git.get_config("perforce.%s.path" % branch) -if p4path == None: - die("Do not know Perforce //depot/path for git branch", branch) - -p4 = p4_command(p4path) - -for o, a in opts: - if o in ("-a", "--authors"): - p4.authors(a) - -localdir = git.basedir() -if p4.where()[:len(localdir)] != localdir: - report(1, "**WARNING** Appears p4 client is misconfigured") - report(1, " for sync from %s to %s" % (p4.repopath, localdir)) - if ignore_warnings != True: - die("Reconfigure or use \"--ignore\" on command line") - -if stitch == 0: - top = git.top_change(branch) -else: - top = 0 -changes = p4.changes(top) -count = len(changes) -if count == 0: - report(1, "Already up to date...") - sys.exit(0) - -ptz = git.get_config("perforce.timezone") -if ptz: - report(1, "Setting timezone to", ptz) - os.environ['TZ'] = ptz - time.tzset() - -if stitch == 1: - git.remove_files() - git.clean_directories() - p4.sync(changes[0], force=True) -elif top == 0 and branch != git.current_branch(): - p4.sync(changes[0], test=True) - report(1, "Creating new initial commit"); - git.fresh_branch(branch) - p4.sync(changes[0], force=True) -else: - p4.sync(changes[0], trick=True) - -report(1, "processing %s changes from p4 (%s) to git (%s)" % (count, p4.repopath, branch)) -for id in changes: - report(1, "Importing changeset", id) - change = p4.describe(id) - p4.sync(id) - if tagall : - git.commit(change.author, change.email, change.date, change.msg, id) - else: - git.commit(change.author, change.email, change.date, change.msg, "import") - if stitch == 1: - git.clean_directories() - stitch = 0 diff --git a/contrib/p4import/git-p4import.txt b/contrib/p4import/git-p4import.txt deleted file mode 100644 index 9967587fe6..0000000000 --- a/contrib/p4import/git-p4import.txt +++ /dev/null @@ -1,167 +0,0 @@ -git-p4import(1) -=============== - -NAME ----- -git-p4import - Import a Perforce repository into git - - -SYNOPSIS --------- -[verse] -`git-p4import` [-q|-v] [--notags] [--authors <file>] [-t <timezone>] - <//p4repo/path> <branch> -`git-p4import` --stitch <//p4repo/path> -`git-p4import` - - -DESCRIPTION ------------ -Import a Perforce repository into an existing git repository. When -a <//p4repo/path> and <branch> are specified a new branch with the -given name will be created and the initial import will begin. - -Once the initial import is complete you can do an incremental import -of new commits from the Perforce repository. You do this by checking -out the appropriate git branch and then running `git-p4import` without -any options. - -The standard p4 client is used to communicate with the Perforce -repository; it must be configured correctly in order for `git-p4import` -to operate (see below). - - -OPTIONS -------- --q:: - Do not display any progress information. - --v:: - Give extra progress information. - -\--authors:: - Specify an authors file containing a mapping of Perforce user - ids to full names and email addresses (see Notes below). - -\--notags:: - Do not create a tag for each imported commit. - -\--stitch:: - Import the contents of the given perforce branch into the - currently checked out git branch. - -\--log:: - Store debugging information in the specified file. - --t:: - Specify that the remote repository is in the specified timezone. - Timezone must be in the format "US/Pacific" or "Europe/London" - etc. You only need to specify this once, it will be saved in - the git config file for the repository. - -<//p4repo/path>:: - The Perforce path that will be imported into the specified branch. - -<branch>:: - The new branch that will be created to hold the Perforce imports. - - -P4 Client ---------- -You must make the `p4` client command available in your $PATH and -configure it to communicate with the target Perforce repository. -Typically this means you must set the "$P4PORT" and "$P4CLIENT" -environment variables. - -You must also configure a `p4` client "view" which maps the Perforce -branch into the top level of your git repository, for example: - ------------- -Client: myhost - -Root: /home/sean/import - -Options: noallwrite clobber nocompress unlocked modtime rmdir - -View: - //public/jam/... //myhost/jam/... ------------- - -With the above `p4` client setup, you could import the "jam" -perforce branch into a branch named "jammy", like so: - ------------- -$ mkdir -p /home/sean/import/jam -$ cd /home/sean/import/jam -$ git init -$ git p4import //public/jam jammy ------------- - - -Multiple Branches ------------------ -Note that by creating multiple "views" you can use `git-p4import` -to import additional branches into the same git repository. -However, the `p4` client has a limitation in that it silently -ignores all but the last "view" that maps into the same local -directory. So the following will *not* work: - ------------- -View: - //public/jam/... //myhost/jam/... - //public/other/... //myhost/jam/... - //public/guest/... //myhost/jam/... ------------- - -If you want more than one Perforce branch to be imported into the -same directory you must employ a workaround. A simple option is -to adjust your `p4` client before each import to only include a -single view. - -Another option is to create multiple symlinks locally which all -point to the same directory in your git repository and then use -one per "view" instead of listing the actual directory. - - -Tags ----- -A git tag of the form p4/xx is created for every change imported from -the Perforce repository where xx is the Perforce changeset number. -Therefore after the import you can use git to access any commit by its -Perforce number, e.g. git show p4/327. - -The tag associated with the HEAD commit is also how `git-p4import` -determines if there are new changes to incrementally import from the -Perforce repository. - -If you import from a repository with many thousands of changes -you will have an equal number of p4/xxxx git tags. Git tags can -be expensive in terms of disk space and repository operations. -If you don't need to perform further incremental imports, you -may delete the tags. - - -Notes ------ -You can interrupt the import (e.g. ctrl-c) at any time and restart it -without worry. - -Author information is automatically determined by querying the -Perforce "users" table using the id associated with each change. -However, if you want to manually supply these mappings you can do -so with the "--authors" option. It accepts a file containing a list -of mappings with each line containing one mapping in the format: - ------------- - perforce_id = Full Name <email@address.com> ------------- - - -Author ------- -Written by Sean Estabrooks <seanlkml@sympatico.ca> - - -GIT ---- -Part of the gitlink:git[7] suite diff --git a/contrib/remote-helpers/git-remote-bzr b/contrib/remote-helpers/git-remote-bzr index c3a3cac77b..5f4b2e3e16 100755 --- a/contrib/remote-helpers/git-remote-bzr +++ b/contrib/remote-helpers/git-remote-bzr @@ -13,8 +13,11 @@ # 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' +# If you want to specify which branches you want to track (per repo): +# % git config remote.origin.bzr-branches 'trunk, devel, test' +# +# Where 'origin' is the name of the repository you want to specify the +# branches. # import sys @@ -41,8 +44,8 @@ import StringIO import atexit, shutil, hashlib, urlparse, subprocess NAME_RE = re.compile('^([^<>]+)') -AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]*)>$') -EMAIL_RE = re.compile('^([^<>]+[^ \\\t<>])?\\b(?:[ \\t<>]*?)\\b([^ \\t<>]+@[^ \\t<>]+)') +AUTHOR_RE = re.compile('^([^<>]+?)? ?[<>]([^<>]*)(?:$|>)') +EMAIL_RE = re.compile(r'([^ \t<>]+@[^ \t<>]+)') RAW_AUTHOR_RE = re.compile('^(\w+) (.+)? <(.*)> (\d+) ([+-]\d+)') def die(msg, *args): @@ -168,17 +171,16 @@ class Parser: if not m: return None _, name, email, date, tz = m.groups() + name = name.decode('utf-8') committer = '%s <%s>' % (name, email) tz = int(tz) tz = ((tz / 100) * 3600) + ((tz % 100) * 60) return (committer, int(date), tz) def rev_to_mark(rev): - global marks return marks.from_rev(rev) def mark_to_rev(mark): - global marks return marks.to_rev(mark) def fixup_user(user): @@ -191,8 +193,7 @@ def fixup_user(user): else: m = EMAIL_RE.match(user) if m: - name = m.group(1) - mail = m.group(2) + mail = m.group(1) else: m = NAME_RE.match(user) if m: @@ -233,8 +234,6 @@ def get_filechanges(cur, prev): return modified, removed def export_files(tree, files): - global marks, filenodes - final = [] for path, fid in files.iteritems(): kind = tree.kind(fid) @@ -276,8 +275,6 @@ def export_files(tree, files): return final def export_branch(repo, name): - global prefix - ref = '%s/heads/%s' % (prefix, name) tip = marks.get_tip(name) @@ -378,16 +375,12 @@ def export_branch(repo, name): marks.set_tip(name, revid) def export_tag(repo, name): - global tags, prefix - ref = '%s/tags/%s' % (prefix, name) print "reset %s" % ref print "from :%u" % rev_to_mark(tags[name]) print def do_import(parser): - global dirname - repo = parser.repo path = os.path.join(dirname, 'marks-git') @@ -413,8 +406,6 @@ def do_import(parser): sys.stdout.flush() def parse_blob(parser): - global blob_marks - parser.next() mark = parser.get_mark() parser.next() @@ -425,8 +416,6 @@ def parse_blob(parser): class CustomTree(): def __init__(self, branch, revid, parents, files): - global files_cache - self.updates = {} self.branch = branch @@ -484,7 +473,7 @@ class CustomTree(): add_entry(fid, dirname, 'directory') return fid - def add_entry(fid, path, kind, mode = None): + def add_entry(fid, path, kind, mode=None): dirname, basename = os.path.split(path) parent_fid = get_parent(dirname, basename) @@ -505,7 +494,7 @@ class CustomTree(): self.files[path] = [change[0], None] changes.append(change) - def update_entry(fid, path, kind, mode = None): + def update_entry(fid, path, kind, mode=None): dirname, basename = os.path.split(path) parent_fid = get_parent(dirname, basename) @@ -583,9 +572,6 @@ def c_style_unescape(string): return string def parse_commit(parser): - global marks, blob_marks, parsed_refs - global mode - parents = [] ref = parser[1] @@ -657,8 +643,6 @@ def parse_commit(parser): marks.new_mark(revid, commit_mark) def parse_reset(parser): - global parsed_refs - ref = parser[1] parser.next() @@ -674,8 +658,6 @@ def parse_reset(parser): parsed_refs[ref] = mark_to_rev(from_mark) def do_export(parser): - global parsed_refs, dirname - parser.next() for line in parser.each_block('done'): @@ -699,9 +681,11 @@ def do_export(parser): branch.generate_revision_history(revid, marks.get_tip(name)) if name in peers: - peer = bzrlib.branch.Branch.open(peers[name]) + peer = bzrlib.branch.Branch.open(peers[name], + possible_transports=transports) try: - peer.bzrdir.push_branch(branch, revision_id=revid) + peer.bzrdir.push_branch(branch, revision_id=revid, + overwrite=force) except bzrlib.errors.DivergedBranches: print "error %s non-fast forward" % ref continue @@ -724,8 +708,6 @@ def do_export(parser): print def do_capabilities(parser): - global dirname - print "import" print "export" print "refspec refs/heads/*:%s/heads/*" % prefix @@ -737,14 +719,36 @@ def do_capabilities(parser): print "*import-marks %s" % path print "*export-marks %s" % path + print "option" print +class InvalidOptionValue(Exception): + pass + +def get_bool_option(val): + if val == 'true': + return True + elif val == 'false': + return False + else: + raise InvalidOptionValue() + +def do_option(parser): + global force + opt, val = parser[1:3] + try: + if opt == 'force': + force = get_bool_option(val) + print 'ok' + else: + print 'unsupported' + except InvalidOptionValue: + print "error '%s' is not a valid value for option '%s'" % (val, opt) + def ref_is_valid(name): return not True in [c in name for c in '~^: \\'] def do_list(parser): - global tags - master_branch = None for name in branches: @@ -770,24 +774,24 @@ def do_list(parser): def clone(path, remote_branch): try: - bdir = bzrlib.bzrdir.BzrDir.create(path) + bdir = bzrlib.bzrdir.BzrDir.create(path, possible_transports=transports) except bzrlib.errors.AlreadyControlDirError: - bdir = bzrlib.bzrdir.BzrDir.open(path) + bdir = bzrlib.bzrdir.BzrDir.open(path, possible_transports=transports) repo = bdir.find_repository() repo.fetch(remote_branch.repository) return remote_branch.sprout(bdir, repository=repo) def get_remote_branch(name): - global dirname, branches - - remote_branch = bzrlib.branch.Branch.open(branches[name]) + remote_branch = bzrlib.branch.Branch.open(branches[name], + possible_transports=transports) if isinstance(remote_branch.user_transport, bzrlib.transport.local.LocalTransport): return remote_branch branch_path = os.path.join(dirname, 'clone', name) try: - branch = bzrlib.branch.Branch.open(branch_path) + branch = bzrlib.branch.Branch.open(branch_path, + possible_transports=transports) except bzrlib.errors.NotBranchError: # clone branch = clone(branch_path, remote_branch) @@ -821,17 +825,17 @@ def find_branches(repo): yield name, branch.base def get_repo(url, alias): - global dirname, peer, branches - normal_url = bzrlib.urlutils.normalize_url(url) - origin = bzrlib.bzrdir.BzrDir.open(url) + origin = bzrlib.bzrdir.BzrDir.open(url, possible_transports=transports) 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) + shared_dir = bzrlib.bzrdir.BzrDir.open(shared_path, + possible_transports=transports) except bzrlib.errors.NotBranchError: - shared_dir = bzrlib.bzrdir.BzrDir.create(shared_path) + shared_dir = bzrlib.bzrdir.BzrDir.create(shared_path, + possible_transports=transports) try: shared_repo = shared_dir.open_repository() except bzrlib.errors.NoRepositoryPresent: @@ -844,16 +848,21 @@ def get_repo(url, alias): else: # check and remove old organization try: - bdir = bzrlib.bzrdir.BzrDir.open(clone_path) + bdir = bzrlib.bzrdir.BzrDir.open(clone_path, + possible_transports=transports) bdir.destroy_repository() except bzrlib.errors.NotBranchError: pass except bzrlib.errors.NoRepositoryPresent: pass - wanted = get_config('remote-bzr.branches').rstrip().split(', ') + wanted = get_config('remote.%s.bzr-branches' % alias).rstrip().split(', ') # stupid python wanted = [e for e in wanted if e] + if not wanted: + wanted = get_config('remote-bzr.branches').rstrip().split(', ') + # stupid python + wanted = [e for e in wanted if e] if not wanted: try: @@ -897,6 +906,18 @@ def main(args): global files_cache global is_tmp global branches, peers + global transports + global force + + marks = None + is_tmp = False + gitdir = os.environ.get('GIT_DIR', None) + + if len(args) < 3: + die('Not enough arguments.') + + if not gitdir: + die('GIT_DIR not set') alias = args[1] url = args[2] @@ -906,18 +927,16 @@ def main(args): blob_marks = {} parsed_refs = {} files_cache = {} - marks = None branches = {} peers = {} + transports = [] + force = False if alias[5:] == url: is_tmp = True alias = hashlib.sha1(alias).hexdigest() - else: - is_tmp = False prefix = 'refs/bzr/%s' % alias - gitdir = os.environ['GIT_DIR'] dirname = os.path.join(gitdir, 'bzr', alias) if not is_tmp: @@ -944,6 +963,8 @@ def main(args): do_import(parser) elif parser.check('export'): do_export(parser) + elif parser.check('option'): + do_option(parser) else: die('unhandled command: %s' % line) sys.stdout.flush() diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg index 1c713e0af1..eb89ef6779 100755 --- a/contrib/remote-helpers/git-remote-hg +++ b/contrib/remote-helpers/git-remote-hg @@ -23,8 +23,12 @@ import subprocess import urllib import atexit import urlparse, hashlib +import time as ptime # +# If you want to see Mercurial revisions as Git commit notes: +# git config core.notesRef refs/notes/hg +# # 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 @@ -47,8 +51,8 @@ import urlparse, hashlib # NAME_RE = re.compile('^([^<>]+)') -AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]*)>$') -EMAIL_RE = re.compile('^([^<>]+[^ \\\t<>])?\\b(?:[ \\t<>]*?)\\b([^ \\t<>]+@[^ \\t<>]+)') +AUTHOR_RE = re.compile('^([^<>]+?)? ?[<>]([^<>]*)(?:$|>)') +EMAIL_RE = re.compile(r'([^ \t<>]+@[^ \t<>]+)') AUTHOR_HG_RE = re.compile('^(.*?) ?<(.*?)(?:>(.+)?)?$') RAW_AUTHOR_RE = re.compile('^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)') @@ -126,6 +130,7 @@ class Marks: self.rev_marks = {} self.last_mark = 0 self.version = 0 + self.last_note = 0 def load(self): if not os.path.exists(self.path): @@ -137,6 +142,7 @@ class Marks: self.marks = tmp['marks'] self.last_mark = tmp['last-mark'] self.version = tmp.get('version', 1) + self.last_note = tmp.get('last-note', 0) for rev, mark in self.marks.iteritems(): self.rev_marks[mark] = rev @@ -150,7 +156,7 @@ class Marks: self.version = 2 def dict(self): - return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark, 'version' : self.version } + return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark, 'version' : self.version, 'last-note' : self.last_note } def store(self): json.dump(self.dict(), open(self.path, 'w')) @@ -227,8 +233,6 @@ class Parser: return sys.stdin.read(size) def get_author(self): - global bad_mail - ex = None m = RAW_AUTHOR_RE.match(self.line) if not m: @@ -261,8 +265,6 @@ def fix_file_path(path): return os.path.relpath(path, '/') def export_files(files): - global marks, filenodes - final = [] for f in files: fid = node.hex(f.filenode()) @@ -314,8 +316,7 @@ def fixup_user_git(user): else: m = EMAIL_RE.match(user) if m: - name = m.group(1) - mail = m.group(2) + mail = m.group(1) else: m = NAME_RE.match(user) if m: @@ -344,8 +345,6 @@ def fixup_user_hg(user): return (name, mail) def fixup_user(user): - global mode, bad_mail - if mode == 'git': name, mail = fixup_user_git(user) else: @@ -374,7 +373,7 @@ def updatebookmarks(repo, peer): bookmarks.write(repo) def get_repo(url, alias): - global dirname, peer + global peer myui = ui.ui() myui.setconfig('ui', 'interactive', 'off') @@ -391,11 +390,24 @@ def get_repo(url, alias): os.makedirs(dirname) else: shared_path = os.path.join(gitdir, 'hg') - if not os.path.exists(shared_path): - try: - hg.clone(myui, {}, url, shared_path, update=False, pull=True) - except: - die('Repository error') + + # check and upgrade old organization + hg_path = os.path.join(shared_path, '.hg') + if os.path.exists(shared_path) and not os.path.exists(hg_path): + repos = os.listdir(shared_path) + for x in repos: + local_hg = os.path.join(shared_path, x, 'clone', '.hg') + if not os.path.exists(local_hg): + continue + if not os.path.exists(hg_path): + shutil.move(local_hg, hg_path) + shutil.rmtree(os.path.join(shared_path, x, 'clone')) + + # setup shared repo (if not there) + try: + hg.peer(myui, {}, shared_path, create=True) + except error.RepoError: + pass if not os.path.exists(dirname): os.makedirs(dirname) @@ -403,6 +415,9 @@ def get_repo(url, alias): local_path = os.path.join(dirname, 'clone') if not os.path.exists(local_path): hg.share(myui, shared_path, local_path, update=False) + else: + # make sure the shared path is always up-to-date + util.writefile(os.path.join(local_path, '.hg', 'sharedpath'), hg_path) repo = hg.repository(myui, local_path) try: @@ -416,16 +431,12 @@ def get_repo(url, alias): return repo def rev_to_mark(rev): - global marks return marks.from_rev(rev.hex()) def mark_to_rev(mark): - global marks return marks.to_rev(mark) def export_ref(repo, name, kind, head): - global prefix, marks, mode - ename = '%s/%s' % (kind, name) try: tip = marks.get_tip(ename) @@ -522,6 +533,31 @@ def export_ref(repo, name, kind, head): print "from :%u" % rev_to_mark(head) print + pending_revs = set(revs) - notes + if pending_revs: + note_mark = marks.next_mark() + ref = "refs/notes/hg" + + print "commit %s" % ref + print "mark :%d" % (note_mark) + print "committer remote-hg <> %d %s" % (ptime.time(), gittz(ptime.timezone)) + desc = "Notes for %s\n" % (name) + print "data %d" % (len(desc)) + print desc + if marks.last_note: + print "from :%u" % marks.last_note + + for rev in pending_revs: + notes.add(rev) + c = repo[rev] + print "N inline :%u" % rev_to_mark(c) + msg = c.hex() + print "data %d" % (len(msg)) + print msg + print + + marks.last_note = note_mark + marks.set_tip(ename, head.hex()) def export_tag(repo, tag): @@ -537,12 +573,9 @@ def export_branch(repo, branch): export_ref(repo, branch, 'branches', head) def export_head(repo): - global g_head export_ref(repo, g_head[0], 'bookmarks', g_head[1]) def do_capabilities(parser): - global prefix, dirname - print "import" print "export" print "refspec refs/heads/branches/*:%s/branches/*" % prefix @@ -562,8 +595,6 @@ def branch_tip(branch): return branches[branch][-1] def get_branch_tip(repo, branch): - global branches - heads = branches.get(hgref(branch), None) if not heads: return None @@ -576,7 +607,7 @@ def get_branch_tip(repo, branch): return heads[0] def list_head(repo, cur): - global g_head, bmarks, fake_bmark + global g_head, fake_bmark if 'default' not in branches: # empty repo @@ -592,8 +623,6 @@ def list_head(repo, cur): g_head = (head, node) def do_list(parser): - global branches, bmarks, track_branches - repo = parser.repo for bmark, node in bookmarks.listbookmarks(repo).iteritems(): bmarks[bmark] = repo[node] @@ -661,8 +690,6 @@ def do_import(parser): print 'done' def parse_blob(parser): - global blob_marks - parser.next() mark = parser.get_mark() parser.next() @@ -684,9 +711,6 @@ def c_style_unescape(string): return string def parse_commit(parser): - global marks, blob_marks, parsed_refs - global mode - from_mark = merge_mark = None ref = parser[1] @@ -805,8 +829,6 @@ def parse_commit(parser): marks.new_mark(node, commit_mark) def parse_reset(parser): - global parsed_refs - ref = parser[1] parser.next() # ugh @@ -999,8 +1021,6 @@ def check_tip(ref, kind, name, heads): return tip in heads def do_export(parser): - global parsed_refs, bmarks, peer - p_bmarks = [] p_revs = {} @@ -1072,7 +1092,7 @@ def do_export(parser): author, msg = parsed_tags.get(tag, (None, None)) if mode == 'git': if not msg: - msg = 'Added tag %s for changeset %s' % (tag, node[:12]); + msg = 'Added tag %s for changeset %s' % (tag, node[:12]) tagnode, branch = write_tag(parser.repo, tag, node, msg, author) p_revs[tagnode] = 'refs/heads/branches/' + gitref(branch) else: @@ -1130,7 +1150,7 @@ def do_option(parser): def fix_path(alias, repo, orig_url): url = urlparse.urlparse(orig_url, 'file') - if url.scheme != 'file' or os.path.isabs(url.path): + if url.scheme != 'file' or os.path.isabs(os.path.expanduser(url.path)): return abs_url = urlparse.urljoin("%s/" % os.getcwd(), orig_url) cmd = ['git', 'config', 'remote.%s.url' % alias, "hg::%s" % abs_url] @@ -1145,6 +1165,17 @@ def main(args): global filenodes global fake_bmark, hg_version global dry_run + global notes, alias + + marks = None + is_tmp = False + gitdir = os.environ.get('GIT_DIR', None) + + if len(args) < 3: + die('Not enough arguments.') + + if not gitdir: + die('GIT_DIR not set') alias = args[1] url = args[2] @@ -1166,16 +1197,12 @@ def main(args): if alias[4:] == url: is_tmp = True alias = hashlib.sha1(alias).hexdigest() - else: - is_tmp = False - gitdir = os.environ['GIT_DIR'] dirname = os.path.join(gitdir, 'hg', alias) branches = {} bmarks = {} blob_marks = {} parsed_refs = {} - marks = None parsed_tags = {} filenodes = {} fake_bmark = None @@ -1184,6 +1211,7 @@ def main(args): except: hg_version = None dry_run = False + notes = set() repo = get_repo(url, alias) prefix = 'refs/hg/%s' % alias diff --git a/contrib/remote-helpers/test-bzr.sh b/contrib/remote-helpers/test-bzr.sh index dce281f911..4f379c2ab4 100755 --- a/contrib/remote-helpers/test-bzr.sh +++ b/contrib/remote-helpers/test-bzr.sh @@ -5,21 +5,24 @@ test_description='Test remote-bzr' -. ./test-lib.sh +test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=${0%/*}/../../t +. "$TEST_DIRECTORY"/test-lib.sh -if ! test_have_prereq PYTHON; then +if ! test_have_prereq PYTHON +then skip_all='skipping remote-bzr tests; python not available' test_done fi -if ! python -c 'import bzrlib'; then +if ! python -c 'import bzrlib' +then skip_all='skipping remote-bzr tests; bzr not available' test_done fi check () { - echo $3 > expected && - git --git-dir=$1/.git log --format='%s' -1 $2 > actual + echo $3 >expected && + git --git-dir=$1/.git log --format='%s' -1 $2 >actual test_cmp expected actual } @@ -29,7 +32,7 @@ test_expect_success 'cloning' ' ( bzr init bzrrepo && cd bzrrepo && - echo one > content && + echo one >content && bzr add content && bzr commit -m one ) && @@ -41,7 +44,7 @@ test_expect_success 'cloning' ' test_expect_success 'pulling' ' ( cd bzrrepo && - echo two > content && + echo two >content && bzr commit -m two ) && @@ -53,13 +56,33 @@ test_expect_success 'pulling' ' test_expect_success 'pushing' ' ( cd gitrepo && - echo three > content && + echo three >content && git commit -a -m three && git push ) && - echo three > expected && - cat bzrrepo/content > actual && + echo three >expected && + cat bzrrepo/content >actual && + test_cmp expected actual +' + +test_expect_success 'forced pushing' ' + ( + cd gitrepo && + echo three-new >content && + git commit -a --amend -m three-new && + git push -f + ) && + + ( + cd bzrrepo && + # the forced update overwrites the bzr branch but not the bzr + # working directory (it tries to merge instead) + bzr revert + ) && + + echo three-new >expected && + cat bzrrepo/content >actual && test_cmp expected actual ' @@ -67,16 +90,16 @@ test_expect_success 'roundtrip' ' ( cd gitrepo && git pull && - git log --format="%s" -1 origin/master > actual + git log --format="%s" -1 origin/master >actual ) && - echo three > expected && + echo three-new >expected && test_cmp expected actual && (cd gitrepo && git push && git pull) && ( cd bzrrepo && - echo four > content && + echo four >content && bzr commit -m four ) && @@ -86,19 +109,19 @@ test_expect_success 'roundtrip' ' ( cd gitrepo && - echo five > content && + echo five >content && git commit -a -m five && git push && git pull ) && (cd bzrrepo && bzr revert) && - echo five > expected && - cat bzrrepo/content > actual && + echo five >expected && + cat bzrrepo/content >actual && test_cmp expected actual ' -cat > expected <<EOF +cat >expected <<\EOF 100644 blob 54f9d6da5c91d556e6b54340b1327573073030af content 100755 blob 68769579c3eaadbe555379b9c3538e6628bae1eb executable 120000 blob 6b584e8ece562ebffc15d38808cd6b98fc3d97ea link @@ -107,7 +130,7 @@ EOF test_expect_success 'special modes' ' ( cd bzrrepo && - echo exec > executable + echo exec >executable chmod +x executable && bzr add executable bzr commit -m exec && @@ -122,21 +145,21 @@ test_expect_success 'special modes' ' ( cd gitrepo && git pull - git ls-tree HEAD > ../actual + git ls-tree HEAD >../actual ) && test_cmp expected actual && ( cd gitrepo && - git cat-file -p HEAD:link > ../actual + git cat-file -p HEAD:link >../actual ) && - printf content > expected && + printf content >expected && test_cmp expected actual ' -cat > expected <<EOF +cat >expected <<\EOF 100644 blob 54f9d6da5c91d556e6b54340b1327573073030af content 100755 blob 68769579c3eaadbe555379b9c3538e6628bae1eb executable 120000 blob 6b584e8ece562ebffc15d38808cd6b98fc3d97ea link @@ -147,8 +170,8 @@ test_expect_success 'moving directory' ' ( cd bzrrepo && mkdir movedir && - echo one > movedir/one && - echo two > movedir/two && + echo one >movedir/one && + echo two >movedir/two && bzr add movedir && bzr commit -m movedir && bzr mv movedir movedir-new && @@ -158,7 +181,7 @@ test_expect_success 'moving directory' ' ( cd gitrepo && git pull && - git ls-tree HEAD > ../actual + git ls-tree HEAD >../actual ) && test_cmp expected actual @@ -167,7 +190,7 @@ test_expect_success 'moving directory' ' test_expect_success 'different authors' ' ( cd bzrrepo && - echo john >> content && + echo john >>content && bzr commit -m john \ --author "Jane Rey <jrey@example.com>" \ --author "John Doe <jdoe@example.com>" @@ -176,10 +199,10 @@ test_expect_success 'different authors' ' ( cd gitrepo && git pull && - git show --format="%an <%ae>, %cn <%ce>" --quiet > ../actual + git show --format="%an <%ae>, %cn <%ce>" --quiet >../actual ) && - echo "Jane Rey <jrey@example.com>, A U Thor <author@example.com>" > expected && + echo "Jane Rey <jrey@example.com>, A U Thor <author@example.com>" >expected && test_cmp expected actual ' @@ -196,12 +219,12 @@ test_expect_success 'fetch utf-8 filenames' ' bzr init bzrrepo && cd bzrrepo && - echo test >> "ærø" && + echo test >>"ærø" && bzr add "ærø" && - echo test >> "ø~?" && + echo test >>"ø~?" && bzr add "ø~?" && bzr commit -m add-utf-8 && - echo test >> "ærø" && + echo test >>"ærø" && bzr commit -m test-utf-8 && bzr rm "ø~?" && bzr mv "ærø" "ø~?" && @@ -211,9 +234,9 @@ test_expect_success 'fetch utf-8 filenames' ' ( git clone "bzr::bzrrepo" gitrepo && cd gitrepo && - git -c core.quotepath=false ls-files > ../actual + git -c core.quotepath=false ls-files >../actual ) && - echo "ø~?" > expected && + echo "ø~?" >expected && test_cmp expected actual ' @@ -229,7 +252,7 @@ test_expect_success 'push utf-8 filenames' ' bzr init bzrrepo && cd bzrrepo && - echo one >> content && + echo one >>content && bzr add content && bzr commit -m one ) && @@ -238,15 +261,15 @@ test_expect_success 'push utf-8 filenames' ' git clone "bzr::bzrrepo" gitrepo && cd gitrepo && - echo test >> "ærø" && + echo test >>"ærø" && git add "ærø" && git commit -m utf-8 && git push ) && - (cd bzrrepo && bzr ls > ../actual) && - printf "content\nærø\n" > expected && + (cd bzrrepo && bzr ls >../actual) && + printf "content\nærø\n" >expected && test_cmp expected actual ' @@ -256,7 +279,7 @@ test_expect_success 'pushing a merge' ' ( bzr init bzrrepo && cd bzrrepo && - echo one > content && + echo one >content && bzr add content && bzr commit -m one ) && @@ -265,27 +288,27 @@ test_expect_success 'pushing a merge' ' ( cd bzrrepo && - echo two > content && + echo two >content && bzr commit -m two ) && ( cd gitrepo && - echo three > content && + echo three >content && git commit -a -m three && git fetch && git merge origin/master || true && - echo three > content && + echo three >content && git commit -a --no-edit && git push ) && - echo three > expected && - cat bzrrepo/content > actual && + echo three >expected && + cat bzrrepo/content >actual && test_cmp expected actual ' -cat > expected <<EOF +cat >expected <<\EOF origin/HEAD origin/branch origin/trunk @@ -299,7 +322,7 @@ test_expect_success 'proper bzr repo' ' ( bzr init bzrrepo/trunk && cd bzrrepo/trunk && - echo one >> content && + echo one >>content && bzr add content && bzr commit -m one ) && @@ -307,14 +330,14 @@ test_expect_success 'proper bzr repo' ' ( bzr branch bzrrepo/trunk bzrrepo/branch && cd bzrrepo/branch && - echo two >> content && + echo two >>content && bzr commit -m one ) && ( git clone "bzr::bzrrepo" gitrepo && cd gitrepo && - git for-each-ref --format "%(refname:short)" refs/remotes/origin > ../actual + git for-each-ref --format "%(refname:short)" refs/remotes/origin >../actual ) && test_cmp expected actual @@ -327,11 +350,11 @@ test_expect_success 'strip' ' bzr init bzrrepo && cd bzrrepo && - echo one >> content && + echo one >>content && bzr add content && bzr commit -m one && - echo two >> content && + echo two >>content && bzr commit -m two ) && @@ -341,20 +364,50 @@ test_expect_success 'strip' ' cd bzrrepo && bzr uncommit --force && - echo three >> content && + echo three >>content && bzr commit -m three && - echo four >> content && + echo four >>content && bzr commit -m four && - bzr log --line | sed -e "s/^[0-9][0-9]*: //" > ../expected + 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 + git log --format="%an %ad %s" --date=short origin/master >../actual + ) && + + test_cmp expected actual +' + +test_expect_success 'export utf-8 authors' ' + test_when_finished "rm -rf bzrrepo gitrepo && LC_ALL=C && unset GIT_COMMITTER_NAME" && + + LC_ALL=en_US.UTF-8 + export LC_ALL + + GIT_COMMITTER_NAME="Grégoire" + export GIT_COMMITTER_NAME + + bzr init bzrrepo && + + ( + git init gitrepo && + cd gitrepo && + echo greg >>content && + git add content && + git commit -m one && + git remote add bzr "bzr::../bzrrepo" && + git push bzr master + ) && + + ( + cd bzrrepo && + bzr log | grep "^committer: " >../actual ) && + echo "committer: Grégoire <committer@example.com>" >expected && test_cmp expected actual ' diff --git a/contrib/remote-helpers/test-hg-bidi.sh b/contrib/remote-helpers/test-hg-bidi.sh index f83d67d74f..e24c51daad 100755 --- a/contrib/remote-helpers/test-hg-bidi.sh +++ b/contrib/remote-helpers/test-hg-bidi.sh @@ -10,12 +10,14 @@ test_description='Test bidirectionality of remote-hg' . ./test-lib.sh -if ! test_have_prereq PYTHON; then +if ! test_have_prereq PYTHON +then skip_all='skipping remote-hg tests; python not available' test_done fi -if ! python -c 'import mercurial'; then +if ! python -c 'import mercurial' +then skip_all='skipping remote-hg tests; mercurial not available' test_done fi @@ -43,7 +45,7 @@ hg_push () { git checkout -q -b tmp && git fetch -q "hg::../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' && git checkout -q @{-1} && - git branch -q -D tmp 2> /dev/null || true + git branch -q -D tmp 2>/dev/null || true ) } @@ -62,7 +64,7 @@ setup () { echo "tag = -d \"0 0\"" echo "[extensions]" echo "graphlog =" - ) >> "$HOME"/.hgrc && + ) >>"$HOME"/.hgrc && git config --global remote-hg.hg-git-compat true git config --global remote-hg.track-branches true @@ -81,22 +83,22 @@ test_expect_success 'encoding' ' git init -q gitrepo && cd gitrepo && - echo alpha > alpha && + echo alpha >alpha && git add alpha && git commit -m "add älphà" && GIT_AUTHOR_NAME="tést èncödîng" && export GIT_AUTHOR_NAME && - echo beta > beta && + echo beta >beta && git add beta && git commit -m "add beta" && - echo gamma > gamma && + echo gamma >gamma && git add gamma && git commit -m "add gämmâ" && : TODO git config i18n.commitencoding latin-1 && - echo delta > delta && + echo delta >delta && git add delta && git commit -m "add déltà" ) && @@ -105,8 +107,8 @@ test_expect_success 'encoding' ' git_clone hgrepo gitrepo2 && hg_clone gitrepo2 hgrepo2 && - HGENCODING=utf-8 hg_log hgrepo > expected && - HGENCODING=utf-8 hg_log hgrepo2 > actual && + HGENCODING=utf-8 hg_log hgrepo >expected && + HGENCODING=utf-8 hg_log hgrepo2 >actual && test_cmp expected actual ' @@ -117,14 +119,14 @@ test_expect_success 'file removal' ' ( git init -q gitrepo && cd gitrepo && - echo alpha > alpha && + echo alpha >alpha && git add alpha && git commit -m "add alpha" && - echo beta > beta && + echo beta >beta && git add beta && git commit -m "add beta" mkdir foo && - echo blah > foo/bar && + echo blah >foo/bar && git add foo && git commit -m "add foo" && git rm alpha && @@ -137,8 +139,8 @@ test_expect_success 'file removal' ' git_clone hgrepo gitrepo2 && hg_clone gitrepo2 hgrepo2 && - hg_log hgrepo > expected && - hg_log hgrepo2 > actual && + hg_log hgrepo >expected && + hg_log hgrepo2 >actual && test_cmp expected actual ' @@ -150,12 +152,12 @@ test_expect_success 'git tags' ' git init -q gitrepo && cd gitrepo && git config receive.denyCurrentBranch ignore && - echo alpha > alpha && + echo alpha >alpha && git add alpha && git commit -m "add alpha" && git tag alpha && - echo beta > beta && + echo beta >beta && git add beta && git commit -m "add beta" && git tag -a -m "added tag beta" beta @@ -165,8 +167,8 @@ test_expect_success 'git tags' ' git_clone hgrepo gitrepo2 && hg_clone gitrepo2 hgrepo2 && - hg_log hgrepo > expected && - hg_log hgrepo2 > actual && + hg_log hgrepo >expected && + hg_log hgrepo2 >actual && test_cmp expected actual ' @@ -178,7 +180,7 @@ test_expect_success 'hg branch' ' git init -q gitrepo && cd gitrepo && - echo alpha > alpha && + echo alpha >alpha && git add alpha && git commit -q -m "add alpha" && git checkout -q -b not-master @@ -201,8 +203,8 @@ test_expect_success 'hg branch' ' : Back to the common revision && (cd hgrepo && hg checkout default) && - hg_log hgrepo > expected && - hg_log hgrepo2 > actual && + hg_log hgrepo >expected && + hg_log hgrepo2 >actual && test_cmp expected actual ' @@ -214,7 +216,7 @@ test_expect_success 'hg tags' ' git init -q gitrepo && cd gitrepo && - echo alpha > alpha && + echo alpha >alpha && git add alpha && git commit -m "add alpha" && git checkout -q -b not-master @@ -231,8 +233,8 @@ test_expect_success 'hg tags' ' hg_push hgrepo gitrepo && hg_clone gitrepo hgrepo2 && - hg_log hgrepo > expected && - hg_log hgrepo2 > actual && + hg_log hgrepo >expected && + hg_log hgrepo2 >actual && test_cmp expected actual ' diff --git a/contrib/remote-helpers/test-hg-hg-git.sh b/contrib/remote-helpers/test-hg-hg-git.sh index 2219284382..6dcd95d10f 100755 --- a/contrib/remote-helpers/test-hg-hg-git.sh +++ b/contrib/remote-helpers/test-hg-hg-git.sh @@ -10,17 +10,20 @@ test_description='Test remote-hg output compared to hg-git' . ./test-lib.sh -if ! test_have_prereq PYTHON; then +if ! test_have_prereq PYTHON +then skip_all='skipping remote-hg tests; python not available' test_done fi -if ! python -c 'import mercurial'; then +if ! python -c 'import mercurial' +then skip_all='skipping remote-hg tests; mercurial not available' test_done fi -if ! python -c 'import hggit'; then +if ! python -c 'import hggit' +then skip_all='skipping remote-hg tests; hg-git not available' test_done fi @@ -66,7 +69,7 @@ hg_push_git () { git fetch -q "hg::../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' && git branch -D default && git checkout -q @{-1} && - git branch -q -D tmp 2> /dev/null || true + git branch -q -D tmp 2>/dev/null || true ) } @@ -100,7 +103,7 @@ setup () { echo "hgext.bookmarks =" echo "hggit =" echo "graphlog =" - ) >> "$HOME"/.hgrc && + ) >>"$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 @@ -121,7 +124,7 @@ test_expect_success 'executable bit' ' ( git init -q gitrepo && cd gitrepo && - echo alpha > alpha && + echo alpha >alpha && chmod 0644 alpha && git add alpha && git commit -m "add alpha" && @@ -133,17 +136,18 @@ test_expect_success 'executable bit' ' git commit -m "clear executable bit" ) && - for x in hg git; do + for x in hg git + do ( hg_clone_$x gitrepo hgrepo-$x && cd hgrepo-$x && hg_log . && hg manifest -r 1 -v && hg manifest -v - ) > output-$x && + ) >"output-$x" && git_clone_$x hgrepo-$x gitrepo2-$x && - git_log gitrepo2-$x > log-$x + git_log gitrepo2-$x >"log-$x" done && test_cmp output-hg output-git && @@ -156,7 +160,7 @@ test_expect_success 'symlink' ' ( git init -q gitrepo && cd gitrepo && - echo alpha > alpha && + echo alpha >alpha && git add alpha && git commit -m "add alpha" && ln -s alpha beta && @@ -164,16 +168,17 @@ test_expect_success 'symlink' ' git commit -m "add beta" ) && - for x in hg git; do + for x in hg git + do ( hg_clone_$x gitrepo hgrepo-$x && cd hgrepo-$x && hg_log . && hg manifest -v - ) > output-$x && + ) >"output-$x" && git_clone_$x hgrepo-$x gitrepo2-$x && - git_log gitrepo2-$x > log-$x + git_log gitrepo2-$x >"log-$x" done && test_cmp output-hg output-git && @@ -186,28 +191,29 @@ test_expect_success 'merge conflict 1' ' ( hg init hgrepo1 && cd hgrepo1 && - echo A > afile && + echo A >afile && hg add afile && hg ci -m "origin" && - echo B > afile && + echo B >afile && hg ci -m "A->B" && hg up -r0 && - echo C > afile && + echo C >afile && hg ci -m "A->C" && hg merge -r1 && - echo C > afile && + echo C >afile && hg resolve -m afile && hg ci -m "merge to C" ) && - for x in hg git; do + for x in hg git + do git_clone_$x hgrepo1 gitrepo-$x && hg_clone_$x gitrepo-$x hgrepo2-$x && - hg_log hgrepo2-$x > hg-log-$x && - git_log gitrepo-$x > git-log-$x + hg_log hgrepo2-$x >"hg-log-$x" && + git_log gitrepo-$x >"git-log-$x" done && test_cmp hg-log-hg hg-log-git && @@ -220,28 +226,29 @@ test_expect_success 'merge conflict 2' ' ( hg init hgrepo1 && cd hgrepo1 && - echo A > afile && + echo A >afile && hg add afile && hg ci -m "origin" && - echo B > afile && + echo B >afile && hg ci -m "A->B" && hg up -r0 && - echo C > afile && + echo C >afile && hg ci -m "A->C" && hg merge -r1 || true && - echo B > afile && + echo B >afile && hg resolve -m afile && hg ci -m "merge to B" ) && - for x in hg git; do + for x in hg git + do git_clone_$x hgrepo1 gitrepo-$x && hg_clone_$x gitrepo-$x hgrepo2-$x && - hg_log hgrepo2-$x > hg-log-$x && - git_log gitrepo-$x > git-log-$x + hg_log hgrepo2-$x >"hg-log-$x" && + git_log gitrepo-$x >"git-log-$x" done && test_cmp hg-log-hg hg-log-git && @@ -254,29 +261,30 @@ test_expect_success 'converged merge' ' ( hg init hgrepo1 && cd hgrepo1 && - echo A > afile && + echo A >afile && hg add afile && hg ci -m "origin" && - echo B > afile && + echo B >afile && hg ci -m "A->B" && - echo C > afile && + echo C >afile && hg ci -m "B->C" && hg up -r0 && - echo C > afile && + echo C >afile && hg ci -m "A->C" && hg merge -r2 || true && hg ci -m "merge" ) && - for x in hg git; do + for x in hg git + do git_clone_$x hgrepo1 gitrepo-$x && hg_clone_$x gitrepo-$x hgrepo2-$x && - hg_log hgrepo2-$x > hg-log-$x && - git_log gitrepo-$x > git-log-$x + hg_log hgrepo2-$x >"hg-log-$x" && + git_log gitrepo-$x >"git-log-$x" done && test_cmp hg-log-hg hg-log-git && @@ -290,32 +298,33 @@ test_expect_success 'encoding' ' git init -q gitrepo && cd gitrepo && - echo alpha > alpha && + echo alpha >alpha && git add alpha && git commit -m "add älphà" && GIT_AUTHOR_NAME="tést èncödîng" && export GIT_AUTHOR_NAME && - echo beta > beta && + echo beta >beta && git add beta && git commit -m "add beta" && - echo gamma > gamma && + echo gamma >gamma && git add gamma && git commit -m "add gämmâ" && : TODO git config i18n.commitencoding latin-1 && - echo delta > delta && + echo delta >delta && git add delta && git commit -m "add déltà" ) && - for x in hg git; do + for x in hg git + do hg_clone_$x gitrepo hgrepo-$x && git_clone_$x hgrepo-$x gitrepo2-$x && - HGENCODING=utf-8 hg_log hgrepo-$x > hg-log-$x && - git_log gitrepo2-$x > git-log-$x + HGENCODING=utf-8 hg_log hgrepo-$x >"hg-log-$x" && + git_log gitrepo2-$x >"git-log-$x" done && test_cmp hg-log-hg hg-log-git && @@ -328,14 +337,14 @@ test_expect_success 'file removal' ' ( git init -q gitrepo && cd gitrepo && - echo alpha > alpha && + echo alpha >alpha && git add alpha && git commit -m "add alpha" && - echo beta > beta && + echo beta >beta && git add beta && git commit -m "add beta" mkdir foo && - echo blah > foo/bar && + echo blah >foo/bar && git add foo && git commit -m "add foo" && git rm alpha && @@ -344,17 +353,18 @@ test_expect_success 'file removal' ' git commit -m "remove foo/bar" ) && - for x in hg git; do + for x in hg git + do ( hg_clone_$x gitrepo hgrepo-$x && cd hgrepo-$x && hg_log . && hg manifest -r 3 && hg manifest - ) > output-$x && + ) >"output-$x" && git_clone_$x hgrepo-$x gitrepo2-$x && - git_log gitrepo2-$x > log-$x + git_log gitrepo2-$x >"log-$x" done && test_cmp output-hg output-git && @@ -368,20 +378,21 @@ test_expect_success 'git tags' ' git init -q gitrepo && cd gitrepo && git config receive.denyCurrentBranch ignore && - echo alpha > alpha && + echo alpha >alpha && git add alpha && git commit -m "add alpha" && git tag alpha && - echo beta > beta && + echo beta >beta && git add beta && git commit -m "add beta" && git tag -a -m "added tag beta" beta ) && - for x in hg git; do + for x in hg git + do hg_clone_$x gitrepo hgrepo-$x && - hg_log hgrepo-$x > log-$x + hg_log hgrepo-$x >"log-$x" done && test_cmp log-hg log-git @@ -390,12 +401,13 @@ test_expect_success 'git tags' ' test_expect_success 'hg author' ' test_when_finished "rm -rf gitrepo* hgrepo*" && - for x in hg git; do + for x in hg git + do ( git init -q gitrepo-$x && cd gitrepo-$x && - echo alpha > alpha && + echo alpha >alpha && git add alpha && git commit -m "add alpha" && git checkout -q -b not-master @@ -406,38 +418,38 @@ test_expect_success 'hg author' ' cd hgrepo-$x && hg co master && - echo beta > beta && + echo beta >beta && hg add beta && hg commit -u "test" -m "add beta" && - echo gamma >> beta && + echo gamma >>beta && hg commit -u "test <test@example.com> (comment)" -m "modify beta" && - echo gamma > gamma && + echo gamma >gamma && hg add gamma && hg commit -u "<test@example.com>" -m "add gamma" && - echo delta > delta && + echo delta >delta && hg add delta && hg commit -u "name<test@example.com>" -m "add delta" && - echo epsilon > epsilon && + echo epsilon >epsilon && hg add epsilon && hg commit -u "name <test@example.com" -m "add epsilon" && - echo zeta > zeta && + echo zeta >zeta && hg add zeta && hg commit -u " test " -m "add zeta" && - echo eta > eta && + echo eta >eta && hg add eta && hg commit -u "test < test@example.com >" -m "add eta" && - echo theta > theta && + echo theta >theta && hg add theta && hg commit -u "test >test@example.com>" -m "add theta" && - echo iota > iota && + echo iota >iota && hg add iota && hg commit -u "test <test <at> example <dot> com>" -m "add iota" ) && @@ -445,8 +457,8 @@ test_expect_success 'hg author' ' hg_push_$x hgrepo-$x gitrepo-$x && hg_clone_$x gitrepo-$x hgrepo2-$x && - hg_log hgrepo2-$x > hg-log-$x && - git_log gitrepo-$x > git-log-$x + hg_log hgrepo2-$x >"hg-log-$x" && + git_log gitrepo-$x >"git-log-$x" done && test_cmp hg-log-hg hg-log-git && @@ -456,12 +468,13 @@ test_expect_success 'hg author' ' test_expect_success 'hg branch' ' test_when_finished "rm -rf gitrepo* hgrepo*" && - for x in hg git; do + for x in hg git + do ( git init -q gitrepo-$x && cd gitrepo-$x && - echo alpha > alpha && + echo alpha >alpha && git add alpha && git commit -q -m "add alpha" && git checkout -q -b not-master @@ -481,8 +494,8 @@ test_expect_success 'hg branch' ' hg_push_$x hgrepo-$x gitrepo-$x && hg_clone_$x gitrepo-$x hgrepo2-$x && - hg_log hgrepo2-$x > hg-log-$x && - git_log gitrepo-$x > git-log-$x + hg_log hgrepo2-$x >"hg-log-$x" && + git_log gitrepo-$x >"git-log-$x" done && test_cmp hg-log-hg hg-log-git && @@ -492,12 +505,13 @@ test_expect_success 'hg branch' ' test_expect_success 'hg tags' ' test_when_finished "rm -rf gitrepo* hgrepo*" && - for x in hg git; do + for x in hg git + do ( git init -q gitrepo-$x && cd gitrepo-$x && - echo alpha > alpha && + echo alpha >alpha && git add alpha && git commit -m "add alpha" && git checkout -q -b not-master @@ -518,7 +532,7 @@ test_expect_success 'hg tags' ' git --git-dir=gitrepo-$x/.git tag -l && hg_log hgrepo2-$x && cat hgrepo2-$x/.hgtags - ) > output-$x + ) >"output-$x" done && test_cmp output-hg output-git diff --git a/contrib/remote-helpers/test-hg.sh b/contrib/remote-helpers/test-hg.sh index f7ce8aa853..a933b1e30c 100755 --- a/contrib/remote-helpers/test-hg.sh +++ b/contrib/remote-helpers/test-hg.sh @@ -8,55 +8,60 @@ test_description='Test remote-hg' -. ./test-lib.sh +test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=${0%/*}/../../t +. "$TEST_DIRECTORY"/test-lib.sh -if ! test_have_prereq PYTHON; then +if ! test_have_prereq PYTHON +then skip_all='skipping remote-hg tests; python not available' test_done fi -if ! python -c 'import mercurial'; then +if ! python -c 'import mercurial' +then skip_all='skipping remote-hg tests; mercurial not available' test_done fi check () { - echo $3 > expected && - git --git-dir=$1/.git log --format='%s' -1 $2 > actual + echo $3 >expected && + git --git-dir=$1/.git log --format='%s' -1 $2 >actual test_cmp expected actual } check_branch () { - if [ -n "$3" ]; then - echo $3 > expected && - hg -R $1 log -r $2 --template '{desc}\n' > actual && + if test -n "$3" + then + echo $3 >expected && + hg -R $1 log -r $2 --template '{desc}\n' >actual && test_cmp expected actual else - hg -R $1 branches > out && + hg -R $1 branches >out && ! grep $2 out fi } check_bookmark () { - if [ -n "$3" ]; then - echo $3 > expected && - hg -R $1 log -r "bookmark('$2')" --template '{desc}\n' > actual && + if test -n "$3" + then + echo $3 >expected && + hg -R $1 log -r "bookmark('$2')" --template '{desc}\n' >actual && test_cmp expected actual else - hg -R $1 bookmarks > out && + hg -R $1 bookmarks >out && ! grep $2 out fi } check_push () { - local expected_ret=$1 ret=0 ref_ret=0 IFS=':' + expected_ret=$1 ret=0 ref_ret=0 shift - git push origin "$@" 2> error + git push origin "$@" 2>error ret=$? cat error - while read branch kind + while IFS=':' read branch kind do case "$kind" in 'new') @@ -75,10 +80,10 @@ check_push () { grep "^ [a-f0-9]*\.\.[a-f0-9]* *${branch} -> ${branch}$" error || ref_ret=1 ;; esac - let 'ref_ret' && echo "match for '$branch' failed" && break + test $ref_ret -ne 0 && echo "match for '$branch' failed" && break done - if let 'expected_ret != ret || ref_ret' + if test $expected_ret -ne $ret || test $ref_ret -ne 0 then return 1 fi @@ -92,7 +97,7 @@ setup () { echo "username = H G Wells <wells@example.com>" echo "[extensions]" echo "mq =" - ) >> "$HOME"/.hgrc && + ) >>"$HOME"/.hgrc && GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" && GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" && @@ -107,7 +112,7 @@ test_expect_success 'cloning' ' ( hg init hgrepo && cd hgrepo && - echo zero > content && + echo zero >content && hg add content && hg commit -m zero ) && @@ -122,7 +127,7 @@ test_expect_success 'cloning with branches' ' ( cd hgrepo && hg branch next && - echo next > content && + echo next >content && hg commit -m next ) && @@ -137,7 +142,7 @@ test_expect_success 'cloning with bookmarks' ' cd hgrepo && hg checkout default && hg bookmark feature-a && - echo feature-a > content && + echo feature-a >content && hg commit -m feature-a ) && @@ -157,7 +162,7 @@ test_expect_success 'update bookmark' ' git clone "hg::hgrepo" gitrepo && cd gitrepo && git checkout --quiet devel && - echo devel > content && + echo devel >content && git commit -a -m devel && git push --quiet ) && @@ -172,7 +177,7 @@ test_expect_success 'new bookmark' ' git clone "hg::hgrepo" gitrepo && cd gitrepo && git checkout --quiet -b feature-b && - echo feature-b > content && + echo feature-b >content && git commit -a -m feature-b && git push --quiet origin feature-b ) && @@ -184,9 +189,9 @@ test_expect_success 'new bookmark' ' rm -rf hgrepo author_test () { - echo $1 >> content && + echo $1 >>content && hg commit -u "$2" -m "add $1" && - echo "$3" >> ../expected + echo "$3" >>../expected } test_expect_success 'authors' ' @@ -199,22 +204,23 @@ test_expect_success 'authors' ' touch content && hg add content && - > ../expected && + >../expected && author_test alpha "" "H G Wells <wells@example.com>" && - author_test beta "test" "test <unknown>" && - author_test beta "test <test@example.com> (comment)" "test <test@example.com>" && - 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 <test@example.com>" && - 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 <test@example.com>" && - author_test iota "test < test <at> example <dot> com>" "test <unknown>" && - author_test kappa "test@example.com" "Unknown <test@example.com>" + author_test beta "beta" "beta <unknown>" && + author_test gamma "gamma <test@example.com> (comment)" "gamma <test@example.com>" && + author_test delta "<delta@example.com>" "Unknown <delta@example.com>" && + author_test epsilon "epsilon<test@example.com>" "epsilon <test@example.com>" && + author_test zeta "zeta <test@example.com" "zeta <test@example.com>" && + author_test eta " eta " "eta <unknown>" && + author_test theta "theta < test@example.com >" "theta <test@example.com>" && + author_test iota "iota >test@example.com>" "iota <test@example.com>" && + author_test kappa "kappa < test <at> example <dot> com>" "kappa <unknown>" && + author_test lambda "lambda@example.com" "Unknown <lambda@example.com>" && + author_test mu "mu.mu@example.com" "Unknown <mu.mu@example.com>" ) && git clone "hg::hgrepo" gitrepo && - git --git-dir=gitrepo/.git log --reverse --format="%an <%ae>" > actual && + git --git-dir=gitrepo/.git log --reverse --format="%an <%ae>" >actual && test_cmp expected actual ' @@ -226,11 +232,11 @@ test_expect_success 'strip' ' hg init hgrepo && cd hgrepo && - echo one >> content && + echo one >>content && hg add content && hg commit -m one && - echo two >> content && + echo two >>content && hg commit -m two ) && @@ -240,20 +246,20 @@ test_expect_success 'strip' ' cd hgrepo && hg strip 1 && - echo three >> content && + echo three >>content && hg commit -m three && - echo four >> content && + echo four >>content && hg commit -m four ) && ( cd gitrepo && git fetch && - git log --format="%s" origin/master > ../actual + git log --format="%s" origin/master >../actual ) && - hg -R hgrepo log --template "{desc}\n" > expected && + hg -R hgrepo log --template "{desc}\n" >expected && test_cmp actual expected ' @@ -263,18 +269,18 @@ test_expect_success 'remote push with master bookmark' ' ( hg init hgrepo && cd hgrepo && - echo zero > content && + echo zero >content && hg add content && hg commit -m zero && hg bookmark master && - echo one > content && + echo one >content && hg commit -m one ) && ( git clone "hg::hgrepo" gitrepo && cd gitrepo && - echo two > content && + echo two >content && git commit -a -m two && git push ) && @@ -282,7 +288,7 @@ test_expect_success 'remote push with master bookmark' ' check_branch hgrepo default two ' -cat > expected <<EOF +cat >expected <<\EOF changeset: 0:6e2126489d3d tag: tip user: A U Thor <author@example.com> @@ -300,13 +306,13 @@ test_expect_success 'remote push from master branch' ' git init gitrepo && cd gitrepo && git remote add origin "hg::../hgrepo" && - echo one > content && + echo one >content && git add content && git commit -a -m one && git push origin master ) && - hg -R hgrepo log > actual && + hg -R hgrepo log >actual && cat actual && test_cmp expected actual && @@ -322,7 +328,7 @@ test_expect_success 'remote cloning' ' ( hg init hgrepo && cd hgrepo && - echo zero > content && + echo zero >content && hg add content && hg commit -m zero ) && @@ -331,6 +337,17 @@ test_expect_success 'remote cloning' ' check gitrepo HEAD zero ' +test_expect_success 'moving remote clone' ' + test_when_finished "rm -rf gitrepo*" && + + ( + git clone "hg::hgrepo" gitrepo && + mv gitrepo gitrepo2 && + cd gitrepo2 && + git fetch + ) +' + test_expect_success 'remote update bookmark' ' test_when_finished "rm -rf gitrepo*" && @@ -343,7 +360,7 @@ test_expect_success 'remote update bookmark' ' git clone "hg::hgrepo" gitrepo && cd gitrepo && git checkout --quiet devel && - echo devel > content && + echo devel >content && git commit -a -m devel && git push --quiet ) && @@ -358,7 +375,7 @@ test_expect_success 'remote new bookmark' ' git clone "hg::hgrepo" gitrepo && cd gitrepo && git checkout --quiet -b feature-b && - echo feature-b > content && + echo feature-b >content && git commit -a -m feature-b && git push --quiet origin feature-b ) && @@ -374,15 +391,15 @@ test_expect_success 'remote push diverged' ' ( cd hgrepo && hg checkout default && - echo bump > content && + echo bump >content && hg commit -m bump ) && ( cd gitrepo && - echo diverge > content && + echo diverge >content && git commit -a -m diverged && - check_push 1 <<-EOF + check_push 1 <<-\EOF master:non-fast-forward EOF ) && @@ -403,16 +420,16 @@ test_expect_success 'remote update bookmark diverge' ' ( cd hgrepo && - echo "bump bookmark" > content && + echo "bump bookmark" >content && hg commit -m "bump bookmark" ) && ( cd gitrepo && git checkout --quiet diverge && - echo diverge > content && + echo diverge >content && git commit -a -m diverge && - check_push 1 <<-EOF + check_push 1 <<-\EOF diverge:fetch-first EOF ) && @@ -427,7 +444,7 @@ test_expect_success 'remote new bookmark multiple branch head' ' git clone "hg::hgrepo" gitrepo && cd gitrepo && git checkout --quiet -b feature-c HEAD^ && - echo feature-c > content && + echo feature-c >content && git commit -a -m feature-c && git push --quiet origin feature-c ) && @@ -438,24 +455,92 @@ test_expect_success 'remote new bookmark multiple branch head' ' # cleanup previous stuff rm -rf hgrepo +test_expect_success 'fetch special filenames' ' + test_when_finished "rm -rf hgrepo gitrepo && LC_ALL=C" && + + LC_ALL=en_US.UTF-8 + export LC_ALL + + ( + hg init hgrepo && + cd hgrepo && + + echo test >> "æ rø" && + hg add "æ rø" && + echo test >> "ø~?" && + hg add "ø~?" && + hg commit -m add-utf-8 && + echo test >> "æ rø" && + hg commit -m test-utf-8 && + hg rm "ø~?" && + hg mv "æ rø" "ø~?" && + hg commit -m hg-mv-utf-8 + ) && + + ( + git clone "hg::hgrepo" gitrepo && + cd gitrepo && + git -c core.quotepath=false ls-files > ../actual + ) && + echo "ø~?" > expected && + test_cmp expected actual +' + +test_expect_success 'push special filenames' ' + test_when_finished "rm -rf hgrepo gitrepo && LC_ALL=C" && + + mkdir -p tmp && cd tmp && + + LC_ALL=en_US.UTF-8 + export LC_ALL + + ( + hg init hgrepo && + cd hgrepo && + + echo one >> content && + hg add content && + hg commit -m one + ) && + + ( + git clone "hg::hgrepo" gitrepo && + cd gitrepo && + + echo test >> "æ rø" && + git add "æ rø" && + git commit -m utf-8 && + + git push + ) && + + (cd hgrepo && + hg update && + hg manifest > ../actual + ) && + + printf "content\næ rø\n" > expected && + test_cmp expected actual +' + setup_big_push () { ( hg init hgrepo && cd hgrepo && - echo zero > content && + echo zero >content && hg add content && hg commit -m zero && hg bookmark bad_bmark1 && - echo one > content && + echo one >content && hg commit -m one && hg bookmark bad_bmark2 && hg bookmark good_bmark && hg bookmark -i good_bmark && hg -q branch good_branch && - echo "good branch" > content && + echo "good branch" >content && hg commit -m "good branch" && hg -q branch bad_branch && - echo "bad branch" > content && + echo "bad branch" >content && hg commit -m "bad branch" ) && @@ -463,40 +548,40 @@ setup_big_push () { ( cd gitrepo && - echo two > content && + echo two >content && git commit -q -a -m two && git checkout -q good_bmark && - echo three > content && + echo three >content && git commit -q -a -m three && git checkout -q bad_bmark1 && git reset --hard HEAD^ && - echo four > content && + echo four >content && git commit -q -a -m four && git checkout -q bad_bmark2 && git reset --hard HEAD^ && - echo five > content && + echo five >content && git commit -q -a -m five && git checkout -q -b new_bmark master && - echo six > content && + echo six >content && git commit -q -a -m six && git checkout -q branches/good_branch && - echo seven > content && + echo seven >content && git commit -q -a -m seven && - echo eight > content && + echo eight >content && git commit -q -a -m eight && git checkout -q branches/bad_branch && git reset --hard HEAD^ && - echo nine > content && + echo nine >content && git commit -q -a -m nine && git checkout -q -b branches/new_branch master && - echo ten > content && + echo ten >content && git commit -q -a -m ten ) } @@ -509,7 +594,7 @@ test_expect_success 'remote big push' ' ( cd gitrepo && - check_push 1 --all <<-EOF + check_push 1 --all <<-\EOF master good_bmark branches/good_branch @@ -537,17 +622,17 @@ test_expect_success 'remote big push fetch first' ' ( hg init hgrepo && cd hgrepo && - echo zero > content && + echo zero >content && hg add content && hg commit -m zero && hg bookmark bad_bmark && hg bookmark good_bmark && hg bookmark -i good_bmark && hg -q branch good_branch && - echo "good branch" > content && + echo "good branch" >content && hg commit -m "good branch" && hg -q branch bad_branch && - echo "bad branch" > content && + echo "bad branch" >content && hg commit -m "bad branch" ) && @@ -556,39 +641,37 @@ test_expect_success 'remote big push fetch first' ' ( cd hgrepo && hg bookmark -f bad_bmark && - echo update_bmark > content && + echo update_bmark >content && hg commit -m "update bmark" ) && ( cd gitrepo && - echo two > content && + echo two >content && git commit -q -a -m two && git checkout -q good_bmark && - echo three > content && + echo three >content && git commit -q -a -m three && git checkout -q bad_bmark && - echo four > content && + echo four >content && git commit -q -a -m four && git checkout -q branches/bad_branch && - echo five > content && + echo five >content && git commit -q -a -m five && - check_push 1 --all <<-EOF + check_push 1 --all <<-\EOF && master good_bmark - new_bmark:new - new_branch:new bad_bmark:fetch-first branches/bad_branch:festch-first EOF git fetch && - check_push 1 --all <<-EOF + check_push 1 --all <<-\EOF master good_bmark bad_bmark:non-fast-forward @@ -597,7 +680,7 @@ test_expect_success 'remote big push fetch first' ' ) ' -test_expect_failure 'remote big push force' ' +test_expect_success 'remote big push force' ' test_when_finished "rm -rf hgrepo gitrepo*" && setup_big_push @@ -605,7 +688,7 @@ test_expect_failure 'remote big push force' ' ( cd gitrepo && - check_push 0 --force --all <<-EOF + check_push 0 --force --all <<-\EOF master good_bmark branches/good_branch @@ -627,7 +710,7 @@ test_expect_failure 'remote big push force' ' check_bookmark hgrepo new_bmark six ' -test_expect_failure 'remote big push dry-run' ' +test_expect_success 'remote big push dry-run' ' test_when_finished "rm -rf hgrepo gitrepo*" && setup_big_push @@ -635,7 +718,7 @@ test_expect_failure 'remote big push dry-run' ' ( cd gitrepo && - check_push 0 --dry-run --all <<-EOF + check_push 1 --dry-run --all <<-\EOF && master good_bmark branches/good_branch @@ -646,7 +729,7 @@ test_expect_failure 'remote big push dry-run' ' branches/bad_branch:non-fast-forward EOF - check_push 0 --dry-run master good_bmark new_bmark branches/good_branch branches/new_branch <<-EOF + check_push 0 --dry-run master good_bmark new_bmark branches/good_branch branches/new_branch <<-\EOF master good_bmark branches/good_branch @@ -671,10 +754,10 @@ test_expect_success 'remote double failed push' ' ( hg init hgrepo && cd hgrepo && - echo zero > content && + echo zero >content && hg add content && hg commit -m zero && - echo one > content && + echo one >content && hg commit -m one ) && @@ -682,7 +765,7 @@ test_expect_success 'remote double failed push' ' git clone "hg::hgrepo" gitrepo && cd gitrepo && git reset --hard HEAD^ && - echo two > content && + echo two >content && git commit -a -m two && test_expect_code 1 git push && test_expect_code 1 git push diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh index 7d7af03274..dc59a91031 100755 --- a/contrib/subtree/git-subtree.sh +++ b/contrib/subtree/git-subtree.sh @@ -9,10 +9,10 @@ if [ $# -eq 0 ]; then fi OPTS_SPEC="\ git subtree add --prefix=<prefix> <commit> -git subtree add --prefix=<prefix> <repository> <commit> +git subtree add --prefix=<prefix> <repository> <ref> git subtree merge --prefix=<prefix> <commit> -git subtree pull --prefix=<prefix> <repository> <refspec...> -git subtree push --prefix=<prefix> <repository> <refspec...> +git subtree pull --prefix=<prefix> <repository> <ref> +git subtree push --prefix=<prefix> <repository> <ref> git subtree split --prefix=<prefix> <commit...> -- h,help show the help @@ -489,6 +489,12 @@ ensure_clean() fi } +ensure_valid_ref_format() +{ + git check-ref-format "refs/heads/$1" || + die "'$1' does not look like a ref" +} + cmd_add() { if [ -e "$dir" ]; then @@ -508,8 +514,7 @@ cmd_add() # specified directory. Allowing a refspec might be # misleading because we won't do anything with any other # branches fetched via the refspec. - git rev-parse -q --verify "$2^{commit}" >/dev/null || - die "'$2' does not refer to a commit" + ensure_valid_ref_format "$2" "cmd_add_repository" "$@" else @@ -699,7 +704,11 @@ cmd_merge() cmd_pull() { + if [ $# -ne 2 ]; then + die "You must provide <repository> <ref>" + fi ensure_clean + ensure_valid_ref_format "$2" git fetch "$@" || exit $? revs=FETCH_HEAD set -- $revs @@ -709,8 +718,9 @@ cmd_pull() cmd_push() { if [ $# -ne 2 ]; then - die "You must provide <repository> <refspec>" + die "You must provide <repository> <ref>" fi + ensure_valid_ref_format "$2" if [ -e "$dir" ]; then repository=$1 refspec=$2 diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt index e0957eee55..02669b1534 100644 --- a/contrib/subtree/git-subtree.txt +++ b/contrib/subtree/git-subtree.txt @@ -9,10 +9,10 @@ git-subtree - Merge subtrees together and split repository into subtrees SYNOPSIS -------- [verse] -'git subtree' add -P <prefix> <refspec> -'git subtree' add -P <prefix> <repository> <refspec> -'git subtree' pull -P <prefix> <repository> <refspec...> -'git subtree' push -P <prefix> <repository> <refspec...> +'git subtree' add -P <prefix> <commit> +'git subtree' add -P <prefix> <repository> <ref> +'git subtree' pull -P <prefix> <repository> <ref> +'git subtree' push -P <prefix> <repository> <ref> 'git subtree' merge -P <prefix> <commit> 'git subtree' split -P <prefix> [OPTIONS] [<commit>] @@ -68,7 +68,7 @@ COMMANDS -------- add:: Create the <prefix> subtree by importing its contents - from the given <refspec> or <repository> and remote <refspec>. + from the given <commit> or <repository> and remote <ref>. A new commit is created automatically, joining the imported project's history with your own. With '--squash', imports only a single commit from the subproject, rather than its @@ -90,13 +90,13 @@ merge:: pull:: Exactly like 'merge', but parallels 'git pull' in that - it fetches the given commit from the specified remote + it fetches the given ref from the specified remote repository. push:: Does a 'split' (see below) using the <prefix> supplied and then does a 'git push' to push the result to the - repository and refspec. This can be used to push your + repository and ref. This can be used to push your subtree to different branches of the remote repository. split:: |