Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ omf install https://github.com/wfxr/forgit
# for zinit
zinit load wfxr/forgit

# for antidote (in .zsh_plugins.txt)
wfxr/forgit kind:defer

# for oh-my-zsh
git clone https://github.com/wfxr/forgit.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/forgit

Expand Down Expand Up @@ -144,6 +147,10 @@ If you're having issues after updating, and commands such as `forgit::add` or al

- **Interactive `git reset HEAD <file>` selector** (`grh`)

- **Interactive `git restore <file>` selector** (`grs`)



- **Interactive `git checkout <file>` selector** (`gcf`)

- **Interactive `git checkout <branch>` selector** (`gcb`)
Expand Down Expand Up @@ -222,6 +229,7 @@ forgit_diff=gd
forgit_show=gso
forgit_add=ga
forgit_reset_head=grh
forgit_restore=grs
forgit_ignore=gi
forgit_attributes=gat
forgit_checkout_file=gcf
Expand Down Expand Up @@ -286,6 +294,7 @@ These are passed to the according `git` calls.
| `gd` | `FORGIT_DIFF_GIT_OPTS` |
| `gso` | `FORGIT_SHOW_GIT_OPTS` |
| `grh` | `FORGIT_RESET_HEAD_GIT_OPTS` |
| `grs` | `FORGIT_RESTORE_GIT_OPTS` |
| `gcf` | `FORGIT_CHECKOUT_FILE_GIT_OPTS` |
| `gcb` | `FORGIT_CHECKOUT_BRANCH_GIT_OPTS`, `FORGIT_CHECKOUT_BRANCH_BRANCH_GIT_OPTS` |
| `gsw` | `FORGIT_SWITCH_BRANCH_GIT_OPTS` |
Expand Down Expand Up @@ -346,6 +355,7 @@ Customizing fzf options for each command individually is also supported:
| `gd` | `FORGIT_DIFF_FZF_OPTS` |
| `gso` | `FORGIT_SHOW_FZF_OPTS` |
| `grh` | `FORGIT_RESET_HEAD_FZF_OPTS` |
| `grs` | `FORGIT_RESTORE_FZF_OPTS` |
| `gcf` | `FORGIT_CHECKOUT_FILE_FZF_OPTS` |
| `gcb` | `FORGIT_CHECKOUT_BRANCH_FZF_OPTS` |
| `gsw` | `FORGIT_SWITCH_BRANCH_FZF_OPTS` |
Expand Down
35 changes: 35 additions & 0 deletions bin/git-forgit
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,39 @@ _forgit_reset_head() {
git status --short
}

_forgit_restore_preview() {
git diff --color=always -- "$1" | _forgit_pager diff
}

_forgit_git_restore() {
_forgit_restore_git_opts=()
_forgit_parse_array _forgit_restore_git_opts "$FORGIT_RESTORE_GIT_OPTS"
git restore "${_forgit_restore_git_opts[@]}" "$@"
}

# git restore selector
_forgit_restore() {
_forgit_inside_work_tree || return 1
local files opts
_forgit_contains_non_flags "$@" && {
_forgit_git_restore "$@"
return $?
}
[[ $(_forgit_list_files --modified | wc -l) -eq 0 ]] && echo 'Nothing to restore.' && return 1
opts="
$FORGIT_FZF_DEFAULT_OPTS
-m -0
--preview=\"$FORGIT restore_preview {}\"
$FORGIT_RESTORE_FZF_OPTS
"
files=()
while IFS='' read -r file; do
files+=("$file")
done < <(_forgit_list_files --modified |
FZF_DEFAULT_OPTS="$opts" fzf)
[[ "${#files[@]}" -gt 0 ]] && _forgit_git_restore "$@" "${files[@]}"
}

