├── .github ├── images │ └── demo.gif └── workflows │ ├── publish.yml │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── src ├── git.rs ├── git │ ├── client.rs │ └── utils.rs ├── interactions.rs └── main.rs └── upload.sh /.github/images/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craciuncezar/git-smart-checkout/4aa7327beddc543ed4d94544f888a6fdfb27f22e/.github/images/demo.gif -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: 3 | 4 | name: Publish 5 | 6 | jobs: 7 | publish: 8 | name: Publish 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v3 13 | 14 | - name: Install stable toolchain 15 | uses: actions-rs/toolchain@v1 16 | with: 17 | profile: minimal 18 | toolchain: stable 19 | override: true 20 | 21 | - run: cargo publish --token ${CRATES_TOKEN} 22 | env: 23 | CRATES_TOKEN: ${{ secrets.CRATES_TOKEN }} 24 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Build 19 | run: cargo build --verbose 20 | - name: Run tests 21 | run: cargo test --verbose 22 | linting: 23 | runs-on: ubuntu-latest 24 | 25 | steps: 26 | - uses: actions/checkout@v2 27 | - name: Format check 28 | run: cargo fmt -- --check 29 | - name: Clippy 30 | uses: actions-rs/cargo@v1 31 | with: 32 | command: clippy 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "0.7.20" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anyhow" 16 | version = "1.0.53" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0" 19 | 20 | [[package]] 21 | name = "autocfg" 22 | version = "1.1.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 25 | 26 | [[package]] 27 | name = "bitflags" 28 | version = "1.3.2" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 31 | 32 | [[package]] 33 | name = "cc" 34 | version = "1.0.72" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" 37 | 38 | [[package]] 39 | name = "cfg-if" 40 | version = "1.0.0" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 43 | 44 | [[package]] 45 | name = "console" 46 | version = "0.15.0" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31" 49 | dependencies = [ 50 | "encode_unicode", 51 | "libc", 52 | "once_cell", 53 | "regex", 54 | "terminal_size", 55 | "unicode-width", 56 | "winapi", 57 | ] 58 | 59 | [[package]] 60 | name = "ctrlc" 61 | version = "3.2.1" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "a19c6cedffdc8c03a3346d723eb20bd85a13362bb96dc2ac000842c6381ec7bf" 64 | dependencies = [ 65 | "nix", 66 | "winapi", 67 | ] 68 | 69 | [[package]] 70 | name = "dialoguer" 71 | version = "0.10.0" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "349d6b4fabcd9e97e1df1ae15395ac7e49fb144946a0d453959dc2696273b9da" 74 | dependencies = [ 75 | "console", 76 | "fuzzy-matcher", 77 | "tempfile", 78 | "zeroize", 79 | ] 80 | 81 | [[package]] 82 | name = "either" 83 | version = "1.8.1" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" 86 | 87 | [[package]] 88 | name = "encode_unicode" 89 | version = "0.3.6" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 92 | 93 | [[package]] 94 | name = "fastrand" 95 | version = "1.7.0" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" 98 | dependencies = [ 99 | "instant", 100 | ] 101 | 102 | [[package]] 103 | name = "fuzzy-matcher" 104 | version = "0.3.7" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" 107 | dependencies = [ 108 | "thread_local", 109 | ] 110 | 111 | [[package]] 112 | name = "git-smart-checkout" 113 | version = "0.1.3" 114 | dependencies = [ 115 | "anyhow", 116 | "ctrlc", 117 | "dialoguer", 118 | "itertools", 119 | "regex", 120 | ] 121 | 122 | [[package]] 123 | name = "instant" 124 | version = "0.1.12" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 127 | dependencies = [ 128 | "cfg-if", 129 | ] 130 | 131 | [[package]] 132 | name = "itertools" 133 | version = "0.10.5" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 136 | dependencies = [ 137 | "either", 138 | ] 139 | 140 | [[package]] 141 | name = "libc" 142 | version = "0.2.117" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c" 145 | 146 | [[package]] 147 | name = "memchr" 148 | version = "2.5.0" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 151 | 152 | [[package]] 153 | name = "memoffset" 154 | version = "0.6.5" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 157 | dependencies = [ 158 | "autocfg", 159 | ] 160 | 161 | [[package]] 162 | name = "nix" 163 | version = "0.23.1" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" 166 | dependencies = [ 167 | "bitflags", 168 | "cc", 169 | "cfg-if", 170 | "libc", 171 | "memoffset", 172 | ] 173 | 174 | [[package]] 175 | name = "once_cell" 176 | version = "1.9.0" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" 179 | 180 | [[package]] 181 | name = "redox_syscall" 182 | version = "0.2.10" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 185 | dependencies = [ 186 | "bitflags", 187 | ] 188 | 189 | [[package]] 190 | name = "regex" 191 | version = "1.7.1" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" 194 | dependencies = [ 195 | "aho-corasick", 196 | "memchr", 197 | "regex-syntax", 198 | ] 199 | 200 | [[package]] 201 | name = "regex-syntax" 202 | version = "0.6.28" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" 205 | 206 | [[package]] 207 | name = "remove_dir_all" 208 | version = "0.5.3" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 211 | dependencies = [ 212 | "winapi", 213 | ] 214 | 215 | [[package]] 216 | name = "tempfile" 217 | version = "3.3.0" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" 220 | dependencies = [ 221 | "cfg-if", 222 | "fastrand", 223 | "libc", 224 | "redox_syscall", 225 | "remove_dir_all", 226 | "winapi", 227 | ] 228 | 229 | [[package]] 230 | name = "terminal_size" 231 | version = "0.1.17" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" 234 | dependencies = [ 235 | "libc", 236 | "winapi", 237 | ] 238 | 239 | [[package]] 240 | name = "thread_local" 241 | version = "1.1.4" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" 244 | dependencies = [ 245 | "once_cell", 246 | ] 247 | 248 | [[package]] 249 | name = "unicode-width" 250 | version = "0.1.9" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 253 | 254 | [[package]] 255 | name = "winapi" 256 | version = "0.3.9" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 259 | dependencies = [ 260 | "winapi-i686-pc-windows-gnu", 261 | "winapi-x86_64-pc-windows-gnu", 262 | ] 263 | 264 | [[package]] 265 | name = "winapi-i686-pc-windows-gnu" 266 | version = "0.4.0" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 269 | 270 | [[package]] 271 | name = "winapi-x86_64-pc-windows-gnu" 272 | version = "0.4.0" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 275 | 276 | [[package]] 277 | name = "zeroize" 278 | version = "1.5.2" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "7c88870063c39ee00ec285a2f8d6a966e5b6fb2becc4e8dac77ed0d370ed6006" 281 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "git-smart-checkout" 3 | version = "0.1.3" 4 | authors = ["Cezar Craciun"] 5 | description = """ 6 | A better way of switching git branches. 7 | """ 8 | keywords = ["git", "branch", "checkout", "fuzzy"] 9 | license = "MIT" 10 | edition = "2021" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [dependencies] 15 | dialoguer = {version="0.10.1", features=["fuzzy-select"]} 16 | ctrlc = { version = "3.0", features = ["termination"] } 17 | anyhow = "1.0.0" 18 | regex = "1.5.6" 19 | itertools = "0.10.5" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Cezar Craciun 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

