Skip to content

Commit 4e91e35

Browse files
committed
Uses fzf instead of pick; format with black and isort; prepare for 2.0.0
1 parent 22528cf commit 4e91e35

File tree

8 files changed

+165
-126
lines changed

8 files changed

+165
-126
lines changed

README.md

+5-9
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33

44
![License](https://camo.githubusercontent.com/890acbdcb87868b382af9a4b1fac507b9659d9bf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)
55

6-
__pick-git__ is a set of command line tools for leveraging thoughtbot's [pick](https://github.com/calleerlandsson/pick) to turbocharge your Git workflow.
6+
__pick-git__ is a set of command line tools for leveraging [fzf](https://github.com/junegunn/fzf) to turbocharge your Git workflow.
77

88
Git can be a bit of a pain, especially when passing branches or commit hashes as args. Big projects have lots of branches and tons of commits. Finding and copying commit hashes to compare commits, for example, is awkward and slow.
99

10-
`pick`, however, was literally born for jobs like this. __pick-git__ uses `pick` to make working with branches, commits and files in your project's repo a breeze.
10+
`fzf`, however, was literally born for jobs like this. __pick-git__ uses `fzf` to make working with branches, commits and files in your project's repo a breeze.
1111

1212
It's installable via `pip` and works with Python 2/3.
1313

@@ -19,7 +19,7 @@ pip install pick-git
1919

2020

2121
## Dependencies
22-
- [pick](https://github.com/calleerlandsson/pick)
22+
- [fzf](https://github.com/junegunn/fzf)
2323
- [pyperclip](https://github.com/asweigart/pyperclip) (optional, and anyway it's automatically included if you install with `pip`)
2424

2525

@@ -34,7 +34,7 @@ I have `ghp` aliased to `pick-git --function commit`. The function argument is o
3434

3535
`gd` is a shortcut I have that resolves to `git diff`. The `-b` flag allows me to pick both commits and compare them, instead of just picking one and comparing it with HEAD.
3636

37-
At the end the final command that was invoked, `gd 28faaf7 4750072`, was printed to the console. I was able to find two commits and compare them very quickly and with very few keystrokes. __Even if these commits had been in a much bigger project and were months old__, pick's fuzzy select would have found them in no time as long as my commit messages were descriptive.
37+
At the end the final command that was invoked, `gd 28faaf7 4750072`, was printed to the console. I was able to find two commits and compare them very quickly and with very few keystrokes. __Even if these commits had been in a much bigger project and were months old__, fzf's fuzzy select would have found them in no time as long as my commit messages were descriptive.
3838

3939

4040
### Shortcuts to pick-git Public Functions
@@ -92,7 +92,7 @@ Run `pick-git -h`.
9292

9393

9494
## Contributing
95-
The "primitives" for the package are defined in `pick_git/core.py` and are listed below. These are the functions that actually invoke `pick`. If you think of other useful primitives please fork the repo and submit a pull request.
95+
The "primitives" for the package are defined in `pick_git/core.py` and are listed below. These are the functions that actually invoke `fzf`. If you think of other useful primitives please fork the repo and submit a pull request.
9696

9797
- `pick_branch`
9898
- `pick_commit`
@@ -117,7 +117,3 @@ If anyone has ideas I'd love to hear them.
117117

118118
## License
119119
This code is licensed under the [MIT License](https://opensource.org/licenses/MIT).
120-
121-
122-
## Thanks
123-
To Calle Erlandsson and thoughtbot for writing pick =)

pick_git/command_line.py

+56-25
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,51 @@
1-
import subprocess
21
import argparse
2+
import subprocess
33
import sys
44

5-
from .pg import PG
65
from .helpers import PGPublicMethodMixin
6+
from .pg import PG
77

8+
your_version = "2.0.0"
89

9-
parser = argparse.ArgumentParser(description='Invoke a pick-git function.')
10+
parser = argparse.ArgumentParser(description="Invoke a pick-git function.")
1011

11-
parser.add_argument('--function', required=True,
12-
help='Specify public function to invoke. This argument is required. See README for descriptions of public functions.')
12+
parser.add_argument(
13+
"--function",
14+
required=True,
15+
help="Specify public function to invoke. This argument is required. See README for descriptions of public functions.",
16+
)
1317

14-
parser.add_argument('-b', '--both', action='store_true',
15-
help='Pick both branches, tags, commits, or files, where appropriate.')
16-
parser.add_argument('-S', '--show', action='store_true',
17-
help='Show file instead of diffing it, where appropriate.')
18-
parser.add_argument('-s', '--staged', action='store_true',
19-
help='Diff staged files, where appropriate.')
20-
parser.add_argument('-d', '--detailed', action='store_true',
21-
help='Show detail of commits instead of just count, when invoking branch_compare.')
22-
parser.add_argument('-n', '--nocopy', dest='no_copy', action='store_true',
23-
help='Disable automatic copying of branch names, commit hashes, file names, etc.')
18+
parser.add_argument(
19+
"-b",
20+
"--both",
21+
action="store_true",
22+
help="Pick both branches, tags, commits, or files, where appropriate.",
23+
)
24+
parser.add_argument(
25+
"-S",
26+
"--show",
27+
action="store_true",
28+
help="Show file instead of diffing it, where appropriate.",
29+
)
30+
parser.add_argument("-s", "--staged", action="store_true", help="Diff staged files, where appropriate.")
31+
parser.add_argument(
32+
"-d",
33+
"--detailed",
34+
action="store_true",
35+
help="Show detail of commits instead of just count, when invoking branch_compare.",
36+
)
37+
parser.add_argument(
38+
"-n",
39+
"--nocopy",
40+
dest="no_copy",
41+
action="store_true",
42+
help="Disable automatic copying of branch names, commit hashes, file names, etc.",
43+
)
2444

25-
parser.add_argument('--shell',
26-
help='Specify shell invoked interactively when `execute` is invoked.')
27-
parser.add_argument('--rcfile',
28-
help='Specify startup file invoked by shell when `execute` is invoked.')
45+
parser.add_argument("--shell", help="Specify shell invoked interactively when `execute` is invoked.")
46+
parser.add_argument("--rcfile", help="Specify startup file invoked by shell when `execute` is invoked.")
2947

30-
parser.add_argument('args', help='Pass other args to function.', nargs='*')
48+
parser.add_argument("args", help="Pass other args to function.", nargs="*")
3149

3250

3351
def main():
@@ -36,12 +54,25 @@ def main():
3654
3755
http://python-packaging.readthedocs.io/en/latest/command-line-scripts.html#the-console-scripts-entry-point
3856
"""
57+
if len(sys.argv) > 1 and (sys.argv[1] == "-v" or sys.argv[1] == "--version"):
58+
print("pick-git version {}".format(your_version))
59+
sys.exit(0)
60+
3961
args = parser.parse_args()
40-
kwargs = {name: args.__getattribute__(name) for name in [
41-
'both', 'show', 'staged', 'detailed', 'no_copy', 'shell', 'rcfile',
42-
]}
43-
if not subprocess.call(['which', 'pick']) == 0:
44-
print("pick isn't installed! exiting...")
62+
kwargs = {
63+
name: args.__getattribute__(name)
64+
for name in [
65+
"both",
66+
"show",
67+
"staged",
68+
"detailed",
69+
"no_copy",
70+
"shell",
71+
"rcfile",
72+
]
73+
}
74+
if not subprocess.call(["which", "fzf"]) == 0:
75+
print("fzf isn't installed! exiting...")
4576
sys.exit()
4677
pg = PG(**kwargs)
4778
if not hasattr(PGPublicMethodMixin, args.function):

pick_git/core.py

+37-43
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1+
import os
12
import subprocess
23
import sys
3-
import os
4-
from subprocess import STDOUT, PIPE
54
from functools import wraps
5+
from subprocess import PIPE
66

77

88
def repository_root():
9-
"""Return full path to root of repo.
10-
"""
11-
return subprocess.check_output(['git', 'rev-parse', '--show-toplevel']).strip().decode('utf-8')
9+
"""Return full path to root of repo."""
10+
return subprocess.check_output(["git", "rev-parse", "--show-toplevel"]).strip().decode("utf-8")
1211

1312

1413
def cd_repository_root():
@@ -20,20 +19,18 @@ def cd_repository_root():
2019

2120

2221
def current_branch():
23-
"""Return name of currently checked out branch.
24-
"""
25-
return subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']).strip().decode('utf-8')
22+
"""Return name of currently checked out branch."""
23+
return subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]).strip().decode("utf-8")
2624

2725

2826
def add_new_line(b):
29-
"""To end of `str` or `bytes` instance.
30-
"""
27+
"""To end of `str` or `bytes` instance."""
3128
if sys.version_info < (3, 0, 0):
32-
if b[-1] != '\n':
33-
b += '\n'
29+
if b[-1] != "\n":
30+
b += "\n"
3431
else:
35-
if b[-1:] != bytes('\n', 'utf-8'):
36-
b += bytes('\n', 'utf-8')
32+
if b[-1:] != bytes("\n", "utf-8"):
33+
b += bytes("\n", "utf-8")
3734
return b
3835

3936

@@ -47,87 +44,84 @@ def exit_on_keyboard_interrupt(f):
4744
4845
See here: https://stackoverflow.com/questions/39499959/terminating-a-subprocess-with-keyboardinterrupt/39503654
4946
"""
47+
5048
@wraps(f)
5149
def wrapper(*args, **kwargs):
52-
raise_exception = kwargs.pop('raise_exception', False)
50+
raise_exception = kwargs.pop("raise_exception", False)
5351
try:
5452
return f(*args, **kwargs)
5553
except KeyboardInterrupt:
5654
if not raise_exception:
5755
sys.exit()
5856
raise KeyboardInterrupt
57+
5958
return wrapper
6059

6160

6261
@exit_on_keyboard_interrupt
6362
def pick_branch(*args):
64-
"""Pick a branch, local or remote.
65-
"""
66-
branches = subprocess.check_output(('git', 'branch', '-a') + args)
67-
p = subprocess.Popen(['pick'], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
63+
"""Pick a branch, local or remote."""
64+
branches = subprocess.check_output(("git", "branch", "-a") + args)
65+
p = subprocess.Popen(["fzf"], stdin=PIPE, stdout=PIPE)
6866
branch = p.communicate(input=branches)[0]
6967
if not branch:
7068
raise KeyboardInterrupt
71-
return branch.split()[-1].decode('utf-8')
69+
return branch.split()[-1].decode("utf-8")
7270

7371

7472
@exit_on_keyboard_interrupt
7573
def pick_tag(*args):
76-
"""Pick a local tag.
77-
"""
78-
branches = subprocess.check_output(('git', 'tag', '-l') + args)
79-
p = subprocess.Popen(['pick'], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
74+
"""Pick a local tag."""
75+
branches = subprocess.check_output(("git", "tag", "-l") + args)
76+
p = subprocess.Popen(["fzf"], stdin=PIPE, stdout=PIPE)
8077
branch = p.communicate(input=branches)[0]
8178
if not branch:
8279
raise KeyboardInterrupt
83-
return branch.split()[-1].decode('utf-8')
80+
return branch.split()[-1].decode("utf-8")
8481

8582

8683
@exit_on_keyboard_interrupt
8784
def pick_commit(*args):
88-
"""Pick a commit hash.
89-
"""
90-
commits = subprocess.check_output(('git', 'log', "--pretty=format:%h %ad | %s%d [%an]", '--date=short') + args)
91-
p = subprocess.Popen(['pick'], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
85+
"""Pick a commit hash."""
86+
commits = subprocess.check_output(("git", "log", "--pretty=format:%h %ad | %s%d [%an]", "--date=short") + args)
87+
p = subprocess.Popen(["fzf"], stdin=PIPE, stdout=PIPE)
9288
commit = p.communicate(input=add_new_line(commits))[0]
9389
if not commit:
9490
raise KeyboardInterrupt
95-
return commit.split()[0].decode('utf-8')
91+
return commit.split()[0].decode("utf-8")
9692

9793

9894
@exit_on_keyboard_interrupt
9995
def pick_commit_reflog(*args):
100-
"""Pick a commit hash from the reflog.
101-
"""
102-
commits = subprocess.check_output(('git', 'reflog', '--date=short') + args)
103-
p = subprocess.Popen(['pick'], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
96+
"""Pick a commit hash from the reflog."""
97+
commits = subprocess.check_output(("git", "reflog", "--date=short") + args)
98+
p = subprocess.Popen(["fzf"], stdin=PIPE, stdout=PIPE)
10499
commit = p.communicate(input=add_new_line(commits))[0]
105100
if not commit:
106101
raise KeyboardInterrupt
107-
return commit.split()[0].decode('utf-8')
102+
return commit.split()[0].decode("utf-8")
108103

109104

110105
@exit_on_keyboard_interrupt
111106
def pick_modified_file(*args):
112107
"""Pick a file whose state differs between branches or commits, which are
113108
passed in `args`. `args` can contain between 0 and 2 elements.
114109
"""
115-
files = subprocess.check_output(('git', 'diff', '--name-only') + args)
116-
p = subprocess.Popen(['pick'], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
110+
files = subprocess.check_output(("git", "diff", "--name-only") + args)
111+
p = subprocess.Popen(["fzf"], stdin=PIPE, stdout=PIPE)
117112
file = p.communicate(input=files)[0]
118113
if not file:
119114
raise KeyboardInterrupt
120-
return file.strip().decode('utf-8')
115+
return file.strip().decode("utf-8")
121116

122117

123118
@exit_on_keyboard_interrupt
124119
def pick_file(*args):
125-
"""Pick a file from the index.
126-
"""
120+
"""Pick a file from the index."""
127121
branch = current_branch()
128-
files = subprocess.check_output(('git', 'ls-tree', '-r', branch, '--name-only') + args)
129-
p = subprocess.Popen(['pick'], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
122+
files = subprocess.check_output(("git", "ls-tree", "-r", branch, "--name-only") + args)
123+
p = subprocess.Popen(["fzf"], stdin=PIPE, stdout=PIPE)
130124
file = p.communicate(input=files)[0]
131125
if not file:
132126
raise KeyboardInterrupt
133-
return file.strip().decode('utf-8')
127+
return file.strip().decode("utf-8")

0 commit comments

Comments
 (0)