-
Notifications
You must be signed in to change notification settings - Fork 0
/
monify
202 lines (171 loc) · 4.79 KB
/
monify
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#! /usr/local/bin/bash
# Example: monify create my_repo "api-module web-module mobile-module" https://[email protected]/project
# Example: monify clean
set -e
set -x
BASH_VERSION=$(/usr/bin/env bash --version)
if [[ $string = *"version 3"* ]]; then
echo "bash version 4 and higher is required."
exit
else
if [[ $string = *"version 4"* ]]; then
echo "bash version is good."
fi
fi
COMMAND=$1
if [[ $COMMAND == clean ]]; then
sudo unmount $TMPFS_DIR || :
rmdir $TMPFS_DIR || :
rm -rf $BUILD_DIR
exit
fi
REPO_NAME=$2
BUILD_DIR="$PWD/mega$REPO_NAME"
MERGED_DIR="$BUILD_DIR/uni$REPO_NAME"
GIT_URL=$4
REPOS=$3
INITIAL_COMMIT="init"
TMPFS_DIR="$BUILD_DIR/tmp"
GRAFTS_FILE="$MERGED_DIR/.git/info/grafts"
function clone_repos {
for repo in $REPOS; do
cd $BUILD_DIR
mkdir $repo
git clone --mirror "$GIT_URL/$repo.git" "$repo/.git"
cd $repo
git config --bool core.bare false
git reset --hard HEAD
# We dont want tto later filter the remote branches
# This is also a safeguard against pushing any changes we make to the server
git remote remove origin
done
}
# sed "s,\t\"*,&'"$1"'/,"
function move_to_dir {
repo_upper=$(echo $repo | tr /a-z/ /A-Z/)
git ls-files -s | sed "s, ,&"$1"/,"
case "$(uname -s)" in
Darwin)
echo 'Mac OS X'
git filter-branch -d "$TMPFS_DIR/$1" --tag-name-filter cat --index-filter '
git ls-files -s | gsed "s,\t\"*,&'"$1"'/," |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' --msg-filter '
echo "['$repo_upper']: " && cat
' -- --all;
;;
Linux)
echo 'Linux'
sudo mount -t tmpfs -o size=512m tmpfs $TMPFS_DIR
git filter-branch -d "$TMPFS_DIR/$1" --tag-name-filter cat --index-filter '
git ls-files -s | sed "s,\t\"*,&'"$1"'/," |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' --msg-filter '
echo -n "['$repo_upper']: " && cat
' -- --all;
;;
CYGWIN*|MINGW32*|MSYS*)
echo 'MS Windows is not supported.'
exit
;;
*)
echo 'OS is not supported.'
exit
;;
esac
}
function filter_all_branches {
# Setup tmpfs if on linux to speed up filtering
mkdir $TMPFS_DIR
case "$(uname -s)" in
Darwin)
echo 'Mac OS X'
;;
Linux)
echo 'Linux'
sudo mount -t tmpfs -o size=512m tmpfs $TMPFS_DIR
;;
CYGWIN*|MINGW32*|MSYS*)
echo 'MS Windows is not supported.'
exit
;;
*)
echo 'OS is not supported.'
exit
;;
esac
for repo in $REPOS; do
cd $BUILD_DIR/$repo
move_to_dir $repo
# Remove original refs
git for-each-ref --format="$(refname)" refs/original | xargs -n 1 git update-ref -d
git reflog expire --expire=now --all
git gc --prune=now
done
}
function setup_merged_repo {
# Creates and initializes the final merged repo, adds a remove for each repo to pull in
mkdir -p $MERGED_DIR
cd $MERGED_DIR
git init
touch .gitignore
git add .
git commit -m "Root commit to be shared (grafted) in merge"
git branch $INITIAL_COMMIT
INITIAL_COMMIT_HASH=$(git rev-list $INITIAL_COMMIT)
echo $INITIAL_COMMIT_HASH >> $GRAFTS_FILE
for repo in $REPOS; do
git remote add $repo $BUILD_DIR/$repo
# The following solution was taken from stackoverflow "git octopus merge with unrelated repositories"
# The octupus merge will fail since they have unrelated history
# Add each root of repo to the grafts file
cd $BUILD_DIR/$repo
for root in $(git rev-list --all --max-parents=0); do
echo $root $INITIAL_COMMIT_HASH >> $GRAFTS_FILE
done
cd $MERGED_DIR
done
}
function clean_merged_repo {
git branch -d $INITIAL_COMMIT
> $GRAFTS_FILE
for repo in $REPOS; do git remote remove $repo; done
}
function merge_branches {
# Expects <local_branch> <remote:branch>
# where the second argument is an associative array of repo name to branch to be merged
git checkout $INITIAL_COMMIT
git checkout -B "$1"
local -n branch_map=$2
BRANCHES_TO_MERGE=""
for remote in "${!branch_map[@]}"; do
git fetch ${remote} ${branch_map[${remote}]}
BRANCHES_TO_MERGE+="${remote}/${branch_map[${remote}]} "
done
# BRANCHES_TO_MERGE is purposely unquoted so the branches expand to seperate arguments
# this will be one large octupus merge, there can be no conflicts since every repo is
# in a different subdirectory
git merge --no-edit $BRANCHES_TO_MERGE
}
if [[ $COMMAND == create ]]; then
mkdir -p $BUILD_DIR
cd $BUILD_DIR
clone_repos
filter_all_branches
setup_merged_repo
cd $MERGED_DIR
declare -A branches
IFS=' ' read -r -a repo_names <<< "$REPOS"
for index in "${!repo_names[@]}"
do
branches["${repo_names[index]}"]=master
done
merge_branches master branches
for index in "${!repo_names[@]}"
do
branches["${repo_names[index]}"]=develop
done
merge_branches develop branches
clean_merged_repo
exit
fi