Git development
 help / color / mirror / Atom feed
* Re: [PATCH] t6024: fix timing problem
From: Johannes Schindelin @ 2006-12-12 23:59 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vvekgog0r.fsf@assigned-by-dhcp.cox.net>

hI,

On Tue, 12 Dec 2006, Junio C Hamano wrote:

> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > This script tests a complicated merge, where _all_ files conflict. In
> > these circumstances, the ordering of the commits -- which is affected
> > not by the timestamps in the commit message -- becomes a deciding factor
> > of the merge result.
> 
> "not by the timestamps", or "by the timestamps"?  I am confused...

I deleted the "only", but not the "not" in front of it. Should have read 
my mail before sending... Sorry.

> Do you mean the commit timestamps affect which merge base commit becomes 
> ours and theirs during the computation of the virtual merge base commit?  
> That certainly explains the problem.

It affects in which order the merge bases are merged. I remember that I 
made a case for the oldest merge base to go first. If two of them (or all 
three!) have the same timestamp, I _think_ they are ordered by SHA1...

Now, the problem here is that two of the merge bases have a common merge 
base, but the third has a completely different root. So, depending on 
which merge base goes first, the add/add conflict can remove the file from 
the index early, in which case the next merge does not find a stage 1.

> > 	How about this: if there is an add/add conflict, we treat it as
> > 	if there _was_ an empty file, and we let the shiny new xdl_merge()
> > 	find the _true_ conflicts, _instead of_ removing the file from
> > 	the index, adding both files with different "~blabla" markers
> > 	appended to their file names to the working directory.
> 
> I was not thinking about this t6024 test failure problem but was
> wondering about doing exactly that in merge-recursive to match
> the "two file merge" magic we have in git-merge-one-file.sh ---
> I guess great minds do think alike ;-).

*beams* Gee, thanks!

Ciao,
Dscho

^ permalink raw reply

* t9100-git-svn-basic.sh fails
From: Sebastian Harl @ 2006-12-12 23:23 UTC (permalink / raw)
  To: git

[-- Attachment #1: Type: text/plain, Size: 488 bytes --]

Hi,

When compiling git 1.4.4.2 on my Debian Sarge box t9100-git-svn-basic.sh fails
with the following output:

  * FAIL 6: detect node change from directory to file #1
         git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch2

I'm using subversion 1.3.2.

Versions up to 1.4.3.2 built fine.

Any clues what this might be caused by?

Thanks in advance.

Cheers,
Sebastian

-- 
Sebastian "tokkee" Harl
GnuPG-ID: 0x8501C7FC
http://tokkee.org/


[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: Using git as a general backup mechanism
From: Junio C Hamano @ 2006-12-12 23:43 UTC (permalink / raw)
  To: Steven Grimm; +Cc: git
In-Reply-To: <457F31E6.8090701@midwinter.com>

Steven Grimm <koreth@midwinter.com> writes:

> What would be great for this would be to store each day's backup as a
> git revision; with a periodic repack, this would be much more
> space-efficient than the rsync hard links.
>
> The problem is that while that would give me a very efficient backup
> scheme, the repository would still grow over time. In rsync land, I
> solve the disk space issue by keeping two weeks' worth of daily
> snapshots, then six months' worth of weekly snapshots, then two years'
> worth of monthly snapshots; files that change daily have a constant
> number of revisions stored in my backups, and older files drop off the
> backup disk as they age.

Why not use N independent branches?  I'd illustrate only with
two levels below, but you could:

 (0) make a full tree snapshot.  Store the commit in 'daily'
     branch as its tip.

 (1) A new day comes.  Create an empty branch 'daily' if you
     do not already have one.  Make a full tree snapshot, and
     create a parentless commit for the day if the 'daily'
     branch did not exist, or make it a child of the 'daily'
     commit from the previous day if the branch existed.

 (2) End of week comes.  Create an empty branch 'weekly' if you
     do not already have one.  Make a full tree snapshot, and
     create a parentless commit for the week if the 'weekly'
     branch did not exist, or make it a child of the 'weekly'
     commit from the last week.  Discard 'lastweek' branch if
     you have one, and rename 'daily' branch to 'lastweek'.

At the end of month, you can rename 'weekly' to 'lastmonth'; if
you discard previous 'lastmonth' at this point, you essentially
made files older than two months drop off the backup disk.  You
can add more hierarchy with longer period to extend the scheme
ad infinitum.

^ permalink raw reply

* Re: [PATCH] t6024: fix timing problem
From: Junio C Hamano @ 2006-12-12 23:23 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0612122347590.2807@wbgn013.biozentrum.uni-wuerzburg.de>

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> This script tests a complicated merge, where _all_ files conflict. In
> these circumstances, the ordering of the commits -- which is affected
> not by the timestamps in the commit message -- becomes a deciding factor
> of the merge result.

"not by the timestamps", or "by the timestamps"?  I am
confused...

Do you mean the commit timestamps affect which merge base commit
becomes ours and theirs during the computation of the virtual
merge base commit?  That certainly explains the problem.

> 	How about this: if there is an add/add conflict, we treat it as
> 	if there _was_ an empty file, and we let the shiny new xdl_merge()
> 	find the _true_ conflicts, _instead of_ removing the file from
> 	the index, adding both files with different "~blabla" markers
> 	appended to their file names to the working directory.

I was not thinking about this t6024 test failure problem but was
wondering about doing exactly that in merge-recursive to match
the "two file merge" magic we have in git-merge-one-file.sh ---
I guess great minds do think alike ;-).



^ permalink raw reply

* Re: Using git as a general backup mechanism (was Re: Using GIT to store /etc)
From: Martin Langhoff @ 2006-12-12 23:23 UTC (permalink / raw)
  To: Steven Grimm; +Cc: git
In-Reply-To: <46a038f90612121515l77c77376xd98e148498e889c4@mail.gmail.com>

On 12/13/06, Martin Langhoff <martin.langhoff@gmail.com> wrote:
> I've been thinking myself of writing a pdumpfs lookalike that uses git
> internally. Sounds you you've got one already ;-)

Actually - what I was considering was mixing the "daily commit" with
GITFS ;-) http://www.sfgoth.com/~mitch/linux/gitfs/

are your scripts published anywhere?

cheers,



^ permalink raw reply

* Re: Using git as a general backup mechanism (was Re: Using GIT to store /etc)
From: Martin Langhoff @ 2006-12-12 23:15 UTC (permalink / raw)
  To: Steven Grimm; +Cc: git
In-Reply-To: <457F31E6.8090701@midwinter.com>

Steven,

I've been thinking myself of writing a pdumpfs lookalike that uses git
internally. Sounds you you've got one already ;-)

In terms of getting rid of old history, have you considered moving a
graft point "forward" in time, and running git-repack -a -d? With your
history being (mostly?) linear this could be a workable scheme, but I
don't have much practice with using grafts.

cheers,



^ permalink raw reply

* Re: Using git as a general backup mechanism (was Re: Using GIT to store /etc)
From: Steven Grimm @ 2006-12-12 23:06 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0612122355400.2807@wbgn013.biozentrum.uni-wuerzburg.de>

Johannes Schindelin wrote:
> $ git pull --depth 1
>
> Though it needs a server _and_ a client supporting shallow clones, which 
> support is brewed in "next" right now.
>   

