Можно ли иметь собственный .gitignore? Доступ только для чтения? - PullRequest
70 голосов
/ 25 мая 2011

Я работаю в командной среде, и уже существует файл .gitignore.

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

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

Ответы [ 5 ]

111 голосов
/ 25 мая 2011
  1. Поместите ваши частные правила игнорирования в .git/info/exclude. См gitignore(5).
  2. Для доступа только для чтения используйте git-daemon, веб-сервер , или Gitosis, или Gitolite.
18 голосов
/ 31 августа 2012

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

git update-index --assume-unchanged [ FILE ]

Как говорится в документе справки git:

Когда бит «предположить, что без изменений» включен, git прекращает проверку файлов рабочего дерева на предмет возможных изменений , поэтому вам нужно вручную сбросить бит, чтобы сообщить git при изменении файла рабочего дерева .. .

Акцент мой. Это продолжает говорить

Эту опцию можно ... использовать в качестве грубого механизма на уровне файлов для игнорирования незафиксированных изменений в отслеживаемых файлах (сродни тому, что .gitignore делает для неотслеживаемых файлов). Git потерпит неудачу (изящно), если ему нужно изменить этот файл в индексе, например при слиянии в коммите; таким образом, в случае, если предполагаемый неотслеживаемый файл изменяется в восходящем направлении, вам нужно будет обработать ситуацию вручную .

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

В случае, если вы хотите снова начать отслеживать файл, все, что вам нужно сделать, это использовать

git update-index --no-assume-unchange [ FILE ]

Надеюсь, это поможет любым будущим читателям этого поста.

2 голосов
/ 25 мая 2011

Для части ssh вы должны рассмотреть возможность использования Gitolite (замена для gitosis).

1 голос
/ 02 мая 2017

Как сказал Фред Фродо, вы можете поместить свои частные правила исключения в .git/info/exclude хранилища.

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

[core]       
    excludesfile = /home/<myusername>/.gitexclude 

Затем добавьте ваши шаблоны исключения в ~/.gitexclude.

0 голосов
/ 25 мая 2011

Вас может заинтересовать хук обновления , который написал Junio ​​и который Карл улучшил. Поместите код ниже в $GIT_DIR/hooks/update и не забудьте включить его с помощью chmod +x.

#!/bin/bash

umask 002

# If you are having trouble with this access control hook script
# you can try setting this to true.  It will tell you exactly
# why a user is being allowed/denied access.

verbose=false

# Default shell globbing messes things up downstream
GLOBIGNORE=*

function grant {
  $verbose && echo >&2 "-Grant-     $1"
  echo grant
  exit 0
}

function deny {
  $verbose && echo >&2 "-Deny-      $1"
  echo deny
  exit 1
}

function info {
  $verbose && echo >&2 "-Info-      $1"
}

# Implement generic branch and tag policies.
# - Tags should not be updated once created.
# - Branches should only be fast-forwarded unless their pattern starts with '+'
case "$1" in
  refs/tags/*)
    git rev-parse --verify -q "$1" &&
    deny >/dev/null "You can't overwrite an existing tag"
    ;;
  refs/heads/*)
    # No rebasing or rewinding
    if expr "$2" : '0*$' >/dev/null; then
      info "The branch '$1' is new..."
    else
      # updating -- make sure it is a fast-forward
      mb=$(git-merge-base "$2" "$3")
      case "$mb,$2" in
        "$2,$mb") info "Update is fast-forward" ;;
    *)    noff=y; info "This is not a fast-forward update.";;
      esac
    fi
    ;;
  *)
    deny >/dev/null \
    "Branch is not under refs/heads or refs/tags.  What are you trying to do?"
    ;;
esac

# Implement per-branch controls based on username
allowed_users_file=$GIT_DIR/info/allowed-users
username=$(id -u -n)
info "The user is: '$username'"

if test -f "$allowed_users_file"
then
  rc=$(cat $allowed_users_file | grep -v '^#' | grep -v '^$' |
    while read heads user_patterns
    do
      # does this rule apply to us?
      head_pattern=${heads#+}
      matchlen=$(expr "$1" : "${head_pattern#+}")
      test "$matchlen" = ${#1} || continue

      # if non-ff, $heads must be with the '+' prefix
      test -n "$noff" &&
      test "$head_pattern" = "$heads" && continue

      info "Found matching head pattern: '$head_pattern'"
      for user_pattern in $user_patterns; do
    info "Checking user: '$username' against pattern: '$user_pattern'"
    matchlen=$(expr "$username" : "$user_pattern")
    if test "$matchlen" = "${#username}"
    then
      grant "Allowing user: '$username' with pattern: '$user_pattern'"
    fi
      done
      deny "The user is not in the access list for this branch"
    done
  )
  case "$rc" in
    grant) grant >/dev/null "Granting access based on $allowed_users_file" ;;
    deny)  deny  >/dev/null "Denying  access based on $allowed_users_file" ;;
    *) ;;
  esac
fi

allowed_groups_file=$GIT_DIR/info/allowed-groups
groups=$(id -G -n)
info "The user belongs to the following groups:"
info "'$groups'"

if test -f "$allowed_groups_file"
then
  rc=$(cat $allowed_groups_file | grep -v '^#' | grep -v '^$' |
    while read heads group_patterns
    do
      # does this rule apply to us?
      head_pattern=${heads#+}
      matchlen=$(expr "$1" : "${head_pattern#+}")
      test "$matchlen" = ${#1} || continue

      # if non-ff, $heads must be with the '+' prefix
      test -n "$noff" &&
      test "$head_pattern" = "$heads" && continue

      info "Found matching head pattern: '$head_pattern'"
      for group_pattern in $group_patterns; do
    for groupname in $groups; do
      info "Checking group: '$groupname' against pattern: '$group_pattern'"
      matchlen=$(expr "$groupname" : "$group_pattern")
      if test "$matchlen" = "${#groupname}"
      then
        grant "Allowing group: '$groupname' with pattern: '$group_pattern'"
      fi
        done
      done
      deny "None of the user's groups are in the access list for this branch"
    done
  )
  case "$rc" in
    grant) grant >/dev/null "Granting access based on $allowed_groups_file" ;;
    deny)  deny  >/dev/null "Denying  access based on $allowed_groups_file" ;;
    *) ;;
  esac
fi

deny >/dev/null "There are no more rules to check.  Denying access"

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

Здесь используются два файла, $GIT_DIR/info/allowed-users и allowed-groups, для описания того, в какие головы кто-то может толкнуть. Формат каждого файла будет выглядеть следующим образом:

refs/heads/master  junio
+refs/heads/pu     junio
refs/heads/cogito$ pasky
refs/heads/bw/.*   linus
refs/heads/tmp/.*  .*
refs/tags/v[0-9].* junio

При этом Линус может выдвигать или создавать ветви bw/penguin или bw/zebra или bw/panda, Pasky может делать только cogito, а JC может создавать master и pu ветви и создавать версионные теги. И любой может сделать tmp/blah ветви. Знак «+» в записи pu означает, что JC может делать на него нажатия без ускоренной перемотки вперед.

Если у этого человека еще нет доступа к хосту, на котором находится ваш репозиторий, возможно, у этого человека должен быть только git-shell доступ, а не неограниченный доступ. Создайте специального пользователя git и в ~git/.ssh/authorized_keys добавьте внешний ключ SSH в следующей форме. Обратите внимание, что ключ должен быть на одной длинной строке, но я обернул его ниже, чтобы облегчить представление.

no-agent-forwarding,no-port-forwarding,no-pty,no-X11-forwarding,
command="env myorg_git_user=joeuser /usr/local/bin/git-shell -c
\"${SSH_ORIGINAL_COMMAND:-}\"" ssh-rsa AAAAB3...2iQ== joeuser@foo.invalid

В зависимости от вашей локальной настройки, вам может потребоваться настроить путь на git-shell. Помните, что sshd крайне параноидален в отношении разрешений для каталога .ssh, поэтому отключите его биты групповой записи и все файлы под ним.

Проведение всех через пользователя git означает, что вам нужно уметь отличать людей друг от друга, и это является целью переменной окружения myorg_git_user. Вместо того чтобы полагаться на безусловный username=$(id -u -n), настройте ваш хук обновления, чтобы использовать его:

# Implement per-branch controls based on username
allowed_users_file=$GIT_DIR/info/allowed-users
if [ -z "$myorg_git_user" ]; then
  username=$(id -u -n)
else
  username=$myorg_git_user
fi
info "The user is: '$username'"

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

$ git clone git@blankman.com.invalid:coolproject.git

но не сможет делать обновления.

$ git push origin mybranch 
Total 0 (delta 0), reused 0 (delta 0)
remote: error: hook declined to update refs/heads/mybranch
To git@blankman.com.invalid:coolproject.git
 ! [remote rejected] mybranch -> mybranch (hook declined)
error: failed to push some refs to 'git@blankman.com.invalid:coolproject.git'

Вы сказали, что работаете в командной среде, поэтому я предполагаю, что ваш центральный репозиторий был создан с опцией --shared. (См. core.sharedRepository в git config документации и --shared в git init документации .) Убедитесь, что новый пользователь git является членом группы системы, которая дает всем вам доступ к вашему центральному хранилищу.

...