git-smart-checkout

3 | 4 |

5 | A git command extension for switching git branches more efficiently. 6 |

7 | 8 | ![brain](https://user-images.githubusercontent.com/27342306/147604624-9d62c8ca-d2f2-42a3-973e-4341a09b0d23.png) 9 |
10 | 11 | [![Crates.io](https://img.shields.io/crates/v/git-smart-checkout.svg)](https://crates.io/crates/git-smart-checkout) 12 | [![License](https://img.shields.io/crates/l/git-smart-checkout.svg)](./LICENSE) 13 | 14 | ![Demo](https://raw.githubusercontent.com/craciuncezar/git-smart-checkout/main/.github/images/demo.gif) 15 | 16 |
17 | 18 | ## About 19 | 20 | Interactively switch branches or fuzzy search for that forgotten branch name. 21 | 22 | All powered by the speed ⚡️ of rust 🦀. 23 | 24 | ## Installation 25 | 26 | If you have [Rust installed](https://www.rust-lang.org/tools/install) (using the recommended rustup installation method) then you can install the binary from the [crate](https://crates.io/crates/git-smart-checkout) using cargo: 27 | 28 | ```sh 29 | cargo install git-smart-checkout 30 | ``` 31 | 32 | For Homebrew users, you can install the binary using the following command: 33 | 34 | ```sh 35 | brew tap craciuncezar/tap 36 | brew install git-smart-checkout 37 | ``` 38 | 39 | You can also install the binary directly from GitHub Releases 40 | 41 | ```sh 42 | curl -sSL https://github.com/craciuncezar/git-smart-checkout/releases/download/v0.1.0/git-smart-checkout -o /usr/local/bin/git-smart-checkout && chmod +x /usr/local/bin/git-smart-checkout 43 | ``` 44 | 45 | ## Usage 46 | 47 | Start by running: 48 | 49 | ```sh 50 | git smart-checkout 51 | ``` 52 | 53 | Once the interactive window is visible you can navigate with keyboard arrows `↑` or `↓` and select the git branch you are looking for by pressing `Enter`. If you know the name of the branch you can start typing to search for that particular branch, the search is using a fuzzy algorithm so you don't need to match the exact name of the branch it will also match partial terms. 54 | 55 | ### Git alias 56 | 57 | To save typing time you can use a regular git alias for `git smart-checkout`. The following command will add the alias `git sc` to your git config, however feel free to use whatever works best for you: 58 | 59 | ```sh 60 | git config --global alias.sc smart-checkout 61 | ``` 62 | -------------------------------------------------------------------------------- /src/git.rs: -------------------------------------------------------------------------------- 1 | pub mod client; 2 | pub mod utils; 3 | 4 | use dialoguer::console::style; 5 | use std::fmt::{self, Display}; 6 | 7 | #[derive(Clone)] 8 | pub struct GitBranch { 9 | pub name: String, 10 | pub selected: bool, 11 | } 12 | 13 | impl Display for GitBranch { 14 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 15 | if self.selected { 16 | return write!(f, "{} (current)", style(&self.name).underlined().green()); 17 | } 18 | 19 | write!(f, "{}", self.name) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/git/client.rs: -------------------------------------------------------------------------------- 1 | use std::process::{Command, Output, Stdio}; 2 | 3 | use itertools::Itertools; 4 | use regex::Regex; 5 | 6 | use super::{utils, GitBranch}; 7 | 8 | pub fn switch_to_branch(branch: &GitBranch) -> Output { 9 | Command::new("git") 10 | .arg("checkout") 11 | .arg(branch.name.clone()) 12 | .output() 13 | .expect("Could not run git checkout") 14 | } 15 | 16 | pub fn stash_git_changes() -> Output { 17 | Command::new("git") 18 | .arg("stash") 19 | .output() 20 | .expect("Could not run git stash") 21 | } 22 | 23 | fn get_git_branches() -> Vec { 24 | let git_branch_command = Command::new("git") 25 | .arg("branch") 26 | .output() 27 | .expect("failed to get list of git branches"); 28 | 29 | let git_branch_stdout = String::from_utf8_lossy(&git_branch_command.stdout); 30 | 31 | git_branch_stdout 32 | .lines() 33 | .map(|branch| { 34 | if let Some(stripped) = branch.strip_prefix('*') { 35 | return GitBranch { 36 | selected: true, 37 | name: String::from(stripped.trim()), 38 | }; 39 | } 40 | 41 | GitBranch { 42 | selected: false, 43 | name: String::from(branch.trim()), 44 | } 45 | }) 46 | .collect() 47 | } 48 | 49 | fn get_list_of_most_recent_branches() -> Vec { 50 | let reflog_command = Command::new("git") 51 | .arg("reflog") 52 | .stdout(Stdio::piped()) 53 | .spawn() 54 | .unwrap(); 55 | 56 | let grep_checkout_command = Command::new("grep") 57 | .arg("checkout") 58 | .stdin(Stdio::from(reflog_command.stdout.unwrap())) 59 | .output() 60 | .expect("failed to grep checkout"); 61 | 62 | let git_reflog_checkout_stdout = String::from_utf8_lossy(&grep_checkout_command.stdout); 63 | 64 | let re = Regex::new(r"checkout: moving from (.*) to").unwrap(); 65 | 66 | re.captures_iter(&git_reflog_checkout_stdout) 67 | .map(|cap| cap[1].to_string()) 68 | .unique() 69 | .collect::>() 70 | } 71 | 72 | pub fn get_sorted_git_branches() -> Vec { 73 | let branches = get_git_branches(); 74 | let most_recent_branches = get_list_of_most_recent_branches(); 75 | 76 | utils::hoist_selected_branch(utils::sort_branches_by_name_list( 77 | branches, 78 | most_recent_branches, 79 | )) 80 | } 81 | -------------------------------------------------------------------------------- /src/git/utils.rs: -------------------------------------------------------------------------------- 1 | use super::GitBranch; 2 | 3 | pub fn hoist_selected_branch(mut branches: Vec) -> Vec { 4 | branches.sort_by(|a, b| b.selected.cmp(&a.selected)); 5 | branches 6 | } 7 | 8 | pub fn sort_branches_by_name_list(branches: Vec, list: Vec) -> Vec { 9 | let mut sorted_branches = branches.to_vec(); 10 | sorted_branches.sort_by(|a, b| { 11 | let a_index = list.iter().position(|x| x == &a.name); 12 | let b_index = list.iter().position(|x| x == &b.name); 13 | 14 | match (a_index, b_index) { 15 | (Some(a), Some(b)) => a.cmp(&b), 16 | (Some(_), None) => std::cmp::Ordering::Less, 17 | (None, Some(_)) => std::cmp::Ordering::Greater, 18 | (None, None) => std::cmp::Ordering::Equal, 19 | } 20 | }); 21 | return sorted_branches; 22 | } 23 | -------------------------------------------------------------------------------- /src/interactions.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use dialoguer::{theme::ColorfulTheme, Confirm, FuzzySelect}; 3 | 4 | use crate::git::GitBranch; 5 | 6 | pub fn select_branch(branches: &[GitBranch]) -> Result<&GitBranch> { 7 | let selection_index = FuzzySelect::with_theme(&ColorfulTheme::default()) 8 | .with_prompt("Search git branch by name") 9 | .default(0) 10 | .items(branches) 11 | .interact()?; 12 | Ok(&branches[selection_index]) 13 | } 14 | 15 | pub fn confirm_git_stash() -> Result { 16 | Ok(Confirm::with_theme(&ColorfulTheme::default()) 17 | .with_prompt("Stash changes before switch branches?") 18 | .interact()?) 19 | } 20 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod git; 2 | mod interactions; 3 | 4 | fn main() { 5 | ctrlc::set_handler(show_cursor).unwrap(); 6 | 7 | let branches = git::client::get_sorted_git_branches(); 8 | let selected_branch = interactions::select_branch(&branches).unwrap_or_else(|_| { 9 | show_cursor(); 10 | std::process::exit(0); 11 | }); 12 | 13 | if selected_branch.selected { 14 | println!("You are already on branch {}", selected_branch.name); 15 | return; 16 | } 17 | 18 | let switch_branch = git::client::switch_to_branch(selected_branch); 19 | 20 | if !switch_branch.stderr.is_empty() { 21 | let error = String::from_utf8_lossy(&switch_branch.stderr); 22 | if error.contains("Please commit your changes or stash them before you switch branches.") { 23 | let should_stash = interactions::confirm_git_stash().unwrap_or_else(|_| { 24 | show_cursor(); 25 | std::process::exit(0); 26 | }); 27 | if should_stash { 28 | git::client::stash_git_changes(); 29 | git::client::switch_to_branch(selected_branch); 30 | } 31 | }; 32 | } 33 | } 34 | 35 | // make sure that the cursor re-appears when interrupting 36 | fn show_cursor() { 37 | let term = dialoguer::console::Term::stderr(); 38 | let _ = term.show_cursor(); 39 | } 40 | -------------------------------------------------------------------------------- /upload.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to create the tar gz and shasum files for gh release and homebrew 4 | # TODO: Automate this into the CI 5 | 6 | echo "Building release binary..." 7 | cargo build --target=x86_64-apple-darwin --release 8 | cd target/x86_64-apple-darwin/release 9 | echo "Creating tar archive..." 10 | tar -czf git-smart-checkout.tar.gz git-smart-checkout 11 | echo "Shasum of tar archive:" 12 | shasum -a 256 git-smart-checkout.tar.gz --------------------------------------------------------------------------------