Will that actually discard old revisions that are already stored locally?

-Steve

^ permalink raw reply

* [PATCH] Get rid of the dependency on RCS' merge program
From: Johannes Schindelin @ 2006-12-12 23:01 UTC (permalink / raw)
  To: git, junkio


Now that we have git-merge-file, an RCS merge lookalike, we no longer
need it. So long, merge, and thanks for all the fish!

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---

	I only ran the test suite, which passed fine...

 .gitignore                        |    1 +
 Documentation/git-merge-index.txt |    4 +-
 INSTALL                           |    9 ----
 git-cvsserver.perl                |    2 +-
 git-rerere.perl                   |    2 +-
 git.spec.in                       |    2 +-
 merge-file.c                      |   75 ++++++------------------------------
 t/t0000-basic.sh                  |   14 +------
 8 files changed, 20 insertions(+), 89 deletions(-)

diff --git a/.gitignore b/.gitignore
index 6b8caa0..2e8f17e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -61,6 +61,7 @@ git-mailsplit
 git-merge
 git-merge-base
 git-merge-index
+git-merge-file
 git-merge-tree
 git-merge-octopus
 git-merge-one-file
diff --git a/Documentation/git-merge-index.txt b/Documentation/git-merge-index.txt
index 6cd0601..0cf505e 100644
--- a/Documentation/git-merge-index.txt
+++ b/Documentation/git-merge-index.txt
@@ -40,8 +40,8 @@ If "git-merge-index" is called with multiple <file>s (or -a) then it
 processes them in turn only stopping if merge returns a non-zero exit
 code.
 
-Typically this is run with the a script calling the merge command from
-the RCS package.
+Typically this is run with the a script calling git's imitation of
+the merge command from the RCS package.
 
 A sample script called "git-merge-one-file" is included in the
 distribution.
diff --git a/INSTALL b/INSTALL
index 8f69039..b5dd9f0 100644
--- a/INSTALL
+++ b/INSTALL
@@ -82,15 +82,6 @@ Issues of note:
 	  do that even if it wasn't for git.  There's no point in living
 	  in the dark ages any more. 
 
-	- "merge", the standard UNIX three-way merge program.  It usually
-	  comes with the "rcs" package on most Linux distributions, so if
-	  you have a developer install you probably have it already, but a
-	  "graphical user desktop" install might have left it out.
-
-	  You'll only need the merge program if you do development using
-	  git, and if you only use git to track other peoples work you'll
-	  never notice the lack of it. 
-
         - "wish", the Tcl/Tk windowing shell is used in gitk to show the
           history graphically
 
diff --git a/git-cvsserver.perl b/git-cvsserver.perl
index bf4e228..740f2fa 100755
--- a/git-cvsserver.perl
+++ b/git-cvsserver.perl
@@ -948,7 +948,7 @@ sub req_update
 
             $log->debug("Temporary directory for merge is $dir");
 
-            my $return = system("merge", $file_local, $file_old, $file_new);
+            my $return = system("git merge-file", $file_local, $file_old, $file_new);
             $return >>= 8;
 
             if ( $return == 0 )
diff --git a/git-rerere.perl b/git-rerere.perl
index 61eef57..fdd6854 100755
--- a/git-rerere.perl
+++ b/git-rerere.perl
@@ -154,7 +154,7 @@ sub find_conflict {
 sub merge {
 	my ($name, $path) = @_;
 	record_preimage($path, "$rr_dir/$name/thisimage");
-	unless (system('merge', map { "$rr_dir/$name/${_}image" }
+	unless (system('git merge-file', map { "$rr_dir/$name/${_}image" }
 		       qw(this pre post))) {
 		my $in;
 		open $in, "<$rr_dir/$name/thisimage" or
diff --git a/git.spec.in b/git.spec.in
index f2374b7..fb95e37 100644
--- a/git.spec.in
+++ b/git.spec.in
@@ -24,7 +24,7 @@ This is a dummy package which brings in all subpackages.
 %package core
 Summary:	Core git tools
 Group:		Development/Tools
-Requires:	zlib >= 1.2, rsync, rcs, curl, less, openssh-clients, expat
+Requires:	zlib >= 1.2, rsync, curl, less, openssh-clients, expat
 %description core
 This is a stupid (but extremely fast) directory content manager.  It
 doesn't do a whole lot, but what it _does_ do is track directory
diff --git a/merge-file.c b/merge-file.c
index fc9b148..69dc1eb 100644
--- a/merge-file.c
+++ b/merge-file.c
@@ -3,52 +3,6 @@
 #include "xdiff-interface.h"
 #include "blob.h"
 
-static void rm_temp_file(const char *filename)
-{
-	unlink(filename);
-	free((void *)filename);
-}
-
-static const char *write_temp_file(mmfile_t *f)
-{
-	int fd;
-	const char *tmp = getenv("TMPDIR");
-	char *filename;
-
-	if (!tmp)
-		tmp = "/tmp";
-	filename = mkpath("%s/%s", tmp, "git-tmp-XXXXXX");
-	fd = mkstemp(filename);
-	if (fd < 0)
-		return NULL;
-	filename = xstrdup(filename);
-	if (f->size != xwrite(fd, f->ptr, f->size)) {
-		rm_temp_file(filename);
-		return NULL;
-	}
-	close(fd);
-	return filename;
-}
-
-static void *read_temp_file(const char *filename, unsigned long *size)
-{
-	struct stat st;
-	char *buf = NULL;
-	int fd = open(filename, O_RDONLY);
-	if (fd < 0)
-		return NULL;
-	if (!fstat(fd, &st)) {
-		*size = st.st_size;
-		buf = xmalloc(st.st_size);
-		if (st.st_size != xread(fd, buf, st.st_size)) {
-			free(buf);
-			buf = NULL;
-		}
-	}
-	close(fd);
-	return buf;
-}
-
 static int fill_mmfile_blob(mmfile_t *f, struct blob *obj)
 {
 	void *buf;
@@ -72,22 +26,19 @@ static void free_mmfile(mmfile_t *f)
 
 static void *three_way_filemerge(mmfile_t *base, mmfile_t *our, mmfile_t *their, unsigned long *size)
 {
-	void *res;
-	const char *t1, *t2, *t3;
-
-	t1 = write_temp_file(base);
-	t2 = write_temp_file(our);
-	t3 = write_temp_file(their);
-	res = NULL;
-	if (t1 && t2 && t3) {
-		int code = run_command("merge", t2, t1, t3, NULL);
-		if (!code || code == -1)
-			res = read_temp_file(t2, size);
-	}
-	rm_temp_file(t1);
-	rm_temp_file(t2);
-	rm_temp_file(t3);
-	return res;
+	mmbuffer_t res;
+	xpparam_t xpp;
+	int merge_status;
+
+	memset(&xpp, 0, sizeof(xpp));
+	merge_status = xdl_merge(base, our, ".our", their, ".their",
+		&xpp, XDL_MERGE_ZEALOUS, &res);
+
+	if (merge_status < 0)
+		return NULL;
+
+	*size = res.size;
+	return res.ptr;
 }
 
 static int common_outf(void *priv_, mmbuffer_t *mb, int nbuf)
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 81f3bed..3260d1d 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -19,11 +19,7 @@ modification *should* take notice and update the test vectors here.
 '
 
 ################################################################
-# It appears that people are getting bitten by not installing
-# 'merge' (usually part of RCS package in binary distributions).
-# Check this and error out before running any tests.  Also catch
-# the bogosity of trying to run tests without building while we
-# are at it.
+# It appears that people try to run tests without building...
 
 ../git >/dev/null
 if test $? != 1
@@ -32,14 +28,6 @@ then
 	exit 1
 fi
 
-merge >/dev/null 2>/dev/null
-if test $? = 127
-then
-	echo >&2 'You do not seem to have "merge" installed.
-Please check INSTALL document.'
-	exit 1
-fi
-
 . ./test-lib.sh
 
 ################################################################
-- 
1.4.4.2.g473fa0-dirty

^ permalink raw reply related

* Re: Using git as a general backup mechanism (was Re: Using GIT to store /etc)
From: Johannes Schindelin @ 2006-12-12 22:57 UTC (permalink / raw)
  To: Steven Grimm; +Cc: git
In-Reply-To: <457F31E6.8090701@midwinter.com>

Hi,

On Tue, 12 Dec 2006, Steven Grimm wrote:

> If there were a shallowize command, you could do something like "git 
> pull; git shallowize --depth 1" to track the latest revision without 
> keeping the history locally.

Almost!

$ git pull --depth 1

Though it needs a server _and_ a client supporting shallow clones, which 
support is brewed in "next" right now.

Ciao,
Dscho

^ permalink raw reply

* Re: GIT - releases workflow
From: Johannes Schindelin @ 2006-12-12 22:54 UTC (permalink / raw)
  To: Sean Kelley; +Cc: git
In-Reply-To: <89b129c60612121444t18ba94ecv57eea4c72be1663a@mail.gmail.com>

Hi,

On Tue, 12 Dec 2006, Sean Kelley wrote:

> I was wondering if anyone could share ideas on how best to use GIT to 
> handle releases for those working with a remote GIT repository?  Do you 
> create a branch and push it to the remote?  Thus you have a new branch 
> referencing the particular release?

Why not just tag the release, and push the tag?

Hth,
Dscho

^ permalink raw reply

* [PATCH] t6024: fix timing problem
From: Johannes Schindelin @ 2006-12-12 22:49 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vmz5w5tuw.fsf@assigned-by-dhcp.cox.net>


This script tests a complicated merge, where _all_ files conflict. In
these circumstances, the ordering of the commits -- which is affected
not by the timestamps in the commit message -- becomes a deciding factor
of the merge result.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---

	On Sat, 9 Dec 2006, Junio C Hamano wrote:

	> There seem to be cases where stage #1 contains blob 'B' or 'A'
	> or nothing depending on something totally random.  Ring a bell?

	This patch fixes it..

	Depending on the order, an add/add conflict _removes_ the file
	from the index, and as a consequence stage 1 is missing in the
	final merge (which still fails, because the return value of the
	previous merge is remembered).

	How about this: if there is an add/add conflict, we treat it as
	if there _was_ an empty file, and we let the shiny new xdl_merge()
	find the _true_ conflicts, _instead of_ removing the file from
	the index, adding both files with different "~blabla" markers
	appended to their file names to the working directory.

	Hmm?

 t/t6024-recursive-merge.sh |   20 +++++++++++---------
 1 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/t/t6024-recursive-merge.sh b/t/t6024-recursive-merge.sh
index 5f821fb..9416c27 100644
--- a/t/t6024-recursive-merge.sh
+++ b/t/t6024-recursive-merge.sh
@@ -11,54 +11,56 @@ test_description='Test merge without common ancestors'
 #       X   \
 # 2 - C - E - G
 
+export GIT_COMMITTER_DATE="2006-12-12 23:28:00 +0100"
 echo 1 > a1
 git add a1
-git commit -m 1 a1
+GIT_AUTHOR_DATE="2006-12-12 23:00:00" git commit -m 1 a1
 
 git checkout -b A master
 echo A > a1
-git commit -m A a1
+GIT_AUTHOR_DATE="2006-12-12 23:00:01" git commit -m A a1
 
 git checkout -b B master
 echo B > a1
-git commit -m B a1
+GIT_AUTHOR_DATE="2006-12-12 23:00:02" git commit -m B a1
 
 git checkout -b D A
 git-rev-parse B > .git/MERGE_HEAD
 echo D > a1
 git update-index a1
-git commit -m D
+GIT_AUTHOR_DATE="2006-12-12 23:00:03" git commit -m D
 
 git symbolic-ref HEAD refs/heads/other
 echo 2 > a1
-git commit -m 2 a1
+GIT_AUTHOR_DATE="2006-12-12 23:00:04" git commit -m 2 a1
 
 git checkout -b C
 echo C > a1
-git commit -m C a1
+GIT_AUTHOR_DATE="2006-12-12 23:00:05" git commit -m C a1
 
 git checkout -b E C
 git-rev-parse B > .git/MERGE_HEAD
 echo E > a1
 git update-index a1
-git commit -m E
+GIT_AUTHOR_DATE="2006-12-12 23:00:06" git commit -m E
 
 git checkout -b G E
 git-rev-parse A > .git/MERGE_HEAD
 echo G > a1
 git update-index a1
-git commit -m G
+GIT_AUTHOR_DATE="2006-12-12 23:00:07" git commit -m G
 
 git checkout -b F D
 git-rev-parse C > .git/MERGE_HEAD
 echo F > a1
 git update-index a1
-git commit -m F
+GIT_AUTHOR_DATE="2006-12-12 23:00:08" git commit -m F
 
 test_expect_failure "combined merge conflicts" "git merge -m final G"
 
 git ls-files --stage > out
 cat > expect << EOF
+100644 f70f10e4db19068f79bc43844b49f3eece45c4e8 1	a1
 100644 cf84443e49e1b366fac938711ddf4be2d4d1d9e9 2	a1
 100644 fd7923529855d0b274795ae3349c5e0438333979 3	a1
 EOF
-- 
1.4.4.2.g473fa0-dirty

^ permalink raw reply related

* Using git as a general backup mechanism (was Re: Using GIT to store /etc)
From: Steven Grimm @ 2006-12-12 22:49 UTC (permalink / raw)
  To: git
In-Reply-To: <200612121553.37499.andyparkins@gmail.com>

This discussion reminds me of a use of git I've had in the back of my 
head to try out for a while. Right now I'm doing my local snapshot 
backups using the rsync-with-hard-links scheme 
(http://www.mikerubel.org/computers/rsync_snapshots/ if you're not 
familiar with it). This is nice in that the contents of files that don't 
change are only stored once on the backup disk. But it is less than 
optimal in that a file that changes even a little bit is stored from 
scratch.

What would be great for this would be to store each day's backup as a 
git revision; with a periodic repack, this would be much more 
space-efficient than the rsync hard links.

The problem is that while that would give me a very efficient backup 
scheme, the repository would still grow over time. In rsync land, I 
solve the disk space issue by keeping two weeks' worth of daily 
snapshots, then six months' worth of weekly snapshots, then two years' 
worth of monthly snapshots; files that change daily have a constant 
number of revisions stored in my backups, and older files drop off the 
backup disk as they age.

Given that there's no way (or is there?) to delete revisions from the 
*beginning* of a git revision history, right now it seems like the only 
approach that comes close is to give up on the "daily then weekly then 
monthly" thing -- probably fine given the space savings of delta 
compression -- and periodically make shallow clones of the backup 
repository that fetch all but the first N revisions; once a shallow 
clone is made, the original gets deleted and the clone is the new backup 
repo.

But it would sure be more efficient to be able to "shallow-ize" an 
existing repository. That would be useful for things other than backups, 
too, e.g. the recent request for some way to track just the current 
version of the kernel code rather than its revision history. If there 
were a shallowize command, you could do something like "git pull; git 
shallowize --depth 1" to track the latest revision without keeping the 
history locally.

Anyone think that sounds like an interesting thing to explore?

-Steve

^ permalink raw reply

* [PATCH 2/3] git-svn: allow dcommit to take an alternate head
From: Eric Wong @ 2006-12-12 22:47 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Eric Wong
In-Reply-To: <11659636223725-git-send-email-normalperson@yhbt.net>

Previously dcommit would unconditionally commit all patches
up-to and including the current HEAD.  Now if an optional
command-line argument is specified, it will only commit
up to the specified revision.

Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
 Documentation/git-svn.txt |    6 ++++--
 git-svn.perl              |   11 ++++++-----
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index a45067e..c589a98 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -57,11 +57,13 @@ See '<<fetch-args,Additional Fetch Arguments>>' if you are interested in
 manually joining branches on commit.
 
 'dcommit'::
-	Commit all diffs from the current HEAD directly to the SVN
+	Commit all diffs from a specified head directly to the SVN
 	repository, and then rebase or reset (depending on whether or
-	not there is a diff between SVN and HEAD).  It is recommended
+	not there is a diff between SVN and head).  It is recommended
 	that you run git-svn fetch and rebase (not pull) your commits
 	against the latest changes in the SVN repository.
+	An optional command-line argument may be specified as an
+	alternative to HEAD.
 	This is advantageous over 'commit' (below) because it produces
 	cleaner, more linear history.
 
diff --git a/git-svn.perl b/git-svn.perl
index 06e89ff..819584b 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -604,8 +604,9 @@ sub commit_lib {
 }
 
 sub dcommit {
+	my $head = shift || 'HEAD';
 	my $gs = "refs/remotes/$GIT_SVN";
-	chomp(my @refs = safe_qx(qw/git-rev-list --no-merges/, "$gs..HEAD"));
+	chomp(my @refs = safe_qx(qw/git-rev-list --no-merges/, "$gs..$head"));
 	my $last_rev;
 	foreach my $d (reverse @refs) {
 		if (quiet_run('git-rev-parse','--verify',"$d~1") != 0) {
@@ -632,16 +633,16 @@ sub dcommit {
 	}
 	return if $_dry_run;
 	fetch();
-	my @diff = safe_qx(qw/git-diff-tree HEAD/, $gs);
+	my @diff = safe_qx('git-diff-tree', $head, $gs);
 	my @finish;
 	if (@diff) {
 		@finish = qw/rebase/;
 		push @finish, qw/--merge/ if $_merge;
 		push @finish, "--strategy=$_strategy" if $_strategy;
-		print STDERR "W: HEAD and $gs differ, using @finish:\n", @diff;
+		print STDERR "W: $head and $gs differ, using @finish:\n", @diff;
 	} else {
-		print "No changes between current HEAD and $gs\n",
-		      "Hard resetting to the latest $gs\n";
+		print "No changes between current $head and $gs\n",
+		      "Resetting to the latest $gs\n";
 		@finish = qw/reset --mixed/;
 	}
 	sys('git', @finish, $gs);
-- 
1.4.4.2.g6f98

^ permalink raw reply related

* [PATCH 3/3] git-svn: correctly display fatal() error messages
From: Eric Wong @ 2006-12-12 22:47 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Eric Wong
In-Reply-To: <11659636223725-git-send-email-normalperson@yhbt.net>

If I wanted to print $@, I'd pass $@ to fatal().  This looks like
a stupid typo on my part.

Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
 git-svn.perl |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index 819584b..c746a3c 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -31,7 +31,7 @@ my %SKIP = ( 'svn:wc:ra_dav:version-url' => 1,
              'svn:entry:committed-date' => 1,
 );
 
-sub fatal (@) { print STDERR $@; exit 1 }
+sub fatal (@) { print STDERR @_; exit 1 }
 # If SVN:: library support is added, please make the dependencies
 # optional and preserve the capability to use the command-line client.
 # use eval { require SVN::... } to make it lazy load
-- 
1.4.4.2.g6f98

^ permalink raw reply related

* [PATCH 1/3] git-svn: enable logging of information not supported by git
From: Eric Wong @ 2006-12-12 22:47 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Eric Wong

The changes are now tracked in
  $GIT_DIR/svn/$GIT_SVN_ID/untracked.log

Information in the untracked.log include:
  * the addition and removal of empty directories
    (changes of these will also warn the user)
  * file and directory property changes, including (but not
    limited to) svk:merge and svn:externals
  * revision properties (revprops) are also tracked
  * users will be warned of 'absent' file and directories
    (if users are forbidden access)

Fields in entries are separated by spaces; "unsafe" characters
are URI-encoded so that each entry takes exactly one line.

There is currently no automated parser for dealing with the data
in untracked.log, but it should be possible to write one to
create empty directories on checkout and manage
externals/subprojects.

Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
 git-svn.perl |  202 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 184 insertions(+), 18 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index 1f8a3b0..06e89ff 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -21,6 +21,16 @@ $ENV{TZ} = 'UTC';
 $ENV{LC_ALL} = 'C';
 $| = 1; # unbuffer STDOUT
 
+# properties that we do not log:
+my %SKIP = ( 'svn:wc:ra_dav:version-url' => 1,
+             'svn:special' => 1,
+             'svn:executable' => 1,
+             'svn:entry:committed-rev' => 1,
+             'svn:entry:last-author' => 1,
+             'svn:entry:uuid' => 1,
+             'svn:entry:committed-date' => 1,
+);
+
 sub fatal (@) { print STDERR $@; exit 1 }
 # If SVN:: library support is added, please make the dependencies
 # optional and preserve the capability to use the command-line client.
@@ -2902,7 +2912,7 @@ sub libsvn_dup_ra {
 }
 
 sub libsvn_get_file {
-	my ($gui, $f, $rev, $chg) = @_;
+	my ($gui, $f, $rev, $chg, $untracked) = @_;
 	$f =~ s#^/##;
 	print "\t$chg\t$f\n" unless $_q;
 
@@ -2940,11 +2950,25 @@ sub libsvn_get_file {
 		waitpid $pid, 0;
 		$hash =~ /^$sha1$/o or die "not a sha1: $hash\n";
 	}
+	%{$untracked->{file_prop}->{$f}} = %$props;
 	print $gui $mode,' ',$hash,"\t",$f,"\0" or croak $!;
 }
 
+sub uri_encode {
+	my ($f) = @_;
+	$f =~ s#([^a-zA-Z0-9\*!\:_\./\-])#uc sprintf("%%%02x",ord($1))#eg;
+	$f
+}
+
+sub uri_decode {
+	my ($f) = @_;
+	$f =~ tr/+/ /;
+	$f =~ s/%([A-F0-9]{2})/chr hex($1)/ge;
+	$f
+}
+
 sub libsvn_log_entry {
-	my ($rev, $author, $date, $msg, $parents) = @_;
+	my ($rev, $author, $date, $msg, $parents, $untracked) = @_;
 	my ($Y,$m,$d,$H,$M,$S) = ($date =~ /^(\d{4})\-(\d\d)\-(\d\d)T
 					 (\d\d)\:(\d\d)\:(\d\d).\d+Z$/x)
 				or die "Unable to parse date: $date\n";
@@ -2952,8 +2976,65 @@ sub libsvn_log_entry {
 		die "Author: $author not defined in $_authors file\n";
 	}
 	$msg = '' if ($rev == 0 && !defined $msg);
-	return { revision => $rev, date => "+0000 $Y-$m-$d $H:$M:$S",
-		author => $author, msg => $msg."\n", parents => $parents || [] }
+
+	open my $un, '>>', "$GIT_SVN_DIR/unhandled.log" or croak $!;
+	my $h;
+	print $un "r$rev\n" or croak $!;
+	$h = $untracked->{empty};
+	foreach (sort keys %$h) {
+		my $act = $h->{$_} ? '+empty_dir' : '-empty_dir';
+		print $un "  $act: ", uri_encode($_), "\n" or croak $!;
+		warn "W: $act: $_\n";
+	}
+	foreach my $t (qw/dir_prop file_prop/) {
+		$h = $untracked->{$t} or next;
+		foreach my $path (sort keys %$h) {
+			my $ppath = $path eq '' ? '.' : $path;
+			foreach my $prop (sort keys %{$h->{$path}}) {
+				next if $SKIP{$prop};
+				my $v = $h->{$path}->{$prop};
+				if (defined $v) {
+					print $un "  +$t: ",
+						  uri_encode($ppath), ' ',
+						  uri_encode($prop), ' ',
+						  uri_encode($v), "\n"
+						  or croak $!;
+				} else {
+					print $un "  -$t: ",
+						  uri_encode($ppath), ' ',
+						  uri_encode($prop), "\n"
+						  or croak $!;
+				}
+			}
+		}
+	}
+	foreach my $t (qw/absent_file absent_directory/) {
+		$h = $untracked->{$t} or next;
+		foreach my $parent (sort keys %$h) {
+			foreach my $path (sort @{$h->{$parent}}) {
+				print $un "  $t: ",
+				      uri_encode("$parent/$path"), "\n"
+				      or croak $!;
+				warn "W: $t: $parent/$path ",
+				     "Insufficient permissions?\n";
+			}
+		}
+	}
+
+	# revprops (make this optional? it's an extra network trip...)
+	my $pool = SVN::Pool->new;
+	my $rp = $SVN->rev_proplist($rev, $pool);
+	foreach (sort keys %$rp) {
+		next if /^svn:(?:author|date|log)$/;
+		print $un "  rev_prop: ", uri_encode($_), ' ',
+		          uri_encode($rp->{$_}), "\n";
+	}
+	$pool->clear;
+	close $un or croak $!;
+
+	{ revision => $rev, date => "+0000 $Y-$m-$d $H:$M:$S",
+	  author => $author, msg => $msg."\n", parents => $parents || [],
+	  revprops => $rp }
 }
 
 sub process_rm {
@@ -2972,9 +3053,11 @@ sub process_rm {
 		}
 		print "\tD\t$f/\n" unless $q;
 		close $ls or croak $?;
+		return $SVN::Node::dir;
 	} else {
 		print $gui '0 ',0 x 40,"\t",$f,"\0" or croak $!;
 		print "\tD\t$f\n" unless $q;
+		return $SVN::Node::file;
 	}
 }
 
@@ -2995,13 +3078,14 @@ sub libsvn_fetch_delta {
 	unless ($ed->{git_commit_ok}) {
 		die "SVN connection failed somewhere...\n";
 	}
-	libsvn_log_entry($rev, $author, $date, $msg, [$last_commit]);
+	libsvn_log_entry($rev, $author, $date, $msg, [$last_commit], $ed);
 }
 
 sub libsvn_fetch_full {
 	my ($last_commit, $paths, $rev, $author, $date, $msg) = @_;
 	open my $gui, '| git-update-index -z --index-info' or croak $!;
 	my %amr;
+	my $ut = { empty => {}, dir_prop => {}, file_prop => {} };
 	my $p = $SVN->{svn_path};
 	foreach my $f (keys %$paths) {
 		my $m = $paths->{$f}->action();
@@ -3012,8 +3096,11 @@ sub libsvn_fetch_full {
 			$f =~ s#^/##;
 		}
 		if ($m =~ /^[DR]$/) {
-			process_rm($gui, $last_commit, $f, $_q);
-			next if $m eq 'D';
+			my $t = process_rm($gui, $last_commit, $f, $_q);
+			if ($m eq 'D') {
+				$ut->{empty}->{$f} = 0 if $t == $SVN::Node::dir;
+				next;
+			}
 			# 'R' can be file replacements, too, right?
 		}
 		my $pool = SVN::Pool->new;
@@ -3026,18 +3113,32 @@ sub libsvn_fetch_full {
 			}
 		} elsif ($t == $SVN::Node::dir && $m =~ /^[AR]$/) {
 			my @traversed = ();
-			libsvn_traverse($gui, '', $f, $rev, \@traversed);
-			foreach (@traversed) {
-				$amr{$_} = $m;
+			libsvn_traverse($gui, '', $f, $rev, \@traversed, $ut);
+			if (@traversed) {
+				foreach (@traversed) {
+					$amr{$_} = $m;
+				}
+			} else {
+				my ($dir, $file) = ($f =~ m#^(.*?)/?([^/]+)$#);
+				delete $ut->{empty}->{$dir};
+				$ut->{empty}->{$f} = 1;
 			}
 		}
 		$pool->clear;
 	}
 	foreach (keys %amr) {
-		libsvn_get_file($gui, $_, $rev, $amr{$_});
+		libsvn_get_file($gui, $_, $rev, $amr{$_}, $ut);
+		my ($d) = ($_ =~ m#^(.*?)/?(?:[^/]+)$#);
+		delete $ut->{empty}->{$d};
+	}
+	unless (exists $ut->{dir_prop}->{''}) {
+		my $pool = SVN::Pool->new;
+		my (undef, undef, $props) = $SVN->get_dir('', $rev, $pool);
+		%{$ut->{dir_prop}->{''}} = %$props;
+		$pool->clear;
 	}
 	close $gui or croak $?;
-	return libsvn_log_entry($rev, $author, $date, $msg, [$last_commit]);
+	libsvn_log_entry($rev, $author, $date, $msg, [$last_commit], $ut);
 }
 
 sub svn_grab_base_rev {
@@ -3098,25 +3199,38 @@ sub libsvn_parse_revision {
 }
 
 sub libsvn_traverse {
-	my ($gui, $pfx, $path, $rev, $files) = @_;
+	my ($gui, $pfx, $path, $rev, $files, $untracked) = @_;
 	my $cwd = length $pfx ? "$pfx/$path" : $path;
 	my $pool = SVN::Pool->new;
 	$cwd =~ s#^\Q$SVN->{svn_path}\E##;
+	my $nr = 0;
 	my ($dirent, $r, $props) = $SVN->get_dir($cwd, $rev, $pool);
+	%{$untracked->{dir_prop}->{$cwd}} = %$props;
 	foreach my $d (keys %$dirent) {
 		my $t = $dirent->{$d}->kind;
 		if ($t == $SVN::Node::dir) {
-			libsvn_traverse($gui, $cwd, $d, $rev, $files);
+			my $i = libsvn_traverse($gui, $cwd, $d, $rev,
+			                        $files, $untracked);
+			if ($i) {
+				$nr += $i;
+			} else {
+				$untracked->{empty}->{"$cwd/$d"} = 1;
+			}
 		} elsif ($t == $SVN::Node::file) {
+			$nr++;
 			my $file = "$cwd/$d";
 			if (defined $files) {
 				push @$files, $file;
 			} else {
-				libsvn_get_file($gui, $file, $rev, 'A');
+				libsvn_get_file($gui, $file, $rev, 'A',
+				                $untracked);
+				my ($dir) = ($file =~ m#^(.*?)/?(?:[^/]+)$#);
+				delete $untracked->{empty}->{$dir};
 			}
 		}
 	}
 	$pool->clear;
+	$nr;
 }
 
 sub libsvn_traverse_ignore {
@@ -3255,6 +3369,7 @@ sub libsvn_new_tree {
 		return $log_entry;
 	}
 	my ($paths, $rev, $author, $date, $msg) = @_;
+	my $ut;
 	if ($_xfer_delta) {
 		my $pool = SVN::Pool->new;
 		my $ed = SVN::Git::Fetcher->new({q => $_q});
@@ -3266,12 +3381,14 @@ sub libsvn_new_tree {
 		unless ($ed->{git_commit_ok}) {
 			die "SVN connection failed somewhere...\n";
 		}
+		$ut = $ed;
 	} else {
+		$ut = { empty => {}, dir_prop => {}, file_prop => {} };
 		open my $gui, '| git-update-index -z --index-info' or croak $!;
-		libsvn_traverse($gui, '', $SVN->{svn_path}, $rev);
+		libsvn_traverse($gui, '', $SVN->{svn_path}, $rev, undef, $ut);
 		close $gui or croak $?;
 	}
-	return libsvn_log_entry($rev, $author, $date, $msg);
+	libsvn_log_entry($rev, $author, $date, $msg, [], $ut);
 }
 
 sub find_graft_path_commit {
@@ -3456,13 +3573,28 @@ sub new {
 	$self->{gui} = $gui;
 	$self->{c} = $git_svn->{c} if exists $git_svn->{c};
 	$self->{q} = $git_svn->{q};
+	$self->{empty} = {};
+	$self->{dir_prop} = {};
+	$self->{file_prop} = {};
+	$self->{absent_dir} = {};
+	$self->{absent_file} = {};
 	require Digest::MD5;
 	$self;
 }
 
+sub open_root {
+	{ path => '' };
+}
+
+sub open_directory {
+	my ($self, $path, $pb, $rev) = @_;
+	{ path => $path };
+}
+
 sub delete_entry {
 	my ($self, $path, $rev, $pb) = @_;
-	process_rm($self->{gui}, $self->{c}, $path, $self->{q});
+	my $t = process_rm($self->{gui}, $self->{c}, $path, $self->{q});
+	$self->{empty}->{$path} = 0 if $t == $SVN::Node::dir;
 	undef;
 }
 
@@ -3479,10 +3611,41 @@ sub open_file {
 
 sub add_file {
 	my ($self, $path, $pb, $cp_path, $cp_rev) = @_;
+	my ($dir, $file) = ($path =~ m#^(.*?)/?([^/]+)$#);
+	delete $self->{empty}->{$dir};
 	{ path => $path, mode_a => 100644, mode_b => 100644,
 	  pool => SVN::Pool->new, action => 'A' };
 }
 
+sub add_directory {
+	my ($self, $path, $cp_path, $cp_rev) = @_;
+	my ($dir, $file) = ($path =~ m#^(.*?)/?([^/]+)$#);
+	delete $self->{empty}->{$dir};
+	$self->{empty}->{$path} = 1;
+	{ path => $path };
+}
+
+sub change_dir_prop {
+	my ($self, $db, $prop, $value) = @_;
+	$self->{dir_prop}->{$db->{path}} ||= {};
+	$self->{dir_prop}->{$db->{path}}->{$prop} = $value;
+	undef;
+}
+
+sub absent_directory {
+	my ($self, $path, $pb) = @_;
+	$self->{absent_dir}->{$pb->{path}} ||= [];
+	push @{$self->{absent_dir}->{$pb->{path}}}, $path;
+	undef;
+}
+
+sub absent_file {
+	my ($self, $path, $pb) = @_;
+	$self->{absent_file}->{$pb->{path}} ||= [];
+	push @{$self->{absent_file}->{$pb->{path}}}, $path;
+	undef;
+}
+
 sub change_file_prop {
 	my ($self, $fb, $prop, $value) = @_;
 	if ($prop eq 'svn:executable') {
@@ -3491,6 +3654,9 @@ sub change_file_prop {
 		}
 	} elsif ($prop eq 'svn:special') {
 		$fb->{mode_b} = defined $value ? 120000 : 100644;
+	} else {
+		$self->{file_prop}->{$fb->{path}} ||= {};
+		$self->{file_prop}->{$fb->{path}}->{$prop} = $value;
 	}
 	undef;
 }
-- 
1.4.4.2.g6f98

^ permalink raw reply related

* Re: [PATCH] Move Fink and Ports check to after config file
From: Junio C Hamano @ 2006-12-12 22:45 UTC (permalink / raw)
  To: Brian Gernhardt; +Cc: git, Shawn Pearce
In-Reply-To: <AF891711-02C9-414F-98CC-BC53DD24EDB3@silverinsanity.com>

Brian Gernhardt <benji@silverinsanity.com> writes:

> Putting NO_FINK or NO_DARWIN_PORTS in config.mak is ignored because the
> checks are done before the config is included.
>
> Signed-off-by: Brian Gernhardt <benji@silverinsanity.com>

First time I saw this today I said "I'd swear I've seen this".

http://thread.gmane.org/gmane.comp.version-control.git/26493/focus=26503

I guess after I asked for a confirmation from you I simply
forgot to apply it.  Thanks for a reminder.



^ permalink raw reply

* GIT - releases workflow
From: Sean Kelley @ 2006-12-12 22:44 UTC (permalink / raw)
  To: git

I was wondering if anyone could share ideas on how best to use GIT to
handle releases for those working with a remote GIT repository?  Do
you create a branch and push it to the remote?  Thus you have a new
branch referencing the particular release?

Sean

-- 

^ permalink raw reply

* Re: [RFC] E-mail aliases
From: Catalin Marinas @ 2006-12-12 22:36 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vvekhufib.fsf@assigned-by-dhcp.cox.net>

On 12/12/06, Junio C Hamano <junkio@cox.net> wrote:
> "Catalin Marinas" <catalin.marinas@gmail.com> writes:
>
> > sets the "To:" header to "linux-kernel@vger.kernel.org".
> >
> > The aliases are read from the [aliases] section in the gitconfig files
> > ("git repo-config aliases.lkml" in this case). I just want to make
> > sure than there isn't any other intended use for the [aliases] section
> > in the config files.
>
> [alias] is used to hold command-line alias, and it seems
> slightly confusing to have two sections that mean something
> quite different.

Didn't know about [alias]. It is indeed confusing to have [aliases] as well.

> Perhaps
>
> [mail "alias"]
>         lkml = linux-kernel@vger.kernel.org

The other option would be to teach stgit to parse alias files used by
mutt etc. as Eric mentioned in the other e-mail (and it doesn't look
difficult). The problem is that you would need to know how to generate
them manually if you use other e-mail clients or web-based services.

> if we are going to have other mail-related configurations that
> might turn out be handy.  send-email would want smtp-server in
> there, for example.

At a quick look, it seems that git-send-email already uses a
[sendemail] section. StGIT currently reads the smtpserver and
authentication information from the [stgit] section.

-- 

^ permalink raw reply

* Re: Tracking a repository for content instead of history
From: Johannes Schindelin @ 2006-12-12 22:25 UTC (permalink / raw)
  To: Nguyen Thai Ngoc Duy; +Cc: git
In-Reply-To: <fcaeb9bf0612121348q35549a4cof0adb85e0391b92c@mail.gmail.com>

Hi,

On Wed, 13 Dec 2006, Nguyen Thai Ngoc Duy wrote:

> On 12/13/06, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
> > Hm.. I'm no git:// expert. But is it possible doing as follow?
> > 1. git-archive <base>
> > 2. reconstruct commit, blobs and trees from the archive
> > 3. tell git server that you have one commit, you need another commit
> > (maybe heads only, i'm not sure here)
> > 4. get the pack from git server, create new commit and a diff
> 
> Ok. Stupid idea. The pack may base on objects that I don't have.

The only not-so-brilliant idea is to reconstruct the commit from the 
archive. This is not possible, as not only some author and 
committer metadata is not reconstructable, but worse: the parents' hash is 
not either. And since all these are hashed to get the commit hash, you 
lost.

However, it could work like this:

- reconstruct tree commit
- ask for a diff between a certain commit, with respect to your tree

It might even be easy to convince git-upload-pack to construct a thin pack 
containing deltas _only_ against objects which are reachable from your 
tree.

Note: this is feasible, but not necessarily sensible:

- it puts more strain on the server, which otherwise could probably reuse 
a lot of deltas, and
- it contradicts the idea of _distributed_ development (for example, you 
could not tell which HEAD commit is newer when you fetched from two 
repos).

Probably, you could add a third argument: merges are not necessarily 
_possible_ with that setup. Note that this argument applies to shallow 
clones, too!

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH] git-add --interactive (wip)
From: Johannes Schindelin @ 2006-12-12 22:15 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Josef Weidendorfer, git
In-Reply-To: <7vwt4wpytm.fsf@assigned-by-dhcp.cox.net>

Hi,

On Tue, 12 Dec 2006, Junio C Hamano wrote:

> I've updated my "git add --interactive" in 'pu' and it now knows how to 
> split a hunk into smaller pieces and recounting the diff offsets before 
> applying (Johannes pointed out that his partial commit script, entirely 
> written in bash using shell arrays, has a similar feature.  I guess I 
> should have stolen his code instead of lifting the logic from my own 
> abandoned porcelain).

Well, not completely true. I do not split hunks into subhunks.

Note that you _could_ split hunks at arbitrary lines; if it is a line 
common between the two files, it is easier though.

And you could not have ripped from my script: I make heavy use of bash 
arrays (in fact, I wrote this script partly to learn how to work with bash 
arrays). If I could think of a clean way to spawn processes piped into 
"less -FS" several times from a C program, I would already have rewritten 
it in C.

> So in short, I think per-hunk update-index is a cute hack and may be 
> useful in a narrow simple cases, but it would not be so useful in the 
> real life.

To the contrary! In spite of having written git-hunk-commit to please 
those poor souls coming from the darcs side, I already used it myself 
quite often! I think it is a killer feature.

Ciao,
Dscho

^ permalink raw reply

* Re: git-cvsimport feature request
From: Johannes Schindelin @ 2006-12-12 22:05 UTC (permalink / raw)
  To: Nguyen Thai Ngoc Duy; +Cc: git
In-Reply-To: <fcaeb9bf0612121334t454ec67av2c319382d1f61cce@mail.gmail.com>

Hi,

[readding list...]

On Wed, 13 Dec 2006, Nguyen Thai Ngoc Duy wrote:

> Hi,
> 
> On 12/12/06, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> > It could be done easily, but it is almost as easy to edit the command line
> > to substitute "git " with "git repo-config alias.cvsup '" (note the
> > single apostrophe at the end) and append and apostrophe at the end of the
> > line.
> 
> Thanks. I know that (and am doing that). Just think that it may be
> more convenient typing the command once.

Something like this?

-- snip --
[PATCH] cvsimport: save the last successful command line as alias "cvsup"

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

---

 git-cvsimport.perl |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index c5bf2d1..48fd55b 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -85,6 +85,12 @@ sub write_author_info($) {
 	close ($f);
 }
 
+my $alias = "cvsimport";
+foreach my $arg (@ARGV) {
+	$arg =~ s/[ \"]/\\&/g;
+	$alias .= ' ' . $arg;
+}
+
 getopts("hivmkuo:d:p:C:z:s:M:P:A:S:L:") or usage();
 usage if $opt_h;
 
@@ -946,6 +952,9 @@ if (defined $orig_git_index) {
 if ($orig_branch) {
 	print "DONE.\n" if $opt_v;
 	if ($opt_i) {
+		# uncomment this line, if the alias "cvsup" should be
+		# created/updated even with -i
+		#system("git-repo-config", "alias.cvsup", $alias);
 		exit 0;
 	}
 	my $tip_at_end = `git-rev-parse --verify HEAD`;
@@ -971,3 +980,7 @@ if ($orig_branch) {
 		die "checkout failed: $?\n" if $?;
 	}
 }
+
+# so far, so good. store it as alias cvsup
+system("git-repo-config", "alias.cvsup", $alias);

^ permalink raw reply related

* Re: [PATCH] git-add --interactive (wip)
From: Junio C Hamano @ 2006-12-12 21:51 UTC (permalink / raw)
  To: Josef Weidendorfer; +Cc: git, Johannes Schindelin
In-Reply-To: <200612111147.44964.Josef.Weidendorfer@gmx.de>

Josef Weidendorfer <Josef.Weidendorfer@gmx.de> writes:

> I just tried to work with this thing to separate my recent
> "branch.*.localmerge" changes to the simple version I posted
> afterwards.
>
> I noted that I need to manually change a few dependent hunks,
> so this "one hunk at a time" and not being able to edit changes
> in a hunk does not fit my workflow.

I've updated my "git add --interactive" in 'pu' and it now knows
how to split a hunk into smaller pieces and recounting the diff
offsets before applying (Johannes pointed out that his partial
commit script, entirely written in bash using shell arrays, has
a similar feature.  I guess I should have stolen his code
instead of lifting the logic from my own abandoned porcelain).

Hunk splitting allows you to start with this hunk:

        @@ -9,9 +9,10 @@
         #include "builtin.h"
         #include "dir.h"
         #include "cache-tree.h"
        +#include "exec_cmd.h"

         static const char builtin_add_usage[] =
        -"git-add [-n] [-v] <filepattern>...";
        +"git-add [-n] [-v] <filepattern>... | git-add --interactive";

         static void prune_directory(struct dir_struct *dir, const char **...
         {

and lets you split it into two, and you can pick each individually:

        @@ -9,5 +9,6 @@
         #include "builtin.h"
         #include "dir.h"
         #include "cache-tree.h"
        +#include "exec_cmd.h"

         static const char builtin_add_usage[] =
        @@ -12,6 +13,6 @@

         static const char builtin_add_usage[] =
        -"git-add [-n] [-v] <filepattern>...";
        +"git-add [-n] [-v] <filepattern>... | git-add --interactive";

         static void prune_directory(struct dir_struct *dir, const char **...
         {

The post-context of the first hunk and pre-context of the
second hunk are duplicated to give you better context when
reviewing each of them alone.  If you choose to apply both, they
are merged back again before applied.

Anyway, after I finished doing this, I started thinking...

One of the most beautifully done patch series in git.git history
is this series by Sergey Vlasov:

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

The resulting commits are from e8d2a6d4 to 4041483e (inclusive).

What's interesting about this series is that its patches touch
the same area of the code over and over again, refining a bit by
bit as the series progresses.

Sergey might have done it exactly the way the final patches
presented the evolution, but I somehow doubt it [*1*].  I often
have the state that corresponds to [PATCH n/n] in my working
tree after hacking around without making a single commit, and
often would start wanting to commit the state as a clean
multi-step series at that point.  I think this is the same for
everybody.

What I often end up doing is to make a snapshot of that
"proposed final" state, reset to the original, and work toward
the proposed final state:

	# snapshot
	$ git commit -a -m 'commit goal'
        $ git tag -f CG
        $ git reset --hard HEAD^

	# repeat for (i = 1; i <= n; i++)
        $ git diff HEAD CG >P.diff
        $ edit
        # use P.diff as a reference, and edit the working tree
        # files to produce [i/n] state.  I might remove pieces
        # that belong to [j/n] for j > i from  P.diff and run
	# "git apply --index", or hand edit the files directly
	# in the working tree.
	$ make test
        $ git commit -a -m "[PATCH i/n] title..."
        # end repeat

	# when finished the above cycle, this diff should only
	# show the improvements I made during the decomposition.
        $ git diff CG HEAD

For a very simple case where the patch munging in the "repeat"
part of the above workflow only deletes hunks (or sub-hunks),
the patch subcommand of "git add --interactive" with hunk
splitting would work nicely, but in general it would not be
enough.  It certainly is far from usable to produce something
like what Sergey gave us.

To make it easier, one possibility might be to add a subcommand
to "git add --interactive" that lets you edit what is currently
staged in the index by opening a temporary copy in your favorite
editor, and stage the result of your edit in the index.  But I
feel quite uneasy to introduce ways to update the index with
something _wildly_ different from what you ever had in your
working tree as a whole.

I think it is wrong to commit partially, purely from the index,
when you are building a series that has complex changes that
come during the series but go away at the end.  The user should
be able to verify all the steps in the middle in such a complex
series, but it is not easy if you have it only in the index.

You could do

	$ git checkout-index --prefix=testarea/ -f -q -u -a

and run your tests there, but that takes a discipline, and is
cumbersome to do.

So in short, I think per-hunk update-index is a cute hack and
may be useful in a narrow simple cases, but it would not be so
useful in the real life.


> Just as a sidenote: after deciding to not apply hunks, you
> lose them in this WIP, as you will find nothing in "unstaged" mode
> afterwards :-(

I do not understand this part.  You can 'revert' to match the
index to HEAD and run 'patch' to pick what you want again.


[Footnote]

*1* Maybe Sergey indeed did things the way the series was
presented, in which case that would only strengthen my respect
to his ability even more.  The quoted patch series made him one
of three people on the git list whose patches I trust 100%; in
fact, I trust their patches so much that I read them not to find
bugs but to admire and enjoy.

^ permalink raw reply

* Re: Tracking a repository for content instead of history
From: Nguyen Thai Ngoc Duy @ 2006-12-12 21:48 UTC (permalink / raw)
  To: git
In-Reply-To: <fcaeb9bf0612121346s3c82bcdbh522c17f4ae9f279b@mail.gmail.com>

On 12/13/06, Nguyen Thai Ngoc Duy <pclouds@gmail.com> wrote:
> Hm.. I'm no git:// expert. But is it possible doing as follow?
> 1. git-archive <base>
> 2. reconstruct commit, blobs and trees from the archive
> 3. tell git server that you have one commit, you need another commit
> (maybe heads only, i'm not sure here)
> 4. get the pack from git server, create new commit and a diff

Ok. Stupid idea. The pack may base on objects that I don't have.

-- 

^ permalink raw reply

* Re: Tracking a repository for content instead of history
From: Nguyen Thai Ngoc Duy @ 2006-12-12 21:46 UTC (permalink / raw)
  To: Andy Parkins; +Cc: git
In-Reply-To: <200612121538.41197.andyparkins@gmail.com>

On 12/12/06, Andy Parkins <andyparkins@gmail.com> wrote:
> I suppose so; but I was thinking more an automated way of getting the data
> that is supplied for the kernel anyway.  So:
>
> base-v1.0.0.tar.gz
> patch-v1.0.1.gz
> patch-v1.0.2.gz
> etc
>
> Each patch is obviously smaller than "base".  Git could easily make the
> patches, and each of those patches could be fed by hand into a repository
> with git-apply.  It doesn't seem like something that would require support on
> the other side, because it isn't so much a shallow clone (which /would/
> preserve history, making it available if wanted); it is pulling just, say,
> tagged commits out of an existing repository.
>
> Given a list of tags it is almost:
>
> git-archive <get me base>
> ssh remote git-diff v1.0.0..v1.0.1 | git-apply; git commit
> ssh remote git-diff v1.0.1..v1.0.2 | git-apply; git commit
>
> If that makes sense?  Obviously though it would be possible to use git rather
> than ssh to do this.

Hm.. I'm no git:// expert. But is it possible doing as follow?
1. git-archive <base>
2. reconstruct commit, blobs and trees from the archive
3. tell git server that you have one commit, you need another commit
(maybe heads only, i'm not sure here)
4. get the pack from git server, create new commit and a diff
-- 

^ permalink raw reply

* Re: index manipulation quickref
From: Nguyen Thai Ngoc Duy @ 2006-12-12 21:32 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vac1tvuyr.fsf@assigned-by-dhcp.cox.net>

On 12/13/06, Junio C Hamano <junkio@cox.net> wrote:
> I think this goes in the wrong direction.  For "newbies" the
> Porcelain-ish set is supposed to be enough and if there is
> something missing that they need to do update-index command
> itself or a pipeline that involves update-index to achieve
> common tasks, we should enhance Porcelain-ish that captures the
> pattern.

It is supposed to be porcelain command only. I figure what operation a
user may need when manipulating index, then find the corresponding
porcelain command.

As you can see, we have porcelain commands for most of operations. The
missing piece is reset a file in index (and maybe "git cat-file
::file" -- it's too cryptic). Hopefully "git reset -- file" will be
implemented soon.
-- 

^ permalink raw reply


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