syntax = "proto3";

package gitaly;

import "errors.proto";
import "google/protobuf/timestamp.proto";
import "lint.proto";
import "shared.proto";

option go_package = "gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb";

// OperationService provides an interface for performing mutating git
// operations on a repository on behalf of a user. The user's operation is
// treated as untrusted. Any reference update is thus checked against GitLab's
// '/allowed' endpoint.
service OperationService {

  // This comment is left unintentionally blank.
  rpc UserCreateBranch(UserCreateBranchRequest) returns (UserCreateBranchResponse) {
    option (op_type) = {
      op: MUTATOR
    };
  }

  // This comment is left unintentionally blank.
  rpc UserUpdateBranch(UserUpdateBranchRequest) returns (UserUpdateBranchResponse) {
    option (op_type) = {
      op: MUTATOR
    };
  }

  // UserDeleteBranch force-deletes a single branch in the context of a specific user. It executes
  // hooks and contacts Rails to verify that the user is indeed allowed to delete that branch. The
  // following known error conditions may happen:
  //
  // - Returns `InvalidArgument` in case either the branch name or user are not set.
  // - Returns `FailedPrecondition` in case the branch does not exist.
  // - Returns `OK` with a `PreReceiveError` in case custom hooks refused the update. If the
  //   `gitaly_user_delete_branch_structured_errors` feature flag is enabled this error case will
  //   instead return `PermissionDenied` with either a `CustomHook` or AccessCheck` structured
  //   error.
  // - Returns `FailedPrecondition` in case updating the reference fails because
  //   of a concurrent write to the same reference. If the
  //   `gitaly_user_delete_branch_structured_errors` feature flag is set this error case will
  //   instead return `FailedPrecondition` with a `ReferenceUpdate` structured error.
  rpc UserDeleteBranch(UserDeleteBranchRequest) returns (UserDeleteBranchResponse) {
    option (op_type) = {
      op: MUTATOR
    };
  }

  // UserCreateTag creates a new tag. This RPC knows to create both lightweight and annotated tags
  // depending on whether a message is set.
  rpc UserCreateTag(UserCreateTagRequest) returns (UserCreateTagResponse) {
    option (op_type) = {
      op: MUTATOR
    };
  }

  // This comment is left unintentionally blank.
  rpc UserDeleteTag(UserDeleteTagRequest) returns (UserDeleteTagResponse) {
    option (op_type) = {
      op: MUTATOR
    };
  }

  // UserMergeRef creates a merge commit and updates target_ref to point to that
  // new commit. The first parent of the merge commit (the main line) is taken
  // from first_parent_ref. The second parent is specified by its commit ID in source_sha.
  // If target_ref already exists it will be overwritten.
  rpc UserMergeToRef(UserMergeToRefRequest) returns (UserMergeToRefResponse) {
    option (op_type) = {
      op: MUTATOR
    };
  }

  // UserMergeBranch tries to merge the given commit into the target branch.
  // The merge commit is created with the given user as author/committer and
  // the given message.
  //
  // This RPC requires confirmation to make any user-visible changes to the
  // repository. The first request sent shall contain details about the
  // requested merge, which will result in a response with the created merge
  // commit ID. Only if a second message with `apply = true` is sent will the
  // merge be applied.
  rpc UserMergeBranch(stream UserMergeBranchRequest) returns (stream UserMergeBranchResponse) {
    option (op_type) = {
      op: MUTATOR
    };
  }

  // UserFFBranch tries to perform a fast-forward merge of the given branch to
  // the given commit. If the merge is not a fast-forward merge, the request
  // will fail. The RPC will return an empty response in case updating the
  // reference fails e.g. because of a race.
  rpc UserFFBranch(UserFFBranchRequest) returns (UserFFBranchResponse) {
    option (op_type) = {
      op: MUTATOR
    };
  }

  // UserCherryPick tries to perform a cherry-pick of a given commit onto a
  // branch.
  rpc UserCherryPick(UserCherryPickRequest) returns (UserCherryPickResponse) {
    option (op_type) = {
      op: MUTATOR
    };
  }

  // UserCommitFiles builds a commit from a stream of actions and updates the target branch to point to it.
  // UserCommitFilesRequest with a UserCommitFilesRequestHeader must be sent as the first message of the stream.
  // Following that, a variable number of actions can be sent to build a new commit. Each action consists of
  // a header followed by content if used by the action.
  rpc UserCommitFiles(stream UserCommitFilesRequest) returns (UserCommitFilesResponse) {
    option (op_type) = {
      op: MUTATOR
    };
  }

  // UserRebaseConfirmable rebases the given remote branch onto a target
  // branch. The remote branch may be part of another repository.
  //
  // This RPC requires confirmation to make any user-visible changes to the
  // repository. The first request sent shall contains details about the
  // requested rebase, which will result in a response with the created rebase
  // commit ID. Only if a second message with `apply = true` is sent will the
  // rebase be applied.
  rpc UserRebaseConfirmable(stream UserRebaseConfirmableRequest) returns (stream UserRebaseConfirmableResponse) {
    option (op_type) = {
      op: MUTATOR
    };
  }

  // UserRevert tries to perform a revert of a given commit onto a branch.
  rpc UserRevert(UserRevertRequest) returns (UserRevertResponse) {
    option (op_type) = {
      op: MUTATOR
    };
  }

  // UserSquash squashes a range of commits into a single commit. If
  // successful, it returns the object ID of the newly created squash commit.
  // On error, it returns a gRPC error. Some specific errors will have an
  // embedded UserSquashError such that clients can deduce what exactly has
  // failed.
  rpc UserSquash(UserSquashRequest) returns (UserSquashResponse) {
    option (op_type) = {
      op: MUTATOR
    };
  }

  // UserApplyPatch applies patches to a given branch.
  rpc UserApplyPatch(stream UserApplyPatchRequest) returns (UserApplyPatchResponse) {
    option (op_type) = {
      op: MUTATOR
    };
  }

  // UserUpdateSubmodule updates a submodule to point to a new commit.
  rpc UserUpdateSubmodule(UserUpdateSubmoduleRequest) returns (UserUpdateSubmoduleResponse) {
    option (op_type) = {
      op: MUTATOR
    };
  }

}

// This comment is left unintentionally blank.
message UserCreateBranchRequest {
  // This comment is left unintentionally blank.
  Repository repository = 1 [(target_repository)=true];
  // This comment is left unintentionally blank.
  bytes branch_name = 2;
  // This comment is left unintentionally blank.
  User user = 3;
  // This comment is left unintentionally blank.
  bytes start_point = 4;
}

// This comment is left unintentionally blank.
message UserCreateBranchResponse {
  // This comment is left unintentionally blank.
  Branch branch = 1;
  // pre_receive_error is deprecated and never set by Gitaly. Instead, Gitaly returns a structured
  // error with the `custom_hook` field set. This field will be removed in v16.0.
  string pre_receive_error = 2 [deprecated=true];
}

// UserCreateBranchError is an error returned by the UserCreateBranch RPC in some specific well
// defined error cases.
message UserCreateBranchError {
  oneof error {
    // CustomHookError is set if any custom hook which has running as part of
    // this RPC call has returned a non-zero exit code.
    CustomHookError custom_hook = 1;
  }
}

// This comment is left unintentionally blank.
message UserUpdateBranchRequest {
  // This comment is left unintentionally blank.
  Repository repository = 1 [(target_repository)=true];
  // This comment is left unintentionally blank.
  bytes branch_name = 2;
  // This comment is left unintentionally blank.
  User user = 3;
  // This comment is left unintentionally blank.
  bytes newrev = 4;
  // This comment is left unintentionally blank.
  bytes oldrev = 5;
}

// This comment is left unintentionally blank.
message UserUpdateBranchResponse {
  // This comment is left unintentionally blank.
  string pre_receive_error = 1;
}

// UserDeleteBranchRequest is a request for the UserDeleteBranch RPC.
message UserDeleteBranchRequest {
  // Repository is the repository to delete the branch in.
  Repository repository = 1 [(target_repository)=true];
  // BranchName is the name of the branch that shall be deleted. This is expected to be the branch
  // name only, e.g. in case you want to delete `refs/heads/main` the request needs to only contain
  // `main` as the branch name.
  bytes branch_name = 2;
  // User is the user on whose behalf we should delete the branch. This information is used to
  // perform access checks against the Rails `/internal/allowed` API. This user is also exposed to
  // any custom hooks executed as part of this RPC call.
  User user = 3;
}

// UserDeleteBranchResponse is a response for the UserDeleteBranch RPC.
message UserDeleteBranchResponse {
  // PreReceiveError is never set anymore. This RPC will instead return a UserDeleteBranchError for
  // a subset of well-defined error cases. This field will be removed in v16.0.
  string pre_receive_error = 1 [deprecated=true];
}

