Git должен удалить пустые каталоги? - PullRequest
5 голосов
/ 03 апреля 2019

Недавно я сделал git rm последнего файла в каталоге (a) и по какой-то причине решил также удалить этот каталог. Я проверил поведение с новым файлом следующим образом:

mkdir newdir
touch newdir/newfile
git add newdir/newfile
git commit
git rm newdir/newfile

Когда я делаю эту последнюю строку, каталог newdir полностью исчезает. Это ожидаемое поведение? Насколько я понимаю, Git отслеживал файлы, а не каталоги.

Поскольку после первого шага он не жалуется на создание каталога без отслеживаемых файлов, почему он удаляет каталог только потому, что я удаляю из него последний отслеживаемый файл?

Для чего стоит, я использую версию 2.7.4.


(a) У меня был один каталог-заполнитель с файлом gitDummy, так что он был перенесен в репозиторий. Затем у меня было много реальных файлов, которые я хотел добавить, поэтому я удалил пустышку и попытался скопировать новые файлы, чтобы подготовиться к добавлению, фиксации и отправке.

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

1 Ответ

8 голосов
/ 03 апреля 2019

Это следует за этим июньским потоком 2018 года , где оно сообщается как "git rm bug"

TLDR;это не ошибка.

Никакая команда Git не должна вести себя так, чтобы при переходе от коммита X к Y дерево оставалось в таком состоянии, чтобы вы не получили тот же Y если вы клонировали.

В теме:

ОБЗОР

"git rm" удалит больше файлов, чем указано.Это либо ошибка, либо недокументированное поведение (не на страницах руководства).

SETUP

  1. В репозитории git создайте пустой каталог ИЛИ цепочку пустых каталогов

    $ mkdir -p path / to / some /

  2. Создайте файл в самом глубоком каталоге и добавьте его в список отслеживания

    $ touch path /в / some / file $ git add path / в / some / file $ git commit -m 'add path / to / some / file'

THE BUG

Запустите 'git rm' для отслеживаемого файла.

ОЖИДАЕМОЕ ПОВЕДЕНИЕ

$ git rm path/to/some/file
rm 'path/to/some/file'
$ ls path
to/
$ ls path/to
some/

Обратите внимание, что path/, path/to/ и path/to/some/ все еще существуют.

АКТУАЛЬНОЕ ПОВЕДЕНИЕ

$ git rm path/to/some/file
rm 'path/to/some/file'
$ ls path
ls: cannot access 'path': No such file or directory

Вся цепочка пустых каталогов удаляется, несмотря на то, что git выводит только "rm 'path/to/some/file'".

Это ТОЛЬКО происходит, когда все каталоги в цепочке пусты после удаления отслеживаемого файла.

Это поведение НЕ задокументировано на страницах руководства.

Я предлагаю добавить операторы 'rmdir' в вывод 'git rm' или обновить страницы руководства, чтобы отразить это поведение.

Общий принцип таков:

Git не может отслеживать пустые каталоги.
Так как это было only содержимым во всей этой иерархии, всяиерархия должна была быть удалена.

Похоже, что это поведение было в течение многих лет, так как d9b814cc97 ("Добавить встроенную" команду git rm "", 2006-05-19,Git v1.4.0-rc1).
Интересно, что Линус отметил в сообщении коммита, чтоудаление ведущих каталогов отличалось от того, когда git-rm был сценарием оболочки.
И он задался вопросом, может быть, стоит иметь возможность контролировать это поведение.

Я полагаю, что большинство пользователей либо хотят текущийповедение или они редко сталкиваются с этим и удивляются, учитывая, как долго git rm работал таким образом.

Это также согласуется с другими частями Git, которые удаляют файлы.Например, «git checkout» до состояния, в котором нет файла, удалит ведущие каталоги (если они, конечно, пусты).

В более общем случае:

Я собираюсь быть противоречивым и упрямым и предположить, что текущее поведение в порядке, поскольку нет никаких убедительных причин для любого другого поведения.

Неизменно, каждая защита для подвешиванияопустошение каталогов сводится к тому, что «в будущем я могу сделать что-то, что ожидает, что эти каталоги будут существовать».
Ну, если это так, то создавайте их тогда, когда они вам нужны - ничего, что вы должны делать, просто не нужно предположим, существование необходимых каталогов.

Кроме того, "отслеживая" эти каталоги, вы предлагаете Git спокойно делать то, что обычно следует делать с помощью "git rm --cached".
Если мне нужно такое поведение, я бы предпочел набрать его сам.

Например, чтобы проиллюстрировать, почему не удаление пустой папки было бы проблематичным:

Другие говорили, почему, но вот крайний случай, о котором вы, вероятно, не задумывались:

(
    rm -rf /tmp/repo &&
    git init /tmp/repo &&
    cd /tmp/repo &&
    mkdir -p foo/bar/baz &&
    git status
)

Если у вас просто пустые каталоги, "git status" ничего не сообщит, хотя "git clean -dxfn "покажет, что будет очищено.

Так что, если это сработает, как вы предлагаете, тогда кто-нибудь может git rm какой-то файл, тогда все сообщат, что они находятся на коммите XYZ,но если бы они клонировали этот коммит, то получили бы дерево, которое выглядело бы иначе.

Никакая команда Git не должна вести себя так, чтобы при переходе из коммита * оставить дерево в состоянии, при котором вы не получите тот же Y, если будете клонировать.


Примечание: официальный git rm тест (git/git/t/t3600-rm.sh) самого репозитория Git совершенно ясен относительно того, что он ожидает:

test_expect_success 'rm removes subdirectories recursively' '
    mkdir -p dir/subdir/subsubdir &&
    echo content >dir/subdir/subsubdir/file &&
    git add dir/subdir/subsubdir/file &&
    git rm -f dir/subdir/subsubdir/file &&
    ! test -d dir
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...