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

Re: [RFC] Applying a graft to a tree and "rippling" the changes through the history

From
Matthias Urlichs <smurf@smurf.noris.de>
Date
Nov 18, 2005, 08:49 UTC
Message-ID
<pan.2005.11.18.08.49.30.32345@smurf.noris.de>
In-Reply-To
<7vll01ut6j.fsf@assigned-by-dhcp.cox.net>
Hi, Junio C Hamano wrote:
Show 6 quoted lines
> Ryan Anderson <ryan@michonline.com> writes:
> 
>> I've written a tool that will take a single commit, add it as a parent
>> of another commit, and recreate the history above that second commit in
>> a fully compatible manner.
> 

You're not the only one. My tool is different, however, in that it accepts a list of old=>new commits. I have used it successfully to re-graft my changes from a CVS->GIT tree to the corresponding CVS->SVN->GIT tree (which cannot be identical, because (a) SVN's timestamps are not accurate enough and (b) SVN's CVS import is more accurate in reproducing CVS archives than cvsps can be).

> Also another rhetorical, tongue-in-cheek question.  What is your
> plan to ripple the graft through to update signed tags?  ;-)
I'd suggest adding the capability of grafting something onto a tag...
#!/usr/bin/python
# This is a simple script which clones a git subtree to another.
import sys,re,optparse,os,subprocess

parser = optparse.OptionParser("corresponding_file [ old_commit ]", conflict_handler="resolve", description="""\ Transfer a list of commits from one repository to another.

The first argument is a list of SHA1 entries of the form
	old new
It lists which commits are "the same".

old_commit and those of its parents which are not listed in the corresponding_file are copied, i.e. new commit objects are created. Their SHA1s are added to the file so that you may repeat the process with other commits, or run it incrementally.

""")
parser.add_option("-h","--help","-?", action="help",
                    help="Print this help message and exit")
parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
                    help="Report progress")
(options, args) = parser.parse_args()
if len(args) < 1 or len(args) > 3:
	parser.error("requires one to three arguments")
def end(p):
	try:
		retcode = p.wait()
	except OSError,e:
		print >>sys.stderr, "git-rev-list failed:", e
	else:
		if retcode < 0:
			print >>sys.stderr, "git-rev-list was terminated by signal", -retcode
			sys.exit(1)
		elif retcode > 0:
			print >>sys.stderr, "git-rev-list exited with non-zero exit code", retcode
			sys.exit(1)
re_cmt = re.compile(r'\s*#.*')
corr = {}
for l in open(args[0]):
	l = re_cmt.sub("",l).strip()
	if l == "": continue
	try:
		a,b = l.split()
	except ValueError:
		continue
	if len(a) != 40: continue
	if len(b) != 40: continue
	corr[a]=b
corrf=open(args[0],"a")
if len(args) >= 2:
	srctag = args[1]
else:
	srctag = "HEAD"
srcrepo = os.path.curdir
commits=[]
cmd = ["git-rev-list",srctag]
for k in corr.iterkeys():
	cmd.append("^"+k)
if options.verbose:
	print cmd
p=subprocess.Popen(cmd, stdout=subprocess.PIPE)
for l in p.stdout:
	l = l.strip()
	commits.append(l)
end(p)
while len(commits):
	c = commits.pop()
	if c in corr: continue
	if options.verbose:
		print "Processing:",c
	p=subprocess.Popen(["git-cat-file","commit",c], stdout=subprocess.PIPE)
	qf=os.tempnam()
	try:
		q=open(qf,"w")
		nx=False
		for l in p.stdout:
			if nx:
				q.write(l)
				continue
			l = l.strip()
			if l == "":
				nx=True
				q.write("\n")
				continue
			a,b = l.split(" ",1)
			if a == "parent":
				b = corr[b]
			print >>q,a,b
		q.close()
		q=subprocess.Popen(["git-hash-object","-w","-t","commit",qf], stdout=subprocess.PIPE)
		d = q.stdout.read().strip()
		end(q)
	finally:
		os.unlink(qf)
	end(p)
	corr[c] = d
	print >>corrf, c,d
	if options.verbose:
		print c,d,l

# OK, everything is done. corrf.close() print d

-- 
Matthias Urlichs   |   {M:U} IT Design @ m-u-it.de   |  smurf@smurf.noris.de
Disclaimer: The quote was selected randomly. Really. | http://smurf.noris.de
 - -
It's not what you know or what you do, it's who you know.
Previous: Ryan Anderson
Message 5 of 5 in “[RFC] Applying a graft to a tree and "rippling" the changes through the history”
  1. Ryan AndersonNov 6, 2005
  2. Randal L. SchwartzNov 6, 2005
  3. Junio C HamanoNov 7, 2005
  4. Ryan AndersonNov 7, 2005
  5. Matthias UrlichsNov 18, 2005

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.