**Description**

Currently `BaseOperator` and `XComArgs` implements the same logic of `__lshift__`, `__rshift__` and others "chain" operations (`>>`, `<<`). It seems resonable to abstract this logic into `TaskMixin` to introduce some DRYness especially because the new concept of `TaskGroup` will also implement the same methods.

**Use case / motivation**

Limit duplication of logic.

**Related Issues**

https://github.com/apache/airflow/pull/10827#issuecomment-691927501
#10153 

airflow/models/baseoperator.py
start_date: Optional[datetime] = None,
              end_date: Optional[datetime] = None,
              upstream: bool = False,
              downstream: bool = False,
              session: Session = None):
        """
        Clears the state of task instances associated with the task, following
        the parameters specified.
        """
        qry = session.query(TaskInstance).filter(TaskInstance.dag_id == self.dag_id)
        if start_date:
            qry = qry.filter(TaskInstance.execution_date >= start_date)
        if end_date:
            qry = qry.filter(TaskInstance.execution_date <= end_date)
        tasks = [self.task_id]
        if upstream:
            tasks += [
                t.task_id for t in self.get_flat_relatives(upstream=True)]
        if downstream:
            tasks += [
                t.task_id for t in self.get_flat_relatives(upstream=False)]
        qry = qry.filter(TaskInstance.task_id.in_(tasks))
        results = qry.all()
        count = len(results)
        clear_task_instances(results, session, dag=self.dag)
        session.commit()
        return count
    @provide_session
    def get_task_instances(self, start_date: Optional[datetime] = None,