Git development
 help / color / mirror / Atom feed
* rebase destroys branches
From: Gene Thomas [DATACOM] @ 2013-03-04 23:06 UTC (permalink / raw)
  To: git@vger.kernel.org

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

Hello,
          I am evaluating git for use in a company. Please correct if I am wrong. I am concerned that an inexperienced developer could mistakenly rebase branches, destroying the original branch. Attached is a script (Windoze) that shows the 'topic' branch being moved!, after the rebase we are unable to see the original branch, read it's history or find it's commit points.

Surely no operation should remove anything from the repository. Operations like this irreversibly break the repository . When rebasing the original branch must be retained.

Yours faithfully,


Gene Thomas.


[-- Attachment #2: git-test.bat --]
[-- Type: application/octet-stream, Size: 1196 bytes --]


rem https://www.kernel.org/pub/software/scm/git/docs/git-rebase.html

rem (c) 2013 Gene Thomas
rem Datacom
rem Gene.Thomas@datacom.co.nz

if exist "git-test" rmdir /q /s git-test
mkdir git-test
cd git-test
git init

rem ==========================

echo d > d.txt
git add d.txt
git tag d
git commit -a -m d

echo e > e.txt
git add e.txt
git tag e
git commit -a -m e

git branch topic
git checkout topic

echo a > a.txt
git add a.txt
git tag a
git commit -m a

echo b > b.txt
git add b.txt
git tag b
git tag v2.0
git commit -a -m b

echo c > c.txt
git add c.txt
git tag c
git commit -a -m c

git log

rem ==========================

git checkout master

echo f > f.txt
git add f.txt
git tag f
git commit -a -m f

echo g > g.txt
git add g.txt
git tag g
git commit -a -m g

rem ==========================

git checkout topic
git rebase master

git log

rem ==========================

git checkout v2.0
git branch
rem we are on the "(no branch)" psuedo branch

rem origional 'topic' branch is lost
rem commits are still in the repositry
rem but can only be referenced by hash or tag
rem a mistake would destroy the history

^ permalink raw reply

* Re: rebase destroys branches
From: Philip Oakley @ 2013-03-04 23:43 UTC (permalink / raw)
  To: Gene Thomas [DATACOM], Git List
In-Reply-To: <C057AC9B02D06A49810E9597C11F55BF14DFE51C9F@dnzwgex2.datacom.co.nz>

From: "Gene Thomas [DATACOM]" <Gene.Thomas@datacom.co.nz>
Sent: Monday, March 04, 2013 11:06 PM
>Hello,
>I am evaluating git for use in a company. Please correct if I am wrong.
>I am concerned that an inexperienced developer could mistakenly rebase
>branches, destroying the original branch.

The original branch is not 'destroyed', rather the pointer to the 
previous tip is within the logs. All the content is still available 
until the logs expire.

>   Attached is a script (Windoze)
>that shows the 'topic' branch being moved!, after the rebase we are
>unable to see the original branch, read it's history or find it's 
>commit
>points.

>Surely no operation should remove anything from the repository.
>Operations like this irreversibly break the repository . When rebasing
>the original branch must be retained.

It's easy to misread some of Git's strengths if you have come from other 
historic corporate 'version control systems' which are often based on 
drawing office practice of old (e.g. the belief there is a single master 
to be protected is one misconception for software).

Rebase, at the personal level, is an important mechanism for staff to 
prepare better code and commit messages. Trying to hide the reality will 
just make your management 'control' less effective as staff work around 
it and delay check-ins, etc.

The broader access control and repo management issues are deliberately 
not part of Git, and there are good tools for that. e.g. Gitolite.

>Yours faithfully,


>Gene Thomas.

Philip

^ permalink raw reply

* git repo on Win 2008
From: J.V. @ 2013-03-04 23:43 UTC (permalink / raw)
  To: git@vger.kernel.org

What is the best way to host a shared git repo on a Windows 2008 box?  I 
would like to create a repo on the 2008 box (that everyone will 
pull/push to), but add the initial code from my developer (Windows7 box).


J.V.

^ permalink raw reply

* [PATCH 1/2] commit: add in_merge_bases_many()
From: Junio C Hamano @ 2013-03-05  0:48 UTC (permalink / raw)
  To: git

Similar to in_merge_bases(commit, other) that returns true when
commit is an ancestor (i.e. in the merge bases between the two) of
the other commit, in_merge_bases_many(commit, n_other, other[])
checks if commit is an ancestor of any of the other[] commits.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 commit.c | 24 ++++++++++++++++++------
 commit.h |  1 +
 2 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/commit.c b/commit.c
index e8eb0ae..3a201e0 100644
--- a/commit.c
+++ b/commit.c
@@ -852,25 +852,37 @@ int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
 }
 
 /*
- * Is "commit" an ancestor of (i.e. reachable from) the "reference"?
+ * Is "commit" an ancestor of one of the "reference"s?
  */
-int in_merge_bases(struct commit *commit, struct commit *reference)
+int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit **reference)
 {
 	struct commit_list *bases;
-	int ret = 0;
+	int ret = 0, i;
 
-	if (parse_commit(commit) || parse_commit(reference))
+	if (parse_commit(commit))
 		return ret;
+	for (i = 0; i < nr_reference; i++)
+		if (parse_commit(reference[i]))
+			return ret;
 
-	bases = paint_down_to_common(commit, 1, &reference);
+	bases = paint_down_to_common(commit, nr_reference, reference);
 	if (commit->object.flags & PARENT2)
 		ret = 1;
 	clear_commit_marks(commit, all_flags);
-	clear_commit_marks(reference, all_flags);
+	for (i = 0; i < nr_reference; i++)
+		clear_commit_marks(reference[i], all_flags);
 	free_commit_list(bases);
 	return ret;
 }
 
+/*
+ * Is "commit" an ancestor of (i.e. reachable from) the "reference"?
+ */
+int in_merge_bases(struct commit *commit, struct commit *reference)
+{
+	return in_merge_bases_many(commit, 1, &reference);
+}
+
 struct commit_list *reduce_heads(struct commit_list *heads)
 {
 	struct commit_list *p;
diff --git a/commit.h b/commit.h
index b6ad8f3..d5b9712 100644
--- a/commit.h
+++ b/commit.h
@@ -170,6 +170,7 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads,
 
 int is_descendant_of(struct commit *, struct commit_list *);
 int in_merge_bases(struct commit *, struct commit *);
+int in_merge_bases_many(struct commit *, int, struct commit **);
 
 extern int interactive_add(int argc, const char **argv, const char *prefix, int patch);
 extern int run_add_interactive(const char *revision, const char *patch_mode,
-- 
1.8.2-rc2-182-g857a7fa

^ permalink raw reply related

* [PATCH 2/2] push: --follow-tag
From: Junio C Hamano @ 2013-03-05  0:54 UTC (permalink / raw)
  To: git
In-Reply-To: <7vd2vewu24.fsf@alter.siamese.dyndns.org>

The new option "--follow-tag" tells "git push" to push tags that are
missing from the other side and that can be reached by the history
that is otherwise pushed out.  For example, if you are using the
"simple", "current", or "upstream" push, you would ordinarily push
the history leading to the commit at your current HEAD and nothing
else.  With this option, you would also push all tags that can be
reached from that commit to the other side.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 * The previous and this were built on 'maint', and may have
   trivial conflicts with 'master' and upwards.

   This is primarily to scratch my own itch; after tagging an rc or
   final release, I've been doing

   	git push k.org v1.8.2
        git push k.org

   and the first step can easily be forgotten.  With

	git push k.org --follow-tag

   I no longer should have to worry about that.  It will push out
   whatever would be pushed out without --follow-tag, and also tags
   that are missing from my k.org repository that point into the
   history being pushed out.

   I'd certainly need help with phrasing in the documentation, by
   the way.

 Documentation/git-push.txt |  8 +++-
 builtin/push.c             |  2 +
 remote.c                   | 92 ++++++++++++++++++++++++++++++++++++++++++++++
 remote.h                   |  3 +-
 t/t5516-fetch-push.sh      | 73 ++++++++++++++++++++++++++++++++++++
 transport.c                |  2 +
 transport.h                |  1 +
 7 files changed, 179 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 8b637d3..5020662 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -9,7 +9,7 @@ git-push - Update remote refs along with associated objects
 SYNOPSIS
 --------
 [verse]
-'git push' [--all | --mirror | --tags] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
+'git push' [--all | --mirror | --tags] [--follow-tag] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
 	   [--repo=<repository>] [-f | --force] [--prune] [-v | --verbose] [-u | --set-upstream]
 	   [<repository> [<refspec>...]]
 
@@ -111,6 +111,12 @@ no `push.default` configuration variable is set.
 	addition to refspecs explicitly listed on the command
 	line.
 
+--follow-tag::
+	Push all the refs that would be pushed without this option,
+	and also push the refs under `refs/tags` that are missing
+	from the remote but are reachable from the refs that would
+	be pushed without this option.
+
 --receive-pack=<git-receive-pack>::
 --exec=<git-receive-pack>::
 	Path to the 'git-receive-pack' program on the remote
diff --git a/builtin/push.c b/builtin/push.c
index db9ba30..08e3db1 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -399,6 +399,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 		OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
 		OPT_BIT(0, "prune", &flags, N_("prune locally removed refs"),
 			TRANSPORT_PUSH_PRUNE),
+		OPT_BIT(0, "follow-tag", &flags, N_("push missing but relevant tags"),
+			TRANSPORT_PUSH_FOLLOW_TAG),
 		OPT_END()
 	};
 
diff --git a/remote.c b/remote.c
index ca1f8f2..4441944 100644
--- a/remote.c
+++ b/remote.c
@@ -1195,6 +1195,94 @@ static struct ref **tail_ref(struct ref **head)
 	return tail;
 }
 
