mirror of
https://github.com/tomasriveral/Nix-Git-Cherry-Picker.git
synced 2026-08-11 18:28:40 +02:00
198 lines
6.3 KiB
Bash
Executable File
198 lines
6.3 KiB
Bash
Executable File
set -euo pipefail
|
|
trap 'echo "Interrupted or failed. Repo may be mid-rebase/cherry-pick." ; exit 1' INT ERR
|
|
|
|
if [[ $# -eq 0 ]]; then
|
|
echo "Usage: ngcp [mode] [options]"
|
|
echo "Run 'ngcp --help' for more information."
|
|
exit 1
|
|
fi
|
|
|
|
# waits for an internet connection. It pings both Google DNS and Cloudfare dns in case one of them is down
|
|
pings=0
|
|
until ping -c1 -W1 1.1.1.1 >/dev/null 2>&1 || \
|
|
ping -c1 -W1 8.8.8.8 >/dev/null 2>&1
|
|
do
|
|
sleep 1
|
|
((pings++))
|
|
if (( pings > 2 )); then
|
|
echo "No internet connection. Retrying in 1 second..."
|
|
fi
|
|
done
|
|
|
|
CONFIG="$HOME/.config/nix-git-cherry-picker/config.json"
|
|
|
|
if [[ ! -f "$CONFIG" ]]; then
|
|
echo "Error: Config file not found at $CONFIG"
|
|
echo "Please create it with the necessary settings."
|
|
exit 1
|
|
fi
|
|
|
|
localBranch=$(jq -r '.localBranch' "$CONFIG")
|
|
remoteBranch=$(jq -r '.remoteBranch' "$CONFIG")
|
|
nixConfigPath=$(jq -r '.nixConfigPath' "$CONFIG")
|
|
|
|
automatic=0
|
|
|
|
# if there is the flag --automatic it will fail when merge conflict and tell you to do it manually.
|
|
# if there is the flag --no-rebuild it won't rebuild your system to test the new commits
|
|
# if there is the flag --continue-with-rebuild it will rebuild if --no-rebuild was set
|
|
for flag in "$@"; do
|
|
if [[ "$flag" == "--automatic" ]]; then
|
|
automatic=1
|
|
elif [[ "$flag" == "--help" ]]; then
|
|
echo "Usage: ngcp [mode] [options]"
|
|
echo "Mode:"
|
|
echo " pick <commit 1> <commit2> <...> Cherry-pick commits for the remote branch."
|
|
echo " pick -i [n] Interactively select from the last 10 (or n) commits."
|
|
echo " pick --interactive [n] Interactively select from the last 10 (or n) commits."
|
|
echo " last <int n> Cherry-pick the last n commits."
|
|
echo " pull Pulls the changes to the local branch."
|
|
echo "Options:"
|
|
echo " --automatic Exit with no changes if merge conflict and instructs the user to pull manually. Use this option for automation."
|
|
exit
|
|
fi
|
|
done
|
|
# checks if connection
|
|
|
|
|
|
if [[ "$1" == "pick" || "$1" == "last" ]]; then
|
|
interactive=0
|
|
interactive_count=10
|
|
|
|
if [[ "$1" == "pick" && "${2:-}" == "-i" || "$1" == "pick" && "${2:-}" == "--interactive" ]]; then
|
|
interactive=1
|
|
|
|
if [[ -n "${3:-}" ]]; then
|
|
if ! [[ "$3" =~ ^[1-9][0-9]*$ ]]; then
|
|
echo "Invalid interactive commit count: $3"
|
|
exit 1
|
|
fi
|
|
interactive_count="$3"
|
|
fi
|
|
fi
|
|
|
|
if (( interactive )); then
|
|
if ! command -v fzf >/dev/null 2>&1; then
|
|
echo "Error: fzf is required for interactive mode."
|
|
echo "Please install fzf and try again."
|
|
exit 1
|
|
fi
|
|
|
|
mapfile -t commits < <(
|
|
git -C "$nixConfigPath" log \
|
|
--format='%H%x09%h%x09%s' \
|
|
-n "$interactive_count" \
|
|
HEAD |
|
|
fzf \
|
|
--multi \
|
|
--reverse \
|
|
--header="TAB select/deselect • ENTER confirm" \
|
|
--preview="git -C '$nixConfigPath' show --stat --oneline {1}" |
|
|
cut -f1
|
|
)
|
|
|
|
if [[ "${#commits[@]}" -eq 0 ]]; then
|
|
echo "No commits selected."
|
|
exit 0
|
|
fi
|
|
|
|
# fzf displays newest -> oldest, but cherry-picking should happen
|
|
# oldest -> newest.
|
|
mapfile -t commits < <(printf '%s\n' "${commits[@]}" | tac)
|
|
|
|
elif [[ "$1" == "last" ]]; then
|
|
if [[ "$#" -lt 2 ]] || ! [[ "$2" =~ ^[1-9][0-9]*$ ]]; then
|
|
echo "Invalid arguments. Usage: ngcp last <number>"
|
|
exit 1
|
|
fi
|
|
|
|
mapfile -t commits < <(
|
|
git -C "$nixConfigPath" log --format='%H' --reverse -n "$2" HEAD
|
|
)
|
|
|
|
echo "Cherry-picking the last ${#commits[@]} commits:"
|
|
printf ' %s\n' "${commits[@]}"
|
|
|
|
else
|
|
commits=("${@:2}")
|
|
fi
|
|
|
|
#if doesnt exist, just get the branch from the remote
|
|
if ! git -C "$nixConfigPath" checkout "$remoteBranch"; then
|
|
git -C "$nixConfigPath" checkout -b "$remoteBranch" "origin/$remoteBranch"
|
|
fi
|
|
echo "Pulling latest commits before cherry-picking..."
|
|
if git -C "$nixConfigPath" pull --rebase ; then
|
|
echo "Pull successful."
|
|
elif (( automatic )); then
|
|
echo "Merge conflict detected during pull. Please run ngcp pull manually"
|
|
notify-send "Merge conflict detected during ngcp pull." "Please run ngcp pull manually"
|
|
git -C "$nixConfigPath" rebase --abort
|
|
exit 1
|
|
else
|
|
echo "Merge conflict detected during pull."
|
|
echo "Resolve conflicts and run:"
|
|
echo " git rebase --continue"
|
|
echo "Type 'y' when done."
|
|
|
|
while git -C "$nixConfigPath" rev-parse --verify REBASE_HEAD >/dev/null 2>&1; do
|
|
read -r answer
|
|
[[ "$answer" == "y" ]] || continue
|
|
done
|
|
echo "Pull successful"
|
|
fi
|
|
for commit in "${commits[@]}"; do
|
|
if git -C "$nixConfigPath" cherry-pick "$commit"; then
|
|
echo "Applied $commit successfully"
|
|
else
|
|
echo "Cherry-pick of $commit failed."
|
|
echo "Resolve conflicts and run:"
|
|
echo " git cherry-pick --continue"
|
|
echo
|
|
echo "Type 'y' when done."
|
|
|
|
while git -C "$nixConfigPath" rev-parse --verify CHERRY_PICK_HEAD >/dev/null 2>&1; do
|
|
read -r answer
|
|
[[ "$answer" == "y" ]] || continue
|
|
done
|
|
|
|
echo "Cherry-pick for $commit resolved."
|
|
fi
|
|
done
|
|
git -C "$nixConfigPath" push --force origin "$remoteBranch"
|
|
git -C "$nixConfigPath" checkout "$localBranch"
|
|
elif [[ "$1" == "pull" ]]; then
|
|
gitStatus=$(git -C "$nixConfigPath" status --porcelain)
|
|
if [[ -n "$gitStatus" ]]; then
|
|
echo "Git directory is dirty. Please clean it up before running ngcp pull"
|
|
echo "$gitStatus"
|
|
notify-send "Git directory is dirty." "Please clean it up before running ngcp pull\n $gitStatus"
|
|
exit 1
|
|
fi
|
|
if git -C "$nixConfigPath" pull --rebase ; then
|
|
echo "Pull successful"
|
|
else
|
|
if (( automatic )); then
|
|
git -C "$nixConfigPath" rebase --abort || true
|
|
echo "git pull failed. Please run ngcp pull manually"
|
|
notify-send "Git pull failed." "Please run ngcp pull manually"
|
|
exit 1
|
|
else
|
|
echo "Merge conflict detected during pull."
|
|
echo "Resolve conflicts and run:"
|
|
echo " git rebase --continue"
|
|
echo "Type 'y' when done."
|
|
|
|
while git -C "$nixConfigPath" rev-parse --verify REBASE_HEAD >/dev/null 2>&1; do
|
|
read -r answer
|
|
[[ "$answer" == "y" ]] || continue
|
|
done
|
|
echo "Pull successful"
|
|
fi
|
|
fi
|
|
git -C "$nixConfigPath" push --force origin "$localBranch"
|
|
else
|
|
echo "Invalid argument. Please run ngcp --help"
|
|
exit
|
|
fi
|