# HG changeset patch # User Brendan Cully # Date 1186294072 25200 # Node ID 35d47b06d4e307934912a079a7aaaf4c3bb56fdf # Parent 5023af9fcba40e137da65e3d9a03b6597f36fce5 patch: add git symlink support diff --git a/mercurial/patch.py b/mercurial/patch.py --- a/mercurial/patch.py +++ b/mercurial/patch.py @@ -202,9 +202,9 @@ def readgitpatch(fp, firstline=None): gp.op = 'DELETE' elif line.startswith('new file mode '): gp.op = 'ADD' - gp.mode = int(line.rstrip()[-3:], 8) + gp.mode = int(line.rstrip()[-6:], 8) elif line.startswith('new mode '): - gp.mode = int(line.rstrip()[-3:], 8) + gp.mode = int(line.rstrip()[-6:], 8) elif line.startswith('GIT binary patch'): dopatch |= GP_BINARY gp.binary = True @@ -1048,12 +1048,15 @@ def updatedir(ui, repo, patches): ctype, gp = patches[f] if gp and gp.mode: x = gp.mode & 0100 != 0 + l = gp.mode & 020000 != 0 dst = os.path.join(repo.root, gp.path) # patch won't create empty files if ctype == 'ADD' and not os.path.exists(dst): repo.wwrite(gp.path, '', x and 'x' or '') else: - util.set_exec(dst, x) + util.set_link(dst, l) + if not l: + util.set_exec(dst, x) cmdutil.addremove(repo, cfiles) files = patches.keys() files.extend([r for r in removes if r not in files]) @@ -1145,11 +1148,15 @@ def diff(repo, node1=None, node2=None, f if node2: ctx2 = context.changectx(repo, node2) execf2 = ctx2.manifest().execf + linkf2 = ctx2.manifest().linkf else: ctx2 = context.workingctx(repo) execf2 = util.execfunc(repo.root, None) + linkf2 = util.linkfunc(repo.root, None) if execf2 is None: - execf2 = ctx2.parents()[0].manifest().copy().execf + mc = ctx2.parents()[0].manifest().copy() + execf2 = mc.execf + linkf2 = mc.linkf # returns False if there was no rename between ctx1 and ctx2 # returns None if the file was created between ctx1 and ctx2 @@ -1206,8 +1213,8 @@ def diff(repo, node1=None, node2=None, f if f not in removed: tn = getfilectx(f, ctx2).data() if opts.git: - def gitmode(x): - return x and '100755' or '100644' + def gitmode(x, l): + return l and '120000' or (x and '100755' or '100644') def addmodehdr(header, omode, nmode): if omode != nmode: header.append('old mode %s\n' % omode) @@ -1215,10 +1222,10 @@ def diff(repo, node1=None, node2=None, f a, b = f, f if f in added: - mode = gitmode(execf2(f)) + mode = gitmode(execf2(f), linkf2(f)) if f in copied: a = copied[f] - omode = gitmode(man1.execf(a)) + omode = gitmode(man1.execf(a), man1.linkf(a)) addmodehdr(header, omode, mode) if a in removed and a not in gone: op = 'rename' @@ -1236,11 +1243,11 @@ def diff(repo, node1=None, node2=None, f if f in srcs: dodiff = False else: - mode = gitmode(man1.execf(f)) + mode = gitmode(man1.execf(f), man1.linkf(f)) header.append('deleted file mode %s\n' % mode) else: - omode = gitmode(man1.execf(f)) - nmode = gitmode(execf2(f)) + omode = gitmode(man1.execf(f), man1.linkf(f)) + nmode = gitmode(execf2(f), linkf2(f)) addmodehdr(header, omode, nmode) if util.binary(to) or util.binary(tn): dodiff = 'binary' diff --git a/tests/test-symlinks b/tests/test-symlinks --- a/tests/test-symlinks +++ b/tests/test-symlinks @@ -72,3 +72,13 @@ hg commit -A -m 'add symlink in a/b/c su echo '2. clone it' cd .. hg clone test testclone + +echo '# git symlink diff' +cd testclone +hg diff --git -r null:tip +hg export --git tip > ../sl.diff +echo '# import git symlink diff' +hg rm a/b/c/demo +hg commit -m'remove link' +hg import ../sl.diff +hg diff --git -r 1:tip diff --git a/tests/test-symlinks.out b/tests/test-symlinks.out --- a/tests/test-symlinks.out +++ b/tests/test-symlinks.out @@ -20,3 +20,20 @@ 1. commit a symlink adding a/b/c/demo 2. clone it 1 files updated, 0 files merged, 0 files removed, 0 files unresolved +# git symlink diff +diff --git a/a/b/c/demo b/a/b/c/demo +new file mode 120000 +--- /dev/null ++++ b/a/b/c/demo +@@ -0,0 +1,1 @@ ++/path/to/symlink/source +\ No newline at end of file +# import git symlink diff +applying ../sl.diff +diff --git a/a/b/c/demo b/a/b/c/demo +new file mode 120000 +--- /dev/null ++++ b/a/b/c/demo +@@ -0,0 +1,1 @@ ++/path/to/symlink/source +\ No newline at end of file