@@ -38,6 +38,7 @@ PATCH_DIR="umpf-patches"
38
38
IDENTICAL=false
39
39
STABLE=false
40
40
FORCE=false
41
+ DRYRUN=false
41
42
UPDATE=false
42
43
VERBOSE=false
43
44
VERSION_SEPARATOR=-
@@ -178,6 +179,8 @@ usage() {
178
179
--nix with format-patch: write patch series nix
179
180
-h, --help
180
181
-f, --force
182
+ --dry-run with push/pull: Do everything except actually send
183
+ the updates.
181
184
--flags specify/override umpf-flags
182
185
-i, --identical use exact commit hashes, not tip of branches
183
186
-s, --stable create a 'stable' tag from a branch based on an
@@ -194,6 +197,7 @@ usage() {
194
197
specified, it's interpreted as
195
198
<topic>=[<remote>/]<topic>
196
199
-u, --update with --patchdir: update existing patches in <path>
200
+ with push/pull: update only existing branches
197
201
-v, --version <version> with tag: overwrite version number [default: 1]
198
202
199
203
Commands:
@@ -218,6 +222,8 @@ usage() {
218
222
build <umpf> build an umerge from another umpf
219
223
distribute <commit-ish> push patches not yet in any topic branch
220
224
upstream
225
+ push [<umpf>] push topic branches to the given remote
226
+ pull [<umpf>] pull topic branches into the local repository
221
227
222
228
continue continue a previously interrupted umpf command
223
229
abort abort a previously started umpf command
@@ -245,7 +251,7 @@ setup() {
245
251
fi
246
252
247
253
o=" fhilsub:n:p:r:v:"
248
- l=" auto-rerere,bb,nix,flags:,force,help,identical,stable,update,base:,name:,patchdir:,relative:,override:,remote:,local,version:"
254
+ l=" auto-rerere,bb,nix,flags:,dry-run, force,help,identical,stable,update,base:,name:,patchdir:,relative:,override:,remote:,local,version:"
249
255
if ! args=" $( getopt -n umpf -o " ${o} " -l " ${l} " -- " ${@ } " ) " ; then
250
256
usage
251
257
exit 1
@@ -271,6 +277,9 @@ setup() {
271
277
-f|--force)
272
278
FORCE=true
273
279
;;
280
+ --dry-run)
281
+ DRYRUN=true
282
+ ;;
274
283
--flags)
275
284
FLAGS=" ${1} "
276
285
shift
@@ -1855,6 +1864,198 @@ do_distribute() {
1855
1864
run_distribute
1856
1865
}
1857
1866
1867
+ # ## namespace: push ###
1868
+
1869
+ push_topic () {
1870
+ echo " ${content} " >> " ${STATE} /topic-names"
1871
+ }
1872
+
1873
+ push_hashinfo () {
1874
+ echo " ${content} " >> " ${STATE} /topics"
1875
+ }
1876
+
1877
+ push_release () {
1878
+ echo " ${content} " >> " ${STATE} /tagname"
1879
+ }
1880
+
1881
+ push_topic_range () {
1882
+ [ ! -e " ${STATE} /tagname" ] && return
1883
+ [ -e " ${STATE} /tagrev-flat" ] && abort " more than one 'topic-range' after 'release'!"
1884
+
1885
+ echo " ${content##* ..} " > " ${STATE} /tagrev-flat"
1886
+ }
1887
+
1888
+ # ## command: push ###
1889
+
1890
+ resolve_commitish () {
1891
+ ${GIT} rev-parse --revs-only " $@ " 2> /dev/null
1892
+ }
1893
+
1894
+ shorten_commitish () {
1895
+ resolve_commitish --short ${1}
1896
+ }
1897
+
1898
+ resolve_tag () {
1899
+ local remote=$1 tag=$2 commit
1900
+ if [ -n " $remote " ]; then
1901
+ # handles conflicting tags on remote
1902
+ commit=$( git ls-remote -q $remote refs/tags/$tag 2> /dev/null | \
1903
+ sed ' s/\s\+.*$//' )
1904
+ else
1905
+ commit=" refs/tags/$tag "
1906
+ fi
1907
+
1908
+ resolve_commitish " ${commit} ^{}"
1909
+ }
1910
+
1911
+ update_local () {
1912
+ local success=false args=" ${1} "
1913
+ local opts
1914
+
1915
+ ${FORCE} && opts+=" --force"
1916
+
1917
+ local line
1918
+ while read -r line; do
1919
+ local prefix=" " suffix=" "
1920
+
1921
+ eval set -- ${line}
1922
+ [ ${# } -eq 0 ] && continue
1923
+
1924
+ local refparsed=$( shorten_commitish $3 )
1925
+
1926
+ if [ -z " ${refparsed} " ]; then
1927
+ prefix=" * [new branch]"
1928
+ elif [[ " ${1} " = * ~* ]]; then
1929
+ prefix=" ${1} ..$( shorten_commitish ${2} ) "
1930
+ elif $FORCE ; then
1931
+ prefix=" + ${refparsed} ..$( shorten_commitish ${2} ) "
1932
+ suffix=" (forced update)"
1933
+ else
1934
+ prefix=" ! [rejected]"
1935
+ suffix=" (non-fast-forward)"
1936
+ fi
1937
+
1938
+ printf " %-40s %s -> %s%s\n" " $prefix " $2 $3 " $suffix "
1939
+ done <<< " $args"
1940
+
1941
+ while read -r line; do
1942
+ eval set -- ${line}
1943
+ [ ${# } -eq 0 ] && continue
1944
+
1945
+ if $DRYRUN || git branch $opts $3 $2 ; then
1946
+ success=true
1947
+ fi
1948
+ done <<< " $args"
1949
+
1950
+ $success || abort
1951
+ }
1952
+
1953
+ do_push () {
1954
+ local opts args remote
1955
+ local -a branches branch_names
1956
+ local -A topics
1957
+
1958
+ if [ -z " ${GIT_REMOTE} " ]; then
1959
+ info " Git remote must be specified. Cannot continue."
1960
+ exit 1
1961
+ fi
1962
+
1963
+ if [ " ${GIT_REMOTE} " != " refs/heads/" ]; then
1964
+ remote=${GIT_REMOTE%/ }
1965
+ fi
1966
+
1967
+ prepare_persistent push " ${@ } "
1968
+ parse_series push " ${STATE} /series"
1969
+
1970
+ local tagname=" $( < " ${STATE} /tagname" ) "
1971
+ local tagrevf=" $( < " ${STATE} /tagrev-flat" ) "
1972
+ mapfile -t branches < " ${STATE} /topics"
1973
+ mapfile -t branch_names < " ${STATE} /topic-names"
1974
+
1975
+ if [ -n " ${remote} " ]; then
1976
+ # Needed, so git rev-parse below can check for existent branches
1977
+ git fetch --quiet --no-tags ${remote} 2> /dev/null
1978
+ fi
1979
+
1980
+ local rtagrev=" $( resolve_tag " ${remote} " ${tagname} ) "
1981
+ local rtagrevf=" $( resolve_commitish ${rtagrev} ^) "
1982
+ if [ " $tagrevf " != " $rtagrevf " ]; then
1983
+ if [ -z " $rtagrevf " ]; then
1984
+ abort " ${remote}${remote: +/ } refs/tags/$tagname not found"
1985
+ else
1986
+ abort " ${remote}${remote: +/ } refs/tags/$tagname " \
1987
+ " has unexpected commit-ish $rtagrev "
1988
+ fi
1989
+ fi
1990
+
1991
+ for i in " ${! branch_names[@]} " ; do
1992
+ local branch=${branch_names[$i]}
1993
+ local rbranchrev=" $( resolve_commitish " ${GIT_REMOTE}${branch} " ) "
1994
+
1995
+ [ -z " ${remote} " ] && [ " ${branches[$i]} " = " ${rbranchrev} " ] && continue
1996
+
1997
+ # Don't touch local branches that are already on the correct revision.
1998
+ # For remote branches, we let git push handle it.
1999
+ [ -z " ${remote} " ] && [ " ${branches[$i]} " = " ${rbranchrev} " ] && continue
2000
+ $UPDATE && [ -z " ${rbranchrev} " ] && continue
2001
+
2002
+ topics[${branch} ]=$( resolve_commitish ${branches[$i]} )
2003
+ done
2004
+
2005
+ if [ -n " ${remote} " ]; then
2006
+ ${FORCE} && opts+=" --force-with-lease"
2007
+ ${DRYRUN} && opts+=" --dry-run"
2008
+
2009
+ for topic in " ${! topics[@]} " ; do
2010
+ args+=" ${topics[$topic]} :refs/heads/${topic} "
2011
+ done
2012
+
2013
+ if [ -z " $args " ]; then
2014
+ info " No branches to push"
2015
+ cleanup
2016
+ return
2017
+ fi
2018
+
2019
+ ${GIT} push $opts ${remote} -- $args
2020
+ else # local
2021
+ for topic in " ${! topics[@]} " ; do
2022
+ local ref=$topic rev=${topics[$topic]}
2023
+ local oldval
2024
+
2025
+ # The old value being computed below is not needed to
2026
+ # create the branch. We compute a suitable one anyway,
2027
+ # so we can show how a ref's commit-ish has changed in
2028
+ # the pull case like we do in the push case.
2029
+ if git merge-base --is-ancestor $ref $rev & > /dev/null; then
2030
+ local ancestors=$( git rev-list $rev ^$ref --count)
2031
+ args+=" $( shorten_commitish " $rev " ) ~$ancestors "
2032
+ elif $FORCE ; then
2033
+ args+=" $( shorten_commitish " $ref " ) "
2034
+ else
2035
+ args+=' ""'
2036
+ fi
2037
+ args+=" $rev $ref "
2038
+ args+=$' \n '
2039
+ done
2040
+
2041
+ if [ -z " $args " ]; then
2042
+ info " No branches to push"
2043
+ cleanup
2044
+ return
2045
+ fi
2046
+
2047
+ update_local " $args "
2048
+ fi
2049
+
2050
+ cleanup
2051
+ }
2052
+
2053
+ # ## command: pull ###
2054
+
2055
+ do_pull () {
2056
+ GIT_REMOTE=refs/heads/ do_push " $@ "
2057
+ }
2058
+
1858
2059
# ## command: continue ###
1859
2060
1860
2061
do_continue () {
0 commit comments