📄 svnmerge.sh
字号:
#!/bin/sh## Copyright (c) 2004-2005, Awarix, Inc.# All rights reserved.## Subject to the following obligations and disclaimer of warranty,# use and redistribution of this software, in source or object code# forms, with or without modifications are expressly permitted by# Awarix; provided, however, that:## (i) Any and all reproductions of the source or object code# must include the copyright notice above and the following# disclaimer of warranties; and# (ii) No rights are granted, in any manner or form, to use# Awarix trademarks, including the mark "AWARIX"# on advertising, endorsements, or otherwise except as such# appears in the above copyright notice or in the software.## THIS SOFTWARE IS BEING PROVIDED BY AWARIX "AS IS", AND# TO THE MAXIMUM EXTENT PERMITTED BY LAW, AWARIX MAKES NO# REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING# THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,# OR NON-INFRINGEMENT. AWARIX DOES NOT WARRANT, GUARANTEE,# OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS# OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,# RELIABILITY OR OTHERWISE. IN NO EVENT SHALL AWARIX BE# LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE# OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL# DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF# USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF# THE USE OF THIS SOFTWARE, EVEN IF AWARIX IS ADVISED OF# THE POSSIBILITY OF SUCH DAMAGE.## Author: Archie Cobbs archie @ awarix dot com## Acknowledgements:# John Belmonte <john@neggie.net> - metadata and usability improvements## $HeadURL: https://svn.collab.net/repos/svn/branches/1.3.x/contrib/client-side/svnmerge.sh $# $LastChangedDate: 2006-03-10 08:31:59 -0600 (Fri, 10 Mar 2006) $# $LastChangedBy: malcolm $# $LastChangedRevision: 18811 $# Definitions (would like ':' in property names but can't because of bug 1971)NAME="svnmerge"SVN_MERGE_SVN="svn"SVN_MERGE_PROP="${NAME}-integrated"SRCREV=`echo '$Rev: 18811 $' | sed 's/^\$Rev: \([0-9]\{1,\}\).\{0,\}$/\1/g'`SRCDATE=`echo '$Date: 2006-03-10 08:31:59 -0600 (Fri, 10 Mar 2006) $' | sed 's/^\$Date: .\{0,\}(\(.\{0,\}\)).\{0,\}$/\1/g'`# We expect non-localized outputLC_MESSAGES="C"export LC_MESSAGES# Subroutine to output usage messageusage(){ echo 'Usage:' echo " ${NAME} init [-s] [-v] [-n] [-r revs] [-f file] [src]" echo ' Initialize merge tracking from "src" on the current working' echo ' directory. "revs" specifies the already-merged in revisions;' echo ' it defaults to "1-HEAD", where HEAD is the latest revision of' echo ' "src", if "src" is specified; if "src" is omitted, then "src"' echo ' (and optionally "revs") are computed from the "svn cp" history' echo ' of the current working directory.' echo '' echo " ${NAME} avail [-s] [-v] [-l] [-d] [-r revs] [-S src] [dest]" echo ' Show unmerged revisions available for "dest" as a revision' echo ' list. If revision list "revs" is given, the revisions shown' echo ' will be limited to those also specified in "revs". If "dest"' echo ' is tracking only one source, "src" may be omitted.' echo ' Options specific to this command:' echo ' -l Show corresponding log history instead of revision list' echo ' -d Show corresponding diffs instead of revision list' echo '' echo " ${NAME} merge [-s] [-v] [-n] [-r revs] [-f file] [-S src] [dest]" echo ' Merge in revisions specified by "revs" into "dest" from the' echo ' given "src" location. "revs" is the revision list specifying' echo ' revisions to merge in. Already merged-in revisions will not be' echo ' merged in again. Default for "revs" is "1-HEAD" where HEAD is' echo ' the latest revision of the "src" repository (i.e., merge all' echo ' available). If "dest" is tracking only one source, "src" may' echo ' be omitted.' echo '' echo ' Options common to multiple commands:' echo ' -v Verbose mode: output more information about progress' echo ' -s Show subversion commands that make changes' echo " -n Don't actually change anything, just pretend; implies -s" echo ' -f Write a suitable commit log message into "file"' echo ' -r Specify a revision list, consisting of revision numbers' echo ' and ranges separated by commas, e.g., "534,537-539,540"' echo '' echo ' "src" may be a repository path or a working directory.' echo ' "dest" is always a working directory and defaults to ".".' echo " This is svnmerge revision ${SRCREV} dated ${SRCDATE}." echo '' exit 1}# Subroutine to output an error and bailerror(){ echo ${NAME}: ${1+"$@"} exit 1}# Subroutine to output progress message, unless in quiet modereport(){ if [ "${SVN_MERGE_VERBOSE}" != "" ]; then echo ${NAME}: ${1+"$@"} fi}# Subroutine to output an error, usage, and bailusage_error(){ echo ${NAME}: ${1+"$@"} usage}# Subroutine to do (or pretend to do) an SVN commandsvn_command(){ if [ "${SVN_MERGE_SHOW_CMDS}" != "" ]; then echo "${SVN_MERGE_SVN}" ${1+"$@"} fi if [ "${SVN_MERGE_PRETEND}" = "" ]; then "${SVN_MERGE_SVN}" ${1+"$@"} if [ $? -ne 0 ]; then error command failed: ${1+"$@"} fi fi}# Check the current status of ${BRANCH_DIR} for up-to-dateness and local modscheck_branch_dir(){ report "checking status of \"${BRANCH_DIR}\"" "${SVN_MERGE_SVN}" status -u "${BRANCH_DIR}" | grep -q '^.......\*' && \ error "\"${BRANCH_DIR}\" is not up to date; please \"svn update\" first" [ `"${SVN_MERGE_SVN}" stat -q "${BRANCH_DIR}" \ | sed '/^$/,$d' | wc -l` = "0" ] || \ error "\"${BRANCH_DIR}\" has local modifications; it must be clean"}# Subroutine to clean up an URL or pathnormalize_url(){ TEMP="$1" while true; do TEMP2=`echo "${TEMP}" | sed -e 's/$/\//g' \ -e 's/\/[^/]\{1,\}\/\.\.\//\//g' -e 's/\/\.\//\//g' \ -e 's/\([^:/]\)\/\//\1\//g' -e 's/\/$//g'` [ "${TEMP2}" != "${TEMP}" ] || break TEMP="${TEMP2}" done RETURN_VALUE="${TEMP}"}# Subroutine to parse out the start and end from a range like "123-456"get_start_end(){ START=`echo "$1" | sed 's/^\([0-9]\{1,\}\)-\([0-9]\{1,\}\)$/\1/g'` END=`echo "$1" | sed 's/^\([0-9]\{1,\}\)-\([0-9]\{1,\}\)$/\2/g'`}# Subroutine to get all integrated revisions for a given headget_all_integrated_revs(){ RETURN_VALUE=`"${SVN_MERGE_SVN}" propget "${SVN_MERGE_PROP}" "$1"`}# Subroutine to retrieve a target's integrated revisions for a given headget_integrated_revs(){ TEMP=`"${SVN_MERGE_SVN}" propget "${SVN_MERGE_PROP}" "$2" | grep "^${1}:"` [ -z "${TEMP}" ] && \ error no integration info available for repository path \"$1\" RETURN_VALUE="${TEMP#${1}:}"}# Subroutine to set a target's integrated revisions for a given headset_integrated_revs(){ TEMP=`"${SVN_MERGE_SVN}" propget "${SVN_MERGE_PROP}" "$3" | grep -v "^${1}:"` TEMP=`echo "${TEMP} ${1}:${2}" | xargs -n 1 | sort` svn_command propset -q "${SVN_MERGE_PROP}" "${TEMP}" "$3"}# Subroutine to retrieve the default head of the given targetget_default_head(){ # To make bi-directional merges easier, find the target's # repository local path so it can be removed from the list of # possible integration sources. target_to_url "$1" url_to_rlpath "${RETURN_VALUE}" RETURN_VALUE=`"${SVN_MERGE_SVN}" propget "${SVN_MERGE_PROP}" "$1" | cut -d: -f 1 | grep -v "^${RETURN_VALUE}$"` [ -z "${RETURN_VALUE}" ] && error no integration info available [ `echo "${RETURN_VALUE}" | wc -l` -gt 1 ] && \ error explicit \"src\" argument required}# Subroutine to parse, validate, and normalize a revision list.# This input has commas separating ranges and any additional whitespace.# The result has the form "123-123,125-127,128-130,132-132", i.e.,# sorted with all adjacent, empty, and redundant ranges merged.normalize_list(){ # Special case empty list TEMP=`echo "$1" | tr -d '[:space:]'` if [ "${TEMP}" = "" ]; then RETURN_VALUE="" return 0 fi # See if list is well formed NUMPAT='[0-9]\{1,\}' RNGPAT="${NUMPAT}\(-${NUMPAT}\)\{0,1\}" LISTPAT="\(,\{0,1\}${RNGPAT},\{0,1\}\)\{0,\}" expr "${TEMP}" : "${LISTPAT}\$" >/dev/null || \ usage_error invalid revision list \"$1\" # Now sort the list and compress out redundancies RESULT='' LAST_START='' LAST_END='' for RNG in `echo "${TEMP}" | tr , '\n' | sort -n -t - -k 1,2 \ | sed 's/^\([0-9]\{1,\}\)$/\1-\1/g'`; do # Get range start and end get_start_end "${RNG}" # First revision is #1 if [ "${START}" -le 0 ]; then START="1" fi # Completely ignore any empty ranges if [ "${START}" -gt "${END}" ]; then continue fi # First iteration? if [ "${LAST_START}" = "" ]; then LAST_START=${START} LAST_END=${END} continue fi # Does this range overlap with the previous? if [ "${START}" -le `expr "${LAST_END}" + 1` ]; then if [ "${END}" -gt "${LAST_END}" ]; then LAST_END=${END} fi continue fi # Break off discontigous range [ "${RESULT}" = "" ] || RESULT="${RESULT}," RESULT="${RESULT}${LAST_START}-${LAST_END}" LAST_START=${START} LAST_END=${END} done # Tack on final range if [ "${LAST_START}" != "" ]; then [ "${RESULT}" = "" ] || RESULT="${RESULT}," RESULT="${RESULT}${LAST_START}-${LAST_END}" fi # Done RETURN_VALUE="${RESULT}"}# Subroutine to compute the set $1 minus $2, where $1 and $2 are# *normalized* revision lists. This is also pretty gross.list_subtract(){ TEMP='' for ARNG in `echo $1 | tr ',' ' '`; do # Parse range get_start_end "${ARNG}" ASTART="${START}" AEND="${END}" # Iterate over subtracted ranges for BRNG in `echo $2 | tr ',' ' '`; do # Parse range get_start_end "${BRNG}" BSTART="${START}" BEND="${END}" # Is this BRNG entirely before or past ARNG? if [ ${ASTART} -gt ${BEND} ]; then continue elif [ ${BSTART} -gt ${AEND} ]; then break fi # Keep the initial part of ARNG missed by BRNG (if anything) [ "${TEMP}" = "" ] || TEMP="${TEMP}," TEMP="${TEMP}${ASTART}-`expr ${BSTART} - 1`" # Keep going with whatever remains of ARNG (if anything) if [ ${AEND} -gt ${BEND} ]; then ASTART=`expr ${BEND} + 1` else AEND=`expr ${ASTART} - 1` break fi done # Keep what's left of ARNG (if anything) [ "${TEMP}" = "" ] || TEMP="${TEMP}," TEMP="${TEMP}${ASTART}-${AEND}" done # Normalize the result normalize_list "${TEMP}"}# Subroutine to return a normalized list to a more pleasant formbeautify_list(){ TEMP='' for RNG in `echo "$1" | tr ',' ' '`; do get_start_end "${RNG}" [ "${TEMP}" = "" ] || TEMP="${TEMP}," TEMP="${TEMP}${START}" if [ "${END}" != "${START}" ]; then TEMP="${TEMP}-${END}" fi done RETURN_VALUE="${TEMP}"}# Subroutine to convert working copy path or repo URL $1 to a repo URLtarget_to_url(){ if [ -d "$1" -a -d "$1/.svn" ]; then RETURN_VALUE=`"${SVN_MERGE_SVN}" info "$1" \ | grep ^URL: | sed -e 's/^URL: \(.*\)$/\1/g'` else RETURN_VALUE="$1" fi}# Subroutine to compute the root repo URL given wc path or repo URL $1.# Constrained to svn command line tools, we are stuck with this ugly trial-# and-error implementation. It could be made faster with a binary search.get_repo_root(){ target_to_url "$1" while TEMP=`dirname ${RETURN_VALUE}` && "${SVN_MERGE_SVN}" proplist "${TEMP}" >/dev/null 2>&1; do RETURN_VALUE="${TEMP}" done}# Subroutine to convert repo URL $1 to a repo-local pathurl_to_rlpath(){ get_repo_root $1 RETURN_VALUE="${1#${RETURN_VALUE}}"}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -