Git development
 help / color / mirror / Atom feed
* [PATCH 4/8] git_remote_helpers: Use 2to3 if building with Python 3
From: John Keeping @ 2013-01-12 19:23 UTC (permalink / raw)
  To: git; +Cc: John Keeping, Eric S. Raymond, Felipe Contreras, Sverre Rabbelier
In-Reply-To: <cover.1358018078.git.john@keeping.me.uk>

Using the approach detailed on the Python wiki[1], run 2to3 on the code
as part of the build if building with Python 3.

The code itself requires no changes to convert cleanly.

[1] http://wiki.python.org/moin/PortingPythonToPy3k

Signed-off-by: John Keeping <john@keeping.me.uk>
---
 git_remote_helpers/setup.py | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/git_remote_helpers/setup.py b/git_remote_helpers/setup.py
index 4d434b6..6de41de 100644
--- a/git_remote_helpers/setup.py
+++ b/git_remote_helpers/setup.py
@@ -4,6 +4,15 @@
 
 from distutils.core import setup
 
+# If building under Python3 we need to run 2to3 on the code, do this by
+# trying to import distutils' 2to3 builder, which is only available in
+# Python3.
+try:
+    from distutils.command.build_py import build_py_2to3 as build_py
+except ImportError:
+    # 2.x
+    from distutils.command.build_py import build_py
+
 setup(
     name = 'git_remote_helpers',
     version = '0.1.0',
@@ -14,4 +23,5 @@ setup(
     url = 'http://www.git-scm.com/',
     package_dir = {'git_remote_helpers': ''},
     packages = ['git_remote_helpers', 'git_remote_helpers.git'],
+    cmdclass = {'build_py': build_py},
 )
-- 
1.8.1

^ permalink raw reply related

* [PATCH 5/8] svn-fe: allow svnrdump_sim.py to run with Python 3
From: John Keeping @ 2013-01-12 19:23 UTC (permalink / raw)
  To: git; +Cc: John Keeping, Eric S. Raymond, Felipe Contreras, Sverre Rabbelier
In-Reply-To: <cover.1358018078.git.john@keeping.me.uk>

The changes to allow this script to run with Python 3 are minimal and do
not affect its functionality on the versions of Python 2 that are
already supported (2.4 onwards).

Signed-off-by: John Keeping <john@keeping.me.uk>
---
 contrib/svn-fe/svnrdump_sim.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/contrib/svn-fe/svnrdump_sim.py b/contrib/svn-fe/svnrdump_sim.py
index 17cf6f9..4e78a1c 100755
--- a/contrib/svn-fe/svnrdump_sim.py
+++ b/contrib/svn-fe/svnrdump_sim.py
@@ -14,7 +14,7 @@ if sys.hexversion < 0x02040000:
 
 def getrevlimit():
         var = 'SVNRMAX'
-        if os.environ.has_key(var):
+        if var in os.environ:
                 return os.environ[var]
         return None
 
@@ -44,7 +44,7 @@ def writedump(url, lower, upper):
 
 if __name__ == "__main__":
         if not (len(sys.argv) in (3, 4, 5)):
-                print "usage: %s dump URL -rLOWER:UPPER"
+                print("usage: %s dump URL -rLOWER:UPPER")
                 sys.exit(1)
         if not sys.argv[1] == 'dump': raise NotImplementedError('only "dump" is suppported.')
         url = sys.argv[2]
-- 
1.8.1

^ permalink raw reply related

* [PATCH 6/8] git-remote-testpy: hash bytes explicitly
From: John Keeping @ 2013-01-12 19:23 UTC (permalink / raw)
  To: git; +Cc: John Keeping, Eric S. Raymond, Felipe Contreras, Sverre Rabbelier
In-Reply-To: <cover.1358018078.git.john@keeping.me.uk>

Under Python 3 'hasher.update(...)' must take a byte string and not a
unicode string.  Explicitly encode the argument to this method as UTF-8
so that this code works under Python 3.

This moves the required Python version forward to 2.0.

Signed-off-by: John Keeping <john@keeping.me.uk>
---
 git-remote-testpy.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/git-remote-testpy.py b/git-remote-testpy.py
index e4533b1..58aa1ae 100644
--- a/git-remote-testpy.py
+++ b/git-remote-testpy.py
@@ -31,9 +31,9 @@ from git_remote_helpers.git.exporter import GitExporter
 from git_remote_helpers.git.importer import GitImporter
 from git_remote_helpers.git.non_local import NonLocalGit
 
-if sys.hexversion < 0x01050200:
-    # os.makedirs() is the limiter
-    sys.stderr.write("git-remote-testgit: requires Python 1.5.2 or later.\n")
+if sys.hexversion < 0x02000000:
+    # string.encode() is the limiter
+    sys.stderr.write("git-remote-testgit: requires Python 2.0 or later.\n")
     sys.exit(1)
 
 def get_repo(alias, url):
@@ -45,7 +45,7 @@ def get_repo(alias, url):
     repo.get_head()
 
     hasher = _digest()
-    hasher.update(repo.path)
+    hasher.update(repo.path.encode('utf-8'))
     repo.hash = hasher.hexdigest()
 
     repo.get_base_path = lambda base: os.path.join(
-- 
1.8.1

^ permalink raw reply related

* [PATCH 7/8] git-remote-testpy: don't do unbuffered text I/O
From: John Keeping @ 2013-01-12 19:23 UTC (permalink / raw)
  To: git; +Cc: John Keeping, Eric S. Raymond, Felipe Contreras, Sverre Rabbelier
In-Reply-To: <cover.1358018078.git.john@keeping.me.uk>

Python 3 forbids unbuffered I/O in text mode.  Change the reading of
stdin in git-remote-testpy so that we read the lines as bytes and then
decode them a line at a time.

This allows us to keep the I/O unbuffered in order to avoid
reintroducing the bug fixed by commit 7fb8e16 (git-remote-testgit: fix
race when spawning fast-import).

Signed-off-by: John Keeping <john@keeping.me.uk>
---
 git-remote-testpy.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/git-remote-testpy.py b/git-remote-testpy.py
index 58aa1ae..815222f 100644
--- a/git-remote-testpy.py
+++ b/git-remote-testpy.py
@@ -154,7 +154,7 @@ def do_import(repo, args):
     refs = [ref]
 
     while True:
-        line = sys.stdin.readline()
+        line = sys.stdin.readline().decode()
         if line == '\n':
             break
         if not line.startswith('import '):
@@ -217,7 +217,7 @@ def read_one_line(repo):
 
     line = sys.stdin.readline()
 
-    cmdline = line
+    cmdline = line.decode()
 
     if not cmdline:
         warn("Unexpected EOF")
@@ -269,7 +269,7 @@ def main(args):
 
     more = True
 
-    sys.stdin = os.fdopen(sys.stdin.fileno(), 'r', 0)
+    sys.stdin = os.fdopen(sys.stdin.fileno(), 'rb', 0)
     while (more):
         more = read_one_line(repo)
 
-- 
1.8.1

^ permalink raw reply related

* [PATCH 8/8] git-remote-testpy: call print as a function
From: John Keeping @ 2013-01-12 19:23 UTC (permalink / raw)
  To: git; +Cc: John Keeping, Eric S. Raymond, Felipe Contreras, Sverre Rabbelier
In-Reply-To: <cover.1358018078.git.john@keeping.me.uk>

This is harmless in Python 2, which sees the parentheses as redundant
grouping, but is required for Python 3.  Since this is the only change
required to make this script just run under Python 3 without needing
2to3 it seems worthwhile.

The case of an empty print must be handled specially because in that
case Python 2 will interpret '()' as an empty tuple and print it as
'()'; inserting an empty string fixes this.

Signed-off-by: John Keeping <john@keeping.me.uk>
---
 git-remote-testpy.py | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/git-remote-testpy.py b/git-remote-testpy.py
index 815222f..8ba5d28 100644
--- a/git-remote-testpy.py
+++ b/git-remote-testpy.py
@@ -87,9 +87,9 @@ def do_capabilities(repo, args):
     """Prints the supported capabilities.
     """
 
-    print "import"
-    print "export"
-    print "refspec refs/heads/*:%s*" % repo.prefix
+    print("import")
+    print("export")
+    print("refspec refs/heads/*:%s*" % repo.prefix)
 
     dirname = repo.get_base_path(repo.gitdir)
 
@@ -98,11 +98,11 @@ def do_capabilities(repo, args):
 
     path = os.path.join(dirname, 'git.marks')
 
-    print "*export-marks %s" % path
+    print("*export-marks %s" % path)
     if os.path.exists(path):
-        print "*import-marks %s" % path
+        print("*import-marks %s" % path)
 
-    print # end capabilities
+    print('') # end capabilities
 
 
 def do_list(repo, args):
@@ -115,16 +115,16 @@ def do_list(repo, args):
 
     for ref in repo.revs:
         debug("? refs/heads/%s", ref)
-        print "? refs/heads/%s" % ref
+        print("? refs/heads/%s" % ref)
 
     if repo.head:
         debug("@refs/heads/%s HEAD" % repo.head)
-        print "@refs/heads/%s HEAD" % repo.head
+        print("@refs/heads/%s HEAD" % repo.head)
     else:
         debug("@refs/heads/master HEAD")
-        print "@refs/heads/master HEAD"
+        print("@refs/heads/master HEAD")
 
-    print # end list
+    print('') # end list
 
 
 def update_local_repo(repo):
@@ -167,7 +167,7 @@ def do_import(repo, args):
     repo = update_local_repo(repo)
     repo.exporter.export_repo(repo.gitdir, refs)
 
-    print "done"
+    print("done")
 
 
 def do_export(repo, args):
@@ -184,8 +184,8 @@ def do_export(repo, args):
         repo.non_local.push(repo.gitdir)
 
     for ref in changed:
-        print "ok %s" % ref
-    print
+        print("ok %s" % ref)
+    print('')
 
 
 COMMANDS = {
-- 
1.8.1

^ permalink raw reply related

* Re: Suggestion: add option in git-p4 to preserve user in Git repository
From: Olivier Delalleau @ 2013-01-12 19:44 UTC (permalink / raw)
  To: Pete Wyckoff; +Cc: git, Luke Diamand
In-Reply-To: <20130112163838.GA28722@padd.com>

2013/1/12 Pete Wyckoff <pw@padd.com>:
> shish@keba.be wrote on Thu, 10 Jan 2013 22:38 -0500:
>> I'm in a situation where I don't have P4 admin rights to use the
>> --preserve-user option of git-p4. However, I would like to keep user
>> information in the associated Git branch.
>>
>> Would it be possible to add an option for this?
>
> The --preserve-user option is used to submit somebody else's work
> from git to p4.  It does "p4 change -f" to edit the author of the
> change after it has been submitted to p4.  P4 requires admin
> privileges to do that.
>
> Changes that are imported _from_ p4 to git do have the correct
> author information.
>
> Can you explain a bit more what you're looking for?
>
>                 -- Pete

Hi,

Sorry I wasn't clear enough. When "git p4 submit" submits changes from
Git to P4, it also edits the Git history and replaces the Git commits'
authors by the information from the Perforce account submitting the
changes. The advantage is that both the P4 and Git repositories share
the same author information, but in my case I would like to keep in
the Git repository the original authors (because the P4 account I'm
using to submit to P4 is shared by all Git users).

Hope it makes more sense now :)

-=- Olivier

^ permalink raw reply

* [PATCH] rebase --preserve-merges keeps empty merge commits
From: Phil Hord @ 2013-01-12 20:46 UTC (permalink / raw)
  To: git
  Cc: phil.hord, Neil Horman, Martin von Zweigbergk, Junio C Hamano,
	Phil Hord

Since 90e1818f9a  (git-rebase: add keep_empty flag, 2012-04-20)
'git rebase --preserve-merges' fails to preserve empty merge commits
unless --keep-empty is also specified.  Merge commits should be
preserved in order to preserve the structure of the rebased graph,
even if the merge commit does not introduce changes to the parent.

Teach rebase not to drop merge commits only because they are empty.

A special case which is not handled by this change is for a merge commit
whose parents are now the same commit because all the previous different
parents have been dropped as a result of this rebase or some previous
operation.
---
 git-rebase--interactive.sh | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 44901d5..8ed7fcc 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -190,6 +190,11 @@ is_empty_commit() {
 	test "$tree" = "$ptree"
 }
 
+is_merge_commit()
+{
+	git rev-parse --verify --quiet "$1"^2 >/dev/null 2>&1
+}
+
 # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and
 # GIT_AUTHOR_DATE exported from the current environment.
 do_with_author () {
@@ -874,7 +879,7 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \
 while read -r shortsha1 rest
 do
 
-	if test -z "$keep_empty" && is_empty_commit $shortsha1
+	if test -z "$keep_empty" && is_empty_commit $shortsha1 && ! is_merge_commit $shortsha1
 	then
 		comment_out="# "
 	else
-- 
1.8.1.dirty

^ permalink raw reply related

* Re: [PATCH v2 05/21] commit: convert to use parse_pathspec
From: Martin von Zweigbergk @ 2013-01-12 22:54 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano
In-Reply-To: <1357903275-16804-6-git-send-email-pclouds@gmail.com>

On Fri, Jan 11, 2013 at 3:20 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
>
> diff --git a/cache.h b/cache.h
> index e52365d..a3c316f 100644
> --- a/cache.h
> +++ b/cache.h
> @@ -476,6 +476,9 @@ extern int ie_modified(const struct index_state *, struct cache_entry *, struct
>  /* Pathspec magic */
>  #define PATHSPEC_FROMTOP    (1<<0)
>
> +/* Pathspec flags */
> +#define PATHSPEC_EMPTY_MATCH_ALL (1<<0) /* No args means match everything */
> +
>  struct pathspec {
>         const char **raw; /* get_pathspec() result, not freed by free_pathspec() */
>         int nr;
> diff --git a/setup.c b/setup.c
> index 6e960b9..a26b6c0 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -280,6 +280,9 @@ void parse_pathspec(struct pathspec *pathspec,
>         if (!entry && !prefix)
>                 return;
>
> +       if (!*argv && (flags & PATHSPEC_EMPTY_MATCH_ALL))
> +               return;
> +
>         /* No arguments with prefix -> prefix pathspec */
>         if (!entry) {
>                 static const char *raw[2];

I was surprised not to find these two hunks in 02/21. If they were
there, you wouldn't have to explain in the log message of that patch
that "flags" is for future-proofing. Also, "*argv" is written "entry"
in the surrounding conditions.

^ permalink raw reply

* Re: Suggestion: add option in git-p4 to preserve user in Git repository
From: Pete Wyckoff @ 2013-01-12 22:56 UTC (permalink / raw)
  To: Olivier Delalleau; +Cc: git, Luke Diamand
In-Reply-To: <CAFXk4bpM8X3k=iwRjM9kvm4XbZyKS+hTCiVbHOjH3jK6MkkBSg@mail.gmail.com>

shish@keba.be wrote on Sat, 12 Jan 2013 14:44 -0500:
> 2013/1/12 Pete Wyckoff <pw@padd.com>:
> > shish@keba.be wrote on Thu, 10 Jan 2013 22:38 -0500:
> >> I'm in a situation where I don't have P4 admin rights to use the
> >> --preserve-user option of git-p4. However, I would like to keep user
> >> information in the associated Git branch.
> >>
> >> Would it be possible to add an option for this?
> >
> > The --preserve-user option is used to submit somebody else's work
> > from git to p4.  It does "p4 change -f" to edit the author of the
> > change after it has been submitted to p4.  P4 requires admin
> > privileges to do that.
> >
> > Changes that are imported _from_ p4 to git do have the correct
> > author information.
> >
> > Can you explain a bit more what you're looking for?
> 
> Sorry I wasn't clear enough. When "git p4 submit" submits changes from
> Git to P4, it also edits the Git history and replaces the Git commits'
> authors by the information from the Perforce account submitting the
> changes. The advantage is that both the P4 and Git repositories share
> the same author information, but in my case I would like to keep in
> the Git repository the original authors (because the P4 account I'm
> using to submit to P4 is shared by all Git users).

Ah, I see what you're looking for now.  It's certainly possible
to keep a mapping in the git side to remember who really wrote
each change that went into p4, but there's nothing set up to do
that now.  And it would be a fair amount of work, with many
little details.

You could put the true name in the commit message, like
we do signed-off-by messages: "Author: Real Coder <rc@my.com>".
That would keep the proper attribution, but not work with "git
log --author", e.g.; you'd have to use "--grep='Real Coder'"
instead.

		-- Pete

^ permalink raw reply

* Re: [PATCH 3/8] git_remote_helpers: Force rebuild if python version changes
From: Pete Wyckoff @ 2013-01-12 23:30 UTC (permalink / raw)
  To: John Keeping; +Cc: git, Eric S. Raymond, Felipe Contreras, Sverre Rabbelier
In-Reply-To: <89f55d20da9a4c0a8490f95107cbf5d04219d0fb.1358018078.git.john@keeping.me.uk>

john@keeping.me.uk wrote on Sat, 12 Jan 2013 19:23 +0000:
> When different version of python are used to build via distutils, the
> behaviour can change.  Detect changes in version and pass --force in
> this case.
[..]
> diff --git a/git_remote_helpers/Makefile b/git_remote_helpers/Makefile
[..]
> +py_version=$(shell $(PYTHON_PATH) -c \
> +	'import sys; print("%i.%i" % sys.version_info[:2])')
> +
>  all: $(pysetupfile)
> -	$(QUIET)$(PYTHON_PATH) $(pysetupfile) $(QUIETSETUP) build
> +	$(QUIET)test "$$(cat GIT-PYTHON_VERSION 2>/dev/null)" = "$(py_version)" || \
> +	flags=--force; \
> +	$(PYTHON_PATH) $(pysetupfile) $(QUIETSETUP) build $$flags
> +	$(QUIET)echo "$(py_version)" >GIT-PYTHON_VERSION

Can you depend on ../GIT-PYTHON-VARS instead?  It comes from
96a4647 (Makefile: detect when PYTHON_PATH changes, 2012-12-18).
It doesn't check version, just path, but hopefully that's good
enough.  I'm imagining a rule that would do "clean" if
../GIT-PYTHON-VARS changed, then build without --force.

		-- Pete

^ permalink raw reply

* Re: [PATCH 0/8] Initial support for Python 3
From: Pete Wyckoff @ 2013-01-12 23:43 UTC (permalink / raw)
  To: John Keeping
  Cc: git, Eric S. Raymond, Felipe Contreras, Sverre Rabbelier,
	Sebastian Morr
In-Reply-To: <cover.1358018078.git.john@keeping.me.uk>

john@keeping.me.uk wrote on Sat, 12 Jan 2013 19:23 +0000:
> I started having a look to see how much work would be needed to make Git
> work with Python 3 and the answer is mostly not much.  The exception is
> git-p4.py which is hit hard by the distinction between byte strings and
> unicode strings, particularly because the Python output mode of p4
> targets Python 2.
> 
> I don't know if it's worthwhile to actually apply these but here they
> are in case anyone's interested.
> 
> Having said that, the changes are minimal and involve either wrapping
> parentheses around arguments to print or being a bit more explicit about
> how we expect byte strings to be decoded to unicode.
> 
> With these patches all tests pass with python3 except t98* (git-p4), but
> there are a couple of topics in-flight which will affect that
> (fc/remote-testgit-feature-done and er/replace-cvsimport).
> 
> John Keeping (8):
>   git_remote_helpers: Allow building with Python 3
>   git_remote_helpers: fix input when running under Python 3
>   git_remote_helpers: Force rebuild if python version changes
>   git_remote_helpers: Use 2to3 if building with Python 3
>   svn-fe: allow svnrdump_sim.py to run with Python 3
>   git-remote-testpy: hash bytes explicitly
>   git-remote-testpy: don't do unbuffered text I/O
>   git-remote-testpy: call print as a function
> 
>  contrib/svn-fe/svnrdump_sim.py     |  4 ++--
>  git-remote-testpy.py               | 40 +++++++++++++++++++-------------------
>  git_remote_helpers/.gitignore      |  1 +
>  git_remote_helpers/Makefile        | 10 ++++++++--
>  git_remote_helpers/git/importer.py |  2 +-
>  git_remote_helpers/setup.py        | 10 ++++++++++
>  6 files changed, 42 insertions(+), 25 deletions(-)

These look good, in that there are relatively few changed needed.

Sebastian Morr tried a similar patch a year ago, in

    http://thread.gmane.org/gmane.comp.version-control.git/187545

He made changes beyond yours, in particular "print >>" lines,
that you seem to handle with 2to3 during the build.  I'm not sure
which approach is better in the long run.  He worked on the
other .py in contrib/ too.

Can you give me some hints about the byte/unicode string issues
in git-p4.py?  There's really only one place that does:

    p4 = subprocess.Popen("p4 -G ...")
    marshal.load(p4.stdout)

If that's the only issue, this might not be too paniful.

I hesitated to take Sebastian's changes due to the huge number of
print() lines, but maybe a 2to3 approach would make that aspect
of python3 support not too onerous.

		-- Pete

^ permalink raw reply

* Re: [PATCH 0/8] Initial support for Python 3
From: John Keeping @ 2013-01-13  0:41 UTC (permalink / raw)
  To: Pete Wyckoff
  Cc: git, Eric S. Raymond, Felipe Contreras, Sverre Rabbelier,
	Sebastian Morr
In-Reply-To: <20130112234304.GC23079@padd.com>

On Sat, Jan 12, 2013 at 06:43:04PM -0500, Pete Wyckoff wrote:
> john@keeping.me.uk wrote on Sat, 12 Jan 2013 19:23 +0000:
>> I started having a look to see how much work would be needed to make Git
>> work with Python 3 and the answer is mostly not much.  The exception is
>> git-p4.py which is hit hard by the distinction between byte strings and
>> unicode strings, particularly because the Python output mode of p4
>> targets Python 2.
>> 
>> I don't know if it's worthwhile to actually apply these but here they
>> are in case anyone's interested.
>> 
>> Having said that, the changes are minimal and involve either wrapping
>> parentheses around arguments to print or being a bit more explicit about
>> how we expect byte strings to be decoded to unicode.
>> 
>> With these patches all tests pass with python3 except t98* (git-p4), but
>> there are a couple of topics in-flight which will affect that
>> (fc/remote-testgit-feature-done and er/replace-cvsimport).
>> 
>> John Keeping (8):
>>   git_remote_helpers: Allow building with Python 3
>>   git_remote_helpers: fix input when running under Python 3
>>   git_remote_helpers: Force rebuild if python version changes
>>   git_remote_helpers: Use 2to3 if building with Python 3
>>   svn-fe: allow svnrdump_sim.py to run with Python 3
>>   git-remote-testpy: hash bytes explicitly
>>   git-remote-testpy: don't do unbuffered text I/O
>>   git-remote-testpy: call print as a function
>> 
>>  contrib/svn-fe/svnrdump_sim.py     |  4 ++--
>>  git-remote-testpy.py               | 40 +++++++++++++++++++-------------------
>>  git_remote_helpers/.gitignore      |  1 +
>>  git_remote_helpers/Makefile        | 10 ++++++++--
>>  git_remote_helpers/git/importer.py |  2 +-
>>  git_remote_helpers/setup.py        | 10 ++++++++++
>>  6 files changed, 42 insertions(+), 25 deletions(-)
> 
> These look good, in that there are relatively few changed needed.
> 
> Sebastian Morr tried a similar patch a year ago, in
> 
>     http://thread.gmane.org/gmane.comp.version-control.git/187545
> 
> He made changes beyond yours, in particular "print >>" lines,
> that you seem to handle with 2to3 during the build.  I'm not sure
> which approach is better in the long run.  He worked on the
> other .py in contrib/ too.

In the long run I'd want to move away from "print >>" to use
"print(file=..., ...)" but that's only available from Python 2.6 onwards
(via a __future__ import) and I think we probably don't want to rule out
Python 2.5 yet.

Without 2to3 the only way to do this for both Python 2 and 3 is as
"file.write('...\n')".

> Can you give me some hints about the byte/unicode string issues
> in git-p4.py?  There's really only one place that does:
> 
>     p4 = subprocess.Popen("p4 -G ...")
>     marshal.load(p4.stdout)
> 
> If that's the only issue, this might not be too paniful.

The problem is that what gets loaded there is a dictionary (encoded by
p4) that maps byte strings to byte strings, so all of the accesses to
that dictionary need to either:

   1) explicitly call encode() on a string constant
or 2) use a byte string constant with a "b" prefix

Or we could re-write the dictionary once, which handles the keys... but
some of the values are also used as strings and we can't handle that as
a one-off conversion since in other places we really do want the byte
string (think content of binary files).

Basically a thorough audit of all access to variables that come from p4
would be needed, with explicit decode()s for authors, dates, etc.

> I hesitated to take Sebastian's changes due to the huge number of
> print() lines, but maybe a 2to3 approach would make that aspect
> of python3 support not too onerous.

I think we'd want to change to print() eventually and having a single
codebase for 2 and 3 would be nicer for development, but I think we need
to be able to say "no one is using Python 2.5 or earlier" before we can
do that and I'm not sure we're there yet.  From where we are at the
moment I think 2to3 is a good answer, particularly where we're already
using distutils to generate a release image.


John

^ permalink raw reply

* Re: missing objects -- prevention
From: Sitaram Chamarty @ 2013-01-13  0:56 UTC (permalink / raw)
  To: Jeff King; +Cc: Git Mailing List
In-Reply-To: <20130112131358.GB21875@sigill.intra.peff.net>

On Sat, Jan 12, 2013 at 6:43 PM, Jeff King <peff@peff.net> wrote:
> On Sat, Jan 12, 2013 at 06:39:52AM +0530, Sitaram Chamarty wrote:
>
>> >   1. The repo has a ref R pointing at commit X.
>> >
>> >   2. A user starts a push to another ref, Q, of commit Y that builds on
>> >      X. Git advertises ref R, so the sender knows they do not need to
>> >      send X, but only Y. The user then proceeds to send the packfile
>> >      (which might take a very long time).
>> >
>> >   3. Meanwhile, another user deletes ref R. X becomes unreferenced.
>>
>> The gitolite logs show that no deletion of refs has happened.
>
> To be pedantic, step 3 could also be rewinding R to a commit before X.
> Anything that causes X to become unreferenced.

Right, but there were no rewinds also; I should have mentioned that.
(Gitolite log files mark rewinds and deletes specially, so they're
easy to search.  There were two attempted rewinds but they failed the
gitolite update hook so -- while the new objects would have landed in
the object store -- the old ones were not dereferenced).

>> > There is a race with simultaneously deleting and packing refs. It
>> > doesn't cause object db corruption, but it will cause refs to "rewind"
>> > back to their packed versions. I have seen that one in practice (though
>> > relatively rare). I fixed it in b3f1280, which is not yet in any
>> > released version.
>>
>> This is for the packed-refs file right?  And it could result in a ref
>> getting deleted right?
>
> Yes, if the ref was not previously packed, it could result in the ref
> being deleted entirely.
>
>> I said above that the gitolite logs say no ref was deleted.  What if
>> the ref "deletion" happened because of this race, making the rest of
>> your 4-step scenario above possible?
>
> It's possible. I do want to highlight how unlikely it is, though.

Agreed.

>> > up in the middle, or fsck rejects the pack). We have historically left
>>
>> fsck... you mean if I had 'receive.fsckObjects' true, right?  I don't.
>>  Should I?  Would it help this overall situation?  As I understand it,
>> thats only about the internals of each object to check corruption, and
>> cannot detect a *missing* object on the local object store.
>
> Right, I meant if you have receive.fsckObjects on. It won't help this
> situation at all, as we already do a connectivity check separate from
> the fsck. But I do recommend it in general, just because it helps catch
> bad objects before they gets disseminated to a wider audience (at which
> point it is often infeasible to rewind history). And it has found git
> bugs (e.g., null sha1s in tree entries).

I will add this.  Any idea if there's a significant performance hit?

>> > At GitHub, we've taken to just cleaning them up aggressively (I think
>> > after an hour), though I am tempted to put in an optional signal/atexit
>>
>> OK; I'll do the same then.  I suppose a cron job is the best way; I
>> didn't find any config for expiring these files.
>
> If you run "git prune --expire=1.hour.ago", it should prune stale
> tmp_pack_* files more than an hour old. But you may not be comfortable
> with such a short expiration for the objects themselves. :)
>
>> Thanks again for your help.  I'm going to treat it (for now) as a
>> disk/fs error after hearing from you about the other possibility I
>> mentioned above, although I find it hard to believe one repo can be
>> hit buy *two* races occurring together!
>
> Yeah, the race seems pretty unlikely (though it could be just the one
> race with a rewind). As I said, I haven't actually ever seen it in
> practice. In my experience, though, disk/fs issues do not manifest as
> just missing objects, but as corrupted packfiles (e.g., the packfile
> directory entry ends up pointing to the wrong inode, which is easy to
> see because the inode's content is actually a reflog). And then of
> course with the packfile unreadable, you have missing objects. But YMMV,
> depending on the fs and what's happened to the machine to cause the fs
> problem.

That's always the hard part.  System admins (at the Unix level) insist
there's nothing wrong and no disk errors and so on...  that is why I
was interested in network errors causing problems and so on.

Anyway, now that I know the tmp_pack_* files are caused mostly by
failed pushes than by failed auto-gc, at least I can deal with the
immediate problem easily!

Thanks once again for your patient replies!

sitaram


-- 
Sitaram

^ permalink raw reply

* Re: missing objects -- prevention
From: Sitaram Chamarty @ 2013-01-13  0:57 UTC (permalink / raw)
  To: Jeff King; +Cc: Git Mailing List
In-Reply-To: <CAMK1S_iKARYqi_Dv90og0No7NN=WxFg+ixmRvnkvfdrcOi1r=Q@mail.gmail.com>

Uggh...

On Sun, Jan 13, 2013 at 6:26 AM, Sitaram Chamarty <sitaramc@gmail.com> wrote:

> the object store -- the old ones were not dereferenced).

I meant *un* referenced of course :)

^ permalink raw reply

* [PATCH/RFC 0/7] mutiple improvements
From: Techlive Zheng @ 2013-01-13  1:52 UTC (permalink / raw)
  To: git, gitster; +Cc: apenwarr, greened, Techlive Zheng

* refactor tests for 'git subtree'
  * rearrange some tests
  * clean up unnecessary quotes
  * make each test self-contained
* keep commit intact after the split by using '%B'
* handle '--prefix' argument with slash appended correctly

David A. Greene (1):
  contrib/subtree: Remove test number comments

Techlive Zheng (6):
  contrib/subtree: Add vim modeline
  contrib/subtree: Ignore testing directory
  contrib/subtree: Code cleaning and refactoring
  contrib/subtree: Make each test self-contained
  contrib/subtree: Use %B for the split commit message
  contrib/subtree: Handle '--prefix' argument with a slash appended

 contrib/subtree/.gitignore         |    5 +-
 contrib/subtree/git-subtree.sh     |   83 ++-
 contrib/subtree/git-subtree.txt    |   13 +
 contrib/subtree/t/t7900-subtree.sh | 1233 +++++++++++++++++++++++-------------
 4 files changed, 872 insertions(+), 462 deletions(-)

-- 
1.8.1

^ permalink raw reply

* [PATCH/RFC 1/7] contrib/subtree: Add vim modeline
From: Techlive Zheng @ 2013-01-13  1:52 UTC (permalink / raw)
  To: git, gitster; +Cc: apenwarr, greened, Techlive Zheng
In-Reply-To: <1358041958-1998-1-git-send-email-techlivezheng@gmail.com>

Signed-off-by: Techlive Zheng <techlivezheng@gmail.com>
---
 contrib/subtree/git-subtree.sh     | 2 ++
 contrib/subtree/t/t7900-subtree.sh | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 920c664..138e1e0 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -710,3 +710,5 @@ cmd_push()
 }
 
 "cmd_$command" "$@"
+
+# vim: set ts=4 sw=4 noet
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index bc2eeb0..3e02aeb 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -506,3 +506,5 @@ test_expect_success 'verify one file change per commit' '
 '
 
 test_done
+
+# vim: set et ts=4 sw=4
-- 
1.8.1

^ permalink raw reply related

* [PATCH/RFC 2/7] contrib/subtree: Ignore testing directory
From: Techlive Zheng @ 2013-01-13  1:52 UTC (permalink / raw)
  To: git, gitster; +Cc: apenwarr, greened, Techlive Zheng
In-Reply-To: <1358041958-1998-1-git-send-email-techlivezheng@gmail.com>

Signed-off-by: Techlive Zheng <techlivezheng@gmail.com>
---
 contrib/subtree/.gitignore | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/contrib/subtree/.gitignore b/contrib/subtree/.gitignore
index 91360a3..59aeeb4 100644
--- a/contrib/subtree/.gitignore
+++ b/contrib/subtree/.gitignore
@@ -1,6 +1,5 @@
 *~
 git-subtree
-git-subtree.xml
 git-subtree.1
-mainline
-subproj
+git-subtree.xml
+t/trash\ directory.*
-- 
1.8.1

^ permalink raw reply related

* [PATCH/RFC 3/7] contrib/subtree: Remove test number comments
From: Techlive Zheng @ 2013-01-13  1:52 UTC (permalink / raw)
  To: git, gitster; +Cc: apenwarr, greened, Techlive Zheng
