Ist es möglich, einen benutzerdefinierten .gitignore zu haben? Schreibgeschützter Zugriff?

79

Ich arbeite in einer Teamumgebung und es gibt bereits eine .gitignoreDatei.

Ich möchte der .gitignoreDatei weitere Elemente hinzufügen , aber ich möchte diese Datei auch nicht einchecken. Ist es möglich, benutzerdefinierte Ignorierdateien festzulegen, die nur für mich gelten?

Außerdem möchte ich jemandem schreibgeschützten Zugriff auf ein privates Git-Repository auf unserem Server gewähren. Wenn ich seinen SSH-Schlüssel zu unserem Server hinzufüge, erhält er wie alle anderen vollen Zugriff. Wie kann ich es auf schreibgeschützt beschränken, keine Commits erlaubt?

Blankman
quelle

Antworten:

122
  1. Geben Sie Ihre privaten Ignorierregeln ein .git/info/exclude. Siehe gitignore(5).
  2. Verwenden Sie für den schreibgeschützten Zugriff git-daemoneinen Webserver , Gitosis oder Gitolite.
Fred Foo
quelle
und um die Sache noch schlimmer zu machen, möchte ich, dass dieser Gitignore für ein bestimmtes Projekt und nicht für ein globales Umfeld bestimmt ist.
Blankman
7
@Blankman: Füge es in .git/info/exclude das Stammverzeichnis des Projekts ein .
Fred Foo
1
Das machen es komplett: Mit der Konfigurationsoption core.excludesfilekönnen Sie eine globale Ausschlussdatei angeben .
KingCrunch
1
Ich stimme Simon zu, dass Sie für jede Neuinstallation Gitolit anstelle von Gitosis verwenden sollten.
ebneter
1
Ein nützlicher Weg, dies zu verwenden: Zuerst -> ln -s .git/info/exclude .personalGitignoreDann können wir # ln -s .git/info/exclude .personalGitignore \n .personalGitignorezu .gitignore hinzufügen
Josu Goñi
18

Ich weiß, dass ich etwas spät zum Gespräch komme, aber vielleicht möchten Sie es in Betracht ziehen

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

In dem Git-Hilfedokument heißt es:

Wenn das Bit "Unverändert annehmen" aktiviert ist, überprüft git die Arbeitsbaumdateien nicht mehr auf mögliche Änderungen . Sie müssen das Bit also manuell deaktivieren, um git mitzuteilen, wenn Sie die Arbeitsbaumdatei ändern ...

Hervorhebung von mir. Es geht weiter zu sagen

Diese Option kann ... als grober Mechanismus auf Dateiebene verwendet werden, um nicht festgeschriebene Änderungen in nachverfolgten Dateien zu ignorieren (ähnlich wie .gitignore für nicht nachverfolgte Dateien). Git schlägt (ordnungsgemäß) fehl, wenn diese Datei im Index geändert werden muss, z. B. beim Zusammenführen in einem Commit. Wenn also die angenommene, nicht verfolgte Datei vorgelagert geändert wird, müssen Sie die Situation manuell behandeln .

Denken Sie also daran, dass Sie alle vorgelagerten Änderungen an diesen Dateien berücksichtigen müssen.

Für den Fall, dass Sie die Datei erneut verfolgen möchten, müssen Sie sie nur verwenden

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

Ich hoffe, dies hilft zukünftigen Zuschauern dieses Beitrags.

Jake Greene
quelle
2

Für den SSH-Teil sollten Sie Gitolite (ein Ersatz für Gitosis) in Betracht ziehen.

Simon
quelle
2

Wie Fred Frodo sagte, können Sie Ihre privaten Ausschlussregeln in .git/info/excludedas Repository aufnehmen.

Wenn Sie dieselben Ausschlussregeln auf alle Repositorys auf Ihrem Computer anwenden möchten, können Sie der .gitconfigDatei in Ihrem Benutzerverzeichnis Folgendes hinzufügen .

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

Fügen Sie dann Ihre Ausschlussmuster hinzu ~/.gitexclude.

Jesse Hogan
quelle
1

