All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Marc Becker via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Aniket Gupta <aniketgupta3001@gmail.com>,
	Marc Becker <becm@gmx.de>, Marc Becker <becm@gmx.de>
Subject: [PATCH v3] fast-import: allow 'from' to reference new commits and tags by oid
Date: Wed, 14 Oct 2026 16:27:32 +0000	[thread overview]
Message-ID: <pull.2252.v3.git.1791995252623.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.2252.git.1791653078449.gitgitgadget@gmail.com>

From: Marc Becker <becm@gmx.de>

During a 'git fast-import' session, newly created objects are written
to an in-progress packfile and recorded in fast-import's internal
object table.  Until a 'checkpoint' command or the end of the session
finalizes and indexes that packfile, these objects are not visible to
the repository's object database via odb_read_object_peeled().

Commands such as 'ls' (via parse_treeish_dataref() and dereference())
and 'cat-blob' already account for this when given a hex object name:
they look up the object in fast-import's internal object table with
find_object() first and read it from the in-progress packfile with
gfi_unpack_entry() when its '.pack_id' is not MAX_PACK_ID.

By contrast, when 'from <committish>' (in a 'commit' or 'reset'
command) is given a hex object name instead of a mark or branch name,
parse_objectish() parses the hex string into 'b->oid' and calls
parse_from_existing(), which unconditionally looks up the object via
odb_read_object_peeled().  If the object is a commit or tag created in
the current pack cycle, odb_read_object_peeled() returns NULL and
fast-import dies with "fatal: not a valid commit: <oid>".

Teach parse_from_existing() to look up 'b->oid' with find_object()
first, peel any tag objects in the object table using dereference(),
and unpack the target commit with gfi_unpack_entry() if it resides in
the in-progress packfile, before falling back to
odb_read_object_peeled() for objects in the repository's object
database.

Signed-off-by: Marc Becker <becm@gmx.de>
---
    fast-import: fix lookup for new commits
    
    Changes since v2:
    
     * use LLM-generated commit message (description is on point) by Junio
     * provide hash-specific OIDs in test code via test_oid

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2252%2Fbecm%2Ffix-fast-import-commit-from-existing-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2252/becm/fix-fast-import-commit-from-existing-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/2252

