|
| 1 | +#!/bin/bash -e |
| 2 | +# |
| 3 | +# Automatically update configured branch dependencies. |
| 4 | +# |
| 5 | +# Configure with parent branch for local tracking, e.g.: |
| 6 | +# git config branch.$branch.parent master |
| 7 | +# |
| 8 | +# Configure with description about what branch is for, e.g.: |
| 9 | +# git config branch.$branch.description "Dependence changes" |
| 10 | +# |
| 11 | + |
| 12 | +# TODO: Maybe make upstream origin default remote configurable. |
| 13 | +origin=origin |
| 14 | + |
| 15 | +current=$(git branch --show-current) |
| 16 | + |
| 17 | +changes=$(git status -s) |
| 18 | +if [[ -n $changes ]]; then |
| 19 | + echo Working branch $current not clean, please revert/commit/stash before proceeding. |
| 20 | + false |
| 21 | +fi |
| 22 | + |
| 23 | +main=$(git config upstream.main) || true |
| 24 | +if [[ -z $main ]]; then |
| 25 | + echo "Upstream main branch not defined, please set with (e.g.) 'git config upstream.main master'" |
| 26 | + false |
| 27 | +fi |
| 28 | + |
| 29 | +upstream=$(git config upstream.remote) || true |
| 30 | +if [[ -z $upstream ]]; then |
| 31 | + echo "Upstream remote not defined, please set with (e.g.) 'git config upstream.remote faucet'" |
| 32 | + false |
| 33 | +fi |
| 34 | + |
| 35 | +echo Fetching upstream remote $upstream $main branch... |
| 36 | +git fetch -q $upstream $main |
| 37 | + |
| 38 | +echo Fetching upstream origin... |
| 39 | +git fetch -q $origin |
| 40 | + |
| 41 | +echo Updating local $main branch... |
| 42 | +git switch -q $main |
| 43 | +git merge -n -q $upstream/$main |
| 44 | + |
| 45 | +git for-each-ref --format="%(refname:short) %(upstream:short)" refs/heads | \ |
| 46 | +while read local remote; do |
| 47 | + parent=$(git config branch.$local.parent) || true |
| 48 | + |
| 49 | + pmsg= |
| 50 | + if [[ -z $parent ]]; then |
| 51 | + pmsg=" (parent not configured, try e.g. 'git config branch.$local.parent $main')" |
| 52 | + fi |
| 53 | + |
| 54 | + if [[ -z $pmsg && -z $remote ]]; then |
| 55 | + pmsg=" (remote not configured, use `git push` to configure)" |
| 56 | + fi |
| 57 | + |
| 58 | + echo Updating branch $local$pmsg... |
| 59 | + git switch -q $local |
| 60 | + |
| 61 | + if [[ -n $parent ]]; then |
| 62 | + mergebase=$(git merge-base $local $parent) |
| 63 | + mergediff=$(git diff $parent $mergebase | wc -l) |
| 64 | + if [[ $mergediff -ne 0 ]]; then |
| 65 | + echo " Merge from local $parent..." |
| 66 | + git merge -n -q $parent |
| 67 | + fi |
| 68 | + |
| 69 | + masterdiff=$(git diff $parent | wc -l) || true |
| 70 | + if [[ $local != $parent && $masterdiff -eq 0 ]]; then |
| 71 | + echo " git branch -D $local # Branch is identical, consider deleting" |
| 72 | + fi |
| 73 | + fi |
| 74 | + |
| 75 | + if [[ -n $remote ]]; then |
| 76 | + git rev-list --left-right ${local}...${remote} -- 2>/dev/null >/tmp/git_upstream_status_delta || true |
| 77 | + LEFT_AHEAD=$(grep -c '^<' /tmp/git_upstream_status_delta) || true |
| 78 | + RIGHT_AHEAD=$(grep -c '^>' /tmp/git_upstream_status_delta) || true |
| 79 | + |
| 80 | + if [[ $RIGHT_AHEAD != 0 ]]; then |
| 81 | + echo " Disjoint upstream, merging down..." |
| 82 | + git pull |
| 83 | + fi |
| 84 | + |
| 85 | + difflines=$(git diff $remote | wc -l) |
| 86 | + if [[ $LEFT_AHEAD != 0 ]]; then |
| 87 | + echo " Push to upstream $remote..." |
| 88 | + git push |
| 89 | + fi |
| 90 | + fi |
| 91 | +done |
| 92 | + |
| 93 | +echo Returning to local branch $current... |
| 94 | +git switch -q $current |
0 commit comments