In-Reply-To: <1358041958-1998-1-git-send-email-techlivezheng@gmail.com>

From: "David A. Greene" <greened@obbligato.org>

Delete the comments indicating test numbers as it causes maintenance
headaches.  t*.sh -i will help us find any broken tests.

Signed-off-by: David A. Greene <greened@obbligato.org>
Signed-off-by: Techlive Zheng <techlivezheng@gmail.com>
---
 contrib/subtree/t/t7900-subtree.sh | 55 --------------------------------------
 1 file changed, 55 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 3e02aeb..abdcddb 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -60,7 +60,6 @@ last_commit_message()
 	git log --pretty=format:%s -1
 }
 
-# 1
 test_expect_success 'init subproj' '
         test_create_repo subproj
 '
@@ -68,7 +67,6 @@ test_expect_success 'init subproj' '
 # To the subproject!
 cd subproj
 
-# 2
 test_expect_success 'add sub1' '
         create sub1 &&
         git commit -m "sub1" &&
@@ -76,14 +74,12 @@ test_expect_success 'add sub1' '
         git branch -m master subproj
 '
 
-# 3
 test_expect_success 'add sub2' '
         create sub2 &&
         git commit -m "sub2" &&
         git branch sub2
 '
 
-# 4
 test_expect_success 'add sub3' '
         create sub3 &&
         git commit -m "sub3" &&
@@ -93,7 +89,6 @@ test_expect_success 'add sub3' '
 # Back to mainline
 cd ..
 
-# 5
 test_expect_success 'add main4' '
         create main4 &&
         git commit -m "main4" &&
@@ -101,101 +96,85 @@ test_expect_success 'add main4' '
         git branch subdir
 '
 
-# 6
 test_expect_success 'fetch subproj history' '
         git fetch ./subproj sub1 &&
         git branch sub1 FETCH_HEAD
 '
 
-# 7
 test_expect_success 'no subtree exists in main tree' '
         test_must_fail git subtree merge --prefix=subdir sub1
 '
 
-# 8
 test_expect_success 'no pull from non-existant subtree' '
         test_must_fail git subtree pull --prefix=subdir ./subproj sub1
 '
 
-# 9
 test_expect_success 'check if --message works for add' '
         git subtree add --prefix=subdir --message="Added subproject" sub1 &&
         check_equal ''"$(last_commit_message)"'' "Added subproject" &&
         undo
 '
 
-# 10
 test_expect_success 'check if --message works as -m and --prefix as -P' '
         git subtree add -P subdir -m "Added subproject using git subtree" sub1 &&
         check_equal ''"$(last_commit_message)"'' "Added subproject using git subtree" &&
         undo
 '
 
-# 11
 test_expect_success 'check if --message works with squash too' '
         git subtree add -P subdir -m "Added subproject with squash" --squash sub1 &&
         check_equal ''"$(last_commit_message)"'' "Added subproject with squash" &&
         undo
 '
 
