I have a small application that manages several git repositories similar to Github/Gitorious. Github allows for inline file editing, and I'd like to know if anyone has any idea on how they manage this.
My initial thought was that it would do a complete clone of the repository, use your submission to replace the file, commit, and push, but this seems like an very expensive operation with large repositories like the linux kernel.
Any ideas on a more efficient way to add and edit files to a bare repository?
You can use plumbing commands.
Get your current HEAD, get the tree from there then your blobs.
Once you have the blob you can put the content in a textbox. When it's finished you just have to hash the new blob, create the new tree, the new commit and tadaam. It's "pushed".
PS: Remember you're in a bare repository, so check that every command you use don't need the index nor the working directory.
As it has been asked here is a step by step example.
First we get the current file content:
> git cat-file -p HEAD:var/test/text.txt
test
We do our little modification on that content and now have a new content ready to be pushed. To save that content we're going to hash it:
> git hash-object -t blob -w var/test/text.txt
9764d221e6b50063b83c0268544c5d5b745ec9c5
This will save it, and return a sha-1 of that object (blob), the very next step consist in creating a new folder test
which will contain our text.txt
file. But first let's look at what does the current test
folder look like:
> git ls-tree HEAD:var/test
100644 blob 9daeafb9864cf43055ae93beb0afd6c7d144bfa4 text.txt
So what we want to do here, is replace the previous SHA-1 (9daeafb...
) with the new one (9764d22...
) and generate a new tree based on that (pay attention to the \t
).
> echo -e "100644 blob 9764d221e6b50063b83c0268544c5d5b745ec9c5\ttext.txt" | git mktree
b7788f9e8e9a24be31188167a6a0bc1de9e41d24
Great, so now we have the new file text.txt
and the parent folder test
, we now need var
.
> git ls-tree HEAD:var
040000 tree 9bfb857f532d280ecd7704beb40a2ea4ba332f5a test
> echo -e "040000 tree b7788f9e8e9a24be31188167a6a0bc1de9e41d24\ttest" | git mktree
536f33626a47138499fade7df6d02327f75d80be
and now we need the parent of var
(which is the root of our repository):
> git ls-tree HEAD
040000 tree 31a6ee5e7d14a0569721632a05234185a109d6bd var
> echo -e "040000 tree 536f33626a47138499fade7df6d02327f75d80be\tvar" | git mktree
7db3d6bc14cce98ff89ccc285b9d17965f5ca92b
And it's done, our tree is ready. The only thing missing is the actual commit:
> git commit-tree -p HEAD -m "commit message" 7db3d6bc14cce98ff89ccc285b9d17965f5ca92b
4aa2de2cf9e3e4f5470bcd1ee1e83ef6e4025eaf
But it isn't ready yet, now we want the commit to be the HEAD, so the very last step is:
> git update-ref HEAD 4aa2de2cf9e3e4f5470bcd1ee1e83ef6e4025eaf
And now we're done.
Resources: