Skip to content

Commit

Permalink
Start work from the alternative branch
Browse files Browse the repository at this point in the history
Sometimes a new work should be started from the non-master branch. And
this is implemented by adding a second optional argument to
`start-work` command. Also, internal logic has an enhancement that
allows pulling only for branches that have configured remote tracking.

The completion scrips complete the second argument of the command. And
short instructions on how to test the completion updates are added to
README.md.
  • Loading branch information
extsoft committed Mar 12, 2020
1 parent e2de11d commit 9e2acc0
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 40 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,9 @@ In order to get the documentation preview locally, please install required depen

The [docs/commands.md](docs/commands.md) generates by running `./workflows generate-docs` script.
All other files in ["docs" directory](docs/) require manual corrections.

### Completions testing
1. source updated competion file
- bash: `source completions/git-elegant.bash`
- zsh: `source completions/_git-elegant`
2. run `git-elegant <some>` and press Tab twice
11 changes: 11 additions & 0 deletions completions/_git-elegant
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ __ge_complete_commands () {
case ${line[1]} in
accept-work|obtain-work) __ge_remotes ;;
show-release-notes) __ge_show_release_notes ;;
start-work) __ge_start_work ;;
*) _arguments '--help' '--no-workflows' ;;
esac
}
Expand Down Expand Up @@ -93,3 +94,13 @@ __ge_show_release_notes() {
'2:from:(${all[@]})' \
'3:to:(${all[@]})'
}

__ge_start_work() {
local all=(
$(git for-each-ref --sort '-version:refname' --format '%(refname:short)' refs 2>/dev/null)
)
_arguments '--help' \
'--no-workflows' \
'1:name:()' \
'2:from:(${all[@]})'
}
14 changes: 7 additions & 7 deletions completions/git-elegant.bash
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ _git_elegant() {
$(git elegant show-commands)
)
COMPREPLY=( $(compgen -W "${opts[*]}" -- ${cursor}) )
return 0 ;;
;;
accept-work|obtain-work)
local opts=(
${gecops}
Expand All @@ -31,25 +31,25 @@ _git_elegant() {
COMPREPLY=(
$(compgen -W "${opts[*]}" -- ${cursor})
)
return 0 ;;
;;
show-release-notes)
COMPREPLY=( $(compgen -W "simple smart ${gecops[*]}" -- ${cursor}) )
return 0 ;;
;;
*)
COMPREPLY=( $(compgen -W "${gecops[*]}" -- ${cursor}) )
return 0 ;;
;;
esac
fi

# the second word prior to the ${cursor}
if [[ ${#COMP_WORDS[*]} > $(( 2 + ${offset} )) ]]; then
case "${COMP_WORDS[COMP_CWORD-$(( 2 + ${offset} ))]}" in
show-release-notes)
show-release-notes|start-work)
local opts=(
$(git for-each-ref --sort "-version:refname" --format "%(refname:short)" refs 2>/dev/null)
)
COMPREPLY=( $(compgen -W "${opts[*]}" -- ${cursor}) )
return 0 ;;
;;
*) ;;
esac
fi
Expand All @@ -62,7 +62,7 @@ _git_elegant() {
$(git for-each-ref --sort "-version:refname" --format "%(refname:short)" refs 2>/dev/null)
)
COMPREPLY=( $(compgen -W "${opts[*]}" -- ${cursor}) )
return 0 ;;
;;
*) ;;
esac
fi
Expand Down
4 changes: 3 additions & 1 deletion docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,13 +368,15 @@ git stash list
# `start-work`

```bash
usage: git elegant start-work <name>
usage: git elegant start-work <name> [from-ref]
```

Creates a new local branch based on the latest version of the default upstream
branch. If there are some uncommitted changes, they will be moved to the new
branch.

`from-ref` argument overrides the default upstream branch with a given one.

The command uses stash pipe to preserve the current Git state prior to execution
and restore after.

Expand Down
9 changes: 3 additions & 6 deletions libexec/git-elegant-prune-repository
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,17 @@ The command works even if the remotes are unavailable.
MESSAGE
}

--is-there-upstream-for() {
git rev-parse --abbrev-ref ${1}@{upstream} >/dev/null 2>&1
}