Sie könnten an einem Update-Hook interessiert sein , den Junio ​​geschrieben und den Carl verbessert hat. Geben Sie den folgenden Code ein $GIT_DIR/hooks/updateund vergessen Sie nicht, ihn mit zu aktivieren 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"

Mit diesem Hook geben Sie dann bestimmten Benutzern oder Gruppen die Möglichkeit, Änderungen am Repository vorzunehmen. Jeder andere, der es sehen kann, hat nur Lesezugriff.

Dies verwendet zwei Dateien $GIT_DIR/info/allowed-usersund allowed-groups, um zu beschreiben, welche Köpfe von wem hineingeschoben werden können. Das Format jeder Datei würde folgendermaßen aussehen:

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

Damit kann Linus pushen oder erstellen bw/penguinoder bw/zebraoder bw/pandaverzweigen, Pasky kann nur cogitound JC kann masterund puverzweigen und versionierte Tags erstellen . Und jeder kann tmp/blahZweige machen. Das Pluszeichen im puDatensatz bedeutet, dass JC nicht schnell vorwärts drücken kann.

Wenn diese Person noch keinen Zugriff auf den Host hat, auf dem sich Ihr Repository befindet, sollte diese Person möglicherweise nur git-shellZugriff und keinen uneingeschränkten Zugriff haben. Erstellen Sie einen speziellen Git-Benutzer und ~git/.ssh/authorized_keysfügen Sie den SSH-Schlüssel des Außenstehenden in der folgenden Form hinzu. Beachten Sie, dass sich der Schlüssel in einer langen Zeile befinden sollte, aber ich habe ihn unten verpackt, um die Präsentation zu erleichtern.

No-Agent-Weiterleitung, No-Port-Weiterleitung, No-Pty, No-X11-Weiterleitung,
command = "env myorg_git_user = joeuser / usr / local / bin / git-shell -c
"$ {SSH_ORIGINAL_COMMAND: -}" ssh-rsa AAAAB3 ... 2iQ == [email protected]

Abhängig von Ihrem lokalen Setup müssen Sie möglicherweise den Pfad zu anpassen git-shell. Denken Sie daran, dass die sshdBerechtigungen des .sshVerzeichnisses sehr paranoid sind. Deaktivieren Sie daher die Gruppenschreibbits und alle darunter liegenden Dateien.

Wenn Sie alle Benutzer durch den Git-Benutzer leiten, müssen Sie in der Lage sein, die Benutzer voneinander zu unterscheiden. Dies ist der Zweck der myorg_git_userUmgebungsvariablen. Anstatt sich auf ein Unbedingtes zu verlassen username=$(id -u -n), optimieren Sie Ihren Update-Hook, um ihn zu verwenden:

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

Mit diesem Setup klont Ihr Freund mit schreibgeschütztem Zugriff mit einem Befehl, der dem folgenden ähnelt. Der jeweilige Pfad hängt von Ihrem Setup ab. Um den netten Pfad zum Laufen zu bringen, verschieben Sie entweder Ihr Repository in das Home-Verzeichnis des Git-Benutzers oder erstellen Sie einen Symlink, der darauf verweist.

$ git clone [email protected]: coolproject.git

kann aber keine Updates vornehmen.

$ git push origin mybranch 
Insgesamt 0 (Delta 0), wiederverwendet 0 (Delta 0)
remote: error: hook lehnte es ab, refs / Heads / Mybranch zu aktualisieren
An [email protected]: coolproject.git
 ! [remote abgelehnt] mybranch -> mybranch (Haken abgelehnt)
Fehler: Einige Refs konnten nicht an '[email protected]: coolproject.git' gesendet werden.

Sie sagten, Sie arbeiten in einer Teamumgebung, daher gehe ich davon aus, dass Ihr zentrales Repository mit dieser --sharedOption erstellt wurde. (Siehe core.sharedRepositoryin der git configDokumentation und --sharedin der git initDokumentation .) Stellen Sie sicher, dass der neue Git-Benutzer Mitglied der Systemgruppe ist, die Ihnen allen Zugriff auf Ihr zentrales Repository gewährt.

Greg Bacon
quelle