From 7dd31f64a4f57a2db2a504b026dbab7cde2b84bc Mon Sep 17 00:00:00 2001 From: Malf Furious Date: Wed, 6 Sep 2017 00:37:26 -0400 Subject: Add merge op --- merge.sh | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 merge.sh diff --git a/merge.sh b/merge.sh new file mode 100644 index 0000000..071ddca --- /dev/null +++ b/merge.sh @@ -0,0 +1,178 @@ +## +# systr_merge_tree +# +# Merge the contents of into the current worktree, using +# the calculated merge-base of and BASE (since your worktree +# is essentally BASE plus pending changes). +# +# The merge is staged in a separate directory. This is because systrunk +# doesn't want to overwrite the worktree unless the merge will run +# successfully. We don't want to write garbage to the worktree and lose +# uncommitted changes to other files. Users can resolve conflicts in +# this separate tree and either apply the complete merge when ready; +# or abort the merge alltogether, if problems arise. +# +# Invoke systr_merge_finish to apply new content to the worktree and +# prep for a merge-commit. +## +function systr_merge_tree +{ + if [ $# -lt 1 ]; then + echo "Fatal: too few args to merge_tree" >&2 + exit 1 + fi + + commit=$(systr_repo_resolve_reference "$1") + mergebase=$(systr_repo_merge_base "$commit" "$BASE") + + mergebase=$( + cd "$path/revs/$mergebase/" + echo $PWD + ) + + rm -rf .systr/merge/ .systr/tmp/ + mkdir .systr/merge .systr/tmp + + systr_rsync_diff "$path/revs/$commit/" "$mergebase" .systr/tmp/ + systr_rsync_diff . "$mergebase" .systr/merge/ + + systr_rsync_del "$path/revs/$commit/" "$mergebase" .systr/merge/ + systr_rsync_del . "$mergebase" .systr/tmp/ + + systr_rsync_merge .systr/tmp/ .systr/merge/ +} + +## +# systr_merge_finish +# +# Apply merged contents to the worktree. This works by first deleted +# removed files from then copying the local merge directory +# into the worktree. +# +# Once this completes, the user should run systrunk commit to record +# the merged tree in the repository. +## +function systr_merge_finish +{ + if [ $# -lt 1 ]; then + echo "Fatal: too few args to merge_finish" >&2 + exit 1 + fi + + commit=$(systr_repo_resolve_reference "$1") + mergebase=$(systr_repo_merge_base "$commit" "$BASE") + + mergebase=$( + cd "$path/revs/$mergebase/" + echo $PWD + ) + + rsync -az --existing --ignore-existing --delete --compare-dest="$mergebase" \ + --exclude='*.systr' "$path/revs/$commit/" . + + rsync -azi .systr/merge/ . + + rm -rf .systr/merge/ .systr/tmp/ +} + +## +# systrunk merge +# +# Merge the tree of into the worktree. If conflicts are found, +# they are interactively addressed. Once all conflicts are resolved, +# the merged content is moved into the worktree, ready for commit. +# Otherwise, the user may abort the merge, leaving the worktree intact. +# +# If =TRAC, as is the case for an 'update' operation, a merge +# commit is not expected and the MERG pointer will be cleared after +# the worktree is successfully updated. +# +# If the interactive prompt is left, user can invoke 'systrunk apply-merge' +# to proceed or 'systrunk abort-merge' to abort. +## +function systr_merge +{ + if [ $# -lt 1 ]; then + echo "Fatal: too few args to merge" >&2 + exit 1 + fi + + commit="$1" + + systr_merge_tree "$commit" + echo "$commit" >.systr/MERG + + # resolve conflicts # + find .systr/merge/ -name '*\*' | while read file; + do + orig=${file::-1} + vimdiff "$orig" "$file" + rm "$file" + done + + find .systr/merge/ -name '*~' | while read file; + do + name=${file::-1} + echo "$name removed on $commit // {created on worktree}" + while true; + do + echo "Use [d]eleted file Use [e]dited file Inspect in [v]im [A]bort" + read opt + + if [[ "$opt" == "d" ]]; then + rm "$file" + break + elif [[ "$opt" == "e" ]]; then + mv "$file" "$name" + break + elif [[ "$opt" == "v" ]]; then + vim "$file" + elif [[ "$opt" == "A" ]]; then + exit + fi + done + done + + find .systr/merge/ -name '*\&' | while read file; + do + name=${file::-1} + echo "$name removed on worktree // {created on $commit}" + while true; + do + echo "Use [d]eleted file Use [e]dited file Inspect in [v]im [A]bort" + read opt + + if [[ "$opt" == "d" ]]; then + rm "$file" + break + elif [[ "$opt" == "e" ]]; then + mv "$file" "$name" + break + elif [[ "$opt" == "v" ]]; then + vim "$file" + elif [[ "$opt" == "A" ]]; then + exit + fi + done + done + + # apply merge # + systr_merge_finish "$commit" + + if [[ "$commit" == "TRAC" ]]; then + echo "NULL" >.systr/MERG + fi +} + +## +# systrunk abort-merge +# +# Abort an in-progress merge that has *not* yet been incorporated +# into the worktree. This purges the merge staging directories and +# clears the MERG pointer. +## +function systr_merge_abort +{ + rm -rf .systr/merge/ .systr/tmp/ + echo "NULL" >.systr/MERG +} -- cgit v1.2.3