* [PATCH] pack-objects: finishing touches.
From: Junio C Hamano @ 2006-02-17 10:37 UTC (permalink / raw)
To: git
In-Reply-To: <7vu0ay8v4f.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano <junkio@cox.net> writes:
> This one has one nasty data corruption bug, which fortunately I
> think I have figured out how to fix. Please do not use it for
> your production repository in the meantime.
It turns out that there wasn't a data corruption bug, but it can
create a pack with delta chains whose length exceeds twice the
specified depth. The data corruption bug was on my unpublished
WIP and killed even before it hit "pu" ;-). This addresses most
of the remaining issues and has been merged to "next" tonight.
-- >8 --
This introduces --no-reuse-delta option to disable reusing of
existing delta, which is a large part of the optimization
introduced by this series. This may become necessary if
repeated repacking makes delta chain too long. With this, the
output of the command becomes identical to that of the older
implementation.
It still allows reusing non-deltified representations; there is
no point uncompressing and recompressing the whole text.
It also adds a couple more statistics output, while squelching
it under -q flag, which the last round forgot to do.
One remaining minor issue when --no-reuse-delta option is not
used is that it can create a delta chain that is deeper than
specified.
A<--B<--C<--D E F G
Suppose we have a delta chain A to D (A is stored in full either
in a pack or as a loose object. B is depth1 delta relative to A,
C is depth2 delta relative to B...) with loose objects E, F, G.
And we are going to pack them.
B, C and D are left as delta against A, B and C respectively.
So A, E, F, and G are examined, and let's say we decided to keep
E expanded, and store the rest as deltas like this:
E<--F<--G<--A
Oops. We ended up making D a bit too deep, didn't we? B, C and
D form a chain on top of A!
This is because we did not know what the final depth of A would
be when checking objects and deciding to keep the existing
delta.
To prevent this from happening, we could say that A should be
kept expanded. But how would we tell that, cheaply?
To do this most precisely, after check_object() runs, each
object that is used as the base object of some existing delta
needs to be marked with the maximum depth of the objects we
decided to keep deltified (in this case, D is depth 3 relative
to A, so if no other delta chain that is longer than 3 based on
A exists, mark A with 3). Then when attempting to deltify A, we
would take that number into account to see if the final delta
chain that leads to D becomes too deep.
However, this is a bit cumbersome to compute, so we would cheat
and reduce the maximum depth for A arbitrarily to depth/4 in
this implementation.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
Documentation/git-pack-objects.txt | 21 +++++++
pack-objects.c | 102 +++++++++++++++++++++++++-----------
2 files changed, 91 insertions(+), 32 deletions(-)
98885061623676a37575e59d7f7aff64072e3300
diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt
index 2d67d39..4cb2e83 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.txt
@@ -8,7 +8,10 @@ git-pack-objects - Create a packed archi
SYNOPSIS
--------
-'git-pack-objects' [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list
+[verse]
+'git-pack-objects' [-q] [--no-reuse-delta] [--non-empty]
+ [--local] [--incremental] [--window=N] [--depth=N]
+ {--stdout | base-name} < object-list
DESCRIPTION
@@ -32,6 +35,10 @@ Placing both in the pack/ subdirectory o
any of the directories on $GIT_ALTERNATE_OBJECT_DIRECTORIES)
enables git to read from such an archive.
+In a packed archive, an object is either stored as a compressed
+whole, or as a difference from some other object. The latter is
+often called a delta.
+
OPTIONS
-------
@@ -74,6 +81,18 @@ base-name::
Only create a packed archive if it would contain at
least one object.
+-q::
+ This flag makes the command not to report its progress
+ on the standard error stream.
+
+--no-reuse-delta::
+ When creating a packed archive in a repository that
+ has existing packs, the command reuses existing deltas.
+ This sometimes results in a slightly suboptimal pack.
+ This flag tells the command not to reuse existing deltas
+ but compute them from scratch.
+
+
Author
------
Written by Linus Torvalds <torvalds@osdl.org>
diff --git a/pack-objects.c b/pack-objects.c
index 70fb2af..38e1c99 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -5,7 +5,7 @@
#include "csum-file.h"
#include <sys/time.h>
-static const char pack_usage[] = "git-pack-objects [-q] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list";
+static const char pack_usage[] = "git-pack-objects [-q] [--no-reuse-delta] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list";
struct object_entry {
unsigned char sha1[20];
@@ -14,10 +14,11 @@ struct object_entry {
unsigned int depth; /* delta depth */
unsigned int hash; /* name hint hash */
enum object_type type;
+ unsigned char edge; /* reused delta chain points at this entry. */
+ enum object_type in_pack_type; /* could be delta */
unsigned long delta_size; /* delta data size (uncompressed) */
struct object_entry *delta; /* delta base object */
struct packed_git *in_pack; /* already in pack */
- enum object_type in_pack_type; /* could be delta */
unsigned int in_pack_offset;
};
@@ -36,6 +37,7 @@ struct object_entry {
static unsigned char object_list_sha1[20];
static int non_empty = 0;
+static int no_reuse_delta = 0;
static int local = 0;
static int incremental = 0;
static struct object_entry **sorted_by_sha, **sorted_by_type;
@@ -75,7 +77,9 @@ static int pack_revindex_hashsz = 0;
* stats
*/
static int written = 0;
+static int written_delta = 0;
static int reused = 0;
+static int reused_delta = 0;
static int pack_revindex_ix(struct packed_git *p)
{
@@ -227,10 +231,23 @@ static unsigned long write_object(struct
unsigned char header[10];
unsigned hdrlen, datalen;
enum object_type obj_type;
+ int to_reuse = 0;
obj_type = entry->type;
- if (!entry->in_pack ||
- (obj_type != entry->in_pack_type)) {
+ if (! entry->in_pack)
+ to_reuse = 0; /* can't reuse what we don't have */
+ else if (obj_type == OBJ_DELTA)
+ to_reuse = 1; /* check_object() decided it for us */
+ else if (obj_type != entry->in_pack_type)
+ to_reuse = 0; /* pack has delta which is unusable */
+ else if (entry->delta)
+ to_reuse = 0; /* we want to pack afresh */
+ else
+ to_reuse = 1; /* we have it in-pack undeltified,
+ * and we do not need to deltify it.
+ */
+
+ if (! to_reuse) {
buf = read_sha1_file(entry->sha1, type, &size);
if (!buf)
die("unable to read %s", sha1_to_hex(entry->sha1));
@@ -266,8 +283,12 @@ static unsigned long write_object(struct
sha1write(f, buf, datalen);
unuse_packed_git(p);
hdrlen = 0; /* not really */
+ if (obj_type == OBJ_DELTA)
+ reused_delta++;
reused++;
}
+ if (obj_type == OBJ_DELTA)
+ written_delta++;
written++;
return hdrlen + datalen;
}
@@ -294,7 +315,6 @@ static void write_pack_file(void)
int i;
struct sha1file *f;
unsigned long offset;
- unsigned long mb;
struct pack_header hdr;
if (!base_name)
@@ -357,10 +377,9 @@ static int add_object_entry(unsigned cha
unsigned int idx = nr_objects;
struct object_entry *entry;
struct packed_git *p;
- unsigned int found_offset;
- struct packed_git *found_pack;
+ unsigned int found_offset = 0;
+ struct packed_git *found_pack = NULL;
- found_pack = NULL;
for (p = packed_git; p; p = p->next) {
struct pack_entry e;
if (find_pack_entry_one(sha1, &e, p)) {
@@ -420,32 +439,39 @@ static void check_object(struct object_e
char type[20];
if (entry->in_pack) {
+ unsigned char base[20];
+ unsigned long size;
+ struct object_entry *base_entry;
+
+ /* We want in_pack_type even if we do not reuse delta.
+ * There is no point not reusing non-delta representations.
+ */
+ check_reuse_pack_delta(entry->in_pack,
+ entry->in_pack_offset,
+ base, &size,
+ &entry->in_pack_type);
+
/* Check if it is delta, and the base is also an object
* we are going to pack. If so we will reuse the existing
* delta.
*/
- unsigned char base[20];
- unsigned long size;
- struct object_entry *base_entry;
- if (!check_reuse_pack_delta(entry->in_pack,
- entry->in_pack_offset,
- base, &size,
- &entry->in_pack_type) &&
+ if (!no_reuse_delta &&
+ entry->in_pack_type == OBJ_DELTA &&
(base_entry = locate_object_entry(base))) {
- /* We do not know depth at this point, but it
- * does not matter. Getting delta_chain_length
- * with packed_object_info_detail() is not so
- * expensive, so we could do that later if we
- * wanted to. Calling sha1_object_info to get
- * the true size (and later an uncompressed
- * representation) of deeply deltified object
- * is quite expensive.
+
+ /* Depth value does not matter - find_deltas()
+ * will never consider reused delta as the
+ * base object to deltify other objects
+ * against, in order to avoid circular deltas.
*/
- entry->depth = 1;
- /* uncompressed size */
+
+ /* uncompressed size of the delta data */
entry->size = entry->delta_size = size;
entry->delta = base_entry;
entry->type = OBJ_DELTA;
+
+ base_entry->edge = 1;
+
return;
}
/* Otherwise we would do the usual */
@@ -568,6 +594,13 @@ static int try_delta(struct unpacked *cu
if (cur_entry->type != old_entry->type)
return -1;
+ /* If the current object is at edge, take the depth the objects
+ * that depend on the current object into account -- otherwise
+ * they would become too deep.
+ */
+ if (cur_entry->edge)
+ max_depth /= 4;
+
size = cur_entry->size;
if (size < 50)
return -1;
@@ -627,7 +660,7 @@ static void find_deltas(struct object_en
if (entry->delta)
/* This happens if we decided to reuse existing
- * delta from a pack.
+ * delta from a pack. "!no_reuse_delta &&" is implied.
*/
continue;
@@ -636,6 +669,7 @@ static void find_deltas(struct object_en
n->data = read_sha1_file(entry->sha1, type, &size);
if (size != entry->size)
die("object %s inconsistent object length (%lu vs %lu)", sha1_to_hex(entry->sha1), size, entry->size);
+
j = window;
while (--j > 0) {
unsigned int other_idx = idx + j;
@@ -664,7 +698,7 @@ static void prepare_pack(int window, int
fprintf(stderr, "Packing %d objects", nr_objects);
get_object_details();
if (progress)
- fprintf(stderr, ".");
+ fputc('.', stderr);
sorted_by_type = create_sorted_list(type_size_sort);
if (window && depth)
@@ -694,8 +728,9 @@ static int reuse_cached_pack(unsigned ch
}
}
- fprintf(stderr, "Reusing %d objects pack %s\n", nr_objects,
- sha1_to_hex(sha1));
+ if (progress)
+ fprintf(stderr, "Reusing %d objects pack %s\n", nr_objects,
+ sha1_to_hex(sha1));
if (pack_to_stdout) {
if (copy_fd(ifd, 1))
@@ -775,6 +810,10 @@ int main(int argc, char **argv)
progress = 0;
continue;
}
+ if (!strcmp("--no-reuse-delta", arg)) {
+ no_reuse_delta = 1;
+ continue;
+ }
if (!strcmp("--stdout", arg)) {
pack_to_stdout = 1;
continue;
@@ -850,7 +889,8 @@ int main(int argc, char **argv)
puts(sha1_to_hex(object_list_sha1));
}
}
- fprintf(stderr, "Total %d, written %d, reused %d\n",
- nr_objects, written, reused);
+ if (progress)
+ fprintf(stderr, "Total %d, written %d (delta %d), reused %d (delta %d)\n",
+ nr_objects, written, written_delta, reused, reused_delta);
return 0;
}
--
1.2.1.g91016
^ permalink raw reply related
* Re: [PATCH] Handle branch names with slashes
From: Karl Hasselström @ 2006-02-17 9:53 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <tnxbqx6z592.fsf@arm.com>
On 2006-02-17 09:47:21 +0000, Catalin Marinas wrote:
> Karl Hasselström <kha@treskal.com> wrote:
>
> > Let StGIT grok branch names with slashes in them. It used to fall
> > flat on its face when confronted with them.
>
> Thanks for the patches you sent. I'll have a look at them tomorrow.
>
> As a side note, for future patches, could you please use my
> catalin.marinas@gmail.com address instead of the company one? I
> maintain StGIT outside the working hours and it's much easier to
> grab them from my personal address.
Ah, I hadn't realized you were using more than one address. Will do.
--
Karl Hasselström, kha@treskal.com
www.treskal.com/kalle
^ permalink raw reply
* Re: [PATCH] Handle branch names with slashes
From: Catalin Marinas @ 2006-02-17 9:47 UTC (permalink / raw)
To: Karl Hasselström; +Cc: git
In-Reply-To: <20060217014117.12525.21330.stgit@backpacker.hemma.treskal.com>
Karl Hasselström <kha@treskal.com> wrote:
> Let StGIT grok branch names with slashes in them. It used to fall flat
> on its face when confronted with them.
Thanks for the patches you sent. I'll have a look at them tomorrow.
As a side note, for future patches, could you please use my
catalin.marinas@gmail.com address instead of the company one? I
maintain StGIT outside the working hours and it's much easier to grab
them from my personal address.
Thanks,
--
Catalin
^ permalink raw reply
* Re: [PATCH] Make git-reset delete empty directories
From: Junio C Hamano @ 2006-02-17 8:15 UTC (permalink / raw)
To: Shawn Pearce; +Cc: git
In-Reply-To: <20060217072616.GA15358@spearce.org>
Shawn Pearce <spearce@spearce.org> writes:
> When git-reset --hard is used and a subdirectory becomes
> empty (as it contains no tracked files in the target tree)
> the empty subdirectory should be removed.
I thought I said it would be a few-liner, but it appears I did
not send that message.
This untested one is far simpler, if less efficient, isn't it?
---
diff --git a/git-reset.sh b/git-reset.sh
index fe53fc8..195d043 100755
--- a/git-reset.sh
+++ b/git-reset.sh
@@ -88,6 +88,9 @@ case "$reset_type" in
# it is ok if this fails -- it may already
# have been culled by checkout-index.
unlink $_;
+ while (s|/[^/]*$|| && $_ ne "") {
+ rmdir($_) or last;
+ }
}
}
' $tmp-exists
^ permalink raw reply related
* [PATCH] Make git-reset delete empty directories
From: Shawn Pearce @ 2006-02-17 7:26 UTC (permalink / raw)
To: git
When git-reset --hard is used and a subdirectory becomes
empty (as it contains no tracked files in the target tree)
the empty subdirectory should be removed. This matches
the behavior of git-checkout-index and git-read-tree -m
which would not have created the subdirectory or would
have deleted it when updating the working directory.
Subdirectories which are not empty will be left behind.
This may happen if the subdirectory still contains object
files from the user's build process (for example).
---
git-reset.sh | 17 ++++++++++++---
t/t7101-reset.sh | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 77 insertions(+), 3 deletions(-)
create mode 100755 t/t7101-reset.sh
base 3397f9df53092871de2c33c143f1f4413654c40d
last 9e4158a26134a05e6011613976e26e7bfa813aca
diff --git a/git-reset.sh b/git-reset.sh
index fe53fc8065dc82c0054ba9891b28a00b0752bf87..8eac4640bc8dfb655f8429036b68644df027dea4 100755
--- a/git-reset.sh
+++ b/git-reset.sh
@@ -74,22 +74,33 @@ case "$reset_type" in
git-ls-files --cached -z |
perl -e '
use strict;
- my (%keep, $fh);
+ my (%keep_file, %keep_dir, %rm_dir, $fh);
$/ = "\0";
while (<STDIN>) {
chomp;
- $keep{$_} = 1;
+ $keep_file{$_} = 1;
+ while (s,/?[^/]+$,, && $_) {
+ last if $keep_dir{$_}++;
+ }
}
open $fh, "<", $ARGV[0]
or die "cannot open $ARGV[0]";
while (<$fh>) {
chomp;
- if (! exists $keep{$_}) {
+ if (! exists $keep_file{$_}) {
# it is ok if this fails -- it may already
# have been culled by checkout-index.
unlink $_;
+ while (s,/?[^/]+$,, && $_ && !$keep_dir{$_}) {
+ last if $rm_dir{$_}++;
+ }
}
}
+ foreach (sort {length($b) <=> length($a)} keys %rm_dir) {
+ # it is ok if this fails -- it may have user files
+ # we do not track and thus should not delete.
+ rmdir $_;
+ }
' $tmp-exists
;;
--soft )
diff --git a/t/t7101-reset.sh b/t/t7101-reset.sh
new file mode 100755
index 0000000000000000000000000000000000000000..a9191407f21c748f4c00bf909f670fc2b5124ec3
--- /dev/null
+++ b/t/t7101-reset.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Shawn Pearce
+#
+
+test_description='git-reset should cull empty subdirs'
+. ./test-lib.sh
+
+test_expect_success \
+ 'creating initial files' \
+ 'mkdir path0 &&
+ cp ../../COPYING path0/COPYING &&
+ git-add path0/COPYING &&
+ git-commit -m add -a'
+
+test_expect_success \
+ 'creating second files' \
+ 'mkdir path1 &&
+ mkdir path1/path2 &&
+ cp ../../COPYING path1/path2/COPYING &&
+ cp ../../COPYING path1/COPYING &&
+ cp ../../COPYING COPYING &&
+ cp ../../COPYING path0/COPYING-TOO &&
+ git-add path1/path2/COPYING &&
+ git-add path1/COPYING &&
+ git-add COPYING &&
+ git-add path0/COPYING-TOO &&
+ git-commit -m change -a'
+
+test_expect_success \
+ 'resetting tree HEAD^' \
+ 'git-reset --hard HEAD^'
+
+test_expect_success \
+ 'checking initial files exist after rewind' \
+ 'test -d path0 &&
+ test -f path0/COPYING'
+
+test_expect_failure \
+ 'checking lack of path1/path2/COPYING' \
+ 'test -f path1/path2/COPYING'
+
+test_expect_failure \
+ 'checking lack of path1/COPYING' \
+ 'test -f path1/COPYING'
+
+test_expect_failure \
+ 'checking lack of COPYING' \
+ 'test -f COPYING'
+
+test_expect_failure \
+ 'checking checking lack of path1/COPYING-TOO' \
+ 'test -f path0/COPYING-TOO'
+
+test_expect_failure \
+ 'checking lack of path1/path2' \
+ 'test -d path1/path2'
+
+test_expect_failure \
+ 'checking lack of path1' \
+ 'test -d path1'
+
+test_done
^ permalink raw reply related
* [PATCH 1/2] Update .git/refs/heads/base after patch deletion
From: Karl Hasselström @ 2006-02-17 4:31 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20060217042728.14175.39928.stgit@backpacker.hemma.treskal.com>
Save the current HEAD into refs/heads/base if the stack is empty after
a patch has been deleted. This was not done before, which caused
refs/heads/base to not be updated after 'stg commit'. To guard against
existing repositories with no applied patches and HEAD !=
refs/heads/base, also do the update every time someone asks for the
name of refs/heads/base.
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
stgit/stack.py | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/stgit/stack.py b/stgit/stack.py
index 68a2936..bc39d14 100644
--- a/stgit/stack.py
+++ b/stgit/stack.py
@@ -366,6 +366,7 @@ class Series:
return names
def get_base_file(self):
+ self.__begin_stack_check()
return self.__base_file
def get_protected(self):
@@ -686,6 +687,7 @@ class Series:
f = file(self.__unapplied_file, 'w+')
f.writelines([line + '\n' for line in unapplied])
f.close()
+ self.__begin_stack_check()
def forward_patches(self, names):
"""Try to fast-forward an array of patches.
^ permalink raw reply related
* [PATCH 2/2] Add 'stg uncommit' command
From: Karl Hasselström @ 2006-02-17 4:31 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20060217042728.14175.39928.stgit@backpacker.hemma.treskal.com>
Add an uncommit command, which is exactly the opposite of 'stg
commit'.
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
stgit/commands/commit.py | 5 ++-
stgit/commands/uncommit.py | 80 ++++++++++++++++++++++++++++++++++++++++++++
stgit/main.py | 2 +
stgit/stack.py | 12 +++++--
4 files changed, 94 insertions(+), 5 deletions(-)
diff --git a/stgit/commands/commit.py b/stgit/commands/commit.py
index a3b7277..ed9a0b3 100644
--- a/stgit/commands/commit.py
+++ b/stgit/commands/commit.py
@@ -28,8 +28,9 @@ usage = """%prog [options]
Merge the applied patches into the base of the current stack and
remove them from the series while advancing the base.
-Use this command only if you want to permanently store the applied
-patches and no longer manage them with StGIT."""
+Use this command if you want to permanently store the applied patches
+and no longer manage them with StGIT. If you should change your mind
+later, use 'stg uncommit'."""
options = []
diff --git a/stgit/commands/uncommit.py b/stgit/commands/uncommit.py
new file mode 100644
index 0000000..4ac0dfb
--- /dev/null
+++ b/stgit/commands/uncommit.py
@@ -0,0 +1,80 @@
+__copyright__ = """
+Copyright (C) 2006, Catalin Marinas <catalin.marinas@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+
+import sys, os
+from optparse import OptionParser, make_option
+
+from stgit.commands.common import *
+from stgit.utils import *
+from stgit import stack, git
+
+help = 'turn regular git commits into StGIT patches'
+usage = """%prog [options] <patchname1> [<patchname2> ... ]
+
+Takes one or more git commits at the base of the current stack, and
+turns them into StGIT patches. These new patches are alreay applied,
+at the bottom of the stack. This is the exact opposite of 'stg
+commit'.
+
+You can either give one patch name for each commit you wish to
+uncommit, or use the --number option and exactly one patch name; StGIT
+will then create numbered patches with the given patch name as prefix.
+
+Only commits with exactly one parent can be uncommitted; in other
+words, you can't uncommmit a merge."""
+
+options = [make_option('-n', '--number', type = 'int',
+ help = 'uncommit the specified number of commits')]
+
+def func(parser, options, args):
+ if len(args) == 0:
+ parser.error('you must specify at least one patch name')
+ if options.number:
+ if len(args) != 1:
+ parser.error('when using --number, specify exactly one patch name')
+ patchnames = ['%s%d' % (args[0], i)
+ for i in xrange(options.number - 1, -1, -1)]
+ else:
+ patchnames = args
+
+ if crt_series.get_protected():
+ raise CmdException, 'This branch is protected. Uncommit is not permitted'
+
+ print 'Uncommitting %d patches...' % len(patchnames),
+ sys.stdout.flush()
+
+ for patchname in patchnames:
+ base_file = crt_series.get_base_file()
+ commit_id = read_string(base_file)
+ commit = git.Commit(commit_id)
+ try:
+ parent, = commit.get_parents()
+ except ValueError:
+ raise CmdException, ('Commit %s does not have exactly one parent'
+ % commit_id)
+ author_name, author_email, author_date = name_email_date(
+ commit.get_author())
+ crt_series.new_patch(patchname,
+ can_edit = False, before_existing = True,
+ top = commit_id, bottom = parent,
+ message = commit.get_log(),
+ author_name = author_name,
+ author_email = author_email,
+ author_date = author_date)
+ write_string(base_file, parent)
+
+ print 'done'
diff --git a/stgit/main.py b/stgit/main.py
index 6d86ee4..4a48668 100644
--- a/stgit/main.py
+++ b/stgit/main.py
@@ -57,6 +57,7 @@ import stgit.commands.series
import stgit.commands.status
import stgit.commands.top
import stgit.commands.unapplied
+import stgit.commands.uncommit
#
@@ -92,6 +93,7 @@ commands = {
'status': stgit.commands.status,
'top': stgit.commands.top,
'unapplied':stgit.commands.unapplied,
+ 'uncommit': stgit.commands.uncommit,
}
def print_help():
diff --git a/stgit/stack.py b/stgit/stack.py
index bc39d14..05389bb 100644
--- a/stgit/stack.py
+++ b/stgit/stack.py
@@ -621,7 +621,8 @@ class Series:
unapplied = False, show_patch = False,
top = None, bottom = None,
author_name = None, author_email = None, author_date = None,
- committer_name = None, committer_email = None):
+ committer_name = None, committer_email = None,
+ before_existing = False):
"""Creates a new patch
"""
if self.__patch_applied(name) or self.__patch_unapplied(name):
@@ -664,8 +665,13 @@ class Series:
f.writelines([line + '\n' for line in patches])
f.close()
else:
- append_string(self.__applied_file, patch.get_name())
- self.__set_current(name)
+ if before_existing:
+ insert_string(self.__applied_file, patch.get_name())
+ if not self.get_current():
+ self.__set_current(name)
+ else:
+ append_string(self.__applied_file, patch.get_name())
+ self.__set_current(name)
def delete_patch(self, name):
"""Deletes a patch
^ permalink raw reply related
* [PATCH 0/2] stg uncommit
From: Karl Hasselström @ 2006-02-17 4:27 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <b0943d9e0602150925v6f01accfw@mail.gmail.com>
Here is that uncommit command I was going on and on and on about.
There's also some stricter checking that refs/heads/bases is reset to
HEAD whenever we reach zero applied patches, since otherwise you can't
uncommit patches on an empty stomach.
Note the extremely cool feature that you can uncommit regardless of
how dirty your working tree is!
--
Karl Hasselström
^ permalink raw reply
* Re: [PATCH] pack-objects: reuse data from existing pack.
From: Junio C Hamano @ 2006-02-17 4:30 UTC (permalink / raw)
To: git
In-Reply-To: <7vbqx8m62q.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano <junkio@cox.net> writes:
> When generating a new pack, notice if we have already the wanted
> object in existing packs. If the object has a delitified
> representation, and its base object is also what we are going to
> pack, then reuse the existing deltified representation
> unconditionally, bypassing all the expensive find_deltas() and
> try_deltas() routines.
This one has one nasty data corruption bug, which fortunately I
think I have figured out how to fix. Please do not use it for
your production repository in the meantime.
^ permalink raw reply
* Re: [PATCH] Handle branch names with slashes
From: Karl Hasselström @ 2006-02-17 4:21 UTC (permalink / raw)
To: Sam Vilain; +Cc: Catalin Marinas, git
In-Reply-To: <43F53C76.6080902@vilain.net>
On 2006-02-17 16:01:10 +1300, Sam Vilain wrote:
> Karl Hasselström wrote:
>
> > Let StGIT grok branch names with slashes in them. It used to fall
> > flat on its face when confronted with them.
> >
> > I think I've covered all, or at least most cases, but there are
> > probably some bugs left if you look hard enough.
>
> Does `stgit -r patchname/bottom` still work?
Yes (if you mean 'stg diff -r ... ' :-). It's just branches that can
have slashes in their names, not patches.
--
Karl Hasselström, kha@treskal.com
www.treskal.com/kalle
^ permalink raw reply
* Re: [PATCH] Handle branch names with slashes
From: Sam Vilain @ 2006-02-17 3:01 UTC (permalink / raw)
To: Karl Hasselström; +Cc: Catalin Marinas, git
In-Reply-To: <20060217014117.12525.21330.stgit@backpacker.hemma.treskal.com>
Karl Hasselström wrote:
> Let StGIT grok branch names with slashes in them. It used to fall flat
> on its face when confronted with them.
>
> I think I've covered all, or at least most cases, but there are
> probably some bugs left if you look hard enough.
Does `stgit -r patchname/bottom` still work?
Sam.
^ permalink raw reply
* "stg mail" doesn't set Content-Type and such
From: Karl Hasselström @ 2006-02-17 2:42 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
As can be seen in the headers of the stgit patches I've send to this
list recently, "stgit mail" doesn't seem to handle charsets and stuff
when sending mail; from what I can tell, it just sends the raw bytes
without setting Content-Transfer-Encoding, Content-Type, or anything
similar.
--
Karl Hasselström, kha@treskal.com
www.treskal.com/kalle
^ permalink raw reply
* [PATCH] Change the signature start string to "-- \n"
From: Karl Hasselström @ 2006-02-17 2:25 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
Change the signature start string from "--\n" to "-- \n" in the cover
mail template, as recommended in Mutt's manual:
It is *strongly* recommended that you not unset this variable
[from its default value of "-- \n"] unless your "signature"
contains just your name. The reason for this is because many
software packages use "-- \n" to detect your signature. For
example, Mutt has the ability to highlight the signature in a
different color in the builtin pager.
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
templates/covermail.tmpl | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/templates/covermail.tmpl b/templates/covermail.tmpl
index 9789c9c..44cd19e 100644
--- a/templates/covermail.tmpl
+++ b/templates/covermail.tmpl
@@ -4,5 +4,5 @@ Date: %(date)s
%(endofheaders)s
The following series implements...
---
+--
Signature
^ permalink raw reply related
* [PATCH] git-svn: ensure fetch always works chronologically.
From: Eric Wong @ 2006-02-17 2:13 UTC (permalink / raw)
To: git list, Junio C Hamano
In-Reply-To: <20060216194751.GB4446@Muzzle>
We run svn log against a URL without a working copy for the first fetch,
so we end up a log that's sorted from highest to lowest. That's bad, we
always want lowest to highest. Just default to --revision 0:HEAD now if
-r isn't specified for the first fetch.
Also sort the revisions after we get them just in case somebody
accidentally reverses the argument to --revision for whatever reason.
Thanks again to Emmanuel Guerin for helping me find this.
Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
contrib/git-svn/git-svn | 7 ++++---
1 files changed, 4 insertions(+), 3 deletions(-)
2ec4f205eaa3914a64205ea224292b9e27e06cdf
diff --git a/contrib/git-svn/git-svn b/contrib/git-svn/git-svn
index ddd9579..2caf057 100755
--- a/contrib/git-svn/git-svn
+++ b/contrib/git-svn/git-svn
@@ -168,14 +168,15 @@ sub fetch {
my (@parents) = @_;
$SVN_URL ||= file_to_s("$GIT_DIR/$GIT_SVN/info/url");
my @log_args = -d $SVN_WC ? ($SVN_WC) : ($SVN_URL);
- if (-d $SVN_WC && !$_revision) {
- $_revision = 'BASE:HEAD';
+ unless ($_revision) {
+ $_revision = -d $SVN_WC ? 'BASE:HEAD' : '0:HEAD';
}
- push @log_args, "-r$_revision" if $_revision;
+ push @log_args, "-r$_revision";
push @log_args, '--stop-on-copy' unless $_no_stop_copy;
eval { require XML::Simple or croak $! };
my $svn_log = $@ ? svn_log_raw(@log_args) : svn_log_xml(@log_args);
+ @$svn_log = sort { $a->{revision} <=> $b->{revision} } @$svn_log;
my $base = shift @$svn_log or croak "No base revision!\n";
my $last_commit = undef;
--
1.2.0.gdee6
^ permalink raw reply related
* [PATCH] Use --refid option even when sending a cover mail
From: Karl Hasselström @ 2006-02-17 2:07 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
StGIT used to just ignore the --refid option when sending a cover
mail. With this patch, it will send the cover mail as a reply to the
mail identified by the refid, and the patch emails as replies to the
cover mail as usual.
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
stgit/commands/mail.py | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/stgit/commands/mail.py b/stgit/commands/mail.py
index b3b7b49..975f8c9 100644
--- a/stgit/commands/mail.py
+++ b/stgit/commands/mail.py
@@ -199,6 +199,9 @@ def __build_cover(tmpl, total_nr, msg_id
headers_end = __build_address_headers(options)
headers_end += 'Message-Id: %s\n' % msg_id
+ if options.refid:
+ headers_end += "In-Reply-To: %s\n" % options.refid
+ headers_end += "References: %s\n" % options.refid
if options.version:
version_str = ' %s' % options.version
^ permalink raw reply related
* [PATCH] Handle branch names with slashes
From: Karl Hasselström @ 2006-02-17 1:41 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20060214173509.GA8666@diana.vm.bytemark.co.uk>
Let StGIT grok branch names with slashes in them. It used to fall flat
on its face when confronted with them.
I think I've covered all, or at least most cases, but there are
probably some bugs left if you look hard enough.
Signed-off-by: Karl Hasselström <kha@treskal.com>
---
stgit/commands/branch.py | 6 +++-
stgit/git.py | 12 +++++--
stgit/stack.py | 42 ++++++++++---------------
stgit/utils.py | 77 ++++++++++++++++++++++++++++++++++++++++------
4 files changed, 97 insertions(+), 40 deletions(-)
diff --git a/stgit/commands/branch.py b/stgit/commands/branch.py
index ef44349..d3e8a3c 100644
--- a/stgit/commands/branch.py
+++ b/stgit/commands/branch.py
@@ -173,7 +173,11 @@ def func(parser, options, args):
if len(args) != 0:
parser.error('incorrect number of arguments')
- branches = os.listdir(os.path.join(git.get_base_dir(), 'refs', 'heads'))
+ branches = []
+ basepath = os.path.join(git.get_base_dir(), 'refs', 'heads')
+ for path, dirs, files in os.walk(basepath):
+ branches += [remove_leading_dir(basepath, os.path.join(path, f))
+ for f in files]
branches.sort()
max_len = max([len(i) for i in branches])
diff --git a/stgit/git.py b/stgit/git.py
index 582e803..724b6fd 100644
--- a/stgit/git.py
+++ b/stgit/git.py
@@ -232,7 +232,8 @@ def get_head():
def get_head_file():
"""Returns the name of the file pointed to by the HEAD link
"""
- return os.path.basename(_output_one_line('git-symbolic-ref HEAD'))
+ return remove_leading_dir(os.path.join('refs', 'heads'),
+ _output_one_line('git-symbolic-ref HEAD'))
def set_head_file(ref):
"""Resets HEAD to point to a new ref
@@ -325,7 +326,9 @@ def delete_branch(name):
branch_head = os.path.join('refs', 'heads', name)
if not branch_exists(branch_head):
raise GitException, 'Branch "%s" does not exist' % name
- os.remove(os.path.join(get_base_dir(), branch_head))
+ base = get_base_dir()
+ rm_file_and_dirs(os.path.join(base, branch_head),
+ os.path.join(base, 'refs', 'heads'))
def rename_branch(from_name, to_name):
"""Rename a git branch
@@ -339,8 +342,9 @@ def rename_branch(from_name, to_name):
if get_head_file() == from_name:
set_head_file(to_head)
- os.rename(os.path.join(get_base_dir(), from_head), \
- os.path.join(get_base_dir(), to_head))
+ base = os.path.join(get_base_dir())
+ rename_dirs(os.path.join(base, from_head), os.path.join(base, to_head),
+ os.path.join(base, 'refs', 'heads'))
def add(names):
"""Add the files or recursively add the directory contents
diff --git a/stgit/stack.py b/stgit/stack.py
index 556c40e..68a2936 100644
--- a/stgit/stack.py
+++ b/stgit/stack.py
@@ -406,7 +406,7 @@ class Series:
"""
if len(self.get_applied()) == 0:
head = git.get_head()
- write_string(self.__base_file, head)
+ write_string(self.__base_file, head, mkdir = True)
def __end_stack_check(self):
"""Remove .git/refs/heads/base if the stack is empty.
@@ -499,9 +499,11 @@ class Series:
git.rename_branch(self.__name, to_name)
if os.path.isdir(self.__series_dir):
- os.rename(self.__series_dir, to_stack.__series_dir)
+ rename_dirs(self.__series_dir, to_stack.__series_dir,
+ os.path.join(self.__base_dir, 'patches'))
if os.path.exists(self.__base_file):
- os.rename(self.__base_file, to_stack.__base_file)
+ rename_dirs(self.__base_file, to_stack.__base_file,
+ os.path.join(self.__base_dir, 'refs', 'bases'))
self.__init__(to_name)
@@ -543,29 +545,19 @@ class Series:
for p in patches:
Patch(p, self.__patch_dir, self.__refs_dir).delete()
- if os.path.exists(self.__applied_file):
- os.remove(self.__applied_file)
- if os.path.exists(self.__unapplied_file):
- os.remove(self.__unapplied_file)
- if os.path.exists(self.__current_file):
- os.remove(self.__current_file)
- if os.path.exists(self.__descr_file):
- os.remove(self.__descr_file)
- if not os.listdir(self.__patch_dir):
- os.rmdir(self.__patch_dir)
- else:
- print 'Patch directory %s is not empty.' % self.__name
- if not os.listdir(self.__series_dir):
- os.rmdir(self.__series_dir)
- else:
- print 'Series directory %s is not empty.' % self.__name
- if not os.listdir(self.__refs_dir):
- os.rmdir(self.__refs_dir)
- else:
- print 'Refs directory %s is not empty.' % self.__refs_dir
+ for f in [self.__applied_file, self.__unapplied_file,
+ self.__current_file, self.__descr_file]:
+ rm_if_exists(f)
+
+ for (d, n) in [(self.__patch_dir, 'Patch'),
+ (self.__series_dir, 'Series'),
+ (self.__refs_dir, 'Refs')]:
+ if os.path.isdir(d) and os.listdir(d):
+ print '%s directory %s is not empty.' % (n, self.__name)
+ rmdir_while_empty(d, self.__base_dir)
- if os.path.exists(self.__base_file):
- os.remove(self.__base_file)
+ rm_if_exists(self.__base_file)
+ rmdir_while_empty(os.path.dirname(self.__base_file), self.__base_dir)
def refresh_patch(self, files = None, message = None, edit = False,
show_patch = False,
diff --git a/stgit/utils.py b/stgit/utils.py
index 5749b3b..33c62be 100644
--- a/stgit/utils.py
+++ b/stgit/utils.py
@@ -18,6 +18,18 @@ along with this program; if not, write t
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
+import os.path
+
+def mkdir_file(filename, mode, mkdir):
+ """Opens filename with the given mode, creating the directory it's
+ in if it doesn't already exist and mkdir is true
+ """
+ if mkdir:
+ d = os.path.dirname(filename)
+ if not os.path.isdir(d):
+ os.makedirs(d)
+ return file(filename, mode)
+
def read_string(filename, multiline = False):
"""Reads the first line from a file
"""
@@ -29,42 +41,87 @@ def read_string(filename, multiline = Fa
f.close()
return result
-def write_string(filename, line, multiline = False):
+def write_string(filename, line, multiline = False, mkdir = False):
"""Writes 'line' to file and truncates it
"""
- f = file(filename, 'w+')
+ f = mkdir_file(filename, 'w+', mkdir)
if multiline:
f.write(line)
else:
print >> f, line
f.close()
-def append_strings(filename, lines):
+def append_strings(filename, lines, mkdir = False):
"""Appends 'lines' sequence to file
"""
- f = file(filename, 'a+')
+ f = mkdir_file(filename, 'a+', mkdir)
for line in lines:
print >> f, line
f.close()
-def append_string(filename, line):
+def append_string(filename, line, mkdir = False):
"""Appends 'line' to file
"""
- f = file(filename, 'a+')
+ f = mkdir_file(filename, 'a+', mkdir)
print >> f, line
f.close()
-def insert_string(filename, line):
+def insert_string(filename, line, mkdir = False):
"""Inserts 'line' at the beginning of the file
"""
- f = file(filename, 'r+')
+ f = mkdir_file(filename, 'r+', mkdir)
lines = f.readlines()
f.seek(0); f.truncate()
print >> f, line
f.writelines(lines)
f.close()
-def create_empty_file(name):
+def create_empty_file(name, mkdir = False):
"""Creates an empty file
"""
- file(name, 'w+').close()
+ mkdir_file(name, 'w+', mkdir).close()
+
+def remove_leading_dir(leading, path):
+ """Remove leading directories from a pathname
+ """
+ if not path.startswith(leading):
+ raise Exception('"%s" does not begin with "%s"' % (path, leading))
+ path = path[len(leading):]
+ if len(path) > 0 and path[0] in [os.path.sep, os.path.altsep]:
+ path = path[1:]
+ return path
+
+def rmdir_while_empty(path, stop):
+ """Delete dirs until we reach a directory that isn't empty, or
+ until we reach the path stop
+ """
+ while path.startswith(stop) and len(path) > len(stop):
+ parent = os.path.dirname(path)
+ try:
+ os.rmdir(path)
+ except OSError:
+ return # directory not empty
+ path = parent
+
+def rm_file_and_dirs(path, stop):
+ """Delete the file, and keep deleting dirs until we reach a
+ directory that isn't empty, or until we reach the path stop
+ """
+ os.remove(path)
+ rmdir_while_empty(os.path.dirname(path), stop)
+
+def rm_if_exists(f):
+ """Delete file if it exists
+ """
+ if os.path.exists(f):
+ os.remove(f)
+
+def rename_dirs(from_path, to_path, stop):
+ """Rename file or directory, creating new directories at to_path
+ as necessary, and removing leftover empty directories at from_path
+ until we reach stop
+ """
+ if not os.path.isdir(os.path.dirname(to_path)):
+ os.makedirs(os.path.dirname(to_path))
+ os.rename(from_path, to_path)
+ rmdir_while_empty(os.path.dirname(from_path), stop)
^ permalink raw reply related
* Re: Fake linear history in a deterministic manner.
From: Junio C Hamano @ 2006-02-16 23:54 UTC (permalink / raw)
To: Martin Langhoff; +Cc: git
In-Reply-To: <46a038f90602121746v5adb448ej73cc2be6dd3745ce@mail.gmail.com>
Martin, (and Martyn),
I just cloned the gitcvs via git locally, exported it via
gitcvs, and ran "cvs log" and "cvs annotate README" there.
Good job. I really had a good laugh looking at the generated
output. It just looks like .... CVS! ;-)
I haven't read the code in detail (I tend to start nitpicking
the details without looking at a bigger picture, once I start
reading the code, so I try to only give superficial look until I
know I'll have tons of time to spend on it).
But it looks like a fun project.
^ permalink raw reply
* Re: git faq : draft and rfc
From: Thomas Riboulet @ 2006-02-16 23:52 UTC (permalink / raw)
To: git
In-Reply-To: <20060216151826.GS31278@pasky.or.cz>
On 2/16/06, Petr Baudis <pasky@suse.cz> wrote:
> Dear diary, on Thu, Feb 16, 2006 at 01:36:20AM CET, I got a letter
> where Thomas Riboulet <riboulet@gmail.com> said that...
> > . Git commit is dying telling me "fatal : empty ident <user@myhost>
> > not allowed", what's wrong ?
> > Make sure your Full Name is not empty in chsh or the 5th field of your
> > user line in /etc/passwd isn't empty. If you @myhost is empty make sure
> > your hostname is correctly set.
>
> Please also mention GIT_AUTHOR_NAME; chsh may be frequently unavailable.
ok
>
> > . What's the difference between fetch and pull ?
> > Fetch : download objects and a head from another repository.
> > Pull : pull and merge from another repository.
> > See man git-fetch and git-pull for more.
>
> This could do with a little more elaboration as well. Nice inspiration
> might be <Pine.LNX.4.64.0602140845080.3691@g5.osdl.org>.
ok, I'll as soon as I manage to get it :/
>
> > . Can I tell git to ignore files ?
> > Yes. Put the files path in the repository in the .git/info/exclude file.
>
> Or .gitignore in the tree itself. .git/info/exclude is only for your
> particular checkout while .gitignore is what matters for all and
> everyone's checkouts of the project.
>
ok, added
> > . What can I use to setup a public repository ?
> > A ssh server, an http server, or the git-daemon.
> > See the tutorial for more details.
>
> Well this is about how to make it available, not how to use it.
>
> The repository should be set up by cg-admin-setuprepo or git-init-db
> --shared and normally does not have a working tree attached. You can
> fetch from such a repository either over:
>
> * the GIT protocol (you need to run git-daemon)
> * SSH (you can set up a git-use-only account using git-shell)
> * rsync (has important disadvantages but it is currently the
> fastest way to do the initial checkout)
> * or the HTTP protocol (any reasonable webhosting will do, but
> you need to run git-update-server-info after each repository
> update; if you used cg-admin-setuprepo to set it up, this
> will be done automatically, otherwise you may enable it in
> the post-update hook - see .git/hooks/post-update).
>
> You can push to such a repository over:
>
> * SSH
> * HTTP DAV (you will need to specially configure your HTTP
> server for this)
>
> Obviously, you can also fetch/push from/to a repository locally if it
> is available in the local filesystem structure.
>
the initial aim of that question was simply to tell svn people (and
others) what can be used to setup a public repos.
isn't it a bit too much for a faq ? maybe add some things to the
present answer and put this question in the "general questions"
section (see below), and add more details in the "usage" section ?
> --
> Petr "Pasky" Baudis
> Stuff: http://pasky.or.cz/
> Of the 3 great composers Mozart tells us what it's like to be human,
> Beethoven tells us what it's like to be Beethoven and Bach tells us
> what it's like to be the universe. -- Douglas Adams
>
ok added (and pushed) the :
- taylor qa
- the git import bk qa
- GIT_AUTHOR_NAME
I'll separate the questions between the following sections :
- general questions (who, when, where, ...)
- usage : commands, errors ...
I'm planning on removing the text format faq and handle it as I handle
the html one : through the docbook. ok ?
--
Thom/ange
^ permalink raw reply
* Re: Fake linear history in a deterministic manner.
From: Martin Langhoff @ 2006-02-16 23:29 UTC (permalink / raw)
To: Eric Wong; +Cc: Git Mailing List, Paul Mackerras
In-Reply-To: <20060216222956.GA5818@Muzzle>
On 2/17/06, Eric Wong <normalperson@yhbt.net> wrote:
> Martin Langhoff <martin.langhoff@gmail.com> wrote:
> > To emulate `cvs log somepath` I need to munge history to look linear.
> > I am working on the theory that I will tell the cvs client about *one*
> > linear history, and show merges from parallel histories as a merge
> > commit, "flattened" so to speak, and with a commit message where I'll
> > list the hash and first line of each commit that it involves.
>
> I'd be interested in exporting from git to SVN with something like this.
We're hoping to release the code soon, but the truth is that it's
really trivial. It was more agonizing over the fact that there's no
"good" (aka "stable") algorithm for this.
> > I thought briefly about delaying the decision until I see the merge,
> > and pick the leftmost, or rightmost, if there is some bias in
> > git-merge or cg-merge on putting whatever origin has on a particular
> > side. It'd mean running backwards through history and that the very
> > last merge can flip the decision entirely. Hmmm... any strategy I can
> > come up with means that each new merge throws the dice again entirely.
> >
> > Ideas?
>
> I'd actually like to do this interactively in gitk. Just browse history
> visually and pick the path you want to choose each time there's a merge,
> and then having it output the revisions to stdout or saved to a file
> after you're done picking. Ideally you'd be able to use saved output
> interactively, as well.
It's cool to be able to pick, but if it's for a git-svnserver
implementation, you can't change your (fake) history you tell after
clients have seen. So a merge that gets pushed to the repo later may
contain more interesting paths, but you're bound to the lies you've
told.
cheers,
martin
^ permalink raw reply
* Re: Fake linear history in a deterministic manner.
From: Eric Wong @ 2006-02-16 22:29 UTC (permalink / raw)
To: Martin Langhoff; +Cc: Git Mailing List, Paul Mackerras
In-Reply-To: <46a038f90602121746v5adb448ej73cc2be6dd3745ce@mail.gmail.com>
Martin Langhoff <martin.langhoff@gmail.com> wrote:
> To emulate `cvs log somepath` I need to munge history to look linear.
> I am working on the theory that I will tell the cvs client about *one*
> linear history, and show merges from parallel histories as a merge
> commit, "flattened" so to speak, and with a commit message where I'll
> list the hash and first line of each commit that it involves.
I'd be interested in exporting from git to SVN with something like this.
> I thought briefly about delaying the decision until I see the merge,
> and pick the leftmost, or rightmost, if there is some bias in
> git-merge or cg-merge on putting whatever origin has on a particular
> side. It'd mean running backwards through history and that the very
> last merge can flip the decision entirely. Hmmm... any strategy I can
> come up with means that each new merge throws the dice again entirely.
>
> Ideas?
I'd actually like to do this interactively in gitk. Just browse history
visually and pick the path you want to choose each time there's a merge,
and then having it output the revisions to stdout or saved to a file
after you're done picking. Ideally you'd be able to use saved output
interactively, as well.
--
Eric Wong
^ permalink raw reply
* Re: [PATCH] git-svn: fix revision order when XML::Simple is not loaded
From: Eric Wong @ 2006-02-16 21:44 UTC (permalink / raw)
To: git list
In-Reply-To: <20060216194751.GB4446@Muzzle>
Just to add, XML::Simple is a recommended dependency. git-svn will work
fine without it (after this patch) as long as the repository doesn't
have any log messages that regurgitate or otherwise look like svn log
output (most svn repositories are sane in this regard :)
I may add support for the SVN:: perl libraries in the future, but I'll
always git-svn compatible with the command-line svn client and lazy load
any non-standard libraries.
--
Eric Wong
^ permalink raw reply
* Re: [ANNOUNCE] GIT 1.2.1
From: Greg KH @ 2006-02-16 21:41 UTC (permalink / raw)
To: Brown, Len; +Cc: Junio C Hamano, git, linux-kernel
In-Reply-To: <F7DC2337C7631D4386A2DF6E8FB22B300614210F@hdsmsx401.amr.corp.intel.com>
On Thu, Feb 16, 2006 at 01:47:28AM -0500, Brown, Len wrote:
> Happy to notice Documentation/git-send-email
> to standardize greg's scripts, but don't see it in the release.
>
> anybody using it?
I used it to send out my last 2 round of git patches (usb and i2c). I
like it a lot better than my original script, Ryan's done a great job of
cleaning up my horrible perl code.
thanks,
greg k-h
^ permalink raw reply
* Re: Handling large files with GIT
From: Fredrik Kuivinen @ 2006-02-16 20:32 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Junio C Hamano, Fredrik Kuivinen, Git Mailing List
In-Reply-To: <Pine.LNX.4.64.0602141953081.3691@g5.osdl.org>
On Tue, Feb 14, 2006 at 07:58:03PM -0800, Linus Torvalds wrote:
>
>
> On Tue, 14 Feb 2006, Linus Torvalds wrote:
> >
> > So in case people want to try, here's a third patch. Oh, and it's against
> > my _original_ path, not incremental to the middle one (ie both patches two
> > and three are against patch #1, it's not a nice series).
> >
> > Now I'm really done, and won't be sending out any more patches today.
>
> Still true. I've just been thinking about the last state.
>
> As far as I can tell, the output from git-merge-tree with that fix to only
> simplify subdirectories that match exactly in all of base/branch1/branch2
> is precisely the output that git-merge-recursive actually wants.
>
> Rather than doing a three-way merge with "git-read-tree", and then doing
> "git-ls-files --unmerged", I think this gives the same result much more
> efficiently.
>
> That said, I can't follow the python code, so maybe I'm missing something.
> Fredrik cc'd, in case he can put me right.
>
I don't think you miss anything. I _think_ (I haven't looked at this
too close yet) that it shouldn't be too much work to make
git-merge-recursive make use of the git-merge-tree thing.
- Fredrik
^ permalink raw reply
* [PATCH] git-svn: fix revision order when XML::Simple is not loaded
From: Eric Wong @ 2006-02-16 19:47 UTC (permalink / raw)
To: Emmanuel Guerin; +Cc: git list, Junio C Hamano
In-Reply-To: <20060216073826.GA12055@hand.yhbt.net>
Thanks to Emmanuel Guerin for finding the bug.
Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
contrib/git-svn/git-svn | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
98de7584b4991ab9c4025e36bfbfc10eacd17b8d
diff --git a/contrib/git-svn/git-svn b/contrib/git-svn/git-svn
index 62fc14f..ddd9579 100755
--- a/contrib/git-svn/git-svn
+++ b/contrib/git-svn/git-svn
@@ -523,7 +523,7 @@ sub svn_log_raw {
# if we have an empty log message, put something there:
if (@svn_log) {
- $svn_log[0]->{msg} ||= "\n";
+ $svn_log[$#svn_log]->{msg} ||= "\n";
}
next;
}
@@ -538,7 +538,7 @@ sub svn_log_raw {
date => "$tz $Y-$m-$d $H:$M:$S",
author => $author,
msg => '' );
- unshift @svn_log, \%log_msg;
+ push @svn_log, \%log_msg;
$state = 'msg_start';
next;
}
@@ -546,7 +546,7 @@ sub svn_log_raw {
if ($state eq 'msg_start' && /^$/) {
$state = 'msg';
} elsif ($state eq 'msg') {
- $svn_log[0]->{msg} .= $_."\n";
+ $svn_log[$#svn_log]->{msg} .= $_."\n";
}
}
close $log_fh or croak $?;
--
1.2.0.gdee6
^ permalink raw reply related
* Re: [ANNOUNCE] git-svn - bidirection operations between svn and git
From: Eric Wong @ 2006-02-16 19:25 UTC (permalink / raw)
To: Eduardo Pereira Habkost; +Cc: git list
In-Reply-To: <20060216134248.GC4271@duckman.conectiva>
Eduardo Pereira Habkost <ehabkost@mandriva.com> wrote:
> On Wed, Feb 15, 2006 at 11:38:26PM -0800, Eric Wong wrote:
> > Hello, I've written a simple tool for interoperating between git and
> > svn. I wrote this so I could use git to work on projects where other
> > developers use Subversion. I really hate using svn, but some projects I
> > work on require it, and svk isn't nearly as fast nor simple as git.
>
> Great, I was doing some testing with git-svnimport for this, but I missed
> a tool to automatically commit to svn what I have in my GIT tree.
>
> >
> > git-svn does not replace git-svnimport, git-svnimport handles branches
> > and tags automatically, but is too inflexible about repository layouts
> > to be useful for a good number of projects I follow, and of course
> > git-svnimport can't commit to Subversion repositories :)
>
> I am already using git-svnimport to keep a "mirror" of some subversion
> repositories, here (automatically udpated on crontab). Do you plan to
> allow "integration" with repositories that are just clones of
> git-svnimport'ed repositories?
It's possible, just not very obvious at the moment. git-svn was written
as quickly as possible without regard to svnimport compatibility since I
had some repos that didn't work with svnimport to begin with.
The 'ADDITIONAL FETCH ARGUMENTS' part of the manpage is worth reading
for you. Basically, you can define equalities
"(svn revision number)=(git commit)" as arguments to git-svn fetch to
add parents for all the revisions it imports.
If I were you, I'd only want git-svn to care about partial history,
since you already have the rest of it from git-svnimport. You can do
this:
svn_revno=<last svn revision number you imported from git-svnimport>
git_commit=<equivalent commit sha1 name of svn_revno above>
git-svn fetch --revision $svn_revno:HEAD $svn_revno=$git_commit
> I plan to keep using git-svnimport and the standard git tools to work
> using the "svn mirror on git" as the main repository, but I plan to use
> "git-svn commit" to commit to the SVN repositories. I want this "commit
> tool" to not affect the current repository in any way, just like git-push:
> only send the commits to the remote repository and don't change anything
> in the local repository.
> However, it seems that "git-svn commit" does some tasks assuming we
> are on a "git-svn aware" repository (e.g. the "resyncing" just after
> the commit). Would you accept patches to allow using "git-svn commit"
> to commit changes from any GIT repository (i.e. not "svn-git aware"
> repositories) to any SVN repository, just like "git-push" would work
> for a GIT repository?
>
> However, I am not sure if the easier way would be changing git-svn to
> do this for me or writing a different script just for this task.
You should be 95% there just by exporting the svn_checkout_tree()
function to the command-line. Perhaps automating reading of the
$svn_rev variable can be in order.
--
Eric Wong
^ 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