// UserDeleteBranchError is an error returned by the UserDeleteBranch RPC in some specific well
// defined error cases.
message UserDeleteBranchError {
  oneof error {
    // AccessCheckError is set if the RPC failed because `/internal/allowed` failed.
    AccessCheckError access_check = 1;
    // ReferenceUpdateError is set if the RPC failed because updating the
    // reference to the new object ID has failed.
    ReferenceUpdateError reference_update = 2;
    // CustomHook is set if any custom hook which has running as part of this RPC call has returned
    // a non-zero exit code.
    CustomHookError custom_hook = 3;
  }
}

// This comment is left unintentionally blank.
message UserDeleteTagRequest {
  // This comment is left unintentionally blank.
  Repository repository = 1 [(target_repository)=true];
  // This comment is left unintentionally blank.
  bytes tag_name = 2;
  // This comment is left unintentionally blank.
  User user = 3;
}

// This comment is left unintentionally blank.
message UserDeleteTagResponse {
  // This comment is left unintentionally blank.
  string pre_receive_error = 1;
}

// UserCreateTagRequest is a request for the UserCreateTag RPC.
message UserCreateTagRequest {
  // Repository is the repository in which the tag shall be created.
  Repository repository = 1 [(target_repository)=true];
  // TagName is the name of the tag that shall be created. Note that this should be set to the name
  // only: if you want to create a tag `refs/heads/v1.0`, you need to pass `v1.0` as TagName.
  bytes tag_name = 2;
  // User is the user as which the tag shall be created. This user is used to perform access checks
  // against Rails' `/internal/allowed` endpoint.
  User user = 3;
  // TargetRevision is the revision that the newly created tag should be pointing to. Note that if
  // the revision points to a tag, that tag will be peeled to the commit it is pointing to. If the
  // TargetRevision does not point to a commit then the RPC will return an error.
  bytes target_revision = 4;
  // Message is the message of the tag. If it is empty, a lightweight tag is created. Otherwise, an
  // annotated tag is created.
  bytes message = 5;
  // Timestamp is the optional timestamp to use for the created tag tags. If it's not set, the
  // current time will be used. It's only used if an annotated tag is being created.
  google.protobuf.Timestamp timestamp = 7;
}

// UserCreateTagResponse is a response for the UserCreateTag RPC.
message UserCreateTagResponse {
  // tag is the newly created tag.
  Tag tag = 1;
  // exists is deprecated and never set by Gitaly. Instead, Gitaly returns a structured error with
  // the `reference_exists` field set. This field will be removed in v16.0.
  bool exists = 2 [deprecated=true];
  // pre_receive_error is deprecated and never set by Gitaly. Instead, Gitaly returns a structured
  // error with either of the `access_check`, `reference_update` or `custom_hook` fields being set
  // depending on the error condition. This field will be removed in v16.0.
  string pre_receive_error = 3 [deprecated=true];
}

// UserCreateTagError includes error descriptions which may be set as error details in case
// UserCreateTag fails.
message UserCreateTagError {
  oneof error {
    // AccessCheckError is set if the RPC failed because `/internal/allowed` failed.
    AccessCheckError access_check = 1;
    // ReferenceUpdateError is set if the RPC failed because updating the
    // reference to the new object ID has failed.
    ReferenceUpdateError reference_update = 2;
    // CustomHook is set if any custom hook which has running as part of this RPC call has returned
    // a non-zero exit code.
    CustomHookError custom_hook = 3;
    // ReferenceExistsError is set if the tag reference exists already.
    ReferenceExistsError reference_exists = 4;
  }
}

// This comment is left unintentionally blank.
message UserMergeBranchRequest {
  // The following parameters must only be set in the first message to declare
  // parameters for the merge.

  // repository is the repository to compute the merge for.
  Repository repository = 1 [(target_repository)=true];
  // user is the user to compute the merge as. Its name and mail address are
  // used as author and committer of the merge.
  User user = 2;
  // commit_id is the object ID (hash) of the object that shall be merged into
  // the target branch.
  string commit_id = 3;
  // branch is the branch into which the given commit shall be merged and whose
  // reference is going to be updated.
  bytes branch = 4;
  // message is the message to use for the merge commit.
  bytes message = 5;
  // timestamp is the optional timestamp to use for the merge commit. If it's
  // not set, the current time will be used.
  google.protobuf.Timestamp timestamp = 7;

  // apply must only be set in the second message. Only if this second message
  // is sent and if apply is set to true will the branch be updated to point to
  // the merge commit.
  bool apply = 6;
}

