Возможно ли иметь пользовательский .gitignore? Доступ только для чтения?

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

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

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

Ответ 1

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

Ответ 2

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

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

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

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

Акцент мой. Далее говорится

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

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

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

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

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

Ответ 3

Для части ssh вам следует использовать Gitolite (замена для гитоза).

Ответ 4

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

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

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

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

Ответ 5

Вам может быть интересен крюк обновления, который написал Джунио и что Карл улучшился. Поместите код ниже в $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 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

При этом Linus может создавать или создавать ветки 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== [email protected]

В зависимости от вашей локальной настройки вам может потребоваться настроить путь до 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 [email protected]:coolproject.git

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

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

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