+struct tips {
+	struct commit **tip;
+	int nr, alloc;
+};
+
+static void add_to_tips(struct tips *tips, struct ref *ref)
+{
+	struct commit *commit;
+
+	if (is_null_sha1(ref->new_sha1))
+		return;
+	commit = lookup_commit_reference_gently(ref->new_sha1, 1);
+	if (!commit)
+		return; /* not pushing a commit, which is not an error */
+	ALLOC_GROW(tips->tip, tips->nr + 1, tips->alloc);
+	tips->tip[tips->nr++] = commit;
+}
+
+static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***dst_tail)
+{
+	struct string_list dst_tag = STRING_LIST_INIT_NODUP;
+	struct string_list src_tag = STRING_LIST_INIT_NODUP;
+	struct string_list_item *item;
+	struct ref *ref;
+	struct tips sent_tips;
+
+	/*
+	 * Collect everything we are going to send
+	 * and collect all tags they have.
+	 */
+	memset(&sent_tips, 0, sizeof(sent_tips));
+	for (ref = *dst; ref; ref = ref->next) {
+		if (ref->peer_ref &&
+		    !is_null_sha1(ref->peer_ref->new_sha1))
+			add_to_tips(&sent_tips, ref->peer_ref);
+		if (!prefixcmp(ref->name, "refs/tags/"))
+			string_list_append(&dst_tag, ref->name);
+	}
+	sort_string_list(&dst_tag);
+
+	/* Collect tags they do not have. */
+	for (ref = src; ref; ref = ref->next) {
+		if (prefixcmp(ref->name, "refs/tags/"))
+			continue;
+		if (string_list_has_string(&dst_tag, ref->name))
+			continue;
+		item = string_list_append(&src_tag, ref->name);
+		item->util = ref;
+	}
+	string_list_clear(&dst_tag, 0);
+
+	/*
+	 * At this point, src_tag lists tags that are missing from
+	 * dst, and sent_tips lists the tips we are pushing (or those
+	 * that we know they already have). An element in the src_tag
+	 * that is not an ancestor of any of the sent_tips need to be
+	 * sent to the other side.
+	 */
+	if (sent_tips.nr) {
+		for_each_string_list_item(item, &src_tag) {
+			struct ref *ref = item->util;
+			struct ref *dst_ref;
+			struct commit *commit;
+
+			if (is_null_sha1(ref->new_sha1))
+				continue;
+			commit = lookup_commit_reference_gently(ref->new_sha1, 1);
+			if (!commit)
+				/* not pushing a commit, which is not an error */
+				continue;
+
+			/*
+			 * Is this tag, which they do not have, reachable from
+			 * any of the commits we are sending?
+			 */
+			if (!in_merge_bases_many(commit, sent_tips.nr, sent_tips.tip))
+				continue;
+
+			/* Add it in */
+			dst_ref = make_linked_ref(ref->name, dst_tail);
+			hashcpy(dst_ref->new_sha1, ref->new_sha1);
+			dst_ref->peer_ref = copy_ref(ref);
+		}
+	}
+	string_list_clear(&src_tag, 0);
+	free(sent_tips.tip);
+}
+
 /*
  * Given the set of refs the local repository has, the set of refs the
  * remote repository has, and the refspec used for push, determine
@@ -1257,6 +1345,10 @@ int match_push_refs(struct ref *src, struct ref **dst,
 	free_name:
 		free(dst_name);
 	}
+
+	if (flags & MATCH_REFS_FOLLOW_TAG)
+		add_missing_tags(src, dst, &dst_tail);
+
 	if (send_prune) {
 		/* check for missing refs on the remote */
 		for (ref = *dst; ref; ref = ref->next) {
diff --git a/remote.h b/remote.h
index 251d8fd..950ab5a 100644
--- a/remote.h
+++ b/remote.h
@@ -148,7 +148,8 @@ enum match_refs_flags {
 	MATCH_REFS_NONE		= 0,
 	MATCH_REFS_ALL 		= (1 << 0),
 	MATCH_REFS_MIRROR	= (1 << 1),
-	MATCH_REFS_PRUNE	= (1 << 2)
+	MATCH_REFS_PRUNE	= (1 << 2),
+	MATCH_REFS_FOLLOW_TAG	= (1 << 3)
 };
 
 /* Reporting of tracking info */
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index b5417cc..4ff2eb2 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -995,4 +995,77 @@ test_expect_success 'push --prune refspec' '
 	! check_push_result $the_first_commit tmp/foo tmp/bar
 '
 
+test_expect_success 'fetch follows tags by default' '
+	mk_test heads/master &&
+	rm -fr src dst &&
+	git init src &&
+	(
+		cd src &&
+		git pull ../testrepo master &&
+		git tag -m "annotated" tag &&
+		git for-each-ref >tmp1 &&
+		(
+			cat tmp1
+			sed -n "s|refs/heads/master$|refs/remotes/origin/master|p" tmp1
+		) |
+		sort -k 3 >../expect
+	) &&
+	git init dst &&
+	(
+		cd dst &&
+		git remote add origin ../src &&
+		git config branch.master.remote origin &&
+		git config branch.master.merge refs/heads/master &&
+		git pull &&
+		git for-each-ref >../actual
+	) &&
+	test_cmp expect actual
+'
+
+test_expect_success 'push does not follow tags by default' '
+	mk_test heads/master &&
+	rm -fr src dst &&
+	git init src &&
+	git init --bare dst &&
+	(
+		cd src &&
+		git pull ../testrepo master &&
+		git tag -m "annotated" tag &&
+		git checkout -b another &&
+		git commit --allow-empty -m "future commit" &&
+		git tag -m "future" future &&
+		git checkout master &&
+		git for-each-ref refs/heads/master >../expect &&
+		git push ../dst master
+	) &&
+	(
+		cd dst &&
+		git for-each-ref >../actual
+	) &&
+	test_cmp expect actual
+'
+
+test_expect_success 'push --follow-tag only pushes relevant tags' '
+	mk_test heads/master &&
+	rm -fr src dst &&
+	git init src &&
+	git init --bare dst &&
+	(
+		cd src &&
+		git pull ../testrepo master &&
+		git tag -m "annotated" tag &&
+		git checkout -b another &&
+		git commit --allow-empty -m "future commit" &&
+		git tag -m "future" future &&
+		git checkout master &&
+		git for-each-ref refs/heads/master refs/tags/tag >../expect
+		git push --follow-tag ../dst master
+	) &&
+	(
+		cd dst &&
+		git for-each-ref >../actual
+	) &&
+	test_cmp expect actual
+'
+
 test_done
diff --git a/transport.c b/transport.c
index b9306ef..6e2f22d 100644
--- a/transport.c
+++ b/transport.c
@@ -1059,6 +1059,8 @@ int transport_push(struct transport *transport,
 			match_flags |= MATCH_REFS_MIRROR;
 		if (flags & TRANSPORT_PUSH_PRUNE)
 			match_flags |= MATCH_REFS_PRUNE;
+		if (flags & TRANSPORT_PUSH_FOLLOW_TAG)
+			match_flags |= MATCH_REFS_FOLLOW_TAG;
 
 		if (match_push_refs(local_refs, &remote_refs,
 				    refspec_nr, refspec, match_flags)) {
diff --git a/transport.h b/transport.h
index 4a61c0c..bbebfbc 100644
--- a/transport.h
+++ b/transport.h
@@ -104,6 +104,7 @@ struct transport {
 #define TRANSPORT_RECURSE_SUBMODULES_CHECK 64
 #define TRANSPORT_PUSH_PRUNE 128
 #define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND 256
+#define TRANSPORT_PUSH_FOLLOW_TAG 1024
 
 #define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
 #define TRANSPORT_SUMMARY(x) (int)(TRANSPORT_SUMMARY_WIDTH + strlen(x) - gettext_width(x)), (x)
-- 
1.8.2-rc2-182-g857a7fa

^ permalink raw reply related

* RE: rebase destroys branches
From: Gene Thomas [DATACOM] @ 2013-03-05  1:05 UTC (permalink / raw)
  To: Philip Oakley, Git List
In-Reply-To: <64FF012BC4AF45C4A5067DE93FD9FE17@PhilipOakley>

Philip,
        Thanks for your reply.

>The original branch is not 'destroyed', rather the pointer to the previous tip is within the logs. 

Is that the 'git log' log or internal logs? Are you sure? There doesn't appear to be a way to checkout that tip of see the log back from that tip.

>All the content is still available until the logs expire.

So we will be unable to checkout content after a time?

Gene Thomas.

-----Original Message-----
From: Philip Oakley [mailto:philipoakley@iee.org] 
Sent: Tuesday, 5 March 2013 12:44
To: Gene Thomas [DATACOM]; Git List
Subject: Re: rebase destroys branches

From: "Gene Thomas [DATACOM]" <Gene.Thomas@datacom.co.nz>
Sent: Monday, March 04, 2013 11:06 PM
>Hello,
>I am evaluating git for use in a company. Please correct if I am wrong.
>I am concerned that an inexperienced developer could mistakenly rebase 
>branches, destroying the original branch.

The original branch is not 'destroyed', rather the pointer to the previous tip is within the logs. All the content is still available until the logs expire.

>   Attached is a script (Windoze)
>that shows the 'topic' branch being moved!, after the rebase we are 
>unable to see the original branch, read it's history or find it's 
>commit points.

>Surely no operation should remove anything from the repository.
>Operations like this irreversibly break the repository . When rebasing 
>the original branch must be retained.

It's easy to misread some of Git's strengths if you have come from other historic corporate 'version control systems' which are often based on drawing office practice of old (e.g. the belief there is a single master to be protected is one misconception for software).

Rebase, at the personal level, is an important mechanism for staff to prepare better code and commit messages. Trying to hide the reality will just make your management 'control' less effective as staff work around it and delay check-ins, etc.

The broader access control and repo management issues are deliberately not part of Git, and there are good tools for that. e.g. Gitolite.

>Yours faithfully,


>Gene Thomas.

Philip

^ permalink raw reply

* Fwd: Strange remote interaction
From: Javier Domingo @ 2013-03-05  1:11 UTC (permalink / raw)
  To: git@vger.kernel.org
In-Reply-To: <CALZVapm32S2XqA48KCmfr8O5PVSNMgRj=JfRm_yyYz6N6wE0=A@mail.gmail.com>

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

Hi,

I have just had the attached bash session, and I have no idea on what
is going on.

Any help appreciated,

Javier Domingo

[-- Attachment #2: bug --]
[-- Type: application/octet-stream, Size: 731 bytes --]

javier@frodo:~/proyectos/pfc$ git push -vvv javier master
Pushing to git@server:javier/pfc
To git@server:javier/pfc
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@server:javier/pfc'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and merge the remote changes
hint: (e.g. 'git pull') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
javier@frodo:~/proyectos/pfc$ git fetch -vvv javier 
From server:javier/pfc
 = [up to date]      master     -> javier/master
javier@frodo:~/proyectos/pfc$ git merge javier/master 
Already up-to-date.
javier@frodo:~/proyectos/pfc$ 

^ permalink raw reply

* Re: rebase destroys branches
From: Theodore Ts'o @ 2013-03-05  2:21 UTC (permalink / raw)
  To: Gene Thomas [DATACOM]; +Cc: Philip Oakley, Git List
In-Reply-To: <C057AC9B02D06A49810E9597C11F55BF14DFE5214F@dnzwgex2.datacom.co.nz>

On Tue, Mar 05, 2013 at 02:05:32PM +1300, Gene Thomas [DATACOM] wrote:
> 
> >The original branch is not 'destroyed', rather the pointer to the previous tip is within the logs. 
> 
> Is that the 'git log' log or internal logs? Are you sure? There doesn't appear to be a way to checkout that tip of see the log back from that tip.

See the dovcumentation for "git reflog"

> >All the content is still available until the logs expire.
> 
> So we will be unable to checkout content after a time?

You need to make a distinction between a user's local repository, and
the team's central repository.  The workflow of the individual user is
one where they can and should be allowed to use rebase and "git commit
--amend" if they like.  Consider this the same thing as the user who
chooses to use "quilt" on their local machine while they are preparing
their patches, so they are carefully honed before they are cast into
concrete.  Whether they use "quilt", or manual patching, or simply
don't bother checking things into the central SCM until things are
cleaned up, the end result is the same.

The team's central repository is one where you don't want to allow
history to be lost, and so there you can enforce rules to prevent
this.  For example, if you use Gerrit, you can limit the ability to
reset branches to administrators only.  Everyone else can only add new
commits, not change older ones.

(If someone accidentally checks in NDA'ed material belonging to
someone else, or some other IP content guaranteed to cause your
general counsel to have heart palpitations, trust me, you'll want to
allow administrators to rewind a git branch.  :-)

You can also use Gerrit to enforce code reviews, so that no change
goes in until a second engineer reviews the commit and gives it a
thumbs up (with a permanent record of the code review kept in Gerrit,
something which can be important for pointy-haired corporate types who
worry about Sarbanes Oxley controls --- although from your e-mail
address, you may be lucky enough to be exempt from needing to worry
about SOX controls :-).

Regards,

						- Ted

^ permalink raw reply

* Fwd: Git 1.8.2 l10n round 4
From: Jiang Xin @ 2013-03-05  4:57 UTC (permalink / raw)
  To: Git List
In-Reply-To: <CANYiYbG81JvKFrWash0ec=UBqDWXfW9ZGGsG31WECp5aiWDfxQ@mail.gmail.com>

Hi,

Leaders of Git language teams please note that a new "git.pot" is
generated from v1.8.2-rc2-4-g77995 in the master branch. See
commit:

    l10n: git.pot: v1.8.2 round 4 (1 changed)

    Generate po/git.pot from v1.8.2-rc2-4-g77995 for git v1.8.2
    l10n round 4.

    Signed-off-by: Jiang Xin <worldhello.net@gmail.com>

This update is for the l10n of the upcoming git 1.8.2. You can get it
from the usual place:

    https://github.com/git-l10n/git-po/

--
Jiang Xin

^ permalink raw reply

* Re: Fwd: Strange remote interaction
From: Junio C Hamano @ 2013-03-05  5:21 UTC (permalink / raw)
  To: Javier Domingo; +Cc: git@vger.kernel.org
In-Reply-To: <CALZVapnDyF7m=R7xrjUJUtyr9xVUeDnL4tQSCoM2ze8GSuUUyg@mail.gmail.com>

Javier Domingo <javierdo1@gmail.com> writes:

> I have just had the attached bash session, and I have no idea on what
> is going on.
>
> Any help appreciated,
>
> Javier Domingo
>
> javier@frodo:~/proyectos/pfc$ git push -vvv javier master
> Pushing to git@server:javier/pfc
> To git@server:javier/pfc
>  ! [rejected]        master -> master (non-fast-forward)
> error: failed to push some refs to 'git@server:javier/pfc'
> hint: Updates were rejected because a pushed branch tip is behind its remote
> hint: counterpart. Check out this branch and merge the remote changes
> hint: (e.g. 'git pull') before pushing again.
> hint: See the 'Note about fast-forwards' in 'git push --help' for details.

So push is going to git@server:javier/pfc repository, while ...

> javier@frodo:~/proyectos/pfc$ git fetch -vvv javier 
> From server:javier/pfc
>  = [up to date]      master     -> javier/master

... fetch/pull goes to server:javier/pfc repository.  Are they the
same?

In a usual set-up, an access to git@server:javier/pfc will first
locate the home directory for the user "git" (the token before "@"),
and then its subdirectory javier/pfc, e.g. /home/git/javier/pfc,
while an access to server:javier/pfc will first locate the home
directory of whatever username the ssh connection uses by default
(typically the local user but ~/.ssh/config may have "User"
directive for the server) and then its subdirectory javier/pfc,
e.g. /home/javier/javier/pfc.  These two may be different locations.

Do these two commands show the same output?

	$ git ls-remote git@server:javier/pfc refs/heads/master
        $ git ls-remote server:javier/pfc refs/heads/master

If the above conjecture is correct, I suspect they don't.

^ permalink raw reply

* Re: [PATCH/RFC] Changing submodule foreach --recursive to be depth-first, --parent option to execute command in supermodule as well
From: Eric Cousineau @ 2013-03-05  5:37 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jens Lehmann, git
In-Reply-To: <7vhakqwz1e.fsf@alter.siamese.dyndns.org>

git-submodule.sh: In foreach, make '-post-order' yield post-order 
traversal and
'--include-super' execute commands at the top-level supermodule, with 
both of these
options compatible with '--recursive'.

Signed-off-by: Eric Cousineau <eacousineau@gmail.com>
---
Sorry about missing the part about not included MIME attachments, hope 
this is in a better format now.
Jens, I changed the '--parent' option to '--include-super' which is 
hopefully less vague.
Junio, you made an excellent point about both being useful. In 
particular, I overlooked the case
for doing a submodule pull / update (if, for whatever reason, it is more 
convenient than a submodule
update, maybe for merging). In that case, you might want to initialize 
new submodules and ignore the
old ones, instead of wasting time on them with a post-order traversal pull.
I've implemented your suggestions to have a boolean '--post-order' 
option, and made the '--include-super'
option compatible with it. This way, the original behavior of 'foreach' 
is preserved.

I've updated the test and uploaded it to pastebin: 
http://pastebin.com/BgZNzFpi

  git-submodule.sh | 102 
+++++++++++++++++++++++++++++++++++++++++--------------
  1 file changed, 77 insertions(+), 25 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 004c034..652bea0 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -10,7 +10,7 @@ USAGE="[--quiet] add [-b <branch>] [-f|--force] 
[--name <name>] [--reference <re
     or: $dashless [--quiet] init [--] [<path>...]
     or: $dashless [--quiet] update [--init] [--remote] [-N|--no-fetch] 
[-f|--force] [--rebase] [--reference <repository>] [--merge] 
[--recursive] [--] [<path>...]
     or: $dashless [--quiet] summary [--cached|--files] [--summary-limit 
<n>] [commit] [--] [<path>...]
-   or: $dashless [--quiet] foreach [--recursive] <command>
+   or: $dashless [--quiet] foreach [--recursive] [--include-super] 
[--post-order] <command>
     or: $dashless [--quiet] sync [--recursive] [--] [<path>...]"
  OPTIONS_SPEC=
  . git-sh-setup
@@ -434,6 +434,8 @@ Use -f if you really want to add it." >&2
  cmd_foreach()
  {
      # parse $args after "submodule ... foreach".
+    # Gratuitous (empty) local's to prevent recursive bleeding
+    local include_super= recursive= post_order=
      while test $# -ne 0
      do
          case "$1" in
@@ -443,6 +445,12 @@ cmd_foreach()
          --recursive)
              recursive=1
              ;;
+        --post-order)
+            post_order=1
+            ;;
+        --include-super)
+            include_super=1
+            ;;
          -*)
              usage
              ;;
@@ -453,35 +461,79 @@ cmd_foreach()
          shift
      done

-    toplevel=$(pwd)
+    if test -n "$recursive"
+    then
+        local recursive_flags="--recursive"
+        if test -n "$post_order"
+        then
+            recursive_flags="$recursive_flags --post-order"
+        fi
+    fi
+
+    local toplevel=$(pwd)

      # dup stdin so that it can be restored when running the external
      # command in the subshell (and a recursive call to this function)
      exec 3<&0
+
+    # Use nested functions
+    super_eval() {
+        name=$(basename "$toplevel")
+        clear_local_git_env
+        path=.
+        say "$(eval_gettext "Entering '\$name'")" # Not sure of proper 
thing here
+        eval "$@" || die "$(eval_gettext "Stopping at supermodule; 
script returned non-zero status.")"
+    }

-    module_list |
-    while read mode sha1 stage sm_path
-    do
-        die_if_unmatched "$mode"
-        if test -e "$sm_path"/.git
-        then
-            say "$(eval_gettext "Entering '\$prefix\$sm_path'")"
-            name=$(module_name "$sm_path")
-            (
-                prefix="$prefix$sm_path/"
-                clear_local_git_env
-                # we make $path available to scripts ...
-                path=$sm_path
-                cd "$sm_path" &&
-                eval "$@" &&
-                if test -n "$recursive"
-                then
-                    cmd_foreach "--recursive" "$@"
-                fi
-            ) <&3 3<&- ||
-            die "$(eval_gettext "Stopping at '\$sm_path'; script 
returned non-zero status.")"
-        fi
-    done
+    if test -n "$include_super" -a -z "$post_order"
+    then
+        super_eval "$@"
+    fi &&
+    (
+        module_list |
+        while read mode sha1 stage sm_path
+        do
+            die_if_unmatched "$mode"
+            if test -e "$sm_path"/.git
+            then
+                local name prefix path message epitaph
+                message="$(eval_gettext "Entering '\$prefix\$sm_path'")"
+                epitaph="$(eval_gettext "Stopping at '\$sm_path'; 
script returned non-zero status.")"
+                name=$(module_name "$sm_path")
+                (
+                    prefix="$prefix$sm_path/"
+                    clear_local_git_env
+                    # we make $path available to scripts ...
+                    path=$sm_path
+
+                    sm_eval() {
+                        say "$message"
+                        eval "$@" || die "$epitaph"
+                    }
+
+                    cd "$sm_path" &&
+                    if test -z "$post_order"
+                    then
+                        sm_eval "$@"
+                    fi &&
+                    if test -n "$recursive"
+                    then
+                        cmd_foreach $recursive_flags "$@"
+                    fi &&
+                    if test -n "$post_order"
+                    then
+                        sm_eval "$@"
+                    fi
+                    # Since the (...) seems to limit exit's scope, make 
sure to kill things here if something goes awry
+                    # (the `|| exit 1` at the end)
+                ) <&3 3<&- || exit 1
+            fi
+        done
+    ) &&
+    if test -n "$include_super" -a -n "$post_order"
+    then
+        super_eval "$@"
+    fi
  }

  #
-- 
1.8.2.rc1.24.g06d67b8.dirty

^ permalink raw reply related

* [PATCH] l10n: de.po: translate 1 new message
From: Ralf Thielow @ 2013-03-05  5:39 UTC (permalink / raw)
  To: trast, jk, stimming; +Cc: git, Ralf Thielow

Translate 1 new message came from git.pot update in
ed1ddaf (l10n: git.pot: v1.8.2 round 4 (1 changed)).

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---
 po/de.po | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/po/de.po b/po/de.po
index 37aa24d..83c30b1 100644
--- a/po/de.po
+++ b/po/de.po
@@ -126,12 +126,11 @@ msgid "path to the remote git-upload-archive command"
 msgstr "Pfad zum externen \"git-upload-archive\"-Programm"
 
 #: attr.c:259
-#, fuzzy
 msgid ""
 "Negative patterns are ignored in git attributes\n"
 "Use '\\!' for literal leading exclamation."
 msgstr ""
-"Verneinende Muster sind in Git-Attributen verboten.\n"
+"Verneinende Muster werden in Git-Attributen ignoriert.\n"
 "Benutzen Sie '\\!' für führende Ausrufezeichen."
 
 #: bundle.c:36
-- 
1.8.2.rc2.4.g7799588

^ permalink raw reply related

* Re: [PATCH] match_push_refs(): nobody sets src->peer_ref anymore
From: Jeff King @ 2013-03-05  5:45 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vlia2x05q.fsf@alter.siamese.dyndns.org>

On Mon, Mar 04, 2013 at 02:36:33PM -0800, Junio C Hamano wrote:

> In ancient times, we used to disallow the same source ref to be
> pushed to more than one places, e.g. "git push there master:master
> master:naster" was disallowed.  We later lifted this restriction
> with db27ee63929f (send-pack: allow the same source to be pushed
> more than once., 2005-08-06) and there no longer is anybody that
> sets peer_ref for the source side of the ref list in the push
> codepath since then.
> 
> Remove one leftover no-op in a loop that iterates over the source
> side of ref list (i.e. our local ref) to see if it can/should be
> sent to a matching destination ref while skipping ones that is
> marked with peer_ref (which will never exist, so we do not skip
> anything).
> 
> Signed-off-by: Junio C Hamano <gitster@pobox.com>

This looks good to me. I was curious how difficult it would be to verify
the "no longer is anybody that sets peer_ref" claim. It's actually quite
easy. All of the call-sites just feed the result of get_local_heads(),
which is easy to verify does not ever set peer_ref. Looking at the
current code, I think you could even drop the "src" parameter and just
have match_push_refs call get_local_heads() itself, though that does
feel like a step backwards in terms of function generality.

As an aside, I have always found the embedded "next" and "peer_ref"
pointers in "struct ref" to be hacky. They are not properties of the ref
at all, and the "refs to fetch" list would be more logically represented
as a list of pairs of refs (and then I would not have to ever remember
whether the peer is the local or remote ref in a given case). Probably
not worth worrying about at this point, though, as the code fallout
would be significant for little gain.

-Peff

^ permalink raw reply

* v3.4 released
From: Sitaram Chamarty @ 2013-03-05  6:55 UTC (permalink / raw)
  To: Git Mailing List, gitolite-announce

mostly minor fixes but the rc file format change is in now.

Also, I souped up the refex-expr a bit; here's a teaser:

  * user u2 is allowed to push either 'doc/' or 'src/' but not both

        repo    foo
            RW+                         =   u1 u2 u3

            RW+ VREF/NAME/doc/                      =   u2
            RW+ VREF/NAME/src/                      =   u2
            -   VREF/NAME/doc/ and VREF/NAME/src/   =   u2

Interested people can take a look at src/VREF/refex-expr for details
https://github.com/sitaramc/gitolite/blob/master/src/VREF/refex-expr

-- 
Sitaram

^ permalink raw reply

* Re: [PATCH v6] submodule: add 'deinit' command
From: Heiko Voigt @ 2013-03-05  7:29 UTC (permalink / raw)
  To: Jens Lehmann
  Cc: Junio C Hamano, Phil Hord, Git Mailing List, Michael J Gruber,
	Marc Branchaud, W. Trevor King
In-Reply-To: <51351018.20301@web.de>

Hi,

On Mon, Mar 04, 2013 at 10:20:24PM +0100, Jens Lehmann wrote:
> diff --git a/git-submodule.sh b/git-submodule.sh
> index 004c034..44f70c4 100755
> --- a/git-submodule.sh
> +++ b/git-submodule.sh
> @@ -547,6 +548,80 @@ cmd_init()
>  }
> 
[...]
> +
> +	module_list "$@" |
> +	while read mode sha1 stage sm_path
> +	do
> +		die_if_unmatched "$mode"
> +		name=$(module_name "$sm_path") || exit
> +
> +		# Remove the submodule work tree (unless the user already did it)
> +		if test -d "$sm_path"
> +		then
> +			# Protect submodules containing a .git directory
> +			if test -d "$sm_path/.git"
> +			then
> +				echo >&2 "$(eval_gettext "Submodule work tree '\$sm_path' contains a .git directory")"
> +				die "$(eval_gettext "(use 'rm -rf' if you really want to remove it including all of its history)")"
> +			fi
> +
> +			if test -z "$force"
> +			then
> +				git rm -n "$sm_path" ||
> +				die "$(eval_gettext "Submodule work tree '\$sm_path' contains local modifications; use '-f' to discard them")"

Minor nit. IMO, there is an indentation for the || missing here. Maybe
Junio can squash that in on his side?

> +			fi
> +			rm -rf "$sm_path" || say "$(eval_gettext "Could not remove submodule work tree '\$sm_path'")"
> +		fi
> +
> +		mkdir "$sm_path" || say "$(eval_gettext "Could not create empty submodule directory '\$sm_path'")"

[...]

Everything else looks good to me.

Cheers Heiko

^ permalink raw reply

* Re: [PATCH/RFC] Changing submodule foreach --recursive to be depth-first, --parent option to execute command in supermodule as well
From: Heiko Voigt @ 2013-03-05  7:59 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jens Lehmann, Eric Cousineau, git
In-Reply-To: <7vhakqwz1e.fsf@alter.siamese.dyndns.org>

On Mon, Mar 04, 2013 at 03:00:45PM -0800, Junio C Hamano wrote:
> So if you want a single boolean to toggle between the current
> behaviour and the other one, it would be --post-order.  But you may
> at least want to consider pros and cons of allowing users to give
> two separate commands, one for the pre-order visitation (which is
> the current "command") and the other for the post-order
> visitation. Being able to run both might turn out to be useful.

I second that. Having a --post-order=<command/script> switch will give
us much more flexibility. For ease of use we could allow --post-order
without command to switch the meaning of the main command.

So a final solution would have these switches:

git submodule foreach ... [--pre-order[=<command>]] [--post-order[=<command>]] [<command>]

If only --pre-order without argument is given the command will be
executed pre-order. If only --post-order the command will be executed
post-order. If both are given its an error and so on...

There are some combinations we would need to catch as errors but this
design should allow a step by step implementation:

	1. just the --post-order switch
	2. --post-order with argument switch
	3. --pre-order (including argument) for symmetry of usage

Cheers Heiko

^ permalink raw reply

* Re: git repo on Win 2008
From: Heiko Voigt @ 2013-03-05  8:15 UTC (permalink / raw)
  To: J.V.; +Cc: git@vger.kernel.org
In-Reply-To: <5135319F.50404@gmail.com>

Hi,

wrong mailing list for Windows questions. This is the correct one:

http://groups.google.com/group/msysgit

On Mon, Mar 04, 2013 at 04:43:27PM -0700, J.V. wrote:
> What is the best way to host a shared git repo on a Windows 2008
> box?  I would like to create a repo on the 2008 box (that everyone
> will pull/push to), but add the initial code from my developer
> (Windows7 box).

The simplest way is: Just use a shared folder to which you push/clone a
bare clone of your repository. Everyone with access to that folder will
be able to clone from or push there.

There is even an option in Git GUI for the initial operation:

Menubar->Remote->Add, Fill in your information and choose "Initialize
Remote Repository and Push"

Cheers Heiko

^ permalink raw reply

* Re: [PATCH 2/2] push: --follow-tag
From: Jeff King @ 2013-03-05  8:22 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7v6216wtrk.fsf@alter.siamese.dyndns.org>

On Mon, Mar 04, 2013 at 04:54:39PM -0800, Junio C Hamano wrote:

>    This is primarily to scratch my own itch; after tagging an rc or
>    final release, I've been doing
> 
>    	git push k.org v1.8.2
>         git push k.org
> 
>    and the first step can easily be forgotten.  With
> 
> 	git push k.org --follow-tag
> 
>    I no longer should have to worry about that.  It will push out
>    whatever would be pushed out without --follow-tag, and also tags
>    that are missing from my k.org repository that point into the
>    history being pushed out.

I've run into the same problem. It's a minor annoyance, but your patch
should make it smoother.

Should this be called "--follow-tags"? That makes more sense to me, as
you are catching all tags. For consistency, should this match the naming
of git-fetch's options (or vice versa)? There we have:

  <default>: auto-follow tags

  --tags: fetch all of refs/heads/tags

  --no-tags: do not auto-follow

I think that naming has caused some confusion in the past. And there is
no way to explicitly specify the default behavior. I wonder if both
should support:

  --follow-tags: auto-follow tags

  --no-follow-tags: do not auto-follow tags

  --tags: fetch/push all of refs/heads/tags

  --no-tags: turn off auto-following, and cancel any previous --tags

The default for push should probably keep auto-follow off, though.

> +--follow-tag::
> +	Push all the refs that would be pushed without this option,
> +	and also push the refs under `refs/tags` that are missing
> +	from the remote but are reachable from the refs that would
> +	be pushed without this option.
> +

This reads OK to me, though it is a little confusing in that there are
two sets of refs being discussed, and "the refs that would be pushed
without this option" is quite a long noun phrase (that gets used twice).

You also don't define "reachable" here. Being familiar with git, I
assume it is "the commit that the refs/tag entry peels to is an ancestor
of a commit that is at the tip of a pushed ref".  Maybe that is obvious
enough that it doesn't need to be spelled out.

I think you could just drop the second "refs that would be pushed
without this option", and just say "pushed refs". That is ambiguous (is
it all pushed refs, or refs that would be pushed without this option?),
but since reachability is transitive, they are the same set (i.e., if we
add a ref due to this option, then its ancestors are already candidates,
and it does not affect the outcome).