// This comment is left unintentionally blank.
message UserMergeBranchResponse {
  // First message
  // The merge commit the branch will be updated to. The caller can still abort the merge.
  string commit_id = 1;

  reserved 2;
  // Second message
  // If set, the merge has been applied to the branch.
  OperationBranchUpdate branch_update = 3;

  // PreReceiveError had previously been set in case access checks refused the merge. This has been
  // changed to Instead we return a proper gRPC error with UserMergeBranchError details set to an
  // AccessCheckError.
  reserved "pre_receive_error";
  reserved 4;
}

// UserMergeBranchError includes error descriptions which may be set as error
// details in case UserMergeBranch fails.
message UserMergeBranchError {
  oneof error {
    // AccessCheckError is set if the RPC failed because `/internal/allowed` failed.
    AccessCheckError access_check = 1;
    // ReferenceUpdateError is set if the RPC failed because updating the
    // reference to the new object ID has failed.
    ReferenceUpdateError reference_update = 2;
    // CustomHook is set if any custom hook which has running as part of this RPC call has returned
    // a non-zero exit code.
    CustomHookError custom_hook = 3;
    // MergeConflictError is set if merging the revisions has resulted in conflicting files.
    MergeConflictError merge_conflict = 4;
  }
}

// This comment is left unintentionally blank.
message UserMergeToRefRequest {
  // repository is the repository in which the merge shall be computed.
  Repository repository = 1 [(target_repository)=true];
  // user is the user as which the merge commit shall be created.
  User user = 2;
  // source_sha is the object ID of the second parent of the computed merge.
  string source_sha = 3;
  // branch contains the name of the branch which should be used as the first
  // parent of the computed merge. It is deprecated in favor of
  // `first_parent_ref` and will be ignored in case it is set.
  bytes branch = 4;
  // target_ref contains the fully qualified reference which should be updated
  // with the computed merge commit.
  bytes target_ref = 5;
  // message is the message to use for the merge commit.
  bytes message = 6;
  // first_parent_ref is the name of the reference which should be used as the
  // first parent of the computed merge. Overrides `branch`.
  bytes first_parent_ref = 7;
  // Allow conflicts to occur. Any conflict markers will be part of the merge commit.
  // When tree-based conflicts occur, no conflict markers will be added to the
  // file on the merge commit. The `Their` side of the conflict will be kept and
  // `Our` and `Ancestor` will be ignored.
  bool allow_conflicts = 8;
  // timestamp is the optional timestamp to use for the merge commit. If it's
  // not set, the current time will be used.
  google.protobuf.Timestamp timestamp = 9;
}

// This comment is left unintentionally blank.
message UserMergeToRefResponse {
  // commit_id is the object ID of the computed merge commit.
  string commit_id = 1;

  // PreReceiveError had never been set because this RPC does not perform authentication via
  // `/internal/allowed`. This field was thus removed without replacement.
  reserved "pre_receive_error";
  reserved 2;
}

// OperationBranchUpdate contains the details of a branch update.
message OperationBranchUpdate {
  // commit_id is set to the OID of the created commit if a branch was created or updated.
  string commit_id = 1;
  // repo_created indicates whether the branch created was the first one in the repository.
  // Used for cache invalidation in GitLab.
  bool repo_created = 2;
  // branch_created indicates whether the branch already existed in the repository
  // and was updated or whether it was created. Used for cache invalidation in GitLab.
  bool branch_created = 3;
}

// UserFFBranchRequest contains parameters for the UserFFBranch RPC.
message UserFFBranchRequest {
  // repository is the repository for which to perform the fast-forward merge.
  Repository repository = 1 [(target_repository)=true];
  // user is the user which to perform the fast-forward merge as. This is used
  // for authorization checks.
  User user = 2;
  // commit_id is the commit ID to update the branch to.
  string commit_id = 3;
  // branch is the name of the branch that shall be update. This must be the
  // branch name only and not a fully qualified reference, e.g. "master"
  // instead of "refs/heads/master".
  bytes branch = 4;
}

// This comment is left unintentionally blank.
message UserFFBranchResponse {
  // This comment is left unintentionally blank.
  OperationBranchUpdate branch_update = 1;
  // This comment is left unintentionally blank.
  string pre_receive_error = 2;
}

// This comment is left unintentionally blank.
message UserCherryPickRequest {
  // repository is the repository into which the cherry-pick shall be
  // performed.
  Repository repository = 1 [(target_repository)=true];
  // user is the user to perform the cherry-pick as. This is used for
  // authorization checks and as the committer of the computed cherry-pick.
  User user = 2;
  // commit is the commit to cherry-pick onto the given branch.
  GitCommit commit = 3;
  // branch_name is the name of the branch onto which the cherry-pick shall be
  // executed.
  bytes branch_name = 4;
  // message is the message to use for the cherry-picked commit.
  bytes message = 5;
  // start_branch_name is is used in case the branch_name branch does not
  // exist. In that case, it will be created from the start_branch_name.
  bytes start_branch_name = 6;
  // start_repository is used in case the branch_name branch does not exist. In
  // that case, it will be created from start_branch_name in the
  // start_repository.
  Repository start_repository = 7;
  // dry_run will compute the cherry-pick, but not update the target branch.
  bool dry_run = 8;
  // timestamp is the optional timestamp to use for the created cherry-picked
  // commit's committer date. If it's not set, the current time will be used.
  google.protobuf.Timestamp timestamp = 9;
}

// This comment is left unintentionally blank.
message UserCherryPickResponse {
  // CreateTreeError represents an error which happened when computing the
  // cherry-pick.
  enum CreateTreeError {
    // NONE denotes that no error occurred.
    NONE = 0; // protolint:disable:this ENUM_FIELD_NAMES_PREFIX ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH
    // EMPTY denotes that the cherry-pick would've resulted in an empty commit,
    // typically because it has already been applied to the target branch.
    EMPTY = 1; // protolint:disable:this ENUM_FIELD_NAMES_PREFIX
    // CONFLICT denotes that the cherry-pick resulted in a conflict.
    CONFLICT = 2; // protolint:disable:this ENUM_FIELD_NAMES_PREFIX
  }

  // branch_update represents details about the updated branch.
  OperationBranchUpdate branch_update = 1;
  // create_tree_error is deprecated and never set by Gitaly. Instead, Gitaly returns a structured
  // error with the `cherry_pick_conflict` or `changes_already_applied` field set. This field will
  // be removed in v16.0.
  string create_tree_error = 2 [deprecated=true];
  // commit_error is deprecated and never set by Gitaly. Instead, Gitaly returns a structured
  // error with the `target_branch_diverged` field set. This field will be removed in v16.0.
  string commit_error = 3 [deprecated=true];
  // pre_receive_error is deprecated and never set by Gitaly. Instead, Gitaly returns a structured
  // error with the `access_check` field set. This field will be removed in v16.0.
  string pre_receive_error = 4 [deprecated=true];
  // create_tree_error_code is deprecated and never set by Gitaly. There is no replacement. This
  // field will be removed in v16.0.
  CreateTreeError create_tree_error_code = 5 [deprecated=true];
}

// UserCherryPickError is an error returned by the UserCherryPick RPC.
message UserCherryPickError {
  oneof error {
    // CherryPickConflict is returned if there is a conflict when applying the cherry
    // pick.
    MergeConflictError cherry_pick_conflict = 1;
    // TargetBranchDiverged is returned whenever the tip commit of the branch we're
    // about to apply the new commit on is not a direct ancestor of the newly created
    // cherry-picked commit. This may happen either due to a race where the reference
    // is modified while we compute the cherry-picked commit, or alternatively if the
    // commit fetched from the start branch of the remote repository is not an ancestor
    // of of the local target branch.
    NotAncestorError target_branch_diverged = 2;
    // ChangesAlreadyApplied is returned if the result after applying the cherry pick is empty.
    ChangesAlreadyAppliedError changes_already_applied = 3;
    // AccessCheck is returned in case GitLab's `/internal/allowed` endpoint rejected
    // the change.
    AccessCheckError access_check = 4;
  }
}

// This comment is left unintentionally blank.
message UserRevertRequest {
  // repository is the repository in which the revert shall be applied.
  Repository repository = 1 [(target_repository)=true];
  // user is the user to perform the revert as. This is used both for
  // authorization and as author/committer for the revert commit.
  User user = 2;
  // commit iis the commit to revert.
  GitCommit commit = 3;
  // branch_name is the name of the branch onto which the reverted commit shall
  // be committed.
  bytes branch_name = 4;
  // message is the message to use for the revert commit.
  bytes message = 5;
  // start_branch_name is is used in case the branch_name branch does not
  // exist. In that case, it will be created from the start_branch_name.
  bytes start_branch_name = 6;
  // start_repository is used in case the branch_name branch does not exist. In
  // that case, it will be created from start_branch_name in the
  // start_repository.
  Repository start_repository = 7;
  // dry_run  will compute the revert, but not update the target branch.
  bool dry_run = 8;
  // timestamp is the optional timestamp to use for the created cherry-picked
  // commit's committer date. If it's not set, the current time will be used.
  google.protobuf.Timestamp timestamp = 9;
}

