Предупреждать при выполнении git commit -a, если что-то ставится - PullRequest
8 голосов
/ 09 июля 2011

Иногда из мышечной памяти я запускаю git commit -a, когда у меня есть файлы или части файлов, тщательно подготовленные и готовые к фиксации, в результате чего я теряю свое осторожное действие по подготовке.

Есть ли способ заставить git commit -a предупредить, если в данный момент есть что-то (файл или патч)?

(Очевидно, я должен просто использовать -a меньше, чтобы облегчить мою проблему, но мой вопрос остается в силе.)

Ответы [ 4 ]

2 голосов
/ 10 июля 2011

К сожалению, Git не позволяет псевдонимам переопределять существующие команды, в противном случае вы можете легко добавить эту функцию через псевдоним.

Но вы можете получить часть пути там.Для этого потребуется переобучиться набирать что-нибудь вместо git commit - возможно git c.

Вот как вы можете это сделать:

  1. Поместите следующий код оболочки вгде-нибудь файл сценария (например, /path/to/commit-wrapper)

    #!/bin/sh
    
    # avoid echo because some implementations treat backslashes specially
    log() { printf '%s\n' "$*"; }
    error() { log "ERROR: $*" >&2; }
    fatal() { error "$*"; exit 1; }
    
    check_for_staged() {
        git diff-index --cached --quiet HEAD || {
    
            # simply exit with an error if run non-interactively
            tty >/dev/null \
                || fatal "don't use '$1' when you have staged changes"
    
            # this script is being run interactively; prompt the user to
            # continue
            error "'$1' option used when there are staged changes"
            while true; do
                printf 'Continue anyway? [y/N] ' >&2
                read answer || { printf '\n'; answer=N; }
                [ -n "${answer}" ] || answer=N
                case ${answer} in
                    y|Y) break;;
                    n|N) echo "aborted" >&2; exit 1;;
                    *) error "Please answer 'y' or 'n'.";;
                esac
            done
        }
    }
    
    # TODO:  use 'git rev-parse --parseopt' to reliably detect '-a' (e.g.,
    # to properly handle invocations such as 'git commit -sa')
    for i in "$@"; do
        case ${i} in
            --) break;;
            -a|--all) check_for_staged "${i}"; break;;
        esac
    done
    
    git commit "$@"
    
  2. Сделать файл исполняемым: chmod a+x /path/to/commit-wrapper
  3. Установить псевдоним: git config --global alias.c '!/path/to/commit-wrapper'
  4. Используйте git c вместо git commit.

Если Git когда-либо изменен, чтобы разрешить псевдонимы для существующих команд, измените последнюю строку на "$(git --exec-path)"/git-commit "$@", чтобы избежать бесконечного цикла.

1 голос
/ 10 июля 2011

Добавьте в свой репозиторий pre-commit, что-то вроде следующего:

#!/bin/sh
echo "Make sure you haven't used the -a flag or verify git diff --cached returns nothing"
echo "Run commit again with --no-verify if ok to proceed"
exit 1

Это должно помочь вам преодолеть «мышечную память».

К сожалению, ловушка предварительной фиксации не может быть достаточно мощной, чтобы выполнять больше проверок (например, если вы передали аргумент -a для фиксации.) Кроме того, когда вы делаете -a, ловушка предварительной фиксациивы увидите, как если бы все файлы были размещены, даже после выполнения вы увидите, что они не установлены.Таким образом, вы не можете различить, что вы поставили ранее, и файлы, поставленные из-за -a.

1 голос
/ 10 июля 2011

Вы можете использовать ваш любимый язык сценариев для создания команды git2, которая проверит, запускаете ли вы ее с аргументами commit -a. Если это так, запустите /usr/bin/git status --porcelain и проверьте, есть ли какие-либо изменения в индексе (вывод в формате фарфора легче проанализировать, я бы предпочел прогнать его через grep '^[AMD]' и проверить, нашел ли он что-то. Теперь , вы можете либо напечатать предупреждение и выйти, либо запустить /usr/bin/git, для которого все исходные аргументы продолжались, как если бы не было git2 (это также то, что вы делаете, если вы не запускались с коммитом -a).

Вот пример на Perl (который все равно требуется git):

#!/usr/bin/env perl

use strict;
use warnings;

my %aliases = map { split(/\n/, $_, 2) }
   split /\0/,
   `git config -z --get-regexp alias\\.`;

my %commit_aliases = (( commit => 1 ),
   map { s/alias\.//; $_ => 1 }
   grep $aliases{$_} =~ /^commit\b/,
   keys %aliases);

my ($command, @args) = @ARGV;

if ($commit_aliases{$command} && $args[0] =~ /^-a|^--all/) {
   my @staged = grep /^M/, split /\0/, `git status -z`;
   if (@staged) {
      print "There are staged changes, are you sure you want to commit all? (y/N) ";
      chomp(my $answer = <STDIN>);
      if ($answer =~ /^y/i) {
         run_command()
      }
   } else {
      run_command()
   }
} else {
   run_command()
}

sub run_command {
   system 'git', $command, @args;
   exit $? >> 8;
}

Затем создайте псевдоним bash alias git2 git, и все готово.

0 голосов
/ 09 июля 2011

Я не знаю ни одного автоматического способа, но вручную это делается так же, как в этом вопросе: Как показать изменения, которые были организованы?

Что по сути: git diff --cached

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...