Maybe:

  In addition to any refs that would be pushed without this option,
  also push any refs under `refs/tags` that are missing from the remote
  but are reachable from the pushed refs.

I dunno. I don't really like that version much, either.

> +	/*
> +	 * At this point, src_tag lists tags that are missing from
> +	 * dst, and sent_tips lists the tips we are pushing (or those
> +	 * that we know they already have). An element in the src_tag
> +	 * that is not an ancestor of any of the sent_tips need to be
> +	 * sent to the other side.
> +	 */
> +	if (sent_tips.nr) {
> +		for_each_string_list_item(item, &src_tag) {
> +			struct ref *ref = item->util;
> +			struct ref *dst_ref;
> +			struct commit *commit;
> +
> +			if (is_null_sha1(ref->new_sha1))
> +				continue;
> +			commit = lookup_commit_reference_gently(ref->new_sha1, 1);
> +			if (!commit)
> +				/* not pushing a commit, which is not an error */
> +				continue;

This will find anything under refs/tags, including annotated and
non-annotated tags. I wonder if it is worth making a distinction. In
many workflows, unannotated tags should not be leaked out to public
repos. But because this feature finds any reachable tags, it will push a
tag you made a long time ago as a bookmarker on some part of the history
unrelated to the release you are making now.

One obvious alternative is only to push annotated tags with this
feature. That has the downside of not matching fetch's behavior, as well
as withholding the feature from people whose workflow uses only
unannotated tags.

Another alternative would be to change the inclusion rule from
"reachable" to "points at the tip of something being sent". But then we
lose the feature that it would backfill any old tags the remote happens
to be missing.

-Peff

^ permalink raw reply

* [PATCH] git-completion.zsh: define __gitcomp_file compatibility function
From: Matthieu Moy @ 2013-03-05  8:43 UTC (permalink / raw)
  To: git, gitster; +Cc: felipe.contreras, manlio.perillo, Matthieu Moy
In-Reply-To: <vpqtxowp9e2.fsf@grenoble-inp.fr>

Commit fea16b47b60 (Fri Jan 11 19:48:43 2013, Manlio Perillo,
git-completion.bash: add support for path completion), introduced a new
__gitcomp_file function that uses the bash builtin "compgen". The
function was redefined for ZSH in the deprecated section of
git-completion.bash, but not in the new git-completion.zsh script.

As a result, users of git-completion.zsh trying to complete "git add
fo<tab>" get an error:

git add fo__gitcomp_file:8: command not found: compgen

This patch adds the redefinition and removes the error.

Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
---
> Felipe, you know ZSH completion much better than me. Could you turn this
> into a real patch?

No response from Felipe, so I'm trying my own patch. Compared to the
snippet I already sent, I added the -f option to "compadd", which was
there in the __gitcomp_file function defined in the deprecated ZSH
compatibility section of the bash script, and gives the ZSH equivalent
for "compopt -o filenames".

This fixes an annoying regression for ZSH users, so it may deserve to
be in the future 1.8.2.

 contrib/completion/git-completion.zsh | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh
index 4577502..cf8116d 100644
--- a/contrib/completion/git-completion.zsh
+++ b/contrib/completion/git-completion.zsh
@@ -60,6 +60,15 @@ __gitcomp_nl ()
 	compadd -Q -S "${4- }" -p "${2-}" -- ${=1} && _ret=0
 }
 
+__gitcomp_file ()
+{
+	emulate -L zsh
+
+	local IFS=$'\n'
+	compset -P '*[=:]'
+	compadd -Q -p "${2-}" -f -- ${=1} && _ret=0
+}
+
 _git ()
 {
 	local _ret=1
-- 
1.8.1.3.572.g35e1b60

^ permalink raw reply related

* Re: auto merge bug
From: Jeff King @ 2013-03-05  9:03 UTC (permalink / raw)
  To: David Krmpotic; +Cc: git
In-Reply-To: <CAOFaZ+5F1BcWNU=AkcnS53bQt1VfAfsFjp9EvRCL=7kYiU1ejg@mail.gmail.com>

On Mon, Mar 04, 2013 at 05:46:48PM +0100, David Krmpotic wrote:

> We started working on a .NET app and the XML project file (.csproj)
> got corrupted (a few closing tag missing).
> 
> 79	     <Compile Include="SlovaricaForm.Designer.cs">
> 80	       <DependentUpon>SlovaricaForm.cs</DependentUpon>
> 81	+    <Compile Include="WebCamForm.cs">
> 82	+      <SubType>Form</SubType>
> 83	+    </Compile>
> 84	+    <Compile Include="WebCamForm.Designer.cs">
> 85	+      <DependentUpon>WebCamForm.cs</DependentUpon>
> 86	     </Compile>
> 
> between lines 80 and 81 there should be </Compile>
>
> [...]
>
> The problematic commit is here:
> 
> https://github.com/davidhq/logo_x/commit/e3e5fa4b60b7939999b2a8c44330312755b72f93

Thanks for an easy-to-reproduce report. The problem here is that your
.gitattributes file specifies the "union" merge driver for .csproj
(and other) files. From "git help attributes":

           union
               Run 3-way file level merge for text files, but take lines
               from both versions, instead of leaving conflict markers.
               This tends to leave the added lines in the resulting file
               in random order and the user should verify the result. Do
               not use this if you do not understand the implications.

Your <Compile> stanzas each end on an identical line. So it sees that
one side has:

  A
  B
  Z

and the other side has:

  C
  D
  Z

It realizes that the "Z" is common, so is not part of the conflict. But
in the normal 3-way merge case, the rest of it conflicts, so you get a
chance to inspect it. But with "union", it just silently concatenates
the conflicting bits.

I suspect you can run into other problems with "union" here, too,
because line order _does_ matter for you. It comes close to working if
both sides are just adding elements at the same level of the tree (as
you are here), but what about more complicated edits?

I think what you really want is an XML-aware merge tool that can see you
just added two independent <Compile>...</Compile> stanzas that can
co-exist (i.e., it could do a union, but at the level of XML tags, not
at the level of individual lines).  I do not know offhand of any such
tool (or for that matter, a good general XML-aware 3-way merge tool),
but if you had one, you could plug it in as a custom merge driver.

You might be able to get by with a version of the "union" driver that
asks the 3-way merge driver to be less aggressive about shrinking the
conflict blocks. For example, with this patch to git:

diff --git a/ll-merge.c b/ll-merge.c
index fb61ea6..61b1d4e 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -100,7 +100,6 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
 	}
 
 	memset(&xmp, 0, sizeof(xmp));
-	xmp.level = XDL_MERGE_ZEALOUS;
 	xmp.favor = opts->variant;
 	xmp.xpp.flags = opts->xdl_opts;
 	if (git_xmerge_style >= 0)

I think the merge will produce the results you are looking for. This
would have to be configurable, though, as it is a regression for
existing users of "union", which would want the duplicate-line
suppression (or maybe not; it will only catch such duplicates at the
beginning and end of the conflict hunk, so maybe it is sane to always
ask "union" to keep all lines).

I'd still worry about more complicated edits fooling "union", but at
least the simple cases would work.

In the meantime, I think you are better to drop those "merge"
gitattributes, and just let the regular three way merge generate a
conflict which you can inspect. For the merge in question, it yields:

  diff --cc Logo/Logo.csproj
  index 4113434,c681862..0000000
  --- a/Logo/Logo.csproj
  +++ b/Logo/Logo.csproj
  @@@ -67,17 -67,11 +67,25 @@@
        <Reference Include="System.Xml" />
      </ItemGroup>
      <ItemGroup>
  ++<<<<<<< HEAD
   +    <Compile Include="MainForm.cs">
   +      <SubType>Form</SubType>
   +    </Compile>
   +    <Compile Include="MainForm.Designer.cs">
   +      <DependentUpon>MainForm.cs</DependentUpon>
   +    </Compile>
   +    <Compile Include="SlovaricaForm.cs">
   +      <SubType>Form</SubType>
   +    </Compile>
   +    <Compile Include="SlovaricaForm.Designer.cs">
   +      <DependentUpon>SlovaricaForm.cs</DependentUpon>
  ++=======
  +     <Compile Include="WebCamForm.cs">
  +       <SubType>Form</SubType>
  +     </Compile>
  +     <Compile Include="WebCamForm.Designer.cs">
  +       <DependentUpon>WebCamForm.cs</DependentUpon>
  ++>>>>>>> bd1a059
        </Compile>
        <Compile Include="WordsSelectForm.cs">
          <SubType>Form</SubType>

where you can see that it "shrinks" the conflict hunk to not include the
line added by both sides (the file "</Compile>" after the conflict). But
by triggering a conflict, you can actually look at and fix it. That's
more work, of course.

Another alternate is to keep the "union" driver and just do better
testing of merges. Even with the stock 3-way driver, a merge that
auto-resolves is not necessarily correct (e.g., even if there are not
textual conflicts, there may be semantic ones).

-Peff

^ permalink raw reply related

* Re: auto merge bug
From: Jeff King @ 2013-03-05  9:12 UTC (permalink / raw)
  To: David Krmpotic; +Cc: git
In-Reply-To: <20130305090326.GC13552@sigill.intra.peff.net>

On Tue, Mar 05, 2013 at 04:03:26AM -0500, Jeff King wrote:

> You might be able to get by with a version of the "union" driver that
> asks the 3-way merge driver to be less aggressive about shrinking the
> conflict blocks. For example, with this patch to git:
> 
> diff --git a/ll-merge.c b/ll-merge.c
> index fb61ea6..61b1d4e 100644
> --- a/ll-merge.c
> +++ b/ll-merge.c
> @@ -100,7 +100,6 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
>  	}
>  
>  	memset(&xmp, 0, sizeof(xmp));
> -	xmp.level = XDL_MERGE_ZEALOUS;
>  	xmp.favor = opts->variant;
>  	xmp.xpp.flags = opts->xdl_opts;
>  	if (git_xmerge_style >= 0)
> 
> I think the merge will produce the results you are looking for. This
> would have to be configurable, though, as it is a regression for
> existing users of "union", which would want the duplicate-line
> suppression (or maybe not; it will only catch such duplicates at the
> beginning and end of the conflict hunk, so maybe it is sane to always
> ask "union" to keep all lines).