// This comment is left unintentionally blank.
message UserRevertResponse {
  // CreateTreeError represents an error which happened when computing the
  // revert.
  enum CreateTreeError {
    // NONE denotes that no error occurred.
    NONE = 0; // protolint:disable:this ENUM_FIELD_NAMES_PREFIX ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH
    // EMPTY denotes that the revert would've resulted in an empty commit,
    // typically because it has already been applied to the target branch.
    EMPTY = 1; // protolint:disable:this ENUM_FIELD_NAMES_PREFIX
    // CONFLICT denotes that the revert resulted in a conflict.
    CONFLICT = 2; // protolint:disable:this ENUM_FIELD_NAMES_PREFIX
  }

  // branch_update represents details about the updated branch.
  OperationBranchUpdate branch_update = 1;
  // create_tree_error contains the error message if creation of the tree
  // failed.
  string create_tree_error = 2;
  // commit_error contains the error message if updating the reference failed.
  string commit_error = 3;
  // pre_receive_error contains the error message if the pre-receive hook
  // failed.
  string pre_receive_error = 4;
  // create_tree_error_code contains the error code if creation of the tree
  // failed.
  CreateTreeError create_tree_error_code = 5;
}

// UserCommitFilesActionHeader contains the details of the action to be performed.
message UserCommitFilesActionHeader {
  // This comment is left unintentionally blank.
  enum ActionType {
    // CREATE creates a new file.
    CREATE = 0; // protolint:disable:this ENUM_FIELD_NAMES_PREFIX ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH
    // CREATE_DIR creates a new directory.
    CREATE_DIR = 1; // protolint:disable:this ENUM_FIELD_NAMES_PREFIX
    // UPDATE updates an existing file.
    UPDATE = 2; // protolint:disable:this ENUM_FIELD_NAMES_PREFIX
    // MOVE moves an existing file to a new path.
    MOVE = 3; // protolint:disable:this ENUM_FIELD_NAMES_PREFIX
    // DELETE deletes an existing file.
    DELETE = 4; // protolint:disable:this ENUM_FIELD_NAMES_PREFIX
    // CHMOD changes the permissions of an existing file.
    CHMOD = 5; // protolint:disable:this ENUM_FIELD_NAMES_PREFIX
  }

  // action is the type of the action taken to build a commit. Not all fields are
  // used for all of the actions.
  ActionType action = 1;
  // file_path refers to the file or directory being modified. The meaning differs for each
  // action:
  //   1. CREATE: path of the file to create
  //   2. CREATE_DIR: path of the directory to create
  //   3. UPDATE: path of the file to update
  //   4. MOVE: the new path of the moved file
  //   5. DELETE: path of the file to delete
  //   6. CHMOD: path of the file to modify permissions for
  bytes file_path = 2;
  // previous_path is used in MOVE action to specify the path of the file to move.
  bytes previous_path = 3;
  // base64_content indicates the content of the file is base64 encoded. The encoding
  // must be the standard base64 encoding defined in RFC 4648. Only used for CREATE and
  // UPDATE actions.
  bool base64_content = 4;
  // execute_filemode determines whether the file is created with execute permissions.
  // The field is only used in CREATE and CHMOD actions.
  bool execute_filemode = 5;
  // Move actions that change the file path, but not its content, should set
  // infer_content to true instead of populating the content field. Ignored for
  // other action types.
  bool infer_content = 6;
}

// UserCommitFilesAction is the request message used to stream in the actions to build a commit.
message UserCommitFilesAction {
  oneof user_commit_files_action_payload {
    // header contains the details of action being performed. Header must be sent before the
    // content if content is used by the action.
    UserCommitFilesActionHeader header = 1;
    // content is the content of the file streamed in one or more messages. Only used with CREATE
    // and UPDATE actions.
    bytes content = 2;
  }
}

