summaryrefslogblamecommitdiffstats
path: root/merge.sh
blob: 64a6bffe00521c8f0d0c695b9ef0bd94e0f46a68 (plain) (tree)




























































                                                                        
               













                                                                                 




                                      

























                                                                           
                                


                               
                                                 





                               
                                                





















                                                                                            
                                                 






















                                                                                            
                                  













                                                                   
##
# 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

    branch="$1"
    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/

    if [[ "$branch" == "TRAC" ]]; then
        echo "NULL" >.systr/MERG
        echo "$commit" >.systr/BASE
    fi
}

##
# 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 #
    for file in `find .systr/merge/ -name '*\*'`;
    do
        orig=${file::-1}
        vimdiff "$orig" "$file"
        rm "$file"
    done

    for file in `find .systr/merge/ -name '*~'`;
    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

    for file in `find .systr/merge/ -name '*\&'`;
    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")
}

##
# 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
}