_forgit_stash_show_preview() {
local stash
stash=$(echo "$1" | _forgit_extract_stash_name)
Expand Down Expand Up @@ -1303,6 +1336,7 @@ PUBLIC_COMMANDS=(
"reflog"
"rebase"
"reset_head"
"restore"
"revert_commit"
"show"
"stash_show"
Expand All @@ -1324,6 +1358,7 @@ PRIVATE_COMMANDS=(
"path_preview"
"revert_preview"
"reset_head_preview"
"restore_preview"
"show_enter"
"show_preview"
"stash_push_preview"
Expand Down
3 changes: 3 additions & 0 deletions completions/_git-forgit
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ _git-forgit() {
'reflog:git reflog viewer'
'rebase:git rebase'
'reset_head:git reset HEAD (unstage) selector'
'restore:git restore file selector'
'revert_commit:git revert commit selector'
'reword:git fixup=reword'
'squash:git squash'
Expand All @@ -97,6 +98,7 @@ _git-forgit() {
reflog) _git-forgit-reflog ;;
rebase) _git-rebase ;;
reset_head) _git-staged ;;
restore) _git-checkout-file ;;
revert_commit) __git_recent_commits ;;
reword) _git-log ;;
squash) _git-log ;;
Expand Down Expand Up @@ -126,6 +128,7 @@ compdef _git-log forgit::log
compdef _git-reflog forgit::reflog
compdef _git-rebase forgit::rebase
compdef _git-staged forgit::reset::head
compdef _git-checkout-file forgit::restore
compdef __git_recent_commits forgit::revert::commit
compdef _git-log forgit::reword
compdef _git-log forgit::squash
Expand Down
4 changes: 4 additions & 0 deletions completions/git-forgit.bash
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ _git_forgit()
reflog
rebase
reset_head
restore
revert_commit
reword
show
Expand Down Expand Up @@ -103,6 +104,7 @@ _git_forgit()
reflog) _git_reflog ;;
rebase) _git_rebase ;;
reset_head) _git_reset ;;
restore) _git_checkout_file ;;
revert_commit) _git_revert ;;
reword) _git_log ;;
show) _git_show ;;
Expand Down Expand Up @@ -141,6 +143,7 @@ then
__git_complete forgit::reflog _git_reflog
__git_complete forgit::rebase _git_rebase
__git_complete forgit::reset::head _git_reset
__git_complete forgit::restore _git_checkout_file
__git_complete forgit::revert::commit _git_revert
__git_complete forgit::reword _git_log
__git_complete forgit::show _git_show
Expand All @@ -164,6 +167,7 @@ then
__git_complete "${forgit_reflog}" _git_reflog
__git_complete "${forgit_rebase}" _git_rebase
__git_complete "${forgit_reset_head}" _git_reset
__git_complete "${forgit_restore}" _git_checkout_file
__git_complete "${forgit_revert_commit}" _git_revert
__git_complete "${forgit_reword}" _git_log
__git_complete "${forgit_show}" _git_show
Expand Down
5 changes: 3 additions & 2 deletions completions/git-forgit.fish
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@

function __fish_forgit_needs_subcommand
for subcmd in add blame branch_delete checkout_branch checkout_commit checkout_file checkout_tag \
cherry_pick cherry_pick_from_branch clean diff fixup ignore log reflog rebase reset_head \
revert_commit reword squash stash_show stash_push switch_branch
restore revert_commit reword squash stash_show stash_push switch_branch
if contains -- $subcmd (commandline -opc)
return 1
end
Expand Down Expand Up @@ -39,6 +38,7 @@ complete -c git-forgit -n __fish_forgit_needs_subcommand -a log -d 'git commit v
complete -c git-forgit -n __fish_forgit_needs_subcommand -a reflog -d 'git reflog viewer'
complete -c git-forgit -n __fish_forgit_needs_subcommand -a rebase -d 'git rebase'
complete -c git-forgit -n __fish_forgit_needs_subcommand -a reset_head -d 'git reset HEAD (unstage) selector'
complete -c git-forgit -n __fish_forgit_needs_subcommand -a restore -d 'git restore file selector'
complete -c git-forgit -n __fish_forgit_needs_subcommand -a revert_commit -d 'git revert commit selector'
complete -c git-forgit -n __fish_forgit_needs_subcommand -a reword -d 'git fixup=reword'
complete -c git-forgit -n __fish_forgit_needs_subcommand -a show -d 'git show viewer'
Expand All @@ -61,6 +61,7 @@ complete -c git-forgit -n '__fish_seen_subcommand_from log' -a "(complete -C 'gi
complete -c git-forgit -n '__fish_seen_subcommand_from reflog' -a "(complete -C 'git reflog ')"
complete -c git-forgit -n '__fish_seen_subcommand_from rebase' -a "(complete -C 'git rebase ')"
complete -c git-forgit -n '__fish_seen_subcommand_from reset_head' -a "(__fish_git_files all-staged)"
complete -c git-forgit -n '__fish_seen_subcommand_from restore' -a "(__fish_git_files modified)"
complete -c git-forgit -n '__fish_seen_subcommand_from revert_commit' -a "(__fish_git_commits)"
complete -c git-forgit -n '__fish_seen_subcommand_from reword' -a "(complete -C 'git log ')"
complete -c git-forgit -n '__fish_seen_subcommand_from show' -a "(complete -C 'git show ')"
Expand Down
1 change: 1 addition & 0 deletions conf.d/forgit.plugin.fish
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ alias git-forgit "$FORGIT"
if test -z "$FORGIT_NO_ALIASES"
abbr -a -- (string collect $forgit_add; or string collect "ga") git-forgit add
abbr -a -- (string collect $forgit_reset_head; or string collect "grh") git-forgit reset_head
abbr -a -- (string collect $forgit_restore; or string collect "grs") git-forgit restore
abbr -a -- (string collect $forgit_log; or string collect "glo") git-forgit log
abbr -a -- (string collect $forgit_reflog; or string collect "grl") git-forgit reflog
abbr -a -- (string collect $forgit_diff; or string collect "gd") git-forgit diff
Expand Down
6 changes: 6 additions & 0 deletions forgit.plugin.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ forgit::reset::head() {
"$FORGIT" reset_head "$@"
}

