docs: def diff_objects(self, latest_commit_sha):
          """
                  Push all changes to origin, based on objects, not on commits.
                  Important: Call this push after every new commit, or we lose commits.
                  """
          base = ['git', '--bare', '--git-dir', self.git_path]
  
          object_shas = []
          summary = {'commits': [], 'trees': [], 'files': []}
  
          def read_parents_and_tree_from(commit):
              if commit in self.synced_object_shas or commit in object_shas:
                  # this commit has already been synced or read
                  return None, None
  
              self.synced_object_shas[commit] = True
              summary['commits'].append(commit)
              object_shas.append(commit)
  
              object_content = subprocess.check_output(base + ['cat-file', '-p', commit]).decode('utf-8').strip()
              parents = []
              tree = ''
              for line in object_content.splitlines():
                  if line.startswith('tree '):
                      tree = line[len('tree '):]
                  if line.startswith('parent '):
                      parents.append(line[len('parent '):])
  
              return parents, tree
  
          def collect_files_from_tree(tree):
              if tree in self.synced_object_shas or tree in object_shas:
                  # we have exactly this tree already synced or read, meaning all its objects as well
                  return
  
              self.synced_object_shas[tree] = True
              summary['trees'].append(tree)
              object_shas.append(tree)
  
              object_content = subprocess.check_output(base + ['ls-tree', '-r', '-t', tree]).decode('utf-8').strip()
  
              for line in object_content.splitlines():
                  exploded = line.split(' ')
  
                  if len(exploded) < 3:
                      sys.stderr.write("Error: Wrong line format of ls-tree for %s: %s\n" % (tree, line,))
                      sys.exit(1)
  
                  object_to_add = str(exploded[2][:40])
                  path = str(exploded[2][41:])
  
                  if object_to_add in self.synced_object_shas or object_to_add in object_shas:
                      # have it already in the list or already synced
                      continue
  
                  object_shas.append(object_to_add)
                  self.synced_object_shas[object_to_add] = True
                  summary['files'].append([object_to_add, path])
  
          commits_to_check = [latest_commit_sha]
  
          while len(commits_to_check):
              sha = commits_to_check.pop(0)
              parents, tree = read_parents_and_tree_from(sha)
  
              if parents:
                  for parent in parents:
                      if parent not in commits_to_check:
                          commits_to_check.append(parent)
  
              if tree:
                  collect_files_from_tree(tree)
  
          is_debug2() and self.logger.debug("shas_to_check %d: %s " % (len(object_shas), str(object_shas),))
  
          if not object_shas:
              return [], summary
  
          try:
              is_debug2() and self.logger.debug("Do git-cat-file-check.sh")
  
              ssh_stream = create_ssh_stream(read_home_config(), exit_on_failure=False)
              channel = ssh_stream.get_transport().open_session()
              channel.exec_command('git-cat-file-check.sh "%s"' % (self.model_name + '.git',))
              channel.sendall('\n'.join(object_shas))
              channel.shutdown_write()
  
              def readall(c):
                  content = b''
                  while True:
                      try:
                          chunk = c.recv(1024)
                          if chunk == b'':
                              break
                          content += chunk
                      except (KeyboardInterrupt, SystemExit):
                          return
  
                  return content
  
              missing_objects = readall(channel).decode('utf-8').splitlines()
              channel.close()
              ssh_stream.close()
  
              # make sure we have in summary only SHAs we actually will sync
              for stype in six.iterkeys(summary):
                  ids = summary[stype][:]
                  for sha in ids:
                      if stype == 'files':
                          if sha[0] not in missing_objects:
                              summary[stype].remove(sha)
                      else:
                          if sha not in missing_objects:
                              summary[stype].remove(sha)
  
              return missing_objects, summary
          except (KeyboardInterrupt, SystemExit):
              raise
          except Exception as e:
              self.logger.error("Failed to generate diff_objects: %s" % (str(e),))
              for sha in object_shas:
                  if sha in self.synced_object_shas:
                      del self.synced_object_shas[sha]
              return None, None