{"thread":{"id":"55001","subject":"How to commit without an index file?","startedAt":"2021-01-18T17:00:16Z","lastAt":"2021-01-18T18:02:59Z","messageCount":2,"participants":["Utku","brian m. carlson"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"414601","messageId":"A31FEB7F-0A81-4500-9B1D-F65A5F8823AA@gmail.com","threadId":"55001","inReplyTo":null,"subject":"How to commit without an index file?","fromName":"Utku","fromEmail":"ugultopu@gmail.com","sentAt":"2021-01-18T16:58:56Z","receivedAt":"2021-01-18T17:00:16Z","isPatch":false,"sender":{"key":"ugultopu@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9937444?v=4"},"body":"In my program, I have the file paths, permissions and Git object IDs of\neverything that I want to appear in the next commit. Hence, I want to\ncreate a commit without creating an index file.\n\nEssentially it's like to combining `--cacheinfo` from `update-index`\nwith `commit` like:\n\n\tgit commit \\\n\t\t-m \"Commit message\" \\\n\t\t--branch my-branch \\\n\t\t--cacheinfo \"100644,0123456789abcdef0123456789abcdef01234567,path/to/first/file” \\\n\t\t--cacheinfo \"100755,123456789abcdef0123456789abcdef012345670,path/to/second/file” \\\n\t\t--cacheinfo \"100644,23456789abcdef0123456789abcdef0123456701,path/to/third/file\"\n\nIn this example, the command would not read the index file, but would\nget the information necessary to create the commit tree as arguments (or\nfrom STDIN). The command would handle recursively creating trees for the\nintermediate directories. The object ID for the final tree would be used\nfor the `tree` field of the commit.\n\nI tried tricks for simulating standard streams as an index file to Git,\nbut they didn't work out:\n\n\t$ GIT_INDEX_FILE=/dev/stdout git read-tree HEAD\n\tfatal: Unable to create '/dev/stdout.lock': No such file or directory\n\nThe best I could come up with is creating a no checkout worktree for\n`my-branch` and using a FIFO for the index file, instead of a\nconventional file. The shell script equivalent of it would be as follows\n(I would be happy if you can point out any errors in this script as\nwell):\n\n\tset -e\n\t\n\tgit_dir=$(git rev-parse --git-dir)\n\tworktree_name=my-program\n\tworktree_location=$git_dir/$worktree_name\n\t\n\t# Ran only once\n\tfunction init_worktree {\n\t\tbranch_name=my-branch\n\t\tworktree_gitdir=$git_dir/worktrees/$worktree_name\n\t\t\n\t\tgit worktree add \"$worktree_location\" \"$branch_name\" --no-checkout\n\t\trm -f \"$worktree_gitdir/index”\n\t\tmkfifo \"$worktree_gitdir/index”\n\t\t\n\t\techo \"Initialized worktree at $worktree_location”\n\t}\n\n\t# Ran on every commit\n\tfunction commit_worktree {\n\t\tcd \"$worktree_location”\n\t\tgit read-tree —empty\n\t\tgit update-index --add \\\n\t\t--cacheinfo \"100644,0123456789abcdef0123456789abcdef01234567,path/to/first/file” \\\n\t\t--cacheinfo \"100755,123456789abcdef0123456789abcdef012345670,path/to/second/file” \\\n\t\t--cacheinfo \"100644,23456789abcdef0123456789abcdef0123456701,path/to/third/file”\n\t\t# etc. Will be received as arguments or from STDIN.\n\t\tgit commit -m \"Commit message”\n\t}\n\nSo I guess this is the best it gets? If I wanna make it better, I guess\nI will need to use libgit2?\n\nThank you"},{"id":"414602","messageId":"YAXMmtIXB9gXUi9C@camp.crustytoothpaste.net","threadId":"55001","inReplyTo":"A31FEB7F-0A81-4500-9B1D-F65A5F8823AA@gmail.com","subject":"Re: How to commit without an index file?","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2021-01-18T17:59:54Z","receivedAt":"2021-01-18T18:02:59Z","isPatch":false,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On 2021-01-18 at 16:58:56, Utku wrote:\n> In my program, I have the file paths, permissions and Git object IDs of\n> everything that I want to appear in the next commit. Hence, I want to\n> create a commit without creating an index file.\n> \n> Essentially it's like to combining `--cacheinfo` from `update-index`\n> with `commit` like:\n> \n> \tgit commit \\\n> \t\t-m \"Commit message\" \\\n> \t\t--branch my-branch \\\n> \t\t--cacheinfo \"100644,0123456789abcdef0123456789abcdef01234567,path/to/first/file” \\\n> \t\t--cacheinfo \"100755,123456789abcdef0123456789abcdef012345670,path/to/second/file” \\\n> \t\t--cacheinfo \"100644,23456789abcdef0123456789abcdef0123456701,path/to/third/file\"\n> \n> In this example, the command would not read the index file, but would\n> get the information necessary to create the commit tree as arguments (or\n> from STDIN). The command would handle recursively creating trees for the\n> intermediate directories. The object ID for the final tree would be used\n> for the `tree` field of the commit.\n\nYou could use git mktree, git commit-tree, and git update-ref for this.\nIf you have the object IDs for all the existing blobs and trees, then\nyou can create any necessary trees, pass the root tree to git\ncommit-tree, and then use git update-ref to update the branch from the\nold value to the new value.\n\nNote that if you're doing this in an otherwise busy repository, you\nshould definitely specify the old value of the ref to avoid a race\ncondition where someone else updates it at the same time.\n\nIf this seems like a lot of inconvenient work, then you'll see why we\nhave the index.\n\nIf you just want to create a commit without modifying the _main_ index\nfile, then you can use the GIT_INDEX_FILE environment variable to use a\ntemporary file as the index and then read data into there and commit\nusing git read-tree, git update-index, git commit-tree, and git\nupdate-ref.  We do that elsewhere in Git, and this will definitely be\neasier than writing your own trees using git mktree.\n\n> So I guess this is the best it gets? If I wanna make it better, I guess\n> I will need to use libgit2?\n\nThis may be slightly easier with libgit2, depending on your needs.\n-- \nbrian m. carlson (he/him or they/them)\nHouston, Texas, US\n"}]}