pygitgo 1.6.0__tar.gz → 1.6.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pygitgo-1.6.0/src/pygitgo.egg-info → pygitgo-1.6.2}/PKG-INFO +51 -32
- {pygitgo-1.6.0 → pygitgo-1.6.2}/README.md +49 -31
- {pygitgo-1.6.0 → pygitgo-1.6.2}/pyproject.toml +6 -1
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/commands/git_operations.py +5 -4
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/commands/jump.py +12 -11
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/commands/pull.py +8 -6
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/commands/state.py +10 -12
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/commands/undo.py +13 -18
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/main.py +18 -15
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/utils/setup.py +2 -1
- {pygitgo-1.6.0 → pygitgo-1.6.2/src/pygitgo.egg-info}/PKG-INFO +51 -32
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo.egg-info/requires.txt +1 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/tests/test_config.py +1 -1
- {pygitgo-1.6.0 → pygitgo-1.6.2}/tests/test_git_operations.py +4 -6
- {pygitgo-1.6.0 → pygitgo-1.6.2}/tests/test_jump.py +0 -2
- {pygitgo-1.6.0 → pygitgo-1.6.2}/tests/test_pull.py +7 -15
- {pygitgo-1.6.0 → pygitgo-1.6.2}/tests/test_setup.py +1 -1
- {pygitgo-1.6.0 → pygitgo-1.6.2}/tests/test_state.py +9 -20
- {pygitgo-1.6.0 → pygitgo-1.6.2}/tests/test_undo.py +10 -19
- {pygitgo-1.6.0 → pygitgo-1.6.2}/LICENSE +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/setup.cfg +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/__init__.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/auth/__init__.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/auth/account.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/auth/manager.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/auth/ssh_utils.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/commands/__init__.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/commands/staging.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/exceptions.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/utils/__init__.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/utils/colors.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/utils/config.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/utils/executor.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/utils/platform_utils.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo/utils/update_checker.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo.egg-info/SOURCES.txt +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo.egg-info/dependency_links.txt +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo.egg-info/entry_points.txt +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/src/pygitgo.egg-info/top_level.txt +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/tests/test_main.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/tests/test_platform.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/tests/test_staging.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/tests/test_update_checker.py +0 -0
- {pygitgo-1.6.0 → pygitgo-1.6.2}/tests/test_url_validator.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pygitgo
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.2
|
|
4
4
|
Summary: GitGo CLI - Your Fast Git Companion. Simplifies git push, link, stash, and user management.
|
|
5
5
|
Author: Huerte
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -20,11 +20,12 @@ Requires-Dist: pick>=2.0
|
|
|
20
20
|
Provides-Extra: dev
|
|
21
21
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
22
22
|
Requires-Dist: pytest-mock>=3.10; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
23
24
|
Dynamic: license-file
|
|
24
25
|
|
|
25
26
|
<div align="center">
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+

|
|
28
29
|
|
|
29
30
|
[](https://github.com/Huerte/GitGo/actions)
|
|
30
31
|
[](https://pypi.org/project/pygitgo)
|
|
@@ -38,6 +39,14 @@ Dynamic: license-file
|
|
|
38
39
|
|
|
39
40
|
<a href="https://github.com/Huerte/GitGo/issues">Report Bug</a> · <a href="https://github.com/Huerte/GitGo/issues">Request Feature</a>
|
|
40
41
|
|
|
42
|
+
<br />
|
|
43
|
+
|
|
44
|
+
If GitGo saves you time, consider buying me a coffee. It helps keep the project going.
|
|
45
|
+
|
|
46
|
+
<a href="https://ko-fi.com/huerte">
|
|
47
|
+
<img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support on Ko-fi" />
|
|
48
|
+
</a>
|
|
49
|
+
|
|
41
50
|
</div>
|
|
42
51
|
|
|
43
52
|
---
|
|
@@ -63,7 +72,10 @@ gitgo link https://github.com/username/repo.git "init"
|
|
|
63
72
|
- [Command Reference](#command-reference)
|
|
64
73
|
- [How It Works](#how-it-works)
|
|
65
74
|
- [Contributing](#contributing)
|
|
75
|
+
- [Credits](#credits)
|
|
66
76
|
- [License](#license)
|
|
77
|
+
- [Changelog](CHANGELOG.md)
|
|
78
|
+
- [Contributing Guide](CONTRIBUTING.md)
|
|
67
79
|
|
|
68
80
|
---
|
|
69
81
|
|
|
@@ -75,17 +87,18 @@ gitgo link https://github.com/username/repo.git "init"
|
|
|
75
87
|
|
|
76
88
|
## Features
|
|
77
89
|
|
|
78
|
-
GitGo provides a CLI environment designed for faster and simpler Git workflows.
|
|
90
|
+
GitGo provides a CLI environment designed for faster and simpler Git workflows.
|
|
91
|
+
No chained commands, no cryptic flags — just short commands you can actually remember.
|
|
79
92
|
|
|
80
|
-
- **Simplified Git Operations:** Replaces chained commands with single
|
|
81
|
-
- **
|
|
82
|
-
- **
|
|
93
|
+
- **Simplified Git Operations:** Replaces chained commands with single commands for linking, pushing, and stashing.
|
|
94
|
+
- **Undo Operations:** Safely undo commits, un-queue files, or wipe local changes without any complex Git jargon.
|
|
95
|
+
- **Safe Branch Switching:** Safely traverse branches with `jump`. Auto-stashes messy code and prevents merge conflict disasters with a Try-And-Revert safety engine.
|
|
83
96
|
- **State Management:** A human-readable interface over `git stash`. States are named and listed by index so you never have to remember cryptic stash references.
|
|
84
97
|
- **Custom Defaults:** Save your preferred branch name and commit message locally so you never have to type them again.
|
|
85
98
|
- **Auto-Update Checker:** Silently checks for newer versions in the background and notifies you, without slowing down your commands.
|
|
86
99
|
- **SSH Auto-Setup:** Generates an SSH key, adds it to `ssh-agent`, and opens your GitHub settings automatically.
|
|
87
100
|
- **HTTPS to SSH Conversion:** Silently converts the remote to SSH before pushing if your SSH is configured.
|
|
88
|
-
- **Termux Compatibility:** Works
|
|
101
|
+
- **Termux Compatibility:** Works on Android via Termux, handling common issues like dubious ownership errors out of the box.
|
|
89
102
|
|
|
90
103
|
---
|
|
91
104
|
|
|
@@ -94,16 +107,38 @@ GitGo provides a CLI environment designed for faster and simpler Git workflows.
|
|
|
94
107
|
### Prerequisites
|
|
95
108
|
|
|
96
109
|
- **Python 3.8+**
|
|
97
|
-
- **Git 2.x
|
|
98
|
-
- **OpenSSH
|
|
110
|
+
- **Git 2.x+**: [git-scm.com](https://git-scm.com)
|
|
111
|
+
- **OpenSSH**: required for `gitgo user login` (pre-installed on most systems)
|
|
99
112
|
- A **GitHub account**
|
|
100
113
|
|
|
101
114
|
### Install from PyPI
|
|
102
115
|
|
|
116
|
+
For Windows users or environments without global pip restrictions, you can install GitGo directly via pip:
|
|
117
|
+
|
|
103
118
|
```bash
|
|
104
119
|
pip install pygitgo
|
|
105
120
|
```
|
|
106
121
|
|
|
122
|
+
*(Alternatively, you can use `pipx install pygitgo` if you prefer isolated environments).*
|
|
123
|
+
|
|
124
|
+
### Install via pipx (Cross-Platform)
|
|
125
|
+
|
|
126
|
+
If you already have `pipx` installed, you can use it to safely install GitGo on any operating system:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pipx install pygitgo
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Quick Install (Linux & macOS)
|
|
133
|
+
|
|
134
|
+
The easiest way to install GitGo on Unix systems without worrying about Python environments or PEP 668 restrictions is using our install script:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
curl -sSL https://raw.githubusercontent.com/Huerte/GitGo/main/install.sh | bash
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
This will automatically create an isolated environment and place `gitgo` in your `~/.local/bin` folder.
|
|
141
|
+
|
|
107
142
|
Verify the installation:
|
|
108
143
|
|
|
109
144
|
```bash
|
|
@@ -142,13 +177,13 @@ gitgo link https://github.com/username/repo.git "Initial commit"
|
|
|
142
177
|
gitgo push main "Fix auth bug"
|
|
143
178
|
|
|
144
179
|
# Create a new branch and push
|
|
145
|
-
gitgo push -n
|
|
180
|
+
gitgo push -n feat/login "Add login flow"
|
|
146
181
|
```
|
|
147
182
|
|
|
148
183
|
### 4. Safely Switch Branches
|
|
149
184
|
Jump to a different branch without worrying about your uncommitted changes. GitGo will safely stash them, hop to the new branch, sync with `main`, and carefully unpack them.
|
|
150
185
|
```bash
|
|
151
|
-
gitgo jump
|
|
186
|
+
gitgo jump feat/new-login
|
|
152
187
|
```
|
|
153
188
|
|
|
154
189
|
### 5. Safely Undo Mistakes
|
|
@@ -225,7 +260,7 @@ gitgo jump <branch>
|
|
|
225
260
|
|
|
226
261
|
### `gitgo undo`
|
|
227
262
|
|
|
228
|
-
Safely undo recent actions and mistakes using
|
|
263
|
+
Safely undo recent actions and mistakes using plain commands that say exactly what they do.
|
|
229
264
|
|
|
230
265
|
```bash
|
|
231
266
|
gitgo undo commit # Undo your last commit without losing files
|
|
@@ -235,7 +270,7 @@ gitgo undo changes # Permanently wipe all new files and local edits
|
|
|
235
270
|
|
|
236
271
|
### `gitgo state`
|
|
237
272
|
|
|
238
|
-
A
|
|
273
|
+
A named interface over `git stash`.
|
|
239
274
|
|
|
240
275
|
```bash
|
|
241
276
|
gitgo state list # show all saved states
|
|
@@ -291,13 +326,9 @@ gitgo -r # verify GitGo is ready
|
|
|
291
326
|
|
|
292
327
|
## Contributing
|
|
293
328
|
|
|
294
|
-
Contributions are welcome
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
2. Create a Feature Branch (`git checkout -b feature/your-feature`)
|
|
298
|
-
3. Commit Changes
|
|
299
|
-
4. Push to the Branch (`git push origin feature/your-feature`)
|
|
300
|
-
5. Open a Pull Request
|
|
329
|
+
Contributions are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide,
|
|
330
|
+
including project structure, test instructions, commit conventions, and a
|
|
331
|
+
[Good First Issues](CONTRIBUTING.md#good-first-issues) table if you are not sure where to start.
|
|
301
332
|
|
|
302
333
|
---
|
|
303
334
|
|
|
@@ -314,18 +345,6 @@ Contributions are welcome and appreciated!
|
|
|
314
345
|
|
|
315
346
|
---
|
|
316
347
|
|
|
317
|
-
## Support
|
|
318
|
-
|
|
319
|
-
If GitGo saves you time, consider buying me a coffee. It helps keep the project going.
|
|
320
|
-
|
|
321
|
-
<div align="center">
|
|
322
|
-
<a href="https://ko-fi.com/huerte">
|
|
323
|
-
<img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support on Ko-fi" />
|
|
324
|
-
</a>
|
|
325
|
-
</div>
|
|
326
|
-
|
|
327
|
-
---
|
|
328
|
-
|
|
329
348
|
## License
|
|
330
349
|
|
|
331
350
|
Distributed under the **GPLv3** License. See [`LICENSE`](LICENSE) for details.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+

|
|
4
4
|
|
|
5
5
|
[](https://github.com/Huerte/GitGo/actions)
|
|
6
6
|
[](https://pypi.org/project/pygitgo)
|
|
@@ -14,6 +14,14 @@
|
|
|
14
14
|
|
|
15
15
|
<a href="https://github.com/Huerte/GitGo/issues">Report Bug</a> · <a href="https://github.com/Huerte/GitGo/issues">Request Feature</a>
|
|
16
16
|
|
|
17
|
+
<br />
|
|
18
|
+
|
|
19
|
+
If GitGo saves you time, consider buying me a coffee. It helps keep the project going.
|
|
20
|
+
|
|
21
|
+
<a href="https://ko-fi.com/huerte">
|
|
22
|
+
<img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support on Ko-fi" />
|
|
23
|
+
</a>
|
|
24
|
+
|
|
17
25
|
</div>
|
|
18
26
|
|
|
19
27
|
---
|
|
@@ -39,7 +47,10 @@ gitgo link https://github.com/username/repo.git "init"
|
|
|
39
47
|
- [Command Reference](#command-reference)
|
|
40
48
|
- [How It Works](#how-it-works)
|
|
41
49
|
- [Contributing](#contributing)
|
|
50
|
+
- [Credits](#credits)
|
|
42
51
|
- [License](#license)
|
|
52
|
+
- [Changelog](CHANGELOG.md)
|
|
53
|
+
- [Contributing Guide](CONTRIBUTING.md)
|
|
43
54
|
|
|
44
55
|
---
|
|
45
56
|
|
|
@@ -51,17 +62,18 @@ gitgo link https://github.com/username/repo.git "init"
|
|
|
51
62
|
|
|
52
63
|
## Features
|
|
53
64
|
|
|
54
|
-
GitGo provides a CLI environment designed for faster and simpler Git workflows.
|
|
65
|
+
GitGo provides a CLI environment designed for faster and simpler Git workflows.
|
|
66
|
+
No chained commands, no cryptic flags — just short commands you can actually remember.
|
|
55
67
|
|
|
56
|
-
- **Simplified Git Operations:** Replaces chained commands with single
|
|
57
|
-
- **
|
|
58
|
-
- **
|
|
68
|
+
- **Simplified Git Operations:** Replaces chained commands with single commands for linking, pushing, and stashing.
|
|
69
|
+
- **Undo Operations:** Safely undo commits, un-queue files, or wipe local changes without any complex Git jargon.
|
|
70
|
+
- **Safe Branch Switching:** Safely traverse branches with `jump`. Auto-stashes messy code and prevents merge conflict disasters with a Try-And-Revert safety engine.
|
|
59
71
|
- **State Management:** A human-readable interface over `git stash`. States are named and listed by index so you never have to remember cryptic stash references.
|
|
60
72
|
- **Custom Defaults:** Save your preferred branch name and commit message locally so you never have to type them again.
|
|
61
73
|
- **Auto-Update Checker:** Silently checks for newer versions in the background and notifies you, without slowing down your commands.
|
|
62
74
|
- **SSH Auto-Setup:** Generates an SSH key, adds it to `ssh-agent`, and opens your GitHub settings automatically.
|
|
63
75
|
- **HTTPS to SSH Conversion:** Silently converts the remote to SSH before pushing if your SSH is configured.
|
|
64
|
-
- **Termux Compatibility:** Works
|
|
76
|
+
- **Termux Compatibility:** Works on Android via Termux, handling common issues like dubious ownership errors out of the box.
|
|
65
77
|
|
|
66
78
|
---
|
|
67
79
|
|
|
@@ -70,16 +82,38 @@ GitGo provides a CLI environment designed for faster and simpler Git workflows.
|
|
|
70
82
|
### Prerequisites
|
|
71
83
|
|
|
72
84
|
- **Python 3.8+**
|
|
73
|
-
- **Git 2.x
|
|
74
|
-
- **OpenSSH
|
|
85
|
+
- **Git 2.x+**: [git-scm.com](https://git-scm.com)
|
|
86
|
+
- **OpenSSH**: required for `gitgo user login` (pre-installed on most systems)
|
|
75
87
|
- A **GitHub account**
|
|
76
88
|
|
|
77
89
|
### Install from PyPI
|
|
78
90
|
|
|
91
|
+
For Windows users or environments without global pip restrictions, you can install GitGo directly via pip:
|
|
92
|
+
|
|
79
93
|
```bash
|
|
80
94
|
pip install pygitgo
|
|
81
95
|
```
|
|
82
96
|
|
|
97
|
+
*(Alternatively, you can use `pipx install pygitgo` if you prefer isolated environments).*
|
|
98
|
+
|
|
99
|
+
### Install via pipx (Cross-Platform)
|
|
100
|
+
|
|
101
|
+
If you already have `pipx` installed, you can use it to safely install GitGo on any operating system:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
pipx install pygitgo
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Quick Install (Linux & macOS)
|
|
108
|
+
|
|
109
|
+
The easiest way to install GitGo on Unix systems without worrying about Python environments or PEP 668 restrictions is using our install script:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
curl -sSL https://raw.githubusercontent.com/Huerte/GitGo/main/install.sh | bash
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
This will automatically create an isolated environment and place `gitgo` in your `~/.local/bin` folder.
|
|
116
|
+
|
|
83
117
|
Verify the installation:
|
|
84
118
|
|
|
85
119
|
```bash
|
|
@@ -118,13 +152,13 @@ gitgo link https://github.com/username/repo.git "Initial commit"
|
|
|
118
152
|
gitgo push main "Fix auth bug"
|
|
119
153
|
|
|
120
154
|
# Create a new branch and push
|
|
121
|
-
gitgo push -n
|
|
155
|
+
gitgo push -n feat/login "Add login flow"
|
|
122
156
|
```
|
|
123
157
|
|
|
124
158
|
### 4. Safely Switch Branches
|
|
125
159
|
Jump to a different branch without worrying about your uncommitted changes. GitGo will safely stash them, hop to the new branch, sync with `main`, and carefully unpack them.
|
|
126
160
|
```bash
|
|
127
|
-
gitgo jump
|
|
161
|
+
gitgo jump feat/new-login
|
|
128
162
|
```
|
|
129
163
|
|
|
130
164
|
### 5. Safely Undo Mistakes
|
|
@@ -201,7 +235,7 @@ gitgo jump <branch>
|
|
|
201
235
|
|
|
202
236
|
### `gitgo undo`
|
|
203
237
|
|
|
204
|
-
Safely undo recent actions and mistakes using
|
|
238
|
+
Safely undo recent actions and mistakes using plain commands that say exactly what they do.
|
|
205
239
|
|
|
206
240
|
```bash
|
|
207
241
|
gitgo undo commit # Undo your last commit without losing files
|
|
@@ -211,7 +245,7 @@ gitgo undo changes # Permanently wipe all new files and local edits
|
|
|
211
245
|
|
|
212
246
|
### `gitgo state`
|
|
213
247
|
|
|
214
|
-
A
|
|
248
|
+
A named interface over `git stash`.
|
|
215
249
|
|
|
216
250
|
```bash
|
|
217
251
|
gitgo state list # show all saved states
|
|
@@ -267,13 +301,9 @@ gitgo -r # verify GitGo is ready
|
|
|
267
301
|
|
|
268
302
|
## Contributing
|
|
269
303
|
|
|
270
|
-
Contributions are welcome
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
2. Create a Feature Branch (`git checkout -b feature/your-feature`)
|
|
274
|
-
3. Commit Changes
|
|
275
|
-
4. Push to the Branch (`git push origin feature/your-feature`)
|
|
276
|
-
5. Open a Pull Request
|
|
304
|
+
Contributions are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide,
|
|
305
|
+
including project structure, test instructions, commit conventions, and a
|
|
306
|
+
[Good First Issues](CONTRIBUTING.md#good-first-issues) table if you are not sure where to start.
|
|
277
307
|
|
|
278
308
|
---
|
|
279
309
|
|
|
@@ -290,18 +320,6 @@ Contributions are welcome and appreciated!
|
|
|
290
320
|
|
|
291
321
|
---
|
|
292
322
|
|
|
293
|
-
## Support
|
|
294
|
-
|
|
295
|
-
If GitGo saves you time, consider buying me a coffee. It helps keep the project going.
|
|
296
|
-
|
|
297
|
-
<div align="center">
|
|
298
|
-
<a href="https://ko-fi.com/huerte">
|
|
299
|
-
<img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support on Ko-fi" />
|
|
300
|
-
</a>
|
|
301
|
-
</div>
|
|
302
|
-
|
|
303
|
-
---
|
|
304
|
-
|
|
305
323
|
## License
|
|
306
324
|
|
|
307
325
|
Distributed under the **GPLv3** License. See [`LICENSE`](LICENSE) for details.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pygitgo"
|
|
7
|
-
version = "1.6.
|
|
7
|
+
version = "1.6.2"
|
|
8
8
|
description = "GitGo CLI - Your Fast Git Companion. Simplifies git push, link, stash, and user management."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "GPL-3.0-or-later"}
|
|
@@ -29,6 +29,7 @@ dependencies = [
|
|
|
29
29
|
dev = [
|
|
30
30
|
"pytest>=7.0",
|
|
31
31
|
"pytest-mock>=3.10",
|
|
32
|
+
"pytest-cov>=4.0"
|
|
32
33
|
]
|
|
33
34
|
|
|
34
35
|
[project.urls]
|
|
@@ -40,3 +41,7 @@ gitgo = "pygitgo.main:main"
|
|
|
40
41
|
|
|
41
42
|
[tool.setuptools.packages.find]
|
|
42
43
|
where = ["src"]
|
|
44
|
+
|
|
45
|
+
[tool.pytest.ini_options]
|
|
46
|
+
testpaths = ["tests"]
|
|
47
|
+
addopts = "--cov=pygitgo --cov-report=term-missing"
|
|
@@ -2,6 +2,7 @@ from pygitgo.auth.ssh_utils import convert_https_to_ssh, is_ssh_url, check_conne
|
|
|
2
2
|
from pygitgo.utils.colors import info, success, warning, error
|
|
3
3
|
from pygitgo.utils.executor import run_command
|
|
4
4
|
from pygitgo.utils.config import get_config
|
|
5
|
+
from pygitgo.exceptions import GitGoError
|
|
5
6
|
from argparse import Namespace
|
|
6
7
|
import subprocess
|
|
7
8
|
import sys
|
|
@@ -11,7 +12,7 @@ import os
|
|
|
11
12
|
def get_status_content():
|
|
12
13
|
status = run_command(["git", "status", "--porcelain"], allow_fail=True)
|
|
13
14
|
if isinstance(status, subprocess.CalledProcessError) or not status.strip():
|
|
14
|
-
|
|
15
|
+
raise GitGoError("\nWorking tree is clean. Nothing to commit.\n")
|
|
15
16
|
return status
|
|
16
17
|
|
|
17
18
|
def get_current_branch():
|
|
@@ -41,7 +42,7 @@ def git_new_branch(branch):
|
|
|
41
42
|
from pygitgo.commands.jump import jump_operation
|
|
42
43
|
jump_operation(Namespace(branch=branch))
|
|
43
44
|
else:
|
|
44
|
-
|
|
45
|
+
raise GitGoError(f"\nOperation canceled. Branch '{branch}' already exists.\n")
|
|
45
46
|
else:
|
|
46
47
|
success(f"\nBranch '{branch}' created.\n")
|
|
47
48
|
|
|
@@ -161,7 +162,7 @@ def git_push(branch):
|
|
|
161
162
|
if "rebase in progress" in str(e):
|
|
162
163
|
handle_rebase()
|
|
163
164
|
else:
|
|
164
|
-
|
|
165
|
+
raise GitGoError()
|
|
165
166
|
|
|
166
167
|
|
|
167
168
|
def handle_rebase():
|
|
@@ -175,6 +176,6 @@ def handle_rebase():
|
|
|
175
176
|
info(" git add <files>")
|
|
176
177
|
info(" git rebase --continue")
|
|
177
178
|
warning("When finished, run 'gitgo push <branch> <message>' again.\n")
|
|
178
|
-
|
|
179
|
+
raise GitGoError()
|
|
179
180
|
|
|
180
181
|
return True
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from pygitgo.exceptions import GitGoError
|
|
1
2
|
from pygitgo.commands.git_operations import (
|
|
2
3
|
is_branch_exist, get_current_branch, git_new_branch, get_main_branch
|
|
3
4
|
)
|
|
@@ -30,12 +31,11 @@ def jump_operation(args):
|
|
|
30
31
|
|
|
31
32
|
if original_branch == target_branch:
|
|
32
33
|
warning(f"\nYou are already on branch '{target_branch}'.\n")
|
|
33
|
-
|
|
34
|
+
return
|
|
34
35
|
|
|
35
36
|
has_changes = run_command(['git', 'status', '--porcelain'], allow_fail=True, loading_msg="Checking for uncommitted changes...")
|
|
36
37
|
if isinstance(has_changes, subprocess.CalledProcessError):
|
|
37
|
-
|
|
38
|
-
sys.exit(1)
|
|
38
|
+
raise GitGoError("\nUnable to check for uncommitted changes. Please ensure you're in a valid git repository.\n")
|
|
39
39
|
|
|
40
40
|
stashed_code = False
|
|
41
41
|
if has_changes.strip():
|
|
@@ -43,12 +43,12 @@ def jump_operation(args):
|
|
|
43
43
|
user_input = input("Do you want to move these changes to your new branch? (y/n): ").strip().lower()
|
|
44
44
|
if user_input != 'y':
|
|
45
45
|
warning("\nYou cannot switch branches with unsaved changes. Jump canceled.\n")
|
|
46
|
-
|
|
46
|
+
return
|
|
47
47
|
else:
|
|
48
48
|
stash_result = run_command(["git", "stash", "push", "-u", "-m", "GitGo Jump Auto-Stash"], allow_fail=True, loading_msg="Saving your changes before jumping...")
|
|
49
49
|
if isinstance(stash_result, subprocess.CalledProcessError):
|
|
50
50
|
warning("\nFailed to save your changes. Please resolve any issues and try again.")
|
|
51
|
-
|
|
51
|
+
raise GitGoError()
|
|
52
52
|
info("\nYour changes have been saved. Jumping to the new branch...")
|
|
53
53
|
stashed_code = True
|
|
54
54
|
|
|
@@ -61,7 +61,7 @@ def jump_operation(args):
|
|
|
61
61
|
info("Exiting without jumping...\n")
|
|
62
62
|
if stashed_code:
|
|
63
63
|
run_command(["git", "stash", "pop"], loading_msg="Putting your unsaved changes back...")
|
|
64
|
-
|
|
64
|
+
return
|
|
65
65
|
|
|
66
66
|
git_new_branch(target_branch)
|
|
67
67
|
created_branch = target_branch
|
|
@@ -76,7 +76,7 @@ def jump_operation(args):
|
|
|
76
76
|
user_input = input("Do you want to stay on the new branch without the latest updates? (y/n): ").strip().lower()
|
|
77
77
|
if user_input != 'y':
|
|
78
78
|
undo_jump_operation(original_branch, stashed_code, created_branch)
|
|
79
|
-
|
|
79
|
+
raise GitGoError()
|
|
80
80
|
else:
|
|
81
81
|
success(f"\nOkay! You are on the new branch, but without the latest updates from '{main_branch}'.")
|
|
82
82
|
|
|
@@ -91,17 +91,18 @@ def jump_operation(args):
|
|
|
91
91
|
|
|
92
92
|
if conflict_choice != 'y':
|
|
93
93
|
undo_jump_operation(original_branch, stashed_code, created_branch)
|
|
94
|
-
|
|
94
|
+
return
|
|
95
95
|
else:
|
|
96
96
|
success("\nOkay! You are on the new branch with your code.")
|
|
97
97
|
warning("Please open your code editor RIGHT NOW to fix the conflicts!")
|
|
98
98
|
info("Your stash backup is still saved. Run 'gitgo state list' to see it.\n")
|
|
99
|
-
|
|
99
|
+
return
|
|
100
100
|
else:
|
|
101
101
|
run_command(["git", "stash", "drop"], allow_fail=True, loading_msg="Cleaning up the temporary stash...")
|
|
102
102
|
success(f"\nSuccess! You are now on '{target_branch}'.")
|
|
103
103
|
success("Your unsaved code was moved here safely!\n")
|
|
104
|
-
|
|
104
|
+
return
|
|
105
105
|
else:
|
|
106
106
|
success(f"\nSuccess! You are now on '{target_branch}'.\n")
|
|
107
|
-
|
|
107
|
+
return
|
|
108
|
+
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from pygitgo.exceptions import GitGoError
|
|
1
2
|
from pygitgo.utils.colors import success, warning, error, info
|
|
2
3
|
from pygitgo.utils.executor import run_command
|
|
3
4
|
from pygitgo.exceptions import GitCommandError
|
|
@@ -17,7 +18,7 @@ def pull_operation(args):
|
|
|
17
18
|
if isinstance(remote_refs, subprocess.CalledProcessError) or not remote_refs.strip():
|
|
18
19
|
error(f"\nFailed! The branch '{branch}' does not exist on the remote server.")
|
|
19
20
|
warning("You might need to push your local branch first.\n")
|
|
20
|
-
|
|
21
|
+
raise GitGoError()
|
|
21
22
|
|
|
22
23
|
run_command(
|
|
23
24
|
["git", "pull", "--rebase", "--autostash", "origin", branch],
|
|
@@ -35,9 +36,10 @@ def pull_operation(args):
|
|
|
35
36
|
info("2. Fix the red conflict lines in your files.")
|
|
36
37
|
info("3. Save the files.")
|
|
37
38
|
info("4. Run this command to finish: git rebase --continue\n")
|
|
38
|
-
|
|
39
|
+
raise GitGoError()
|
|
39
40
|
else:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
raise GitGoError(
|
|
42
|
+
"\nFailed to pull updates from the server!"
|
|
43
|
+
"Please check your internet connection and try again."
|
|
44
|
+
f"Details: {e}\n"
|
|
45
|
+
)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from pygitgo.exceptions import GitGoError
|
|
1
2
|
from pygitgo.utils.colors import info, highlight, error, warning, success
|
|
2
3
|
from pygitgo.utils.executor import run_command
|
|
3
4
|
import sys
|
|
@@ -19,7 +20,7 @@ def all_save_state():
|
|
|
19
20
|
|
|
20
21
|
if not output:
|
|
21
22
|
info("\nNo saved states found.\n")
|
|
22
|
-
|
|
23
|
+
return
|
|
23
24
|
|
|
24
25
|
save_states = []
|
|
25
26
|
|
|
@@ -88,7 +89,7 @@ def ask_state_id(save_states):
|
|
|
88
89
|
state_id = input(">> ").strip().lower()
|
|
89
90
|
if state_id == 'q':
|
|
90
91
|
warning("\nLoad operation cancelled by user.\n")
|
|
91
|
-
|
|
92
|
+
return
|
|
92
93
|
proceed = validate_state_id(state_id, save_states)
|
|
93
94
|
|
|
94
95
|
return state_id
|
|
@@ -106,10 +107,9 @@ def load_state(state_id=None):
|
|
|
106
107
|
if state_id.isdigit():
|
|
107
108
|
proceed = validate_state_id(state_id, save_states)
|
|
108
109
|
if not proceed:
|
|
109
|
-
|
|
110
|
+
raise GitGoError()
|
|
110
111
|
else:
|
|
111
|
-
|
|
112
|
-
sys.exit(1)
|
|
112
|
+
raise GitGoError(f"\nInvalid argument '{state_id}' for load operation. Expected a state ID.\n")
|
|
113
113
|
|
|
114
114
|
if not proceed:
|
|
115
115
|
state_id = ask_state_id(save_states)
|
|
@@ -141,18 +141,17 @@ def delete_state(identifier=None):
|
|
|
141
141
|
if confirm.lower() == 'y':
|
|
142
142
|
run_command(["git", "stash", "clear"])
|
|
143
143
|
success("\nAll saved states deleted successfully.\n")
|
|
144
|
-
|
|
144
|
+
return
|
|
145
145
|
else:
|
|
146
146
|
warning("\nDelete operation cancelled by user.\n")
|
|
147
|
-
|
|
147
|
+
return
|
|
148
148
|
|
|
149
149
|
elif not identifier.isdigit():
|
|
150
|
-
|
|
151
|
-
sys.exit(1)
|
|
150
|
+
raise GitGoError("\nInvalid input. Please enter a valid state ID.\n")
|
|
152
151
|
|
|
153
152
|
state_id = identifier
|
|
154
153
|
if not validate_state_id(state_id, all_save_state()):
|
|
155
|
-
|
|
154
|
+
raise GitGoError()
|
|
156
155
|
|
|
157
156
|
run_command(["git", "stash", "drop", str(int(state_id) - 1)])
|
|
158
157
|
success(f"\nState with ID '{state_id}' deleted successfully.\n")
|
|
@@ -173,5 +172,4 @@ def state_operations(args):
|
|
|
173
172
|
elif action == "delete":
|
|
174
173
|
delete_state(identifier)
|
|
175
174
|
else:
|
|
176
|
-
|
|
177
|
-
sys.exit(1)
|
|
175
|
+
raise GitGoError(f"\nUnknown state operation: {action}\n")
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from pygitgo.exceptions import GitGoError
|
|
1
2
|
from pygitgo.utils.colors import success, warning, error, info
|
|
2
3
|
from pygitgo.exceptions import GitCommandError
|
|
3
4
|
from pygitgo.utils.executor import run_command
|
|
@@ -9,18 +10,15 @@ def undo_commit():
|
|
|
9
10
|
run_command(["git", "reset", "--soft", "HEAD~"])
|
|
10
11
|
success("\nSuccess! Your last commit is undone. Your files are safe.\n")
|
|
11
12
|
except GitCommandError as e:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
raise GitGoError(
|
|
14
|
+
"\nFailed! You might not have any previous commits to undo yet."
|
|
15
|
+
f"Details: {e}\n"
|
|
16
|
+
)
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
def undo_add():
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
success("\nSuccess! Files are no longer ready to commit.\n")
|
|
21
|
-
except GitCommandError as e:
|
|
22
|
-
error(f"\n{e}\n")
|
|
23
|
-
sys.exit(1)
|
|
20
|
+
run_command(["git", "reset", "HEAD"])
|
|
21
|
+
success("\nSuccess! Files are no longer ready to commit.\n")
|
|
24
22
|
|
|
25
23
|
|
|
26
24
|
def undo_changes():
|
|
@@ -29,14 +27,11 @@ def undo_changes():
|
|
|
29
27
|
if confirm.lower() != "y":
|
|
30
28
|
info("\nCanceled. Your files are safe.\n")
|
|
31
29
|
return
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
|
|
31
|
+
run_command(["git", "reset", "--hard", "HEAD"], loading_msg="Throwing away edits...")
|
|
32
|
+
run_command(["git", "clean", "-fd"], loading_msg="Removing new files...")
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
except GitCommandError as e:
|
|
38
|
-
error(f"\n{e}\n")
|
|
39
|
-
sys.exit(1)
|
|
34
|
+
success("\nSuccess! All changes are completely gone. You have a clean start.\n")
|
|
40
35
|
|
|
41
36
|
|
|
42
37
|
def undo_operations(args):
|
|
@@ -49,5 +44,5 @@ def undo_operations(args):
|
|
|
49
44
|
elif action == "changes":
|
|
50
45
|
undo_changes()
|
|
51
46
|
else:
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
raise GitGoError(f"\nUnknown undo operation: {action}\n")
|
|
48
|
+
|
|
@@ -38,10 +38,11 @@ def link_operation(args):
|
|
|
38
38
|
repo_url = args.url
|
|
39
39
|
|
|
40
40
|
if not validate_repo_url(repo_url):
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
raise GitGoError(
|
|
42
|
+
"\nInvalid repository URL!\n"
|
|
43
|
+
"Expected format: https://github.com/username/repo.git"
|
|
44
|
+
" or: git@github.com:username/repo.git\n"
|
|
45
|
+
)
|
|
45
46
|
|
|
46
47
|
commit_message = args.message
|
|
47
48
|
|
|
@@ -106,8 +107,7 @@ def push_operation(args):
|
|
|
106
107
|
|
|
107
108
|
if args.new:
|
|
108
109
|
if not branch:
|
|
109
|
-
|
|
110
|
-
sys.exit(1)
|
|
110
|
+
raise GitGoError("\nBranch name required when using --new flag!\n")
|
|
111
111
|
git_new_branch(branch)
|
|
112
112
|
else:
|
|
113
113
|
if branch and not message and not is_branch_exist(branch):
|
|
@@ -121,8 +121,7 @@ def push_operation(args):
|
|
|
121
121
|
warning(f"You are currently on branch '{current_branch}', not '{branch}'.")
|
|
122
122
|
user_choice = input(f"Do you want to switch to branch '{branch}'? (y/n): ").lower()
|
|
123
123
|
if user_choice != 'y':
|
|
124
|
-
|
|
125
|
-
sys.exit(1)
|
|
124
|
+
raise GitGoError("\nPush aborted to prevent committing to the wrong branch.\n")
|
|
126
125
|
jump_operation(Namespace(branch=branch))
|
|
127
126
|
|
|
128
127
|
elif not branch:
|
|
@@ -200,15 +199,14 @@ def user_management(args):
|
|
|
200
199
|
|
|
201
200
|
if not action:
|
|
202
201
|
display_current_user()
|
|
203
|
-
|
|
202
|
+
return
|
|
204
203
|
|
|
205
204
|
if action == 'login':
|
|
206
205
|
login()
|
|
207
206
|
elif action == 'logout':
|
|
208
207
|
logout()
|
|
209
208
|
else:
|
|
210
|
-
|
|
211
|
-
sys.exit(1)
|
|
209
|
+
raise GitGoError(f"\nInvalid user operation '{action}'!\n")
|
|
212
210
|
|
|
213
211
|
|
|
214
212
|
def get_version():
|
|
@@ -226,7 +224,7 @@ def main():
|
|
|
226
224
|
epilog="Use 'gitgo <command> -h' for help on a specific command."
|
|
227
225
|
)
|
|
228
226
|
|
|
229
|
-
parser.add_argument("-v", "-V", "--version", action="
|
|
227
|
+
parser.add_argument("-v", "-V", "--version", action="store_true", help="show program's version number and exit")
|
|
230
228
|
parser.add_argument("-r", "--ready", action="store_true", help="Check tool readiness")
|
|
231
229
|
|
|
232
230
|
subparsers = parser.add_subparsers(title="Commands", dest="command")
|
|
@@ -329,13 +327,18 @@ def main():
|
|
|
329
327
|
|
|
330
328
|
args = parser.parse_args()
|
|
331
329
|
|
|
330
|
+
if getattr(args, 'version', False):
|
|
331
|
+
print(f"GitGo {get_version()}")
|
|
332
|
+
print(f"Support GitGo: https://ko-fi.com/huerte")
|
|
333
|
+
return
|
|
334
|
+
|
|
332
335
|
if args.ready:
|
|
333
336
|
info("\nALL UNITS ONLINE. GitGo STANDING BY. AWAITING COMMANDS...\n")
|
|
334
|
-
|
|
337
|
+
return
|
|
335
338
|
|
|
336
339
|
if not args.command:
|
|
337
340
|
parser.print_help()
|
|
338
|
-
|
|
341
|
+
return
|
|
339
342
|
|
|
340
343
|
ensure_first_run_setup()
|
|
341
344
|
check_for_updates_background(get_version())
|
|
@@ -358,7 +361,7 @@ def main():
|
|
|
358
361
|
elif args.command == "pull":
|
|
359
362
|
pull_operation(args)
|
|
360
363
|
except GitGoError as e:
|
|
361
|
-
error(f"
|
|
364
|
+
error(f"{e}")
|
|
362
365
|
sys.exit(1)
|
|
363
366
|
|
|
364
367
|
if __name__ == "__main__":
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from pygitgo.exceptions import GitGoError
|
|
1
2
|
from pygitgo.auth.ssh_utils import ensure_github_known_host
|
|
2
3
|
from pygitgo.utils.config import get_config, set_config
|
|
3
4
|
from pygitgo.utils.colors import error, info
|
|
@@ -11,7 +12,7 @@ def check_git_installed():
|
|
|
11
12
|
error("\nGit is not installed or not found on your PATH!")
|
|
12
13
|
info("Install Git from: https://git-scm.com/downloads")
|
|
13
14
|
info("After installing, restart your terminal and try again.\n")
|
|
14
|
-
|
|
15
|
+
raise GitGoError()
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
def ensure_first_run_setup():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pygitgo
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.2
|
|
4
4
|
Summary: GitGo CLI - Your Fast Git Companion. Simplifies git push, link, stash, and user management.
|
|
5
5
|
Author: Huerte
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -20,11 +20,12 @@ Requires-Dist: pick>=2.0
|
|
|
20
20
|
Provides-Extra: dev
|
|
21
21
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
22
22
|
Requires-Dist: pytest-mock>=3.10; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
23
24
|
Dynamic: license-file
|
|
24
25
|
|
|
25
26
|
<div align="center">
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+

|
|
28
29
|
|
|
29
30
|
[](https://github.com/Huerte/GitGo/actions)
|
|
30
31
|
[](https://pypi.org/project/pygitgo)
|
|
@@ -38,6 +39,14 @@ Dynamic: license-file
|
|
|
38
39
|
|
|
39
40
|
<a href="https://github.com/Huerte/GitGo/issues">Report Bug</a> · <a href="https://github.com/Huerte/GitGo/issues">Request Feature</a>
|
|
40
41
|
|
|
42
|
+
<br />
|
|
43
|
+
|
|
44
|
+
If GitGo saves you time, consider buying me a coffee. It helps keep the project going.
|
|
45
|
+
|
|
46
|
+
<a href="https://ko-fi.com/huerte">
|
|
47
|
+
<img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support on Ko-fi" />
|
|
48
|
+
</a>
|
|
49
|
+
|
|
41
50
|
</div>
|
|
42
51
|
|
|
43
52
|
---
|
|
@@ -63,7 +72,10 @@ gitgo link https://github.com/username/repo.git "init"
|
|
|
63
72
|
- [Command Reference](#command-reference)
|
|
64
73
|
- [How It Works](#how-it-works)
|
|
65
74
|
- [Contributing](#contributing)
|
|
75
|
+
- [Credits](#credits)
|
|
66
76
|
- [License](#license)
|
|
77
|
+
- [Changelog](CHANGELOG.md)
|
|
78
|
+
- [Contributing Guide](CONTRIBUTING.md)
|
|
67
79
|
|
|
68
80
|
---
|
|
69
81
|
|
|
@@ -75,17 +87,18 @@ gitgo link https://github.com/username/repo.git "init"
|
|
|
75
87
|
|
|
76
88
|
## Features
|
|
77
89
|
|
|
78
|
-
GitGo provides a CLI environment designed for faster and simpler Git workflows.
|
|
90
|
+
GitGo provides a CLI environment designed for faster and simpler Git workflows.
|
|
91
|
+
No chained commands, no cryptic flags — just short commands you can actually remember.
|
|
79
92
|
|
|
80
|
-
- **Simplified Git Operations:** Replaces chained commands with single
|
|
81
|
-
- **
|
|
82
|
-
- **
|
|
93
|
+
- **Simplified Git Operations:** Replaces chained commands with single commands for linking, pushing, and stashing.
|
|
94
|
+
- **Undo Operations:** Safely undo commits, un-queue files, or wipe local changes without any complex Git jargon.
|
|
95
|
+
- **Safe Branch Switching:** Safely traverse branches with `jump`. Auto-stashes messy code and prevents merge conflict disasters with a Try-And-Revert safety engine.
|
|
83
96
|
- **State Management:** A human-readable interface over `git stash`. States are named and listed by index so you never have to remember cryptic stash references.
|
|
84
97
|
- **Custom Defaults:** Save your preferred branch name and commit message locally so you never have to type them again.
|
|
85
98
|
- **Auto-Update Checker:** Silently checks for newer versions in the background and notifies you, without slowing down your commands.
|
|
86
99
|
- **SSH Auto-Setup:** Generates an SSH key, adds it to `ssh-agent`, and opens your GitHub settings automatically.
|
|
87
100
|
- **HTTPS to SSH Conversion:** Silently converts the remote to SSH before pushing if your SSH is configured.
|
|
88
|
-
- **Termux Compatibility:** Works
|
|
101
|
+
- **Termux Compatibility:** Works on Android via Termux, handling common issues like dubious ownership errors out of the box.
|
|
89
102
|
|
|
90
103
|
---
|
|
91
104
|
|
|
@@ -94,16 +107,38 @@ GitGo provides a CLI environment designed for faster and simpler Git workflows.
|
|
|
94
107
|
### Prerequisites
|
|
95
108
|
|
|
96
109
|
- **Python 3.8+**
|
|
97
|
-
- **Git 2.x
|
|
98
|
-
- **OpenSSH
|
|
110
|
+
- **Git 2.x+**: [git-scm.com](https://git-scm.com)
|
|
111
|
+
- **OpenSSH**: required for `gitgo user login` (pre-installed on most systems)
|
|
99
112
|
- A **GitHub account**
|
|
100
113
|
|
|
101
114
|
### Install from PyPI
|
|
102
115
|
|
|
116
|
+
For Windows users or environments without global pip restrictions, you can install GitGo directly via pip:
|
|
117
|
+
|
|
103
118
|
```bash
|
|
104
119
|
pip install pygitgo
|
|
105
120
|
```
|
|
106
121
|
|
|
122
|
+
*(Alternatively, you can use `pipx install pygitgo` if you prefer isolated environments).*
|
|
123
|
+
|
|
124
|
+
### Install via pipx (Cross-Platform)
|
|
125
|
+
|
|
126
|
+
If you already have `pipx` installed, you can use it to safely install GitGo on any operating system:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pipx install pygitgo
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Quick Install (Linux & macOS)
|
|
133
|
+
|
|
134
|
+
The easiest way to install GitGo on Unix systems without worrying about Python environments or PEP 668 restrictions is using our install script:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
curl -sSL https://raw.githubusercontent.com/Huerte/GitGo/main/install.sh | bash
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
This will automatically create an isolated environment and place `gitgo` in your `~/.local/bin` folder.
|
|
141
|
+
|
|
107
142
|
Verify the installation:
|
|
108
143
|
|
|
109
144
|
```bash
|
|
@@ -142,13 +177,13 @@ gitgo link https://github.com/username/repo.git "Initial commit"
|
|
|
142
177
|
gitgo push main "Fix auth bug"
|
|
143
178
|
|
|
144
179
|
# Create a new branch and push
|
|
145
|
-
gitgo push -n
|
|
180
|
+
gitgo push -n feat/login "Add login flow"
|
|
146
181
|
```
|
|
147
182
|
|
|
148
183
|
### 4. Safely Switch Branches
|
|
149
184
|
Jump to a different branch without worrying about your uncommitted changes. GitGo will safely stash them, hop to the new branch, sync with `main`, and carefully unpack them.
|
|
150
185
|
```bash
|
|
151
|
-
gitgo jump
|
|
186
|
+
gitgo jump feat/new-login
|
|
152
187
|
```
|
|
153
188
|
|
|
154
189
|
### 5. Safely Undo Mistakes
|
|
@@ -225,7 +260,7 @@ gitgo jump <branch>
|
|
|
225
260
|
|
|
226
261
|
### `gitgo undo`
|
|
227
262
|
|
|
228
|
-
Safely undo recent actions and mistakes using
|
|
263
|
+
Safely undo recent actions and mistakes using plain commands that say exactly what they do.
|
|
229
264
|
|
|
230
265
|
```bash
|
|
231
266
|
gitgo undo commit # Undo your last commit without losing files
|
|
@@ -235,7 +270,7 @@ gitgo undo changes # Permanently wipe all new files and local edits
|
|
|
235
270
|
|
|
236
271
|
### `gitgo state`
|
|
237
272
|
|
|
238
|
-
A
|
|
273
|
+
A named interface over `git stash`.
|
|
239
274
|
|
|
240
275
|
```bash
|
|
241
276
|
gitgo state list # show all saved states
|
|
@@ -291,13 +326,9 @@ gitgo -r # verify GitGo is ready
|
|
|
291
326
|
|
|
292
327
|
## Contributing
|
|
293
328
|
|
|
294
|
-
Contributions are welcome
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
2. Create a Feature Branch (`git checkout -b feature/your-feature`)
|
|
298
|
-
3. Commit Changes
|
|
299
|
-
4. Push to the Branch (`git push origin feature/your-feature`)
|
|
300
|
-
5. Open a Pull Request
|
|
329
|
+
Contributions are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide,
|
|
330
|
+
including project structure, test instructions, commit conventions, and a
|
|
331
|
+
[Good First Issues](CONTRIBUTING.md#good-first-issues) table if you are not sure where to start.
|
|
301
332
|
|
|
302
333
|
---
|
|
303
334
|
|
|
@@ -314,18 +345,6 @@ Contributions are welcome and appreciated!
|
|
|
314
345
|
|
|
315
346
|
---
|
|
316
347
|
|
|
317
|
-
## Support
|
|
318
|
-
|
|
319
|
-
If GitGo saves you time, consider buying me a coffee. It helps keep the project going.
|
|
320
|
-
|
|
321
|
-
<div align="center">
|
|
322
|
-
<a href="https://ko-fi.com/huerte">
|
|
323
|
-
<img src="https://ko-fi.com/img/githubbutton_sm.svg" alt="Support on Ko-fi" />
|
|
324
|
-
</a>
|
|
325
|
-
</div>
|
|
326
|
-
|
|
327
|
-
---
|
|
328
|
-
|
|
329
348
|
## License
|
|
330
349
|
|
|
331
350
|
Distributed under the **GPLv3** License. See [`LICENSE`](LICENSE) for details.
|
|
@@ -56,7 +56,7 @@ def test_config_operation_not_valid_keys(mocker):
|
|
|
56
56
|
value = "true"
|
|
57
57
|
args = Namespace(key=key, action="set", value=value)
|
|
58
58
|
|
|
59
|
-
assert capture_system_exit_code(lambda: config_operation(args))
|
|
59
|
+
assert capture_system_exit_code(lambda: config_operation(args)) == 0
|
|
60
60
|
|
|
61
61
|
fake_error.assert_called_with(f"\nInvalid configuration key: '{key}'")
|
|
62
62
|
fake_warning.assert_called_with(f"Valid keys are: {', '.join(VALID_KEYS)}\n")
|
|
@@ -44,10 +44,9 @@ def test_git_branch_exists_jump_no(mocker):
|
|
|
44
44
|
|
|
45
45
|
branch_name = "existing-branch"
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
from pygitgo.exceptions import GitGoError
|
|
48
|
+
with pytest.raises(GitGoError):
|
|
48
49
|
git_new_branch(branch_name)
|
|
49
|
-
|
|
50
|
-
assert exc_info.value.code == 1
|
|
51
50
|
fake_error.assert_called_once_with(f"Failed to create branch '{branch_name}'! It may already exist.")
|
|
52
51
|
fake_jump.assert_not_called()
|
|
53
52
|
|
|
@@ -199,10 +198,9 @@ def test_handle_rebase_conflict(mocker):
|
|
|
199
198
|
return_value='rebase'
|
|
200
199
|
)
|
|
201
200
|
|
|
202
|
-
|
|
201
|
+
from pygitgo.exceptions import GitGoError
|
|
202
|
+
with pytest.raises(GitGoError):
|
|
203
203
|
handle_rebase()
|
|
204
|
-
|
|
205
|
-
assert exc_info.value.code == 1
|
|
206
204
|
|
|
207
205
|
fake_run.assert_called_with(
|
|
208
206
|
["git", "status"], allow_fail=True
|
|
@@ -57,8 +57,6 @@ def test_jump_operation_not_valid_repo(mocker):
|
|
|
57
57
|
|
|
58
58
|
assert capture_system_exit_code(lambda: jump_operation(make_args('main'))) == 1
|
|
59
59
|
|
|
60
|
-
fake_warning.assert_called_with("\nUnable to check for uncommitted changes. Please ensure you're in a valid git repository.")
|
|
61
|
-
|
|
62
60
|
fake_run.assert_any_call(['git', 'status', '--porcelain'], allow_fail=True, loading_msg="Checking for uncommitted changes...")
|
|
63
61
|
|
|
64
62
|
def test_jump_operation_has_changes_exit(mocker):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
from unittest.mock import patch, MagicMock
|
|
3
3
|
from pygitgo.commands.pull import pull_operation
|
|
4
|
-
from pygitgo.exceptions import GitCommandError
|
|
4
|
+
from pygitgo.exceptions import GitCommandError, GitGoError
|
|
5
5
|
from argparse import Namespace
|
|
6
6
|
import subprocess
|
|
7
7
|
|
|
@@ -44,22 +44,16 @@ def test_pull_operation_success_with_branch(mock_success, mock_run_command):
|
|
|
44
44
|
)
|
|
45
45
|
mock_success.assert_called_once()
|
|
46
46
|
|
|
47
|
-
@patch("pygitgo.commands.pull.sys.exit")
|
|
48
|
-
@patch("pygitgo.commands.pull.error")
|
|
49
47
|
@patch("pygitgo.commands.pull.run_command")
|
|
50
|
-
def test_pull_operation_branch_not_found(mock_run_command
|
|
48
|
+
def test_pull_operation_branch_not_found(mock_run_command):
|
|
51
49
|
mock_run_command.return_value = subprocess.CalledProcessError(128, ["git", "ls-remote"])
|
|
52
50
|
|
|
53
51
|
args = Namespace(branch="does-not-exist")
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
mock_exit.assert_called_once_with(1)
|
|
57
|
-
mock_error.assert_called()
|
|
52
|
+
with pytest.raises(GitGoError):
|
|
53
|
+
pull_operation(args)
|
|
58
54
|
|
|
59
|
-
@patch("pygitgo.commands.pull.sys.exit")
|
|
60
|
-
@patch("pygitgo.commands.pull.error")
|
|
61
55
|
@patch("pygitgo.commands.pull.run_command")
|
|
62
|
-
def test_pull_operation_merge_conflict(mock_run_command
|
|
56
|
+
def test_pull_operation_merge_conflict(mock_run_command):
|
|
63
57
|
conflict_err = GitCommandError(["git", "pull"], stderr="merge conflict in file.py")
|
|
64
58
|
|
|
65
59
|
def side_effect_fn(*args, **kwargs):
|
|
@@ -71,7 +65,5 @@ def test_pull_operation_merge_conflict(mock_run_command, mock_error, mock_exit):
|
|
|
71
65
|
mock_run_command.side_effect = side_effect_fn
|
|
72
66
|
|
|
73
67
|
args = Namespace(branch="main")
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
mock_exit.assert_called_once_with(1)
|
|
77
|
-
mock_error.assert_any_call("\nMERGE CONFLICT DETECTED!")
|
|
68
|
+
with pytest.raises(GitGoError):
|
|
69
|
+
pull_operation(args)
|
|
@@ -18,7 +18,7 @@ def test_check_git_installed_exist(mocker):
|
|
|
18
18
|
fake_error = mocker.patch("pygitgo.utils.setup.error")
|
|
19
19
|
fake_info = mocker.patch("pygitgo.utils.setup.info")
|
|
20
20
|
|
|
21
|
-
assert capture_system_exit_code(lambda: check_git_installed()) ==
|
|
21
|
+
assert capture_system_exit_code(lambda: check_git_installed()) == 0
|
|
22
22
|
|
|
23
23
|
fake_error.assert_not_called()
|
|
24
24
|
fake_info.assert_not_called()
|
|
@@ -49,10 +49,8 @@ def test_all_save_state_no_output(mocker):
|
|
|
49
49
|
fake_run = mocker.patch("pygitgo.commands.state.run_command", return_value="")
|
|
50
50
|
fake_info = mocker.patch("pygitgo.commands.state.info")
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
all_save_state()
|
|
52
|
+
all_save_state()
|
|
54
53
|
|
|
55
|
-
assert exc_info.value.code == 0
|
|
56
54
|
fake_info.assert_called_once_with("\nNo saved states found.\n")
|
|
57
55
|
fake_run.assert_called_once_with([
|
|
58
56
|
"git", "stash", "list",
|
|
@@ -124,22 +122,19 @@ def test_load_state_invalid_id(mocker):
|
|
|
124
122
|
mocker.patch("pygitgo.commands.state.all_save_state", return_value=save_states)
|
|
125
123
|
mocker.patch("pygitgo.commands.state.validate_state_id", return_value=False)
|
|
126
124
|
|
|
127
|
-
|
|
125
|
+
from pygitgo.exceptions import GitGoError
|
|
126
|
+
with pytest.raises(GitGoError):
|
|
128
127
|
load_state("100")
|
|
129
128
|
|
|
130
|
-
assert exc_info.value.code == 1
|
|
131
|
-
|
|
132
129
|
def test_load_state_invalid_argument(mocker):
|
|
133
130
|
save_states = [{"id": 1, "ref": "stash@{0}", "date": "date", "message": "msg"}]
|
|
134
131
|
mocker.patch("pygitgo.commands.state.all_save_state", return_value=save_states)
|
|
135
132
|
fake_error = mocker.patch("pygitgo.commands.state.error")
|
|
136
133
|
|
|
137
|
-
|
|
134
|
+
from pygitgo.exceptions import GitGoError
|
|
135
|
+
with pytest.raises(GitGoError):
|
|
138
136
|
load_state("invalid_arg")
|
|
139
137
|
|
|
140
|
-
assert exc_info.value.code == 1
|
|
141
|
-
fake_error.assert_called_once_with("\nInvalid argument 'invalid_arg' for load operation. Expected a state ID.\n")
|
|
142
|
-
|
|
143
138
|
def test_load_state_no_args(mocker):
|
|
144
139
|
save_states = [{"id": 1, "ref": "stash@{0}", "date": "date", "message": "msg"},
|
|
145
140
|
{"id": 2, "ref": "stash@{1}", "date": "date2", "message": "msg2"}]
|
|
@@ -178,10 +173,8 @@ def test_delete_state_all_confirm(mocker):
|
|
|
178
173
|
fake_run = mocker.patch("pygitgo.commands.state.run_command")
|
|
179
174
|
fake_success = mocker.patch("pygitgo.commands.state.success")
|
|
180
175
|
|
|
181
|
-
|
|
182
|
-
delete_state("-a")
|
|
176
|
+
delete_state("-a")
|
|
183
177
|
|
|
184
|
-
assert exc_info.value.code == 0
|
|
185
178
|
fake_run.assert_called_once_with(["git", "stash", "clear"])
|
|
186
179
|
fake_success.assert_called_once_with("\nAll saved states deleted successfully.\n")
|
|
187
180
|
|
|
@@ -189,21 +182,17 @@ def test_delete_state_all_cancel(mocker):
|
|
|
189
182
|
mocker.patch("builtins.input", return_value="n")
|
|
190
183
|
fake_warning = mocker.patch("pygitgo.commands.state.warning")
|
|
191
184
|
|
|
192
|
-
|
|
193
|
-
delete_state("-a")
|
|
185
|
+
delete_state("-a")
|
|
194
186
|
|
|
195
|
-
assert exc_info.value.code == 0
|
|
196
187
|
fake_warning.assert_called_once_with("\nDelete operation cancelled by user.\n")
|
|
197
188
|
|
|
198
189
|
def test_delete_state_invalid_id(mocker):
|
|
199
190
|
fake_error = mocker.patch("pygitgo.commands.state.error")
|
|
200
191
|
|
|
201
|
-
|
|
192
|
+
from pygitgo.exceptions import GitGoError
|
|
193
|
+
with pytest.raises(GitGoError):
|
|
202
194
|
delete_state("abc")
|
|
203
195
|
|
|
204
|
-
assert exc_info.value.code == 1
|
|
205
|
-
fake_error.assert_called_once_with("\nInvalid input. Please enter a valid state ID.\n")
|
|
206
|
-
|
|
207
196
|
def test_delete_state_specific_id(mocker):
|
|
208
197
|
mocker.patch("pygitgo.commands.state.validate_state_id", return_value=True)
|
|
209
198
|
mocker.patch("pygitgo.commands.state.all_save_state", return_value=[])
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
from unittest.mock import patch, MagicMock
|
|
3
3
|
from pygitgo.commands.undo import undo_commit, undo_add, undo_changes, undo_operations
|
|
4
|
-
from pygitgo.exceptions import GitCommandError
|
|
4
|
+
from pygitgo.exceptions import GitGoError, GitCommandError
|
|
5
5
|
from argparse import Namespace
|
|
6
6
|
|
|
7
7
|
@patch("pygitgo.commands.undo.run_command")
|
|
@@ -12,15 +12,12 @@ def test_undo_commit_success(mock_success, mock_run_command):
|
|
|
12
12
|
mock_success.assert_called_once()
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
@patch("pygitgo.commands.undo.sys.exit")
|
|
16
|
-
@patch("pygitgo.commands.undo.error")
|
|
17
15
|
@patch("pygitgo.commands.undo.run_command")
|
|
18
|
-
def test_undo_commit_failure(mock_run_command
|
|
16
|
+
def test_undo_commit_failure(mock_run_command):
|
|
19
17
|
mock_run_command.side_effect = GitCommandError(["git", "reset", "--soft", "HEAD~"])
|
|
20
|
-
|
|
18
|
+
with pytest.raises(GitGoError):
|
|
19
|
+
undo_commit()
|
|
21
20
|
mock_run_command.assert_called_once()
|
|
22
|
-
assert mock_error.call_count == 2
|
|
23
|
-
mock_exit.assert_called_once_with(1)
|
|
24
21
|
|
|
25
22
|
|
|
26
23
|
@patch("pygitgo.commands.undo.run_command")
|
|
@@ -31,15 +28,12 @@ def test_undo_add_success(mock_success, mock_run_command):
|
|
|
31
28
|
mock_success.assert_called_once()
|
|
32
29
|
|
|
33
30
|
|
|
34
|
-
@patch("pygitgo.commands.undo.sys.exit")
|
|
35
|
-
@patch("pygitgo.commands.undo.error")
|
|
36
31
|
@patch("pygitgo.commands.undo.run_command")
|
|
37
|
-
def test_undo_add_failure(mock_run_command
|
|
32
|
+
def test_undo_add_failure(mock_run_command):
|
|
38
33
|
mock_run_command.side_effect = GitCommandError(["git", "reset", "HEAD"])
|
|
39
|
-
|
|
34
|
+
with pytest.raises(GitCommandError):
|
|
35
|
+
undo_add()
|
|
40
36
|
mock_run_command.assert_called_once()
|
|
41
|
-
mock_error.assert_called_once()
|
|
42
|
-
mock_exit.assert_called_once_with(1)
|
|
43
37
|
|
|
44
38
|
|
|
45
39
|
@patch("pygitgo.commands.undo.run_command")
|
|
@@ -85,10 +79,7 @@ def test_undo_operations_changes(mock_undo_changes):
|
|
|
85
79
|
mock_undo_changes.assert_called_once()
|
|
86
80
|
|
|
87
81
|
|
|
88
|
-
|
|
89
|
-
@patch("pygitgo.commands.undo.error")
|
|
90
|
-
def test_undo_operations_invalid(mock_error, mock_exit):
|
|
82
|
+
def test_undo_operations_invalid():
|
|
91
83
|
args = Namespace(action="invalid")
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
mock_exit.assert_called_once_with(1)
|
|
84
|
+
with pytest.raises(GitGoError):
|
|
85
|
+
undo_operations(args)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|