diff --git a/bin/git-forgit b/bin/git-forgit index 94a1c17..659b512 100755 --- a/bin/git-forgit +++ b/bin/git-forgit @@ -213,6 +213,22 @@ _forgit_list_files() { git ls-files -z "$@" "$rootdir" | tr '\0' '\n' | uniq } +# Print changed files in the worktree +# +# Always includes modified and unmerged files. Includes untracked files when +# status.showUntrackedFiles is true or unset. Never includes staged files. +_forgit_worktree_changes() { + local changed unmerged untracked show_untracked + changed=$(git config --get-color color.status.changed red) + unmerged=$(git config --get-color color.status.unmerged red) + untracked=$(git config --get-color color.status.untracked red) + show_untracked=$(git config status.showUntrackedFiles) + + git -c color.status=always -c status.relativePaths=true -c core.quotePath=false status -s --untracked="${show_untracked:-all}" | + grep -F -e "$changed" -e "$unmerged" -e "$untracked" | + sed -E 's/^(..[^[:space:]]*)[[:space:]]+(.*)$/[\1] \2/' +} + _forgit_is_submodule() { git submodule --quiet status "$1" } @@ -516,13 +532,10 @@ _forgit_edit_add_file() { # git add selector _forgit_add() { _forgit_inside_work_tree || return 1 - local changed unmerged untracked files opts show_untracked + local files opts # Add files if passed as arguments _forgit_contains_non_flags "$@" && { _forgit_git_add "$@" && git status -s; return $?; } - changed=$(git config --get-color color.status.changed red) - unmerged=$(git config --get-color color.status.unmerged red) - untracked=$(git config --get-color color.status.untracked red) opts=" $FORGIT_FZF_DEFAULT_OPTS -0 -m --nth 2..,.. @@ -531,14 +544,9 @@ _forgit_add() { $FORGIT_ADD_FZF_OPTS " files=() - show_untracked=$(git config status.showUntrackedFiles) while IFS='' read -r file; do files+=("$file") - done < <(git -c color.status=always -c status.relativePaths=true -c core.quotePath=false status -s --untracked="${show_untracked:-all}" | - grep -F -e "$changed" -e "$unmerged" -e "$untracked" | - sed -E 's/^(..[^[:space:]]*)[[:space:]]+(.*)$/[\1] \2/' | - FZF_DEFAULT_OPTS="$opts" fzf | - _forgit_get_single_file_from_add_line) + done < <(_forgit_worktree_changes | FZF_DEFAULT_OPTS="$opts" fzf | _forgit_get_single_file_from_add_line) [[ "${#files[@]}" -gt 0 ]] && _forgit_git_add "$@" "${files[@]}" && git status -s && return echo 'Nothing to add.' } diff --git a/tests/working-tree-changes.test.sh b/tests/working-tree-changes.test.sh new file mode 100644 index 0000000..4744844 --- /dev/null +++ b/tests/working-tree-changes.test.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + + function set_up_before_script() { + source bin/git-forgit + + # Ignore global git config files + export GIT_CONFIG_SYSTEM=/dev/null + export GIT_CONFIG_GLOBAL=/dev/null + + cd "$(bashunit::temp_dir)" || return 1 + git init --quiet + git config user.name "Test User" + git config user.email "test@example.com" + + touch "tracked file.txt" + touch "modified file.txt" + git add . + git commit -m "init" --quiet + + echo modified > "modified file.txt" + + touch "staged file.txt" + git add "staged file.txt" + + touch "untracked_file.txt" + } + + function test_forgit_worktree_changes_contains_modified() { + local output + + output=$(_forgit_worktree_changes) + + assert_contains "modified file.txt" "$output" + } + + function test_forgit_worktree_changes_contains_untracked() { + local output + + output=$(_forgit_worktree_changes) + + assert_contains "untracked_file.txt" "$output" + } + + function test_forgit_worktree_changes_excludes_staged() { + local output + + output=$(_forgit_worktree_changes) + assert_not_contains "staged file.txt" "$output" + } + + + function test_forgit_worktree_changes_excludes_tracked() { + local output + + output=$(_forgit_worktree_changes) + + assert_not_contains "tracked file.txt" "$output" + }