about summary refs log tree commit diff stats
path: root/pkgs/by-name/gi/git-edit-index/git-edit-index.sh
blob: 94a8d4a4b3713fece7fc56825227047ff16506b0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/usr/bin/env dash

NAME="git-edit-index"

warn() {
    echo "WARNING: $1"
}

help() {
    cat <<EOF
Edit a file from the index. This script does not touch the unstaged variant of the file.

USAGE:
    $NAME [OPTIONS] [--] FILES..

OPTIONS:
    --
                            Stop parsing options and interpret everything as an file.

    --help | -h
                            Display this help and exit.

    --version | -v
                            Display version and copyright information and exit.
ARGUMENTS:
    FILES := [[ git diff --name-only --cached --diff-filter=AM ]]
                            The files to edit.

EOF
}

GIT_DIR="$(git rev-parse --show-toplevel)"
materialize_file() {
    git diff --cached "$1" >"$GIT_DIR/.git/EDIT_INDEX_PATCH"

    git add "$1"
    git restore --staged "$1"
    cat "$1" >"$GIT_DIR/.git/EDIT_INDEX_FILE"
    git restore "$1"

    git apply "$GIT_DIR/.git/EDIT_INDEX_PATCH"
    "$EDITOR" "$1"

    git add "$1"
    mv "$GIT_DIR/.git/EDIT_INDEX_FILE" "$1"
}

edit() {
    files_to_add="$(mktemp)"
    cleanup() {
        rm "$files_to_add"
    }
    trap cleanup EXIT

    realpath --relative-to=. "$@" >"$files_to_add"

    git diff --name-only --cached --diff-filter=AM | while read -r index_file; do
        if grep -q "$index_file" "$files_to_add"; then
            sed -i "s|$index_file||" "$files_to_add"
            materialize_file "$index_file"
        fi
    done

    unedided_files="$(sed '/^\s*$/d' "$files_to_add" | wc -l)"
    if [ "$unedided_files" -gt 0 ]; then
        warn "Failed to edit $unedided_files file(s):"
        cat "$files_to_add"
    fi
}

for arg in "$@"; do
    case "$arg" in
    "--help" | "-h")
        help
        exit 0
        ;;
    "--")
        end_of_cli_options=true
        ;;
    esac
    [ "$end_of_cli_options" = "true" ] && break
done

edit "$@"

# vim: ft=sh