4 ms·
Ask HN: In Git, how do you “insert” a blob at an arbitrary position in a tree?
Note: let's just say that the normal way of doing things, I.e. through git porcelain, are not an option.
FWIW, yes, I've read the git internals documentation, and they were helpful but very brief. They explained blobs, trees, and working directories, but I think for me to figure out on my own how to do what I want to do I would have to read some of the code for how git porcelain is implemented, which is fine.
My question:
Let's say I have a file that represents an array, where each element of the array is separated by a new line character. How would I append a new line to the end of that file, without actually editing the file directly? Just by creating a new blob, and associating that blob with a tree?
Then, imagine if the file began and ended with square brackets, so now to append to this "array" I need to insert at one line minus the end of the file (you can assume the brackets have a new line after/before, respectively)
The bonus round is taking the same logic from above, but applying it to just arbitrary lines within a file. This isn't so necessary for what I'm working on, but git obviously has a way of doing this, so I'd like to understand the general solution.
For context why I even want to do this:
I'd like to update a file that's in a GH repo, without actually pulling the file to do it. GH has a low level API that's basically an HTTP interface exposing many low-level GitHub operations. So, I'd like to just say "add this line, to this file", without having to clone the repo or do a bunch of back and fourth over the network.
- saurik 5y agoAFAIK (but I don't work with the network protocol, only the repository layout; that said, I do have a passing understanding of the network protocol) you fundamentally have to pull the whole file, and git doesn't "obviously ha[ve] a way of doing this". That said, at the end of your question you stop talking about git and start talking about GitHub and APIs offered by them, which is of course entirely unrelated to working with git itself and they could provide absolutely any random complex functionality.
- asimpletune 5y agoHey, thanks for following up on this. I figured out more or less in the end how to do what I was looking for, but I was also confused about one detail regarding git internals. I'll start by briefly clarifying the relationship between git internals and the GitHub API I was mentioning above. GitHub has an api the call "Git Database API" https://docs.github.com/en/rest/guides/getting-started-with-the-git-database-api https://docs.github.com/en/rest/guides/getting-started-with-... which: > gives you access to read and write raw Git objects to your Git database on GitHub and to list and update your references (branch heads and tags). These "raw" git objects correspond to the fundamental objects used in git https://git-scm.com/book/en/v2/Git-Internals-Git-Objects https://git-scm.com/book/en/v2/Git-Internals-Git-Objects which are blobs, trees, commits, references, and tags. So you can use this API to manipulate those things, much as you would using git plumbing commands. However, just knowing that doesn't fix that my question was confused about one thing, which was the relationship between blobs and trees and how they are used in relation to files and directories. I thought somehow that trees could be used to structure a file, as well as a directory, since directories in UNIX are files as well. This isn't the case. Putting that aside for a moment, doing this by pulling the file, as you mentioned, is easy. If you already have a reference to the branch and commit to work from (and if you don't you can just get those with the API), you just use the database API I mentioned to grab the tree, and then you can grab the blob you want. After that you can put everything back (I.e. create a new blob, post a new tree replacing the old one, create a commit, and then update the branch to point to the new commit). However, if you're never going to edit and only append data at the end of the file, you can do this without even pulling the old file! To keep it short you basically overwrite the blob with whatever new data you want to add and then handle the merge as a union merge. Union merges (I.e. "select both ours and theirs, but ours first") are supported in git and GitLab but not GitHub yet. This works for "appending" to files, even if they have brackets, but not putting the new blob into arbitrary locations with the old one. I left a lot of details out but hopefully this helps someone who may have similar needs as I did in this situation. This is very useful if you have some file-based data storage that you're guaranteed will be written to in an append-only fashion, and then if some reason those files are under version control.