58cc98193f96944199d81c57d70b141c02b0226e
[msysgit.git] / share / msysGit / merging-rebase.sh
blob58cc98193f96944199d81c57d70b141c02b0226e
1 #!/bin/sh
3 # Rebase 'devel' on top of an upstream branch (defaults to 'junio/next'),
4 # retaining "fast-forwardability" by "merging" (with the "ours" strategy) the
5 # previous state on top of the current upstream state.
7 # options:
8 # --dry-run
9 # do not perform the rebase but only display the revisions selected
11 # --graph
12 # as for dry-run but display the commits as a graph
14 # --cherry
15 # as for --dry-run but display the commits using cherry notation to mark
16 # commits that are suitable for upstream consideration.
18 force=
19 dryrun=
20 graph=
21 cherry=
22 while test $# -gt 0
24 case "$1" in
25 -f|--force)
26 force=t
28 -s|--show|-d|--dry-run)
29 dryrun=t
31 -g|--graph)
32 dryrun=t
33 graph=--graph
35 -c|--cherry)
36 dryrun=t
37 cherry=--cherry
39 -h|--help)
40 cat >&2 << EOF
41 Usage: $0 [options] [<upstream>]
43 Options:
44 -s|--show show which commits would be cherry-picked
45 -g|--graph like --show, but with the commit graph
46 -c|--cherry try to leave out commits that were applied upstream
47 EOF
48 exit 1
50 -*)
51 echo "Unknown option: $1" >&2
52 exit 1
55 break
57 esac
58 shift
59 done
61 TO=${1:-junio/next}
63 if test -z "$force" && test -z "$(git rev-list .."$TO")"
64 then
65 echo "Nothing new in $TO; To force a rebase, use the --force, Luke!" >&2
66 exit 1
69 HEAD_NAME="$(git rev-parse --symbolic-full-name HEAD)"
70 case "$HEAD_NAME" in
71 refs/heads/*)
72 UPSTREAM=$(git rev-parse --symbolic-full-name HEAD@{u}) || {
73 echo "Not tracking any remote branch!" >&2
74 exit 1
76 test "$(git rev-parse HEAD)" = "$(git rev-parse $UPSTREAM)" ||
77 test "$(git rev-parse $HEAD_NAME@{1})" = "$(git rev-parse $UPSTREAM)" || {
78 echo "Your '$HEAD_NAME' is not up-to-date!" >&2
79 exit 1
81 ;; # okay
82 HEAD) ;; # okay
84 echo "Not on any branch!" >&2
85 exit 1
87 esac
88 FROM_SHA1=$(git rev-parse --short HEAD)
89 TO_SHA1=$(git rev-parse --short $TO)
91 is_ours_merge () {
92 test "$(git rev-parse $1:)" = "$(git rev-parse "$1^:")"
95 list_merges () {
96 git rev-list --parents "$@" | sed -n 's/ .* .*//p'
99 # Find old merging rebase, if any
101 REBASING_BASE=
102 for commit in $(list_merges $TO..)
104 if is_ours_merge $commit
105 then
106 REBASING_BASE=$commit
107 break
109 done
111 BASE_MESSAGE=
112 if test -n "$REBASING_BASE"
113 then
114 BASE_MESSAGE="using $REBASING_BASE as base."
115 MESSAGE="$(git cat-file commit $REBASING_BASE |
116 sed '1,/^$/d')"
117 # old style rebasing merge?
118 case "$MESSAGE" in
119 "Rebasing merge to "*)
120 BASE_MESSAGE="using the rebasing merge $REBASING_BASE."
121 # Fake a commit such that 'git log <commit>..' shows all the
122 # commits we want to rebase
123 PREVIOUS_REBASING="$(git rev-parse $REBASING_BASE^2)"
124 PREVIOUS_ONTO="$(echo "$MESSAGE" |
125 sed -n '1s/Rebasing merge .*(\(.*\))/\1/p')"
126 # To avoid checking out unneeded files/file versions, the
127 # throw-away base points to the tree we want to rebase onto
128 REBASING_BASE="$(echo Dummy |
129 git commit-tree $TO_SHA1: \
130 -p $PREVIOUS_ONTO -p $PREVIOUS_REBASING)"
132 esac
135 RANGE=$REBASING_BASE..
136 if test -n "$dryrun"
137 then
138 git log --oneline $graph $cherry --boundary $RANGE
139 exit
142 # Fake our own editor to inject initial steps into the edit script
143 TODO_EXTRA="$(git rev-parse --git-dir)/.todo-extra"
144 printf "%s\n\n%s\n%s" "Start the merging-rebase to $TO" \
145 "This commit starts the rebase of $FROM_SHA1 to $TO_SHA1" \
146 "$BASE_MESSAGE" > "$TODO_EXTRA.msg"
147 cat > "$TODO_EXTRA" << EOF
148 # Start the merging rebase:
149 # Reset to $TO and ...
150 exec git reset --hard $TO
151 # ... fake-merge current $HEAD_NAME
152 exec git merge -s ours -m "\$(cat "$TODO_EXTRA.msg")" $FROM_SHA1
154 # Patches to rebase:
156 TMP_EDITOR="$(git rev-parse --git-dir)/.rebasing-editor.sh" &&
157 cat > "$TMP_EDITOR" << EOF &&
158 #!/bin/sh
159 case "\$1" in
160 */git-rebase-todo)
161 # prepend the initialising commands
162 cat "\$1" >> "$TODO_EXTRA" &&
163 mv "$TODO_EXTRA" "\$1"
164 esac &&
165 exec "$(git var GIT_EDITOR)" "\$@"
167 chmod a+x "$TMP_EDITOR"
169 # Rebase!
170 GIT_EDITOR="$TMP_EDITOR" git rebase --autosquash -i ${REBASING_BASE:-$TO}