// UserCommitFilesRequestHeader is the header of the UserCommitFiles that defines the commit details,
// parent and other information related to the call.
message UserCommitFilesRequestHeader {
  // repository is the target repository where to apply the commit.
  Repository repository = 1 [(target_repository)=true];
  // user is the user peforming the call.
  User user = 2;
  // branch_name is the name of the branch to point to the new commit. If start_sha and start_branch_name
  // are not defined, the commit of branch_name is used as the parent commit.
  bytes branch_name = 3;
  // commit_message is the message to use in the commit.
  bytes commit_message = 4;
  // commit_author_name is the commit author's name. If not provided, the user's name is
  // used instead.
  bytes commit_author_name = 5;
  // commit_author_email is the commit author's email. If not provided, the user's email is
  // used instead.
  bytes commit_author_email = 6;
  // start_branch_name specifies the branch whose commit to use as the parent commit. Takes priority
  // over branch_name. Optional.
  bytes start_branch_name = 7;
  // start_repository specifies which contains the parent commit. If not specified, repository itself
  // is used to look up the parent commit. Optional.
  Repository start_repository = 8;
  // force determines whether to force update the target branch specified by branch_name to
  // point to the new commit.
  bool force = 9;
  // start_sha specifies the SHA of the commit to use as the parent of new commit. Takes priority
  // over start_branch_name and branc_name. Optional.
  string start_sha = 10;
  // timestamp is the optional timestamp to use for the commits as author and
  // committer date. If it's not set, the current time will be used.
  google.protobuf.Timestamp timestamp = 11;
}

// UserCommitFiles is the request of UserCommitFiles.
message UserCommitFilesRequest {
  oneof user_commit_files_request_payload {
    // header defines the details of where to commit, the details and which commit to use as the parent.
    // header must always be sent as the first request of the stream.
    UserCommitFilesRequestHeader header = 1;
    // action contains an action to build a commit. There can be multiple actions per stream.
    UserCommitFilesAction action = 2;
  }
}

// UserCommitFilesResponse is the response object of UserCommitFiles.
message UserCommitFilesResponse {
  // branch_update contains the details of the commit and the branch update.
  OperationBranchUpdate branch_update = 1;
  // index_error is set to the error message when an invalid action was attempted, such as
  // trying to create a file that already existed.
  string index_error = 2;
  // pre_receive_error is set when the pre-receive hook errored.
  string pre_receive_error = 3;
}

// UserCommitFilesError is an error returned by the UserCommitFiles RPC in some specific well
// defined error cases.
message UserCommitFilesError {
  oneof error {
    // AccessCheckError is set if the RPC failed because `/internal/allowed` failed.
    AccessCheckError access_check = 1;
    // IndexError is set to the error message when an operation conflicts with the repository
    // index, such as creating a file that already exists.
    IndexError index_update = 2;
    // CustomHook is set if any custom hook which has running as part of this RPC call has returned
    // a non-zero exit code.
    CustomHookError custom_hook = 3;
  }
}

// This comment is left unintentionally blank.
message UserRebaseConfirmableRequest {
  // Header contains information to compute the rebase and must be sent as
  // first message.
  message Header {
    // repository is the repository in which the rebase will be computed and
    // applied.
    Repository repository = 1 [(target_repository)=true];
    // user is the user to compute the rebase as. It will be used as
    // "committer" of rebased commits.
    User user = 2;
    // RebaseId does nothing anymore.
    string rebase_id = 3 [deprecated=true];
    // branch is the branch onto which the rebase shall happen.
    bytes branch = 4;
    // branch_sha is the expected object ID which branch currently points to.
    // This is used as a safety guard to avoid races when branch has been
    // updated meanwhile.
    string branch_sha = 5;
    // remote_repository is the repository which contains the branch which
    // shall be rebased onto the local branch.
    Repository remote_repository = 6;
    // remote_branch contains the branch name which shall re rebased onto the
    // local branch.
    bytes remote_branch = 7;
    // git_push_options contain options which shall be passed to the git hooks
    // when the local branch gets updated.
    repeated string git_push_options = 8;
    // timestamp is the optional timestamp to use for the rebased commits as
    // committer date. If it's not set, the current time will be used.
    google.protobuf.Timestamp timestamp = 9;
  }

  oneof user_rebase_confirmable_request_payload {
    // For each request stream there must be first a request with a header
    // containing details about the rebase to perform.
    Header header = 1;
    // A second request must be made to confirm that the rebase should
    // be applied to the branch.
    bool apply = 2;
  }
}

// This comment is left unintentionally blank.
message UserRebaseConfirmableResponse {
  oneof user_rebase_confirmable_response_payload {
    // The first response will contain the rebase commit the branch will
    // be updated to. The caller can still abort the rebase.
    string rebase_sha = 1;
    // The second response confirms that the rebase has been applied to
    // the branch.
    bool rebase_applied = 2;
  }
  // pre_receive_error contains an error message if the rebase failed because
  // of an error raised by hooks.
  string pre_receive_error = 3;
  // git_error contains an error message if git operations have failed.
  string git_error = 4;
}

