Git Bash застревает в diff / log, самопроизвольно повторяет одну и ту же команду снова и снова - PullRequest
37 голосов
/ 29 сентября 2011

У меня странная проблема с Git Bash в Windows 7 / XP.Раньше он работал нормально, но недавно я обнаружил, что после выполнения git diff или git log Git Bash становится непригодным для использования: после diff / log, даже после того, как я возвращаюсь в командную строку, Bash продолжает внезапно и, по-видимому, самопроизвольно повторятьсята же команда, без ответа, и пока я нахожусь в процессе ввода следующей команды.

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

Ответы [ 2 ]

53 голосов
/ 01 октября 2011

Вы должны использовать q, чтобы выйти из git-пейджера.Использование Ctrl-C вызывает проблемы только в Windows.

Ctrl-C не должен выходить из пейджера (и это не происходит в системе Linux).Когда вы нажимаете Ctrl-C в Windows (я полагаю, msysgit?), Вы каким-то образом убиваете процесс «извне» (то есть из cmd.exe).Я не знаю точных причин, почему это происходит.

Поскольку в прошлом я сталкивался с подобными проблемами: попробуйте несколько раз нажать q и Ctrl-C в случайном порядке, если вам повезетя снова получу рабочее приглашение;) [Нет лучшего решения, о котором я знаю, - но оно сработало для меня…]

2 голосов
/ 22 января 2017

Обратите внимание, что с Git 2.12 (1 квартал 2017 года, 6+ лет спустя) Ctrl + C в сеансе git-пейджера должен вести себя лучше.

См. коммит 46df690 , коммит 246f0ed , коммит 2b296c9 (07 января 2017) Джефф Кинг (peff) .
(Объединено с Junio ​​C Hamano - gitster - в коммит 5918bdc , 18 января 2017 г.)

execv_dashed_external: ждать ребенка в случае смерти

Набрав от ^C до pager, что обычно не убивает его, убил Git и снял пейджер как побочный урон в определенной структуре дерева процессов.
Это было исправлено.

Вы можете запустить любой внешний пунктир с помощью таких команд, как git -p stash list, где команда завершает работу, но пейджер все еще идет.

Короткая версия - все должно нормально останавливаться (Git и пейджер)

Но подробно:

Когда git запускает pager, для процесса git важно торчать и ждать, пока pager закончится, даже если больше нет данных для его подачи.
Это потому, что git порождает pager как дочерний элемент, и, таким образом, процесс git является лидером сеанса на терминале. После того, как он умрет, pager закончит текущее чтение с терминала символ), а затем получите EIO, пытаясь прочитать снова.

Примечание: EIO (ошибка 5) для ошибки ввода / вывода и ( источник ):

ловушка для всевозможных неожиданных аппаратных ошибок. Это может быть из-за физической ошибки, но дополнительно, потерянный процесс (процесс, чей родитель умер), который пытается прочитать из стандартного ввода, получит это. Системы BSD возвращают это, если вы пытаетесь открыть устройство pty, которое уже используется.
Попытка чтения из закрытого потока вернет EIO, равно как и чтение или запись на диск, который находится за пределами физических границ устройства.
Открытие /dev/tty, когда у процесса нет контроля tty, также будет выпадать EIO.

Итак (назад к ^C в pager):

Когда вы нажимаете ^C, это отправляет SIGINT на git и на pager, и это аналогичная ситуация.
pager игнорирует его, но процесс git должен зависать, пока не закончится пейджер. Мы говорили об этом давно в a3da882 (пейджер: до wait_for_pager о смерти сигнала, 2009-01-22) .

Но когда у вас есть пунктирная внешняя строка (или псевдоним, указывающий на встроенную функцию, которая повторно выполнит git для встроенной функции), в миксе будет дополнительный процесс.
Например, запустив:

$ git -c alias.l=log l

будет иметь дерево процессов, подобное:

  git (parent)
    \
     git-log (child)
      \
       less (pager)

Если вы нажмете ^C, SIGINT перейдет ко всем из них. Пейджер игнорирует его, и дочерний процесс git завершается в wait_for_pager ().
Но родительский процесс git умрет, и случится обычная проблема с EIO.

...