* [PATCH] Fix minor grammatical typos in the git-gc man page
From: Theodore Ts'o @ 2007-05-31 23:00 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Git Mailing List, Theodore Ts'o
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
---
Documentation/git-gc.txt | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
index 4ac839f..c7742ca 100644
--- a/Documentation/git-gc.txt
+++ b/Documentation/git-gc.txt
@@ -37,10 +37,10 @@ OPTIONS
--aggressive::
Usually 'git-gc' runs very quickly while providing good disk
- space utilization and performance. This option will cause
- git-gc to more aggressive optimize the repository at the expense
+ space utilization and performance. This option will cause
+ git-gc to more aggressively optimize the repository at the expense
of taking much more time. The effects of this optimization are
- persistent, so this option only needs to be sporadically; every
+ persistent, so this option only needs to be used occasionally; every
few hundred changesets or so.
Configuration
--
1.5.2.136.g322bc
^ permalink raw reply related
* [PATCH 4/4] Add new --diff-opts/-O flag to diff- and status-related commands.
From: Yann Dirson @ 2007-05-31 22:34 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20070531222920.6005.74481.stgit@gandelf.nowhere.earth>
This new flag allows to pass arbitrary flags to the git-diff calls
underlying several StGIT commands. It can be used to pass flags
affecting both diff- and status-generating commands (eg. -M or -C), or
flags only affecting diff-generating ones (eg. --color, --binary).
It supercedes --binary for commands where it was allowed,
'-O --binary' is now available for the same functionality.
Signed-off-by: Yann Dirson <ydirson@altern.org>
---
stgit/commands/diff.py | 9 ++++-----
stgit/commands/export.py | 9 ++++-----
stgit/commands/files.py | 9 ++++++++-
stgit/commands/mail.py | 9 ++++-----
stgit/commands/show.py | 11 +++++++++--
stgit/commands/status.py | 10 +++++++++-
stgit/git.py | 21 ++++++++++++---------
7 files changed, 50 insertions(+), 28 deletions(-)
diff --git a/stgit/commands/diff.py b/stgit/commands/diff.py
index b66c75b..f8b19f8 100644
--- a/stgit/commands/diff.py
+++ b/stgit/commands/diff.py
@@ -44,9 +44,8 @@ shows the specified patch (defaulting to the current one)."""
options = [make_option('-r', '--range',
metavar = 'rev1[..[rev2]]', dest = 'revs',
help = 'show the diff between revisions'),
- make_option('--binary',
- help = 'output a diff even for binary files',
- action = 'store_true'),
+ make_option('-O', '--diff-opts',
+ help = 'options to pass to git-diff'),
make_option('-s', '--stat',
help = 'show the stat instead of the diff',
action = 'store_true')]
@@ -79,8 +78,8 @@ def func(parser, options, args):
rev1 = 'HEAD'
rev2 = None
- if options.binary:
- diff_flags = [ '--binary' ]
+ if options.diff_opts:
+ diff_flags = options.diff_opts.split()
else:
diff_flags = []
diff --git a/stgit/commands/export.py b/stgit/commands/export.py
index d6b36a9..35851bc 100644
--- a/stgit/commands/export.py
+++ b/stgit/commands/export.py
@@ -62,9 +62,8 @@ options = [make_option('-d', '--dir',
help = 'Use FILE as a template'),
make_option('-b', '--branch',
help = 'use BRANCH instead of the default one'),
- make_option('--binary',
- help = 'output a diff even for binary files',
- action = 'store_true'),
+ make_option('-O', '--diff-opts',
+ help = 'options to pass to git-diff'),
make_option('-s', '--stdout',
help = 'dump the patches to the standard output',
action = 'store_true')]
@@ -87,8 +86,8 @@ def func(parser, options, args):
os.makedirs(dirname)
series = file(os.path.join(dirname, 'series'), 'w+')
- if options.binary:
- diff_flags = [ '--binary' ]
+ if options.diff_opts:
+ diff_flags = options.diff_opts.split()
else:
diff_flags = []
diff --git a/stgit/commands/files.py b/stgit/commands/files.py
index 59893d8..659a82b 100644
--- a/stgit/commands/files.py
+++ b/stgit/commands/files.py
@@ -38,6 +38,8 @@ options = [make_option('-s', '--stat',
action = 'store_true'),
make_option('-b', '--branch',
help = 'use BRANCH instead of the default one'),
+ make_option('-O', '--diff-opts',
+ help = 'options to pass to git-diff'),
make_option('--bare',
help = 'bare file names (useful for scripting)',
action = 'store_true')]
@@ -61,4 +63,9 @@ def func(parser, options, args):
elif options.bare:
out.stdout_raw(git.barefiles(rev1, rev2) + '\n')
else:
- out.stdout_raw(git.files(rev1, rev2) + '\n')
+ if options.diff_opts:
+ diff_flags = options.diff_opts.split()
+ else:
+ diff_flags = []
+
+ out.stdout_raw(git.files(rev1, rev2, diff_flags = diff_flags) + '\n')
diff --git a/stgit/commands/mail.py b/stgit/commands/mail.py
index 7113cff..cec1828 100644
--- a/stgit/commands/mail.py
+++ b/stgit/commands/mail.py
@@ -120,9 +120,8 @@ options = [make_option('-a', '--all',
help = 'username for SMTP authentication'),
make_option('-b', '--branch',
help = 'use BRANCH instead of the default one'),
- make_option('--binary',
- help = 'output a diff even for binary files',
- action = 'store_true'),
+ make_option('-O', '--diff-opts',
+ help = 'options to pass to git-diff'),
make_option('-m', '--mbox',
help = 'generate an mbox file instead of sending',
action = 'store_true')]
@@ -377,8 +376,8 @@ def __build_message(tmpl, patch, patch_nr, total_nr, msg_id, ref_id, options):
else:
prefix_str = ''
- if options.binary:
- diff_flags = [ '--binary' ]
+ if options.diff_opts:
+ diff_flags = options.diff_opts.split()
else:
diff_flags = []
diff --git a/stgit/commands/show.py b/stgit/commands/show.py
index a270efd..ea4c874 100644
--- a/stgit/commands/show.py
+++ b/stgit/commands/show.py
@@ -35,7 +35,9 @@ options = [make_option('-a', '--applied',
action = 'store_true'),
make_option('-u', '--unapplied',
help = 'show the unapplied patches',
- action = 'store_true')]
+ action = 'store_true'),
+ make_option('-O', '--diff-opts',
+ help = 'options to pass to git-diff')]
def func(parser, options, args):
@@ -58,8 +60,13 @@ def func(parser, options, args):
else:
patches = parse_patches(args, applied + unapplied, len(applied))
+ if options.diff_opts:
+ diff_flags = options.diff_opts.split()
+ else:
+ diff_flags = []
+
commit_ids = [git_id(patch) for patch in patches]
- commit_str = '\n'.join([git.pretty_commit(commit_id)
+ commit_str = '\n'.join([git.pretty_commit(commit_id, diff_flags=diff_flags)
for commit_id in commit_ids])
if commit_str:
pager(commit_str)
diff --git a/stgit/commands/status.py b/stgit/commands/status.py
index b8f0623..156552b 100644
--- a/stgit/commands/status.py
+++ b/stgit/commands/status.py
@@ -58,6 +58,8 @@ options = [make_option('-m', '--modified',
make_option('-x', '--noexclude',
help = 'do not exclude any files from listing',
action = 'store_true'),
+ make_option('-O', '--diff-opts',
+ help = 'options to pass to git-diff'),
make_option('--reset',
help = 'reset the current tree changes',
action = 'store_true')]
@@ -75,5 +77,11 @@ def func(parser, options, args):
resolved_all()
git.reset()
else:
+ if options.diff_opts:
+ diff_flags = options.diff_opts.split()
+ else:
+ diff_flags = []
+
git.status(args, options.modified, options.new, options.deleted,
- options.conflict, options.unknown, options.noexclude)
+ options.conflict, options.unknown, options.noexclude,
+ diff_flags = diff_flags)
diff --git a/stgit/git.py b/stgit/git.py
index 7358fae..4bc41aa 100644
--- a/stgit/git.py
+++ b/stgit/git.py
@@ -217,7 +217,7 @@ def __run(cmd, args=None):
return 0
def __tree_status(files = None, tree_id = 'HEAD', unknown = False,
- noexclude = True, verbose = False):
+ noexclude = True, verbose = False, diff_flags = []):
"""Returns a list of pairs - [status, filename]
"""
if verbose:
@@ -254,7 +254,8 @@ def __tree_status(files = None, tree_id = 'HEAD', unknown = False,
cache_files += [('C', filename) for filename in conflicts]
# the rest
- for line in _output_lines(['git-diff-index', tree_id, '--'] + files):
+ for line in _output_lines(['git-diff-index'] + diff_flags +
+ [ tree_id, '--'] + files):
fs = tuple(line.rstrip().split(' ',4)[-1].split('\t',1))
if fs[1] not in conflicts:
cache_files.append(fs)
@@ -737,13 +738,15 @@ def merge(base, head1, head2, recursive = False):
raise GitException, 'GIT index merging failed (possible conflicts)'
def status(files = None, modified = False, new = False, deleted = False,
- conflict = False, unknown = False, noexclude = False):
+ conflict = False, unknown = False, noexclude = False,
+ diff_flags = []):
"""Show the tree status
"""
if not files:
files = []
- cache_files = __tree_status(files, unknown = True, noexclude = noexclude)
+ cache_files = __tree_status(files, unknown = True, noexclude = noexclude,
+ diff_flags = diff_flags)
all = not (modified or new or deleted or conflict or unknown)
if not all:
@@ -809,12 +812,12 @@ def diffstat(files = None, rev1 = 'HEAD', rev2 = None):
raise GitException, 'git.diffstat failed'
return diff_str
-def files(rev1, rev2):
+def files(rev1, rev2, diff_flags = []):
"""Return the files modified between rev1 and rev2
"""
result = ''
- for line in _output_lines(['git-diff-tree', '-r', rev1, rev2]):
+ for line in _output_lines(['git-diff-tree'] + diff_flags + ['-r', rev1, rev2]):
result += '%s %s\n' % tuple(line.rstrip().split(' ',4)[-1].split('\t',1))
return result.rstrip()
@@ -829,11 +832,11 @@ def barefiles(rev1, rev2):
return result.rstrip()
-def pretty_commit(commit_id = 'HEAD'):
+def pretty_commit(commit_id = 'HEAD', diff_flags = []):
"""Return a given commit (log + diff)
"""
- return _output(['git-diff-tree', '--cc', '--always', '--pretty', '-r',
- commit_id])
+ return _output(['git-diff-tree'] + diff_flags +
+ ['--cc', '--always', '--pretty', '-r', commit_id])
def checkout(files = None, tree_id = None, force = False):
"""Check out the given or all files
^ permalink raw reply related
* [PATCH 3/4] Make diff flags handling more modular.
From: Yann Dirson @ 2007-05-31 22:34 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20070531222920.6005.74481.stgit@gandelf.nowhere.earth>
Signed-off-by: Yann Dirson <ydirson@altern.org>
---
stgit/commands/diff.py | 7 ++++++-
stgit/commands/export.py | 8 +++++++-
stgit/commands/mail.py | 7 ++++++-
stgit/git.py | 12 ++++--------
4 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/stgit/commands/diff.py b/stgit/commands/diff.py
index f56cbeb..b66c75b 100644
--- a/stgit/commands/diff.py
+++ b/stgit/commands/diff.py
@@ -79,10 +79,15 @@ def func(parser, options, args):
rev1 = 'HEAD'
rev2 = None
+ if options.binary:
+ diff_flags = [ '--binary' ]
+ else:
+ diff_flags = []
+
if options.stat:
out.stdout_raw(git.diffstat(args, git_id(rev1), git_id(rev2)) + '\n')
else:
diff_str = git.diff(args, git_id(rev1), git_id(rev2),
- binary = options.binary)
+ diff_flags = diff_flags )
if diff_str:
pager(diff_str)
diff --git a/stgit/commands/export.py b/stgit/commands/export.py
index cafcbe3..d6b36a9 100644
--- a/stgit/commands/export.py
+++ b/stgit/commands/export.py
@@ -87,6 +87,11 @@ def func(parser, options, args):
os.makedirs(dirname)
series = file(os.path.join(dirname, 'series'), 'w+')
+ if options.binary:
+ diff_flags = [ '--binary' ]
+ else:
+ diff_flags = []
+
applied = crt_series.get_applied()
if len(args) != 0:
patches = parse_patches(args, applied)
@@ -175,7 +180,8 @@ def func(parser, options, args):
# write the diff
git.diff(rev1 = patch.get_bottom(),
rev2 = patch.get_top(),
- out_fd = f, binary = options.binary)
+ out_fd = f,
+ diff_flags = diff_flags )
if not options.stdout:
f.close()
patch_no += 1
diff --git a/stgit/commands/mail.py b/stgit/commands/mail.py
index b95014c..7113cff 100644
--- a/stgit/commands/mail.py
+++ b/stgit/commands/mail.py
@@ -377,6 +377,11 @@ def __build_message(tmpl, patch, patch_nr, total_nr, msg_id, ref_id, options):
else:
prefix_str = ''
+ if options.binary:
+ diff_flags = [ '--binary' ]
+ else:
+ diff_flags = []
+
total_nr_str = str(total_nr)
patch_nr_str = str(patch_nr).zfill(len(total_nr_str))
if total_nr > 1:
@@ -394,7 +399,7 @@ def __build_message(tmpl, patch, patch_nr, total_nr, msg_id, ref_id, options):
'endofheaders': '',
'diff': git.diff(rev1 = git_id('%s//bottom' % patch),
rev2 = git_id('%s//top' % patch),
- binary = options.binary),
+ diff_flags = diff_flags ),
'diffstat': git.diffstat(rev1 = git_id('%s//bottom'%patch),
rev2 = git_id('%s//top' % patch)),
# for backward template compatibility
diff --git a/stgit/git.py b/stgit/git.py
index 5cdc8cd..7358fae 100644
--- a/stgit/git.py
+++ b/stgit/git.py
@@ -770,27 +770,23 @@ def status(files = None, modified = False, new = False, deleted = False,
out.stdout('%s' % fs[1])
def diff(files = None, rev1 = 'HEAD', rev2 = None, out_fd = None,
- binary = False):
+ diff_flags = []):
"""Show the diff between rev1 and rev2
"""
if not files:
files = []
- args = []
- if binary:
- args.append('--binary')
-
if rev1 and rev2:
- diff_str = _output(['git-diff-tree', '-p'] + args
+ diff_str = _output(['git-diff-tree', '-p'] + diff_flags
+ [rev1, rev2, '--'] + files)
elif rev1 or rev2:
refresh_index()
if rev2:
diff_str = _output(['git-diff-index', '-p', '-R']
- + args + [rev2, '--'] + files)
+ + diff_flags + [rev2, '--'] + files)
else:
diff_str = _output(['git-diff-index', '-p']
- + args + [rev1, '--'] + files)
+ + diff_flags + [rev1, '--'] + files)
else:
diff_str = ''
^ permalink raw reply related
* [PATCH 2/4] Call external commands without a shell where possible.
From: Yann Dirson @ 2007-05-31 22:34 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20070531222920.6005.74481.stgit@gandelf.nowhere.earth>
On my dev box it consistently improves performance when timing the
full testsuite:
before:
user 2m22.509s
sys 0m50.695s
user 2m23.565s
sys 0m49.399s
user 2m23.497s
sys 0m49.675s
after:
user 2m20.261s
sys 0m45.687s
user 2m21.485s
sys 0m46.427s
user 2m20.581s
sys 0m45.367s
Signed-off-by: Yann Dirson <ydirson@altern.org>
---
stgit/git.py | 42 +++++++++++++++++++++---------------------
1 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/stgit/git.py b/stgit/git.py
index 845c712..5cdc8cd 100644
--- a/stgit/git.py
+++ b/stgit/git.py
@@ -74,7 +74,7 @@ class Commit:
def __init__(self, id_hash):
self.__id_hash = id_hash
- lines = _output_lines('git-cat-file commit %s' % id_hash)
+ lines = _output_lines(['git-cat-file', 'commit', id_hash])
for i in range(len(lines)):
line = lines[i]
if line == '\n':
@@ -102,8 +102,8 @@ class Commit:
return None
def get_parents(self):
- return _output_lines('git-rev-list --parents --max-count=1 %s'
- % self.__id_hash)[0].split()[1:]
+ return _output_lines(['git-rev-list', '--parents', '--max-count=1',
+ self.__id_hash])[0].split()[1:]
def get_author(self):
return self.__author
@@ -285,7 +285,7 @@ def get_head_file():
"""Returns the name of the file pointed to by the HEAD link
"""
return strip_prefix('refs/heads/',
- _output_one_line('git-symbolic-ref HEAD'))
+ _output_one_line(['git-symbolic-ref', 'HEAD']))
def set_head_file(ref):
"""Resets HEAD to point to a new ref
@@ -617,27 +617,27 @@ def commit(message, files = None, parents = None, allowempty = False,
must_switch = True
# write the index to repository
if tree_id == None:
- tree_id = _output_one_line('git-write-tree')
+ tree_id = _output_one_line(['git-write-tree'])
else:
must_switch = False
# the commit
- cmd = ''
+ cmd = ['env']
if author_name:
- cmd += 'GIT_AUTHOR_NAME="%s" ' % author_name
+ cmd += ['GIT_AUTHOR_NAME=%s' % author_name]
if author_email:
- cmd += 'GIT_AUTHOR_EMAIL="%s" ' % author_email
+ cmd += ['GIT_AUTHOR_EMAIL=%s' % author_email]
if author_date:
- cmd += 'GIT_AUTHOR_DATE="%s" ' % author_date
+ cmd += ['GIT_AUTHOR_DATE=%s' % author_date]
if committer_name:
- cmd += 'GIT_COMMITTER_NAME="%s" ' % committer_name
+ cmd += ['GIT_COMMITTER_NAME=%s' % committer_name]
if committer_email:
- cmd += 'GIT_COMMITTER_EMAIL="%s" ' % committer_email
- cmd += 'git-commit-tree %s' % tree_id
+ cmd += ['GIT_COMMITTER_EMAIL=%s' % committer_email]
+ cmd += ['git-commit-tree', tree_id]
# get the parents
for p in parents:
- cmd += ' -p %s' % p
+ cmd += ['-p', p]
commit_id = _output_one_line(cmd, message)
if must_switch:
@@ -652,9 +652,9 @@ def apply_diff(rev1, rev2, check_index = True, files = None):
the pushing would fall back to the three-way merge.
"""
if check_index:
- index_opt = '--index'
+ index_opt = ['--index']
else:
- index_opt = ''
+ index_opt = []
if not files:
files = []
@@ -662,7 +662,7 @@ def apply_diff(rev1, rev2, check_index = True, files = None):
diff_str = diff(files, rev1, rev2)
if diff_str:
try:
- _input_str('git-apply %s' % index_opt, diff_str)
+ _input_str(['git-apply'] + index_opt, diff_str)
except GitException:
return False
@@ -680,7 +680,7 @@ def merge(base, head1, head2, recursive = False):
# general when pushing or picking patches)
try:
# use _output() to mask the verbose prints of the tool
- _output('git-merge-recursive %s -- %s %s' % (base, head1, head2))
+ _output(['git-merge-recursive', base, '--', head1, head2])
except GitException, ex:
err_output = str(ex)
pass
@@ -696,7 +696,7 @@ def merge(base, head1, head2, recursive = False):
files = {}
stages_re = re.compile('^([0-7]+) ([0-9a-f]{40}) ([1-3])\t(.*)$', re.S)
- for line in _output('git-ls-files --unmerged --stage -z').split('\0'):
+ for line in _output(['git-ls-files', '--unmerged', '--stage', '-z']).split('\0'):
if not line:
continue
@@ -818,7 +818,7 @@ def files(rev1, rev2):
"""
result = ''
- for line in _output_lines('git-diff-tree -r %s %s' % (rev1, rev2)):
+ for line in _output_lines(['git-diff-tree', '-r', rev1, rev2]):
result += '%s %s\n' % tuple(line.rstrip().split(' ',4)[-1].split('\t',1))
return result.rstrip()
@@ -828,7 +828,7 @@ def barefiles(rev1, rev2):
"""
result = ''
- for line in _output_lines('git-diff-tree -r %s %s' % (rev1, rev2)):
+ for line in _output_lines(['git-diff-tree', '-r', rev1, rev2]):
result += '%s\n' % line.rstrip().split(' ',4)[-1].split('\t',1)[-1]
return result.rstrip()
@@ -947,7 +947,7 @@ def apply_patch(filename = None, diff = None, base = None,
refresh_index()
try:
- _input_str('git-apply --index', diff)
+ _input_str(['git-apply', '--index'], diff)
except GitException:
if base:
switch(orig_head)
^ permalink raw reply related
* [PATCH 1/4] Add 2 new contrib scripts.
From: Yann Dirson @ 2007-05-31 22:34 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20070531222920.6005.74481.stgit@gandelf.nowhere.earth>
Signed-off-by: Yann Dirson <ydirson@altern.org>
---
contrib/stg-k | 32 ++++++++++++++++++++++++++++++++
contrib/stg-unnew | 15 +++++++++++++++
2 files changed, 47 insertions(+), 0 deletions(-)
diff --git a/contrib/stg-k b/contrib/stg-k
new file mode 100755
index 0000000..0134c25
--- /dev/null
+++ b/contrib/stg-k
@@ -0,0 +1,32 @@
+#!/bin/sh
+set -e
+
+# stg-k - execute given StGIT command while preserving local changes
+
+# Uses a temporary patch to save local changes, then execute the given
+# command, and restore local changes from the saved patch. In
+# essence, "stg-k pop" is a "stg pop -k" that works better, hence its
+# name.
+
+# CAVEAT: this script relies on the operation to run ignoring hidden
+# patches, so in 0.12 (where "stg push" can push an hidden patch)
+# "stg-k push" will fail midway, albeit with no information loss -
+# you'll just have to finish manually. Luckilly this appears to work
+# on master branch.
+
+# Copyright (c) 2007 Yann Dirson <ydirson@altern.org>
+# Subject to the GNU GPL, version 2.
+
+stg new __local -m " - local changes (internal patch)"
+stg refresh
+stg pop
+
+# avoid bad interactions like "stg-k push" not behaving as expected
+stg hide __local
+
+stg "$@"
+
+stg unhide __local
+
+stg push __local
+stg-unnew
diff --git a/contrib/stg-unnew b/contrib/stg-unnew
new file mode 100755
index 0000000..5ac8781
--- /dev/null
+++ b/contrib/stg-unnew
@@ -0,0 +1,15 @@
+#!/bin/sh
+set -e
+
+# stg-unnew - sort of "reverse an 'stg new'"
+
+# Remove the current patch from the stack, keeping its contents as
+# uncommitted changes.
+
+# Copyright (c) 2007 Yann Dirson <ydirson@altern.org>
+# Subject to the GNU GPL, version 2.
+
+patch=$(stg top)
+stg pop
+stg pick --fold $patch
+stg delete $patch
^ permalink raw reply related
* [StGIT PATCH 0/4] Rename detection, take 2
From: Yann Dirson @ 2007-05-31 22:34 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
This series brings the ability to pass arbitrary flags to git-diff
through StGIT commands. Eg:
stg files -O -C
stg diff -O '-C -w --color'
stg mail -O --binary
The latter shows that the recently-added --binary is not needed any
more, so I removed it.
While doing this, I realized that many git commands were spawned
through shell commands instead of directly exec'ing them, and that was
annyoing for consistency, so this is part of the same patch. As a
bonus, it slightly improves performance.
--
Yann Dirson <ydirson@altern.org> |
Debian-related: <dirson@debian.org> | Support Debian GNU/Linux:
| Freedom, Power, Stability, Gratis
http://ydirson.free.fr/ | Check <http://www.debian.org/>
^ permalink raw reply
* [PATCH] Make the installation target of git-gui a little less chatty
From: Alex Riesen @ 2007-05-31 22:25 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: git, Junio C Hamano
Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
---
The patch is hand-tuned to start in git-gui, so that it can be applied
in git-gui repo.
Makefile | 17 +++++++++++------
1 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/Makefile b/Makefile
index 3de0de1..1eafbf8 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,10 @@ all::
# Define V=1 to have a more verbose compile.
#
+QUIET =
+ifndef V
+ QUIET = @
+endif
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -109,12 +113,13 @@ GIT-GUI-VARS: .FORCE-GIT-GUI-VARS
all:: $(ALL_PROGRAMS) lib/tclIndex
install: all
- $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)'
- $(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)'
- $(foreach p,$(GITGUI_BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;)
- $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(libdir_SQ)'
- $(INSTALL) -m644 lib/tclIndex '$(DESTDIR_SQ)$(libdir_SQ)'
- $(foreach p,$(ALL_LIBFILES), $(INSTALL) -m644 $p '$(DESTDIR_SQ)$(libdir_SQ)' ;)
+ @echo installing git-gui
+ $(QUIET)$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+ $(QUIET)$(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+ $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;)
+ $(QUIET)$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(libdir_SQ)'
+ $(QUIET)$(INSTALL) -m644 lib/tclIndex '$(DESTDIR_SQ)$(libdir_SQ)'
+ $(QUIET)$(foreach p,$(ALL_LIBFILES), $(INSTALL) -m644 $p '$(DESTDIR_SQ)$(libdir_SQ)' ;)
dist-version:
@mkdir -p $(TARDIR)
--
1.5.2.162.gbaa1f
^ permalink raw reply related
* [PATCH] Make the installation targets a little less chatty
From: Alex Riesen @ 2007-05-31 22:23 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
by default. V=1 works as usual.
Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
---
Now it quite quiet. I tried top show every installed file, but it
wasn't an improvement at all so I decided to just show what's being
done.
Makefile | 32 +++++++++++++++++++-------------
templates/Makefile | 5 +++--
2 files changed, 22 insertions(+), 15 deletions(-)
diff --git a/Makefile b/Makefile
index cac0a4a..fccc57b 100644
--- a/Makefile
+++ b/Makefile
@@ -660,6 +660,7 @@ ifeq ($(TCLTK_PATH),)
NO_TCLTK=NoThanks
endif
+QUIET=
QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
QUIET_SUBDIR1 =
@@ -671,6 +672,8 @@ endif
ifneq ($(findstring $(MAKEFLAGS),s),s)
ifndef V
+ QUIET = @
+
QUIET_CC = @echo ' ' CC $@;
QUIET_AR = @echo ' ' AR $@;
QUIET_LINK = @echo ' ' LINK $@;
@@ -973,33 +976,36 @@ check: common-cmds.h
### Installation rules
install: all
- $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(bindir_SQ)'
- $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)'
- $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
- $(INSTALL) git$X '$(DESTDIR_SQ)$(bindir_SQ)'
- $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
- $(MAKE) -C perl prefix='$(prefix_SQ)' install
+ $(QUIET)$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(bindir_SQ)'
+ $(QUIET)$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+ @echo installing programs
+ $(QUIET)$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+ $(QUIET)$(INSTALL) git$X '$(DESTDIR_SQ)$(bindir_SQ)'
+ @echo setting up builtins
+ $(QUIET)$(foreach p,$(BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;)
+ $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) DESTDIR='$(DESTDIR_SQ)' install
+ $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) prefix='$(prefix_SQ)' install
ifndef NO_TCLTK
- $(INSTALL) gitk-wish '$(DESTDIR_SQ)$(bindir_SQ)'/gitk
- $(MAKE) -C git-gui install
+ $(QUIET)$(INSTALL) gitk-wish '$(DESTDIR_SQ)$(bindir_SQ)'/gitk
+ $(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) install
endif
- if test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \
+ @if test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \
then \
ln -f '$(DESTDIR_SQ)$(bindir_SQ)/git$X' \
'$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' || \
cp '$(DESTDIR_SQ)$(bindir_SQ)/git$X' \
'$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X'; \
fi
- $(foreach p,$(BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;)
ifneq (,$X)
- $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p';)
+ @echo cleaning '$(DESTDIR_SQ)$(gitexecdir_SQ)' of old scripts
+ $(QUIET)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p';)
endif
install-doc:
- $(MAKE) -C Documentation install
+ $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) install
quick-install-doc:
- $(MAKE) -C Documentation quick-install
+ $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) quick-install
diff --git a/templates/Makefile b/templates/Makefile
index b8352e7..b9a39e2 100644
--- a/templates/Makefile
+++ b/templates/Makefile
@@ -45,6 +45,7 @@ clean:
rm -rf blt boilerplates.made
install: all
- $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(template_dir_SQ)'
- (cd blt && $(TAR) cf - .) | \
+ @echo installing templates
+ $(QUIET)$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(template_dir_SQ)'
+ $(QUIET)(cd blt && $(TAR) cf - .) | \
(cd '$(DESTDIR_SQ)$(template_dir_SQ)' && $(TAR) xf -)
--
1.5.2.162.gbaa1f
^ permalink raw reply related
* Re: [ANNOUNCE] tig 0.7
From: Jonas Fonseca @ 2007-05-31 21:55 UTC (permalink / raw)
To: Steven Grimm; +Cc: git
In-Reply-To: <465F2731.2080707@midwinter.com>
Steven Grimm <koreth@midwinter.com> wrote Thu, May 31, 2007:
> This doesn't build on OS X out of the box, FYI. It needs the following
> tweaks (which break the build on Linux, so I'm not suggesting you apply
> this -- looks like you might need a configure script or at least some
> conditionals in the Makefile.) The change to tig.c cleans up a compiler
> warning, but it does build fine without that change.
I am aware of this and your suggestion is already in the TODO file.
However, for 0.7 I ended up needing the new status view feature more
than working on fixing that.
--
Jonas Fonseca
^ permalink raw reply
* Re: [RFH] QGit: how to cram a patch in a crowded screen
From: Jan Hudec @ 2007-05-31 19:56 UTC (permalink / raw)
To: Marco Costalba; +Cc: Andy Parkins, git, Pavel Roskin
In-Reply-To: <e5bfff550705270856o195b9075u1c99a05e79d69742@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1728 bytes --]
On Sun, May 27, 2007 at 17:56:05 +0200, Marco Costalba wrote:
> On 5/27/07, Jan Hudec <bulb@ucw.cz> wrote:
> >On Sat, May 26, 2007 at 22:44:28 +0200, Marco Costalba wrote:
> >> On 5/26/07, Andy Parkins <andyparkins@gmail.com> wrote:
> >> >
> >> >For example, the log view widget would show:
> >> >
> >> ><Header>
> >> ><Log Message>
> >> ><Patch>
> >> >
> >> >All visually distinct to improve searching by eye (perhaps including
> >> >clear separators between files patched). Then the file list could
> >> >include a "<header>" psuedo-file that would jump back to the top of the
> >> >viewer.
> >>
> >> This seems really gitk like. Not that I don' t like it, but _if_ it's
> >> possible I would prefer something a little bit more original.
> >
> >IMHO there's no point in being original.
>
> True. But there's no point also in avoiding experimenting a little bit.
>
> I've pushed some patches to use different ways to switch between diff
> and messages, please read the last patch log message for a summary of
> the changes.
>
> If interested give it a try. it would be grat to hear your comment on that
> also.
I have to say that I like the gitk way better. There is the issue of
over-scrolling. I often want to quickly scan through the diff, so I scroll
pretty quickly and it switches over when I reach the end.
I understand the reason to not calculate the diff until it's requested.
I think I might like it if only message is shown initially and when user
scrolls at -- or rather past -- the end, the diff would be APPENDED to it.
That way the scrolling would look more natural, while still only generating
the diff only on request.
--
Jan 'Bulb' Hudec <bulb@ucw.cz>
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [PATCH (tig)] Supply explicit permission bits to 'install'.
From: Jonas Fonseca @ 2007-05-31 19:54 UTC (permalink / raw)
To: Jeffrey C. Ollie; +Cc: git
In-Reply-To: <11806392321132-git-send-email-jeff@ocjtech.us>
Jeffrey C. Ollie <jeff@ocjtech.us> wrote Thu, May 31, 2007:
> 'install' will install files with permissions set to '0755' if the
> permissions are not specified on the command line. Having the execute
> bits set on non-executable content is not desireable. Specify mode
> 0644 for non-executable content as well as specify mode 0755 for
> executable content (in case the defaults change or are different on
> different systems). Also tell 'install' to preserve timestamps.
Thank you. I updated the patch to install HTML files with explicit
permissions.
--
Jonas Fonseca
^ permalink raw reply
* Re: [ANNOUNCE] tig 0.7
From: Steven Grimm @ 2007-05-31 19:51 UTC (permalink / raw)
To: Jonas Fonseca; +Cc: git
In-Reply-To: <20070531123808.GA25719@diku.dk>
This doesn't build on OS X out of the box, FYI. It needs the following
tweaks (which break the build on Linux, so I'm not suggesting you apply
this -- looks like you might need a configure script or at least some
conditionals in the Makefile.) The change to tig.c cleans up a compiler
warning, but it does build fine without that change.
---
Makefile | 2 +-
tig.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index 57196b0..db5844c 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ endif
RPM_VERSION = $(subst -,.,$(VERSION))
-LDLIBS = -lcurses
+LDLIBS = -lcurses -liconv
CFLAGS = -Wall -O2 '-DVERSION="$(VERSION)"'
DFLAGS = -g -DDEBUG -Werror
PROGS = tig
diff --git a/tig.c b/tig.c
index e918fe6..e94ef4b 100644
--- a/tig.c
+++ b/tig.c
@@ -1913,7 +1913,7 @@ update_view(struct view *view)
line[linelen - 1] = 0;
if (opt_iconv != ICONV_NONE) {
- char *inbuf = line;
+ const char *inbuf = line;
size_t inlen = linelen;
char *outbuf = out_buffer;
--
1.5.2.35.ga334
^ permalink raw reply related
* Re: [MinGW port] Unable to repack on Clearcase dynamic views
From: Robin Rosenberg @ 2007-05-31 18:51 UTC (permalink / raw)
To: Paolo Teti; +Cc: Nguyen Thai Ngoc Duy, Git Mailing List
In-Reply-To: <34a7ae040705310246w72c30c19ic063895a46b8f3fb@mail.gmail.com>
torsdag 31 maj 2007 skrev Paolo Teti:
> 2007/5/30, Robin Rosenberg <robin.rosenberg.lists@dewire.com>:
>
> > BTW, Does anyone have something like git-cvsexportcommit for clearcase?
>
> a stupid workaround is git-cvsexportcommit + clearimport /clearexport_cvs.
> -
That would require a clearcase to cvs converter, wouldn't it, so I'd have something to commit to..
Even more stupid than my attempt at a clearcase to git converter.
-- robin
^ permalink raw reply
* [PATCH (tig)] Supply explicit permission bits to 'install'.
From: Jeffrey C. Ollie @ 2007-05-31 19:20 UTC (permalink / raw)
To: Jonas Fonseca; +Cc: git, Jeffrey C. Ollie
'install' will install files with permissions set to '0755' if the
permissions are not specified on the command line. Having the execute
bits set on non-executable content is not desireable. Specify mode
0644 for non-executable content as well as specify mode 0755 for
executable content (in case the defaults change or are different on
different systems). Also tell 'install' to preserve timestamps.
Signed-off-by: Jeffrey C. Ollie <jeff@ocjtech.us>
---
Makefile | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile
index 57196b0..f9adecb 100644
--- a/Makefile
+++ b/Makefile
@@ -38,7 +38,7 @@ doc-html: $(HTMLDOC)
install: all
mkdir -p $(DESTDIR)$(bindir) && \
for prog in $(PROGS); do \
- install $$prog $(DESTDIR)$(bindir); \
+ install -p -m 0755 $$prog $(DESTDIR)$(bindir); \
done
install-doc-man: doc-man
@@ -46,8 +46,8 @@ install-doc-man: doc-man
$(DESTDIR)$(mandir)/man5
for doc in $(MANDOC); do \
case "$$doc" in \
- *.1) install $$doc $(DESTDIR)$(mandir)/man1 ;; \
- *.5) install $$doc $(DESTDIR)$(mandir)/man5 ;; \
+ *.1) install -p -m 0644 $$doc $(DESTDIR)$(mandir)/man1 ;; \
+ *.5) install -p -m 0644 $$doc $(DESTDIR)$(mandir)/man5 ;; \
esac \
done
--
1.5.2.GIT
^ permalink raw reply related
* [StGIT RFC PATCH] Add contrib/stg-k script.
From: Yann Dirson @ 2007-05-31 18:54 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
Signed-off-by: Yann Dirson <ydirson@altern.org>
---
This patch mainly adds a contrib script that allows to execute given
StGIT command while preserving local changes. It is surely not
fool-proof in itself yet.
It relies on another small script which removes the current patch from
the stack, keeping its contents as uncommitted changes. I named it
"stg-unnew" because under a very particular angle it may look like
reversing the "stg new" operation - but I'm highly dissatisfied with
that name, and would gladly accept any sensible suggestion to rename
it :)
contrib/stg-k | 32 ++++++++++++++++++++++++++++++++
contrib/stg-unnew | 15 +++++++++++++++
2 files changed, 47 insertions(+), 0 deletions(-)
diff --git a/contrib/stg-k b/contrib/stg-k
new file mode 100755
index 0000000..0134c25
--- /dev/null
+++ b/contrib/stg-k
@@ -0,0 +1,32 @@
+#!/bin/sh
+set -e
+
+# stg-k - execute given StGIT command while preserving local changes
+
+# Uses a temporary patch to save local changes, then execute the given
+# command, and restore local changes from the saved patch. In
+# essence, "stg-k pop" is a "stg pop -k" that works better, hence its
+# name.
+
+# CAVEAT: this script relies on the operation to run ignoring hidden
+# patches, so in 0.12 (where "stg push" can push an hidden patch)
+# "stg-k push" will fail midway, albeit with no information loss -
+# you'll just have to finish manually. Luckilly this appears to work
+# on master branch.
+
+# Copyright (c) 2007 Yann Dirson <ydirson@altern.org>
+# Subject to the GNU GPL, version 2.
+
+stg new __local -m " - local changes (internal patch)"
+stg refresh
+stg pop
+
+# avoid bad interactions like "stg-k push" not behaving as expected
+stg hide __local
+
+stg "$@"
+
+stg unhide __local
+
+stg push __local
+stg-unnew
diff --git a/contrib/stg-unnew b/contrib/stg-unnew
new file mode 100755
index 0000000..5ac8781
--- /dev/null
+++ b/contrib/stg-unnew
@@ -0,0 +1,15 @@
+#!/bin/sh
+set -e
+
+# stg-unnew - sort of "reverse an 'stg new'"
+
+# Remove the current patch from the stack, keeping its contents as
+# uncommitted changes.
+
+# Copyright (c) 2007 Yann Dirson <ydirson@altern.org>
+# Subject to the GNU GPL, version 2.
+
+patch=$(stg top)
+stg pop
+stg pick --fold $patch
+stg delete $patch
^ permalink raw reply related
* git-p4import.py robustness changes
From: Scott Lamb @ 2007-05-31 16:47 UTC (permalink / raw)
To: git
I'm trying out git-p4import.py (and git itself) for the first time.
I'm frustrated with its error behavior. For example, it's saying this:
$ git-p4import.py //my/path/... master
Setting perforce to //my/path/...
Already up to date...
when it should be saying this:
$ git-p4import.py //my/path/... master
Setting perforce to //my/path/...
git-p4import fatal error: p4 changes //my/path/...@1,#head:
Request too large (over 150000); see 'p4 help maxresults'.
There's a logfile option, but that's a poor excuse for no error
handling. I'd like to fix it. A couple questions, though:
First, is it acceptable to switch from os.popen to the subprocess
module? I ask because the latter was only introduced with Python 2.4
on. The subprocess module does work with earlier versions of Python
(definitely 2.3) and is GPL-compatible, so maybe it could be thrown
into the distribution if desired.
I could make do with popen2.Popen3, but subprocess is actually
pleasant to use:
git = subprocess.Popen(cmdlist,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = git.communicate(stdin)
if git.wait() != 0:
raise GitException("'git %s' failed: %s" % (cmd, stderr))
vs. the popen2 way, which is longer and uglier. It'd probably involve
tempfiles rather than reimplementing subprocess.Popen.communicate().
Second, this crowd seems to want sequences of tiny patches. How does
this sound?
* patch 1 - use subprocess to make git_command.git() and p4_command.p4
() throw properly-typed exceptions on error, fix caller exception
handling to match.
* patch 2 - remove the use of the shell and pipelines (fix some
escaping problems).
* patch 3 - use lists instead of space separation for the commandline
arguments (fix more escaping problems).
* patch 4 - allow grabbing partial history (make my error go away).
Cheers,
Scott
--
Scott Lamb <http://www.slamb.org/>
^ permalink raw reply
* Re: Breaking up repositories
From: Josh Triplett @ 2007-05-31 15:53 UTC (permalink / raw)
To: Jason Sewall; +Cc: git, Jamey Sharp
[-- Attachment #1: Type: text/plain, Size: 1298 bytes --]
Jason Sewall wrote:
> I recently imported my subversion repo with git-svn and I'm curious
> what the best way to break up the monolithic repo (my many disparate
> projects from my single svn repo) into individual git repos of their
> own.
>
> I'm still trying to get a grasp on the considerable git toolbox and I
> can't seem to find the functionality I'm describing, but I'm sure it
> exists - I heard Linus talk about it in that Google talk on git!
In the specific case of git-svn, you can probably give git-svn the
appropriate paths to import each project separately; that may do what you
want, depending on your repository layout.
In the general case, if you want to split a subtree of a git repo into a git
repo, you want git-split, by Jamey Sharp and I:
<http://people.freedesktop.org/~jamey/git-split>
From a copy of the git repo you want to split, just run "git-split subdir",
optionally with a newest and oldest commit, and it will output the sha1 of
the new top commit for use as the new branch ref. Remove all other
branches, reflogs, and other references to the old commits, and use prune
or gc to get rid of old objects. Repeat as desired for other subdirs.
We really need to fix some things in git-split and get it merged into git.
- Josh Triplett
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 252 bytes --]
^ permalink raw reply
* Re: [PATCH] always start looking up objects in the last used pack first
From: Nicolas Pitre @ 2007-05-31 15:39 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: Junio C Hamano, git
In-Reply-To: <20070531050211.GV7044@spearce.org>
On Thu, 31 May 2007, Shawn O. Pearce wrote:
> Nicolas Pitre <nico@cam.org> wrote:
> > Pack Sort w/o this patch w/ this patch
> > -------------------------------------------------------------
> > recent objects last 26.4s 20.9s
> > recent objects first 24.9s 18.4s
>
> Looks pretty good.
>
> > + next:
> > + if (p == last_found)
> > + p = packed_git;
> > + else
> > + p = p->next;
> > + if (p == last_found)
> > + p = p->next;
> > + } while (p);
>
> So if we didn't find the object in the pack that we found the
> last object in, we restart our search with the most recent pack?
Right.
> Why not just go to p->next and loop around? If we missed in this
> pack and the packs are sorted by recency, wouldn't we want to just
> search the next pack?
Testing shows that with such a strategy the same operation went from
18.4s to 19.8s. But this is with split packs resulting from a
git-repack -a -d --max-pack-size=...
If you search for an object and don't find it in the last used pack,
that doesn't mean that the object is necessarily in the pack next to the
last one.
The object recency order doesn't actually mean object age. Consider for
example 3 commits: the first with everything initially created, the
second commit modifying only half the files, and the third modifying
only a quarter of the files.
Object recency order means that the latest commit will see (almost) all
its objects early and contiguously in the pack stream. The latest commit
will still reference between 1/4 to 1/2 of the objects that were created
from the first commit though.
Objects for the middle commit will appear after that, but only those
that were not referenced by the latest commit. This means that in this
example 3/4 of the needed objects for the middle commit will still be
found early in the pack stream.
And the first commit will see its objects at the end of the pack stream,
but again only those objects that weren't referenced by younger commits
already. Up to 1/2 of those objects needed for the first commit might
be found in the early portion of the pack stream, or at worst 1/4 in the
early portion and 1/4 in the mid portion of the pack stream.
If a repack creates split packs more or less according to the commit
separation above then failure to find an object in the last used pack
should really continue to scan available packs from the beginning of the
list. Merely going on with the next available pack is a bad move in
this case.
HOWEVER...
If the accumulation of packs is due to multiple fetches/pushes without a
repack then the situation is somewhat reversed and much less clear.
Considering the scenario above but with a fetch between commits you'd
end up with this:
1- a large pack with all objects for the first commit.
2- a pack with only half the objects for the second commit (the other
half is still available in pack #1).
3- a pack with only 1/4 of the objects for the latest commit (the rest
is shared between pack #1 and pack #2).
Here it is not clear what to do. Given that the last-used-pack
heuristic makes such a big difference in the split pack it will
certainly help a lot in this case too. But where to go when that
heuristic fails is unclear. If you want to favorize speed for latest
commits then I'd argue that going back to the beginning of the list is
still the right thing to do. If you want to have a more balanced
behavior for all commits (think git-blame) then probably going to the
pack next to the last used would be the best thing to do in this case as
younger packs will never contain objects that older commits are
interested in.
...
Which makes me wonder about a possible incremental improvement to my
patch: on failure to find an object in the last used pack, the search
should then start again from the pack containing the commit from which
this object search is related to. In the split pack case all commit
objects will be located in the first pack so nothing will change there.
In the multiple-fetch case then the search will always reset to packs
not younger than the commit triggering those object lookups. Question
is how to implement that nicely...
Nicolas
^ permalink raw reply
* Re: Breaking up repositories
From: Dave Hanson @ 2007-05-31 13:55 UTC (permalink / raw)
To: Jason Sewall; +Cc: git
In-Reply-To: <31e9dd080705302350x7752c1f0p3dee2f0d35a97b56@mail.gmail.com>
I had similar problem; I split my monolithic repo, monolithic-git, as follows.
1. When I did the git-svn, I ended up with git branches for each
project in my svn repo. I think I created these by hand, but I don't
recall.
2. To split project foo into its own repo, foo-git, from monolithic-git, I did:
mkdir foo-git
cd foo-git
git init
git pull ../monolithic-git foo
>From then on, I worked in foo-git. Eventually, I pitched
monolithic-git. I suspect there's a better way to do this...others
will surely chime in.
dave h
^ permalink raw reply
* Re: [PATCH] Introduce git version --list-features for porcelain use
From: Shawn O. Pearce @ 2007-05-31 13:30 UTC (permalink / raw)
To: Alex Riesen; +Cc: Junio C Hamano, git, Johannes Schindelin
In-Reply-To: <81b0412b0705302350i3ebf48e8h24537c20a413e709@mail.gmail.com>
Alex Riesen <raa.lkml@gmail.com> wrote:
> On 5/31/07, Shawn O. Pearce <spearce@spearce.org> wrote:
> >Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> >>
> >> On Wed, 30 May 2007, Alex Riesen wrote:
> >>
> >> > git-version --features?
> >>
> >> Melikes.
> >
> >Good?
> >
>
> Was just a suggestion. Good.
Well, a quick poll on IRC seemed to get like 5 additional votes for
this being a switch on git-version. That sealed the deal. I wasn't
committed one way or the other. I just wanted the functionality...
Also votes from you and Dscho carry a little weight around here. :-)
--
Shawn.
^ permalink raw reply
* Re: [PATCH (tig)] Infrastructure for tig rpm builds.
From: Jonas Fonseca @ 2007-05-31 13:16 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
In-Reply-To: <200705300131.17137.jnareb@gmail.com>
Jakub Narebski <jnareb@gmail.com> wrote Wed, May 30, 2007:
> On Tue, 29 May 2007, Jonas Fonseca wrote:
> > Jakub Narebski <jnareb@gmail.com> wrote Mon, May 28, 2007:
> [...]
> By the way, isn't Ubuntu based on Debian? Do you
> have rpmbuild installed?
Yes it is Debian-based and yes I do, but I don't know if I need to do
something explicitly to get it working. Mostly, prefixing things with
'sudo' works magic on Ubuntu but not in this case. ;)
> BTW. perhaps you could provide spec equivalent for building tig*.deb?
Well, there already exists a Debian package for tig so it would be easy
to lift the files required and if the Debian maintainer wanted it, sure.
However, not as simple as a .spec file so it is more work to maintain.
> 1000:[master!tig]$ make rpm
Maybe you can test the newly released tig 0.7 tarball?
Your patch was added as commit 8cdf56913e7e486bb3f527c24ee4a4d19f2a4f61,
with a few minor adjustments.
> [...]
> >> +%files
> >> +%defattr(-,root,root)
> >> +%{_bindir}/*
> >> +%doc README COPYING INSTALL SITES BUGS TODO tigrc
>
> By the way, should we put tigrc in examples/tigrc, or perhaps in some
> skeleton file?
It is mostly the default (builtin) options, so I don't see the point.
Maybe it is time tig got a contrib area though, since I've been wanting
to make a bash completion file. The tigrc file could go there as
tigrc.sample or something. Could make it more obvious the intension of
the file?
> > I don't know if manual.txt should perhaps be included if
> > HTML and PDF files will not be generated.
> >
> >> +%{!?_without_docs: %{_mandir}/man1/*.1*}
> >> +%{!?_without_docs: %{_mandir}/man5/*.5*}
> >> +%{!?_without_docs: %doc *.html *.pdf}
>
> O.K. It would be as easy as %{?_without_docs: %doc *.txt}
I will try to correct this together with the no-PDF doc-building.
--
Jonas Fonseca
^ permalink raw reply
* [ANNOUNCE] tig 0.7
From: Jonas Fonseca @ 2007-05-31 12:38 UTC (permalink / raw)
To: git
Hello,
tig version 0.7 has been released into the wild. Apart from a few bug
fixes, cleanups, and minor improvements, it has support for a very basic
status view, which makes it possible to stage/unstage changes as well as
add untracked files.
Thanks for the patches related to the build/packaging infrastructure.
Grab the tarball at http://jonas.nitro.dk/tig/releases/
or pull it from git://repo.or.cz/tig.git
Following is a slightly edited shortlog:
Greg KH (1):
Make it possible to install man pages and html files separately
Jakub Narebski (1):
Infrastructure for tig rpm builds
Jonas Fonseca (22):
Add TODO item about diff chunk staging/unstaging
Fix revision graph visualization during incremental updating
Introduce add_line_text to simplify pager based rendering
move_view: fix view->offset overflow bug
Be more paranoid about paths when updating the tree view
Improve management of view->ref and the title line
Move space separator from get_key to formatting in open_help_view
Make keybinding reference more dynamic
Add string_copy_rev
Add notice about empty pager view
Add open method to view_ops
Refactor add_line_text parts into add_line_data; use it in main_read
main_read: cleanup and simplify
Add status view
Add manpage XSL from git and enhance with literallayout fixes
Add version information to man pages
Move "static" version info to VERSION file
Update sync-docs target to use git porcelain instead of cogito
Various random Makefile cleanups
Rename sync-docs to release-doc; add release-dist rule
tig-0.7
--
Jonas Fonseca
^ permalink raw reply
* Re: [MinGW port] Unable to repack on Clearcase dynamic views
From: Paolo Teti @ 2007-05-31 9:46 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: Nguyen Thai Ngoc Duy, Git Mailing List
In-Reply-To: <200705302028.15549.robin.rosenberg.lists@dewire.com>
2007/5/30, Robin Rosenberg <robin.rosenberg.lists@dewire.com>:
> BTW, Does anyone have something like git-cvsexportcommit for clearcase?
a stupid workaround is git-cvsexportcommit + clearimport /clearexport_cvs.
^ permalink raw reply
* Re: [RFH] QGit: how to cram a patch in a crowded screen
From: Alex Riesen @ 2007-05-31 9:27 UTC (permalink / raw)
To: Pavel Roskin; +Cc: Marco Costalba, Andy Parkins, git
In-Reply-To: <1180571013.3582.32.camel@dv>
On 5/31/07, Pavel Roskin <proski@gnu.org> wrote:
> specific behavior. I belong to the post-vi generation, so my mind
> cannot easily associate letters (like 'i' and 'k') with up and down
That's because 'i' is not "up" and 'k' is not "down".
'j' is "down" and 'k' is "up" :-P
^ permalink raw reply
* Re: Yet another Perforce importer
From: Alex Riesen @ 2007-05-31 9:23 UTC (permalink / raw)
To: git
In-Reply-To: <20070522211334.GC30871@steel.home>
Fixed another bug which could commit an empty tree.
Improved error handling: the p4 program sends errors in the data stream,
which were ignored. Now the scripts attempts to print them out.
---
@rem = 'NT: CMD.EXE vim: syntax=perl noet sw=4
@perl -x -s %0 -- %*
@exit
@rem ';
#!perl -w
#line 7
local $VERBOSE = 0;
local $DRYRUN = 0;
local $SHOW_DIFFS = 0;
local $AUTO_COMMIT = 0;
local $JUST_COMMIT = 0;
local $P4CLIENT = undef;
local @EDIT_COMMIT = 0;
local @FULL_IMPORT = 0;
local @DESC = ();
local $SPEC = undef;
local @P4ARGS = ();
local $P4HAVE_FILE = undef;
local %P4USERS = ();
local $FULL_DESC = 1;
local $HEAD_FROM_P4 = 0;
local $P4_EDIT_CHANGED = 0;
local $P4_EDIT_HEAD = undef;
push(@P4ARGS, '-P', $ENV{P4PASSWD})
if defined($ENV{P4PASSWD}) and length($ENV{P4PASSWD});
use Cwd;
local $start_dir = cwd();
sub read_args {
my ($in_client, $in_cl, $in_fi, $in_p4, $no_opt) = (0,0,0,0,0);
foreach my $f ( @_ ) {
goto _files if $no_opt;
if ($in_client) { $in_client = 0; $P4CLIENT = $f; next }
if ($in_cl) { $in_cl=0; push(@DESC,"c$f"); next }
if ($in_fi) { $in_fi=0; push(@DESC,"f$f"); next }
if ($in_p4) { $in_p4=0; push(@DESC,"4$f"); next }
$no_opt=1, next if $f eq '--';
$DRYRUN=1, next if $f eq '-n' or $f eq '--dry-run';
$SHOW_DIFFS=$DRYRUN=1, next if $f eq '--diffs';
$AUTO_COMMIT=1, next if $f eq '-y' or $f eq '--yes';
$JUST_COMMIT=1, next if $f eq '--just-commit';
$EDIT_COMMIT=1, next if ($f eq '-e') or ($f eq '--edit');
$FULL_IMPORT=1, next if $f eq '--full';
$FULL_DESC++, next if $f eq '--p4-desc';
$P4_EDIT_CHANGED=1, next if $f eq '--p4-edit-changed';
if ($f =~ /^--p4-edit-changed=(.*)/) {
$P4_EDIT_CHANGED=1;
$P4_EDIT_HEAD=$1;
next
}
$VERBOSE++, next if $f eq '-v' or $f eq '--verbose';
$in_client = 1, next if $f eq '--client';
$P4CLIENT = $1, next if $f =~ /^--client=(.*)/;
$in_cl = 1, next if $f eq '-C';
push(@DESC,"c$1"), next if $f =~ /^--changelist=(.*)/;
$in_fi = 1, next if $f eq '-F';
push(@DESC,"f$1"), next if $f =~ /^--file=(.*)/;
$in_p4 = 1, next if ($f eq '--ptr') or ($f eq '--p4');
push(@DESC,"4$2"), next if $f =~ /^--(p4|ptr)=(.*)/;
if ($f eq '--help' or $f eq '-h') {
print <<EOF;
$0 [-n|--dry-run] [-y|--yes] [--client <client-name>] [--diffs] \
[-e|--edit] [--just-commit] [--full] [-v|--verbose] [-C <change-number>] \
[-F <filename>] [--ptr|--p4 <p4-path-and/or-revision>] [--p4-desc] \
[--] [<specification>]
Perforce client state importer. Creates a git commit on the current
branch from a state the given p4 client and working directory hold.
<specification> must be given and is expected to be a file which will be
stored on the side branch under the name "spec".
Remote-to-local mapping and the revisions of files are stored in "have",
and the client definition - in "client".
--client client Specify client name (saved in .git/p4/client for the next time)
--full Perform full import, don't even try to figure out what changed
-y|--yes Commit automatically (by default only index updated)
--just-commit To be used after you forgot to run with --yes first time
-n|--dry-run Do not update the index and do not commit
-e|--edit Edit commit description before committing
-v|--verbose Be more verbose. Can be given many times, increases verbosity
--file=file
-F file Take description for the commit from a file in the
next parameter
--changelist=change
-C change Take description for the commit from this p4 change
--p4|--ptr p4-path-and/or-revision
--p4|--ptr=p4-path-and/or-revision
Take description for the commit from the p4 change described
by this p4 path, possibly including revision specification
--p4-desc Increase amount of junk from p4 change description
--diffs Show files which are different between local filesystem, index,
and the current HEAD. Does not do anything else
--p4-edit-changed
--p4-edit-changed=sha1
Merge with the given sha1 and prepare a p4 submission.
Current HEAD must fast-forward to sha1. If sha1 is omited,
the current HEAD is assumed. The working directory must
have no local changes.
The descriptions taken from p4 changes given by -C and --p4 will
be concatenated if the options given multiple times.
"--" can be used to separate options from description files.
EOF
exit(0);
}
die "$0: unknown option $f\n" if $f =~ /^-/;
_files:
warn "$0: spec was already set, $SPEC ignored\n" if defined($SPEC);
$SPEC = $f;
}
}
read_args(@ARGV);
local ($GIT_DIR) = qx{git rev-parse --git-dir};
$GIT_DIR =~ s/\r?\n$//s if defined($GIT_DIR);
die "$0: git directory not found\n" if !defined($GIT_DIR) or !-d $GIT_DIR;
local $editor = $ENV{VISUAL};
$editor = $ENV{EDITOR} unless defined($editor);
$editor = 'd:/Programs/Vim/vim70/gvim.exe' unless defined($editor);
die "$0: no editor defined\n" unless defined($editor);
if ($SHOW_DIFFS) {
my $sep = $/;
$/="\0";
my ($show, $cnt) = (0, 0);
if (open(F, '-|', 'git diff-files -r --name-only -z')) {
while (<F>) {
my $c = chop;
$_ .= $c if $c ne "\0";
print "Changed files:\n" if !$show;
print " $_\n";
$show = 1;
$cnt++;
}
close(F);
}
if (open(F, '-|', 'git diff-index --cached -r -z HEAD')) {
$show = 0;
my ($diff, $info) = (0, 1);
while (<F>) {
my $c = chop;
$_ .= $c if $c ne "\0";
if ($info) {
next if !/^:(\d{6}) (\d{6}) ([0-9a-f]{40}) ([0-9a-f]{40}) ./o;
# show only content changes, p4 does not support exec-bit anyway
$diff = $3 ne $4;
} elsif ($diff) {
print "Changes between index and HEAD:\n" if !$show;
print " $_\n";
$show = 1;
$cnt++;
}
$info = !$info;
}
close(F);
}
$/ = $sep;
exit($cnt ? 1: 0);
}
# P4 client was given in command-line. Store it
if ( defined($P4CLIENT) ) {
mkdir "$GIT_DIR/p4", 0777;
if ( open(F, '>', "$GIT_DIR/p4/client") ) {
print F "$P4CLIENT\n";
close(F);
} else {
die "$0: cannot store client name: $!\n"
}
} else {
if ( open(F, '<', "$GIT_DIR/p4/client") ) {
($P4CLIENT) = <F>;
close(F);
$P4CLIENT =~ s/^\s*//,$P4CLIENT =~ s/\s*$// if defined($P4CLIENT);
}
}
die "P4 client not defined\n" if !defined($P4CLIENT) or !length($P4CLIENT);
print "reading P4 client $P4CLIENT\n" if $VERBOSE;
local ($P4ROOT, $p4clnt, $P4HOST);
open(my $fdo, '>', "$GIT_DIR/p4/client.def") or die "p4/client.def: $!\n";
binmode($fdo);
open(my $fdi, '-|', "p4 client -o $P4CLIENT") or die "p4 client: $!\n";
binmode($fdi);
my $last_line_len = 0;
while (<$fdi>) {
next if /^#/o;
if ( m/^\s*Root:\s*(\S+)[\\\/]*\s*$/so ) { $P4ROOT = $1 }
elsif ( m/^\s*Client:\s*(\S+)/o ) { $p4clnt = $1 }
elsif ( m/^\s*Host:\s*(\S+)/o ) { $P4HOST = $1 }
($VERBOSE and print), next if /^(Access|Update):/;
s/\r?\n$//so;
my $len = length($_);
print $fdo "$_\n" if $len or $len != $last_line_len;
$last_line_len = $len;
}
close($fdi);
close($fdo);
die "Client root not defined\n" unless defined($P4ROOT);
if ( $VERBOSE ) {
print "GIT_DIR: $GIT_DIR\n";
print "Root: $P4ROOT (cwd: $start_dir)\n";
print "Host: $P4HOST\n";
print "Client: $p4clnt\n" if $p4clnt ne $P4CLIENT;
}
if ($P4_EDIT_CHANGED) {
my $rc = system('git', 'diff-files', '--quiet');
exit(127) if $rc & 0xff; # error starting the program
die "$0: there are changes in $P4ROOT. Import them first.\n" if $rc;
$P4_EDIT_HEAD = 'HEAD' if !defined($P4_EDIT_HEAD);
my ($mergehead) = qx{git rev-parse $P4_EDIT_HEAD};
exit(127) if $?;
exit(1) if !defined($mergehead);
$mergehead =~ s/\r?\n//gs;
exit(1) if !length($mergehead);
print "Checking out $P4_EDIT_HEAD ($mergehead) for p4 edit\n" if $VERBOSE;
# Check if the give reference is a direct descendant of current branch
if ($P4_EDIT_HEAD ne 'HEAD') {
my ($sha1) = qx{git rev-list --max-count=1 $mergehead..HEAD};
exit(127) if $?;
die "$0: HEAD does not fast-forward to $P4_EDIT_HEAD\n"
if defined($sha1) and $sha1 =~ /^[0-9a-f]{40}\b/;
}
my $cnt;
my @files = ();
my $sep = $/;
$/="\0";
if (open(F, '-|', "git diff-index -R --cached -r -z $mergehead")) {
my ($diff, $info, $M) = (0, 1, '');
while (<F>) {
my $c = chop;
$_ .= $c if $c ne "\0";
if ($info) {
next if !/^:\d{6} \d{6} ([0-9a-f]{40}) ([0-9a-f]{40}) (\w+)/o;
# use only content changes, p4 does not support exec-bit
$diff = $1 ne $2;
$M = $3; # change type marker
} elsif ($diff) {
print "$M $_\n" if $VERBOSE;
die "File contains characters which p4 cannot support\n"
if /[\n@#%*]/s;
push @files, "$M$_";
$cnt++;
}
$info = !$info;
}
close(F);
}
$/ = $sep;
if (!$cnt) {
warn "$0: No content changes found between HEAD and $P4_EDIT_HEAD";
exit(0);
}
# Create a new changelist
my $p4;
open($p4, "p4 -c $P4CLIENT -H $P4HOST -d $P4ROOT change -o|") or
die "$0: failed to create changelist\n";
my @desc = map {s/\r?\n//so; $_} <$p4>;
close($p4);
open($p4, '>', "$GIT_DIR/p4/changelist") or
die "$GIT_DIR/p4/changelist: $!\n";
foreach (@desc) {
print $p4 "$_\n";
if (/^Description:/o) {
my $range = "..$mergehead";
$range = "${mergehead}^..$mergehead" if $P4_EDIT_HEAD eq 'HEAD';
if (open(my $fd, '-|', "git log $range")) {
while(<$fd>) {
# I believe it is not possible to save this information
# in Perforce.
next if /^(commit |Author:|Date:)/;
s/\r?\n$//so;
next if !length($_);
s/^\s+//o;
print $p4 " $_\n";
}
close($fd);
}
}
}
close($p4);
open(STDIN, '<', "$GIT_DIR/p4/changelist") or
die "$GIT_DIR/p4/changelist: $!\n";
open($p4, "p4 -c $P4CLIENT -H $P4HOST -d $P4ROOT change -i|") or
die "$0: failed to create changelist\n";
my ($newchange) = grep {s/^Change (\d+) created\b.*/$1/so} <$p4>;
close($p4);
print "Checking out P4 files in changelist $newchange\n" if $VERBOSE;
# open files for edit
$cnt = 0;
open($p4, '>', "$GIT_DIR/p4/files") or die "$GIT_DIR/p4/files: $!\n";
print $p4 "-c\n$newchange\n";
print $p4 (map {++$cnt; substr($_,1)."\n"} grep {/^M/} @files);
close($p4);
sub runp4 {
return system('p4','-c',$P4CLIENT,'-H',$P4HOST,'-d',$P4ROOT,@_);
}
runp4('-x',"$GIT_DIR/p4/files", 'edit') if $cnt;
$cnt = 0;
open($p4, '>', "$GIT_DIR/p4/files") or die "$GIT_DIR/p4/files: $!\n";
print $p4 "-c\n$newchange\n";
print $p4 (map {++$cnt; substr($_,1)."\n"} grep {/^A/} @files);
close($p4);
runp4('-x',"$GIT_DIR/p4/files", 'add') if $cnt;
$cnt = 0;
open($p4, '>', "$GIT_DIR/p4/files") or die "$GIT_DIR/p4/files: $!\n";
print $p4 "-c\n$newchange\n";
print $p4 (map {++$cnt; substr($_,1)."\n"} grep {/^D/} @files);
close($p4);
runp4('-x',"$GIT_DIR/p4/files", 'delete') if $cnt;
# p4 modifies working directory on checkout, stupid thing
system('git', 'update-index', '--refresh');
$rc = system('git', 'read-tree', '-m', '-u', $mergehead);
exit(127) if $rc & 0xff;
exit(1) if $rc;
print "The state of $P4_EDIT_HEAD($mergehead) is checked out.\n";
print "A p4 changelist $newchange is prepared.\n";
exit(0);
}
my ($git_head,$git_p4_head,$git_p4_have) = &git_p4_init;
if ($JUST_COMMIT) {
git_p4_commit($git_head, $git_p4_head);
exit 0;
}
local %gitignore_dirs = ();
$gitignore_dirs{'/'} = read_filter_file("$GIT_DIR/info/exclude");
push(@{$gitignore_dirs{'/'}}, @{read_filter_file('.gitignore')});
my %git_index = ();
$/ = "\0";
my @git_X = ();
print "Reading git file list(git ls-files @git_X --cached -z)...\n" if $VERBOSE;
foreach ( qx{git ls-files @git_X --cached -z} ) {
chop; # chop \0
next if m/^\.gitignore$/o;
next if m/\/\.gitignore$/o;
next if filtered($_);
$git_index{$_} = 1;
}
my @git_add = ();
my @git_addx = ();
my @git_del = ();
my @git_upd = ();
print "Reading P4 file list...\n" if $VERBOSE;
local ($Conflicts,$Ignored,$Added,$Deleted,$Updated) = (0,0,0,0,0);
$/ = "\n";
my $in_name = 0;
my @root = split(/[\/\\]+/, $P4ROOT);
my %p4_index = ();
my %p4_a_lc = ();
my %lnames = ();
my %lconflicts = ();
if (opendir(DIR, '.')) {
$lnames{'.'} = [grep {$_ ne '.' and $_ ne '..'} readdir(DIR)];
closedir(DIR);
#print "read $start_dir (",scalar(@{$lnames{'.'}}),")\n";
}
open(my $have, "p4 -G @P4ARGS -c $P4CLIENT -H $P4HOST -d $P4ROOT have |") or
die "$0: failed to start p4: $!\n";
binmode($have);
$P4HAVE_FILE = "$GIT_DIR/p4/have";
open(my $storedhave, '>', $P4HAVE_FILE) or die "$P4HAVE_FILE: $!\n";
binmode($storedhave);
my ($cnt,$err,$ent) = (0,0,undef);
while (defined($ent=read_pydict_entry($have))) {
if (defined($ent->{code}) and defined($ent->{data})) {
++$err if $ent->{code} eq 'error';
print STDERR 'p4: '.$ent->{code}.': '.$ent->{data}."\n";
next;
}
next if !defined($ent->{depotFile}) or !defined($ent->{clientFile});
++$cnt;
my $a = $ent->{depotFile};
$ent->{clientFile} =~ m!^//[^/]+/(.*)!o;
my $b = $1;
my @bb = split(/\/+/, $b);
print $storedhave "$a\0$ent->{clientFile}\0$ent->{haveRev}\0\n";
if ( $^O eq 'MSWin32' ) {
# stupid windows, daft activestate, dumb P4
# This piece below is checking for file name conflicts
# which happen on windows because of it mangling the names.
my $blc = lc $b;
if ( $#bb > 0 ) {
my $path = '.';
foreach my $n (@bb[0 .. $#bb -1]) {
my @conflicts =
grep {lc $_ eq lc $n and $_ ne $n} @{$lnames{$path}};
if (@conflicts and !exists($lconflicts{"$path/$n"})) {
warn "warning: $a -> $b\n".
"warning: conflict between path \"$path/$n\" and ".
"local filesystem in \"@conflicts\"\n";
$Conflicts++;
$lconflicts{"$path/$n"} = 1;
}
$path .= "/$n";
if (!exists($lnames{$path})) {
if (opendir(DIR, $path)) {
$lnames{$path} =
[grep {$_ ne '.' and $_ ne '..'} readdir(DIR)];
closedir(DIR);
#print "read $path (",scalar(@{$lnames{$path}}),")\n";
}
}
}
}
if (!exists($p4_a_lc{$blc})) {
$p4_a_lc{$blc} = [$a, $b];
} else {
warn("warning: $a -> $b\n".
"warning: conflicts with ".
$p4_a_lc{$blc}->[0]." -> ".
$p4_a_lc{$blc}->[1]."\n");
$Conflicts++;
next;
}
}
my $i;
for ($i = 0; $i < $#bb; ++$i) {
my $bdir = join('/',@bb[0 .. $i]) . '/';
if ( !exists($gitignore_dirs{$bdir}) ) {
$gitignore_dirs{$bdir} = read_filter_file("$bdir.gitignore");
}
}
if (filtered($b)) {
print " i $b\n" if $VERBOSE > 3;
$Ignored++;
next
}
$p4_index{$b} = $a;
if ( exists($git_index{$b}) ) {
my $needup = 1;
if (defined($git_p4_have)) {
$prev = $git_p4_have->{$a};
if (defined($prev)) {
$prev->[0] =~ m!^//[^/]+/(.*)!o;
$needup = 0 if ($b eq $1) and ($prev->[1] eq $ent->{haveRev});
if ($needup and $VERBOSE > 1) {
my $reason;
$reason = 'local file' if $b ne $1;
$reason = 'revision' if $prev->[1] ne $ent->{haveRev};
print "$a ($reason changed)\n";
}
}
}
if ($needup) {
$Updated++;
push(@git_upd, $b);
}
} else {
$Added++;
if ( $b =~ m/\.(bat|cmd|pl|sh|exe|dll)$/io )
{ push(@git_addx, $b) } else { push(@git_add, $b) }
}
}
close($storedhave);
close($have);
exit 1 if $err; # the error already reported
die "Nothing in the client $P4CLIENT\n" if !$cnt;
undef %p4_a_lc;
@git_del = grep { !exists($p4_index{$_}) } keys %git_index;
$Deleted = $#git_del + 1;
#foreach (keys %git_index)
#{ push(@git_del, $_) if !exists($p4_index{$_}) }
if ( $DRYRUN ) {
print($#git_add+$#git_addx+ 2," files to add\n") if $VERBOSE;
print map {" a $_\n"} @git_add if $VERBOSE > 2;
print map {" a $_\n"} @git_addx if $VERBOSE > 2;
print($#git_del+1," files to unreg\n") if $VERBOSE;
print map {" d $_\n"} @git_del if $VERBOSE > 2;
print($#git_upd+1," files to update\n") if $VERBOSE;
print map {" u $_\n"} @git_upd if $VERBOSE > 2;
print "added: $Added, unregd: $Deleted, updated: $Updated,
ignored: $Ignored";
print ", conflicts: $Conflicts" if $Conflicts;
print "\n";
} else {
if (@git_add || @git_addx) {
print($#git_add+$#git_addx+ 2,
" files | git update-index --add -z --stdin\n")
if $VERBOSE;
if (@git_add) {
open(GIT, '| git update-index --add --chmod=-x -z --stdin') or
die "$0 git-update-index(add): $!\n";
print GIT map {print " a $_\n" if $VERBOSE > 1; "$_\0"} @git_add;
close(GIT);
}
if (@git_addx) {
open(GIT, '| git update-index --add --chmod=+x -z --stdin') or
die "$0 git-update-index(add): $!\n";
print GIT map {print " a $_\n" if $VERBOSE > 1; "$_\0"} @git_addx;
close(GIT);
}
}
if (@git_del) {
print($#git_del+1," files | git update-index --remove -z --stdin\n")
if $VERBOSE;
open(GIT, '| git update-index --force-remove -z --stdin') or
die "$0 git-update-index(del): $!\n";
print GIT map {print " d $_\n" if $VERBOSE > 1; "$_\0"} @git_del;
close(GIT);
}
if (@git_upd) {
print($#git_upd+1," files | git update-index -z --stdin\n")
if $VERBOSE;
open(GIT, '| git update-index -z --stdin') or
die "$0 git-update-index(upd): $!\n";
print GIT map {print " u $_\n" if $VERBOSE > 1; "$_\0"} @git_upd;
close(GIT);
}
print "added: $Added, unregd: $Deleted, updated: $Updated,
ignored: $Ignored";
print ", conflicts: $Conflicts" if $Conflicts;
print "\n";
git_p4_commit($git_head, $git_p4_head) if $AUTO_COMMIT;
}
exit 0;
sub filtered {
my $name = shift;
study($name);
my @path = split(/\/+/o, $name);
my $dir = '';
$name = '';
foreach my $d (@path) {
$name .= $d;
# print STDERR "$dir: $name $d\n" if $v;
foreach my $re (@{$gitignore_dirs{'/'}}) {
return 1 if $name =~ m/$re/;
return 1 if $d =~ m/$re/;
}
if ( length($dir) and exists($gitignore_dirs{$dir}) ) {
foreach my $re (@{$gitignore_dirs{$dir}}) {
return 1 if $name =~ m/$re/;
return 1 if $d =~ m/$re/;
}
}
$name .= '/';
$dir = $name;
}
# print STDERR "$name not filtered\n" if $v;
return 0;
}
sub read_filter_file {
my @filts = ();
my $file = shift;
if ( open(my $if, '<', $file) ) {
print "added ignore file $file\n" if $VERBOSE;
$/ = "\n";
while (my $l = <$if>) {
next if $l =~ /^\s*#/o;
next if $l =~ /^\s*$/o;
$l =~ s/[\r\n]+$//so;
$l =~ s/\./\\./go;
$l =~ s/\*/.*/go;
if ( $l =~ m/\// ) {
$l = "^$l($|/)";
} else {
$l = "(^|/)$l\$";
}
print " filter $l\n" if $VERBOSE > 1;
push(@filts, qr/$l/);
}
close($if);
}
return \@filts;
}
sub r_pystr
{
my $fd = shift;
my ($len,$str)=('','');
my ($c,$rd,$b) = (4,0,'');
while ($c > 0) {
$rd = sysread($fd,$b,$c);
warn("failed to read len: $!"), return undef if !defined($rd);
warn("not enough data for len"), return undef if !$rd;
$len .= $b;
$c -= $rd;
}
$len = unpack('V',$len);
while ($len > 0) {
$rd = sysread($fd,$b,$len);
warn("failed to read data: $!"), return undef if !defined($rd);
warn("not enough data"), return undef if !$rd;
$str .= $b;
$len -= $rd;
}
return $str;
}
sub read_pydict_entry
{
my $f = shift;
my ($buf,$rd);
FIL: while (1) {
# object type identifier
$rd = sysread($f, $buf, 1);
last FIL if $rd == 0;
warn("p4: object type: $!\n"),last if $rd != 1;
# '{' is a python marshalled dict
warn("p4: object type: not {\n"),last if $buf ne '{';
my $ent = {};
PAIR: while (1) {
my ($b,$key);
# key type identifier
$rd = sysread($f, $b, 1);
warn("p4: key type: $!\n"),last FIL if $rd != 1;
if ($b eq 's') { # length-prefixed string
$key = r_pystr($f);
warn("p4: key: $!\n"),last FIL if !defined($b);
} elsif ($b eq '0') { # NULL-element, end of entry
last PAIR;
} else {
die("p4: key type: not s (string)\n");
last FIL;
}
# value type identifier
$rd = sysread($f, $b, 1);
warn("p4: $key value type: $!\n"),last FIL if $rd != 1;
if ($b eq 's') { # length-prefixed string
$b = r_pystr($f);
warn("p4: $key value: $!\n"),last FIL if !defined($b);
$ent->{$key} = $b;
} elsif ($b eq 'i') { # 4-byte integer
$rd = sysread($f, $b, 4);
warn("p4: $key value data: $!\n"),last FIL if $rd != 4;
$ent->{$key} = $b;
} else {
warn("p4: $key value type: not s ($b)\n");
last FIL;
}
}
return $ent;
}
return undef;
}
sub cl2msg {
my $cl = shift;
my($o1,$o2,$i);
if(!open($o1, '>>', "$GIT_DIR/p4/msg")) {
warn "p4/msg: $!\n";
return;
}
binmode($o1);
if(!open($o2, '>>', "$GIT_DIR/p4/p4msg")) {
warn "p4/p4msg: $!\n";
close($o1);
return
}
binmode($o2);
if(!open($i, '-|', "p4 describe -s $cl")){
warn "p4 describe: $!\n";
close($o1);
close($o2);
return
}
binmode($i);
print $o1 "$cl: " if $FULL_DESC;
print $o2 "$cl: ";
my @a;
my $u = undef;
while (my $l = <$i>) {
if ($l =~ /^Change \d+ by (\S+)@[^ ]* on ([^\r\n]*)/so) {
$u = $1;
$ENV{GIT_AUTHOR_DATE} = $2 if length($2);
}
last if $FULL_DESC < 2 and $l =~ /^\s*Affected files \.{3}\s*$/so;
$l =~ s/\r?\n$//so;
push @a, $l;
}
close($i);
print $o2 substr($a[2],1),"\n"; # p4 side-branch commit description
close($o2);
# import branch commit description
if ($FULL_DESC > 1) {
# desc level 2+: keep the Change line
print $o1 map {"$_\n"} (substr($a[2],1),"\n",@a);
} else {
# levels 0 and 1: remove the Change line
print $o1 map { (length($_) ? substr($_,1):'')."\n" } @a[2..$#a];
}
close($o1);
if (defined($u)) {
if (!exists($P4USERS{$u})) {
my ($mail,$name) = grep {/^(Email|FullName):/} qx{p4 user -o $u};
if ($? == 0 and defined($mail) and defined($name)) {
s/^\S+: ([^\r\n]*)\r?\n$/$1/so for ($mail,$name);
if (length($name) and length($mail)) {
$P4USERS{$u} = {name=>$name, email=>$mail};
}
}
}
if ($P4USERS{$u}) {
$p4u = $P4USERS{$u};
$ENV{GIT_AUTHOR_NAME} = $p4u->{name};
$ENV{GIT_AUTHOR_EMAIL} = $p4u->{email};
}
}
}
sub git_p4_init {
my ($commit,$parent,$p4commit,$p4parent);
my ($HEAD) = qx{git rev-parse HEAD};
$HEAD = '' if $?;
my ($p4head) = qx{git rev-parse refs/p4import/$P4CLIENT};
$p4head = '' if $?;
s/\r?\n//gs for ($HEAD, $p4head);
die "No HEAD commit! Refusing to import.\n" if !length($HEAD);
if (length($p4head)) {
($commit,$p4parent) =
grep { s/^parent (.{40}).*/$1/s }
qx{git cat-file commit $p4head};
$commit = $p4parent = '' if $?;
$p4parent = '' if !defined($p4parent);
} else {
$commit = $p4parent = '';
}
while (($commit ne $HEAD) and length($p4parent)) {
$p4head = $p4parent;
($commit,$p4parent) =
grep { s/^parent (.{40}).*/$1/s }
qx{git cat-file commit $p4head};
$commit = $p4parent = '' if $?;
$p4parent = '' if !defined($p4parent);
if ($VERBOSE and ($HEAD eq $commit)) {
print "found p4 import commit ";
system('git','name-rev',$p4head);
}
}
if ($HEAD ne $commit) {
$HEAD_FROM_P4 = 0;
warn "Current HEAD is not from $P4CLIENT, doing full import\n";
} else {
$HEAD_FROM_P4 = 1;
}
my $p4have = undef;
if (!$FULL_IMPORT and ($HEAD eq $commit) and length($p4head)) {
if (open(my $f, '-|', "git cat-file blob $p4head:have")) {
my $old = $/;
$/ = "\0";
my $cnt = 0;
while(1) {
my $p4name = <$f>;
last if !defined($p4name);
$p4name =~ s/^.//so if $cnt; # remove \n
my $name = <$f>;
my $rev = <$f>;
last if !defined($name) or !defined($rev);
chop($p4name,$name,$rev);
++$cnt;
if (defined($p4have)) {
$p4have->{$p4name} = [$name,$rev];
} else {
$p4have = {$p4name=>[$name,$rev]};
}
}
$/ = $old;
close($f);
print "loaded $cnt revisions from $p4head\n" if $VERBOSE;
}
}
return ($HEAD, $p4head, $p4have);
}
sub git_p4_commit {
my ($HEAD, $p4head) = @_;
my ($commit,$parent,$p4commit,$p4parent);
my ($fdo,$fdi,$rc);
$rc = system('git','diff-index','--exit-code','--quiet','--cached','HEAD');
if ($rc == 0) {
warn("No changes\n");
return;
}
return if $DRYRUN;
if (!@DESC && !$EDIT_COMMIT) {
warn "$0: no commit description given\n";
return;
}
my $p4x = "$GIT_DIR/p4/idx.tmp";
unlink($p4x);
$ENV{PAGER} = 'cat';
if (!defined($SPEC) or !open(STDIN, '<', $SPEC)) {
if ( $^O eq 'MSWin32' ) {
open(STDIN, '<', 'NUL') or die "$SPEC: $!\n";
} else {
open(STDIN, '<', '/dev/null') or die "$SPEC: $!\n";
}
}
my ($p4spec) = qx{git hash-object -t blob -w --stdin};
die "Failed to store $SPEC in git repo\n" if $?;
open(STDIN, '<', "$GIT_DIR/p4/client.def") or die "cldef: $!\n";
my ($p4clnt) = qx{git hash-object -t blob -w --stdin};
die "Failed to save mappings of $P4CLIENT in git repo" if $?;
if (!defined($P4HAVE_FILE)) {
print "reading state of $P4CLIENT\n" if $VERBOSE;
$P4HAVE_FILE = "$GIT_DIR/p4/have";
open($fdo, '>', $P4HAVE_FILE) or die "p4/have: $!\n";
binmode($fdo);
open($fdi, "p4 -G @P4ARGS -c $P4CLIENT -H $P4HOST -d $P4ROOT have|") or
die "p4 have: $!\n";
binmode($fdi);
my ($cnt,$err,$ent) = (0,0,undef);
while (defined($ent=read_pydict_entry($fdi))) {
if (defined($ent->{code}) and defined($ent->{data})) {
++$err if $ent->{code} eq 'error';
print STDERR 'p4: '.$ent->{code}.': '.$ent->{data}."\n";
next;
}
next if !defined($ent->{depotFile});
next if !defined($ent->{clientFile});
++$cnt;
print $fdo "$ent->{depotFile}\0",
"$ent->{clientFile}\0",
"$ent->{haveRev}\0\n";
}
close($fdi);
close($fdo);
exit 1 if $err; # the error already reported
die "The client $P4CLIENT has nothing\n" if !$cnt;
}
open(STDIN, '<', $P4HAVE_FILE) or die "$P4HAVE_FILE: $!\n";
my ($p4have) = qx{git hash-object -t blob -w --stdin};
die "Failed to save state of $P4CLIENT in git repo" if $?;
#
# Prepare commit messages
#
unlink("$GIT_DIR/p4/msg", "$GIT_DIR/p4/p4msg");
open($fdo, '>', "$GIT_DIR/p4/msg"); close($fdo);
open($fdo, '>', "$GIT_DIR/p4/p4msg"); close($fdo);
foreach my $i (@DESC) {
$i =~ s/^(.)//o;
if ('c' eq $1) {
print "reading changes for $i\n" if $VERBOSE;
cl2msg($i);
} elsif ('f' eq $1) {
my($o1,$o2,$i);
if (open($o1, '>>', "$GIT_DIR/p4/msg")) {
if (open($o2, '>>', "$GIT_DIR/p4/p4msg")) {
if (open($i, '<', $i)) {
my $n = 0;
while(<$i>) {
$n++;
print $o1 $_;
print $o2 $_ if $n == 1;
}
close($i);
}
close($o2);
}
close($o1);
}
} elsif ('4' eq $1) {
print "reading changes for $i\n" if $VERBOSE;
my ($change)=qx{p4 changes -m1 $i};
if (!defined($change) or $change !~ m/\s+(\d+)\s/) {
die "$i does not resolve into a change number\n";
}
cl2msg($1);
}
}
system("$editor $GIT_DIR/p4/msg") if $EDIT_COMMIT;
# copy mirror-branch commit message into side-branch
# commit message if no other description were given.
if (!-s "$GIT_DIR/p4/p4msg") {
open($fdi, '<', "$GIT_DIR/p4/msg") or die "$GIT_DIR/p4/msg: $!\n";
sysread($fdi,$buf,-s "$GIT_DIR/p4/msg");
close($fdi);
open($fdo, '>>', "$GIT_DIR/p4/p4msg") or die "$GIT_DIR/p4/p4msg: $!\n";
syswrite($fdo,$buf);
close($fdo);
}
#
# Store the imported file data
#
if ($VERBOSE < 2) {
if ( $^O eq 'MSWin32' ) { open(STDERR, "NUL") }
else { open(STDERR, "/dev/null") }
}
my ($tree) = qx{git write-tree};
die "Failed to write current tree\n" if $?;
$parent = length($HEAD) ? "-p $HEAD": '';
open(STDIN, '<', "$GIT_DIR/p4/msg") or die "p4/msg: $!\n";
$tree =~ s/\r?\n//gs;
($commit)=qx{git commit-tree $tree $parent};
die "failed to commit current tree\n" if $?;
s/\r?\n//gs for ($commit);
print "current tree stored in commit $commit\n" if $VERBOSE;
#
# Storing import control data
#
$ENV{GIT_INDEX_FILE} = $p4x;
open($fdo, '|-', 'git update-index --add --index-info') or
die "could not start git update-index\n";
binmode($fdo);
s/\r?\n//gs for ($p4spec,$p4clnt,$p4have);
print $fdo "100644 $p4spec\tspec\n";
print $fdo "100644 $p4clnt\tclient\n";
print $fdo "100644 $p4have\thave\n";
close($fdo);
if($?) {
die "Failed to store $SPEC in p4import index and git repo\n".
"Failed to save mappings of $P4CLIENT in p4import index and git repo\n".
"Failed to save state of $P4CLIENT in p4import index and git repo\n"
}
my ($p4tree)=qx{git write-tree};
die "Failed to store $SPEC (tree) in git repo\n" if $?;
# Bind import control data to the file data
$p4parent="-p $commit";
$p4parent="$p4parent -p $p4head" if length($p4head);
open(STDIN, '<', "$GIT_DIR/p4/p4msg") or die "p4/p4msg: $!\n";
$p4tree =~ s/\r?\n//gs;
($p4commit)=qx{git commit-tree $p4tree $p4parent};
die "Failed to store $SPEC (commit) in git repo\n" if $?;
$p4commit =~ s/\r?\n//gs;
# Finishing touches: update references
system('git','update-ref','-m','backup ref of current branch',
'p4/backup-HEAD','HEAD');
system('git','update-ref','-m','backup ref of p4import',
'p4/backup-p4import',"refs/p4import/$P4CLIENT");
$rc = system('git','update-ref','-m','data of p4import','HEAD',$commit);
die "Failed to update HEAD\n" if $rc;
$rc = system('git','update-ref','-m','p4import',"refs/p4import/$P4CLIENT",$p4commit);
die "Failed to store $SPEC (reference) in git repo\n" if $rc;
if ($VERBOSE) {
print STDOUT (grep {s/\r?\n//gs;s/.*?\s//} qx{git name-rev
refs/p4import/$P4CLIENT}), ":\n";
system('git','log','--max-count=1','--pretty=format:%h %s%n',$p4commit);
}
print STDOUT (grep {s/\r?\n//gs;s/.*?\s//} qx{git name-rev HEAD}), ":\n";
system('git','log','--max-count=1','--pretty=format:%h %s%n',$commit);
}
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox