Как восстановить права доступа к файлам и каталогам в git, если они были изменены?

279

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

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

Дейл Форестер
источник

Ответы:

572

Git отслеживает разрешение файлов и выставляет изменения разрешений при создании патчей с помощью git diff -p. Итак, все, что нам нужно, это:

  1. создать обратный патч
  2. включать только изменения разрешения
  3. применить патч к нашей рабочей копии

Как однострочник:

git diff -p -R --no-ext-diff --no-color \
    | grep -E "^(diff|(old|new) mode)" --color=never  \
    | git apply

Вы также можете добавить его в качестве псевдонима для вашего git config ...

git config --global --add alias.permission-reset '!git diff -p -R --no-ext-diff --no-color | grep -E "^(diff|(old|new) mode)" --color=never | git apply'

... и вы можете вызвать его через:

git permission-reset

Обратите внимание, что если вы используете shell bash, убедитесь, что 'вместо "кавычек используется !git, в противном случае он будет заменен последней gitкомандой, которую вы выполнили.

Спасибо @Mixologic за указание, что при простом использовании -Ron git diffгромоздкая sedкоманда больше не требуется.

muhqu
источник
3
Я в OS X, это не работает. Я определил проблему в git apply. Он не применяет изменения прав доступа к файлам.
pepper_chico
15
О, это сработало, я пытался подать заявку из каталога, отличного от корня хранилища. git apply работает только там.
pepper_chico
6
Есть ли какая-то причина, по которой вы бы просто не делали "git diff -p -R" вместо того, чтобы делать sed, чтобы сделать все наоборот?
Mixologic
6
@RobQuist Мои локальные изменения не были удалены при использовании команды
muhqu
17
Я получаюfatal: unrecognized input
Tieme
121

Пытаться git config core.fileMode false

Со git configстраницы руководства :

core.fileMode

Если false, различия в исполняемых битах между индексом и рабочей копией игнорируются; полезно на сломанных файловых системах, таких как FAT. Смотрите git-update-index (1) .

Значение по умолчанию - true, за исключением того, что git-clone (1) или git-init (1) будут проверять и устанавливать core.fileMode false, если это необходимо, при создании хранилища.

Тим Хениган
источник
Спасибо, это то, что я в итоге сделал. Очень привык к тому, что cvs не отслеживает разрешения, так что это работает.
Дейл Форестер
3
@shovas: Я рад, что это помогло. У меня возникла похожая проблема при совместном использовании репозиториев между Linux и Windows. Кстати: если это ответило на ваш вопрос, пометьте ответ как правильный.
Тим Хениган
Возможно ли, что git checkout origin/masterправа доступа к файлу, назначенные серверу , устанавливаются для моей локальной рабочей копии? Потому что всякий раз, когда я собираю V8 для ArangoDB, права доступа к файлам меняются так, что доступ запрещается ко всей папке сборки (даже с повышенными правами; Windows 7+, то есть). Мне нужно исправить все локальные права доступа к файлам, прежде чем я смогу продолжить процесс сборки. core.filemode falseЭто тоже можно исправить? Я подозреваю, что git устанавливает права Linux на моем компьютере с Windows. Сценарии сборки могут просто сохранять их и применять те же разрешения для вновь создаваемых файлов ...
CodeManX
Им интересно , если есть какой - либо недостаток установки filemodeна false!
Кевороид
11

Git не хранит права доступа к файлам, кроме исполняемых скриптов. Попробуйте использовать что-то вроде git-cache-meta, чтобы сохранить владение файлом и разрешения.

Git может хранить только два типа режимов: 755 (исполняемый) и 644 (не исполняемый). Если бы ваш файл был 444, git сохранял бы в нем 644.

Kroger
источник
14
Извините, но это неверно. Git действительно отслеживает разрешения.
Будет
4
Это примерно точно, см. Git.wiki.kernel.org/index.php/ContentLimitations . Точные установленные разрешения отображаются в зависимости от сервера и, возможно, клиента, umaskа также от настроек конфигурации, см. Stackoverflow.com/a/12735291/125150 .
Мотти Стром
12
@ Нет, не будет. Не могу поверить, что ваш комментарий получил так много голосов.
эйс
@ Уилл, это примерно правильно. По документам ...a mode of 100644, which means it’s a normal file. Other options are 100755, which means it’s an executable file; and 120000, which specifies a symbolic link. The mode is taken from normal UNIX modes but is much less flexible — these three modes are the only ones that are valid for files (blobs) in Git (although other modes are used for directories and submodules).
Esmail
9
git diff -p \
| grep -E '^(diff|old mode|new mode)' \
| sed -e 's/^old/NEW/;s/^new/old/;s/^NEW/new/' \
| git apply

в большинстве случаев будет работать, но если у вас установлены внешние инструменты сравнения, такие как meld, вы должны добавить --no-ext-diff

git diff --no-ext-diff -p \
    | grep -E '^(diff|old mode|new mode)' \
    | sed -e 's/^old/NEW/;s/^new/old/;s/^NEW/new/' \
    | git apply

был необходим в моей ситуации

zainengineer
источник
0

Я использую Git из Cygwin для Windows, git applyрешение не работает для меня. Вот мое решение, запустить chmodна каждом файле, чтобы сбросить его разрешения.

#!/bin/bash
IFS=$'\n'
for c in `git diff -p |sed -n '/diff --git/{N;s/diff --git//g;s/\n/ /g;s# a/.* b/##g;s/old mode //g;s/\(.*\) 100\(.*\)/chmod \2 \1/g;p}'`
do
        eval $c
done
unset IFS

alijandro
источник
-1

git diff -pиспользуемый в ответе Мухку может не показать все расхождения.

  • видел это в Cygwin для файлов, которые мне не принадлежали
  • изменения режима полностью игнорируются, если core.filemodeесть false(по умолчанию для MSysGit)

Этот код читает метаданные напрямую:

(set -o errexit pipefail nounset;
git ls-tree HEAD -z | while read -r -d $'\0' mask type blob path
do
    if [ "$type" != "blob" ]; then continue; fi;
    case "$mask" in
    #do not touch other bits
    100644) chmod a-x "$path";;
    100755) chmod a+x "$path";;
    *) echo "invalid: $mask $type $blob\t$path" >&2; false;;
    esac
done)

Однострочник непроизводственного класса (полностью заменяет маски):

git ls-tree HEAD | perl -ne '/^10(0\d{3}) blob \S+\t(.+)$/ && { system "chmod",$1,$2 || die }'

(Кредит на "$ '\ 0'" идет по адресу http://transnum.blogspot.ru/2008/11/bashs-read-built-in-supports-0-as.html )

ivan_pozdeev
источник
-2

Самое простое, что нужно сделать, это просто поменять разрешения обратно. Как заметил @kroger, git отслеживает только исполняемые биты. Так что вам, вероятно, просто нужно запустить, chmod -x filenameчтобы исправить это (или, +xесли это то, что нужно.

Пэт Нотц
источник
Вот пример из git show: diff --git a / OpenWatch / src / org / ale / openwatch / fb / FBUtils.java b / OpenWatch / src / org / ale / openwatch / fb / FBUtils.java index cd6fa6a..e5b0935 100644 Это немного жирным шрифтом есть файл разрешений.
Конрадо
Мне это тоже показалось проще. К сожалению, я столкнулся с той же проблемой, что и Конрадо - я не мог изменить разрешение с 100644на 100755. Я не думаю, что вы заслуживаете понижения; Git должен быть проголосовал против. Это так сломано во многих отношениях на многих различных уровнях ...
jww
-2

etckeeperИнструмент может обрабатывать разрешения и с:

etckeeper init -d /mydir

Вы можете использовать его для других папок, чем /etc.

Установите с помощью диспетчера пакетов или получите ссылки по ссылке выше.

MoreIT
источник
4
На что он устанавливает разрешения? Если он не читает метаданные Git и не вызывает Git, он не выполняет то, что запрашивал OP.
ivan_pozdeev