forgit::restore() {
"$FORGIT" restore "$@"
}

forgit::stash::show() {
"$FORGIT" stash_show "$@"
}
Expand Down Expand Up @@ -166,6 +170,7 @@ if [[ -z "$FORGIT_NO_ALIASES" ]]; then

builtin export forgit_add="${forgit_add:-ga}"
builtin export forgit_reset_head="${forgit_reset_head:-grh}"
builtin export forgit_restore="${forgit_restore:-grs}"
builtin export forgit_log="${forgit_log:-glo}"
builtin export forgit_reflog="${forgit_reflog:-grl}"
builtin export forgit_diff="${forgit_diff:-gd}"
Expand All @@ -191,6 +196,7 @@ if [[ -z "$FORGIT_NO_ALIASES" ]]; then

builtin alias "${forgit_add}"='forgit::add'
builtin alias "${forgit_reset_head}"='forgit::reset::head'
builtin alias "${forgit_restore}"='forgit::restore'
builtin alias "${forgit_log}"='forgit::log'
builtin alias "${forgit_reflog}"='forgit::reflog'
builtin alias "${forgit_diff}"='forgit::diff'
Expand Down
67 changes: 67 additions & 0 deletions tests/restore.test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env bash

function set_up_before_script() {
source bin/git-forgit
export GIT_CONFIG_SYSTEM=/dev/null
export GIT_CONFIG_GLOBAL=/dev/null
cd "$(bashunit::temp_dir)" || return 1
git init -q
git config user.email "test@example.com"
git config user.name "Test User"
echo "initial" >README.md
git add README.md
git commit -q -m "Initial commit"
}

function test_restore_shows_message_when_no_modified_files() {
output=$(_forgit_restore 2>&1)
assert_general_error
assert_same "Nothing to restore." "$output"
}

function test_restore_reverts_modified_file_to_committed_state() {
echo "original content" >tracked.txt
git add tracked.txt
git commit -q -m "Add tracked file"
echo "modified content" >tracked.txt
_forgit_git_restore tracked.txt
assert_same "original content" "$(cat tracked.txt)"
}

function test_restore_does_not_affect_untracked_files() {
echo "untracked content" >untracked.txt
_forgit_git_restore untracked.txt 2>/dev/null || true
assert_file_exists untracked.txt
assert_same "untracked content" "$(cat untracked.txt)"
}

function test_restore_only_reverts_unstaged_changes_when_file_has_staged_and_unstaged() {
echo "committed" >mixed.txt
git add mixed.txt
git commit -q -m "Add mixed file"
echo "staged change" >mixed.txt
git add mixed.txt
echo "unstaged change" >mixed.txt
_forgit_git_restore mixed.txt
assert_same "staged change" "$(cat mixed.txt)"
}

function test_restore_with_renamed_file() {
echo "rename content" >before-rename.txt
git add before-rename.txt
git commit -q -m "Add file for rename test"
git mv before-rename.txt after-rename.txt
git commit -q -m "Rename file"
echo "modified after rename" >after-rename.txt
_forgit_git_restore after-rename.txt
assert_same "rename content" "$(cat after-rename.txt)"
}

function test_restore_passes_through_arguments_when_non_flags_provided() {
echo "original" >passthrough.txt
git add passthrough.txt
git commit -q -m "Add passthrough file"
echo "modified" >passthrough.txt
_forgit_restore passthrough.txt
assert_same "original" "$(cat passthrough.txt)"
}
Loading