// This comment is left unintentionally blank.
message UserSquashRequest {
  // repository is the repository into which the squashed commit shall be
  // written.
  Repository repository = 1 [(target_repository)=true];
  // user is used for authorization checks.
  User user = 2;
  // start_sha is the object ID of the start commit of the range which shall be
  // squashed. Must be an ancestor of end_sha.
  string start_sha = 5;
  // end_sha is the object ID of the end commit of the range which shall be
  // squashed.
  string end_sha = 6;
  // author will be used as the author of the squashed commit.
  User author = 7;
  // commit_message is the message to be used for the squashed commit.
  bytes commit_message = 8;
  // timestamp is the optional timestamp to use for the squashed commit as
  // committer date. If it's not set, the current time will be used.
  google.protobuf.Timestamp timestamp = 9;

  reserved 3, 4;
  reserved "squash_id";
}

// This comment is left unintentionally blank.
message UserSquashResponse {
  // squash_sha is the object ID of the squashed commit.
  string squash_sha = 1;

  // DEPRECATED: https://gitlab.com/gitlab-org/gitaly/proto/merge_requests/161
  reserved 2;
  reserved "pre_receive_error";

  // GitError is not used anymore. Instead, this RPC always returns a real
  // error with an optional UserRebaseConfirmableError, which may be set on
  // special errors.
  reserved 3;
  reserved "git_error";
}

// This comment is left unintentionally blank.
message UserRebaseConfirmableError {
  oneof error {
    // RebaseConflict is returned in case rebasing commits on top of the start
    // commit fails with a merge conflict and in case merge squashing commits
    // fails with a merge conflict.
    MergeConflictError rebase_conflict = 1;
    // AccessCheckError is returned in case GitLab's `/internal/allowed` endpoint rejected
    // the change.
    AccessCheckError access_check = 2;
  }
}

// UserSquashError is an error that may be returned when the UserSquash RPC
// fails.
message UserSquashError {
  oneof error {
    // ResolveRevision is returned in case resolving either the start or end
    // revision has failed.
    ResolveRevisionError resolve_revision = 1;
    // RebaseConflict is returned in case rebasing commits on top of the start
    // commit fails with a merge conflict.
    MergeConflictError rebase_conflict = 2;
  }
}

// This comment is left unintentionally blank.
message UserApplyPatchRequest {
  // Header contains information about how to apply the patches.
  message Header {
    // repository is the repository to which the patches shall be applied to.
    Repository repository = 1 [(target_repository)=true];
    // user is used for authentication.
    User user = 2;
    // target_branch is the branch onto which the patches shall be applied.
    bytes target_branch = 3;
    // timestamp is the optional timestamp to use for the squashed commit as
    // committer date. If it's not set, the current time will be used.
    google.protobuf.Timestamp timestamp = 4;
  }

  oneof user_apply_patch_request_payload {
    // header must be sent as the first message and contains information about
    // how to apply the patches.
    Header header = 1;
    // patches contains the patch data.
    bytes patches = 2;
  }
}

// This comment is left unintentionally blank.
message UserApplyPatchResponse {
  // branch_update contains information about the updated branch.
  OperationBranchUpdate branch_update = 1;
}

// This comment is left unintentionally blank.
message UserUpdateSubmoduleRequest {
  // repository is the repository in which the submodule shall be updated.
  Repository repository = 1 [(target_repository)=true];
  // user is used both for authorization and as author/committer of the
  // resulting commit.
  User user = 2;
  // commit_sha is the object ID the submodule shall be updated to.
  string commit_sha = 3;
  // branch is the branch which shall be updated. This is the unqualified name
  // of the branch, it must not have a "refs/heads/" prefix.
  bytes branch = 4;
  // submodule is the path to the submodule which shall be updated.
  bytes submodule = 5;
  // commit_message is the message updating the submodule.
  bytes commit_message = 6;
  // timestamp is the optional timestamp to use for the commit updating the
  // submodule as committer date. If it's not set, the current time will be
  // used.
  google.protobuf.Timestamp timestamp = 7;
}

// This comment is left unintentionally blank.
message UserUpdateSubmoduleResponse {
  // branch_update contains information about the updated branch.
  OperationBranchUpdate branch_update = 1;
  // pre_receive_error contains an error message if the pre-receive hook
  // rejects the update.
  string pre_receive_error = 2;
  // DEPRECATED: https://gitlab.com/gitlab-org/gitaly/proto/merge_requests/237
  reserved 3;
  reserved "create_tree_error";
  // commit_error contains an error message if committing the update fails.
  string commit_error = 4;
}
