diff --git a/README.md b/README.md index fc695de..5f7fb5b 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,9 @@ using the matched rule and runs it. Rules enabled by default are as follows: * `git_diff_staged` – adds `--staged` to previous `git diff` with unexpected output; * `git_no_command` – fixes wrong git commands like `git brnch`; * `git_pull` – sets upstream before executing previous `git pull`; +* `git_pull_clone` – clones instead of pulling when the repo does not exist; * `git_push` – adds `--set-upstream origin $branch` to previous failed `git push`; +* `git_push_force` – adds `--force` to a `git push`; * `git_stash` – stashes you local modifications before rebasing or switching branch; * `go_run` – appends `.go` extension when compiling/running Go programs * `grep_recursive` – adds `-r` when you trying to grep directory; diff --git a/tests/rules/test_git_pull_clone.py b/tests/rules/test_git_pull_clone.py new file mode 100644 index 0000000..07249fa --- /dev/null +++ b/tests/rules/test_git_pull_clone.py @@ -0,0 +1,21 @@ +import pytest +from thefuck.rules.git_pull_clone import match, get_new_command +from tests.utils import Command + + +git_err = ''' +fatal: Not a git repository (or any parent up to mount point /home) +Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set). +''' + + +@pytest.mark.parametrize('command', [ + Command(script='git pull git@github.com:mcarton/thefuck.git', stderr=git_err)]) +def test_match(command): + assert match(command, None) + + +@pytest.mark.parametrize('command, output', [ + (Command(script='git pull git@github.com:mcarton/thefuck.git', stderr=git_err), 'git clone git@github.com:mcarton/thefuck.git')]) +def test_get_new_command(command, output): + assert get_new_command(command, None) == output diff --git a/tests/rules/test_git_push_force.py b/tests/rules/test_git_push_force.py new file mode 100644 index 0000000..c55e77d --- /dev/null +++ b/tests/rules/test_git_push_force.py @@ -0,0 +1,52 @@ +import pytest +from thefuck.rules.git_push_force import match, get_new_command +from tests.utils import Command + + +git_err = ''' +To /tmp/foo + ! [rejected] master -> master (non-fast-forward) + error: failed to push some refs to '/tmp/bar' + hint: Updates were rejected because the tip of your current branch is behind + hint: its remote counterpart. Integrate the remote changes (e.g. + hint: 'git pull ...') before pushing again. + hint: See the 'Note about fast-forwards' in 'git push --help' for details. +''' + +git_uptodate = 'Everything up-to-date' +git_ok = ''' +Counting objects: 3, done. +Delta compression using up to 4 threads. +Compressing objects: 100% (2/2), done. +Writing objects: 100% (3/3), 282 bytes | 0 bytes/s, done. +Total 3 (delta 0), reused 0 (delta 0) +To /tmp/bar + 514eed3..f269c79 master -> master +''' + + +@pytest.mark.parametrize('command', [ + Command(script='git push', stderr=git_err), + Command(script='git push nvbn', stderr=git_err), + Command(script='git push nvbn master', stderr=git_err)]) +def test_match(command): + assert match(command, None) + + +@pytest.mark.parametrize('command', [ + Command(script='git push', stderr=git_ok), + Command(script='git push', stderr=git_uptodate), + Command(script='git push nvbn', stderr=git_ok), + Command(script='git push nvbn master', stderr=git_uptodate), + Command(script='git push nvbn', stderr=git_ok), + Command(script='git push nvbn master', stderr=git_uptodate)]) +def test_not_match(command): + assert not match(command, None) + + +@pytest.mark.parametrize('command, output', [ + (Command(script='git push', stderr=git_err), 'git push --force'), + (Command(script='git push nvbn', stderr=git_err), 'git push --force nvbn'), + (Command(script='git push nvbn master', stderr=git_err), 'git push --force nvbn master')]) +def test_get_new_command(command, output): + assert get_new_command(command, None) == output diff --git a/thefuck/rules/git_pull_clone.py b/thefuck/rules/git_pull_clone.py new file mode 100644 index 0000000..c5e68a7 --- /dev/null +++ b/thefuck/rules/git_pull_clone.py @@ -0,0 +1,14 @@ +import re +from thefuck import utils, shells + + +@utils.git_support +def match(command, settings): + return ('git pull' in command.script + and 'fatal: Not a git repository' in command.stderr + and "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)." in command.stderr) + + +@utils.git_support +def get_new_command(command, settings): + return command.script.replace(' pull ', ' clone ') diff --git a/thefuck/rules/git_push_force.py b/thefuck/rules/git_push_force.py new file mode 100644 index 0000000..53d2117 --- /dev/null +++ b/thefuck/rules/git_push_force.py @@ -0,0 +1,15 @@ +from thefuck import utils + + +@utils.git_support +def match(command, settings): + return ('git' in command.script + and 'push' in command.script + and '! [rejected]' in command.stderr + and 'failed to push some refs to' in command.stderr + and 'Updates were rejected because the tip of your current branch is behind' in command.stderr) + + +@utils.git_support +def get_new_command(command, settings): + return command.script.replace('push', 'push --force')