]> Untitled Git - hvutilities.git/commitdiff
gitseg: add new script gitseg
authorHugo Villeneuve <hugo@hugovil.com>
Tue, 24 Mar 2026 18:33:00 +0000 (14:33 -0400)
committerHugo Villeneuve <hugo@hugovil.com>
Thu, 2 Apr 2026 23:34:04 +0000 (19:34 -0400)
Signed-off-by: Hugo Villeneuve <hugo@hugovil.com>
scripts/Makefile.am
scripts/gitseg [new file with mode: 0644]

index 91648ea3e46adb97cb505b0f60948aac6e1c7cdb..85654f191629053046d136cbc1f7f3310f3ff919 100644 (file)
@@ -9,6 +9,7 @@ dist_bin_SCRIPTS = \
     fix-avi \
     flac2ogg flac2mp3 \
     git-repos-update-clean \
+    gitseg \
     gztobz2 tarbz2 \
     hv-backup \
     hvpdf-rotate \
diff --git a/scripts/gitseg b/scripts/gitseg
new file mode 100644 (file)
index 0000000..5b336ac
--- /dev/null
@@ -0,0 +1,246 @@
+#!/bin/bash
+
+# Build branch from multiple git segments (branches)
+
+set -e
+
+PROG_NAME="`readlink -e $0`"
+PROG_PATH=$(dirname ${PROG_NAME})
+source ${PROG_PATH}/hvutilities.sh
+
+GITSEG_TEMP_BRANCH="gitseg-rebase"
+
+catch()
+{
+    if [ "$1" != "0" ]; then
+        # Error handling goes here
+        echo "Error $1 occurred"
+
+        if [ x"${orig_branch}" != x"" ]; then
+            if git status | grep -q "currently cherry-picking commit"; then
+                git cherry-pick --abort
+            fi
+
+            if git status | grep -q "currently editing a commit while rebasing branch"; then
+                git rebase --abort
+            fi
+
+            git checkout ${orig_branch}
+        fi
+    fi
+
+    # Cleanup for both normal exit and error:
+    # TODO
+}
+
+# Set default values
+force_push="0"
+orig_branch=""
+
+print_usage()
+{
+    echo "${PROG_NAME} -- Build branch from multiple git segments (branches)"
+    echo "Usage: ${PROG_NAME} [OPTIONS...]"
+    echo
+    echo "Options:"
+    echo "  -d   debug mode"
+    echo "  -p   force push stacked branches (\"stack\" command)"
+    echo
+}
+
+gitseg_label()
+{
+    label="segment ${orig_branch}"
+    previous=$(git_find_commit_by_title "${label}")
+
+    if [ "${previous}" != "" ]; then
+        log_err "Commit already exists: ${label}"
+        exit 1
+    fi
+
+    git commit --allow-empty -m "segment ${orig_branch}"
+}
+
+# Arg1: source branch
+# Arg2: destination branch
+gitseg_new()
+{
+    local src_branch="${1}"
+    local dest_branch="${2}"
+
+    if [ "${orig_branch}" = "${dest_branch}" ]; then
+        log_err "Cannot delete current branch: ${orig_branch}"
+        exit 1
+    fi
+
+    # If dest branch exits, delete it:
+    if git branch | grep -q -e "${dest_branch}$"; then
+        git branch ${Q} -D ${dest_branch} 1>/dev/null
+    fi
+
+    git checkout ${Q} -b ${dest_branch} ${src_branch}
+}
+
+# Arg1: segment name
+# Output:
+#   commit_start
+#   commit_end
+gitseg_scan()
+{
+    seg="${1}"
+
+    if ! git branch | grep -q -e "${seg}$"; then
+        log_err "Missing branch for segment: ${seg}"
+        exit 1
+    fi
+
+    commit_start=$(git_find_commit_by_title "segment ${seg}" "${seg}")
+
+    if [ "${commit_start}" = "" ]; then
+        log_err "Missing start segment indicator for: ${seg}"
+        exit 1
+    fi
+
+    # Prévoir le cas ou il y seulement le commit start...
+    commit_end=$(git log --oneline --max-count=1 ${seg} | awk {'print $1'})
+
+    log_dbg "  commit_start: ${commit_start}"
+    log_dbg "  commit_end:   ${commit_end}"
+}
+
+gitseg_rebase()
+{
+    src_branch="${1}"
+    shift
+
+    log_info "Rebase source branch: ${src_branch}"
+
+    for s in ${*}; do
+        log_info "Rebase segment ${s}"
+
+        gitseg_scan ${s}
+
+        temp_branch="${GITSEG_TEMP_BRANCH}"
+        if git branch | grep -q -e "${temp_branch}$"; then
+            git branch ${Q} -D ${temp_branch}
+        fi
+
+        gitseg_new ${src_branch} ${temp_branch}
+
+        # For rebase, we need to include the indicator empty commit:
+        git cherry-pick --empty=keep -1 ${commit_start} 1>/dev/null
+
+        if [ "${commit_end}" != "${commit_start}" ]; then
+            git cherry-pick ${commit_start}..${commit_end} 1>/dev/null
+        fi
+
+        git checkout ${Q} "${s}"
+        git reset ${Q} --hard ${temp_branch}
+        git branch ${Q} -D ${temp_branch}
+    done
+
+    if [ "${force_push}" -eq 1 ]; then
+        git push -f
+    fi
+}
+
+gitseg_stack()
+{
+    for s in ${*}; do
+        log_info "Stack segment ${s}"
+
+        gitseg_scan ${s}
+
+        if [ "${commit_end}" = "${commit_start}" ]; then
+            # Nothing to do, segment has no commits, except for start indicator.
+            continue
+        fi
+
+        git checkout ${Q} "${orig_branch}"
+        git cherry-pick ${commit_start}..${commit_end} 1>/dev/null
+    done
+
+    if [ "${force_push}" -eq 1 ]; then
+        git push -f
+    fi
+}
+
+while getopts "dhp" flag ;do
+    case ${flag} in
+        d)
+            debug="1"
+            ;;
+       h)
+           print_usage
+            exit 0
+            ;;
+        p)
+            force_push="1"
+            ;;
+        ?)
+            log_err "${PROG_NAME}: Option invalide: ${OPTARG}."
+            exit 1
+            ;;
+    esac
+done
+shift `expr "${OPTIND}" - 1`
+
+# `$#' now represents the number of arguments after the options.
+# `$1' is the first argument, etc.
+if [ $# -lt 1 ]; then
+    log_err "${PROG_NAME}: Missing command."
+    exit 1
+fi
+
+cmd=${1}
+
+shift
+
+orig_branch=$(git branch --show-current)
+
+if [ "${debug}" = "1" ]; then
+    Q=""
+else
+    Q="-q"
+    trap 'catch $?' EXIT
+fi
+
+case ${cmd} in
+    label)
+        gitseg_label
+        ;;
+    new)
+        if [ $# -ne 2 ]; then
+            log_err "${PROG_NAME}: Missing arguments."
+            exit 1
+        fi
+        log_info "New branch ${2}"
+        gitseg_new "${1}" "${2}"
+        ;;
+    rebase)
+        if [ $# -lt 1 ]; then
+            log_err "${PROG_NAME}: Missing base branch."
+            exit 1
+        fi
+        src_branch="${1}"
+        shift
+
+        if [ $# -lt 1 ]; then
+            echo "${PROG_NAME}: Missing segment(s)."
+            exit 1
+        fi
+
+        gitseg_rebase "${src_branch}" "${*}"
+        ;;
+    stack)
+        if [ $# -lt 1 ]; then
+            echo "${PROG_NAME}: Missing segment(s)."
+            exit 1
+        fi
+        gitseg_stack "${*}"
+        ;;
+    *)
+        log_err "Unknown command: ${cmd}"
+        exit 1
+        ;;
+esac