summaryrefslogtreecommitdiffstats
path: root/merge.sh
diff options
context:
space:
mode:
Diffstat (limited to 'merge.sh')
-rw-r--r--merge.sh178
1 files changed, 178 insertions, 0 deletions
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 <commit>
+#
+# Merge the contents of <commit> into the current worktree, using
+# the calculated merge-base of <commit> 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 <commit>
+#
+# Apply merged contents to the worktree. This works by first deleted
+# removed files from <commit> 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 <commit>
+#
+# Merge the tree of <commit> 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 <commit>=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
+}