default() {
source ${BINS}/plugins/state
git-verbose checkout ${MASTER}
if --is-there-upstream-for ${MASTER}; then
if is-there-upstream-for ${MASTER}; then
git-verbose fetch --all || info-text "As the remotes can't be fetched, the current local version is used."
git-verbose rebase
fi
for branch in $(git for-each-ref --format "%(refname:short)" refs/heads); do
if [[ ${branch} == ${MASTER} ]]; then continue; fi
if [[ -n $(git config --get branch.${branch}.merge) ]]; then
if --is-there-upstream-for ${branch}; then
if is-there-upstream-for ${branch}; then
# the branch has existing upstream; keep it
continue
fi
Expand Down
12 changes: 9 additions & 3 deletions libexec/git-elegant-start-work
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ MESSAGE

command-synopsis() {
cat <<MESSAGE
usage: git elegant start-work <name>
usage: git elegant start-work <name> [from-ref]
MESSAGE
}

Expand All @@ -19,6 +19,8 @@ Creates a new local branch based on the latest version of the default upstream
branch. If there are some uncommitted changes, they will be moved to the new
branch.
\`from-ref\` argument overrides the default upstream branch with a given one.
The command uses stash pipe to preserve the current Git state prior to execution
and restore after.
Expand All @@ -38,8 +40,12 @@ MESSAGE
}

--start-work-logic(){
git-verbose checkout ${MASTER}
git-verbose pull || info-text "As the branch can't be pulled, the current local version is used."
source ${BINS}/plugins/state
local target=${2:-${MASTER}}
git-verbose checkout ${target}
if is-there-upstream-for ${target}; then
git-verbose pull
fi
git-verbose checkout -b "$1"
}

Expand Down
5 changes: 5 additions & 0 deletions libexec/plugins/state
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,8 @@ last-tag() {
# Seeks for the last created tag.
git for-each-ref --sort "-version:refname" --format "%(refname:short)" refs/tags --count 1
}

is-there-upstream-for() {
# usage: is-there-upstream-for <branch ref>
git rev-parse --abbrev-ref ${1}@{upstream} >/dev/null 2>&1
}
51 changes: 28 additions & 23 deletions tests/git-elegant-start-work.bats
Original file line number Diff line number Diff line change
Expand Up @@ -6,60 +6,65 @@ load addons-repo

setup() {
repo-new
fake-pass "git pull"
}

teardown() {
fake-clean
repo-clean
}

@test "'start-work': branch with given name is created successfully" {
@test "'start-work': starts work with a given name" {
check git-elegant start-work test-feature
[[ "$status" -eq 0 ]]
[[ ${status} -eq 0 ]]
[[ $(git rev-parse --abbrev-ref @) == "test-feature" ]]
}

@test "'start-work': works when the remote repository is unavailable" {
@test "'start-work': updates upsteram branch before start a new work" {
fake-fail "git pull"
fake-pass "git rev-parse --abbrev-ref master@{upstream}"
check git-elegant start-work test-feature
[[ ${status} -eq 0 ]]
[[ ${lines[@]} =~ "As the branch can't be pulled, the current local version is used." ]]
[[ ${status} -eq 100 ]]
}

@test "'start-work': exit code is 45 when branch name isn't set" {
@test "'start-work': raises 45 error if work name is not set" {
check git-elegant start-work
[[ "$status" -eq 45 ]]
[[ ${status} -eq 45 ]]
[[ ${lines[0]} =~ "Please give a name for the new branch." ]]
}

@test "'start-work': print error message when branch name isn't set" {
@test "'start-work': starts work from a given branch instead of a default one" {
repo "git checkout -b custom"
fake-pass "git rev-parse --abbrev-ref custom@{upstream}"
fake-pass "git pull"
check git-elegant start-work
[[ "${lines[0]}" =~ "Please give a name for the new branch." ]]
[[ ${status} -eq 45 ]]
[[ ${lines[0]} =~ "Please give a name for the new branch." ]]
}

@test "'start-work': tracked changes move to a new branch when they are available" {
@test "'start-work': moves existing changes to a new branch" {
repo-non-staged-change "A new line..."
check git-elegant start-work test-feature
[[ "$status" -eq 0 ]]
[[ "${lines[@]}" =~ "stash push" ]]
[[ "${lines[@]}" =~ "stash pop" ]]
[[ ${status} -eq 0 ]]
[[ ${lines[@]} =~ "stash push" ]]
[[ ${lines[@]} =~ "stash pop" ]]
}

@test "'start-work': stash commands don't run when there are no tracked changes" {
@test "'start-work': doesn't run stash pipeline if there are no tracked changes" {
check git-elegant start-work test-feature
[[ "$status" -eq 0 ]]
[[ ! "${lines[@]}" =~ "stash push" ]]
[[ ! "${lines[@]}" =~ "stash pop" ]]
[[ ${status} -eq 0 ]]
[[ ! ${lines[@]} =~ "stash push" ]]
[[ ! ${lines[@]} =~ "stash pop" ]]
}

@test "'start-work': stash is not applied when it is not found for a given message" {
@test "'start-work': doesn't apply a stash when it wasn't found for a given message" {
fake-fail "git diff-index --quiet HEAD"
check git-elegant start-work test-feature
[[ "$status" -eq 0 ]]
[[ "${lines[@]}" =~ "stash push" ]]
[[ ! "${lines[@]}" =~ "stash pop" ]]
[[ ${status} -eq 0 ]]
[[ ${lines[@]} =~ "stash push" ]]
[[ ! ${lines[@]} =~ "stash pop" ]]
}

@test "'start-work': stash is applied when the failed command reruns" {
@test "'start-work': appies a stash when the failed command reruns" {
repo-non-staged-change "A new line..."
fake-fail "git checkout -b fail"
git-elegant start-work fail || true
Expand Down

0 comments on commit 9e2acc0

Please sign in to comment.