ОБНОВЛЕНИЕ² : В Git 2.23 (август 2019 г.) есть новая команда,
git restore
которая делает это, см. Принятый ответ .ОБНОВЛЕНИЕ : Это будет работать более интуитивно, начиная с Git 1.8.3, смотрите мой собственный ответ .
Представьте себе следующий вариант использования: я хочу избавиться от всех изменений в конкретном подкаталоге моего рабочего дерева Git, оставив все остальные подкаталоги без изменений.
Я могу сделать
git checkout .
, но Git Checkout. добавляет каталоги, исключенные при редкой проверкеЕсть
git reset --hard
, но это не позволит мне сделать это для подкаталога:> git reset --hard . fatal: Cannot do hard reset with paths.
Опять же: почему git не может делать жесткий / мягкий сброс по пути?
Я могу
git diff subdir | patch -p1 -R
выполнить обратное исправление текущего состояния, используя , но это довольно странный способ сделать это.
Какова правильная команда Git для этой операции?
Сценарий ниже иллюстрирует проблему. Вставьте соответствующую команду под How to make files
комментарием - текущая команда восстановит файл, a/c/ac
который должен быть исключен из-за разреженной проверки. Обратите внимание, что я не хочу явно восстанавливать, a/a
и a/b
я только «знаю» a
и хочу восстановить все ниже. РЕДАКТИРОВАТЬ : И я также не "знаю" b
, или какие другие каталоги находятся на том же уровне, что и a
.
#!/bin/sh
rm -rf repo; git init repo; cd repo
for f in a b; do
for g in a b c; do
mkdir -p $f/$g
touch $f/$g/$f$g
git add $f/$g
git commit -m "added $f/$g"
done
done
git config core.sparsecheckout true
echo a/a > .git/info/sparse-checkout
echo a/b >> .git/info/sparse-checkout
echo b/a >> .git/info/sparse-checkout
git read-tree -m -u HEAD
echo "After read-tree:"
find * -type f
rm a/a/aa
rm a/b/ab
echo >> b/a/ba
echo "After modifying:"
find * -type f
git status
# How to make files a/* reappear without changing b and without recreating a/c?
git checkout -- a
echo "After checkout:"
git status
find * -type f
источник
git stash && git stash drop
?git checkout -- /path/to/subdir/
?git stash
не принимает аргумент пути ...Ответы:
С Git 2.23 (август 2019) у вас есть новая команда
git restore
Это заменило бы и индекс, и рабочее дерево
HEAD
содержимым, как еслиreset --hard
бы, но для определенного пути.Оригинальный ответ (2013)
Примечание (как заметил по Dan Fabulich ) , что:
git checkout -- <path>
не выполняет полный сброс: он заменяет содержимое рабочего дерева на поэтапное.git checkout HEAD -- <path>
выполняет полный сброс пути, заменяя индекс и рабочее дерево версией изHEAD
коммита.Как ответил на Ajedi32 , обе формы заказа не удалять файлы , которые были удалены в целевой пересмотре .
Если у вас есть дополнительные файлы в рабочем дереве, которых нет в HEAD,
git checkout HEAD -- <path>
они не будут удалены.Примечание: С помощью
git checkout --overlay HEAD -- <path>
(Git 2.22, Q1 2019) файлы, которые появляются в индексе и рабочем дереве, но не в нем<tree-ish>
, удаляются, чтобы они<tree-ish>
точно совпадали .Но эта проверка может относиться к
git update-index --skip-worktree
(для тех каталогов, которые вы хотите игнорировать), как указано в разделе « Почему исключенные файлы продолжают появляться в моей git sparse checkout? ».источник
git checkout HEAD -- .
этого файлы, исключенные из-за разреженной проверки, появляются снова. Чтоgit update-index --skip-worktree
должен делать?git checkout HEAD -- <path>
, а затем удалить каталоги, которые были восстановлены (но которые все еще объявляются в редкой проверке).По словам разработчика Git Дуи Нгуена (Duy Nguyen), который любезно реализовал функцию и переключатель совместимости , следующее, как и ожидалось, начиная с Git 1.8.3 :
(где
a
находится каталог, который вы хотите выполнить с полной перезагрузкой). К исходному поведению можно получить доступ черезисточник
git checkout -- .
где.
означает текущий каталог.git reset -- a
(где a - каталог, который вы хотите сбросить)git reset --hard
весь репо?rm -rf a
раньше.Попробуйте изменить
в
Начиная с версии 1.7.0, Git отмечает флаг skip-worktree .
ls-files
Запуск вашего тестового скрипта (с небольшими изменениями, меняющими
git commit
... наgit commit -q
иgit status
кgit status --short
) выводит:Запустите ваш тестовый скрипт с предлагаемыми
checkout
выходами изменений:источник
git checkout
в первую очередь уважать бит "skip-worktree"?checkout.c
иtree.c
не показывает, что используется флаг пропуска рабочего дерева.В случае простого отказа от изменений, команды
git checkout -- path/
или,git checkout HEAD -- path/
предложенные другими ответами, прекрасно работают. Однако, когда вы хотите сбросить каталог на версию, отличную от HEAD, это решение имеет существенную проблему: оно не удаляет файлы, которые были удалены в целевой редакции.Поэтому вместо этого я начал использовать следующую команду:
Это работает путем нахождения разницы между целевым коммитом и индексом, затем применяя эту разность обратно к рабочему каталогу и индексу. По сути, это означает, что содержимое индекса совпадает с содержимым указанной вами ревизии. Тот факт, что
git diff
используется аргумент пути, позволяет ограничить этот эффект определенным файлом или каталогом.Поскольку эта команда довольно длинная, и я планирую использовать ее часто, я создал для нее псевдоним, который я назвал
reset-checkout
:Вы можете использовать это так:
Или просто:
источник
git checkout --overlay HEAD -- <path>
командой, которую @VonC упоминает в своем ответе?git checkout --overlay HEAD -- <path>
еще не выпущено (Git 2.22 будет выпущен во втором квартале 2019 года)Я собираюсь предложить ужасный вариант здесь, так как я понятия не имею, как сделать что-то с git, кроме как,
add
commit
иpush
вот как я «перевернул» подкаталог:Я запустил новый репозиторий на своем локальном компьютере, вернул все это к коммиту, из которого я хотел скопировать код, а затем скопировал эти файлы в мой рабочий каталог
add
commit
push
и так далее. Не ненавидь игрока, ненавидь мистера Торвальдса за то, что он умнее всех нас.источник
Сброс обычно меняет все, но вы можете использовать,
git stash
чтобы выбрать то, что вы хотите сохранить. Как вы упомянули,stash
он не принимает путь напрямую, но его все равно можно использовать для сохранения определенного пути с--keep-index
флагом. В вашем примере вы бы спрятали каталог b, а затем сбросили все остальное.Это приведет вас к точке, где последняя часть вашего скрипта выведет это:
Я считаю, что это был целевой результат (b остается измененным, файлы / * возвращаются, / / не воссоздается).
Этот подход имеет дополнительное преимущество, поскольку он очень гибкий; вы можете получить как можно более мелкие детали, добавив определенные файлы, но не другие, в каталог.
источник
git add
все, кромеa
, верно? Звучит сложно на практике.git add .
Затем вы можетеgit reset a
добавить все, кромеa
.git add
не добавляет удаленные файлы. Итак, если вы восстанавливаете только удаленные файлы,git add .
добавьте все измененные файлы, но не удаленные.Если размер подкаталога не особенно велик, и вы хотите держаться подальше от CLI, вот быстрое решение для ручного сброса подкаталога:
Приветствия. Вы просто вручную сбрасываете подкаталог в вашей ветви функций, чтобы он был таким же, как и в основной ветви !!
источник
Ajedi32 «S ответа является то , что я искал , но для некоторых коммитов я столкнулся с этой ошибкой:
error: cannot apply binary patch to 'path/to/directory' without full index line
Может быть потому, что некоторые файлы каталога являются двоичными файлами. Добавление опции --binary к команде git diff исправило это:
источник
Что о
источник