Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to replace a git lfs file #2215

Open
bauergeorg opened this issue Apr 8, 2022 · 0 comments
Open

How to replace a git lfs file #2215

bauergeorg opened this issue Apr 8, 2022 · 0 comments

Comments

@bauergeorg
Copy link

Hi,

I have a function to replace files. Using git tree and git blob. Now we want to use git lfs server. But I don't know how to communicate with git lfs server.
Can somebody help me?

def replace_file(self, repo, repo_file_name, source_file_path, ref_name=None, target_path=''):
  ''' Replace a file in a git repository. 
  
  Parameter:
      repo: Repository with type 'Github.get_repo()' or as str.
      repo_file_name (old): e.g. test-123-20211021.txt
      source_file_path (new): e.g. C:\\repository_git\\action-package-deploy\\download\\test-123-20211022.txt
      ref_name: Branch name like 'main' or 'develop'. If None = default branch
      target_path: e.g. deploy, if '' (default) main folder of repository
  '''
  
  # input management
  if isinstance(repo, str):
      repo = self.get_repo(repo)
  
  # take handle ref
  local_ref_name, local_ref_type = self._handle_ref(repo, ref_name)
  #print("::DEBUG:: ref_name = {}".format(ref_name))               # DEBUG INFO!
  #print("::DEBUG:: local_ref_name = {}".format(local_ref_name))   # DEBUG INFO!
  #print("::DEBUG:: local_ref_type = {}".format(local_ref_type))   # DEBUG INFO!
  
  print("Replace file '{}' with '{}' at repository '{}' on branch '{}'.".format(repo_file_name, os.path.basename(source_file_path), repo.name, local_ref_name))
  
  # read for help: https://github.com/PyGithub/PyGithub/issues/1628 and
  # https://stackoverflow.com/questions/55786299/delete-multiple-files-from-github-api and
  # https://stackoverflow.com/questions/23637961/how-do-i-mark-a-file-as-deleted-in-a-tree-using-the-github-api
  # in case of a binary file a workaround is done:
  # >>>>>>> https://github.com/PyGithub/PyGithub/issues/863
  
  # set old and new path
  if target_path == '':
      new_path = os.path.basename(source_file_path)
      old_path = repo_file_name
  else:
      new_path = target_path + '/' + os.path.basename(source_file_path)
      old_path = target_path + '/' + repo_file_name
  
  # Step 1: get sha of branch in repo
  # API:
  # >>> GET /repos/:owner/:REPO/branches/master
  #
  # >>> $PARENT_SHA = {commit.sha}
  repo_sha = self.get_git_ref_sha(repo, local_ref_name)
          
  # Step 2: create a blob with file content and get target sha
  # API:
  # >>> $TARGET_SHA = {commit.sha}
  print("Read file '{}' ...".format(source_file_path))
  data = base64.b64encode(open(source_file_path, 'rb').read())
  
  # check file size without using GIT LFS
  if os.path.getsize(source_file_path) > 100000000:
      raise Exception("File size limit reached! File '{}' is larger than 100MB.".format(source_file_path))
  
  print('Create blob with content ...')
  blob = repo.create_git_blob(content=data.decode("utf-8"), encoding='base64')
  blob_sha = blob.sha
  # post_parameters = {'content': bytes(data), 'encoding': 'utf-8',}
  # headers, data = repo._requester.requestJson("POST", f"{repo.url}/git/blobs", input=post_parameters)
  
  # Step 3: create a git tree to update the reference
  # API:
  # >>> POST /repos/:owner/:REPO/git/trees
  # >>> {
  # >>>   "base_tree": $BASE_SHA,
  # >>>   "tree": [
  # >>>       {
  # >>>           "path": "path/to/file",
  # >>>           "mode": "100644", 
  # >>>           "type": "commit",
  # >>>           "sha": $TARGET_SHA
  # >>>       }
  # >>>   ]
  # >>> }
  #
  # >>> $TREE_SHA = {sha}
  base_tree = repo.get_git_tree(repo_sha, recursive = True)
  # add new element
  elem1 = InputGitTreeElement(path=new_path, mode='100644', type='blob', sha=blob_sha)
  # delete old element
  elem2 = InputGitTreeElement(path=old_path, mode='100644', type='blob', sha=None)
  tree = repo.create_git_tree([elem1, elem2], base_tree)
  
  # Step 4: Commit the tree
  # API:
  # >>> POST /repos/:owner/:REPO/git/commits
  # >>> {
  # >>>   "message": "<your commit message>",
  # >>>   "tree": $TREE_SHA,
  # >>>   "parents": [$PARENT_SHA]
  # >>> }
  msg = "Update file: '{}' -> '{}'.".format(repo_file_name, os.path.basename(source_file_path))
  parents = [repo.get_git_commit(repo_sha)]
  print("Create commit with messsage '{}'".format(msg))
  commit = repo.create_git_commit(msg, tree, parents, author = self.author, committer = self.author)
  
  # Step 5: Update branch to point to your new commit
  # API:
  # >>> PATCH /repos/:owner/:REPO/git/refs/heads/master
  # >>> {
  # >>>   "sha": $COMMIT_SHA
  # >>> }
  if local_ref_type in ['branch', 'tag-branch', 'default']:
      reference = repo.get_git_ref('heads/'+local_ref_name)
  else:
      reference = repo.get_git_ref('tags/'+local_ref_name)      
  reference.edit(commit.sha, force=True)
  
  # set return value (or overwrite vaue of first changed repo)                       
  return commit.sha
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant