diff options
Diffstat (limited to 'bin/incremental-git-filterbranch')
-rwxr-xr-x | bin/incremental-git-filterbranch | 796 |
1 files changed, 796 insertions, 0 deletions
diff --git a/bin/incremental-git-filterbranch b/bin/incremental-git-filterbranch new file mode 100755 index 0000000..eb24b0f --- /dev/null +++ b/bin/incremental-git-filterbranch @@ -0,0 +1,796 @@ +#!/bin/sh +# +# Wrapper for git-filter-branch so that we can use it in an incremental +# way. +# +# Copyright (c) Michele Locati, 2018 +# +# MIT license +# https://github.com/mlocati/incremental-git-filter-branch/blob/master/LICENSE +# + +# Exit immediately if a pipeline, a list, or a compound command, exits with a non-zero status. +set -o errexit +# Treat unset variables and parameters other than the special parameters "@" and "*" as an error when performing parameter expansion. +set -o nounset +# Set the Internal Field Separator +IFS=' +' + +# Exit with 1. +# +# Arguments: +# $1: the message to be printed +die () { + printf '%s\n' "${1}">&2 + exit 1 +} + + +# Print the usage and exit. +# +# Arguments: +# $1 [optional]: if specified, a short usage message will be printed and we'll exit with 1; +# if not specified: a full syntax will be printed and we'll exit with 0 +usage () { + if test $# -eq 1 + then + printf '%s\n\n%s\n' "${1}" "Type ${0} --help to get help">&2 + exit 1 + fi + printf '%s' "Usage: +${0} [-h | --help] [--workdir <workdirpath>] + [--branch-whitelist <whitelist>] [--branch-blacklist <blacklist>] + [--tag-whitelist <whitelist>] [--tag-blacklist <blacklist>] + [--tags-plan (visited|all|none)] + [--tags-max-history-lookup <depth>] + [--no-hardlinks] [--no-atomic] [--no-lock] [--] + <sourcerepository> <filter> <destinationrepository> + Apply git filter-branch in an incremental way + +Where: + +--workdir workdirpath + set the path to the directory where the temporary local repositories are created. + By default, we'll use a directory named temp in the current directory. +--branch-whitelist <whitelist> + a whitespace-separated list of branches to be included in the process. + Multiple options can be specified. + By default, all branches will be processed. +--branch-blacklist <blacklist> + a whitespace-separated list of branches to be excluded from the process. + Multiple options can be specified. + By default, all branches will be processed. + Blacklisted branches take the precedence over whitelisted ones. +--tag-whitelist <whitelist> + a whitespace-separated list of tags to be included in the process. + Multiple options can be specified. +--tag-blacklist <blacklist> + a whitespace-separated list of tags to be excluded from the process. + Multiple options can be specified. + Blacklisted tags take the precedence over whitelisted ones. +--tags-plan + how tags should be processed. This can be one of these values: + visited: process only the tags visited (default) + none: do not process any tag + all: process all tags +--tags-max-history-lookup + limit the depth when looking for best matched filtered commit when --tags-plan is 'all'. + By default this value is 20. +--no-hardlinks + Do not create hard links (useful for file systems that don't support it). +--no-atomic + Do not use an atomic transaction when pushing to the destination repository. +--no-lock + Do not acquire an exclusive lock (useful for systems that don't have flock(1)). +sourcerepository + The URL or path to the source repository. +filter + The list of parameters to be passed to the git filter-branch command. +destinationrepository + The URL or path to the destination repository. + +You can prefix branch/tag names in both whitelists and blacklists with 'rx:': in this case a regular expression check will be performed. +For instance: --branch-whitelist 'master rx:release\\/\\d+(\\.\\d+)*' will match 'master' and 'release/1.1' +" + exit 0 +} + + +# Parse the command arguments and exits in case of errors. +# +# Arguments: +# $@: all the command line parameters +readParameters () { + WORK_DIRECTORY="$(pwd)/temp" + BRANCH_WHITELIST='' + BRANCH_BLACKLIST='' + TAG_WHITELIST='' + TAG_BLACKLIST='' + TAGS_PLAN='visited' + PROCESS_TAGS_MAXHISTORYLOOKUP=20 + NO_HARDLINKS='' + ATOMIC='--atomic' + NO_LOCK='' + while : + do + if test $# -lt 1 + then + usage 'Not enough arguments' + fi + readParameters_currentArgument="${1}" + case "${readParameters_currentArgument}" in + --) + shift 1 + break + ;; + -h|--help) + usage + ;; + --workdir) + if test $# -lt 2 + then + usage 'Not enough arguments' + fi + WORK_DIRECTORY="${2}" + if test -z "${WORK_DIRECTORY}" + then + die 'The working directory option is empty' + fi + shift 2 + ;; + --branch-whitelist) + if test $# -lt 2 + then + usage 'Not enough arguments' + fi + BRANCH_WHITELIST="${BRANCH_WHITELIST} ${2}" + shift 2 + ;; + --branch-blacklist) + if test $# -lt 2 + then + usage 'Not enough arguments' + fi + BRANCH_BLACKLIST="${BRANCH_BLACKLIST} ${2}" + shift 2 + ;; + --tag-whitelist) + if test $# -lt 2 + then + usage 'Not enough arguments' + fi + TAG_WHITELIST="${TAG_WHITELIST} ${2}" + shift 2 + ;; + --tag-blacklist) + if test $# -lt 2 + then + usage 'Not enough arguments' + fi + TAG_BLACKLIST="${TAG_BLACKLIST} ${2}" + shift 2 + ;; + --tags-plan) + if test $# -lt 2 + then + usage 'Not enough arguments' + fi + case "${2}" in + 'all') + TAGS_PLAN='all' + ;; + 'visited') + TAGS_PLAN='visited' + ;; + 'none') + TAGS_PLAN='' + ;; + *) + usage "Invalid value of the ${readParameters_currentArgument} option" + ;; + esac + shift 2 + ;; + --tags-max-history-lookup) + if test $# -lt 2 + then + usage 'Not enough arguments' + fi + PROCESS_TAGS_MAXHISTORYLOOKUP="${BRANCH_BLACKLIST} ${2}" + if ! test "${PROCESS_TAGS_MAXHISTORYLOOKUP}" -eq "${PROCESS_TAGS_MAXHISTORYLOOKUP}" 2>/dev/null + then + usage "Value of ${readParameters_currentArgument} should be numeric" + fi + if test "${PROCESS_TAGS_MAXHISTORYLOOKUP}" -lt 1 + then + usage "Value of ${readParameters_currentArgument} should be greater than 0" + fi + shift 2 + ;; + --no-hardlinks) + NO_HARDLINKS='--no-hardlinks' + shift 1 + ;; + --no-atomic) + ATOMIC='--no-atomic' + shift 1 + ;; + --no-lock) + NO_LOCK='yes' + shift 1 + ;; + -*) + usage "Unknown option: ${readParameters_currentArgument}" + ;; + *) + break + ;; + esac + done + if test -z "${TAGS_PLAN}" + then + if test -n "${TAG_WHITELIST}" -o -n "${TAG_BLACKLIST}" + then + die "You can't use --tag-whitelist or --tag-blacklist when you specify '--tags-plan none'" + fi + fi + if test $# -lt 3 + then + usage 'Not enough arguments' + fi + if test $# -gt 3 + then + usage 'Too many arguments' + fi + SOURCE_REPOSITORY_URL="${1}" + if test -z "${SOURCE_REPOSITORY_URL}" + then + die 'The source repository location is empty.' + fi + SOURCE_REPOSITORY_URL=$(absolutizePath "${SOURCE_REPOSITORY_URL}") + FILTER="${2}" + if test -z "${FILTER}" + then + die 'The filter is empty.' + fi + checkFilter ${FILTER} + DESTINATION_REPOSITORY_URL="${3}" + if test -z "${DESTINATION_REPOSITORY_URL}" + then + die 'The destination repository location is empty.' + fi + DESTINATION_REPOSITORY_URL=$(absolutizePath "${DESTINATION_REPOSITORY_URL}") +} + + +# Check if a string is a directory. If so, return its absolute path, otherwise the string itself. +# +# Arguments: +# $1: the string to be checked +# +# Output: +# The absolute path (if found), or $1 +absolutizePath () { + if test -d "${1}" + then + printf '%s' "$(cd "${1}" && pwd)" + else + printf '%s' "${1}" + fi +} + + +# Check the contents of the <filter> argument and die in case of errors. +# +# Arguments: +# $@: all parts of the filter +checkFilter () { + checkFilter_some=0 + while test $# -ge 1 + do + checkFilter_some=1 + checkFilter_optName="${1}" + shift 1 + case "${checkFilter_optName}" in + --setup) + if test $# -lt 1 + then + die "Invalid syntax in filter (${checkFilter_optName} without command)" + fi + shift 1 + ;; + --tag-name-filter) + die "You can't use --tag-name-filter (it's handled automatically)" + ;; + --*-filter) + if test $# -lt 1 + then + die "Invalid syntax in filter (${checkFilter_optName} without command)" + fi + shift 1 + ;; + --prune-empty) + ;; + *) + die "Invalid syntax in filter (unknown option: ${checkFilter_optName})" + ;; + esac + done + if test ${checkFilter_some} -lt 1 + then + die 'The filter is empty.' + fi +} + + +# Check that the system has the required commands, and exit in case of problems. +checkEnvironment () { + if test -z "${NO_LOCK}" + then + if ! command -v flock >/dev/null + then + die 'The flock command is not available. You may want to use --no-lock option to avoid using it (but no concurrency check will be performed).' + fi + fi + for checkEnvironment_command in git sed grep md5sum + do + if ! command -v "${checkEnvironment_command}" >/dev/null + then + die "The required ${checkEnvironment_command} command is not available." + fi + done + checkEnvironment_vMin='2.15.0' + checkEnvironment_vCur=$(git --version | cut -d ' ' -f3) + checkEnvironment_vWork=$(printf '%s\n%s' "${checkEnvironment_vCur}" "${checkEnvironment_vMin}" | sort -t '.' -n -k1,1 -k2,2 -k3,3 -k4,4 | head -n 1) + if test "${checkEnvironment_vWork}" != "${checkEnvironment_vMin}" + then + die "This script requires git ${checkEnvironment_vMin} (you have git ${checkEnvironment_vWork})." + fi +} + + +# Initialize the working directory and associated variables, and exit in case of problems. +initializeEnvironment () { + if ! test -d "${WORK_DIRECTORY}" + then + mkdir --parents -- "${WORK_DIRECTORY}" || die "Failed to create the working directory ${WORK_DIRECTORY}" + fi + WORK_DIRECTORY=$(absolutizePath "${WORK_DIRECTORY}") + SOURCE_REPOSITORY_DIR=${WORK_DIRECTORY}/source-$(md5 "${SOURCE_REPOSITORY_URL}") + WORKER_REPOSITORY_DIR=${WORK_DIRECTORY}/worker-$(md5 "${SOURCE_REPOSITORY_URL}${DESTINATION_REPOSITORY_URL}") +} + + +# Acquire a lock (if allowed by options): we'll return from this function once the lock has been acquired +acquireLock () { + if test -z "${NO_LOCK}" + then + exec 9>"${WORKER_REPOSITORY_DIR}.lock" + while : + do + if flock --exclusive --timeout 3 9 + then + break + fi + echo 'Lock detected... Waiting that it becomes available...' + done + fi +} + + +# Create or update the mirror of the source repository. +prepareLocalSourceRepository () { + prepareLocalSourceRepository_haveToCreateMirror=1 + if test -f "${SOURCE_REPOSITORY_DIR}/config" + then + echo '# Updating source repository' + if git -C "${SOURCE_REPOSITORY_DIR}" remote update --prune + then + prepareLocalSourceRepository_haveToCreateMirror=0 + fi + fi + if test ${prepareLocalSourceRepository_haveToCreateMirror} -eq 1 + then + echo '# Cloning source repository' + rm -rf "${SOURCE_REPOSITORY_DIR}" + git clone --mirror "${SOURCE_REPOSITORY_URL}" "${SOURCE_REPOSITORY_DIR}" + fi +} + + +# Store in the SOURCE_BRANCHES variable the list of the branches in the source repository. +# Exit if no branch can be found. +getSourceRepositoryBranches () { + echo '# Listing source branches' + # List all branches and takes only the part after "refs/heads/", and store them in the SOURCE_BRANCHES variable + SOURCE_BRANCHES=$(git -C "${SOURCE_REPOSITORY_DIR}" show-ref --heads | sed -E 's:^.*?refs/heads/::') + if test -z "${SOURCE_BRANCHES}" + then + die 'Failed to retrieve branch list' + fi +} + + +# Get the tags that exist in a specific branch of the source repository. +# +# Arguments: +# $1: the branch name +# +# Output: +# The list of tags (one per line) +getSourceRepositoryTagsInBranch () { + git -C "${SOURCE_REPOSITORY_DIR}" tag --list --merged "refs/heads/${1}" 2>/dev/null || true +} + + +# Get the list of all the tags that exist in a repository. +# +# Arguments: +# $1: the directory of the repository +# +# Output: +# The list of tags (one per line) +getTagList () { + # List all tags and takes only the part after "refs/heads/" + git -C "${1}" show-ref --tags | sed -E 's:^.*?refs/tags/::' || true +} + + +# Check if a string is in a white/black list. +# +# Arguments: +# $1: the string to be checked +# $2: the white/black list +# +# Return: +# 0 (true): if the string is in the list +# 1 (false): if the string is not in the list +stringInList () { + for stringInList_listItem in ${2} + do + if test -n "${stringInList_listItem}" + then + case "${stringInList_listItem}" in + rx:*) + stringInList_substring=$(printf '%s' "${stringInList_listItem}" | cut -c4-) + if printf '%s' "${1}" | grep -Eq "^${stringInList_substring}$" + then + return 0 + fi + ;; + *) + if test "${1}" = "${stringInList_listItem}" + then + return 0 + fi + ;; + esac + fi + done + return 1 +} + + +# Check if a string satisfies whitelist and blacklist checks. +# +# Arguments: +# $1: the string to be checked +# $2: the whitelist +# $3: the blacklist +# +# Return: +# 0 (true): if the string satisfies the criteria +# 1 (false): if the string does not satisfy the criteria +stringPassesLists () { + if stringInList "${1}" "${3}" + then + return 1 + fi + if test -z "${2}" + then + return 0 + fi + if stringInList "${1}" "${2}" + then + return 0 + fi + return 1 +} + + +# Store in the WORK_BRANCHES variable the list of the branches to be processed (checking the white/black lists). +# Die if no branch can be found. +getBranchesToProcess () { + echo '# Determining the branches to be processed' + WORK_BRANCHES='' + for getBranchesToProcess_branch in ${SOURCE_BRANCHES} + do + if stringPassesLists "${getBranchesToProcess_branch}" "${BRANCH_WHITELIST}" "${BRANCH_BLACKLIST}" + then + WORK_BRANCHES="${WORK_BRANCHES} ${getBranchesToProcess_branch}" + fi + done + if test -z "${WORK_BRANCHES}" + then + die 'None of the source branches passes the whitelist/blacklist filter' + fi +} + + +# Create the worker repository (if it does not already exist) +prepareWorkerRepository () { + prepareWorkerRepository_haveToCreateRepo=1 + if test -f "${WORKER_REPOSITORY_DIR}/.git/config" + then + echo '# Checking working repository' + if git -C "${WORKER_REPOSITORY_DIR}" rev-parse --git-dir >/dev/null 2>/dev/null + then + prepareWorkerRepository_haveToCreateRepo=0 + fi + fi + if test ${prepareWorkerRepository_haveToCreateRepo} -eq 1 + then + echo '# Creating working repository' + rm -rf "${WORKER_REPOSITORY_DIR}" + echo '# Adding mirror source repository to working repository' + git clone ${NO_HARDLINKS} --local --origin source "${SOURCE_REPOSITORY_DIR}" "${WORKER_REPOSITORY_DIR}" + echo '# Adding destination repository to working repository' + if ! git -C "${WORKER_REPOSITORY_DIR}" remote add destination "${DESTINATION_REPOSITORY_URL}" + then + rm -rf "${WORKER_REPOSITORY_DIR}" + exit 1 + fi + echo '# Fetching data from cloned destination repository' + if ! git -C "${WORKER_REPOSITORY_DIR}" fetch --prune destination + then + rm -rf "${WORKER_REPOSITORY_DIR}" + exit 1 + fi + fi +} + + +# Process a branch, fetching it from the mirror of the source repository. +# Any relevat tag will also be processed. +# +# Arguments: +# $1: the name of the branch to work with +processBranch () { + echo ' - fetching' + git -C "${WORKER_REPOSITORY_DIR}" fetch --quiet --tags source "${1}" + echo ' - checking-out' + git -C "${WORKER_REPOSITORY_DIR}" checkout --quiet --force -B "filter-branch/source/${1}" "remotes/source/${1}" + echo ' - determining delta' + processBranch_range="filter-branch/result/${1}" + processBranch_last=$(git -C "${WORKER_REPOSITORY_DIR}" show-ref -s "refs/heads/filter-branch/filtered/${1}" || true) + if test -n "${processBranch_last}" + then + processBranch_range="${processBranch_last}..${processBranch_range}" + fi + processBranch_fetchHead=$(git -C "${WORKER_REPOSITORY_DIR}" rev-parse FETCH_HEAD) + if test "${processBranch_last}" = "${processBranch_fetchHead}" + then + echo ' - nothing new, skipping' + else + echo ' - initializing filter' + rm -f "${WORKER_REPOSITORY_DIR}/.git/refs/filter-branch/originals/${1}/refs/heads/filter-branch/result/${1}" + git -C "${WORKER_REPOSITORY_DIR}" branch --force "filter-branch/result/${1}" FETCH_HEAD + rm -rf "${WORKER_REPOSITORY_DIR}.filter-branch" + echo " - filtering commits" + processBranch_tags='' + if test -z "${TAGS_PLAN}" + then + processBranch_tags='' + else + processBranch_tags=$(getSourceRepositoryTagsInBranch "${1}") + fi + if test -z "${processBranch_tags}" + then + processBranch_tagNameFilter='' + else + # shellcheck disable=SC2016 + processBranch_tagNameFilter='read -r tag; printf "filter-branch/converted-tags/%s" "${tag}"' + fi + rm -rf "${WORKER_REPOSITORY_DIR}.map" + exec 3>&1 + # shellcheck disable=SC2086 + if processBranch_stdErr=$(git -C "${WORKER_REPOSITORY_DIR}" filter-branch \ + ${FILTER} \ + --remap-to-ancestor \ + --tag-name-filter "${processBranch_tagNameFilter}" \ + -d "${WORKER_REPOSITORY_DIR}.filter-branch" \ + --original "refs/filter-branch/originals/${1}" \ + --state-branch "refs/filter-branch/state" \ + --force \ + -- "${processBranch_range}" \ + 1>&3 2>&1 | tee /dev/stderr + ) + then + processBranch_rc=0 + else + processBranch_rc=1 + fi + exec 3>&- + if test "${processBranch_rc}" -ne 0 + then + if test -n "${processBranch_stdErr##*Found nothing to rewrite*}" + then + die 'git failed' + fi + else + if test "${TAGS_PLAN}" = 'all' -a -n "${processBranch_tags}" + then + if ! processBranchTag_availableTags="$(git -C "${WORKER_REPOSITORY_DIR}" tag --list | grep -E '^filter-branch/converted-tags/' | sed -E 's:^filter-branch/converted-tags/::')" + then + processBranchTag_availableTags='' + fi + for processBranch_tag in ${processBranch_tags} + do + if ! itemInList "${processBranch_tag}" "${processBranchTag_availableTags}" + then + if stringPassesLists "${processBranch_tag}" "${TAG_WHITELIST}" "${TAG_BLACKLIST}" + then + processNotConvertedTag "${processBranch_tag}" + fi + fi + done + fi + fi + echo " - storing state" + git -C "${WORKER_REPOSITORY_DIR}" branch -f "filter-branch/filtered/${1}" FETCH_HEAD + fi +} + + +# Print the SHA-1 hash of the tag of the work repository (if found). +# +# Arguments: +# $1: the name of the tag +# +# Output: +# The SHA-1 of the tag, or nothing if the tag does not exist +getWorkingTagHash () { + git -C "${WORKER_REPOSITORY_DIR}" rev-list -n 1 "refs/tags/${1}" 2>/dev/null || true +} + + +# Print the SHA-1 hash of the nearest translated commit corresponding to a specific original commit. +# +# Arguments: +# $1: the SHA-1 hash of the original commit +# $2: the allowed history depth +# +# Output: +# The SHA-1 hash of the translated commit (if it can be found within $2 depth), or nothing otherwise +# +# Return: +# 0 (true): if the translated commit has been found (and printed) +# 1 (false): if the translated commit couldn't be found +getTranslatedNearestCommitHash () { + if test "${2}" -lt 1 -o -z "${PROCESS_TAGS_VISITEDHASHES##* ${1} *}" + then + return 1 + fi + PROCESS_TAGS_VISITEDHASHES="${PROCESS_TAGS_VISITEDHASHES}${1} " + if getTranslatedNearestCommitHash_v="$(grep -E "^${1}:" "${WORKER_REPOSITORY_DIR}.map")" + then + printf '%s' "${getTranslatedNearestCommitHash_v#${1}:}" + return 0 + fi + for getTranslatedNearestCommitHash_v in $(git -C "${WORKER_REPOSITORY_DIR}" rev-list --parents -n 1 "${1}") + do + if test "${getTranslatedNearestCommitHash_v}" != "${1}" + then + if getTranslatedNearestCommitHash "${getTranslatedNearestCommitHash_v}" "$(( $2 - 1))" + then + return 0 + fi + fi + done + return 1 +} + + +# Tries to create a new translated tag, associating it to the nearest translated commit +# +# Arguments: +# $1: the name of the tag to be translated +processNotConvertedTag () { + printf ' - remapping tag %s\n' "${1}" + processNotConvertedTag_tagOriginalHash="$(getWorkingTagHash "${1}")" + if test -z "${processNotConvertedTag_tagOriginalHash}" + then + printf 'Failed to get hash of tag %s\n' "${1}">&2 + exit 1 + fi + if test ! -f "${WORKER_REPOSITORY_DIR}.map" + then + git -C "${WORKER_REPOSITORY_DIR}" show refs/filter-branch/state:filter.map >"${WORKER_REPOSITORY_DIR}.map" + fi + PROCESS_TAGS_VISITEDHASHES=' ' + if processNotConvertedTag_commitHash="$(getTranslatedNearestCommitHash "${processNotConvertedTag_tagOriginalHash}" "${PROCESS_TAGS_MAXHISTORYLOOKUP}")" + then + printf '%s -> filter-branch/converted-tags/%s (%s -> %s)\n' "${1}" "${1}" "${processNotConvertedTag_tagOriginalHash}" "${processNotConvertedTag_commitHash}" + git -C "${WORKER_REPOSITORY_DIR}" tag --force "filter-branch/converted-tags/${1}" "${processNotConvertedTag_commitHash}" + else + printf 'Failed to map tag %s\n' "${1}">&2 + fi +} + + +# Process all the branches listed in the WORK_BRANCHES variable, and push the result to the destination repository. +processBranches () { + processBranches_pushRefSpec='' + for processBranches_branch in ${WORK_BRANCHES} + do + echo "# Processing branch ${processBranches_branch}" + processBranch "${processBranches_branch}" + processBranches_pushRefSpec="${processBranches_pushRefSpec} filter-branch/result/${processBranches_branch}:${processBranches_branch}" + done + if test -n "${TAGS_PLAN}" + then + echo '# Listing source tags' + processBranches_sourceTags=$(getTagList "${SOURCE_REPOSITORY_DIR}") + echo '# Determining destination tags' + for processBranches_sourceTag in ${processBranches_sourceTags} + do + if stringPassesLists "${processBranches_sourceTag}" "${TAG_WHITELIST}" "${TAG_BLACKLIST}" + then + processBranches_rewrittenTag="filter-branch/converted-tags/${processBranches_sourceTag}" + if git -C "${WORKER_REPOSITORY_DIR}" rev-list --max-count=0 "${processBranches_rewrittenTag}" 2>/dev/null + then + processBranches_pushRefSpec="${processBranches_pushRefSpec} ${processBranches_rewrittenTag}:${processBranches_sourceTag}" + fi + fi + done + fi + echo "# Pushing to destination repository" + # shellcheck disable=SC2086 + git -C "${WORKER_REPOSITORY_DIR}" push --quiet --force ${ATOMIC} destination ${processBranches_pushRefSpec} +} + + +# Calculate the MD5 hash of a string. +# +# Arguments: +# $1: the string for which you want the MD5 hash +# +# Output: +# The MD5-1 hash of $1 +md5 () { + printf '%s' "${1}" | md5sum | sed -E 's: .*$::' +} + + +# Check if a string is in a list (separated by spaces, tabs or new lines) +# +# Arguments: +# $1: the string +# $2: the list of strings +# +# Return: +# 0 (true): $1 is in $2 +# 1 (false): $1 is not in $2 +itemInList () { + for itemInList_item in ${2} + do + if test "${1}" = "${itemInList_item}" + then + return 0 + fi + done + return 1 +} + + +readParameters "$@" +checkEnvironment +initializeEnvironment +acquireLock +prepareLocalSourceRepository +getSourceRepositoryBranches +getBranchesToProcess +prepareWorkerRepository +processBranches +echo "All done." |