code: func ParseAttributesLine(line string, domain []string, allowMacro bool) (m MatchAttribute, err error) {
  	line = strings.TrimSpace(line)
  
  	if strings.HasPrefix(line, commentPrefix) || len(line) == 0 {
  		return
  	}
  
  	name, unquoted := unquote(line)
  	attrs := strings.Fields(unquoted)
  	if len(name) == 0 {
  		name = attrs[0]
  		attrs = attrs[1:]
  	}
  
  	var macro bool
  	macro, name, err = checkMacro(name, allowMacro)
  	if err != nil {
  		return
  	}
  
  	m.Name = name
  	m.Attributes = make([]Attribute, 0, len(attrs))
  
  	for _, attrName := range attrs {
  		attr := attribute{
  			name:  attrName,
  			state: attributeSet,
  		}
  
  		// ! and - prefixes
  		state := attributeState(attr.name[0])
  		if state == attributeUnspecified || state == attributeUnset {
  			attr.state = state
  			attr.name = attr.name[1:]
  		}
  
  		kv := strings.SplitN(attrName, "=", 2)
  		if len(kv) == 2 {
  			attr.name = kv[0]
  			attr.value = kv[1]
  			attr.state = attributeSetValue
  		}
  
  		if !validAttributeName(attr.name) {
  			return m, ErrInvalidAttributeName
  		}
  		m.Attributes = append(m.Attributes, attr)
  	}
  
  	if !macro {
  		m.Pattern = ParsePattern(name, domain)
  	}
  	return
  }
docs: // ParseAttributesLine parses a gitattribute line, extracting path pattern and
  // attributes.