Git development
 help / color / mirror / Atom feed
* Re: Moving a directory into another fails
From: Nicolas Vilz @ 2006-07-26 23:25 UTC (permalink / raw)
  To: Jon Smirl; +Cc: git
In-Reply-To: <9e4733910607261603m6772602cr333d8c58f555edaa@mail.gmail.com>

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

On Wed, Jul 26, 2006 at 07:03:30PM -0400, Jon Smirl wrote:
> This is a simpler sequence
> 
> cg clone git foo
> cg clone git foo1
> cd foo
> mkdir zzz
> git mv gitweb zzz
> cg diff >patch
> cg ../foo1
> cg patch <../foo/patch
> 
> Fails with these errors. We have determined that git apply patch is ok
> and this is a bug in cg patch.

Well, perhaps i should react faster and I shouldn't pause my fetchmail
for 2 or 3 hours... this is bad for this list :) You are kind of fast :) 

Nicolas

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

^ permalink raw reply

* Re: Slow fetches of tags
From: Junio C Hamano @ 2006-07-26 23:27 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: git, Johannes Schindelin, Linus Torvalds
In-Reply-To: <20060525131241.GA8443@linux-mips.org>

Ralf Baechle <ralf@linux-mips.org> writes:

> On Wed, May 24, 2006 at 04:43:02PM -0700, Linus Torvalds wrote:
>
>> Actually, maybe the problem is that Ralf's tree has two roots, because of 
>> the old CVS history. It might be following the other root down for the 
>> "have" part, since that one doesn't exist at all in the target and the 
>> other side will never acknowledge any of it. 
>> 
>> I'll play with it.
>
> Interesting idea, so I went to play with it, too.  I took a copy of the
> tree and deleted all branches except the v2.6.16-stable tracking branch
> which I pruned back to v2.6.16.17, then added a new branch starting at
> the oldest commit, your initial import of the kernel tree:

I've been looking at this issue again...

> $ git branch junk 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2
> $ git checkout junk
> $ seq -f "%05.0f" 1 100 | while read i; do echo $i; echo $i > Makefile;\
>   git commit -s -m "Blah $i" Makefile; done
>
> So with this I get:
>
> $ git branch
> * junk
>   v2.6.16-stable
> $
>
> If I now run
>
> $ strace git-fetch-pack --thin git://www.kernel.org/pub/scm/linux/kernel/\
> 	git/stable/linux-2.6.16.y.git \
> 	refs/heads/master refs/tags/v2.6.16.18 2>&1 | grep have /tmp/xxx
>
> I get:

... 100 newest commits from the junk branch and then all the
    tags the downloader has are sent as "have"s.

Now, sending the newest commits before sending the tags is
unavoidable, since the other end does not know where you forked
at (the purpose of the handshake is to find out where to begin
with).  But as soon as you send v2.6.16.17 (the latest tag that
you have in common with the other side, _and_ is a proper
ancestor of what you want -- v2.6.16.18 but that fact you do not
know yet), the server end should be able to say "ok, we know
enough".  That is not happening.

A few hints for debugging this:

 * local test is easier -- fetch-pack spawns upload-pack using
   PATH and GIT_EXEC_PATH so set them to point at the updated
   upload-pack being tested.

 * Passing the standard error from "fetch-pack -v" to "name-rev
   --stdin" makes it a bit more pleasant to see what is going on.

With the attached patch, the server side tells the client to
stop immediately after it says it has the commit tagged as
v2.6.16.17 while asking for v2.6.16.18.  With your "100 commits
on junk" repository, it does not make much of a difference,
though.  The reasons are (1) the 100 commits on "junk" are much
younger than any of the tags, so they are sent anyway, (2) we
have a 32-commit window, and keep one window in flight to make
the protocol stream, which means there will be max 64 "have"
that are in flight unacked, and a clone of linux-2.6.16.y
repository that has up to v2.6.16.17 tag has only 52 tags.

So we end up sending all the tags anyway in this particular
case.

I've thought about sending tags and only _tips_ of branches
first, but I think that would have a grave performance impact on
more normal cases.  If you are dealing with a remote repository
with a bunch of tags, your "master" is ahead of the remote
repository, and you do not use tracking branch to track the
remote (pretend you are Linus and pulling from a subsystem
maintainer), then you obviously do not want to send v2.6.12-rc2
tag before you send commits from your "master" branch to get to
where your subsystem maintainer forked from you (otherwise the
remote side would say "I do not know your 'master' commit, but
now we know we have this ancient v2.6.12-rc2 in common, so let's
have a pack between that and the tip of the subsystem tree"), so
I do think sending "100 commits on junk branch" is unavoidable.

I think the attached patch is safe in general, but somebody may
want to give an extra set of eyeballs to double check the logic
is sane.

-- >8 --
upload-pack: squelch downloader more aggressively under multi-ack

When the server side sees "have" line that makes all the "want"
commits somehow reachable from one of the "have" lines so far,
stop responding "continue" to prevent the other end going down
to send too many refs.

---
diff --git a/upload-pack.c b/upload-pack.c
index 617ee46..ac42d0d 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -452,8 +452,13 @@ static int get_common_commits(void)
 			default:
 				memcpy(hex, sha1_to_hex(sha1), 41);
 				if (multi_ack) {
-					const char *msg = "ACK %s continue\n";
-					packet_write(1, msg, hex);
+					const char *msg = "ACK %s%s\n";
+					const char *cont = " continue";
+					if (ok_to_give_up()) {
+						cont = "";
+						multi_ack = 0;
+					}
+					packet_write(1, msg, hex, cont);
 					memcpy(last_hex, hex, 41);
 				}
 				else if (have_obj.nr == 1)

^ permalink raw reply related

* local clone performance
From: Jon Smirl @ 2006-07-26 23:38 UTC (permalink / raw)
  To: git

Comparing git-clone to cg-clone

[jonsmirl@jonsmirl apps]$ time git-clone git foo
......
real    0m5.755s
user    0m4.548s
sys     0m0.512s

[jonsmirl@jonsmirl apps]$ time cg-clone git foo
....
real    0m18.970s
user    0m10.737s
sys     0m1.392s

Why does it take cg clone so long to set up the missing tags?
git-clone is over 3x faster.

-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply

* Re: [PATCH] cvsserver: imitate git-update-ref when committing
From: Shawn Pearce @ 2006-07-27  0:21 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0607262249010.29667@wbgn013.biozentrum.uni-wuerzburg.de>

You might want to also consider appending to the reflog, if it
exists/is enabled.  I still need to get upload-pack to do this but it
may be useful for some heads for some people...  or maybe not.  :-)

Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> 
> git-update-ref writes into the lockfile, and renames it afterwards. Like 
> commit v1.3.0-rc3~22, it is not only cleaner, but also helps with shared 
> setups: every developer can have a different primary group; what matters 
> is that $GIT_DIR/refs/heads has to be writable by a group you are in.
> 
> Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
> ---
>  git-cvsserver.perl |    8 ++++----
>  1 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/git-cvsserver.perl b/git-cvsserver.perl
> index 1b70cd9..2c1b0c7 100755
> --- a/git-cvsserver.perl
> +++ b/git-cvsserver.perl
> @@ -1144,9 +1144,7 @@ sub req_ci
>          exit;
>      }
>  
> -    open FILE, ">", "$ENV{GIT_DIR}refs/heads/$state->{module}";
> -    print FILE $commithash;
> -    close FILE;
> +    print LOCKFILE $commithash;
>  
>      $updater->update();
>  
> @@ -1173,7 +1171,9 @@ sub req_ci
>      }
>  
>      close LOCKFILE;
> -    unlink($lockfile);
> +    my $reffile = "$ENV{GIT_DIR}refs/heads/$state->{module}";
> +    unlink($reffile);
> +    rename($lockfile, $reffile);
>      chdir "/";
>  
>      print "ok\n";
> -- 
> 1.4.2.rc2.g2b3d-dirty

-- 
Shawn.

^ permalink raw reply

* Re: [PATCH 5/5] git-instaweb: If firefox was not found, just print the URL
From: Eric Wong @ 2006-07-27  1:12 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, junkio
In-Reply-To: <20060726224049.GA16645@localdomain>

Eric Wong <normalperson@yhbt.net> wrote:

Oops, I forgot to run offlineimap for a few hours and was desynced.
Disregard my messages, thanks.

-- 
Eric Wong

^ permalink raw reply

* Re: print errors from git-update-ref
From: Shawn Pearce @ 2006-07-27  1:28 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Alex Riesen, Git Mailing List
In-Reply-To: <7vk663h6zi.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano <junkio@cox.net> wrote:
> "Alex Riesen" <raa.lkml@gmail.com> writes:
> 
> > ...otherwise it not clear what happened when update-ref fails.
> >
> > E.g., git checkout -b a/b/c HEAD would print nothing if refs/heads/a
> > exists and is a directory (it does return 1, so scripts checking for
> > return code should be ok).
> 
> My gut feeling is that complaining from update-ref is fine, but
> I am still tired after a long week and not thinking straight, so
> I will not be applying this tonight.

So I looked into this issue tonight.  For starters I can't seem to
reproduce the situtation reported by Alex, and since he didn't
supply new test cases its difficult to actually fix it.

I did however find problems with git-update-ref a/b/c when a is
actually an existing ref.  This didn't report any error, so here's
a fix.  It may resolve Alex's problem - or maybe not.

-->8--
Display an error from update-ref if target ref name is invalid.

Alex Riesen (raa.lkml@gmail.com) recently observed that git branch
would fail with no error message due to unexpected situations with
regards to refs.  For example, if .git/refs/heads/gu is a file but
`git branch -b refs/heads/gu/fixa HEAD` was invoked by the user
it would fail silently due to refs/heads/gu being a file and not
a directory.

This change adds a test for trying to create a ref within a directory
that is actually currently a file, and adds error printing within
the ref locking routine should the resolve operation fail.

The error printing code probably belongs at this level of the library
as other failures within the ref locking, writing and logging code
are also currently at this level of the code.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 refs.c                |   33 +++++++++++++++++++++++++++++++++
 t/t1400-update-ref.sh |   12 ++++++++++++
 2 files changed, 45 insertions(+), 0 deletions(-)

diff --git a/refs.c b/refs.c
index 56db394..e99e9e4 100644
--- a/refs.c
+++ b/refs.c
@@ -290,10 +290,33 @@ static struct ref_lock *verify_lock(stru
 	return lock;
 }
 
+static char* not_a_directory (const char *orig_path)
+{
+	char *p = strdup(orig_path);
+	struct stat st;
+
+	do {
+		char * s = strrchr(p, '/');
+		if (s) {
+			*s = 0;
+			if (lstat(p, &st) == 0 && S_ISDIR(st.st_mode)) {
+				*s = '/';
+				break;
+			}
+		} else {
+			strcpy(p, orig_path);
+			break;
+		}
+	} while (errno == ENOTDIR);
+
+	return p;
+}
+
 static struct ref_lock *lock_ref_sha1_basic(const char *path,
 	int plen,
 	const unsigned char *old_sha1, int mustexist)
 {
+	const char *orig_path = path;
 	struct ref_lock *lock;
 	struct stat st;
 
@@ -303,7 +326,17 @@ static struct ref_lock *lock_ref_sha1_ba
 	plen = strlen(path) - plen;
 	path = resolve_ref(path, lock->old_sha1, mustexist);
 	if (!path) {
+		int last_errno = errno;
+		if (errno == ENOTDIR) {
+			char* p = not_a_directory(orig_path);
+			error("unable to resolve reference %s: %s",
+				p, strerror(errno));
+			free(p);
+		} else
+			error("unable to resolve reference %s: %s",
+				orig_path, strerror(errno));
 		unlock_ref(lock);
+		errno = last_errno;
 		return NULL;
 	}
 	lock->lk = xcalloc(1, sizeof(struct lock_file));
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 04fab26..e73827c 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -14,6 +14,8 @@ D=44444444444444444444444444444444444444
 E=5555555555555555555555555555555555555555
 F=6666666666666666666666666666666666666666
 m=refs/heads/master
+n_dir=refs/heads/gu
+n=$n_dir/fixes
 
 test_expect_success \
 	"create $m" \
@@ -26,6 +28,16 @@ test_expect_success \
 rm -f .git/$m
 
 test_expect_success \
+	"fail to create $n" \
+	'touch .git/$n_dir
+	 git-update-ref $n $A >out 2>err
+	 test $? = 1 &&
+	 test "" = "$(cat out)" &&
+	 grep "error: unable to resolve reference" err &&
+	 grep $n_dir err'
+rm -f .git/$n_dir out err
+
+test_expect_success \
 	"create $m (by HEAD)" \
 	'git-update-ref HEAD $A &&
 	 test $A = $(cat .git/$m)'
-- 
1.4.2.rc1.g802da

^ permalink raw reply related

* Re: Licensing and the library version of git
From: Shawn Pearce @ 2006-07-27  1:40 UTC (permalink / raw)
  To: Jon Smirl; +Cc: git
In-Reply-To: <9e4733910607261436v4c0802e5v7301e904593f9bab@mail.gmail.com>

Jon Smirl <jonsmirl@gmail.com> wrote:
> Can the library version of git be licensed LGPL instead of GPL? If it
> is GPL then it can't be linked into non-GPL projects like Eclipse.

True.  But I have a pure-Java implementation of portions of GIT:

	- pack file reader, including delta decompression;
	- loose object reader (sans new pack header format);
	- loose object writer (blobs, trees, commits, no tags);
	- ref reader/basic resolver;
	- ref writer;
	- new repository creation;
	- tree and commit parsing;
	- n-way tree structure diff (no blob content diff);

and Eclipse UI for:

	- resource decorator showing object state;
	- rename tracking (well, automatic delete then add);
	- add file/folder to repository;
	- delete file/folder from repository;
	- save workspace state to a tree;
	- periodically flush modified files into blobs;

but I need UI still for creating a commit.  I'd like to get that
code finished this week and get the repository posted on the web
for others to start messing around with if they are interested.
This project has just been slow going for me as I'm working looooong
hours at my day job.  :-)

-- 
Shawn.

^ permalink raw reply

* [PATCH] Per branch properties for pull and fetch
From: Santi Béjar @ 2006-07-27  8:14 UTC (permalink / raw)
  To: Git Mailing List

It allows to specify on a per branch basis the following:
.- default repository to fetch
.- default branches to merge on a per repository basis
.- default pull.{octopus,twohead}

So if you have this in the config:
[branch "my"]
	remote=yours
	merge=master
	merge=our from theirs
	merge=mine from .

and you are in the branch "my":

"git pull": fetch the remote yours and merge the branch master.
"git pull theirs": fetch the remote theirs and merge the branch our.
"git pull .": merge the branch mine from the local repository.
---
 Documentation/config.txt |   14 +++++++++++
 git-fetch.sh             |   13 ++++++----
 git-parse-remote.sh      |   57 ++++++++++++++++++++++++++++++++++++++++++++++
 git-pull.sh              |   29 ++++++++++++++++++++---
 4 files changed, 104 insertions(+), 9 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 465eb13..f12b595 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -116,6 +116,20 @@ apply.whitespace::
 	Tells `git-apply` how to handle whitespaces, in the same way
 	as the '--whitespace' option. See gitlink:git-apply[1].
 
+branch.<name>.remote::
+	When in branch <name>, it tells `git-fetch` which remote to fetch.
+
+branch.<name>.merge::
+	When in branch <name>, it tells `git-pull` to merge this remote
+	branch of the repository branch.<name>.remote. To specify a different
+	remote repository use the from `<branch> from <repo>`.
+
+branch.<name>.octopus::
+	When in branch <name>, the same as pull.octopus.
+
+branch.<name>.twohead::
+	When in branch <name>, the same as pull.twohead.
+
 diff.color::
 	When true (or `always`), always use colors in patch.
 	When false (or `never`), never.  When set to `auto`, use
diff --git a/git-fetch.sh b/git-fetch.sh
index c2eebee..8129d8a 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -68,11 +68,13 @@ done
 
 case "$#" in
 0)
-	test -f "$GIT_DIR/branches/origin" ||
-		test -f "$GIT_DIR/remotes/origin" ||
-			git-repo-config --get remote.origin.url >/dev/null ||
-				die "Where do you want to fetch from today?"
-	set origin ;;
+	curr_branch=$(git-symbolic-ref HEAD)
+	curr_branch=${curr_branch##refs/heads/}
+	origin=$(git-repo-config --get "branch.$curr_branch.remote")
+	origin=${origin:-origin}
+	test -n "$(get_remote_url $origin)" ||
+		die "Where do you want to fetch from today?"
+	set $origin ;;
 esac
 
 remote_nick="$1"
@@ -446,3 +448,4 @@ case ",$update_head_ok,$orig_head," in
 	fi
 	;;
 esac
+echo $remote_nick >"$GIT_DIR/FETCH_REMOTE"
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index 187f088..fe6c713 100755
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -209,3 +209,60 @@ resolve_alternates () {
 		esac
 	done
 }
+
+get_head_for_remote_branch () {
+	if [ "$1" == "." ];
+	then
+		git-rev-parse $2 2>/dev/null||
+			die "error: no such ref $2"
+		return
+	fi
+	data_source=$(get_data_source "$1")
+	case "$data_source" in
+	config)
+		refspec=$(git-repo-config --get "remote.$1.fetch" ^$2:) ;;
+	branches)
+		remote_branch=$(sed -ne '/#/s/.*#//p' "$GIT_DIR/branches/$1")
+		case "$remote_branch" in '') remote_branch=master ;; esac
+		[ $remote_branch == $2 ] &&
+		refspec="refs/heads/${remote_branch}:refs/heads/$1"
+		;;
+	remotes)
+		refspec=$(grep "^Pull: $2:" $GIT_DIR/remotes/$1)
+		refspec=${refspec##Pull: }
+		;;
+	*)
+		die "internal error: get-head_for_remote_branch" ;;
+	esac
+	[ "$refspec" ] || die "Branch $2 does not exist in the repository: $1."
+	git-rev-parse $(expr "z$refspec" : 'z[^:]*:\(.*\)')
+}
+
+get_heads_to_merge_in_branch () {
+ 	case "$#" in
+	2)
+		default=$(git repo-config --get-all "branch.$1.remote")
+		: >"$GIT_DIR/HEADS_TO_MERGE"
+		git repo-config --get-all "branch.$1.merge" |
+		while read ref ; do
+			case $ref in
+			?*' 'from' '?*)
+				remote=$(expr "z$ref" : 'z.* from \(.*\)')
+				branch=$(expr "z$ref" : 'z\(.*\) from .*');;
+			*)
+				remote=$default
+				branch=$ref;;
+			esac
+			[ "$remote" != "$2" ] && continue
+			headm=$(get_head_for_remote_branch $remote $branch) || exit 1
+			echo $headm
+			remoteurl=$(get_remote_url $remote)
+			remoteurl_1=$(expr "z$remoteurl" : 'z\(.*\)\.git/*$') &&
+				remoteurl=$remoteurl_1
+			echo "$headm		branch '$branch' of $remoteurl" \
+				>>"$GIT_DIR/HEADS_TO_MERGE"
+		done
+		;;
+	*) exit 1
+	esac
+}
diff --git a/git-pull.sh b/git-pull.sh
index f380437..467d9c0 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -7,6 +7,7 @@ # Fetch one or more remote refs and merg
 USAGE='[-n | --no-summary] [--no-commit] [-s strategy]... [<fetch-options>] <repo> <head>...'
 LONG_USAGE='Fetch one or more remote refs and merge it/them into the current HEAD.'
 . git-sh-setup
+. git-parse-remote
 
 strategy_args= no_summary= no_commit= squash=
 while case "$#,$1" in 0) break ;; *,-*) ;; *) break ;; esac
@@ -47,6 +48,8 @@ done
 orig_head=$(git-rev-parse --verify HEAD) || die "Pulling into a black hole?"
 git-fetch --update-head-ok --reflog-action=pull "$@" || exit 1
 
+curr_branch=$(git-symbolic-ref HEAD)
+curr_branch=${curr_branch##refs/heads/}
 curr_head=$(git-rev-parse --verify HEAD)
 if test "$curr_head" != "$orig_head"
 then
@@ -70,9 +73,18 @@ to recover.'
 
 fi
 
-merge_head=$(sed -e '/	not-for-merge	/d' \
-	-e 's/	.*//' "$GIT_DIR"/FETCH_HEAD | \
-	tr '\012' ' ')
+remote=$(cat "$GIT_DIR/FETCH_REMOTE")
+merge_head=$(get_heads_to_merge_in_branch "$curr_branch" "$remote" ) || exit
+
+if [ -n "$merge_head" ];
+then
+	merge_name=$(git-fmt-merge-msg <"$GIT_DIR/HEADS_TO_MERGE") || exit
+else
+	merge_head=$(sed -e '/	not-for-merge	/d' \
+		-e 's/	.*//' "$GIT_DIR"/FETCH_HEAD | \
+		tr '\012' ' ')
+	merge_name=$(git-fmt-merge-msg <"$GIT_DIR/FETCH_HEAD") || exit
+fi
 
 case "$merge_head" in
 '')
@@ -85,6 +97,11 @@ case "$merge_head" in
 	then
 		strategy_default_args="-s $var"
 	fi
+	var=`git-repo-config --get branch.$curr_branch.octopus`
+	if test -n "$var"
+	then
+		strategy_default_args="-s $var"
+	fi
 	;;
 *)
 	var=`git-repo-config --get pull.twohead`
@@ -92,6 +109,11 @@ case "$merge_head" in
         then
 		strategy_default_args="-s $var"
 	fi
+	var=`git-repo-config --get branch.$curr_branch.twohead`
+	if test -n "$var"
+        then
+		strategy_default_args="-s $var"
+	fi
 	;;
 esac
 
@@ -101,7 +123,6 @@ case "$strategy_args" in
 	;;
 esac
 
-merge_name=$(git-fmt-merge-msg <"$GIT_DIR/FETCH_HEAD") || exit
 git-merge "--reflog-action=pull $*" \
 	$no_summary $no_commit $squash $strategy_args \
 	"$merge_name" HEAD $merge_head
-- 
1.4.2.rc2.g1728

^ permalink raw reply related

* Re: [WIP] Status update on merge-recursive in C
From: Junio C Hamano @ 2006-07-27  8:51 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, Pavel Roskin
In-Reply-To: <Pine.LNX.4.63.0607091634010.29667@wbgn013.biozentrum.uni-wuerzburg.de>

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

> On Sun, 9 Jul 2006, Pavel Roskin wrote:
>
>> - variable declarations in the middle of the code (allowed by c99 but
>> not by ANSI C) and incomplete function declarations (no "void").  It's
>> not C++, let's stick to the C standards.
>...
>> I'm attaching a patch that fixes everything except variable
>> declarations.
>
> May I ask you a favour? Can you redo the patch in, say, two weeks? Thank 
> you!

Now it's about two weeks so maybe we can apply this on top to
clean up and prod you to continue ;-)?

-- >8 --
[PATCH] merge-recursive in C: pedantic.

This just cleans up mixed declaration and code warnings and
incomplete function declarations, as Pavel earlier pointed out.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 merge-recursive.c |  147 ++++++++++++++++++++++++++++++-----------------------
 1 files changed, 83 insertions(+), 64 deletions(-)

diff --git a/merge-recursive.c b/merge-recursive.c
index 8d30519..3735df1 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -25,9 +25,9 @@ #include "path-list.h"
 /*#define DEBUG*/
 
 #ifdef DEBUG
-#define debug(args, ...) fprintf(stderr, args, ## __VA_ARGS__)
+#define debug(...) fprintf(stderr, __VA_ARGS__)
 #else
-#define debug(args, ...)
+#define debug(...) do { ; /* nothing */ } while (0)
 #endif
 
 #ifdef DEBUG
@@ -61,13 +61,14 @@ static void show_ce_entry(const char *ta
 	fputc('\n', stderr);
 }
 
-static void ls_files() {
+static void ls_files(void) {
 	int i;
 	for (i = 0; i < active_nr; i++) {
 		struct cache_entry *ce = active_cache[i];
 		show_ce_entry("", ce);
 	}
 	fprintf(stderr, "---\n");
+	if (0) ls_files(); /* avoid "unused" warning */
 }
 #endif
 
@@ -89,8 +90,8 @@ static const char *commit_title(struct c
 			s = "(bad commit)";
 			*len = strlen(s);
 		} else {
-			s = commit->buffer;
 			char prev = '\0';
+			s = commit->buffer;
 			while ( *s ) {
 				if ( '\n' == prev && '\n' == *s ) {
 					++s;
@@ -207,7 +208,7 @@ static const char *original_index_file;
 static const char *temporary_index_file;
 static int cache_dirty = 0;
 
-static int flush_cache()
+static int flush_cache(void)
 {
 	/* flush temporary index */
 	struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
@@ -290,11 +291,12 @@ #if 0
 		getenv("GIT_INDEX_FILE"),
 		sha1_to_hex(tree->object.sha1));
 #endif
+	int rc;
 	const char *argv[] = { "git-read-tree", NULL, NULL, };
 	if (cache_dirty)
 		die("read-tree with dirty cache");
 	argv[1] = sha1_to_hex(tree->object.sha1);
-	int rc = run_command_v(2, argv);
+	rc = run_command_v(2, argv);
 	return rc < 0 ? -1: rc;
 }
 
@@ -314,6 +316,7 @@ #if 0
 		sha1_to_hex(head->object.sha1),
 		sha1_to_hex(merge->object.sha1));
 #endif
+	int rc;
 	const char *argv[] = {
 		"git-read-tree", NULL, "-m", NULL, NULL, NULL,
 		NULL,
@@ -324,32 +327,34 @@ #endif
 	argv[3] = sha1_to_hex(common->object.sha1);
 	argv[4] = sha1_to_hex(head->object.sha1);
 	argv[5] = sha1_to_hex(merge->object.sha1);
-	int rc = run_command_v(6, argv);
+	rc = run_command_v(6, argv);
 	return rc < 0 ? -1: rc;
 }
 
 /*
  * TODO: this can be streamlined by refactoring builtin-write-tree.c
  */
-static struct tree *git_write_tree()
+static struct tree *git_write_tree(void)
 {
 #if 0
 	fprintf(stderr, "GIT_INDEX_FILE='%s' git-write-tree\n",
 		getenv("GIT_INDEX_FILE"));
 #endif
-	if (cache_dirty)
-		flush_cache();
-	FILE *fp = popen("git-write-tree 2>/dev/null", "r");
+	FILE *fp;
+	int rc;
 	char buf[41];
 	unsigned char sha1[20];
 	int ch;
 	unsigned i = 0;
+	if (cache_dirty)
+		flush_cache();
+	fp = popen("git-write-tree 2>/dev/null", "r");
 	while ( (ch = fgetc(fp)) != EOF )
 		if ( i < sizeof(buf)-1 && ch >= '0' && ch <= 'f' )
 			buf[i++] = ch;
 		else
 			break;
-	int rc = pclose(fp);
+	rc = pclose(fp);
 	if ( rc == -1 || WEXITSTATUS(rc) )
 		return NULL;
 	buf[i] = '\0';
@@ -467,7 +472,7 @@ static void free_index_entries(struct pa
  * Create a dictionary mapping file names to CacheEntry objects. The
  * dictionary contains one entry for every path with a non-zero stage entry.
  */
-static struct path_list *get_unmerged()
+static struct path_list *get_unmerged(void)
 {
 	struct path_list *unmerged = xcalloc(1, sizeof(struct path_list));
 	int i;
@@ -479,10 +484,10 @@ static struct path_list *get_unmerged()
 	}
 	for (i = 0; i < active_nr; i++) {
 		struct cache_entry *ce = active_cache[i];
+		struct stage_data *e;
 		if (!ce_stage(ce))
 			continue;
-
-		struct stage_data *e = index_entry_get(unmerged, ce->name);
+		e = index_entry_get(unmerged, ce->name);
 		e->stages[ce_stage(ce)].mode = ntohl(ce->ce_mode);
 		memcpy(e->stages[ce_stage(ce)].sha, ce->sha1, 20);
 	}
@@ -530,13 +535,16 @@ static struct path_list *get_renames(str
 					struct tree *bTree,
 					struct path_list *entries)
 {
+	int i;
+	struct path_list *renames;
+	struct diff_options opts;
 #ifdef DEBUG
 	time_t t = time(0);
+
 	debug("getRenames ...\n");
 #endif
-	int i;
-	struct path_list *renames = xcalloc(1, sizeof(struct path_list));
-	struct diff_options opts;
+
+	renames = xcalloc(1, sizeof(struct path_list));
 	diff_setup(&opts);
 	opts.recursive = 1;
 	opts.detect_rename = DIFF_DETECT_RENAME;
@@ -547,6 +555,7 @@ #endif
 	diffcore_std(&opts);
 	for (i = 0; i < diff_queued_diff.nr; ++i) {
 		struct rename *re;
+		struct path_list_item *item;
 		struct diff_filepair *pair = diff_queued_diff.queue[i];
 		if (pair->status != 'R') {
 			diff_free_filepair(pair);
@@ -560,19 +569,17 @@ #endif
 		if ( !re->src_entry ) {
 			re->src_entry = index_entry_from_db(re->pair->one->path,
 					oTree, aTree, bTree);
-			struct path_list_item *item =
-				path_list_insert(re->pair->one->path, entries);
+			item = path_list_insert(re->pair->one->path, entries);
 			item->util = re->src_entry;
 		}
 		re->dst_entry = index_entry_find(entries, re->pair->two->path);
 		if ( !re->dst_entry ) {
 			re->dst_entry = index_entry_from_db(re->pair->two->path,
 					oTree, aTree, bTree);
-			struct path_list_item *item =
-				path_list_insert(re->pair->two->path, entries);
+			item = path_list_insert(re->pair->two->path, entries);
 			item->util = re->dst_entry;
 		}
-		struct path_list_item *item = path_list_insert(pair->one->path, renames);
+		item = path_list_insert(pair->one->path, renames);
 		item->util = re;
 	}
 	opts.output_format = DIFF_FORMAT_NO_OUTPUT;
@@ -613,14 +620,14 @@ int update_stages(const char *path,
  */
 static int remove_path(const char *name)
 {
-	int ret;
-	char *slash;
+	int ret, len;
+	char *slash, *dirs;
 
 	ret = unlink(name);
 	if ( ret )
 		return ret;
-	int len = strlen(name);
-	char *dirs = malloc(len+1);
+	len = strlen(name);
+	dirs = malloc(len+1);
 	memcpy(dirs, name, len);
 	dirs[len] = '\0';
 	while ( (slash = strrchr(name, '/')) ) {
@@ -664,15 +671,17 @@ int remove_file(int clean, const char *p
 static char *unique_path(const char *path, const char *branch)
 {
 	char *newpath = xmalloc(strlen(path) + 1 + strlen(branch) + 8 + 1);
+	char *p;
+	int suffix;
+	struct stat st;
 	strcpy(newpath, path);
 	strcat(newpath, "~");
-	char *p = newpath + strlen(newpath);
+	p = newpath + strlen(newpath);
 	strcpy(p, branch);
 	for ( ; *p; ++p )
 		if ( '/' == *p )
 			*p = '_';
-	int suffix = 0;
-	struct stat st;
+	suffix = 0;
 	while ( path_list_has_path(&currentFileSet, newpath) ||
 		path_list_has_path(&currentDirectorySet, newpath) ||
 		lstat(newpath, &st) == 0 ) {
@@ -754,6 +763,7 @@ void update_file_flags(const unsigned ch
 			die("blob expected for %s '%s'", sha1_to_hex(sha), path);
 
 		if ( S_ISREG(mode) ) {
+			int fd;
 			if ( mkdir_p(path, 0777, 0 /* don't create last element */) )
 				die("failed to create path %s: %s", path, strerror(errno));
 			unlink(path);
@@ -761,7 +771,7 @@ void update_file_flags(const unsigned ch
 				mode = 0777;
 			else
 				mode = 0666;
-			int fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
+			fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
 			if ( fd < 0 )
 				die("failed to open %s: %s", path, strerror(errno));
 			flush_buffer(fd, buf, size);
@@ -863,17 +873,19 @@ static struct merge_file_info merge_file
 			char orig[PATH_MAX];
 			char src1[PATH_MAX];
 			char src2[PATH_MAX];
-
-			git_unpack_file(oSha, orig);
-			git_unpack_file(aSha, src1);
-			git_unpack_file(bSha, src2);
-
 			const char *argv[] = {
 				"merge", "-L", NULL, "-L", NULL, "-L", NULL,
 				src1, orig, src2,
 				NULL
 			};
 			char *la, *lb, *lo;
+			struct stat st;
+			int fd;
+
+			git_unpack_file(oSha, orig);
+			git_unpack_file(aSha, src1);
+			git_unpack_file(bSha, src2);
+
 			argv[2] = la = strdup(mkpath("%s/%s", branch1Name, aPath));
 			argv[6] = lb = strdup(mkpath("%s/%s", branch2Name, bPath));
 			argv[4] = lo = strdup(mkpath("orig/%s", oPath));
@@ -892,8 +904,7 @@ #endif
 				die("Failed to execute 'merge'. merge(1) is used as the "
 				    "file-level merge tool. Is 'merge' in your path?");
 			}
-			struct stat st;
-			int fd = open(src1, O_RDONLY);
+			fd = open(src1, O_RDONLY);
 			if (fd < 0 || fstat(fd, &st) < 0 ||
 					index_fd(result.sha, fd, &st, 1,
 						"blob"))
@@ -1018,6 +1029,7 @@ static int process_renames(struct path_l
 		struct path_list *renames1, *renames2, *renames2Dst;
 		struct rename *ren1, *ren2;
 		const char *branchName1, *branchName2;
+		const char *ren1_src, *ren1_dst;
 		ren1 = find_rename_bysrc(renamesA, src);
 		ren2 = find_rename_bysrc(renamesB, src);
 		/* TODO: refactor, so that 1/2 are not needed */
@@ -1028,12 +1040,13 @@ static int process_renames(struct path_l
 			branchName1 = branchNameA;
 			branchName2 = branchNameB;
 		} else {
+			struct rename *tmp;
 			renames1 = renamesB;
 			renames2 = renamesA;
 			renames2Dst = &byDstA;
 			branchName1 = branchNameB;
 			branchName2 = branchNameA;
-			struct rename *tmp = ren2;
+			tmp = ren2;
 			ren2 = ren1;
 			ren1 = tmp;
 		}
@@ -1045,8 +1058,8 @@ static int process_renames(struct path_l
 			continue;
 		ren1->processed = 1;
 
-		const char *ren1_src = ren1->pair->one->path;
-		const char *ren1_dst = ren1->pair->two->path;
+		ren1_src = ren1->pair->one->path;
+		ren1_dst = ren1->pair->two->path;
 
 		if ( ren2 ) {
 			const char *ren2_src = ren2->pair->one->path;
@@ -1065,8 +1078,8 @@ static int process_renames(struct path_l
 				       src, ren2_dst, branchName2);
 				conflict_rename_rename(ren1, branchName1, ren2, branchName2);
 			} else {
-				remove_file(1, ren1_src);
 				struct merge_file_info mfi;
+				remove_file(1, ren1_src);
 				mfi = merge_file(ren1_src,
 						 ren1->pair->one->sha1,
 						 ren1->pair->one->mode,
@@ -1102,13 +1115,17 @@ static int process_renames(struct path_l
 				update_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst);
 			}
 		} else {
-			/* Renamed in 1, maybe changed in 2 */
-			remove_file(1, ren1_src);
-
 			unsigned char srcShaOtherBranch[20], dstShaOtherBranch[20];
 			unsigned srcModeOtherBranch, dstModeOtherBranch;
 
-			int stage = renamesA == renames1 ? 3: 2;
+			int stage;
+			int tryMerge = 0;
+			char *newPath;
+
+			/* Renamed in 1, maybe changed in 2 */
+			remove_file(1, ren1_src);
+
+			stage = renamesA == renames1 ? 3: 2;
 
 			memcpy(srcShaOtherBranch, ren1->src_entry->stages[stage].sha, 20);
 			srcModeOtherBranch = ren1->src_entry->stages[stage].mode;
@@ -1116,8 +1133,7 @@ static int process_renames(struct path_l
 			memcpy(dstShaOtherBranch, ren1->dst_entry->stages[stage].sha, 20);
 			dstModeOtherBranch = ren1->dst_entry->stages[stage].mode;
 
-			int tryMerge = 0;
-			char *newPath;
+			tryMerge = 0;
 
 			if (path_list_has_path(&currentDirectorySet, ren1_dst)) {
 				cleanMerge = 0;
@@ -1162,18 +1178,19 @@ static int process_renames(struct path_l
 				unsigned omode = ren1->pair->one->mode;
 				unsigned amode = ren1->pair->two->mode;
 				unsigned bmode = srcModeOtherBranch;
+				const char *aBranch = branchName1;
+				const char *bBranch = branchName2;
+				struct merge_file_info mfi;
+
 				memcpy(osha, ren1->pair->one->sha1, 20);
 				memcpy(asha, ren1->pair->two->sha1, 20);
 				memcpy(bsha, srcShaOtherBranch, 20);
-				const char *aBranch = branchName1;
-				const char *bBranch = branchName2;
 
 				if ( renamesA != renames1 ) {
 					memswp(&aname, &bname, sizeof(aname));
 					memswp(asha, bsha, 20);
 					memswp(&aBranch, &bBranch, sizeof(aBranch));
 				}
-				struct merge_file_info mfi;
 				mfi = merge_file(oname, osha, omode,
 						 aname, asha, amode,
 						 bname, bsha, bmode,
@@ -1280,8 +1297,9 @@ static int process_entry(const char *pat
 			conf = "directory/file";
 		}
 		if ( path_list_has_path(&currentDirectorySet, path) ) {
+			const char *newPath;
 			cleanMerge = 0;
-			const char *newPath = unique_path(path, addBranch);
+			newPath = unique_path(path, addBranch);
 			output("CONFLICT (%s): There is a directory with name %s in %s. "
 			       "Adding %s as %s",
 			       conf, path, otherBranch, path, newPath);
@@ -1306,9 +1324,10 @@ static int process_entry(const char *pat
 				assert(0 && "This case must be handled by git-read-tree");
 			}
 		} else {
+			const char *newPath1, *newPath2;
 			cleanMerge = 0;
-			const char *newPath1 = unique_path(path, branch1Name);
-			const char *newPath2 = unique_path(path, branch2Name);
+			newPath1 = unique_path(path, branch1Name);
+			newPath2 = unique_path(path, branch2Name);
 			output("CONFLICT (add/add): File %s added non-identically "
 			       "in both branches. Adding as %s and %s instead.",
 			       path, newPath1, newPath2);
@@ -1319,8 +1338,8 @@ static int process_entry(const char *pat
 
 	} else if ( oSha && aSha && bSha ) {
 		/* case D: Modified in both, but differently. */
-		output("Auto-merging %s", path);
 		struct merge_file_info mfi;
+		output("Auto-merging %s", path);
 		mfi = merge_file(path, oSha, oMode,
 				 path, aSha, aMode,
 				 path, bSha, bMode,
@@ -1373,19 +1392,19 @@ static struct merge_tree_result merge_tr
 	result.tree = git_write_tree();
 
 	if ( !result.tree ) {
+		struct path_list *entries, *re_head, *re_merge;
+		int i;
 		path_list_clear(&currentFileSet, 1);
 		path_list_clear(&currentDirectorySet, 1);
 		get_files_dirs(head, &currentFileSet, &currentDirectorySet);
 		get_files_dirs(merge, &currentFileSet, &currentDirectorySet);
 
-		struct path_list *entries = get_unmerged();
-		struct path_list *re_head, *re_merge;
+		entries = get_unmerged();
 		re_head  = get_renames(head, common, head, merge, entries);
 		re_merge = get_renames(merge, common, head, merge, entries);
 		result.clean = process_renames(re_head, re_merge,
 					       branch1Name, branch2Name);
 		debug("\tprocessing entries...\n");
-		int i;
 		for (i = 0; i < entries->nr; i++) {
 			const char *path = entries->items[i].path;
 			struct stage_data *e = entries->items[i].util;
@@ -1512,6 +1531,10 @@ int main(int argc, char *argv[])
 {
 	static const char *bases[2];
 	static unsigned bases_count = 0;
+	int i;
+	const char *branch1, *branch2;
+	struct merge_result result;
+	struct commit *h1, *h2;
 
 	original_index_file = getenv("GIT_INDEX_FILE");
 
@@ -1523,7 +1546,6 @@ int main(int argc, char *argv[])
 	if (argc < 4)
 		die("Usage: %s <base>... -- <head> <remote> ...\n", argv[0]);
 
-	int i;
 	for (i = 1; i < argc; ++i) {
 		if (!strcmp(argv[i], "--"))
 			break;
@@ -1533,15 +1555,12 @@ int main(int argc, char *argv[])
 	if (argc - i != 3) /* "--" "<head>" "<remote>" */
 		die("Not handling anything other than two heads merge.");
 
-	const char *branch1, *branch2;
-
 	branch1 = argv[++i];
 	branch2 = argv[++i];
 	printf("Merging %s with %s\n", branch1, branch2);
 
-	struct merge_result result;
-	struct commit *h1 = get_ref(branch1);
-	struct commit *h2 = get_ref(branch2);
+	h1 = get_ref(branch1);
+	h2 = get_ref(branch2);
 
 	if (bases_count == 1) {
 		struct commit *ancestor = get_ref(bases[0]);
-- 
1.4.2.rc2.g544b

^ permalink raw reply related

* Re: [PATCH] cvsserver: imitate git-update-ref when committing
From: Johannes Schindelin @ 2006-07-27  8:53 UTC (permalink / raw)
  To: Shawn Pearce; +Cc: git
In-Reply-To: <20060727002130.GA32492@spearce.org>

Hi,

On Wed, 26 Jul 2006, Shawn Pearce wrote:

> You might want to also consider appending to the reflog, if it exists/is 
> enabled.

Given that I do not use it, and do not really understand what it does, 
this would be a bad idea ;-)

Ciao,
Dscho

P.S.: How's your Java thing coming along?

^ permalink raw reply

* Re: [PATCH] Per branch properties for pull and fetch
From: Martin Waitz @ 2006-07-27  8:55 UTC (permalink / raw)
  To: Santi Béjar; +Cc: Git Mailing List
In-Reply-To: <87lkqfcvm2.fsf@gmail.com>

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

hoi :)

On Thu, Jul 27, 2006 at 10:14:45AM +0200, Santi Béjar wrote:
> It allows to specify on a per branch basis the following:
> .- default repository to fetch
> .- default branches to merge on a per repository basis
> .- default pull.{octopus,twohead}
> 
> So if you have this in the config:
> [branch "my"]
> 	remote=yours
> 	merge=master
> 	merge=our from theirs
> 	merge=mine from .

could we default the to-be-merged branch to "remotes/$remote/$branch" if
that exists?. That could make life a lot easier when using
clone --use-separate-remote.

-- 
Martin Waitz

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

^ permalink raw reply

* [PATCH 1/2] rebase: Fix the detection of fast-forwarding of the current branch to upstream.
From: Robert Shearman @ 2006-07-27  9:32 UTC (permalink / raw)
  To: Git Mailing List

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


Previously, a rebasing operation with on a branch that is just tracking 
an upstream branch would output a confusing "Nothing to do" due to no 
patches being given to git-am.

The test brings the behaviour back into line with that of just before 
e646c9c8c0aa995eac284ea0a2117add19c4461c.
Signed-off-by: Robert Shearman <rob@codeweavers.com>
---
  git-rebase.sh |    2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)

[-- Attachment #2: 5d77c657b6e3b8fabe8690171a10aa54ec2cf641.diff --]
[-- Type: text/x-patch, Size: 374 bytes --]

diff --git a/git-rebase.sh b/git-rebase.sh
index 29028dd..5554541 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -281,7 +281,7 @@ git-reset --hard "$onto"
 
 # If the $onto is a proper descendant of the tip of the branch, then
 # we just fast forwarded.
-if test "$mb" = "$onto"
+if test "$mb" = "$branch"
 then
 	echo >&2 "Fast-forwarded $branch to $newbase."
 	exit 0


^ permalink raw reply related

* [PATCH 2/2] rebase: Make the fast-fowarding message more user-friendly by using branch names instead of SHA1 IDs.
From: Robert Shearman @ 2006-07-27  9:32 UTC (permalink / raw)
  To: Git Mailing List

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

Signed-off-by: Robert Shearman <rob@codeweavers.com>
---
  git-rebase.sh |    2 +-
  1 files changed, 1 insertions(+), 1 deletions(-)

[-- Attachment #2: 3bd88862ba13448b574662ffda717b96ddab8e98.diff --]
[-- Type: text/x-patch, Size: 355 bytes --]

diff --git a/git-rebase.sh b/git-rebase.sh
index 5554541..1c23798 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -283,7 +283,7 @@ # If the $onto is a proper descendant of
 # we just fast forwarded.
 if test "$mb" = "$branch"
 then
-	echo >&2 "Fast-forwarded $branch to $newbase."
+	echo >&2 "Fast-forwarded $branch_name to $onto_name."
 	exit 0
 fi
 


^ permalink raw reply related

* Re: [PATCH] Per branch properties for pull and fetch
From: Santi @ 2006-07-27  9:40 UTC (permalink / raw)
  To: Martin Waitz; +Cc: Git Mailing List
In-Reply-To: <20060727085516.GC27593@admingilde.org>

2006/7/27, Martin Waitz <tali@admingilde.org>:
> hoi :)
>
> On Thu, Jul 27, 2006 at 10:14:45AM +0200, Santi Béjar wrote:
> > It allows to specify on a per branch basis the following:
> > .- default repository to fetch
> > .- default branches to merge on a per repository basis
> > .- default pull.{octopus,twohead}
> >
> > So if you have this in the config:
> > [branch "my"]
> >       remote=yours
> >       merge=master
> >       merge=our from theirs
> >       merge=mine from .
>
> could we default the to-be-merged branch to "remotes/$remote/$branch" if
> that exists?. That could make life a lot easier when using
> clone --use-separate-remote.

I would prefer to change git-clone and git-branch to write the full
config. And I'll do this if this or someting like this is accepted.

  Santi

^ permalink raw reply

* Re: [WIP] Status update on merge-recursive in C
From: Johannes Schindelin @ 2006-07-27  9:41 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Pavel Roskin
In-Reply-To: <7vu053o2g7.fsf@assigned-by-dhcp.cox.net>

Hi,

On Thu, 27 Jul 2006, Junio C Hamano wrote:

> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > On Sun, 9 Jul 2006, Pavel Roskin wrote:
> >
> >> - variable declarations in the middle of the code (allowed by c99 but
> >> not by ANSI C) and incomplete function declarations (no "void").  It's
> >> not C++, let's stick to the C standards.
> >...
> >> I'm attaching a patch that fixes everything except variable
> >> declarations.
> >
> > May I ask you a favour? Can you redo the patch in, say, two weeks? Thank 
> > you!
> 
> Now it's about two weeks so maybe we can apply this on top to
> clean up and prod you to continue ;-)?

*grin*

Actually, we continued a little with it, but I mainly waited what would 
happen to "git-read-tree --rename"...

I will send an updated patch soon. The remaining TODOs after that are:

$ grep TODO merge-recursive.c 
 * TODO: we should not have to copy the SHA1s around, but rather reference
 * TODO: check if we can just reuse the active_cache structure: it is already
 * TODO: this can be streamlined by refactoring builtin-read-tree.c
 * TODO: this can be streamlined by refactoring builtin-read-tree.c
 * TODO: this can be streamlined by refactoring builtin-write-tree.c
/* General TODO: no javaIfiCation: rename updateCache to update_cache */
 * TODO: once we no longer call external programs, we'd probably be better off
/* General TODO: get rid of all the debug messages */
                /* TODO: refactor, so that 1/2 are not needed */

So, the biggest problem I see: refactoring builtin-read-tree. I really 
could use some help there -- I already tried 3 times to come up with a 
nice abstraction for unpack_trees() which could be used as a library 
function.

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH] Per branch properties for pull and fetch
From: Santi @ 2006-07-27 10:06 UTC (permalink / raw)
  To: Martin Waitz; +Cc: Git Mailing List
In-Reply-To: <8aa486160607270240h412b0dcek1d57eeb2b254fb2e@mail.gmail.com>

2006/7/27, Santi <sbejar@gmail.com>:
> 2006/7/27, Martin Waitz <tali@admingilde.org>:
> > hoi :)
> >
> > On Thu, Jul 27, 2006 at 10:14:45AM +0200, Santi Béjar wrote:
> > > It allows to specify on a per branch basis the following:
> > > .- default repository to fetch
> > > .- default branches to merge on a per repository basis
> > > .- default pull.{octopus,twohead}
> > >
> > > So if you have this in the config:
> > > [branch "my"]
> > >       remote=yours
> > >       merge=master
> > >       merge=our from theirs
> > >       merge=mine from .
> >
> > could we default the to-be-merged branch to "remotes/$remote/$branch" if
> > that exists?. That could make life a lot easier when using
> > clone --use-separate-remote.
>
> I would prefer to change git-clone and git-branch to write the full
> config. And I'll do this if this or someting like this is accepted.
>

On the other hand, my patch changes the behaviour only when explicitly
configured, and your proposed default would change the behaviour even
without changes to the config.

Santi

^ permalink raw reply

* Re: print errors from git-update-ref
From: Johannes Schindelin @ 2006-07-27 11:04 UTC (permalink / raw)
  To: Shawn Pearce; +Cc: Junio C Hamano, Alex Riesen, Git Mailing List
In-Reply-To: <20060727012856.GB32492@spearce.org>

Hi,

On Wed, 26 Jul 2006, Shawn Pearce wrote:

> This change adds a test for trying to create a ref within a directory
> that is actually currently a file, and adds error printing within
> the ref locking routine should the resolve operation fail.

Why not just print an error message when the resolve operation fails, 
instead of special casing this obscure corner case? It is way shorter, 
too. The test should stay, though.

Ciao,
Dscho

^ permalink raw reply

* [PATCH] Cumulative update of merge-recursive in C
From: Johannes Schindelin @ 2006-07-27 11:17 UTC (permalink / raw)
  To: git, junkio


This contains mainly three sorts of fixes:

- get rid of small wrapper functions
- reuse the diff_filespec structure when sha1, mode & path are needed
- Junio's pedantic updates

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

---

	Sorry for the big patch; it seemed to be tiny each
	time I committed.

 merge-recursive.c |  894 ++++++++++++++++++++++-------------------------------
 1 files changed, 366 insertions(+), 528 deletions(-)

diff --git a/merge-recursive.c b/merge-recursive.c
index 8d30519..85bb47a 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -25,9 +25,9 @@ #include "path-list.h"
 /*#define DEBUG*/
 
 #ifdef DEBUG
-#define debug(args, ...) fprintf(stderr, args, ## __VA_ARGS__)
+#define debug(...) fprintf(stderr, __VA_ARGS__)
 #else
-#define debug(args, ...)
+#define debug(...) do { ; /* nothing */ } while (0)
 #endif
 
 #ifdef DEBUG
@@ -61,13 +61,14 @@ static void show_ce_entry(const char *ta
 	fputc('\n', stderr);
 }
 
-static void ls_files() {
+static void ls_files(void) {
 	int i;
 	for (i = 0; i < active_nr; i++) {
 		struct cache_entry *ce = active_cache[i];
 		show_ce_entry("", ce);
 	}
 	fprintf(stderr, "---\n");
+	if (0) ls_files(); /* avoid "unused" warning */
 }
 #endif
 
@@ -76,41 +77,6 @@ #endif
  * - (const char *)commit->util set to the name, and
  * - *(int *)commit->object.sha1 set to the virtual id.
  */
-static const char *commit_title(struct commit *commit, int *len)
-{
-	const char *s = "(null commit)";
-	*len = strlen(s);
-
-	if ( commit->util ) {
-		s = commit->util;
-		*len = strlen(s);
-	} else {
-		if ( parse_commit(commit) != 0 ) {
-			s = "(bad commit)";
-			*len = strlen(s);
-		} else {
-			s = commit->buffer;
-			char prev = '\0';
-			while ( *s ) {
-				if ( '\n' == prev && '\n' == *s ) {
-					++s;
-					break;
-				}
-				prev = *s++;
-			}
-			*len = 0;
-			while ( s[*len] && '\n' != s[*len] )
-				++(*len);
-		}
-	}
-	return s;
-}
-
-static const char *commit_hex_sha1(const struct commit *commit)
-{
-	return commit->util ? "virtual" : commit ?
-		sha1_to_hex(commit->object.sha1) : "undefined";
-}
 
 static unsigned commit_list_count(const struct commit_list *l)
 {
@@ -136,41 +102,11 @@ static struct commit *make_virtual_commi
  */
 static int sha_eq(const unsigned char *a, const unsigned char *b)
 {
-	if ( !a && !b )
+	if (!a && !b)
 		return 2;
 	return a && b && memcmp(a, b, 20) == 0;
 }
 
-static void memswp(void *p1, void *p2, unsigned n)
-{
-	unsigned char *a = p1, *b = p2;
-	while ( n-- ) {
-		*a ^= *b;
-		*b ^= *a;
-		*a ^= *b;
-		++a;
-		++b;
-	}
-}
-
-/*
- * TODO: we should convert the merge_result users to
- * 	int blabla(..., struct commit **result)
- * like everywhere else in git.
- * Same goes for merge_tree_result and merge_file_info.
- */
-struct merge_result
-{
-	struct commit *commit;
-	unsigned clean:1;
-};
-
-struct merge_tree_result
-{
-	struct tree *tree;
-	unsigned clean:1;
-};
-
 /*
  * TODO: check if we can just reuse the active_cache structure: it is already
  * sorted (by name, stage).
@@ -195,7 +131,7 @@ static void output(const char *fmt, ...)
 {
 	va_list args;
 	int i;
-	for ( i = output_indent; i--; )
+	for (i = output_indent; i--;)
 		fputs("  ", stdout);
 	va_start(args, fmt);
 	vfprintf(stdout, fmt, args);
@@ -203,11 +139,37 @@ static void output(const char *fmt, ...)
 	fputc('\n', stdout);
 }
 
+static void output_commit_title(struct commit *commit)
+{
+	int i;
+	for (i = output_indent; i--;)
+		fputs("  ", stdout);
+	if (commit->util)
+		printf("virtual %s\n", (char *)commit->util);
+	else {
+		printf("%s ", sha1_to_hex(commit->object.sha1));
+		if (parse_commit(commit) != 0)
+			printf("(bad commit)\n");
+		else {
+			const char *s;
+			int len;
+			for (s = commit->buffer; *s; s++)
+				if (*s == '\n' && s[1] == '\n') {
+					s += 2;
+					break;
+				}
+			for (len = 0; s[len] && '\n' != s[len]; len++)
+				; /* do nothing */
+			printf("%.*s\n", len, s);
+		}
+	}
+}
+
 static const char *original_index_file;
 static const char *temporary_index_file;
 static int cache_dirty = 0;
 
-static int flush_cache()
+static int flush_cache(void)
 {
 	/* flush temporary index */
 	struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
@@ -290,11 +252,12 @@ #if 0
 		getenv("GIT_INDEX_FILE"),
 		sha1_to_hex(tree->object.sha1));
 #endif
+	int rc;
 	const char *argv[] = { "git-read-tree", NULL, NULL, };
 	if (cache_dirty)
 		die("read-tree with dirty cache");
 	argv[1] = sha1_to_hex(tree->object.sha1);
-	int rc = run_command_v(2, argv);
+	rc = run_command_v(2, argv);
 	return rc < 0 ? -1: rc;
 }
 
@@ -314,6 +277,7 @@ #if 0
 		sha1_to_hex(head->object.sha1),
 		sha1_to_hex(merge->object.sha1));
 #endif
+	int rc;
 	const char *argv[] = {
 		"git-read-tree", NULL, "-m", NULL, NULL, NULL,
 		NULL,
@@ -324,50 +288,42 @@ #endif
 	argv[3] = sha1_to_hex(common->object.sha1);
 	argv[4] = sha1_to_hex(head->object.sha1);
 	argv[5] = sha1_to_hex(merge->object.sha1);
-	int rc = run_command_v(6, argv);
+	rc = run_command_v(6, argv);
 	return rc < 0 ? -1: rc;
 }
 
 /*
  * TODO: this can be streamlined by refactoring builtin-write-tree.c
  */
-static struct tree *git_write_tree()
+static struct tree *git_write_tree(void)
 {
 #if 0
 	fprintf(stderr, "GIT_INDEX_FILE='%s' git-write-tree\n",
 		getenv("GIT_INDEX_FILE"));
 #endif
-	if (cache_dirty)
-		flush_cache();
-	FILE *fp = popen("git-write-tree 2>/dev/null", "r");
+	FILE *fp;
+	int rc;
 	char buf[41];
 	unsigned char sha1[20];
 	int ch;
 	unsigned i = 0;
-	while ( (ch = fgetc(fp)) != EOF )
-		if ( i < sizeof(buf)-1 && ch >= '0' && ch <= 'f' )
+	if (cache_dirty)
+		flush_cache();
+	fp = popen("git-write-tree 2>/dev/null", "r");
+	while ((ch = fgetc(fp)) != EOF)
+		if (i < sizeof(buf)-1 && ch >= '0' && ch <= 'f')
 			buf[i++] = ch;
 		else
 			break;
-	int rc = pclose(fp);
-	if ( rc == -1 || WEXITSTATUS(rc) )
+	rc = pclose(fp);
+	if (rc == -1 || WEXITSTATUS(rc))
 		return NULL;
 	buf[i] = '\0';
-	if ( get_sha1(buf, sha1) != 0 )
+	if (get_sha1(buf, sha1) != 0)
 		return NULL;
 	return lookup_tree(sha1);
 }
 
-/*
- * TODO: get rid of files_and_dirs; we do not use it except for
- * current_file_set and current_dir_set, which are global already.
- */
-static struct
-{
-	struct path_list *files;
-	struct path_list *dirs;
-} files_and_dirs;
-
 static int save_files_dirs(const unsigned char *sha1,
 		const char *base, int baselen, const char *path,
 		unsigned int mode, int stage)
@@ -379,70 +335,36 @@ static int save_files_dirs(const unsigne
 	newpath[baselen + len] = '\0';
 
 	if (S_ISDIR(mode))
-		path_list_insert(newpath, files_and_dirs.dirs);
+		path_list_insert(newpath, &currentDirectorySet);
 	else
-		path_list_insert(newpath, files_and_dirs.files);
+		path_list_insert(newpath, &currentFileSet);
 	free(newpath);
 
 	return READ_TREE_RECURSIVE;
 }
 
-static int get_files_dirs(struct tree *tree,
-			  struct path_list *files,
-			  struct path_list *dirs)
+static int get_files_dirs(struct tree *tree)
 {
 	int n;
-	files_and_dirs.files = files;
-	files_and_dirs.dirs = dirs;
 	debug("get_files_dirs ...\n");
 	if (read_tree_recursive(tree, "", 0, 0, NULL, save_files_dirs) != 0) {
 		debug("  get_files_dirs done (0)\n");
 		return 0;
 	}
-	n = files->nr + dirs->nr;
+	n = currentFileSet.nr + currentDirectorySet.nr;
 	debug("  get_files_dirs done (%d)\n", n);
 	return n;
 }
 
 /*
- * TODO: this wrapper is so small, we can use path_list_lookup directly.
- * Same goes for index_entry_get(), free_index_entries(), find_rename_bysrc(),
- * free_rename_entries().
- */
-static struct stage_data *index_entry_find(struct path_list *ents,
-					    const char *path)
-{
-	struct path_list_item *item = path_list_lookup(path, ents);
-	if (item)
-		return item->util;
-	return NULL;
-}
-
-static struct stage_data *index_entry_get(struct path_list *ents,
-					   const char *path)
-{
-	struct path_list_item *item = path_list_lookup(path, ents);
-
-	if (item == NULL) {
-		item = path_list_insert(path, ents);
-		item->util = xcalloc(1, sizeof(struct stage_data));
-	}
-	return item->util;
-}
-
-/*
- * TODO: since the result of index_entry_from_db() is tucked into a
- * path_list anyway, this helper can do that already.
- */
-/*
  * Returns a index_entry instance which doesn't have to correspond to
  * a real cache entry in Git's index.
  */
-static struct stage_data *index_entry_from_db(const char *path,
-					       struct tree *o,
-					       struct tree *a,
-					       struct tree *b)
+static struct stage_data *insert_stage_data(const char *path,
+		struct tree *o, struct tree *a, struct tree *b,
+		struct path_list *entries)
 {
+	struct path_list_item *item;
 	struct stage_data *e = xcalloc(1, sizeof(struct stage_data));
 	get_tree_entry(o->object.sha1, path,
 			e->stages[1].sha, &e->stages[1].mode);
@@ -450,24 +372,16 @@ static struct stage_data *index_entry_fr
 			e->stages[2].sha, &e->stages[2].mode);
 	get_tree_entry(b->object.sha1, path,
 			e->stages[3].sha, &e->stages[3].mode);
+	item = path_list_insert(path, entries);
+	item->util = e;
 	return e;
 }
 
-static void free_index_entries(struct path_list **ents)
-{
-	if (!*ents)
-		return;
-
-	path_list_clear(*ents, 1);
-	free(*ents);
-	*ents = NULL;
-}
-
 /*
  * Create a dictionary mapping file names to CacheEntry objects. The
  * dictionary contains one entry for every path with a non-zero stage entry.
  */
-static struct path_list *get_unmerged()
+static struct path_list *get_unmerged(void)
 {
 	struct path_list *unmerged = xcalloc(1, sizeof(struct path_list));
 	int i;
@@ -478,16 +392,22 @@ static struct path_list *get_unmerged()
 		cache_dirty++;
 	}
 	for (i = 0; i < active_nr; i++) {
+		struct path_list_item *item;
+		struct stage_data *e;
 		struct cache_entry *ce = active_cache[i];
 		if (!ce_stage(ce))
 			continue;
 
-		struct stage_data *e = index_entry_get(unmerged, ce->name);
+		item = path_list_lookup(ce->name, unmerged);
+		if (!item) {
+			item = path_list_insert(ce->name, unmerged);
+			item->util = xcalloc(1, sizeof(struct stage_data));
+		}
+		e = item->util;
 		e->stages[ce_stage(ce)].mode = ntohl(ce->ce_mode);
 		memcpy(e->stages[ce_stage(ce)].sha, ce->sha1, 20);
 	}
 
-	debug("  get_unmerged done\n");
 	return unmerged;
 }
 
@@ -499,25 +419,6 @@ struct rename
 	unsigned processed:1;
 };
 
-static struct rename *find_rename_bysrc(struct path_list *e,
-					      const char *name)
-{
-	struct path_list_item *item = path_list_lookup(name, e);
-	if (item)
-		return item->util;
-	return NULL;
-}
-
-static void free_rename_entries(struct path_list **list)
-{
-	if (!*list)
-		return;
-
-	path_list_clear(*list, 0);
-	free(*list);
-	*list = NULL;
-}
-
 /*
  * Get information of all renames which occured between 'oTree' and
  * 'tree'. We need the three trees in the merge ('oTree', 'aTree' and
@@ -530,13 +431,16 @@ static struct path_list *get_renames(str
 					struct tree *bTree,
 					struct path_list *entries)
 {
+	int i;
+	struct path_list *renames;
+	struct diff_options opts;
 #ifdef DEBUG
 	time_t t = time(0);
+
 	debug("getRenames ...\n");
 #endif
-	int i;
-	struct path_list *renames = xcalloc(1, sizeof(struct path_list));
-	struct diff_options opts;
+
+	renames = xcalloc(1, sizeof(struct path_list));
 	diff_setup(&opts);
 	opts.recursive = 1;
 	opts.detect_rename = DIFF_DETECT_RENAME;
@@ -546,6 +450,7 @@ #endif
 	diff_tree_sha1(oTree->object.sha1, tree->object.sha1, "", &opts);
 	diffcore_std(&opts);
 	for (i = 0; i < diff_queued_diff.nr; ++i) {
+		struct path_list_item *item;
 		struct rename *re;
 		struct diff_filepair *pair = diff_queued_diff.queue[i];
 		if (pair->status != 'R') {
@@ -555,78 +460,66 @@ #endif
 		re = xmalloc(sizeof(*re));
 		re->processed = 0;
 		re->pair = pair;
-		re->src_entry = index_entry_find(entries, re->pair->one->path);
-		/* TODO: should it not be an error, if src_entry was found? */
-		if ( !re->src_entry ) {
-			re->src_entry = index_entry_from_db(re->pair->one->path,
-					oTree, aTree, bTree);
-			struct path_list_item *item =
-				path_list_insert(re->pair->one->path, entries);
-			item->util = re->src_entry;
-		}
-		re->dst_entry = index_entry_find(entries, re->pair->two->path);
-		if ( !re->dst_entry ) {
-			re->dst_entry = index_entry_from_db(re->pair->two->path,
-					oTree, aTree, bTree);
-			struct path_list_item *item =
-				path_list_insert(re->pair->two->path, entries);
-			item->util = re->dst_entry;
-		}
-		struct path_list_item *item = path_list_insert(pair->one->path, renames);
+		item = path_list_lookup(re->pair->one->path, entries);
+		if (!item)
+			re->src_entry = insert_stage_data(re->pair->one->path,
+					oTree, aTree, bTree, entries);
+		else
+			re->src_entry = item->util;
+
+		item = path_list_lookup(re->pair->two->path, entries);
+		if (!item)
+			re->dst_entry = insert_stage_data(re->pair->two->path,
+					oTree, aTree, bTree, entries);
+		else
+			re->dst_entry = item->util;
+		item = path_list_insert(pair->one->path, renames);
 		item->util = re;
 	}
 	opts.output_format = DIFF_FORMAT_NO_OUTPUT;
 	diff_queued_diff.nr = 0;
 	diff_flush(&opts);
+#ifdef DEBUG
 	debug("  getRenames done in %ld\n", time(0)-t);
+#endif
 	return renames;
 }
 
-/*
- * TODO: the code would be way nicer, if we had a struct containing just sha1 and mode.
- * In this particular case, we might get away reusing stage_data, no?
- */
-int update_stages(const char *path,
-		   unsigned char *osha, unsigned omode,
-		   unsigned char *asha, unsigned amode,
-		   unsigned char *bsha, unsigned bmode,
-		   int clear /* =True */)
+int update_stages(const char *path, struct diff_filespec *o,
+		struct diff_filespec *a, struct diff_filespec *b, int clear)
 {
 	int options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE;
-	if ( clear )
-		if (add_cacheinfo(0, null_sha1, path, 0, 0, options))
+	if (clear) 
+		if (remove_file_from_cache(path))
 			return -1;
-	if ( omode )
-		if (add_cacheinfo(omode, osha, path, 1, 0, options))
+	if (o)
+		if (add_cacheinfo(o->mode, o->sha1, path, 1, 0, options))
 			return -1;
-	if ( amode )
-		if (add_cacheinfo(omode, osha, path, 2, 0, options))
+	if (a)
+		if (add_cacheinfo(a->mode, a->sha1, path, 2, 0, options))
 			return -1;
-	if ( bmode )
-		if (add_cacheinfo(omode, osha, path, 3, 0, options))
+	if (b)
+		if (add_cacheinfo(b->mode, b->sha1, path, 3, 0, options))
 			return -1;
 	return 0;
 }
 
-/*
- * TODO: there has to be a function in libgit doing this exact thing.
- */
 static int remove_path(const char *name)
 {
-	int ret;
-	char *slash;
+	int ret, len;
+	char *slash, *dirs;
 
 	ret = unlink(name);
-	if ( ret )
+	if (ret)
 		return ret;
-	int len = strlen(name);
-	char *dirs = malloc(len+1);
+	len = strlen(name);
+	dirs = malloc(len+1);
 	memcpy(dirs, name, len);
 	dirs[len] = '\0';
-	while ( (slash = strrchr(name, '/')) ) {
+	while ((slash = strrchr(name, '/'))) {
 		*slash = '\0';
 		len = slash - name;
-		if ( rmdir(name) != 0 )
+		if (rmdir(name) != 0)
 			break;
 	}
 	free(dirs);
@@ -636,7 +529,7 @@ static int remove_path(const char *name)
 /* General TODO: unC99ify the code: no declaration after code */
 /* General TODO: no javaIfiCation: rename updateCache to update_cache */
 /*
- * TODO: once we no longer call external programs, we'd probably be better of
+ * TODO: once we no longer call external programs, we'd probably be better off
  * not setting / getting the environment variable GIT_INDEX_FILE all the time.
  */
 int remove_file(int clean, const char *path)
@@ -644,17 +537,17 @@ int remove_file(int clean, const char *p
 	int updateCache = index_only || clean;
 	int updateWd = !index_only;
 
-	if ( updateCache ) {
+	if (updateCache) {
 		if (!cache_dirty)
 			read_cache_from(getenv("GIT_INDEX_FILE"));
 		cache_dirty++;
 		if (remove_file_from_cache(path))
 			return -1;
 	}
-	if ( updateWd )
+	if (updateWd)
 	{
 		unlink(path);
-		if ( errno != ENOENT || errno != EISDIR )
+		if (errno != ENOENT || errno != EISDIR)
 			return -1;
 		remove_path(path);
 	}
@@ -664,55 +557,31 @@ int remove_file(int clean, const char *p
 static char *unique_path(const char *path, const char *branch)
 {
 	char *newpath = xmalloc(strlen(path) + 1 + strlen(branch) + 8 + 1);
+	int suffix = 0;
+	struct stat st;
+	char *p = newpath + strlen(newpath);
 	strcpy(newpath, path);
 	strcat(newpath, "~");
-	char *p = newpath + strlen(newpath);
 	strcpy(p, branch);
-	for ( ; *p; ++p )
-		if ( '/' == *p )
+	for (; *p; ++p)
+		if ('/' == *p)
 			*p = '_';
-	int suffix = 0;
-	struct stat st;
-	while ( path_list_has_path(&currentFileSet, newpath) ||
-		path_list_has_path(&currentDirectorySet, newpath) ||
-		lstat(newpath, &st) == 0 ) {
+	while (path_list_has_path(&currentFileSet, newpath) ||
+	       path_list_has_path(&currentDirectorySet, newpath) ||
+	       lstat(newpath, &st) == 0)
 		sprintf(p, "_%d", suffix++);
-	}
+
 	path_list_insert(newpath, &currentFileSet);
 	return newpath;
 }
 
-/*
- * TODO: except for create_last, this so looks like
- * safe_create_leading_directories().
- */
-static int mkdir_p(const char *path, unsigned long mode, int create_last)
+static int mkdir_p(const char *path, unsigned long mode)
 {
+	/* path points to cache entries, so strdup before messing with it */
 	char *buf = strdup(path);
-	char *p;
-
-	for ( p = buf; *p; ++p ) {
-		if ( *p != '/' )
-			continue;
-		*p = '\0';
-		if (mkdir(buf, mode)) {
-			int e = errno;
-			if ( e == EEXIST ) {
-				struct stat st;
-				if ( !stat(buf, &st) && S_ISDIR(st.st_mode) )
-					goto next; /* ok */
-				errno = e;
-			}
-			free(buf);
-			return -1;
-		}
-	next:
-		*p = '/';
-	}
+	int result = safe_create_leading_directories(buf);
 	free(buf);
-	if ( create_last && mkdir(path, mode) )
-		return -1;
-	return 0;
+	return result;
 }
 
 static void flush_buffer(int fd, const char *buf, unsigned long size)
@@ -732,17 +601,16 @@ static void flush_buffer(int fd, const c
 	}
 }
 
-/* General TODO: reindent according to guide lines (no if ( blabla )) */
 void update_file_flags(const unsigned char *sha,
-		   unsigned mode,
-		   const char *path,
-		   int updateCache,
-		   int updateWd)
+		       unsigned mode,
+		       const char *path,
+		       int update_cache,
+		       int update_wd)
 {
-	if ( index_only )
-		updateWd = 0;
+	if (index_only)
+		update_wd = 0;
 
-	if ( updateWd ) {
+	if (update_wd) {
 		char type[20];
 		void *buf;
 		unsigned long size;
@@ -750,37 +618,38 @@ void update_file_flags(const unsigned ch
 		buf = read_sha1_file(sha, type, &size);
 		if (!buf)
 			die("cannot read object %s '%s'", sha1_to_hex(sha), path);
-		if ( strcmp(type, blob_type) != 0 )
+		if (strcmp(type, blob_type) != 0)
 			die("blob expected for %s '%s'", sha1_to_hex(sha), path);
 
-		if ( S_ISREG(mode) ) {
-			if ( mkdir_p(path, 0777, 0 /* don't create last element */) )
+		if (S_ISREG(mode)) {
+			int fd;
+			if (mkdir_p(path, 0777))
 				die("failed to create path %s: %s", path, strerror(errno));
 			unlink(path);
-			if ( mode & 0100 )
+			if (mode & 0100)
 				mode = 0777;
 			else
 				mode = 0666;
-			int fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
-			if ( fd < 0 )
+			fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
+			if (fd < 0)
 				die("failed to open %s: %s", path, strerror(errno));
 			flush_buffer(fd, buf, size);
 			close(fd);
-		} else if ( S_ISLNK(mode) ) {
-			char *linkTarget = malloc(size + 1);
-			memcpy(linkTarget, buf, size);
-			linkTarget[size] = '\0';
-			mkdir_p(path, 0777, 0);
-			symlink(linkTarget, path);
+		} else if (S_ISLNK(mode)) {
+			char *lnk = malloc(size + 1);
+			memcpy(lnk, buf, size);
+			lnk[size] = '\0';
+			mkdir_p(path, 0777);
+			unlink(lnk);
+			symlink(lnk, path);
 		} else
 			die("do not know what to do with %06o %s '%s'",
 			    mode, sha1_to_hex(sha), path);
 	}
-	if ( updateCache )
-		add_cacheinfo(mode, sha, path, 0, updateWd, ADD_CACHE_OK_TO_ADD);
+	if (update_cache)
+		add_cacheinfo(mode, sha, path, 0, update_wd, ADD_CACHE_OK_TO_ADD);
 }
 
-/* TODO: is this often used? if not, do direct call */
 void update_file(int clean,
 		const unsigned char *sha,
 		unsigned mode,
@@ -819,64 +688,53 @@ static char *git_unpack_file(const unsig
 	return path;
 }
 
-/*
- * TODO: the signature would be much more efficient using stage_data
- */
-static struct merge_file_info merge_file(const char *oPath,
-					 const unsigned char *oSha,
-					 unsigned oMode,
-					 const char *aPath,
-					 const unsigned char *aSha,
-					 unsigned aMode,
-					 const char *bPath,
-					 const unsigned char *bSha,
-					 unsigned bMode,
-					 const char *branch1Name,
-					 const char *branch2Name)
+static struct merge_file_info merge_file(struct diff_filespec *o,
+		struct diff_filespec *a, struct diff_filespec *b,
+		const char *branch1Name, const char *branch2Name)
 {
 	struct merge_file_info result;
 	result.merge = 0;
 	result.clean = 1;
 
-	if ( (S_IFMT & aMode) != (S_IFMT & bMode) ) {
+	if ((S_IFMT & a->mode) != (S_IFMT & b->mode)) {
 		result.clean = 0;
-		if ( S_ISREG(aMode) ) {
-			result.mode = aMode;
-			memcpy(result.sha, aSha, 20);
+		if (S_ISREG(a->mode)) {
+			result.mode = a->mode;
+			memcpy(result.sha, a->sha1, 20);
 		} else {
-			result.mode = bMode;
-			memcpy(result.sha, bSha, 20);
+			result.mode = b->mode;
+			memcpy(result.sha, b->sha1, 20);
 		}
 	} else {
-		if ( memcmp(aSha, oSha, 20) != 0 && memcmp(bSha, oSha, 20) != 0 )
+		if (!sha_eq(a->sha1, o->sha1) && !sha_eq(b->sha1, o->sha1))
 			result.merge = 1;
 
-		result.mode = aMode == oMode ? bMode: aMode;
-
-		if ( memcmp(aSha, oSha, 20) == 0 )
-			memcpy(result.sha, bSha, 20);
-		else if ( memcmp(bSha, oSha, 20) == 0 )
-			memcpy(result.sha, aSha, 20);
-		else if ( S_ISREG(aMode) ) {
+		result.mode = a->mode == o->mode ? b->mode: a->mode;
 
-			int code = 1;
+		if (sha_eq(a->sha1, o->sha1))
+			memcpy(result.sha, b->sha1, 20);
+		else if (sha_eq(b->sha1, o->sha1))
+			memcpy(result.sha, a->sha1, 20);
+		else if (S_ISREG(a->mode)) {
+			int code = 1, fd;
+			struct stat st;
 			char orig[PATH_MAX];
 			char src1[PATH_MAX];
 			char src2[PATH_MAX];
-
-			git_unpack_file(oSha, orig);
-			git_unpack_file(aSha, src1);
-			git_unpack_file(bSha, src2);
-
 			const char *argv[] = {
 				"merge", "-L", NULL, "-L", NULL, "-L", NULL,
 				src1, orig, src2,
 				NULL
 			};
 			char *la, *lb, *lo;
-			argv[2] = la = strdup(mkpath("%s/%s", branch1Name, aPath));
-			argv[6] = lb = strdup(mkpath("%s/%s", branch2Name, bPath));
-			argv[4] = lo = strdup(mkpath("orig/%s", oPath));
+
+			git_unpack_file(o->sha1, orig);
+			git_unpack_file(a->sha1, src1);
+			git_unpack_file(b->sha1, src2);
+
+			argv[2] = la = strdup(mkpath("%s/%s", branch1Name, a->path));
+			argv[6] = lb = strdup(mkpath("%s/%s", branch2Name, b->path));
+			argv[4] = lo = strdup(mkpath("orig/%s", o->path));
 
 #if 0
 			printf("%s %s %s %s %s %s %s %s %s %s\n",
@@ -888,17 +746,15 @@ #endif
 			free(la);
 			free(lb);
 			free(lo);
-			if ( code && code < -256 ) {
+			if (code && code < -256) {
 				die("Failed to execute 'merge'. merge(1) is used as the "
 				    "file-level merge tool. Is 'merge' in your path?");
 			}
-			struct stat st;
-			int fd = open(src1, O_RDONLY);
+			fd = open(src1, O_RDONLY);
 			if (fd < 0 || fstat(fd, &st) < 0 ||
 					index_fd(result.sha, fd, &st, 1,
 						"blob"))
 				die("Unable to add %s to database", src1);
-			close(fd);
 
 			unlink(orig);
 			unlink(src1);
@@ -906,12 +762,12 @@ #endif
 
 			result.clean = WEXITSTATUS(code) == 0;
 		} else {
-			if ( !(S_ISLNK(aMode) || S_ISLNK(bMode)) )
+			if (!(S_ISLNK(a->mode) || S_ISLNK(b->mode)))
 				die("cannot merge modes?");
 
-			memcpy(result.sha, aSha, 20);
+			memcpy(result.sha, a->sha1, 20);
 
-			if ( memcmp(aSha, bSha, 20) != 0 )
+			if (!sha_eq(a->sha1, b->sha1))
 				result.clean = 0;
 		}
 	}
@@ -942,17 +798,9 @@ static void conflict_rename_rename(struc
 		       ren2_dst, branch1, dstName2);
 		remove_file(0, ren2_dst);
 	}
-	update_stages(dstName1,
-		      NULL, 0,
-		      ren1->pair->two->sha1, ren1->pair->two->mode,
-		      NULL, 0,
-		      1 /* clear */);
-	update_stages(dstName2,
-		      NULL, 0,
-		      NULL, 0,
-		      ren2->pair->two->sha1, ren2->pair->two->mode,
-		      1 /* clear */);
-	while ( delp-- )
+	update_stages(dstName1, NULL, ren1->pair->two, NULL, 1);
+	update_stages(dstName2, NULL, NULL, ren2->pair->two, 1);
+	while (delp--)
 		free(del[delp]);
 }
 
@@ -989,66 +837,73 @@ static int process_renames(struct path_l
 			   const char *branchNameA,
 			   const char *branchNameB)
 {
-	int cleanMerge = 1, i;
-	struct path_list srcNames = {NULL, 0, 0, 0}, byDstA = {NULL, 0, 0, 0}, byDstB = {NULL, 0, 0, 0};
+	int cleanMerge = 1, i, j;
+	struct path_list byDstA = {NULL, 0, 0, 0}, byDstB = {NULL, 0, 0, 0};
 	const struct rename *sre;
 
-	/*
-	 * TODO: think about a saner way to do this.
-	 * Since both renamesA and renamesB are sorted, it should
-	 * be much more efficient to traverse both simultaneously,
-	 * only byDstA and byDstB should be needed.
-	 */
-	debug("processRenames...\n");
 	for (i = 0; i < renamesA->nr; i++) {
 		sre = renamesA->items[i].util;
-		path_list_insert(sre->pair->one->path, &srcNames);
 		path_list_insert(sre->pair->two->path, &byDstA)->util
 			= sre->dst_entry;
 	}
 	for (i = 0; i < renamesB->nr; i++) {
 		sre = renamesB->items[i].util;
-		path_list_insert(sre->pair->one->path, &srcNames);
 		path_list_insert(sre->pair->two->path, &byDstB)->util
 			= sre->dst_entry;
 	}
 
-	for (i = 0; i < srcNames.nr; i++) {
-		char *src = srcNames.items[i].path;
+	for (i = 0, j = 0; i < renamesA->nr || j < renamesB->nr;) {
+		int compare;
+		char *src;
 		struct path_list *renames1, *renames2, *renames2Dst;
-		struct rename *ren1, *ren2;
+		struct rename *ren1 = NULL, *ren2 = NULL;
 		const char *branchName1, *branchName2;
-		ren1 = find_rename_bysrc(renamesA, src);
-		ren2 = find_rename_bysrc(renamesB, src);
+		const char *ren1_src, *ren1_dst;
+
+		if (i >= renamesA->nr) {
+			compare = 1;
+			ren2 = renamesB->items[j++].util;
+		} else if (j >= renamesB->nr) {
+			compare = -1;
+			ren1 = renamesA->items[i++].util;
+		} else {
+			compare = strcmp(renamesA->items[i].path,
+					renamesB->items[j].path);
+			ren1 = renamesA->items[i++].util;
+			ren2 = renamesB->items[j++].util;
+		}
+
 		/* TODO: refactor, so that 1/2 are not needed */
-		if ( ren1 ) {
+		if (ren1) {
 			renames1 = renamesA;
 			renames2 = renamesB;
 			renames2Dst = &byDstB;
 			branchName1 = branchNameA;
 			branchName2 = branchNameB;
 		} else {
+			struct rename *tmp;
 			renames1 = renamesB;
 			renames2 = renamesA;
 			renames2Dst = &byDstA;
 			branchName1 = branchNameB;
 			branchName2 = branchNameA;
-			struct rename *tmp = ren2;
+			tmp = ren2;
 			ren2 = ren1;
 			ren1 = tmp;
 		}
+		src = ren1->pair->one->path;
 
 		ren1->dst_entry->processed = 1;
 		ren1->src_entry->processed = 1;
 
-		if ( ren1->processed )
+		if (ren1->processed)
 			continue;
 		ren1->processed = 1;
 
-		const char *ren1_src = ren1->pair->one->path;
-		const char *ren1_dst = ren1->pair->two->path;
+		ren1_src = ren1->pair->one->path;
+		ren1_dst = ren1->pair->two->path;
 
-		if ( ren2 ) {
+		if (ren2) {
 			const char *ren2_src = ren2->pair->one->path;
 			const char *ren2_dst = ren2->pair->two->path;
 			/* Renamed in 1 and renamed in 2 */
@@ -1067,57 +922,48 @@ static int process_renames(struct path_l
 			} else {
 				remove_file(1, ren1_src);
 				struct merge_file_info mfi;
-				mfi = merge_file(ren1_src,
-						 ren1->pair->one->sha1,
-						 ren1->pair->one->mode,
-						 ren1_dst,
-						 ren1->pair->two->sha1,
-						 ren1->pair->two->mode,
-						 ren2_dst,
-						 ren2->pair->two->sha1,
-						 ren2->pair->two->mode,
+				mfi = merge_file(ren1->pair->one,
+						 ren1->pair->two,
+						 ren2->pair->two,
 						 branchName1,
 						 branchName2);
-				if ( mfi.merge || !mfi.clean )
+				if (mfi.merge || !mfi.clean)
 					output("Renaming %s->%s", src, ren1_dst);
 
-				if ( mfi.merge )
+				if (mfi.merge)
 					output("Auto-merging %s", ren1_dst);
 
-				if ( !mfi.clean ) {
+				if (!mfi.clean) {
 					output("CONFLICT (content): merge conflict in %s",
 					       ren1_dst);
 					cleanMerge = 0;
 
-					if ( !index_only )
+					if (!index_only)
 						update_stages(ren1_dst,
-							      ren1->pair->one->sha1,
-							      ren1->pair->one->mode,
-							      ren1->pair->two->sha1,
-							      ren1->pair->two->mode,
-							      ren2->pair->two->sha1,
-							      ren2->pair->two->mode,
+							      ren1->pair->one,
+							      ren1->pair->two,
+							      ren2->pair->two,
 							      1 /* clear */);
 				}
 				update_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst);
 			}
 		} else {
 			/* Renamed in 1, maybe changed in 2 */
-			remove_file(1, ren1_src);
-
-			unsigned char srcShaOtherBranch[20], dstShaOtherBranch[20];
-			unsigned srcModeOtherBranch, dstModeOtherBranch;
-
-			int stage = renamesA == renames1 ? 3: 2;
+			struct path_list_item *item;
+			/* we only use sha1 and mode of these */
+			struct diff_filespec src_other, dst_other;
+			int tryMerge, stage = renamesA == renames1 ? 3: 2;
 
-			memcpy(srcShaOtherBranch, ren1->src_entry->stages[stage].sha, 20);
-			srcModeOtherBranch = ren1->src_entry->stages[stage].mode;
+			remove_file(1, ren1_src);
 
-			memcpy(dstShaOtherBranch, ren1->dst_entry->stages[stage].sha, 20);
-			dstModeOtherBranch = ren1->dst_entry->stages[stage].mode;
+			memcpy(src_other.sha1,
+					ren1->src_entry->stages[stage].sha, 20);
+			src_other.mode = ren1->src_entry->stages[stage].mode;
+			memcpy(dst_other.sha1,
+					ren1->dst_entry->stages[stage].sha, 20);
+			dst_other.mode = ren1->dst_entry->stages[stage].mode;
 
-			int tryMerge = 0;
-			char *newPath;
+			tryMerge = 0;
 
 			if (path_list_has_path(&currentDirectorySet, ren1_dst)) {
 				cleanMerge = 0;
@@ -1126,14 +972,15 @@ static int process_renames(struct path_l
 				       ren1_src, ren1_dst, branchName1,
 				       ren1_dst, branchName2);
 				conflict_rename_dir(ren1, branchName1);
-			} else if ( memcmp(srcShaOtherBranch, null_sha1, 20) == 0 ) {
+			} else if (sha_eq(src_other.sha1, null_sha1)) {
 				cleanMerge = 0;
 				output("CONFLICT (rename/delete): Rename %s->%s in %s "
 				       "and deleted in %s",
 				       ren1_src, ren1_dst, branchName1,
 				       branchName2);
 				update_file(0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst);
-			} else if ( memcmp(dstShaOtherBranch, null_sha1, 20) != 0 ) {
+			} else if (!sha_eq(dst_other.sha1, null_sha1)) {
+				const char *newPath;
 				cleanMerge = 0;
 				tryMerge = 1;
 				output("CONFLICT (rename/add): Rename %s->%s in %s. "
@@ -1142,8 +989,9 @@ static int process_renames(struct path_l
 				       ren1_dst, branchName2);
 				newPath = unique_path(ren1_dst, branchName2);
 				output("Adding as %s instead", newPath);
-				update_file(0, dstShaOtherBranch, dstModeOtherBranch, newPath);
-			} else if ( (ren2 = find_rename_bysrc(renames2Dst, ren1_dst)) ) {
+				update_file(0, dst_other.sha1, dst_other.mode, newPath);
+			} else if ((item = path_list_lookup(ren1_dst, renames2Dst))) {
+				ren2 = item->util;
 				cleanMerge = 0;
 				ren2->processed = 1;
 				output("CONFLICT (rename/rename): Rename %s->%s in %s. "
@@ -1154,53 +1002,41 @@ static int process_renames(struct path_l
 			} else
 				tryMerge = 1;
 
-			if ( tryMerge ) {
-				const char *oname = ren1_src;
-				const char *aname = ren1_dst;
-				const char *bname = ren1_src;
-				unsigned char osha[20], asha[20], bsha[20];
-				unsigned omode = ren1->pair->one->mode;
-				unsigned amode = ren1->pair->two->mode;
-				unsigned bmode = srcModeOtherBranch;
-				memcpy(osha, ren1->pair->one->sha1, 20);
-				memcpy(asha, ren1->pair->two->sha1, 20);
-				memcpy(bsha, srcShaOtherBranch, 20);
-				const char *aBranch = branchName1;
-				const char *bBranch = branchName2;
-
-				if ( renamesA != renames1 ) {
-					memswp(&aname, &bname, sizeof(aname));
-					memswp(asha, bsha, 20);
-					memswp(&aBranch, &bBranch, sizeof(aBranch));
-				}
+			if (tryMerge) {
+				struct diff_filespec *o, *a, *b;
 				struct merge_file_info mfi;
-				mfi = merge_file(oname, osha, omode,
-						 aname, asha, amode,
-						 bname, bsha, bmode,
-						 aBranch, bBranch);
+				src_other.path = (char *)ren1_src;
+
+				o = ren1->pair->one;
+				if (renamesA == renames1) {
+					a = ren1->pair->two;
+					b = &src_other;
+				} else {
+					b = ren1->pair->two;
+					a = &src_other;
+				}
+				mfi = merge_file(o, a, b,
+						branchNameA, branchNameB);
 
-				if ( mfi.merge || !mfi.clean )
+				if (mfi.merge || !mfi.clean)
 					output("Renaming %s => %s", ren1_src, ren1_dst);
-				if ( mfi.merge )
+				if (mfi.merge)
 					output("Auto-merging %s", ren1_dst);
-				if ( !mfi.clean ) {
+				if (!mfi.clean) {
 					output("CONFLICT (rename/modify): Merge conflict in %s",
 					       ren1_dst);
 					cleanMerge = 0;
 
-					if ( !index_only )
+					if (!index_only)
 						update_stages(ren1_dst,
-							      osha, omode,
-							      asha, amode,
-							      bsha, bmode,
-							      1 /* clear */);
+								o, a, b, 1);
 				}
 				update_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst);
 			}
 		}
 	}
-	path_list_clear(&srcNames, 0);
-	debug("  processRenames done\n");
+	path_list_clear(&byDstA, 0);
+	path_list_clear(&byDstB, 0);
 
 	if (cache_dirty)
 		flush_cache();
@@ -1229,20 +1065,20 @@ static int process_entry(const char *pat
 	unsigned aMode = entry->stages[2].mode;
 	unsigned bMode = entry->stages[3].mode;
 
-	if ( oSha && (!aSha || !bSha) ) {
+	if (oSha && (!aSha || !bSha)) {
 		/* Case A: Deleted in one */
-		if ( (!aSha && !bSha) ||
-		     (sha_eq(aSha, oSha) && !bSha) ||
-		     (!aSha && sha_eq(bSha, oSha)) ) {
+		if ((!aSha && !bSha) ||
+		    (sha_eq(aSha, oSha) && !bSha) ||
+		    (!aSha && sha_eq(bSha, oSha))) {
 			/* Deleted in both or deleted in one and
 			 * unchanged in the other */
-			if ( aSha )
+			if (aSha)
 				output("Removing %s", path);
 			remove_file(1, path);
 		} else {
 			/* Deleted in one and changed in the other */
 			cleanMerge = 0;
-			if ( !aSha ) {
+			if (!aSha) {
 				output("CONFLICT (delete/modify): %s deleted in %s "
 				       "and modified in %s. Version %s of %s left in tree.",
 				       path, branch1Name,
@@ -1257,8 +1093,8 @@ static int process_entry(const char *pat
 			}
 		}
 
-	} else if ( (!oSha && aSha && !bSha) ||
-		    (!oSha && !aSha && bSha) ) {
+	} else if ((!oSha && aSha && !bSha) ||
+		   (!oSha && !aSha && bSha)) {
 		/* Case B: Added in one. */
 		const char *addBranch;
 		const char *otherBranch;
@@ -1266,7 +1102,7 @@ static int process_entry(const char *pat
 		const unsigned char *sha;
 		const char *conf;
 
-		if ( aSha ) {
+		if (aSha) {
 			addBranch = branch1Name;
 			otherBranch = branch2Name;
 			mode = aMode;
@@ -1279,9 +1115,9 @@ static int process_entry(const char *pat
 			sha = bSha;
 			conf = "directory/file";
 		}
-		if ( path_list_has_path(&currentDirectorySet, path) ) {
-			cleanMerge = 0;
+		if (path_list_has_path(&currentDirectorySet, path)) {
 			const char *newPath = unique_path(path, addBranch);
+			cleanMerge = 0;
 			output("CONFLICT (%s): There is a directory with name %s in %s. "
 			       "Adding %s as %s",
 			       conf, path, otherBranch, path, newPath);
@@ -1291,10 +1127,10 @@ static int process_entry(const char *pat
 			output("Adding %s", path);
 			update_file(1, sha, mode, path);
 		}
-	} else if ( !oSha && aSha && bSha ) {
+	} else if (!oSha && aSha && bSha) {
 		/* Case C: Added in both (check for same permissions). */
-		if ( sha_eq(aSha, bSha) ) {
-			if ( aMode != bMode ) {
+		if (sha_eq(aSha, bSha)) {
+			if (aMode != bMode) {
 				cleanMerge = 0;
 				output("CONFLICT: File %s added identically in both branches, "
 				       "but permissions conflict %06o->%06o",
@@ -1306,9 +1142,10 @@ static int process_entry(const char *pat
 				assert(0 && "This case must be handled by git-read-tree");
 			}
 		} else {
+			const char *newPath1, *newPath2;
 			cleanMerge = 0;
-			const char *newPath1 = unique_path(path, branch1Name);
-			const char *newPath2 = unique_path(path, branch2Name);
+			newPath1 = unique_path(path, branch1Name);
+			newPath2 = unique_path(path, branch2Name);
 			output("CONFLICT (add/add): File %s added non-identically "
 			       "in both branches. Adding as %s and %s instead.",
 			       path, newPath1, newPath2);
@@ -1317,22 +1154,30 @@ static int process_entry(const char *pat
 			update_file(0, bSha, bMode, newPath2);
 		}
 
-	} else if ( oSha && aSha && bSha ) {
+	} else if (oSha && aSha && bSha) {
 		/* case D: Modified in both, but differently. */
-		output("Auto-merging %s", path);
 		struct merge_file_info mfi;
-		mfi = merge_file(path, oSha, oMode,
-				 path, aSha, aMode,
-				 path, bSha, bMode,
+		struct diff_filespec o, a, b;
+
+		output("Auto-merging %s", path);
+		o.path = a.path = b.path = (char *)path;
+		memcpy(o.sha1, oSha, 20);
+		o.mode = oMode;
+		memcpy(a.sha1, aSha, 20);
+		a.mode = aMode;
+		memcpy(b.sha1, bSha, 20);
+		b.mode = bMode;
+		
+		mfi = merge_file(&o, &a, &b,
 				 branch1Name, branch2Name);
 
-		if ( mfi.clean )
+		if (mfi.clean)
 			update_file(1, mfi.sha, mfi.mode, path);
 		else {
 			cleanMerge = 0;
 			output("CONFLICT (content): Merge conflict in %s", path);
 
-			if ( index_only )
+			if (index_only)
 				update_file(0, mfi.sha, mfi.mode, path);
 			else
 				update_file_flags(mfi.sha, mfi.mode, path,
@@ -1347,73 +1192,68 @@ static int process_entry(const char *pat
 	return cleanMerge;
 }
 
-static struct merge_tree_result merge_trees(struct tree *head,
-					    struct tree *merge,
-					    struct tree *common,
-					    const char *branch1Name,
-					    const char *branch2Name)
+static int merge_trees(struct tree *head,
+		       struct tree *merge,
+		       struct tree *common,
+		       const char *branch1Name,
+		       const char *branch2Name,
+		       struct tree **result)
 {
-	int code;
-	struct merge_tree_result result = { NULL, 0 };
-	if ( !memcmp(common->object.sha1, merge->object.sha1, 20) ) {
+	int code, clean;
+	if (sha_eq(common->object.sha1, merge->object.sha1)) {
 		output("Already uptodate!");
-		result.tree = head;
-		result.clean = 1;
-		return result;
+		*result = head;
+		return 1;
 	}
 
-	debug("merge_trees ...\n");
 	code = git_merge_trees(index_only ? "-i": "-u", common, head, merge);
 
-	if ( code != 0 )
+	if (code != 0)
 		die("merging of trees %s and %s failed",
 		    sha1_to_hex(head->object.sha1),
 		    sha1_to_hex(merge->object.sha1));
 
-	result.tree = git_write_tree();
+	*result = git_write_tree();
 
-	if ( !result.tree ) {
+	if (!*result) {
+		struct path_list *entries, *re_head, *re_merge;
+		int i;
 		path_list_clear(&currentFileSet, 1);
 		path_list_clear(&currentDirectorySet, 1);
-		get_files_dirs(head, &currentFileSet, &currentDirectorySet);
-		get_files_dirs(merge, &currentFileSet, &currentDirectorySet);
+		get_files_dirs(head);
+		get_files_dirs(merge);
 
-		struct path_list *entries = get_unmerged();
-		struct path_list *re_head, *re_merge;
+		entries = get_unmerged();
 		re_head  = get_renames(head, common, head, merge, entries);
 		re_merge = get_renames(merge, common, head, merge, entries);
-		result.clean = process_renames(re_head, re_merge,
-					       branch1Name, branch2Name);
-		debug("\tprocessing entries...\n");
-		int i;
+		clean = process_renames(re_head, re_merge,
+				branch1Name, branch2Name);
 		for (i = 0; i < entries->nr; i++) {
 			const char *path = entries->items[i].path;
 			struct stage_data *e = entries->items[i].util;
 			if (e->processed)
 				continue;
 			if (!process_entry(path, e, branch1Name, branch2Name))
-				result.clean = 0;
+				clean = 0;
 		}
 
-		free_rename_entries(&re_merge);
-		free_rename_entries(&re_head);
-		free_index_entries(&entries);
+		path_list_clear(re_merge, 0);
+		path_list_clear(re_head, 0);
+		path_list_clear(entries, 1);
 
-		if (result.clean || index_only)
-			result.tree = git_write_tree();
+		if (clean || index_only)
+			*result = git_write_tree();
 		else
-			result.tree = NULL;
-		debug("\t  processing entries done\n");
+			*result = NULL;
 	} else {
-		result.clean = 1;
+		clean = 1;
 		printf("merging of trees %s and %s resulted in %s\n",
 		       sha1_to_hex(head->object.sha1),
 		       sha1_to_hex(merge->object.sha1),
-		       sha1_to_hex(result.tree->object.sha1));
+		       sha1_to_hex((*result)->object.sha1));
 	}
 
-	debug("  merge_trees done\n");
-	return result;
+	return clean;
 }
 
 /*
@@ -1421,87 +1261,86 @@ static struct merge_tree_result merge_tr
  * commit object and a flag indicating the cleaness of the merge.
  */
 static
-struct merge_result merge(struct commit *h1,
+int merge(struct commit *h1,
 			  struct commit *h2,
 			  const char *branch1Name,
 			  const char *branch2Name,
 			  int callDepth /* =0 */,
-			  struct commit *ancestor /* =None */)
+			  struct commit *ancestor /* =None */,
+			  struct commit **result)
 {
-	struct merge_result result = { NULL, 0 };
-	const char *msg;
-	int msglen;
 	struct commit_list *ca = NULL, *iter;
 	struct commit *mergedCA;
-	struct merge_tree_result mtr;
+	struct tree *mrtree;
+	int clean;
 
 	output("Merging:");
-	msg = commit_title(h1, &msglen);
-	/* TODO: refactor. we always show the sha1 with the title */
-	output("%s %.*s", commit_hex_sha1(h1), msglen, msg);
-	msg = commit_title(h2, &msglen);
-	output("%s %.*s", commit_hex_sha1(h2), msglen, msg);
+	output_commit_title(h1);
+	output_commit_title(h2);
 
-	if ( ancestor )
+	if (ancestor)
 		commit_list_insert(ancestor, &ca);
 	else
 		ca = get_merge_bases(h1, h2, 1);
 
 	output("found %u common ancestor(s):", commit_list_count(ca));
-	for (iter = ca; iter; iter = iter->next) {
-		msg = commit_title(iter->item, &msglen);
-		output("%s %.*s", commit_hex_sha1(iter->item), msglen, msg);
-	}
+	for (iter = ca; iter; iter = iter->next)
+		output_commit_title(iter->item);
 
 	mergedCA = pop_commit(&ca);
 
-	/* TODO: what happens when merge with virtual commits fails? */
 	for (iter = ca; iter; iter = iter->next) {
 		output_indent = callDepth + 1;
-		result = merge(mergedCA, iter->item,
-			       "Temporary merge branch 1",
-			       "Temporary merge branch 2",
-			       callDepth + 1,
-			       NULL);
-		mergedCA = result.commit;
+		/*
+		 * When the merge fails, the result contains files
+		 * with conflict markers. The cleanness flag is
+		 * ignored, it was never acutally used, as result of
+		 * merge_trees has always overwritten it: the commited
+		 * "conflicts" were already resolved. 
+		 */
+		merge(mergedCA, iter->item,
+		      "Temporary merge branch 1",
+		      "Temporary merge branch 2",
+		      callDepth + 1,
+		      NULL,
+		      &mergedCA);
 		output_indent = callDepth;
 
-		if ( !mergedCA )
+		if (!mergedCA)
 			die("merge returned no commit");
 	}
 
-	if ( callDepth == 0 ) {
-		setup_index(0);
+	if (callDepth == 0) {
+		setup_index(0 /* $GIT_DIR/index */);
 		index_only = 0;
 	} else {
-		setup_index(1);
+		setup_index(1 /* temporary index */);
 		git_read_tree(h1->tree);
 		index_only = 1;
 	}
 
-	mtr = merge_trees(h1->tree, h2->tree,
-			  mergedCA->tree, branch1Name, branch2Name);
+	clean = merge_trees(h1->tree, h2->tree, mergedCA->tree,
+			    branch1Name, branch2Name, &mrtree);
 
-	if ( !ancestor && (mtr.clean || index_only) ) {
-		result.commit = make_virtual_commit(mtr.tree, "merged tree");
-		commit_list_insert(h1, &result.commit->parents);
-		commit_list_insert(h2, &result.commit->parents->next);
+	if (!ancestor && (clean || index_only)) {
+		*result = make_virtual_commit(mrtree, "merged tree");
+		commit_list_insert(h1, &(*result)->parents);
+		commit_list_insert(h2, &(*result)->parents->next);
 	} else
-		result.commit = NULL;
+		*result = NULL;
 
-	result.clean = mtr.clean;
-	return result;
+	return clean;
 }
 
 static struct commit *get_ref(const char *ref)
 {
 	unsigned char sha1[20];
 	struct object *object;
-
+	
 	if (get_sha1(ref, sha1))
 		die("Could not resolve ref '%s'", ref);
 	object = deref_tag(parse_object(sha1), ref, strlen(ref));
-	if (object->type != OBJ_COMMIT)
+	if (object->type != TYPE_COMMIT)
 		return NULL;
 	if (parse_commit((struct commit *)object))
 		die("Could not parse commit '%s'", sha1_to_hex(object->sha1));
@@ -1512,6 +1351,9 @@ int main(int argc, char *argv[])
 {
 	static const char *bases[2];
 	static unsigned bases_count = 0;
+	int i, clean;
+	const char *branch1, *branch2;
+	struct commit *result, *h1, *h2;
 
 	original_index_file = getenv("GIT_INDEX_FILE");
 
@@ -1523,7 +1365,6 @@ int main(int argc, char *argv[])
 	if (argc < 4)
 		die("Usage: %s <base>... -- <head> <remote> ...\n", argv[0]);
 
-	int i;
 	for (i = 1; i < argc; ++i) {
 		if (!strcmp(argv[i], "--"))
 			break;
@@ -1533,26 +1374,23 @@ int main(int argc, char *argv[])
 	if (argc - i != 3) /* "--" "<head>" "<remote>" */
 		die("Not handling anything other than two heads merge.");
 
-	const char *branch1, *branch2;
-
 	branch1 = argv[++i];
 	branch2 = argv[++i];
 	printf("Merging %s with %s\n", branch1, branch2);
 
-	struct merge_result result;
-	struct commit *h1 = get_ref(branch1);
-	struct commit *h2 = get_ref(branch2);
+	h1 = get_ref(branch1);
+	h2 = get_ref(branch2);
 
 	if (bases_count == 1) {
 		struct commit *ancestor = get_ref(bases[0]);
-		result = merge(h1, h2, branch1, branch2, 0, ancestor);
+		clean = merge(h1, h2, branch1, branch2, 0, ancestor, &result);
 	} else
-		result = merge(h1, h2, branch1, branch2, 0, NULL);
+		clean = merge(h1, h2, branch1, branch2, 0, NULL, &result);
 
 	if (cache_dirty)
 		flush_cache();
 
-	return result.clean ? 0: 1;
+	return clean ? 0: 1;
 }
 
 /*

^ permalink raw reply related

* Re: Licensing and the library version of git
From: Petr Baudis @ 2006-07-27 11:41 UTC (permalink / raw)
  To: Jon Smirl; +Cc: git
In-Reply-To: <9e4733910607261436v4c0802e5v7301e904593f9bab@mail.gmail.com>

Dear diary, on Wed, Jul 26, 2006 at 11:36:16PM CEST, I got a letter
where Jon Smirl <jonsmirl@gmail.com> said that...
> Can the library version of git be licensed LGPL instead of GPL? If it
> is GPL then it can't be linked into non-GPL projects like Eclipse.

Probably not since it essentially _is_ the base Git code now. You would
need to find all the Git copyright holders and convince them to
relicence it, since there are thoughts about moving more code to the
library, and even parts of scripts might eventually end up there after
rewrite in C.

And I didn't even get to discussing whether LGPL is actually desirable
for Git.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Snow falling on Perl. White noise covering line noise.
Hides all the bugs too. -- J. Putnam

^ permalink raw reply

* Re: Licensing and the library version of git
From: Johannes Schindelin @ 2006-07-27 12:02 UTC (permalink / raw)
  To: Petr Baudis; +Cc: Jon Smirl, git
In-Reply-To: <20060727114105.GZ13776@pasky.or.cz>

Hi,

On Thu, 27 Jul 2006, Petr Baudis wrote:

> And I didn't even get to discussing whether LGPL is actually desirable
> for Git.

... or whether it is neccessary for an Eclipse-plugin to something else 
than GPL.

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH] Per branch properties for pull and fetch
From: Martin Waitz @ 2006-07-27 12:02 UTC (permalink / raw)
  To: Santi; +Cc: Git Mailing List
In-Reply-To: <8aa486160607270306s3f49a01cq91ef61e2c9f005e@mail.gmail.com>

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

hoi :)

On Thu, Jul 27, 2006 at 12:06:34PM +0200, Santi wrote:
> >> could we default the to-be-merged branch to "remotes/$remote/$branch" if
> >> that exists?. That could make life a lot easier when using
> >> clone --use-separate-remote.

> On the other hand, my patch changes the behaviour only when explicitly
> configured, and your proposed default would change the behaviour even
> without changes to the config.

that is correct.

The current default is to always use the remote's master branch, right?
What do others think: does it make sense to default to the same
branchname on the remote side?

It could make life a bit easier if you want to synchronize several topic
branches between different sites.

-- 
Martin Waitz

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

^ permalink raw reply

* Git clone stalls at a read(3, ...) saw using strace
From: André Goddard Rosa @ 2006-07-27 12:16 UTC (permalink / raw)
  To: git; +Cc: junkio

Hi, all!

    Please CC me as I'm not subscribed.

    Using  GIT 1.4.1, I tried to get this repository:

# git clone git://source.mvista.com/git/linux-davinci-2.6.git

    After some time the download stalled completely. I used ps and
saw two git processes.

    Using strace, I saw that the first one, "git clone", was waiting
with waitpid()
for its child termination.
    Its child, "git pack --all -k", was stalled at a "read(3, ...)"

    I went to /proc and saw that fd 3 was a pipe. Anyone know why this
is happening?

    I found an issue somewhat related in google (not sure that is the
same problem):

http://groups.google.com/group/fa.linux.kernel/browse_thread/thread/e64a92f28def32a7/93bd8bf5df1fcc66?lnk=st&q=&rnum=1#93bd8bf5df1fcc66

    It stalled at the first 60 Mb transfered. After CTRL+C it deletes
and I have to start again from scratch.

Thank you for the great alternative to bitkeeper and CVS,
-- 
[]s,
André Goddard

^ permalink raw reply

* Re: [PATCH] Eliminate Scalar::Util usage from private-Error.pm
From: Randal L. Schwartz @ 2006-07-27 12:47 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Jakub Narebski, git
In-Reply-To: <Pine.LNX.4.63.0607261702500.29667@wbgn013.biozentrum.uni-wuerzburg.de>

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

Johannes>  Think ActiveState. 

Think ActiveState for the last time and see Strawberry Perl instead.
<http://vanillaperl.com/>.

-- 
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

^ permalink raw reply

* Re: Licensing and the library version of git
From: Jon Smirl @ 2006-07-27 12:54 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Petr Baudis, git
In-Reply-To: <Pine.LNX.4.63.0607271400160.29667@wbgn013.biozentrum.uni-wuerzburg.de>

On 7/27/06, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> Hi,
>
> On Thu, 27 Jul 2006, Petr Baudis wrote:
>
> > And I didn't even get to discussing whether LGPL is actually desirable
> > for Git.
>
> ... or whether it is neccessary for an Eclipse-plugin to something else
> than GPL.

Eclipse is not licensed GPL. To use the git library with Eclipse it
would need a JNI wrapper which would link it into the code. The work
around would be to make the user compile and link the JNI wrapper. But
I see that someone is already writing a pure Java version which will
work around the GPL problem assuming the Java version is released
under a compatible license.

In general libraries should be licensed LGPL to avoid the license
incompatibility problem. A GPL library forces the main app to be GPL
too. You may like trying to force GPL onto the app but many apps are
stuck with the license they have and can't be changed since there is
no way to contact the original developers. A GPL git library means
that these apps simply won't use git.

This also means that there will never be integrated git support in
Microsoft Visual Studio. This has impacts on switching cross platform
apps like Mozilla to git.

-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply

* Re: [PATCH] Per branch properties for pull and fetch
From: Santi @ 2006-07-27 13:10 UTC (permalink / raw)
  To: Martin Waitz; +Cc: Git Mailing List
In-Reply-To: <20060727120220.GD27593@admingilde.org>

> The current default is to always use the remote's master branch, right?

No.

For .git/remotes/ remotes it defaults to the first Pull line.
For .git/branches/ remotes if defaults to master, but you can specify
another branch.

Santi

^ 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