Here's what the patch would look like to make it non-configurable, but
to just trigger for the "union" case:

diff --git a/ll-merge.c b/ll-merge.c
index fb61ea6..fc33a23 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -83,7 +83,8 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
 			mmfile_t *src1, const char *name1,
 			mmfile_t *src2, const char *name2,
 			const struct ll_merge_options *opts,
-			int marker_size)
+			int marker_size,
+			int level)
 {
 	xmparam_t xmp;
 	assert(opts);
@@ -100,7 +101,7 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
 	}
 
 	memset(&xmp, 0, sizeof(xmp));
-	xmp.level = XDL_MERGE_ZEALOUS;
+	xmp.level = level;
 	xmp.favor = opts->variant;
 	xmp.xpp.flags = opts->xdl_opts;
 	if (git_xmerge_style >= 0)
@@ -129,7 +130,23 @@ static int ll_union_merge(const struct ll_merge_driver *drv_unused,
 	o.variant = XDL_MERGE_FAVOR_UNION;
 	return ll_xdl_merge(drv_unused, result, path_unused,
 			    orig, NULL, src1, NULL, src2, NULL,
-			    &o, marker_size);
+			    &o, marker_size, XDL_MERGE_MINIMAL);
+}
+
+static int ll_text_merge(const struct ll_merge_driver *drv,
+			 mmbuffer_t *result,
+			 const char *path,
+			 mmfile_t *orig, const char *orig_name,
+			 mmfile_t *src1, const char *name1,
+			 mmfile_t *src2, const char *name2,
+			 const struct ll_merge_options *opts,
+			 int marker_size)
+{
+	return ll_xdl_merge(drv, result, path,
+			    orig, orig_name,
+			    src1, name1,
+			    src2, name2,
+			    opts, marker_size, XDL_MERGE_ZEALOUS);
 }
 
 #define LL_BINARY_MERGE 0
