git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* How to commit without an index file?
@ 2021-01-18 16:58 Utku
  2021-01-18 17:59 ` brian m. carlson
  0 siblings, 1 reply; 2+ messages in thread
From: Utku @ 2021-01-18 16:58 UTC (permalink / raw)
  To: git

In my program, I have the file paths, permissions and Git object IDs of
everything that I want to appear in the next commit. Hence, I want to
create a commit without creating an index file.

Essentially it's like to combining `--cacheinfo` from `update-index`
with `commit` like:

	git commit \
		-m "Commit message" \
		--branch my-branch \
		--cacheinfo "100644,0123456789abcdef0123456789abcdef01234567,path/to/first/file” \
		--cacheinfo "100755,123456789abcdef0123456789abcdef012345670,path/to/second/file” \
		--cacheinfo "100644,23456789abcdef0123456789abcdef0123456701,path/to/third/file"

In this example, the command would not read the index file, but would
get the information necessary to create the commit tree as arguments (or
from STDIN). The command would handle recursively creating trees for the
intermediate directories. The object ID for the final tree would be used
for the `tree` field of the commit.

I tried tricks for simulating standard streams as an index file to Git,
but they didn't work out:

	$ GIT_INDEX_FILE=/dev/stdout git read-tree HEAD
	fatal: Unable to create '/dev/stdout.lock': No such file or directory

The best I could come up with is creating a no checkout worktree for
`my-branch` and using a FIFO for the index file, instead of a
conventional file. The shell script equivalent of it would be as follows
(I would be happy if you can point out any errors in this script as
well):

	set -e
	
	git_dir=$(git rev-parse --git-dir)
	worktree_name=my-program
	worktree_location=$git_dir/$worktree_name
	
	# Ran only once
	function init_worktree {
		branch_name=my-branch
		worktree_gitdir=$git_dir/worktrees/$worktree_name
		
		git worktree add "$worktree_location" "$branch_name" --no-checkout
		rm -f "$worktree_gitdir/index”
		mkfifo "$worktree_gitdir/index”
		
		echo "Initialized worktree at $worktree_location”
	}

	# Ran on every commit
	function commit_worktree {
		cd "$worktree_location”
		git read-tree —empty
		git update-index --add \
		--cacheinfo "100644,0123456789abcdef0123456789abcdef01234567,path/to/first/file” \
		--cacheinfo "100755,123456789abcdef0123456789abcdef012345670,path/to/second/file” \
		--cacheinfo "100644,23456789abcdef0123456789abcdef0123456701,path/to/third/file”
		# etc. Will be received as arguments or from STDIN.
		git commit -m "Commit message”
	}

So I guess this is the best it gets? If I wanna make it better, I guess
I will need to use libgit2?

Thank you

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: How to commit without an index file?
  2021-01-18 16:58 How to commit without an index file? Utku
@ 2021-01-18 17:59 ` brian m. carlson
  0 siblings, 0 replies; 2+ messages in thread
From: brian m. carlson @ 2021-01-18 17:59 UTC (permalink / raw)
  To: Utku; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 2271 bytes --]

On 2021-01-18 at 16:58:56, Utku wrote:
> In my program, I have the file paths, permissions and Git object IDs of
> everything that I want to appear in the next commit. Hence, I want to
> create a commit without creating an index file.
> 
> Essentially it's like to combining `--cacheinfo` from `update-index`
> with `commit` like:
> 
> 	git commit \
> 		-m "Commit message" \
> 		--branch my-branch \
> 		--cacheinfo "100644,0123456789abcdef0123456789abcdef01234567,path/to/first/file” \
> 		--cacheinfo "100755,123456789abcdef0123456789abcdef012345670,path/to/second/file” \
> 		--cacheinfo "100644,23456789abcdef0123456789abcdef0123456701,path/to/third/file"
> 
> In this example, the command would not read the index file, but would
> get the information necessary to create the commit tree as arguments (or
> from STDIN). The command would handle recursively creating trees for the
> intermediate directories. The object ID for the final tree would be used
> for the `tree` field of the commit.

You could use git mktree, git commit-tree, and git update-ref for this.
If you have the object IDs for all the existing blobs and trees, then
you can create any necessary trees, pass the root tree to git
commit-tree, and then use git update-ref to update the branch from the
old value to the new value.

Note that if you're doing this in an otherwise busy repository, you
should definitely specify the old value of the ref to avoid a race
condition where someone else updates it at the same time.

If this seems like a lot of inconvenient work, then you'll see why we
have the index.

If you just want to create a commit without modifying the _main_ index
file, then you can use the GIT_INDEX_FILE environment variable to use a
temporary file as the index and then read data into there and commit
using git read-tree, git update-index, git commit-tree, and git
update-ref.  We do that elsewhere in Git, and this will definitely be
easier than writing your own trees using git mktree.

> So I guess this is the best it gets? If I wanna make it better, I guess
> I will need to use libgit2?

This may be slightly easier with libgit2, depending on your needs.
-- 
brian m. carlson (he/him or they/them)
Houston, Texas, US

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 263 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-01-18 18:12 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-18 16:58 How to commit without an index file? Utku
2021-01-18 17:59 ` brian m. carlson

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).