-# 12
 test_expect_success 'add subproj to mainline' '
         git subtree add --prefix=subdir/ FETCH_HEAD &&
         check_equal ''"$(last_commit_message)"'' "Add '"'subdir/'"' from commit '"'"'''"$(git rev-parse sub1)"'''"'"'"
 '
 
-# 13
 # this shouldn't actually do anything, since FETCH_HEAD is already a parent
 test_expect_success 'merge fetched subproj' '
         git merge -m "merge -s -ours" -s ours FETCH_HEAD
 '
 
-# 14
 test_expect_success 'add main-sub5' '
         create subdir/main-sub5 &&
         git commit -m "main-sub5"
 '
 
-# 15
 test_expect_success 'add main6' '
         create main6 &&
         git commit -m "main6 boring"
 '
 
-# 16
 test_expect_success 'add main-sub7' '
         create subdir/main-sub7 &&
         git commit -m "main-sub7"
 '
 
-# 17
 test_expect_success 'fetch new subproj history' '
         git fetch ./subproj sub2 &&
         git branch sub2 FETCH_HEAD
 '
 
-# 18
 test_expect_success 'check if --message works for merge' '
         git subtree merge --prefix=subdir -m "Merged changes from subproject" sub2 &&
         check_equal ''"$(last_commit_message)"'' "Merged changes from subproject" &&
         undo
 '
 
-# 19
 test_expect_success 'check if --message for merge works with squash too' '
         git subtree merge --prefix subdir -m "Merged changes from subproject using squash" --squash sub2 &&
         check_equal ''"$(last_commit_message)"'' "Merged changes from subproject using squash" &&
         undo
 '
 
-# 20
 test_expect_success 'merge new subproj history into subdir' '
         git subtree merge --prefix=subdir FETCH_HEAD &&
         git branch pre-split &&
         check_equal ''"$(last_commit_message)"'' "Merge commit '"'"'"$(git rev-parse sub2)"'"'"' into mainline"
 '
 
-# 21
 test_expect_success 'Check that prefix argument is required for split' '
         echo "You must provide the --prefix option." > expected &&
         test_must_fail git subtree split > actual 2>&1 &&
@@ -207,7 +186,6 @@ test_expect_success 'Check that prefix argument is required for split' '
         rm -f expected actual
 '
 
-# 22
 test_expect_success 'Check that the <prefix> exists for a split' '
         echo "'"'"'non-existent-directory'"'"'" does not exist\; use "'"'"'git subtree add'"'"'" > expected &&
         test_must_fail git subtree split --prefix=non-existent-directory > actual 2>&1 &&
@@ -219,7 +197,6 @@ test_expect_success 'Check that the <prefix> exists for a split' '
 #        rm -f expected actual
 '
 
-# 23
 test_expect_success 'check if --message works for split+rejoin' '
         spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
         git branch spl1 "$spl1" &&
@@ -227,7 +204,6 @@ test_expect_success 'check if --message works for split+rejoin' '
         undo
 '
 
-# 24
 test_expect_success 'check split with --branch' '
         spl1=$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin) &&
         undo &&
@@ -235,7 +211,6 @@ test_expect_success 'check split with --branch' '
         check_equal ''"$(git rev-parse splitbr1)"'' "$spl1"
 '
 
-# 25
 test_expect_success 'check split with --branch for an existing branch' '
         spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
         undo &&
@@ -244,13 +219,10 @@ test_expect_success 'check split with --branch for an existing branch' '
         check_equal ''"$(git rev-parse splitbr2)"'' "$spl1"
 '
 
-# 26
 test_expect_success 'check split with --branch for an incompatible branch' '
         test_must_fail git subtree split --prefix subdir --onto FETCH_HEAD --branch subdir
 '
 
-
-# 27
 test_expect_success 'check split+rejoin' '
         spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
         undo &&
@@ -258,7 +230,6 @@ test_expect_success 'check split+rejoin' '
         check_equal ''"$(last_commit_message)"'' "Split '"'"'subdir/'"'"' into commit '"'"'"$spl1"'"'"'"
 '
 
-# 28
 test_expect_success 'add main-sub8' '
         create subdir/main-sub8 &&
         git commit -m "main-sub8"
@@ -267,14 +238,12 @@ test_expect_success 'add main-sub8' '
 # To the subproject!
 cd ./subproj
 
-# 29
 test_expect_success 'merge split into subproj' '
         git fetch .. spl1 &&
         git branch spl1 FETCH_HEAD &&
         git merge FETCH_HEAD
 '
 
-# 30
 test_expect_success 'add sub9' '
         create sub9 &&
         git commit -m "sub9"
@@ -283,19 +252,16 @@ test_expect_success 'add sub9' '
 # Back to mainline
 cd ..
 
-# 31
 test_expect_success 'split for sub8' '
         split2=''"$(git subtree split --annotate='"'*'"' --prefix subdir/ --rejoin)"''
         git branch split2 "$split2"
 '
 
-# 32
 test_expect_success 'add main-sub10' '
         create subdir/main-sub10 &&
         git commit -m "main-sub10"
 '
 
-# 33
 test_expect_success 'split for sub10' '
         spl3=''"$(git subtree split --annotate='"'*'"' --prefix subdir --rejoin)"'' &&
         git branch spl3 "$spl3"
@@ -304,7 +270,6 @@ test_expect_success 'split for sub10' '
 # To the subproject!
 cd ./subproj
 
-# 34
 test_expect_success 'merge split into subproj' '
         git fetch .. spl3 &&
         git branch spl3 FETCH_HEAD &&
@@ -318,13 +283,11 @@ chkms_sub=$(echo $chkms | multiline | sed 's,^,subdir/,' | fixnl)
 chks="sub1 sub2 sub3 sub9"
 chks_sub=$(echo $chks | multiline | sed 's,^,subdir/,' | fixnl)
 
-# 35
 test_expect_success 'make sure exactly the right set of files ends up in the subproj' '
         subfiles=''"$(git ls-files | fixnl)"'' &&
         check_equal "$subfiles" "$chkms $chks"
 '
 
-# 36
 test_expect_success 'make sure the subproj history *only* contains commits that affect the subdir' '
         allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | fixnl)"'' &&
         check_equal "$allchanges" "$chkms $chks"
@@ -333,20 +296,17 @@ test_expect_success 'make sure the subproj history *only* contains commits that
 # Back to mainline
 cd ..
 
-# 37
 test_expect_success 'pull from subproj' '
         git fetch ./subproj subproj-merge-spl3 &&
         git branch subproj-merge-spl3 FETCH_HEAD &&
         git subtree pull --prefix=subdir ./subproj subproj-merge-spl3
 '
 
-# 38
 test_expect_success 'make sure exactly the right set of files ends up in the mainline' '
         mainfiles=''"$(git ls-files | fixnl)"'' &&
         check_equal "$mainfiles" "$chkm $chkms_sub $chks_sub"
 '
 
-# 39
 test_expect_success 'make sure each filename changed exactly once in the entire history' '
         # main-sub?? and /subdir/main-sub?? both change, because those are the
         # changes that were split into their own history.  And subdir/sub?? never
@@ -355,12 +315,10 @@ test_expect_success 'make sure each filename changed exactly once in the entire
         check_equal "$allchanges" ''"$(echo $chkms $chkm $chks $chkms_sub | multiline | sort | fixnl)"''
 '
 
-# 40
 test_expect_success 'make sure the --rejoin commits never make it into subproj' '
         check_equal ''"$(git log --pretty=format:'"'%s'"' HEAD^2 | grep -i split)"'' ""
 '
 
-# 41
 test_expect_success 'make sure no "git subtree" tagged commits make it into subproj' '
         # They are meaningless to subproj since one side of the merge refers to the mainline
         check_equal ''"$(git log --pretty=format:'"'%s%n%b'"' HEAD^2 | grep "git-subtree.*:")"'' ""
@@ -370,14 +328,12 @@ test_expect_success 'make sure no "git subtree" tagged commits make it into subp
 mkdir test2
 cd test2
 
-# 42
 test_expect_success 'init main' '
         test_create_repo main
 '
 
 cd main
 
-# 43
 test_expect_success 'add main1' '
         create main1 &&
         git commit -m "main1"
@@ -385,14 +341,12 @@ test_expect_success 'add main1' '
 
 cd ..
 
-# 44
 test_expect_success 'init sub' '
         test_create_repo sub
 '
 
 cd sub
 
-# 45
 test_expect_success 'add sub2' '
         create sub2 &&
         git commit -m "sub2"
@@ -402,7 +356,6 @@ cd ../main
 
 # check if split can find proper base without --onto
 
-# 46
 test_expect_success 'add sub as subdir in main' '
         git fetch ../sub master &&
         git branch sub2 FETCH_HEAD &&
@@ -411,7 +364,6 @@ test_expect_success 'add sub as subdir in main' '
 
 cd ../sub
 
-# 47
 test_expect_success 'add sub3' '
         create sub3 &&
         git commit -m "sub3"
@@ -419,20 +371,17 @@ test_expect_success 'add sub3' '
 
 cd ../main
 
-# 48
 test_expect_success 'merge from sub' '
         git fetch ../sub master &&
         git branch sub3 FETCH_HEAD &&
         git subtree merge --prefix subdir sub3
 '
 
-# 49
 test_expect_success 'add main-sub4' '
         create subdir/main-sub4 &&
         git commit -m "main-sub4"
 '
 
-# 50
 test_expect_success 'split for main-sub4 without --onto' '
         git subtree split --prefix subdir --branch mainsub4
 '
@@ -442,19 +391,16 @@ test_expect_success 'split for main-sub4 without --onto' '
 # have been sub3, but it was not, because its cache was not set to
 # itself)
 
-# 51
 test_expect_success 'check that the commit parent is sub3' '
         check_equal ''"$(git log --pretty=format:%P -1 mainsub4)"'' ''"$(git rev-parse sub3)"''
 '
 
-# 52
 test_expect_success 'add main-sub5' '
         mkdir subdir2 &&
         create subdir2/main-sub5 &&
         git commit -m "main-sub5"
 '
 
-# 53
 test_expect_success 'split for main-sub5 without --onto' '
         # also test that we still can split out an entirely new subtree
         # if the parent of the first commit in the tree is not empty,
@@ -487,7 +433,6 @@ joincommits()
 	echo "$commit $all"
 }
 
-# 54
 test_expect_success 'verify one file change per commit' '
         x= &&
         list=''"$(git log --pretty=format:'"'commit: %H'"' | joincommits)"'' &&
-- 
1.8.1

^ permalink raw reply related

* [PATCH/RFC 4/7] contrib/subtree: Code cleaning and refactoring
From: Techlive Zheng @ 2013-01-13  1:52 UTC (permalink / raw)
  To: git, gitster; +Cc: apenwarr, greened, Techlive Zheng
In-Reply-To: <1358041958-1998-1-git-send-email-techlivezheng@gmail.com>

Mostly prepare for the later tests refactoring.

Signed-off-by: Techlive Zheng <techlivezheng@gmail.com>
---
 contrib/subtree/git-subtree.sh     |  66 ++++-----
 contrib/subtree/t/t7900-subtree.sh | 283 +++++++++++++++++++------------------
 2 files changed, 179 insertions(+), 170 deletions(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 138e1e0..91e6e87 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -5,7 +5,7 @@
 # Copyright (C) 2009 Avery Pennarun <apenwarr@gmail.com>
 #
 if [ $# -eq 0 ]; then
-    set -- -h
+	set -- -h
 fi
 OPTS_SPEC="\
 git subtree add   --prefix=<prefix> <commit>
@@ -110,9 +110,9 @@ if [ -z "$prefix" ]; then
 fi
 
 case "$command" in
-	add) [ -e "$prefix" ] && 
+	add) [ -e "$prefix" ] &&
 		die "prefix '$prefix' already exists." ;;
-	*)   [ -e "$prefix" ] || 
+	*)   [ -e "$prefix" ] ||
 		die "'$prefix' does not exist; use 'git subtree add'" ;;
 esac
 
@@ -181,8 +181,8 @@ cache_set()
 	oldrev="$1"
 	newrev="$2"
 	if [ "$oldrev" != "latest_old" \
-	     -a "$oldrev" != "latest_new" \
-	     -a -e "$cachedir/$oldrev" ]; then
+		-a "$oldrev" != "latest_new" \
+		-a -e "$cachedir/$oldrev" ]; then
 		die "cache for $oldrev already exists!"
 	fi
 	echo "$newrev" >"$cachedir/$oldrev"
@@ -327,7 +327,7 @@ add_msg()
 	fi
 	cat <<-EOF
 		$commit_message
-		
+
 		git-subtree-dir: $dir
 		git-subtree-mainline: $latest_old
 		git-subtree-split: $latest_new
@@ -355,7 +355,7 @@ rejoin_msg()
 	fi
 	cat <<-EOF
 		$commit_message
-		
+
 		git-subtree-dir: $dir
 		git-subtree-mainline: $latest_old
 		git-subtree-split: $latest_new
@@ -368,7 +368,7 @@ squash_msg()
 	oldsub="$2"
 	newsub="$3"
 	newsub_short=$(git rev-parse --short "$newsub")
-	
+
 	if [ -n "$oldsub" ]; then
 		oldsub_short=$(git rev-parse --short "$oldsub")
 		echo "Squashed '$dir/' changes from $oldsub_short..$newsub_short"
@@ -378,7 +378,7 @@ squash_msg()
 	else
 		echo "Squashed '$dir/' content from commit $newsub_short"
 	fi
-	
+
 	echo
 	echo "git-subtree-dir: $dir"
 	echo "git-subtree-split: $newsub"
@@ -427,7 +427,7 @@ new_squash_commit()
 	newsub="$3"
 	tree=$(toptree_for_commit $newsub) || exit $?
 	if [ -n "$old" ]; then
-		squash_msg "$dir" "$oldsub" "$newsub" | 
+		squash_msg "$dir" "$oldsub" "$newsub" |
 			git commit-tree "$tree" -p "$old" || exit $?
 	else
 		squash_msg "$dir" "" "$newsub" |
@@ -455,7 +455,7 @@ copy_or_skip()
 		else
 			nonidentical="$parent"
 		fi
-		
+
 		# sometimes both old parents map to the same newparent;
 		# eliminate duplicates
 		is_new=1
@@ -470,7 +470,7 @@ copy_or_skip()
 			p="$p -p $parent"
 		fi
 	done
-	
+
 	if [ -n "$identical" ]; then
 		echo $identical
 	else
@@ -495,14 +495,14 @@ cmd_add()
 	fi
 
 	ensure_clean
-	
+
 	if [ $# -eq 1 ]; then
 		"cmd_add_commit" "$@"
 	elif [ $# -eq 2 ]; then
 		"cmd_add_repository" "$@"
 	else
-	    say "error: parameters were '$@'"
-	    die "Provide either a refspec or a repository and refspec."
+		say "error: parameters were '$@'"
+		die "Provide either a refspec or a repository and refspec."
 	fi
 }
 
@@ -522,19 +522,19 @@ cmd_add_commit()
 	revs=$(git rev-parse $default --revs-only "$@") || exit $?
 	set -- $revs
 	rev="$1"
-	
+
 	debug "Adding $dir as '$rev'..."
 	git read-tree --prefix="$dir" $rev || exit $?
 	git checkout -- "$dir" || exit $?
 	tree=$(git write-tree) || exit $?
-	
+
 	headrev=$(git rev-parse HEAD) || exit $?
 	if [ -n "$headrev" -a "$headrev" != "$rev" ]; then
 		headp="-p $headrev"
 	else
 		headp=
 	fi
-	
+
 	if [ -n "$squash" ]; then
 		rev=$(new_squash_commit "" "" "$rev") || exit $?
 		commit=$(add_squashed_msg "$rev" "$dir" |
@@ -544,7 +544,7 @@ cmd_add_commit()
 			 git commit-tree $tree $headp -p "$rev") || exit $?
 	fi
 	git reset "$commit" || exit $?
-	
+
 	say "Added dir '$dir'"
 }
 
@@ -552,7 +552,7 @@ cmd_split()
 {
 	debug "Splitting $dir..."
 	cache_setup || exit $?
-	
+
 	if [ -n "$onto" ]; then
 		debug "Reading history for --onto=$onto..."
 		git rev-list $onto |
@@ -563,13 +563,13 @@ cmd_split()
 			cache_set $rev $rev
 		done
 	fi
-	
+
 	if [ -n "$ignore_joins" ]; then
 		unrevs=
 	else
 		unrevs="$(find_existing_splits "$dir" "$revs")"
 	fi
-	
+
 	# We can't restrict rev-list to only $dir here, because some of our
 	# parents have the $dir contents the root, and those won't match.
 	# (and rev-list --follow doesn't seem to solve this)
@@ -591,12 +591,12 @@ cmd_split()
 		debug "  parents: $parents"
 		newparents=$(cache_get $parents)
 		debug "  newparents: $newparents"
-		
+
 		tree=$(subtree_for_commit $rev "$dir")
 		debug "  tree is: $tree"
 
 		check_parents $parents
-		
+
 		# ugly.  is there no better way to tell if this is a subtree
 		# vs. a mainline commit?  Does it matter?
 		if [ -z $tree ]; then
@@ -617,7 +617,7 @@ cmd_split()
 	if [ -z "$latest_new" ]; then
 		die "No new revisions were found"
 	fi
-	
+
 	if [ -n "$rejoin" ]; then
 		debug "Merging split branch into HEAD..."
 		latest_old=$(cache_get latest_old)
@@ -645,13 +645,13 @@ cmd_merge()
 {
 	revs=$(git rev-parse $default --revs-only "$@") || exit $?
 	ensure_clean
-	
+
 	set -- $revs
 	if [ $# -ne 1 ]; then
 		die "You must provide exactly one revision.  Got: '$revs'"
 	fi
 	rev="$1"
-	
+
 	if [ -n "$squash" ]; then
 		first_split="$(find_latest_squash "$dir")"
 		if [ -z "$first_split" ]; then
@@ -697,15 +697,15 @@ cmd_pull()
 cmd_push()
 {
 	if [ $# -ne 2 ]; then
-	    die "You must provide <repository> <refspec>"
+		die "You must provide <repository> <refspec>"
 	fi
 	if [ -e "$dir" ]; then
-	    repository=$1
-	    refspec=$2
-	    echo "git push using: " $repository $refspec
-	    git push $repository $(git subtree split --prefix=$prefix):refs/heads/$refspec
+		repository=$1
+		refspec=$2
+		echo "git push using: " $repository $refspec
+		git push $repository $(git subtree split --prefix=$prefix):refs/heads/$refspec
 	else
-	    die "'$dir' must already exist. Try 'git subtree add'."
+		die "'$dir' must already exist. Try 'git subtree add'."
 	fi
 }
 
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index abdcddb..bb4fd1f 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -4,7 +4,7 @@
 #
 test_description='Basic porcelain support for subtrees
 
-This test verifies the basic operation of the merge, pull, add
+This test verifies the basic operation of the add, pull, merge
 and split subcommands of git subtree.
 '
 
@@ -14,50 +14,73 @@ export TEST_DIRECTORY=$(pwd)/../../../t
 
 create()
 {
-	echo "$1" >"$1"
-	git add "$1"
+    echo "$1" >"$1"
+    git add "$1"
 }
 
+fixnl()
+{
+    t=""
+    while read x; do
+        t="$t$x "
+    done
+    echo $t
+}
 
-check_equal()
+multiline()
 {
-	test_debug 'echo'
-	test_debug "echo \"check a:\" \"{$1}\""
-	test_debug "echo \"      b:\" \"{$2}\""
-	if [ "$1" = "$2" ]; then
-		return 0
-	else
-		return 1
-	fi
+    while read x; do
+        set -- $x
+        for d in "$@"; do
+            echo "$d"
+        done
+    done
 }
 
-fixnl()
+undo()
 {
-	t=""
-	while read x; do
-		t="$t$x "
-	done
-	echo $t
+    git reset --hard HEAD~
 }
 
-multiline()
+test_equal()
 {
-	while read x; do
-		set -- $x
-		for d in "$@"; do
-			echo "$d"
-		done
-	done
+    test_debug 'echo'
+    test_debug "echo \"check a:\" \"{$1}\""
+    test_debug "echo \"      b:\" \"{$2}\""
+    if [ "$1" = "$2" ]; then
+        return 0
+    else
+        return 1
+    fi
 }
 
-undo()
+# Make sure no patch changes more than one file.
+# The original set of commits changed only one file each.
+# A multi-file change would imply that we pruned commits
+# too aggressively.
+join_commits()
 {
-	git reset --hard HEAD~
+    commit=
+    all=
+    while read x y; do
+        if [ -z "$x" ]; then
+            continue
+        elif [ "$x" = "commit:" ]; then
+            if [ -n "$commit" ]; then
+                echo "$commit $all"
+                all=
+            fi
+            commit="$y"
+        else
+            all="$all $y"
+        fi
+    done
+    echo "$commit $all"
 }
 
 last_commit_message()
 {
-	git log --pretty=format:%s -1
+    git log --pretty=format:%s -1
 }
 
 test_expect_success 'init subproj' '
@@ -93,7 +116,7 @@ test_expect_success 'add main4' '
         create main4 &&
         git commit -m "main4" &&
         git branch -m master mainline &&
-        git branch subdir
+        git branch init
 '
 
 test_expect_success 'fetch subproj history' '
@@ -101,40 +124,43 @@ test_expect_success 'fetch subproj history' '
         git branch sub1 FETCH_HEAD
 '
 
-test_expect_success 'no subtree exists in main tree' '
-        test_must_fail git subtree merge --prefix=subdir sub1
-'
-
 test_expect_success 'no pull from non-existant subtree' '
         test_must_fail git subtree pull --prefix=subdir ./subproj sub1
 '
 
-test_expect_success 'check if --message works for add' '
-        git subtree add --prefix=subdir --message="Added subproject" sub1 &&
-        check_equal ''"$(last_commit_message)"'' "Added subproject" &&
+test_expect_success 'no merge from non-existant subtree' '
+        test_must_fail git subtree merge --prefix=subdir FETCH_HEAD
+'
+
+test_expect_success 'add subproj as subtree into subdir/ with --prefix' '
+        git subtree add --prefix=subdir FETCH_HEAD &&
+        test_equal "$(last_commit_message)" "Add '\''subdir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''" &&
         undo
 '
 
-test_expect_success 'check if --message works as -m and --prefix as -P' '
-        git subtree add -P subdir -m "Added subproject using git subtree" sub1 &&
-        check_equal ''"$(last_commit_message)"'' "Added subproject using git subtree" &&
+test_expect_success 'add subproj as subtree into subdir/ with --prefix and --message' '
+        git subtree add --prefix=subdir --message="Added subproject" FETCH_HEAD &&
+        test_equal "$(last_commit_message)" "Added subproject" &&
         undo
 '
 
-test_expect_success 'check if --message works with squash too' '
-        git subtree add -P subdir -m "Added subproject with squash" --squash sub1 &&
-        check_equal ''"$(last_commit_message)"'' "Added subproject with squash" &&
+test_expect_success 'add subproj as subtree into subdir/ with --prefix as -P and --message as -m' '
+        git subtree add -P subdir -m "Added subproject" FETCH_HEAD &&
+        test_equal "$(last_commit_message)" "Added subproject" &&
         undo
 '
 
-test_expect_success 'add subproj to mainline' '
-        git subtree add --prefix=subdir/ FETCH_HEAD &&
-        check_equal ''"$(last_commit_message)"'' "Add '"'subdir/'"' from commit '"'"'''"$(git rev-parse sub1)"'''"'"'"
+test_expect_success 'add subproj as subtree into subdir/ with --squash and --prefix and --message' '
+        git subtree add --prefix=subdir --message="Added subproject with squash" --squash FETCH_HEAD &&
+        test_equal "$(last_commit_message)" "Added subproject with squash" &&
+        undo
 '
 
-# this shouldn't actually do anything, since FETCH_HEAD is already a parent
-test_expect_success 'merge fetched subproj' '
-        git merge -m "merge -s -ours" -s ours FETCH_HEAD
+test_expect_success 'merge the added subproj again, should do nothing' '
+        git subtree add --prefix=subdir FETCH_HEAD &&
+        # this shouldn not actually do anything, since FETCH_HEAD
+        # is already a parent
+        git merge -s ours -m "merge -s -ours" FETCH_HEAD
 '
 
 test_expect_success 'add main-sub5' '
@@ -157,25 +183,30 @@ test_expect_success 'fetch new subproj history' '
         git branch sub2 FETCH_HEAD
 '
 
-test_expect_success 'check if --message works for merge' '
-        git subtree merge --prefix=subdir -m "Merged changes from subproject" sub2 &&
-        check_equal ''"$(last_commit_message)"'' "Merged changes from subproject" &&
+test_expect_success 'merge new subproj history into subdir/ with --prefix' '
+        git subtree merge --prefix=subdir FETCH_HEAD &&
+        test_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\'' into mainline" &&
+        undo
+'
+
+test_expect_success 'merge new subproj history into subdir/ with --prefix and --message' '
+        git subtree merge --prefix=subdir --message="Merged changes from subproject" FETCH_HEAD &&
+        test_equal "$(last_commit_message)" "Merged changes from subproject" &&
         undo
 '
 
-test_expect_success 'check if --message for merge works with squash too' '
-        git subtree merge --prefix subdir -m "Merged changes from subproject using squash" --squash sub2 &&
-        check_equal ''"$(last_commit_message)"'' "Merged changes from subproject using squash" &&
+test_expect_success 'merge new subproj history into subdir/ with --squash and --prefix and --message' '
+        git subtree merge --prefix=subdir --message="Merged changes from subproject using squash" --squash FETCH_HEAD &&
+        test_equal "$(last_commit_message)" "Merged changes from subproject using squash" &&
         undo
 '
 
-test_expect_success 'merge new subproj history into subdir' '
+test_expect_success 'merge new subproj history into subdir/' '
         git subtree merge --prefix=subdir FETCH_HEAD &&
-        git branch pre-split &&
-        check_equal ''"$(last_commit_message)"'' "Merge commit '"'"'"$(git rev-parse sub2)"'"'"' into mainline"
+        git branch pre-split
 '
 
-test_expect_success 'Check that prefix argument is required for split' '
+test_expect_success 'split requires option --prefix' '
         echo "You must provide the --prefix option." > expected &&
         test_must_fail git subtree split > actual 2>&1 &&
         test_debug "echo -n expected: " &&
@@ -186,48 +217,52 @@ test_expect_success 'Check that prefix argument is required for split' '
         rm -f expected actual
 '
 
-test_expect_success 'Check that the <prefix> exists for a split' '
-        echo "'"'"'non-existent-directory'"'"'" does not exist\; use "'"'"'git subtree add'"'"'" > expected &&
+test_expect_success 'split requires path given by option --prefix must exist' '
+        echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" > expected &&
         test_must_fail git subtree split --prefix=non-existent-directory > actual 2>&1 &&
         test_debug "echo -n expected: " &&
         test_debug "cat expected" &&
         test_debug "echo -n actual: " &&
         test_debug "cat actual" &&
-        test_cmp expected actual
-#        rm -f expected actual
+        test_cmp expected actual &&
+        rm -f expected actual
 '
 
-test_expect_success 'check if --message works for split+rejoin' '
-        spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
+test_expect_success 'split subdir/ with --rejoin' '
+        spl1=$(git subtree split --prefix=subdir --annotate="*") &&
         git branch spl1 "$spl1" &&
-        check_equal ''"$(last_commit_message)"'' "Split & rejoin" &&
+        git subtree split --prefix=subdir --annotate="*" --rejoin &&
+        test_equal "$(last_commit_message)" "Split '\''subdir/'\'' into commit '\''$spl1'\''" &&
         undo
 '
 
-test_expect_success 'check split with --branch' '
-        spl1=$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin) &&
+test_expect_success 'split subdir/ with --rejoin and --message' '
+        git subtree split --prefix=subdir --message="Split & rejoin" --annotate="*" --rejoin &&
+        test_equal "$(last_commit_message)" "Split & rejoin" &&
+        undo
+'
+
+test_expect_success 'split subdir/ with --branch' '
+        spl1=$(git subtree split --prefix=subdir --message="Split & rejoin" --annotate="*" --rejoin) &&
         undo &&
-        git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --branch splitbr1 &&
-        check_equal ''"$(git rev-parse splitbr1)"'' "$spl1"
+        git subtree split --prefix=subdir --annotate="*" --branch splitbr1 &&
+        test_equal "$(git rev-parse splitbr1)" "$spl1"
 '
 
-test_expect_success 'check split with --branch for an existing branch' '
-        spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
+test_expect_success 'split subdir/ with --branch for an existing branch' '
+        spl1=$(git subtree split --prefix=subdir --annotate="*" --message="Split & rejoin" --rejoin) &&
         undo &&
         git branch splitbr2 sub1 &&
-        git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --branch splitbr2 &&
-        check_equal ''"$(git rev-parse splitbr2)"'' "$spl1"
+        git subtree split --prefix=subdir --annotate="*" --branch splitbr2 &&
+        test_equal "$(git rev-parse splitbr2)" "$spl1"
 '
 
-test_expect_success 'check split with --branch for an incompatible branch' '
-        test_must_fail git subtree split --prefix subdir --onto FETCH_HEAD --branch subdir
+test_expect_success 'split subdir/ with --branch for an incompatible branch' '
+        test_must_fail git subtree split --prefix=subdir --branch init
 '
 
-test_expect_success 'check split+rejoin' '
-        spl1=''"$(git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)"'' &&
-        undo &&
-        git subtree split --annotate='"'*'"' --prefix subdir --onto FETCH_HEAD --rejoin &&
-        check_equal ''"$(last_commit_message)"'' "Split '"'"'subdir/'"'"' into commit '"'"'"$spl1"'"'"'"
+test_expect_success 'split and rejoin' '
+        git subtree split --prefix=subdir --annotate="*" --rejoin
 '
 
 test_expect_success 'add main-sub8' '
@@ -253,8 +288,8 @@ test_expect_success 'add sub9' '
 cd ..
 
 test_expect_success 'split for sub8' '
-        split2=''"$(git subtree split --annotate='"'*'"' --prefix subdir/ --rejoin)"''
-        git branch split2 "$split2"
+        spl2=$(git subtree split --prefix=subdir/ --annotate="*" --rejoin) &&
+        git branch spl2 "$spl2"
 '
 
 test_expect_success 'add main-sub10' '
@@ -263,7 +298,7 @@ test_expect_success 'add main-sub10' '
 '
 
 test_expect_success 'split for sub10' '
-        spl3=''"$(git subtree split --annotate='"'*'"' --prefix subdir --rejoin)"'' &&
+        spl3=$(git subtree split --prefix=subdir --annotate="*" --rejoin) &&
         git branch spl3 "$spl3"
 '
 
@@ -284,13 +319,13 @@ chks="sub1 sub2 sub3 sub9"
 chks_sub=$(echo $chks | multiline | sed 's,^,subdir/,' | fixnl)
 
 test_expect_success 'make sure exactly the right set of files ends up in the subproj' '
-        subfiles=''"$(git ls-files | fixnl)"'' &&
-        check_equal "$subfiles" "$chkms $chks"
+        subfiles=$(git ls-files | fixnl) &&
+        test_equal "$subfiles" "$chkms $chks"
 '
 
-test_expect_success 'make sure the subproj history *only* contains commits that affect the subdir' '
-        allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | fixnl)"'' &&
-        check_equal "$allchanges" "$chkms $chks"
+test_expect_success 'make sure the subproj *only* contains commits that affect the subdir' '
+        allchanges=$(git log --name-only --pretty=format:"" | sort | fixnl) &&
+        test_equal "$allchanges" "$chkms $chks"
 '
 
 # Back to mainline
@@ -303,25 +338,25 @@ test_expect_success 'pull from subproj' '
 '
 
 test_expect_success 'make sure exactly the right set of files ends up in the mainline' '
-        mainfiles=''"$(git ls-files | fixnl)"'' &&
-        check_equal "$mainfiles" "$chkm $chkms_sub $chks_sub"
+        mainfiles=$(git ls-files | fixnl) &&
+        test_equal "$mainfiles" "$chkm $chkms_sub $chks_sub"
 '
 
 test_expect_success 'make sure each filename changed exactly once in the entire history' '
         # main-sub?? and /subdir/main-sub?? both change, because those are the
         # changes that were split into their own history.  And subdir/sub?? never
         # change, since they were *only* changed in the subtree branch.
-        allchanges=''"$(git log --name-only --pretty=format:'"''"' | sort | fixnl)"'' &&
-        check_equal "$allchanges" ''"$(echo $chkms $chkm $chks $chkms_sub | multiline | sort | fixnl)"''
+        allchanges=$(git log --name-only --pretty=format:"" | sort | fixnl) &&
+        test_equal "$allchanges" "$(echo $chkms $chkm $chks $chkms_sub | multiline | sort | fixnl)"
 '
 
 test_expect_success 'make sure the --rejoin commits never make it into subproj' '
-        check_equal ''"$(git log --pretty=format:'"'%s'"' HEAD^2 | grep -i split)"'' ""
+        test_equal "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" ""
 '
 
 test_expect_success 'make sure no "git subtree" tagged commits make it into subproj' '
         # They are meaningless to subproj since one side of the merge refers to the mainline
-        check_equal ''"$(git log --pretty=format:'"'%s%n%b'"' HEAD^2 | grep "git-subtree.*:")"'' ""
+        test_equal "$(git log --pretty=format:"%s%n%b" HEAD^2 | grep "git-subtree.*:")" ""
 '
 
 # prepare second pair of repositories
@@ -359,7 +394,7 @@ cd ../main
 test_expect_success 'add sub as subdir in main' '
         git fetch ../sub master &&
         git branch sub2 FETCH_HEAD &&
-        git subtree add --prefix subdir sub2
+        git subtree add --prefix=subdir sub2
 '
 
 cd ../sub
@@ -374,7 +409,7 @@ cd ../main
 test_expect_success 'merge from sub' '
         git fetch ../sub master &&
         git branch sub3 FETCH_HEAD &&
-        git subtree merge --prefix subdir sub3
+        git subtree merge --prefix=subdir sub3
 '
 
 test_expect_success 'add main-sub4' '
@@ -383,7 +418,7 @@ test_expect_success 'add main-sub4' '
 '
 
 test_expect_success 'split for main-sub4 without --onto' '
-        git subtree split --prefix subdir --branch mainsub4
+        git subtree split --prefix=subdir --branch mainsub4
 '
 
 # at this point, the new commit parent should be sub3 if it is not,
@@ -392,7 +427,7 @@ test_expect_success 'split for main-sub4 without --onto' '
 # itself)
 
 test_expect_success 'check that the commit parent is sub3' '
-        check_equal ''"$(git log --pretty=format:%P -1 mainsub4)"'' ''"$(git rev-parse sub3)"''
+        test_equal "$(git log --pretty=format:%P -1 mainsub4)" "$(git rev-parse sub3)"
 '
 
 test_expect_success 'add main-sub5' '
@@ -405,49 +440,23 @@ test_expect_success 'split for main-sub5 without --onto' '
         # also test that we still can split out an entirely new subtree
         # if the parent of the first commit in the tree is not empty,
         # then the new subtree has accidently been attached to something
-        git subtree split --prefix subdir2 --branch mainsub5 &&
-        check_equal ''"$(git log --pretty=format:%P -1 mainsub5)"'' ""
+        git subtree split --prefix=subdir2 --branch mainsub5 &&
+        test_equal "$(git log --pretty=format:%P -1 mainsub5)" ""
 '
 
-# make sure no patch changes more than one file.  The original set of commits
-# changed only one file each.  A multi-file change would imply that we pruned
-# commits too aggressively.
-joincommits()
-{
-	commit=
-	all=
-	while read x y; do
-		#echo "{$x}" >&2
-		if [ -z "$x" ]; then
-			continue
-		elif [ "$x" = "commit:" ]; then
-			if [ -n "$commit" ]; then
-				echo "$commit $all"
-				all=
-			fi
-			commit="$y"
-		else
-			all="$all $y"
-		fi
-	done
-	echo "$commit $all"
-}
-
 test_expect_success 'verify one file change per commit' '
         x= &&
-        list=''"$(git log --pretty=format:'"'commit: %H'"' | joincommits)"'' &&
-#        test_debug "echo HERE" &&
-#        test_debug "echo ''"$list"''" &&
-        (git log --pretty=format:'"'commit: %H'"' | joincommits |
-        (       while read commit a b; do
-		        test_debug "echo Verifying commit "''"$commit"''
-		        test_debug "echo a: "''"$a"''
-		        test_debug "echo b: "''"$b"''
-		        check_equal "$b" ""
-		        x=1
-	        done
-	        check_equal "$x" 1
-        ))
+        git log --pretty=format:"commit: %H" | join_commits |
+        (
+            while read commit a b; do
+                test_debug "echo Verifying commit $commit"
+                test_debug "echo a: $a"
+                test_debug "echo b: $b"
+                test_equal "$b" ""
+                x=1
+            done
+            test_equal "$x" 1
+        )
 '
 
 test_done
-- 
1.8.1

^ permalink raw reply related

* [PATCH/RFC 5/7] contrib/subtree: Make each test self-contained
From: Techlive Zheng @ 2013-01-13  1:52 UTC (permalink / raw)
  To: git, gitster; +Cc: apenwarr, greened, Techlive Zheng
In-Reply-To: <1358041958-1998-1-git-send-email-techlivezheng@gmail.com>

Signed-off-by: Techlive Zheng <techlivezheng@gmail.com>
---
 contrib/subtree/t/t7900-subtree.sh | 865 ++++++++++++++++++++++++++-----------
 1 file changed, 614 insertions(+), 251 deletions(-)

diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index bb4fd1f..ece2064 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -12,12 +12,6 @@ export TEST_DIRECTORY=$(pwd)/../../../t
 
 . ../../../t/test-lib.sh
 
-create()
-{
-    echo "$1" >"$1"
-    git add "$1"
-}
-
 fixnl()
 {
     t=""
@@ -37,11 +31,6 @@ multiline()
     done
 }
 
-undo()
-{
-    git reset --hard HEAD~
-}
-
 test_equal()
 {
     test_debug 'echo'
@@ -78,373 +67,746 @@ join_commits()
     echo "$commit $all"
 }
 
+test_create_commit() (
+    repo=$1
+    commit=$2
+    cd "$repo"
+    mkdir -p "$(dirname "$commit")"
+    echo "$commit" > "$commit"
+    git add "$commit"
+    git commit -m "$commit"
+)
+
 last_commit_message()
 {
     git log --pretty=format:%s -1
 }
 
-test_expect_success 'init subproj' '
-        test_create_repo subproj
-'
-
-# To the subproject!
-cd subproj
-
-test_expect_success 'add sub1' '
-        create sub1 &&
-        git commit -m "sub1" &&
-        git branch sub1 &&
-        git branch -m master subproj
-'
-
-test_expect_success 'add sub2' '
-        create sub2 &&
-        git commit -m "sub2" &&
-        git branch sub2
-'
-
-test_expect_success 'add sub3' '
-        create sub3 &&
-        git commit -m "sub3" &&
-        git branch sub3
-'
-
-# Back to mainline
-cd ..
-
-test_expect_success 'add main4' '
-        create main4 &&
-        git commit -m "main4" &&
-        git branch -m master mainline &&
-        git branch init
-'
-
-test_expect_success 'fetch subproj history' '
-        git fetch ./subproj sub1 &&
-        git branch sub1 FETCH_HEAD
-'
+#
+# Tests for 'git subtree add'
+#
 
 test_expect_success 'no pull from non-existant subtree' '
-        test_must_fail git subtree pull --prefix=subdir ./subproj sub1
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        test_must_fail git subtree pull --prefix=subdir ./subproj master
+    )
 '
 
 test_expect_success 'no merge from non-existant subtree' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
         test_must_fail git subtree merge --prefix=subdir FETCH_HEAD
+    )
 '
 
 test_expect_success 'add subproj as subtree into subdir/ with --prefix' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
         git subtree add --prefix=subdir FETCH_HEAD &&
-        test_equal "$(last_commit_message)" "Add '\''subdir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''" &&
-        undo
+        test_equal "$(last_commit_message)" "Add '\''subdir/'\'' from commit '\''$(git rev-parse FETCH_HEAD)'\''"
+    )
 '
 
 test_expect_success 'add subproj as subtree into subdir/ with --prefix and --message' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
         git subtree add --prefix=subdir --message="Added subproject" FETCH_HEAD &&
-        test_equal "$(last_commit_message)" "Added subproject" &&
-        undo
+        test_equal "$(last_commit_message)" "Added subproject"
+    )
 '
 
 test_expect_success 'add subproj as subtree into subdir/ with --prefix as -P and --message as -m' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
         git subtree add -P subdir -m "Added subproject" FETCH_HEAD &&
-        test_equal "$(last_commit_message)" "Added subproject" &&
-        undo
+        test_equal "$(last_commit_message)" "Added subproject"
+    )
 '
 
 test_expect_success 'add subproj as subtree into subdir/ with --squash and --prefix and --message' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
         git subtree add --prefix=subdir --message="Added subproject with squash" --squash FETCH_HEAD &&
-        test_equal "$(last_commit_message)" "Added subproject with squash" &&
-        undo
+        test_equal "$(last_commit_message)" "Added subproject with squash"
+    )
 '
 
 test_expect_success 'merge the added subproj again, should do nothing' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
         git subtree add --prefix=subdir FETCH_HEAD &&
         # this shouldn not actually do anything, since FETCH_HEAD
         # is already a parent
         git merge -s ours -m "merge -s -ours" FETCH_HEAD
+    )
 '
 
-test_expect_success 'add main-sub5' '
-        create subdir/main-sub5 &&
-        git commit -m "main-sub5"
-'
-
-test_expect_success 'add main6' '
-        create main6 &&
-        git commit -m "main6 boring"
-'
-
-test_expect_success 'add main-sub7' '
-        create subdir/main-sub7 &&
-        git commit -m "main-sub7"
-'
-
-test_expect_success 'fetch new subproj history' '
-        git fetch ./subproj sub2 &&
-        git branch sub2 FETCH_HEAD
-'
+#
+# Tests for 'git subtree merge'
+#
 
 test_expect_success 'merge new subproj history into subdir/ with --prefix' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
         git subtree merge --prefix=subdir FETCH_HEAD &&
-        test_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\'' into mainline" &&
-        undo
+        test_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+    )
 '
 
 test_expect_success 'merge new subproj history into subdir/ with --prefix and --message' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
         git subtree merge --prefix=subdir --message="Merged changes from subproject" FETCH_HEAD &&
-        test_equal "$(last_commit_message)" "Merged changes from subproject" &&
-        undo
+        test_equal "$(last_commit_message)" "Merged changes from subproject"
+    )
 '
 
 test_expect_success 'merge new subproj history into subdir/ with --squash and --prefix and --message' '
+    test_create_repo "$test_count/subproj" &&
+    test_create_repo "$test_count" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
         git subtree merge --prefix=subdir --message="Merged changes from subproject using squash" --squash FETCH_HEAD &&
-        test_equal "$(last_commit_message)" "Merged changes from subproject using squash" &&
-        undo
+        test_equal "$(last_commit_message)" "Merged changes from subproject using squash"
+    )
 '
 
-test_expect_success 'merge new subproj history into subdir/' '
-        git subtree merge --prefix=subdir FETCH_HEAD &&
-        git branch pre-split
-'
+#
+# Tests for 'git subtree split'
+#
 
 test_expect_success 'split requires option --prefix' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD &&
         echo "You must provide the --prefix option." > expected &&
         test_must_fail git subtree split > actual 2>&1 &&
         test_debug "echo -n expected: " &&
         test_debug "cat expected" &&
         test_debug "echo -n actual: " &&
         test_debug "cat actual" &&
-        test_cmp expected actual &&
-        rm -f expected actual
+        test_cmp expected actual
+    )
 '
 
 test_expect_success 'split requires path given by option --prefix must exist' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD &&
         echo "'\''non-existent-directory'\'' does not exist; use '\''git subtree add'\''" > expected &&
         test_must_fail git subtree split --prefix=non-existent-directory > actual 2>&1 &&
         test_debug "echo -n expected: " &&
         test_debug "cat expected" &&
         test_debug "echo -n actual: " &&
         test_debug "cat actual" &&
-        test_cmp expected actual &&
-        rm -f expected actual
+        test_cmp expected actual
+    )
 '
 
 test_expect_success 'split subdir/ with --rejoin' '
-        spl1=$(git subtree split --prefix=subdir --annotate="*") &&
-        git branch spl1 "$spl1" &&
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub1 &&
+    test_create_commit "$test_count" main2 &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    test_create_commit "$test_count" subdir/main-sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree merge --prefix=subdir FETCH_HEAD &&
+        split_hash=$(git subtree split --prefix=subdir --annotate="*") &&
         git subtree split --prefix=subdir --annotate="*" --rejoin &&
-        test_equal "$(last_commit_message)" "Split '\''subdir/'\'' into commit '\''$spl1'\''" &&
-        undo
+        test_equal "$(last_commit_message)" "Split '\''subdir/'\'' into commit '\''$split_hash'\''"
+    )
 '
 
 test_expect_success 'split subdir/ with --rejoin and --message' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub1 &&
+    test_create_commit "$test_count" main2 &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    test_create_commit "$test_count" subdir/main-sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree merge --prefix=subdir FETCH_HEAD &&
         git subtree split --prefix=subdir --message="Split & rejoin" --annotate="*" --rejoin &&
-        test_equal "$(last_commit_message)" "Split & rejoin" &&
-        undo
+        test_equal "$(last_commit_message)" "Split & rejoin"
+    )
 '
 
 test_expect_success 'split subdir/ with --branch' '
-        spl1=$(git subtree split --prefix=subdir --message="Split & rejoin" --annotate="*" --rejoin) &&
-        undo &&
-        git subtree split --prefix=subdir --annotate="*" --branch splitbr1 &&
-        test_equal "$(git rev-parse splitbr1)" "$spl1"
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub1 &&
+    test_create_commit "$test_count" main2 &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    test_create_commit "$test_count" subdir/main-sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree merge --prefix=subdir FETCH_HEAD &&
+        split_hash=$(git subtree split --prefix=subdir --annotate="*") &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br &&
+        test_equal "$(git rev-parse subproj-br)" "$split_hash"
+    )
 '
 
 test_expect_success 'split subdir/ with --branch for an existing branch' '
-        spl1=$(git subtree split --prefix=subdir --annotate="*" --message="Split & rejoin" --rejoin) &&
-        undo &&
-        git branch splitbr2 sub1 &&
-        git subtree split --prefix=subdir --annotate="*" --branch splitbr2 &&
-        test_equal "$(git rev-parse splitbr2)" "$spl1"
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git branch subproj-br FETCH_HEAD &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub1 &&
+    test_create_commit "$test_count" main2 &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    test_create_commit "$test_count" subdir/main-sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree merge --prefix=subdir FETCH_HEAD &&
+        split_hash=$(git subtree split --prefix=subdir --annotate="*") &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br &&
+        test_equal "$(git rev-parse subproj-br)" "$split_hash"
+    )
 '
 
 test_expect_success 'split subdir/ with --branch for an incompatible branch' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git branch init HEAD &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub1 &&
+    test_create_commit "$test_count" main2 &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    test_create_commit "$test_count" subdir/main-sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree merge --prefix=subdir FETCH_HEAD &&
         test_must_fail git subtree split --prefix=subdir --branch init
+    )
 '
 
-test_expect_success 'split and rejoin' '
-        git subtree split --prefix=subdir --annotate="*" --rejoin
-'
-
-test_expect_success 'add main-sub8' '
-        create subdir/main-sub8 &&
-        git commit -m "main-sub8"
-'
-
-# To the subproject!
-cd ./subproj
-
-test_expect_success 'merge split into subproj' '
-        git fetch .. spl1 &&
-        git branch spl1 FETCH_HEAD &&
-        git merge FETCH_HEAD
-'
-
-test_expect_success 'add sub9' '
-        create sub9 &&
-        git commit -m "sub9"
-'
-
-# Back to mainline
-cd ..
-
-test_expect_success 'split for sub8' '
-        spl2=$(git subtree split --prefix=subdir/ --annotate="*" --rejoin) &&
-        git branch spl2 "$spl2"
-'
-
-test_expect_success 'add main-sub10' '
-        create subdir/main-sub10 &&
-        git commit -m "main-sub10"
-'
-
-test_expect_success 'split for sub10' '
-        spl3=$(git subtree split --prefix=subdir --annotate="*" --rejoin) &&
-        git branch spl3 "$spl3"
-'
-
-# To the subproject!
-cd ./subproj
-
-test_expect_success 'merge split into subproj' '
-        git fetch .. spl3 &&
-        git branch spl3 FETCH_HEAD &&
-        git merge FETCH_HEAD &&
-        git branch subproj-merge-spl3
-'
-
-chkm="main4 main6"
-chkms="main-sub10 main-sub5 main-sub7 main-sub8"
-chkms_sub=$(echo $chkms | multiline | sed 's,^,subdir/,' | fixnl)
-chks="sub1 sub2 sub3 sub9"
-chks_sub=$(echo $chks | multiline | sed 's,^,subdir/,' | fixnl)
+#
+# Validity checking
+#
 
 test_expect_success 'make sure exactly the right set of files ends up in the subproj' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub1 &&
+    test_create_commit "$test_count" main2 &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    test_create_commit "$test_count" subdir/main-sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree merge --prefix=subdir FETCH_HEAD &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    test_create_commit "$test_count/subproj" sub3 &&
+    test_create_commit "$test_count" subdir/main-sub3 &&
+    (
+        cd "$test_count/subproj" &&
+        git fetch .. subproj-br && git merge FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count/subproj" sub4 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub4 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    (
+        cd "$test_count/subproj" &&
+        git fetch .. subproj-br && git merge FETCH_HEAD &&
+
+        chks="sub1 sub2 sub3 sub4" &&
+        chks_sub=$(echo $chks | multiline | sed '\''s,^,subdir/,'\'' | fixnl) &&
+        chkms="main-sub1 main-sub2 main-sub3 main-sub4" &&
+        chkms_sub=$(echo $chkms | multiline | sed '\''s,^,subdir/,'\'' | fixnl) &&
+
         subfiles=$(git ls-files | fixnl) &&
         test_equal "$subfiles" "$chkms $chks"
+    )
 '
 
 test_expect_success 'make sure the subproj *only* contains commits that affect the subdir' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub1 &&
+    test_create_commit "$test_count" main2 &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    test_create_commit "$test_count" subdir/main-sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree merge --prefix=subdir FETCH_HEAD &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    test_create_commit "$test_count/subproj" sub3 &&
+    test_create_commit "$test_count" subdir/main-sub3 &&
+    (
+        cd "$test_count/subproj" &&
+        git fetch .. subproj-br && git merge FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count/subproj" sub4 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub4 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    (
+        cd "$test_count/subproj" &&
+        git fetch .. subproj-br && git merge FETCH_HEAD &&
+
+        chks="sub1 sub2 sub3 sub4" &&
+        chks_sub=$(echo $chks | multiline | sed '\''s,^,subdir/,'\'' | fixnl) &&
+        chkms="main-sub1 main-sub2 main-sub3 main-sub4" &&
+        chkms_sub=$(echo $chkms | multiline | sed '\''s,^,subdir/,'\'' | fixnl) &&
+
         allchanges=$(git log --name-only --pretty=format:"" | sort | fixnl) &&
         test_equal "$allchanges" "$chkms $chks"
-'
-
-# Back to mainline
-cd ..
-
-test_expect_success 'pull from subproj' '
-        git fetch ./subproj subproj-merge-spl3 &&
-        git branch subproj-merge-spl3 FETCH_HEAD &&
-        git subtree pull --prefix=subdir ./subproj subproj-merge-spl3
+    )
 '
 
 test_expect_success 'make sure exactly the right set of files ends up in the mainline' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub1 &&
+    test_create_commit "$test_count" main2 &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    test_create_commit "$test_count" subdir/main-sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree merge --prefix=subdir FETCH_HEAD &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    test_create_commit "$test_count/subproj" sub3 &&
+    test_create_commit "$test_count" subdir/main-sub3 &&
+    (
+        cd "$test_count/subproj" &&
+        git fetch .. subproj-br && git merge FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count/subproj" sub4 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub4 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    (
+        cd "$test_count/subproj" &&
+        git fetch .. subproj-br && git merge FETCH_HEAD
+    ) &&
+    (
+        cd "$test_count" &&
+        git subtree pull --prefix=subdir ./subproj master &&
+
+        chkm="main1 main2" &&
+        chks="sub1 sub2 sub3 sub4" &&
+        chks_sub=$(echo $chks | multiline | sed '\''s,^,subdir/,'\'' | fixnl) &&
+        chkms="main-sub1 main-sub2 main-sub3 main-sub4" &&
+        chkms_sub=$(echo $chkms | multiline | sed '\''s,^,subdir/,'\'' | fixnl) &&
+
         mainfiles=$(git ls-files | fixnl) &&
         test_equal "$mainfiles" "$chkm $chkms_sub $chks_sub"
+    )
 '
 
 test_expect_success 'make sure each filename changed exactly once in the entire history' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub1 &&
+    test_create_commit "$test_count" main2 &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    test_create_commit "$test_count" subdir/main-sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree merge --prefix=subdir FETCH_HEAD &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    test_create_commit "$test_count/subproj" sub3 &&
+    test_create_commit "$test_count" subdir/main-sub3 &&
+    (
+        cd "$test_count/subproj" &&
+        git fetch .. subproj-br && git merge FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count/subproj" sub4 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub4 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    (
+        cd "$test_count/subproj" &&
+        git fetch .. subproj-br && git merge FETCH_HEAD
+    ) &&
+    (
+        cd "$test_count" &&
+        git subtree pull --prefix=subdir ./subproj master &&
+
+        chkm="main1 main2" &&
+        chks="sub1 sub2 sub3 sub4" &&
+        chks_sub=$(echo $chks | multiline | sed '\''s,^,subdir/,'\'' | fixnl) &&
+        chkms="main-sub1 main-sub2 main-sub3 main-sub4" &&
+        chkms_sub=$(echo $chkms | multiline | sed '\''s,^,subdir/,'\'' | fixnl) &&
+
         # main-sub?? and /subdir/main-sub?? both change, because those are the
         # changes that were split into their own history.  And subdir/sub?? never
         # change, since they were *only* changed in the subtree branch.
         allchanges=$(git log --name-only --pretty=format:"" | sort | fixnl) &&
         test_equal "$allchanges" "$(echo $chkms $chkm $chks $chkms_sub | multiline | sort | fixnl)"
+    )
 '
 
 test_expect_success 'make sure the --rejoin commits never make it into subproj' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub1 &&
+    test_create_commit "$test_count" main2 &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    test_create_commit "$test_count" subdir/main-sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree merge --prefix=subdir FETCH_HEAD &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    test_create_commit "$test_count/subproj" sub3 &&
+    test_create_commit "$test_count" subdir/main-sub3 &&
+    (
+        cd "$test_count/subproj" &&
+        git fetch .. subproj-br && git merge FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count/subproj" sub4 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub4 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    (
+        cd "$test_count/subproj" &&
+        git fetch .. subproj-br && git merge FETCH_HEAD
+    ) &&
+    (
+        cd "$test_count" &&
+        git subtree pull --prefix=subdir ./subproj master &&
+
         test_equal "$(git log --pretty=format:"%s" HEAD^2 | grep -i split)" ""
+    )
 '
 
 test_expect_success 'make sure no "git subtree" tagged commits make it into subproj' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub1 &&
+    test_create_commit "$test_count" main2 &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    test_create_commit "$test_count" subdir/main-sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree merge --prefix=subdir FETCH_HEAD &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    test_create_commit "$test_count/subproj" sub3 &&
+    test_create_commit "$test_count" subdir/main-sub3 &&
+    (
+        cd "$test_count/subproj" &&
+        git fetch .. subproj-br && git merge FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count/subproj" sub4 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub4 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir --annotate="*" --branch subproj-br --rejoin
+    ) &&
+    (
+        cd "$test_count/subproj" &&
+        git fetch .. subproj-br && git merge FETCH_HEAD
+    ) &&
+    (
+        cd "$test_count" &&
+        git subtree pull --prefix=subdir ./subproj master &&
+
         # They are meaningless to subproj since one side of the merge refers to the mainline
         test_equal "$(git log --pretty=format:"%s%n%b" HEAD^2 | grep "git-subtree.*:")" ""
+    )
 '
 
-# prepare second pair of repositories
-mkdir test2
-cd test2
-
-test_expect_success 'init main' '
-        test_create_repo main
-'
-
-cd main
-
-test_expect_success 'add main1' '
-        create main1 &&
-        git commit -m "main1"
-'
-
-cd ..
-
-test_expect_success 'init sub' '
-        test_create_repo sub
-'
-
-cd sub
-
-test_expect_success 'add sub2' '
-        create sub2 &&
-        git commit -m "sub2"
-'
-
-cd ../main
-
-# check if split can find proper base without --onto
-
-test_expect_success 'add sub as subdir in main' '
-        git fetch ../sub master &&
-        git branch sub2 FETCH_HEAD &&
-        git subtree add --prefix=subdir sub2
-'
-
-cd ../sub
-
-test_expect_success 'add sub3' '
-        create sub3 &&
-        git commit -m "sub3"
-'
-
-cd ../main
-
-test_expect_success 'merge from sub' '
-        git fetch ../sub master &&
-        git branch sub3 FETCH_HEAD &&
-        git subtree merge --prefix=subdir sub3
-'
-
-test_expect_success 'add main-sub4' '
-        create subdir/main-sub4 &&
-        git commit -m "main-sub4"
-'
-
-test_expect_success 'split for main-sub4 without --onto' '
-        git subtree split --prefix=subdir --branch mainsub4
-'
-
-# at this point, the new commit parent should be sub3 if it is not,
-# something went wrong (the "newparent" of "master~" commit should
-# have been sub3, but it was not, because its cache was not set to
-# itself)
-
-test_expect_success 'check that the commit parent is sub3' '
-        test_equal "$(git log --pretty=format:%P -1 mainsub4)" "$(git rev-parse sub3)"
-'
+#
+# A new set of tests
+#
 
-test_expect_success 'add main-sub5' '
-        mkdir subdir2 &&
-        create subdir2/main-sub5 &&
-        git commit -m "main-sub5"
-'
+test_expect_success 'make sure "git subtree split" find the correct parent' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git branch subproj-ref FETCH_HEAD &&
+        git subtree merge --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub1 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir --branch subproj-br &&
+
+        # at this point, the new commit parent should be subproj-ref, if it is
+        # not, something went wrong (the "newparent" of "master~" commit should
+        # have been sub2, but it was not, because its cache was not set to
+        # itself)
+        test_equal "$(git log --pretty=format:%P -1 subproj-br)" "$(git rev-parse subproj-ref)"
+    )
+'
+
+test_expect_success 'split a new subtree without --onto option' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree merge --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub1 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir --branch subproj-br
+    ) &&
+    test_create_commit "$test_count" subdir2/main-sub2 &&
+    (
+        cd "$test_count" &&
 
-test_expect_success 'split for main-sub5 without --onto' '
         # also test that we still can split out an entirely new subtree
         # if the parent of the first commit in the tree is not empty,
         # then the new subtree has accidently been attached to something
-        git subtree split --prefix=subdir2 --branch mainsub5 &&
-        test_equal "$(git log --pretty=format:%P -1 mainsub5)" ""
+        git subtree split --prefix=subdir2 --branch subproj2-br &&
+        test_equal "$(git log --pretty=format:%P -1 subproj2-br)" ""
+    )
 '
 
 test_expect_success 'verify one file change per commit' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git branch sub1 FETCH_HEAD &&
+        git subtree add --prefix=subdir sub1
+    ) &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree merge --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub1 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir --branch subproj-br
+    ) &&
+    test_create_commit "$test_count" subdir2/main-sub2 &&
+    (
+        cd "$test_count" &&
+        git subtree split --prefix=subdir2 --branch subproj2-br &&
+
         x= &&
         git log --pretty=format:"commit: %H" | join_commits |
         (
@@ -457,6 +819,7 @@ test_expect_success 'verify one file change per commit' '
             done
             test_equal "$x" 1
         )
+    )
 '
 
 test_done
-- 
1.8.1

^ permalink raw reply related

* [PATCH/RFC 6/7] contrib/subtree: Use %B for the split commit message
From: Techlive Zheng @ 2013-01-13  1:52 UTC (permalink / raw)
  To: git, gitster; +Cc: apenwarr, greened, Techlive Zheng
In-Reply-To: <1358041958-1998-1-git-send-email-techlivezheng@gmail.com>

Use %B rather than %s%n%n%b to handle the special case of a commit that
only has a subject line.  We don't want to introduce a newline after the
subject, causing generation of a new hash.

After this commit, the newly split branch might differ from the previous
one. If this is the case, --fallback option could help.

Signed-off-by: Techlive Zheng <techlivezheng@gmail.com>
Signed-off-by: David A. Greene <greened@obbligato.org>
---
 contrib/subtree/git-subtree.sh     | 13 ++++++++++-
 contrib/subtree/git-subtree.txt    | 13 +++++++++++
 contrib/subtree/t/t7900-subtree.sh | 47 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 91e6e87..018ee32 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -25,6 +25,7 @@ b,branch=     create a new branch from the split subtree
 ignore-joins  ignore prior --rejoin commits
 onto=         try connecting new tree to an existing one
 rejoin        merge the new branch back into HEAD
+fallback      fallback to the obsolete commit generating mechanism
  options for 'add', 'merge', 'pull' and 'push'
 squash        merge subtree changes as a single commit
 "
@@ -45,6 +46,7 @@ ignore_joins=
 annotate=
 squash=
 message=
+fallback=
 
 debug()
 {
@@ -92,6 +94,8 @@ while [ $# -gt 0 ]; do
 		--no-ignore-joins) ignore_joins= ;;
 		--squash) squash=1 ;;
 		--no-squash) squash= ;;
+		--fallback) fallback=1 ;;
+		--no-fallback) fallback= ;;
 		--) break ;;
 		*) die "Unexpected option: $opt" ;;
 	esac
@@ -296,7 +300,14 @@ copy_commit()
 	# We're going to set some environment vars here, so
 	# do it in a subshell to get rid of them safely later
 	debug copy_commit "{$1}" "{$2}" "{$3}"
-	git log -1 --pretty=format:'%an%n%ae%n%ad%n%cn%n%ce%n%cd%n%s%n%n%b' "$1" |
+
+	if [ -z "$fallback" ]; then
+		log_format='%an%n%ae%n%ad%n%cn%n%ce%n%cd%n%B'
+	else
+		log_format='%an%n%ae%n%ad%n%cn%n%ce%n%cd%n%s%n%n%b'
+	fi
+
+	git log -1 --pretty=format:"$log_format" "$1" |
 	(
 		read GIT_AUTHOR_NAME
 		read GIT_AUTHOR_EMAIL
diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt
index c5bce41..ca9f199 100644
--- a/contrib/subtree/git-subtree.txt
+++ b/contrib/subtree/git-subtree.txt
@@ -254,6 +254,19 @@ OPTIONS FOR split
 	'--rejoin' when you split, because you don't want the
 	subproject's history to be part of your project anyway.
 
+--fallback::
+	Previously, git subtree would introduce an extra new line for
+	the commits whose commit message contains only one line.
+	This behavior has been correct. Unfortunately, for those whose
+	current split branch contains these kind of commits, git subtree
+	will generate a new split branch which differs from the existing
+	split branch in these commits. It is better to use this new
+	split branch, because its commits stay intact within the mainline.
+	
+	Otherwise, the previous fault behavior could still be used with
+	this option. This option is only for a compatible purpose, newly
+	split branch should never use this option.
+
 
 EXAMPLE 1. Add command
 ----------------------
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index ece2064..1492303 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -399,6 +399,53 @@ test_expect_success 'split subdir/ with --branch for an incompatible branch' '
     )
 '
 
+test_expect_success 'make sure commits with one line message stay intact after split' '
+    test_create_repo $test_count &&
+    test_create_repo $test_count/subproj &&
+    test_create_commit $test_count main1 &&
+    test_create_commit $test_count/subproj sub1 &&
+    (
+        cd $test_count &&
+        git fetch ./subproj master &&
+        ori_hash=$(git rev-parse FETCH_HEAD) &&
+        git branch subori FETCH_HEAD &&
+        git filter-branch --index-filter '\''git ls-files -s | sed "s-\t-&subdir/-" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"'\'' subori
+        git merge -m "Merge B project as our subdirectory" subori &&
+        git subtree split --prefix subdir --branch splitbr1 &&
+        new_hash_1=$(git rev-parse splitbr1) &&
+        test_equal "$ori_hash" "$new_hash_1" &&
+        git subtree split --prefix subdir --branch splitbr2 --fallback &&
+        new_hash_2=$(git rev-parse splitbr2) &&
+        test_must_fail test_equal "$ori_hash" "$new_hash_2"
+    )
+'
+
+test_expect_success 'make sure --fallback option works correctly for the existing split branch' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count"/subproj &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count"/subproj sub1 &&
+    (
+        cd $test_count &&
+        git fetch ./subproj master &&
+        ori_hash=$(git rev-parse FETCH_HEAD) &&
+        git subtree add --prefix=subdir FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub1 &&
+    (
+        cd $test_count &&
+        git subtree split --prefix subdir --branch splitbr1 &&
+        git subtree split --prefix subdir --branch splitbr2 --fallback &&
+        test_must_fail test_equal "$(git rev-parse splitbr1)" "$(git rev-parse splitbr2)"
+    ) &&
+    test_create_commit "$test_count" subdir/main-sub2 &&
+    (
+        cd $test_count &&
+        test_must_fail git subtree split --prefix subdir --branch splitbr2 &&
+        git subtree split --prefix subdir --branch splitbr2 --fallback
+    )
+'
+
 #
 # Validity checking
 #
-- 
1.8.1

^ permalink raw reply related

* [PATCH/RFC 7/7] contrib/subtree: Handle '--prefix' argument with a slash appended
From: Techlive Zheng @ 2013-01-13  1:52 UTC (permalink / raw)
  To: git, gitster; +Cc: apenwarr, greened, Techlive Zheng
In-Reply-To: <1358041958-1998-1-git-send-email-techlivezheng@gmail.com>

'git subtree merge' will fail if the argument of '--prefix' has a slash
appended.

Signed-off-by: Techlive Zheng <techlivezheng@gmail.com>
---
 contrib/subtree/git-subtree.sh     |  2 +-
 contrib/subtree/t/t7900-subtree.sh | 19 +++++++++++++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/contrib/subtree/git-subtree.sh b/contrib/subtree/git-subtree.sh
index 018ee32..574ff04 100755
--- a/contrib/subtree/git-subtree.sh
+++ b/contrib/subtree/git-subtree.sh
@@ -83,7 +83,7 @@ while [ $# -gt 0 ]; do
 		--annotate) annotate="$1"; shift ;;
 		--no-annotate) annotate= ;;
 		-b) branch="$1"; shift ;;
-		-P) prefix="$1"; shift ;;
+		-P) prefix="${1%/}"; shift ;;
 		-m) message="$1"; shift ;;
 		--no-prefix) prefix= ;;
 		--onto) onto="$1"; shift ;;
diff --git a/contrib/subtree/t/t7900-subtree.sh b/contrib/subtree/t/t7900-subtree.sh
index 1492303..8e09606 100755
--- a/contrib/subtree/t/t7900-subtree.sh
+++ b/contrib/subtree/t/t7900-subtree.sh
@@ -238,6 +238,25 @@ test_expect_success 'merge new subproj history into subdir/ with --squash and --
     )
 '
 
+test_expect_success 'merge new subproj history into subdir/ with a slash appended to the argument of --prefix' '
+    test_create_repo "$test_count" &&
+    test_create_repo "$test_count/subproj" &&
+    test_create_commit "$test_count" main1 &&
+    test_create_commit "$test_count/subproj" sub1 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree add --prefix=subdir/ FETCH_HEAD
+    ) &&
+    test_create_commit "$test_count/subproj" sub2 &&
+    (
+        cd "$test_count" &&
+        git fetch ./subproj master &&
+        git subtree merge --prefix=subdir/ FETCH_HEAD &&
+        test_equal "$(last_commit_message)" "Merge commit '\''$(git rev-parse FETCH_HEAD)'\''"
+    )
+'
+
 #
 # Tests for 'git subtree split'
 #
-- 
1.8.1

^ permalink raw reply related

* Re: How to setup bash completion for alias of git command
From: Ping Yin @ 2013-01-13  3:13 UTC (permalink / raw)
  To: git mailing list
In-Reply-To: <CACSwcnQu8Rx83mcGYR6NGzEhoreNR6DfiK876LF7pa9PGm30JA@mail.gmail.com>

On Sat, Jan 12, 2013 at 10:30 PM, Ping Yin <pkufranky@gmail.com> wrote:
> Following setup works for me  in ubuntu (10.04,11.04) for a long time
>
> alias gtlg='git log'
> complete -o default -o nospace -F _git_log gtlg
>
> However, in debian (testing, wheezy), it doesn't work
>
> $ gtlg or<TAB>
> gtlg or-bash: [: 1: unary operator expected
> -bash: [: 1: unary operator expected
>

with newest git version built with next branch, the same problem remains.

Ping Yin

^ permalink raw reply

* Re: [PATCH 2/8] git_remote_helpers: fix input when running under Python 3
From: Michael Haggerty @ 2013-01-13  3:26 UTC (permalink / raw)
  To: John Keeping; +Cc: git, Eric S. Raymond, Felipe Contreras, Sverre Rabbelier
In-Reply-To: <a8c3aabfab64f49fa0cbb2d45bda79997a875ee8.1358018078.git.john@keeping.me.uk>

On 01/12/2013 08:23 PM, John Keeping wrote:
> Although 2to3 will fix most issues in Python 2 code to make it run under
> Python 3, it does not handle the new strict separation between byte
> strings and unicode strings.  There is one instance in
> git_remote_helpers where we are caught by this.
> 
> Fix it by explicitly decoding the incoming byte string into a unicode
> string.  In this instance, use the locale under which the application is
> running.
> 
> Signed-off-by: John Keeping <john@keeping.me.uk>
> ---
>  git_remote_helpers/git/importer.py | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/git_remote_helpers/git/importer.py b/git_remote_helpers/git/importer.py
> index e28cc8f..6814003 100644
> --- a/git_remote_helpers/git/importer.py
> +++ b/git_remote_helpers/git/importer.py
> @@ -20,7 +20,7 @@ class GitImporter(object):
>          """Returns a dictionary with refs.
>          """
>          args = ["git", "--git-dir=" + gitdir, "for-each-ref", "refs/heads"]
> -        lines = check_output(args).strip().split('\n')
> +        lines = check_output(args).decode().strip().split('\n')
>          refs = {}
>          for line in lines:
>              value, name = line.split(' ')
> 

Won't this change cause an exception if the branch names are not all
valid strings in the current locale's encoding?  I don't see how this
assumption is justified (e.g., see git-check-ref-format(1) for the rules
governing reference names).

Michael

-- 
Michael Haggerty
mhagger@alum.mit.edu
http://softwareswirl.blogspot.com/

^ permalink raw reply

* Re: Suggestion: add option in git-p4 to preserve user in Git repository
From: Olivier Delalleau @ 2013-01-13  4:56 UTC (permalink / raw)
  To: Pete Wyckoff; +Cc: git, Luke Diamand
In-Reply-To: <20130112225640.GA23079@padd.com>

2013/1/12 Pete Wyckoff <pw@padd.com>:
> shish@keba.be wrote on Sat, 12 Jan 2013 14:44 -0500:
>> 2013/1/12 Pete Wyckoff <pw@padd.com>:
>> > shish@keba.be wrote on Thu, 10 Jan 2013 22:38 -0500:
>> >> I'm in a situation where I don't have P4 admin rights to use the
>> >> --preserve-user option of git-p4. However, I would like to keep user
>> >> information in the associated Git branch.
>> >>
>> >> Would it be possible to add an option for this?
>> >
>> > The --preserve-user option is used to submit somebody else's work
>> > from git to p4.  It does "p4 change -f" to edit the author of the
>> > change after it has been submitted to p4.  P4 requires admin
>> > privileges to do that.
>> >
>> > Changes that are imported _from_ p4 to git do have the correct
>> > author information.
>> >
>> > Can you explain a bit more what you're looking for?
>>
>> Sorry I wasn't clear enough. When "git p4 submit" submits changes from
>> Git to P4, it also edits the Git history and replaces the Git commits'
>> authors by the information from the Perforce account submitting the
>> changes. The advantage is that both the P4 and Git repositories share
>> the same author information, but in my case I would like to keep in
>> the Git repository the original authors (because the P4 account I'm
>> using to submit to P4 is shared by all Git users).
>
> Ah, I see what you're looking for now.  It's certainly possible
> to keep a mapping in the git side to remember who really wrote
> each change that went into p4, but there's nothing set up to do
> that now.  And it would be a fair amount of work, with many
> little details.
>
> You could put the true name in the commit message, like
> we do signed-off-by messages: "Author: Real Coder <rc@my.com>".
> That would keep the proper attribution, but not work with "git
> log --author", e.g.; you'd have to use "--grep='Real Coder'"
> instead.

Ok, thanks. I actually manage to hack my way around it, restoring the
author information with "git filter-branch" and overriding the remote
p4 tracking branch with "git update-ref". Did some limited testing and
it seems to work -- hopefully I won't have nasty surprises down the
road ;)

-=- Olivier

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox