11

Using the GitHub API, I can create a tree containing all the modified files for a commit, specify a base_tree that will be updated with this tree of changes and then commit it.

But, as the documentation says, the new tree can contain only paths for files with the modes

100644 for file (blob), 100755 for executable (blob), 040000 for subdirectory (tree), 160000 for submodule (commit), or 120000 for a blob that specifies the path of a symlink.

It doesn't say what should I do if I want to mark some path as deleted, as with git rm <path>.

fiatjaf
  • 11,479
  • 5
  • 56
  • 72

3 Answers3

9

Currently, the only way to remove an entry from the tree (either a blob or another tree) is to construct a new tree and not list that entry. After you have that tree, construct a new commit that links to this new tree, and don't forget to bump the ref to point to this new commit.

Ivan Zuzak
  • 18,068
  • 3
  • 69
  • 61
  • 2
    If you run into any problems, feel free to let us know -- support@github.com. – Ivan Zuzak May 17 '14 at 18:03
  • Thanks for the answer. I can do that procedure you're talking about, then (tree-commit-ref). – fiatjaf May 18 '14 at 22:55
  • Surprised that I'm the first upvoter here. Thanks for the response. This problem really should be addressed on the API page! – Levi Botelho Jul 17 '14 at 13:06
  • 3
    @IvanZuzak What if I'd like to only send the diff by providing a `base_tree` instead of sending the entire tree? Shouldn't there be a way to indicate that a file was deleted? – Marco Jakob Oct 06 '14 at 19:49
  • @MarcoJakob Not sure I understand. Mind sending an email to support@github.com and providing more details about your use case? Sharing as many details as possible helps us provide advice. Thanks – Ivan Zuzak Oct 06 '14 at 20:24
  • I have sent as well, but no response from you. – Nusrat Nuriyev Feb 25 '19 at 09:30
  • 1
    From what I gather we have to send the whole recursive tree otherwise nested directories will be removed. This seems quite unwieldy for simple needs (update/delete files in a directory). Would be a lot neater if we could just indicate the path should be deleted (e.g. pass null to sha) – Dominic Feb 26 '19 at 19:55
  • @Dominic passing a null to sha is supported now. See my answer for the details. – gijswijs Apr 15 '21 at 03:44
7

@ivan-zuzak 's answer is obsolete now that the GitHub API supports deleting files by passing null sha's.

To delete a file you would create a tree in Javascript with octokit like so:

await octokit.request('POST /repos/{owner}/{repo}/git/trees', {
  owner: 'octocat',
  repo: 'hello-world',
  tree: [
    {
      path: 'path/to/file-that-will-be-deleted.py',
      mode: '100644',
      type: 'blob',
      sha: null,
    }
  ],
  base_tree: 'sha'
})

The base_tree should contain the SHA1 of an existing Git tree object you want to delete the file from.

After that everything Ivan said still holds true, so you should construct a new commit that links to this new tree, and bump the ref to point to this new commit.

gijswijs
  • 1,958
  • 19
  • 24
  • Trying to loop through all items in the tree and set `sha: null` to all those I need to remove. But Github API returns "Unprocessable Entity". If I remove these nulls from the tree - everything works but nothing happens actually, I think, because my new tree completely matches the old tree (though I removed unneded items instead of setting sha to null, it doesn't seem to work in terms of removing those items from the repo) – Andrew Jun 17 '22 at 09:55
  • UPD: The reason of that error was marking folders with `sha: null`. But I tried with a single file. Didn't work, thought I didn't get any error. The file is still there – Andrew Jun 17 '22 at 10:02
  • UPD2: I figured this out. I should specify base_tree which you actually mentioned :) worked well. thank you! – Andrew Jun 20 '22 at 18:57
  • Bear in mind that the mode should be `100644` rather than `100664` – Alfredo Gallegos Oct 19 '22 at 20:06
  • @AlfredoGallegos You are right, but Git did allow 100664 for rw-rw-r--, but that turned out to be a mistake. Git still supports 100664 since there may be some Git repositories that still have such entries, but unless you find a really old repository, you won't find any 100664s. source: https://stackoverflow.com/questions/54139971/what-does-a-tree-mean-in-git – gijswijs Oct 21 '22 at 06:28
-2

The most clean way to do this I've found is to create a new branch, create, delete and update files in it using the contents API, then create a merge commit with the master branch and finally update the master branch to this last commit (in the end you should also delete the temporary side-branch).

fiatjaf
  • 11,479
  • 5
  • 56
  • 72