@@ -137,7 +154,7 @@ static struct ll_merge_driver ll_merge_drv[] = {
 #define LL_UNION_MERGE 2
 static struct ll_merge_driver ll_merge_drv[] = {
 	{ "binary", "built-in binary merge", ll_binary_merge },
-	{ "text", "built-in 3-way text merge", ll_xdl_merge },
+	{ "text", "built-in 3-way text merge", ll_text_merge },
 	{ "union", "built-in union merge", ll_union_merge },
 };
 

^ permalink raw reply related

* Re: Fwd: Strange remote interaction
From: Javier Domingo @ 2013-03-05  9:46 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git@vger.kernel.org
In-Reply-To: <7v1ubuwhec.fsf@alter.siamese.dyndns.org>

> In a usual set-up, an access to git@server:javier/pfc will first
> locate the home directory for the user "git" (the token before "@"),
> and then its subdirectory javier/pfc, e.g. /home/git/javier/pfc,
> while an access to server:javier/pfc will first locate the home
> directory of whatever username the ssh connection uses by default
> (typically the local user but ~/.ssh/config may have "User"
> directive for the server) and then its subdirectory javier/pfc,
> e.g. /home/javier/javier/pfc.  These two may be different locations.
>
> Do these two commands show the same output?
>
>         $ git ls-remote git@server:javier/pfc refs/heads/master
>         $ git ls-remote server:javier/pfc refs/heads/master
>
> If the above conjecture is correct, I suspect they don't.

I have a gitolite setup there, so it is imposible the give the same
output. Anyways, as I don't have a user in the server machine, the
second fails.

$ git ls-remote git@server:javier/pfc
22692a2d69d3138b7ccebd64e72c66ea8bf69e9f HEAD
22692a2d69d3138b7ccebd64e72c66ea8bf69e9f refs/heads/master

It is the first time I encounter such a problem.

^ permalink raw reply

* Re: Configurable .gitignore filename?
From: David Aguilar @ 2013-03-05  9:59 UTC (permalink / raw)
  To: Jari Pennanen; +Cc: Matthieu Moy, git
In-Reply-To: <CACoicvKMWSjU6Lf-2PsCShzqGiX-=2xF9+W0EtrHUzWPU7-T_A@mail.gmail.com>

On Mon, Mar 4, 2013 at 7:47 AM, Jari Pennanen <jari.pennanen@gmail.com> wrote:
> 2013/3/4 Matthieu Moy <Matthieu.Moy@grenoble-inp.fr>:
>> There is already core.excludesfile, which does not replace the usual
>> .gitignore but comes in addition. The common use is a user-wide ignore
>> file, not a per-directory one.
>
> I'm actually aware of that. Problem is the normal .gitignore files
> must *not* be used in the second GIT_DIR at all, in my case it's for
> syncing so I need to sync almost all files (including stuff inside
> .gitignore), though I'd still like to retain some ignore files for
> second GIT_DIR, e.g. like in rsync the .rsync-filter file.

How about .git/info/exclude in the 2nd GIT_DIR?  Would that help?
-- 
David

^ permalink raw reply

* Re: Configurable .gitignore filename?
From: Jari Pennanen @ 2013-03-05 10:28 UTC (permalink / raw)
  To: David Aguilar; +Cc: Matthieu Moy, git
In-Reply-To: <CAJDDKr55ayTpzXPG3j5czY=-W08L8QjhMmjqWdRpoWO=MpHdyg@mail.gmail.com>

2013/3/5 David Aguilar <davvid@gmail.com>:
> On Mon, Mar 4, 2013 at 7:47 AM, Jari Pennanen <jari.pennanen@gmail.com> wrote:
>> I'm actually aware of that. Problem is the normal .gitignore files
>> must *not* be used in the second GIT_DIR at all, in my case it's for
>> syncing so I need to sync almost all files (including stuff inside
>> .gitignore), though I'd still like to retain some ignore files for
>> second GIT_DIR, e.g. like in rsync the .rsync-filter file.
>
> How about .git/info/exclude in the 2nd GIT_DIR?  Would that help?

The second GIT_DIR must not use the .gitignore files of the first
GIT_DIR, so it does not help.

Only way to skip the .gitignore files in git-add is to use "git add -f
." but that skips all excludes, including the .git/info/exclude. I
need to skip .gitignore files used by the other GIT_DIR and still have
some of ignore rules, IMO this is not possible at the moment.

^ permalink raw reply

* Re: "git commit" fails due to spurious file in index
From: Torsten Bögershausen @ 2013-03-05 10:40 UTC (permalink / raw)
  To: Robert Irelan; +Cc: git@vger.kernel.org
In-Reply-To: <2D9BD788B02ABA478C57929170AF952B7622B5@EXCH-MBX-3.epic.com>

On 04.03.13 19:15, Robert Irelan wrote:
> Hello all:
> 
> This is my first time posting to this mailing list, but it appears to
> me, through a Google search, that this is where you go to report what
> might be bugs. I'm not sure if this is a bug or not, but it is
> mysterious to me.
> 
> My git repository has this directory structure (I don't know if the file
> names are necessary or not; only the leaf directories contain files):
> 
>     $ tree -ad -I.git
>     .
>     └── admin_scripts
>         ├── integchk
>         │   ├── 2012
>         │   └── 2014
>         ├── jrnadmin
>         │   ├── 2012
>         │   └── 2014
>         └── logarchiver
>             ├── 2012
>             └── 2014
> 
>     10 directories
> 
> The last commit in this repo was a rearrangement of the hierarchy
> carried out using `git mv`.  Before, the directory structure went
> `admin_scripts/version/script_name` instead of
> `admin_scripts/script_name/version`.
> 
> Now I'm attempting to some new files that I've already created into the
> repository, so that the repo now looks like this (`setup/2012`
> contains files, while `setup/2014` is empty):
> 
>     $ tree -ad -I.git
>     .
>     └── admin_scripts
>         ├── integchk
>         │   ├── 2012
>         │   └── 2014
>         ├── jrnadmin
>         │   ├── 2012
>         │   └── 2014
>         ├── logarchiver
>         │   ├── 2012
>         │   └── 2014
>         └── setup
>             ├── 2012
>             └── 2014
> 
>     13 directories
> 
> Now, when I run 'git add admin_script/setup' to add the new directory to
> the repo and then try to commit, I receive the following message:
> 
>     $ git commit
>     mv: cannot stat `admin_scripts/setup/2012/setup': No such file or directory
> 
> The error message is correct in that `admin_scripts/setup/2012/setup`
> does not exist, either as a file or as a directory. However, I'm not
> attempting to add this path at all. Using grep, I've confirmed that the
> only place this path appears in any of my files is in `.git/index`.
> 
> Also, I can commit to other places in the repository without triggering
> any error. In addition, I can clone the repository to other locations
> and apply the problematic commit manually. This is how I've worked
> around the problem for now, and I've moved the repository that's
> exhibiting problems to another directory and started work on the cloned
> copy.
> 
> Why is this spurious path appearing in the index? Is it a bug, or a
> symptom that my repo has been somehow corrupted? Any help would be
> greatly appreciated.
> 
> Robert Irelan | Server Systems | Epic | (608) 271-9000
You have come to the right group.
It might be difficult to tell (at least for me) if there is a bug or a corruption,
May be some tests could help to bring more light into the darkness:

What does "git status" (in the problematic repo) tell you?
What does "git fsck" (in the problematic repo) tell you?
What does "git ls-files" (in both repos) tell you?

/Torsten

^ 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