Range-diff vs v2:

 1:  d834e2fc47 ! 1:  25113432c6 fast-import: fix lookup for new commits and tags
     @@ Metadata
      Author: Marc Becker <becm@gmx.de>
      
       ## Commit message ##
     -    fast-import: fix lookup for new commits and tags
     +    fast-import: allow 'from' to reference new commits and tags by oid
      
     -    Queries for commits created during the same 'git fast-import' session
     -    result in a crash:
     -        < reset refs/heads/newbranch
     -        < from <new-commit-oid>
     -        > fatal: not a valid commit: <new-commit-oid>
     +    During a 'git fast-import' session, newly created objects are written
     +    to an in-progress packfile and recorded in fast-import's internal
     +    object table.  Until a 'checkpoint' command or the end of the session
     +    finalizes and indexes that packfile, these objects are not visible to
     +    the repository's object database via odb_read_object_peeled().
      
     -    Getting file content for commit has no issue (working implementation):
     -        < ls <new-commit-oid> file-in-new-commit.txt
     -        > {file content}
     +    Commands such as 'ls' (via parse_treeish_dataref() and dereference())
     +    and 'cat-blob' already account for this when given a hex object name:
     +    they look up the object in fast-import's internal object table with
     +    find_object() first and read it from the in-progress packfile with
     +    gfi_unpack_entry() when its '.pack_id' is not MAX_PACK_ID.
      
     -    During import, new objects may not (yet) be reachable via the ODB layer.
     -    Try to resolve requested tag/commit via object cache first
     -    to avoid crash.
     -    Add test to 't/t9300.sh' with references to a pending tag and commit.
     +    By contrast, when 'from <committish>' (in a 'commit' or 'reset'
     +    command) is given a hex object name instead of a mark or branch name,
     +    parse_objectish() parses the hex string into 'b->oid' and calls
     +    parse_from_existing(), which unconditionally looks up the object via
     +    odb_read_object_peeled().  If the object is a commit or tag created in
     +    the current pack cycle, odb_read_object_peeled() returns NULL and
     +    fast-import dies with "fatal: not a valid commit: <oid>".
     +
     +    Teach parse_from_existing() to look up 'b->oid' with find_object()
     +    first, peel any tag objects in the object table using dereference(),
     +    and unpack the target commit with gfi_unpack_entry() if it resides in
     +    the in-progress packfile, before falling back to
     +    odb_read_object_peeled() for objects in the repository's object
     +    database.
      
          Signed-off-by: Marc Becker <becm@gmx.de>
      
     @@ t/t9300-fast-import.sh: test_expect_success 'Y: rewrite submodules' '
       	)
       '
       
     -+cat >Y-reference-pending-sha256 <<\Y_INPUT_END
     -+commit refs/heads/main
     -+committer A U Thor <author@example.com> 1712563200 +0000
     -+data 14
     -+commit message
     -+M 644 inline test file
     -+data 14
     -+dummy content
     -+
     -+tag newtag
     -+from 17e650f097a4db6fe069c96935360d3ccc9b35c4018728c5f311a4217c2ced3d
     -+tagger A U Thor <author@example.com> 1712563300 +0000
     -+data 11
     -+tag message
     -+# no emty line after tag data!
     -+reset refs/heads/other
     -+from 85edc5eac315bc680677b2fc71622bd77476f057eb8dc8ed6a497803a24f1f46
     -+
     -+commit refs/heads/further
     -+committer A U Thor <author@example.com> 1712563400 +0000
     -+data 21
     -+what about 2nd commit
     -+from 17e650f097a4db6fe069c96935360d3ccc9b35c4018728c5f311a4217c2ced3d
     -+M 644 inline other test file
     -+data 19
     -+more dummy content
     -+
     -+done
     -+Y_INPUT_END
     -+
     -+cat >Y-reference-pending-sha1 <<\Y_INPUT_END
     -+commit refs/heads/main
     -+committer A U Thor <author@example.com> 1712563200 +0000
     -+data 14
     -+commit message
     -+M 644 inline test file
     -+data 14
     -+dummy content
     -+
     -+tag newtag
     -+from 85b46dd918355ff17b4109ec738723d42f235a04
     -+tagger A U Thor <author@example.com> 1712563300 +0000
     -+data 11
     -+tag message
     -+# no emty line after tag data!
     -+reset refs/heads/other
     -+from ec6c4db71feb5f66615214dad2324ce030e777a7
     -+
     -+commit refs/heads/further
     -+committer A U Thor <author@example.com> 1712563400 +0000
     -+data 21
     -+what about 2nd commit
     -+from 85b46dd918355ff17b4109ec738723d42f235a04
     -+M 644 inline other test file
     -+data 19
     -+more dummy content
     -+
     -+done
     -+Y_INPUT_END
     -+
      +test_expect_success 'Y: reference pending tag or commit' '
     ++	test_oid_cache <<-EOF &&
     ++		pending_commit sha1:85b46dd918355ff17b4109ec738723d42f235a04
     ++		pending_commit sha256:17e650f097a4db6fe069c96935360d3ccc9b35c4018728c5f311a4217c2ced3d
     ++		pending_tag sha1:ec6c4db71feb5f66615214dad2324ce030e777a7
     ++		pending_tag sha256:85edc5eac315bc680677b2fc71622bd77476f057eb8dc8ed6a497803a24f1f46
     ++		EOF
     ++
      +	git init reference-pending &&
      +	(
      +		cd reference-pending &&
     -+		git fast-import < "../Y-reference-pending-$(git rev-parse --show-object-format)"
     ++		git fast-import <<-EOF
     ++			commit refs/heads/main
     ++			committer A U Thor <author@example.com> 1712563200 +0000
     ++			data 14
     ++			commit message
     ++			M 644 inline test file
     ++			data 14
     ++			dummy content
     ++
     ++			tag newtag
     ++			from $(test_oid pending_commit)
     ++			tagger A U Thor <author@example.com> 1712563300 +0000
     ++			data 11
     ++			tag message
     ++			# no emty line after tag data!
     ++			reset refs/heads/other
     ++			from $(test_oid pending_tag)
     ++
     ++			commit refs/heads/further
     ++			committer A U Thor <author@example.com> 1712563400 +0000
     ++			data 21
     ++			what about 2nd commit
     ++			from $(test_oid pending_commit)
     ++			M 644 inline other test file
     ++			data 19
     ++			more dummy content
     ++
     ++			done
     ++			EOF
      +	)
      +'
      +


 builtin/fast-import.c  | 19 +++++++++++++++----
 t/t9300-fast-import.sh | 43 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+), 4 deletions(-)

diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index fbd919982c..574a03c484 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -292,6 +292,9 @@ static void fast_import_state_init(struct fast_import_state *state,
 	state->option = option;
 }
 
+static struct object_entry *dereference(struct object_entry *oe,
+					struct object_id *oid);
+
 static void parse_argv(struct fast_import_state *state);
 static void parse_get_mark(struct fast_import_state *state, const char *p);
 static void parse_cat_blob(struct fast_import_state *state, const char *p);
@@ -2658,12 +2661,20 @@ static void parse_from_existing(struct branch *b)
 		oidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo);
 	} else {
 		unsigned long size;
-		size_t size_st = 0;
 		char *buf;
+		struct object_entry *e = find_object(&b->oid);
 
-		buf = odb_read_object_peeled(the_repository->objects, &b->oid,
-					     OBJ_COMMIT, &size_st, &b->oid);
-		size = cast_size_t_to_ulong(size_st);
+		while (e && e->type == OBJ_TAG)
+			e = dereference(e, &b->oid);
+
+		if (e && e->type == OBJ_COMMIT && e->pack_id != MAX_PACK_ID) {
+			buf = gfi_unpack_entry(e, &size);
+		} else {
+			size_t size_st = 0;
+			buf = odb_read_object_peeled(the_repository->objects, &b->oid,
+						     OBJ_COMMIT, &size_st, &b->oid);
+			size = cast_size_t_to_ulong(size_st);
+		}
 		parse_from_commit(b, buf, size);
 		free(buf);
 	}
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index d9de2ef0d8..9001e2572a 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -3938,4 +3938,47 @@ test_expect_success 'Y: rewrite submodules' '
 	)
 '
 
+test_expect_success 'Y: reference pending tag or commit' '
+	test_oid_cache <<-EOF &&
+		pending_commit sha1:85b46dd918355ff17b4109ec738723d42f235a04
+		pending_commit sha256:17e650f097a4db6fe069c96935360d3ccc9b35c4018728c5f311a4217c2ced3d
+		pending_tag sha1:ec6c4db71feb5f66615214dad2324ce030e777a7
+		pending_tag sha256:85edc5eac315bc680677b2fc71622bd77476f057eb8dc8ed6a497803a24f1f46
+		EOF
+
+	git init reference-pending &&
+	(
+		cd reference-pending &&
+		git fast-import <<-EOF
+			commit refs/heads/main
+			committer A U Thor <author@example.com> 1712563200 +0000
+			data 14
+			commit message
+			M 644 inline test file
+			data 14
+			dummy content
+
+			tag newtag
+			from $(test_oid pending_commit)
+			tagger A U Thor <author@example.com> 1712563300 +0000
+			data 11
+			tag message
+			# no emty line after tag data!
+			reset refs/heads/other
+			from $(test_oid pending_tag)
+
+			commit refs/heads/further
+			committer A U Thor <author@example.com> 1712563400 +0000
+			data 21
+			what about 2nd commit
+			from $(test_oid pending_commit)
+			M 644 inline other test file
+			data 19
+			more dummy content
+
+			done
+			EOF
+	)
+'
+
 test_done

base-commit: 6de20f6092dcf9bdb1c8efe03db4b70c82b423dd
-- 
gitgitgadget

  parent reply	other threads:[~2026-10-14 16:27 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-10 17:24 [PATCH] fast-import: fix lookup for new commits Marc Becker via GitGitGadget
2026-10-11 19:38 ` Aniket Gupta
2026-10-12 22:50 ` [PATCH v2] fast-import: fix lookup for new commits and tags Marc Becker via GitGitGadget
2026-10-13  0:08   ` Junio C Hamano
2026-10-13  1:39   ` Junio C Hamano
2026-10-14 16:27 ` Marc Becker via GitGitGadget [this message]
2026-10-14 19:36   ` [PATCH v3] fast-import: allow 'from' to reference new commits and tags by oid Junio C Hamano
2026-10-14 21:22 ` [PATCH v4] " Marc Becker via GitGitGadget
2026-10-14 22:42   ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=pull.2252.v3.git.1791995252623.gitgitgadget@gmail.com \
    --to=gitgitgadget@gmail.com \
    --cc=aniketgupta3001@gmail.com \
    --cc=becm@gmx.de \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.