From 9cf9a530382fa2c7d8ca4cc2742e97ba1d7d5561 Mon Sep 17 00:00:00 2001 From: Dmytro Serdiuk Date: Wed, 20 Nov 2019 17:50:48 +0200 Subject: [PATCH] Add the ability to polish current work When you are working in a separate branch, you may create several commits. And once the work is done, you may want to change the commits history somehow. `git rebase --interactive` can help with this. But it requires an exact number of commits prior to running the command. So, you have to provide it. And usually, it's done by reviewing `git log` and counting of necessary commits. `polish-work` command aims to solve this in a single command run. And even, if there are pauses in the rebase process (like conflicts or purposeful stops), the command can continue the started rebase process. --- docs/commands.md | 24 +++++++++++++ libexec/git-elegant | 1 + libexec/git-elegant-polish-work | 52 ++++++++++++++++++++++++++++ tests/git-elegant-commands.bats | 1 + tests/git-elegant-polish-work.bats | 55 ++++++++++++++++++++++++++++++ 5 files changed, 133 insertions(+) create mode 100644 libexec/git-elegant-polish-work create mode 100644 tests/git-elegant-polish-work.bats diff --git a/docs/commands.md b/docs/commands.md index a698262..2c4c25a 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -24,6 +24,7 @@ There are commands used in various situations such as start-work Creates a new branch. save-work Commits current modifications. amend-work Amends some changes to the most recent commit. + polish-work Reapplies branch commits interactively. deliver-work Publishes current branch to a remote repository. operate a flow of work management @@ -235,6 +236,29 @@ git fetch --all git checkout -B task-133 custom-remote/new-feature ``` +# `polish-work` + +```bash +usage: git elegant polish-work +``` + +Reapplies branch commits using interactive rebase. It uses only new commits that +aren't in `master` branch. If there is a rebase in progress, the command will +continue it. + +Prior to the execution and in the case of rebase initiation, all uncommitted +tracked modifications will be temporally stashed. And they will be uncovered if +the rebase completes without errors, otherwise, you need to apply them manually +by running `git stash pop`. + +The command raises error 42 if it runs against `master` branch. + +Approximate commands flow is +```bash +==>> git elegant polish-work +git rebase --interactive @~5 +``` + # `release-work` ```bash diff --git a/libexec/git-elegant b/libexec/git-elegant index de490a2..804e067 100755 --- a/libexec/git-elegant +++ b/libexec/git-elegant @@ -115,6 +115,7 @@ $(--print-command-in-usage clear-local) $(--print-command-in-usage start-work) $(--print-command-in-usage save-work) $(--print-command-in-usage amend-work) +$(--print-command-in-usage polish-work) $(--print-command-in-usage deliver-work) operate a flow of work management diff --git a/libexec/git-elegant-polish-work b/libexec/git-elegant-polish-work new file mode 100644 index 0000000..adcb6d8 --- /dev/null +++ b/libexec/git-elegant-polish-work @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +set -e + +command-purpose() { + cat <> git elegant polish-work +git rebase --interactive @~5 +\`\`\` +MESSAGE +} + +default() { + if [[ $(git rev-parse --abbrev-ref HEAD) == "master" ]]; then + error-box "'master' branch history can't be rewritten. Please read more on ${__site}" + exit 42 + fi + if test -d "$(git rev-parse --git-path rebase-merge)" || test -d "$(git rev-parse --git-path rebase-apply)"; then + git-verbose rebase --continue + else + local commits=($(git rev-list ${MASTER}..@)) + if [[ ${#commits[*]} -eq 0 ]]; then + info-text "There are no new commits comparing to '${MASTER}' branch." + else + stash-pipe git-verbose rebase --interactive @~${#commits[*]} + fi + fi +} diff --git a/tests/git-elegant-commands.bats b/tests/git-elegant-commands.bats index 828d02e..f82d8e7 100644 --- a/tests/git-elegant-commands.bats +++ b/tests/git-elegant-commands.bats @@ -23,6 +23,7 @@ teardown() { "amend-work" "show-release-notes" "release-work" + "polish-work" ) check git-elegant commands [ ${#lines[@]} -eq ${#COMMANDS[@]} ] diff --git a/tests/git-elegant-polish-work.bats b/tests/git-elegant-polish-work.bats new file mode 100644 index 0000000..1683217 --- /dev/null +++ b/tests/git-elegant-polish-work.bats @@ -0,0 +1,55 @@ +#!/usr/bin/env bats + +load addons-common +load addons-fake +load addons-repo + +setup() { + repo-new +} + +teardown() { + repo-clean + fake-clean +} + +@test "'polish-work': exit code is 42 when the command is run against 'master' branch" { + check git-elegant polish-work + [[ "${status}" -eq 42 ]] +} + +@test "'polish-work': a rebase process doesn't start when there are no new commits" { + repo "git checkout -b no-new-commits" + check git-elegant polish-work + [[ "${status}" -eq 0 ]] + [[ "${lines[@]}" =~ "There are no new commits comparing to 'master' branch." ]] +} + +@test "'polish-work': a rebase process works when there are new commits" { + repo "git checkout -b new-commits" + repo-commit-file "1" + repo-commit-file "2" + repo-commit-file "3" + fake-fail "git rebase --interactive @~3" "git rebase was executed" + check git-elegant polish-work + [[ "${status}" -eq 100 ]] + [[ ${lines[@]} =~ "git rebase was executed" ]] +} + +@test "'polish-work': current rebase is continued when the rebase process is active" { + repo "git checkout -b new-commits" + fake-pass "git rev-parse --git-path rebase-merge" ".git" + check git-elegant polish-work + [[ "${status}" -ne 0 ]] + [[ ${lines[@]} =~ "No rebase in progress?" ]] +} + +@test "'polish-work': all uncommitted changes are applied back when rebase is completed" { + repo "git checkout -b new-commits" + repo-commit-file "1" + repo-non-staged-change "A new line..." + fake-pass "git rebase --interactive @~1" + fake-fail "git stash pop stash@{0}" + check git-elegant polish-work + [[ "$status" -eq 100 ]] +}