{"thread":{"id":"45648","subject":"Modifying a bare repo directly","startedAt":"2017-04-10T10:09:52Z","lastAt":"2017-04-12T00:48:25Z","messageCount":6,"participants":["Julian Goacher","Ævar Arnfjörð Bjarmason","Jeff King","Eric Wong"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"316465","messageId":"CAG_DJYk3D=sPm6rhGRD_wF4dnJqSU_M+c=NWP4Q5ExBap_-kPw@mail.gmail.com","threadId":"45648","inReplyTo":null,"subject":"Modifying a bare repo directly","fromName":"Julian Goacher","fromEmail":"julian.goacher@gmail.com","sentAt":"2017-04-10T10:09:45Z","receivedAt":"2017-04-10T10:09:52Z","isPatch":false,"sender":{"key":"julian.goacher@gmail.com","avatar":null},"body":"Hi -\n\nIs it possible to modify a bare repo directly? e.g. is it possible to\ninsert a file into a bare repo without first cloning a non-bare copy?\nI'm thinking along the lines of a command or sequence of commands that\nmodifies the file index and then copies the file blob into /objects,\nbut in a situation where the new file exists separately from the\ntarget repo.\n\nThanks -\n\nj/\n"},{"id":"316470","messageId":"CACBZZX7aAHdrvH3wucoQYvZ26mNDYvo3ue4XR0TFF7BxBSWaxw@mail.gmail.com","threadId":"45648","inReplyTo":"CAG_DJYk3D=sPm6rhGRD_wF4dnJqSU_M+c=NWP4Q5ExBap_-kPw@mail.gmail.com","subject":"Re: Modifying a bare repo directly","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-04-10T10:33:18Z","receivedAt":"2017-04-10T10:33:45Z","isPatch":false,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Mon, Apr 10, 2017 at 12:09 PM, Julian Goacher\n<julian.goacher@gmail.com> wrote:\n> Hi -\n>\n> Is it possible to modify a bare repo directly? e.g. is it possible to\n> insert a file into a bare repo without first cloning a non-bare copy?\n> I'm thinking along the lines of a command or sequence of commands that\n> modifies the file index and then copies the file blob into /objects,\n> but in a situation where the new file exists separately from the\n> target repo.\n\nYes you use the plumbing commands (see \"man git\", search for plumbing), e.g.:\n\ngit init --bare mybare.git\ncd mybare.git\necho hello | git hash-object --stdin -w >obj\n$ printf \"100644 blob $(cat obj)\\thello.txt\\n\" | git mktree\naaa96ced2d9a1c8e72c56b253a0e2fe78393feb7\n$ git commit-tree -m \"1st commit\" aaa96ced2d9a1c8e72c56b253a0e2fe78393feb7\n318448647ab7a2b1f78c87cb8a05ac0cf172fbb8\n$ git show 318448647ab7a2b1f78c87cb8a05ac0cf172fbb8\ncommit 3184486\nAuthor: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\nDate:   Mon Apr 10 12:29:22 2017 +0200\n\n    1st commit\n\ndiff --git a/hello.txt b/hello.txt\nnew file mode 100644\nindex 0000000..ce01362\n--- /dev/null\n+++ b/hello.txt\n@@ -0,0 +1 @@\n+hello\n$ git update-ref refs/heads/master 318448647ab7a2b1f78c87cb8a05ac0cf172fbb8\n\nNow when you clone this repo you'll have that one commit.\n"},{"id":"316491","messageId":"20170410140702.bndmudfeofchc2ii@sigill.intra.peff.net","threadId":"45648","inReplyTo":"CACBZZX7aAHdrvH3wucoQYvZ26mNDYvo3ue4XR0TFF7BxBSWaxw@mail.gmail.com","subject":"Re: Modifying a bare repo directly","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-04-10T14:07:02Z","receivedAt":"2017-04-10T14:07:30Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Apr 10, 2017 at 12:33:18PM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> On Mon, Apr 10, 2017 at 12:09 PM, Julian Goacher\n> <julian.goacher@gmail.com> wrote:\n> > Hi -\n> >\n> > Is it possible to modify a bare repo directly? e.g. is it possible to\n> > insert a file into a bare repo without first cloning a non-bare copy?\n> > I'm thinking along the lines of a command or sequence of commands that\n> > modifies the file index and then copies the file blob into /objects,\n> > but in a situation where the new file exists separately from the\n> > target repo.\n> \n> Yes you use the plumbing commands (see \"man git\", search for plumbing), e.g.:\n> \n> git init --bare mybare.git\n> cd mybare.git\n> echo hello | git hash-object --stdin -w >obj\n> $ printf \"100644 blob $(cat obj)\\thello.txt\\n\" | git mktree\n> aaa96ced2d9a1c8e72c56b253a0e2fe78393feb7\n> $ git commit-tree -m \"1st commit\" aaa96ced2d9a1c8e72c56b253a0e2fe78393feb7\n> 318448647ab7a2b1f78c87cb8a05ac0cf172fbb8\n\nThis is definitely the right track, but if you're going to be modifying\nan existing tree (and not just creating a new one), I'd suggest using\nusing a temporary index:\n\n  export GIT_INDEX_FILE=my-index\n  parent=$(git rev-parse HEAD)\n  git read-tree $parent\n  obj=$(echo hello | git hash-object --stdin -w)\n  git update-index --add --cacheinfo 100644,$obj,hello.txt\n  [...and other index changes if you want...]\n  tree=$(git write-tree)\n  commit=$(git commit-tree -p $parent $tree)\n  git update-ref HEAD $commit $parent\n  rm -f $GIT_INDEX_FILE\n\nThat's a bit simpler because it handles modifications to existing trees\n(rather than overwriting), and it handles changes to nested subtrees (to\nedit \"deep/subdir/hello.txt\" using mktree, you have to issue three\nseparate mktree commands).\n\n-Peff\n"},{"id":"316505","messageId":"20170410182209.GA18358@dcvr","threadId":"45648","inReplyTo":"CAG_DJYk3D=sPm6rhGRD_wF4dnJqSU_M+c=NWP4Q5ExBap_-kPw@mail.gmail.com","subject":"Re: Modifying a bare repo directly","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2017-04-10T18:22:09Z","receivedAt":"2017-04-10T18:22:17Z","isPatch":false,"sender":{"key":"e@80x24.org","avatar":null},"body":"Julian Goacher <julian.goacher@gmail.com> wrote:\n> Is it possible to modify a bare repo directly? e.g. is it possible to\n> insert a file into a bare repo without first cloning a non-bare copy?\n> I'm thinking along the lines of a command or sequence of commands that\n> modifies the file index and then copies the file blob into /objects,\n> but in a situation where the new file exists separately from the\n> target repo.\n\nYes.  You can use the commands Ævar and Jeff talked about as\n(those are probably the easiest).  \"git fast-import\" is also\ngreat to avoid using an index entirely; it can be much faster\nfor mass modifications.\n"},{"id":"316650","messageId":"CAG_DJY=3Q1hcGnD72hwhdHxVReD4g7JZou=cm32_WECoJf+5nA@mail.gmail.com","threadId":"45648","inReplyTo":"20170410182209.GA18358@dcvr","subject":"Re: Modifying a bare repo directly","fromName":"Julian Goacher","fromEmail":"julian.goacher@gmail.com","sentAt":"2017-04-11T21:35:17Z","receivedAt":"2017-04-11T21:35:23Z","isPatch":false,"sender":{"key":"julian.goacher@gmail.com","avatar":null},"body":"Thanks for the replies; is there anything that needs to be known about\nconcurrent updates on a repo when using plumbing commands?\n\nOn 10 April 2017 at 19:22, Eric Wong <e@80x24.org> wrote:\n> Julian Goacher <julian.goacher@gmail.com> wrote:\n>> Is it possible to modify a bare repo directly? e.g. is it possible to\n>> insert a file into a bare repo without first cloning a non-bare copy?\n>> I'm thinking along the lines of a command or sequence of commands that\n>> modifies the file index and then copies the file blob into /objects,\n>> but in a situation where the new file exists separately from the\n>> target repo.\n>\n> Yes.  You can use the commands Ævar and Jeff talked about as\n> (those are probably the easiest).  \"git fast-import\" is also\n> great to avoid using an index entirely; it can be much faster\n> for mass modifications.\n"},{"id":"316663","messageId":"20170412004818.xcguj3ndyfixnthy@sigill.intra.peff.net","threadId":"45648","inReplyTo":"CAG_DJY=3Q1hcGnD72hwhdHxVReD4g7JZou=cm32_WECoJf+5nA@mail.gmail.com","subject":"Re: Modifying a bare repo directly","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-04-12T00:48:18Z","receivedAt":"2017-04-12T00:48:25Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Apr 11, 2017 at 10:35:17PM +0100, Julian Goacher wrote:\n\n> Thanks for the replies; is there anything that needs to be known about\n> concurrent updates on a repo when using plumbing commands?\n\nConcurrent writes to the object database are always safe (so\nhash-object, write-tree, commit-tree are fine). Updates to the index\nwill take a lock on the index; use a unique GIT_INDEX_FILE if you want\nmultiple independent updates to avoid conflicting with each other.\n\nSo all of that should be able to proceed independently. The place where\nyou might see conflicts is when you actually update the branch. The\nlocking there uses a \"lease\" system:\n\n  1. At the start of the operation, you note that the branch is at some\n     sha1 X.\n\n  2. When you're ready to write, you feed update-ref the refname, the\n     new sha1, and that original sha1.\n\n  3. Update-ref takes a lock, checks that we are still at the old sha1,\n     and then atomically writes the new sha1.\n\nSo if you have updates to multiple independent branches, they'll never\nconflict. If you have multiple updates to the same branch, they may\nrace, but you'll never \"lose\" an update; each one will either succeed or\nfail. Just make sure you pass the \"old\" sha1 to update-ref (the example\nI posted did so).\n\n-Peff\n"}]}