-
Notifications
You must be signed in to change notification settings - Fork 1
/
git-ff
executable file
·173 lines (134 loc) · 3.99 KB
/
git-ff
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
#!/usr/bin/env bash
# setup color
# msysgit has no tput, I am looking for getting color codes for mingw32 env
if [ `expr "$(uname)" : "MING"` = 0 ]; then
underline=$(tput sgr 0 1)
bold=$(tput bold)
black=$(tput setaf 0)
red=$(tput setaf 1)
green=$(tput setaf 2)
yellow=$(tput setaf 3)
blue=$(tput setaf 4)
magenta=$(tput setaf 5)
cyan=$(tput setaf 6)
white=$(tput setaf 7)
normal=$(tput sgr0)
fi
usage(){
echo "git ff [remote]"
}
shas_store=""
shas() {
local key=$1
local value=$2
if [ "$value" != "" ]; then
shas_store="$shas_store $value:$key"
else
for pair in $shas_store; do
local pair_key=${pair##*:}
local pair_value=${pair%%:*}
if [ "$pair_key" = "$key" ]; then
echo $pair_value
break
fi
done
fi
}
init(){
local remote=$1
local pairs=`git show-ref | grep refs/remotes/$remote`
local pairs=${pairs// /:}
for pair in $pairs; do
shas_store="$shas_store $pair"
done
}
log(){
echo "$@"
}
is_force_updated(){
local full_ref=$1
local fetched=$(shas $full_ref)
if [ "$fetched" != "" ]; then
local forced=`echo $(git rev-list $full_ref..$before_fetched | wc -l)`
if [ "$forced" != "0" ]; then
echo "0"
fi
fi
echo "-1";
}
is_mergable() {
local full_ref=$1
local full_local_ref=$2
#check for mergable
local has_merge_base=`git merge-base $full_ref $full_local_ref >> /dev/null; echo $?`
echo "$has_merge_base"
}
git_ff(){
local full_ref=$1
local ref=$2
local local_ref=$3
local full_local_ref=$4
local head="[pass]"
local body=""
local distance=''
body="$cyan$full_ref$normal"
#has local branch?
local has_local_ref=`git show-ref --verify --quiet $full_local_ref; echo $?`
if [ "$has_local_ref" != "0" ]; then
body="$body: has no local branch"
continue;
elif [ "$(is_force_updated $full_ref)" == "0" ]; then
head="$red[force-updated]"
elif [ "$(is_mergable $full_ref $full_local_ref)" == "0" ]; then
local ahead=`echo $(git rev-list $full_ref..$full_local_ref | wc -l)`
local behind=`echo $(git rev-list $full_local_ref..$full_ref | wc -l)`
#Remote branch changed
distance=": $magenta[+$ahead][-$behind]"
if [ "$behind" != "0" ]; then
git checkout $local_ref
if [ "$ahead" != "0" ]; then
head="$red[rebase]"
#rebase local changes
#git rebase $full_ref
else
head="$yellow[merged]"
#fast-forward merge, cos local branch has no changes
git merge $full_ref
fi
fi
fi
echo "[ff]$head$body $distance$normal"
}
main() {
local remote=$1
if [ "$remote" = "" ]; then
remote='origin'
fi
if [[ -n $(git status -s 2> /dev/null |grep -v ^# |grep -v "working directory clean") ]]; then
echo "Checkouted branch is dirty!"
exit 1;
fi
## bakcup current branch.
local current_branch=$(git symbolic-ref HEAD 2> /dev/null)
init
git config svn-remote.svn.url
if [ "$remote" = "origin" ] && [ "`git config svn-remote.svn.url`" != "" ]; then
git svn fetch
git_ff "trunk" "trunk" "master" "refs/heads/master"
else
git fetch --prune $remote
local branches=`git show-ref | awk '{print $2}' | grep $remote`
for full_ref in $branches; do
local ref=${full_ref#refs/remotes/}
local local_ref=${full_ref#refs/remotes/$remote/}
local full_local_ref="refs/heads/$local_ref"
git_ff $full_ref $ref $local_ref $full_local_ref
done
fi
## restore current branch.
local temp=$(git symbolic-ref HEAD 2> /dev/null)
if [ "$current_branch" != "" ] && [ "$current_branch" != "temp" ]; then
git checkout ${current_branch#refs/heads/}
fi
}
main "$@"