Is it possible to have a custom .gitignore? Read only access?

前端 未结 5 1503
生来不讨喜
生来不讨喜 2020-12-12 23:35

I am working in a team environment, and there is already a .gitignore file.

I want to add more items to the .gitignore file, but I don\'t w

相关标签:
5条回答
  • 2020-12-12 23:50

    You may be interested in an update hook that Junio wrote and that Carl improved. Place the code below in $GIT_DIR/hooks/update and don't forget to enable it with 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"
    

    With this hook in place, you then give particular users or groups to make changes to the repository. Anyone else who can see it has read-only access.

    This uses two files, $GIT_DIR/info/allowed-users and allowed-groups, to describe which heads can be pushed into by whom. The format of each file would look like this:

    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
    

    With this, Linus can push or create bw/penguin or bw/zebra or bw/panda branches, Pasky can do only cogito, and JC can do master and pu branches and make versioned tags. And anybody can do tmp/blah branches. The '+' sign at the pu record means that JC can make non-fast-forward pushes on it.

    If this person doesn't already have access to the host where your repository lives, maybe that person should have only git-shell access rather than unrestricted access. Create a special-purpose git user and in ~git/.ssh/authorized_keys, add the outsider's SSH key in the following form. Note that the key should be on one long line, but I've wrapped it below to aid presentation.

    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

    Depending on your local setup, you may need to adjust the path to git-shell. Remember that sshd is highly paranoid about permissions of the .ssh directory, so turn off its group-write bits and all files beneath it.

    Funneling everyone through the git user means you need to be able tell people apart, and this is the purpose of the myorg_git_user environment variable. Instead of relying on an unconditional username=$(id -u -n), tweak your update hook to use it:

    # 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'"
    

    With this setup, your friend with readonly access will clone with a command resembling the one below. The particular path will depend on your setup. To make the nice path work, either relocate your repository to the git user's home directory or create a symlink that points to it.

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

    but won't be able to make updates.

    $ 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'

    You said you're working in a team environment, so I assume your central repository was created with the --shared option. (See core.sharedRepository in the git config documentation and --shared in the git init documentation.) Make sure the new git user is a member of the system group that gives all of you access to your central repository.

    0 讨论(0)
  • 2020-12-13 00:00

    Like Fred Frodo said, you can put your private exclude rules in the .git/info/exclude of the repository.

    If you want to apply the same exclude rules to all the repositories on your machine, you can add the following to the .gitconfig file in your user directory.

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

    Then add your exclude patterns to ~/.gitexclude.

    0 讨论(0)
  • 2020-12-13 00:01

    I know I am a little late to the conversation but you might want to consider using

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

    As the git help document states:

    When the "assume unchanged" bit is on, git stops checking the working tree files for possible modifications, so you need to manually unset the bit to tell git when you change the working tree file...

    Emphasis mine. It goes on to say

    This option can be ... used as a coarse file-level mechanism to ignore uncommitted changes in tracked files (akin to what .gitignore does for untracked files). Git will fail (gracefully) in case it needs to modify this file in the index e.g. when merging in a commit; thus, in case the assumed-untracked file is changed upstream, you will need to handle the situation manually.

    So just keep in mind that you will have to be aware of any upstream changes made to these files.

    In the event that you want to start tracking the file again all you have to do is use

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

    I hope this helps any future viewers of this post.

    0 讨论(0)
  • 2020-12-13 00:04

    For the ssh part, you should consider using Gitolite (a replacement for gitosis).

    0 讨论(0)
  • 2020-12-13 00:12
    1. Put your private ignore rules in .git/info/exclude. See gitignore(5).
    2. For read-only access, use git-daemon, a web server, or Gitosis, or Gitolite.
    0 讨论(0)
提交回复
热议问题