git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [RFC] git-split: Split the history of a git repository by subdirectories and ranges

From
Junio C Hamano <junkio@cox.net>
Date
Sep 27, 2006, 19:31 UTC
Message-ID
<7v1wpxayyd.fsf@assigned-by-dhcp.cox.net>
In-Reply-To
<7vr6xxb00m.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano <junkio@cox.net> writes:
Show 10 quoted lines
> However, you can do:
>
> $ git rev-list --parents --pretty=raw
>
> which would give you "commit $this_commit $its $parents" lines
> and "parent $true_parent" lines at the same time.
>
> And they will be inconsistent when you have grafts or path
> limiter.  The former honor grafts and path limiter, and the
> latter show the true set of parents.

-- >8 -- An illustration of rev-list --parents --pretty=raw

This script creates two separate histories, A and B, each of which does:

      (A0, B0): create fileA and subdir/fileB
      (A1, B1): modify fileA
      (A2, B2): modify subdir/fileB

and then grafts them together to make B0 a child of A2. So the final history looks like (time flows from top to bottom):

		true parent	touches subdir?
	A0	none		yes (creates it)
        A1      A0		no
        A2	A1		yes
        B0	none		yes (different from what's in A2)
        B1	B0		no
        B2	B1		yes

"git rev-list --parents --pretty=raw B2" would give "fake" parents on the "commit " header lines while "parent " header lines show the parent as recorded in the commit object (i.e. B0 appears to have A2 as its parent on "commit " header but there is no "parent A2" header line in it).

When you have path limiters, we simplify history to omit commits that do not affect the specified paths.

So "git rev-list --parents --pretty=raw B2 subdir" would return "B2 B0 A2 A0" (because B1 and A1 do not touch the path). When it does so, the "commit " header lines have "fake" parents (i.e. B2 appears to have B0 as its parent on "commit " header), but you can still get the true parents by looking at "parent " header.

---
diff --git a/t/t6001-rev-list-graft.sh b/t/t6001-rev-list-graft.sh
new file mode 100755
index 0000000..08a6cff
--- /dev/null
+++ b/t/t6001-rev-list-graft.sh
@@ -0,0 +1,113 @@
+#!/bin/sh
+
+test_description='Revision traversal vs grafts and path limiter'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+	mkdir subdir &&
+	echo >fileA fileA &&
+	echo >subdir/fileB fileB &&
+	git add fileA subdir/fileB &&
+	git commit -a -m "Initial in one history." &&
+	A0=`git rev-parse --verify HEAD` &&
+
+	echo >fileA fileA modified &&
+	git commit -a -m "Second in one history." &&
+	A1=`git rev-parse --verify HEAD` &&
+
+	echo >subdir/fileB fileB modified &&
+	git commit -a -m "Third in one history." &&
+	A2=`git rev-parse --verify HEAD` &&
+
+	rm -f .git/refs/heads/master .git/index &&
+	
+	echo >fileA fileA again &&
+	echo >subdir/fileB fileB again &&
+	git add fileA subdir/fileB &&
+	git commit -a -m "Initial in alternate history." &&
+	B0=`git rev-parse --verify HEAD` &&
+
+	echo >fileA fileA modified in alternate history &&
+	git commit -a -m "Second in alternate history." &&
+	B1=`git rev-parse --verify HEAD` &&
+
+	echo >subdir/fileB fileB modified in alternate history &&
+	git commit -a -m "Third in alternate history." &&
+	B2=`git rev-parse --verify HEAD` &&
+	: done
+'
+
+check () {
+	type=$1
+	shift
+
+	arg=
+	which=arg
+	rm -f test.expect
+	for a
+	do
+		if test "z$a" = z--
+		then
+			which=expect
+			child=
+			continue
+		fi
+		if test "$which" = arg
+		then
+			arg="$arg$a "
+			continue
+		fi
+		if test "$type" = basic
+		then
+			echo "$a"
+		else
+			if test "z$child" != z
+			then
+				echo "$child $a"
+			fi
+			child="$a"
+		fi
+	done >test.expect
+	if test "$type" != basic && test "z$child" != z
+	then
+		echo >>test.expect $child
+	fi
+	if test $type = basic
+	then
+		git rev-list $arg >test.actual
+	elif test $type = parents
+	then
+		git rev-list --parents $arg >test.actual
+	elif test $type = parents-raw
+	then
+		git rev-list --parents --pretty=raw $arg |
+		sed -n -e 's/^commit //p' >test.actual
+	fi
+	diff test.expect test.actual
+}
+
+for type in basic parents parents-raw
+do
+	test_expect_success 'without grafts' "
+		rm -f .git/info/grafts
+		check $type $B2 -- $B2 $B1 $B0
+	"
+
+	test_expect_success 'with grafts' "
+		echo '$B0 $A2' >.git/info/grafts
+		check $type $B2 -- $B2 $B1 $B0 $A2 $A1 $A0
+	"
+
+	test_expect_success 'without grafts, with pathlimit' "
+		rm -f .git/info/grafts
+		check $type $B2 subdir -- $B2 $B0
+	"
+
+	test_expect_success 'with grafts, with pathlimit' "
+		echo '$B0 $A2' >.git/info/grafts
+		check $type $B2 subdir -- $B2 $B0 $A2 $A0
+	"
+
+done
+test_done
Previous: Junio C HamanoNext: Josh Triplett
Message 5 of 19 in “[RFC] git-split: Split the history of a git repository by subdirectories and ranges”
  1. Josh TriplettSep 27, 2006
  2. Junio C HamanoSep 27, 2006
  3. Andy WhitcroftSep 27, 2006
  4. Junio C HamanoSep 27, 2006
  5. Junio C HamanoSep 27, 2006
  6. Josh TriplettOct 23, 2006
  7. Linus TorvaldsOct 23, 2006
  8. Josh TriplettOct 23, 2006
  9. Linus TorvaldsOct 23, 2006
  10. Jakub NarebskiOct 23, 2006
  11. Josh TriplettOct 23, 2006
  12. Linus TorvaldsOct 23, 2006
  13. Linus TorvaldsOct 23, 2006
  14. Johannes SchindelinOct 24, 2006
  15. Linus TorvaldsOct 24, 2006
  16. Junio C HamanoOct 25, 2006
  17. Jakub NarebskiOct 25, 2006
  18. Josh TriplettOct 25, 2006
  19. Junio C HamanoOct 25, 2006

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.