login
Header Space

 
 

Re: [PATCH] Print a sane error message if an alias expands to an invalid git command

Previous thread: Re: [PATCH] add -C[NUM] to git-am by Jakub Narebski on Wednesday, February 7, 2007 - 7:54 pm. (3 messages)

Next thread: [BUG] Empty reflogs and "git log -g" by sbejar on Wednesday, February 7, 2007 - 9:21 pm. (6 messages)
To: <git@...>
Date: Wednesday, February 7, 2007 - 8:18 pm

A perfect example of the sort of trouble I'm having with git just
happened again.

I have a public bare repo on my machine that I have cloned to make a
private repo.  I just want to sync my branches on my public and
private repos.  I do not want to merge across branches, I just want to
"sync".

So, here's what I did.

In my private repo:

%  cat .git/remotes/origin
URL: /repos/git/project
Pull: refs/heads/master:refs/heads/origin
Pull: refs/heads/topic:refs/heads/topic

And this is the sequence of unfortunate events:

Starting on topic branch:

% git commit -a -m "Fix spacing rules"
% git checkout master
% git pull
[Won't pull non-fast-forward on my topic, so I try to get that synced.]
% git checkout topic
% git push
[ok, fine, seems good.]
[Now, instead of remembering to move back to master, I do this:]
% git pull
Trying really trivial in-index merge...
fatal: Merge requires file-level merging
Nope.
[AAAAGH!]
Merging HEAD with 37e229835103a11365b1e081f9b9987a88437e62
Merging:
e298e7f Skip rails in user nets
37e2298 Typofixen.
[NO NO NO!  This is not what I want!]
found 1 common ancestor(s):
a2ba736 Try #2: Fixed (mostly harmless) bugs in handling of time variable.
Auto-merging src/ast/tstD.cc
Auto-merging src/meth/XMLImporter.cc
Auto-merging src/meth/XMLImporter.hh
Auto-merging src/meth/tstXMLI.cc
merge: warning: conflicts during merge
CONFLICT (content): Merge conflict in src/meth/tstXMLF.cc
Auto-merging src/nat/MacroFanLoader.cc
Auto-merging src/nat/VPE.cc
Auto-merging src/nat/PnDef.cc
Auto-merging src/nat/VLExporter.hh
Auto-merging src/nat/tstMod.cc
Automatic merge failed; fix conflicts and then commit the result.

Ok, now I'm hosed.  Putting aside WHY git would do this to me (yes, I
know the answer is that I asked for it), on my topic branch I now have
tons of files listed when I do git status.  git diff shows tons of
stuff I don't want in my branch.

So, I edit the file and "fix" the merge conflict, then realize that
this is probably not what I wan...
To: Bill Lear <rael@...>
Cc: <git@...>
Date: Thursday, February 8, 2007 - 1:27 pm

Ok, others already replied, but here's a few rules to ease your mind in 
general:

 - First off: you can always _trivially_ get back to whatever state you 
   had before, as long as you committed it, and didn't have any dirty 
   state (uncommitted patches) in your working tree.

This is something that it's worth repeating, and even perhaps 
experimenting with to get really comfortable with. Why? Because once you 
learn to get back to any random state you had before, and once you are 
comfortable with that, you suddenly lose the fear of experimenting. 
Whatever you screw up, if you're confident you can get back, who cares?

So the "get back from a mistake" should probably be at the very front of 
our manuals and tutorials. I don't think it currently is, but it's 
actually not that hard. There's just one command to remember: "git reset", 
and the only issue you might ever have with it is:

 - make sure you're on the right branch first! If the problem you had is 
   that you're on the wrong branch, switch branches first! Don't try to 
   make the wrong branch "look right". But once you know you're on the 
   right branch, you know that "git reset" is your friend to getting it 
   anywhere you want.

 - do you want to throw away all your working tree changes (and if 
   you screwed up some git operation, the answer is usually "Yes!"). If 
   so, add the "--hard" flag. It's not on by default, exactly because it 
   *will* throw away all state in your tracked working tree, and reset it 
   to whatever you want to go back to.

 - exactly *what* do you want to go back to? The default is to go back to 
   the state at the last successful commit, but sometimes what you screwed 
   up was exactly the last commit (eg an unintentional "pull" that 
   actually succeeded), and then you need to tell it *what* to reset to.

That's really all there is to it. It's really simple, although especially 
the second point can take some practice to get right.

So NORMALLY, if you did something ...
To: Linus Torvalds <torvalds@...>
Cc: Bill Lear <rael@...>, <git@...>
Date: Thursday, February 8, 2007 - 4:12 pm

I usually undo a pull by throwing away just the merge commit by

        git reset --hard HEAD^

This seems to always get me back to the head commit I had previously, but I'm
wondering would git in some circumstances leave me with the commits I just pulled
and throw away my own work instead. Or is it guaranteed that I always reset
to the parent commit I had before the pull (i.e. ORIG_HEAD)?

Of course HEAD^ doesn't work the same with fast-forward merges, so it would
probably make more sense to just use ORIG_HEAD all the time.
-
To: Kalle Pokki <kalle.pokki@...>
Cc: Bill Lear <rael@...>, <git@...>
Date: Thursday, February 8, 2007 - 5:23 pm

Don't do this.

If the merge just fast-forwarded, you'll do the wrong thing.

So yes, it _works_, but it only works if you actually ended up having a 
real merge. In contrast, the ORIG_HEAD thing always works.

ORIG_HEAD is also particularly useful for doing things like "ok, what did 
I get from that pull?" especially when you track somebody elses work (in 
which case it will basically _always_ be a fast-forward). So I do

	gitk ORIG_HEAD..

in git almost every time I pull from Junio's git thing, just because it's 
a wonderful way to see what has changed, if you're interested in that kind 
of detail.

		Linus
-
To: Linus Torvalds <torvalds@...>
Cc: Kalle Pokki <kalle.pokki@...>, Bill Lear <rael@...>, <git@...>
Date: Thursday, February 8, 2007 - 6:03 pm

Yes, I know. But when looking at the history with gitk, it feels
quite intuitive to just get rid of the one new commit that appeared
on top of the "good" history. Without that kind of visualisation
I would surely always just use ORIG_HEAD as a reference.

Perhaps gitk could (optionally) also show ORIG_HEAD. That way we could
just do

        gitk --all

after a pull and see what got pulled, and everything else was already
there, too, if needed.
-
To: Kalle Pokki <kalle.pokki@...>
Cc: Linus Torvalds <torvalds@...>, Bill Lear <rael@...>, <git@...>
Date: Thursday, February 8, 2007 - 6:10 pm

git config alias.new "gitk --all --not ORIG_HEAD"

Would give you a new git subcommand:

	git new

which shows all of the new stuff, on all branches, but doesn't show
your prior commit history.

-- 
Shawn.
-
To: Shawn O. Pearce <spearce@...>
Cc: Kalle Pokki <kalle.pokki@...>, Linus Torvalds <torvalds@...>, Bill Lear <rael@...>, <git@...>
Date: Friday, February 9, 2007 - 3:21 pm

Yes, but what I meant was that gitk wouldn't stop at ORIG_HEAD,
but just display it as another branch head with a nice green tag.
Normally, displaying ORIG_HEAD would probably not be interesting,
but it might make sense with

        gitk --all

It would give more context to the pull than just

        gitk ORIG_HEAD..
-
To: Shawn O. Pearce <spearce@...>
Cc: Kalle Pokki <kalle.pokki@...>, Linus Torvalds <torvalds@...>, Bill Lear <rael@...>, <git@...>
Date: Thursday, February 8, 2007 - 9:48 pm

Aliases don't seem to be working for me; I'm using git 1.5.0-rc4.  Am
I doing something wrong?

&lt;tytso@candygram&gt; {/usr/projects/linux/linux-2.6}  [master]
37% git version
git version 1.5.0.rc4
&lt;tytso@candygram&gt; {/usr/projects/linux/linux-2.6}  [master]
38% git config alias.new "gitk --all --not ORIG_HEAD"
&lt;tytso@candygram&gt; {/usr/projects/linux/linux-2.6}  [master]
39% git new
git: 'new' is not a git-command

The most commonly used git commands are:
    add            Add file contents to the changeset to be committed next
    apply          Apply a patch on a git index file and a working tree
    archive        Creates an archive of files from a named tree
	...

&lt;tytso@candygram&gt; {/usr/projects/linux/linux-2.6}  [master]
40% tail .git/config 

[user]
        name = Theodore Ts'o
        email = tytso@mit.edu

[remote "iwlwifi"]
        url = http://bughost.org/repos/iwlwifi.git/
        fetch = +refs/heads/*:refs/remotes/iwlwifi/*
[alias]
        new = gitk --all --not ORIG_HEAD
					
-
To: Theodore Tso <tytso@...>
Cc: Kalle Pokki <kalle.pokki@...>, Linus Torvalds <torvalds@...>, Bill Lear <rael@...>, <git@...>
Date: Thursday, February 8, 2007 - 9:58 pm

Its not you.  The problem is 'gitk' is not an internal command,
nor is there a 'git-gitk'.  So we cannot execute it.  Instead we
are giving back a horrible error message.

Symlink git-gitk to gitk and it works.

Sorry about giving false hopes.  :-)

-- 
Shawn.
-
To: Junio C Hamano <junkio@...>
Cc: <git@...>
Date: Saturday, February 10, 2007 - 12:05 pm

Here are some patches to fix the horrible error message and to allow
aliases to expand to external shell commands.

                                        - Ted


-
To: Junio C Hamano <junkio@...>
Cc: <git@...>, Theodore Ts'o <tytso@...>
Date: Saturday, February 10, 2007 - 12:05 pm

Signed-off-by: "Theodore Ts'o" &lt;tytso@mit.edu&gt;
---
 git.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/git.c b/git.c
index 82a8357..c43d4ff 100644
--- a/git.c
+++ b/git.c
@@ -387,8 +387,15 @@ int main(int argc, const char **argv, char **envp)
 		done_alias = 1;
 	}
 
-	if (errno == ENOENT)
+	if (errno == ENOENT) {
+		if (done_alias) {
+			fprintf(stderr, "Expansion of alias '%s' failed; "
+				"'%s' is not a git-command\n",
+				cmd, argv[0]);
+			exit(1);
+		}
 		help_unknown_cmd(cmd);
+	}
 
 	fprintf(stderr, "Failed to run command '%s': %s\n",
 		cmd, strerror(errno));
-- 
1.5.0.rc4

-
To: <git@...>
Cc: Theodore Ts'o <tytso@...>, Alexandre Julliard <julliard@...>
Date: Saturday, February 10, 2007 - 12:50 pm

Thanks for your alias and diff patches.

I'll be away from the keyboard for most of today, so if the list
can do distributed QA (and debugging if necessary) before I
return that would be very appreciated ;-).

-
To: Junio C Hamano <junkio@...>
Cc: <git@...>, Theodore Ts'o <tytso@...>
Date: Saturday, February 10, 2007 - 12:05 pm

If the alias expansion is prefixed with an exclamation point, treat
it as a shell command which is run using system(3).

Signed-off-by: "Theodore Ts'o" &lt;tytso@mit.edu&gt;
---
 Documentation/config.txt |    6 ++++++
 git.c                    |   10 ++++++++++
 2 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 4e650af..de185d8 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -222,6 +222,12 @@ alias.*::
 	spaces, the usual shell quoting and escaping is supported.
 	quote pair and a backslash can be used to quote them.
 
+	If the alias expansion is prefixed with an exclamation point,
+	it will be treated as a shell command.  For example, defining
+	"alias.new = !gitk --all --not ORIG_HEAD", the invocation 
+	"git new" is eqvuialent to running the shell command 
+	"gitk --all --not ORIG_HEAD".
+
 apply.whitespace::
 	Tells `git-apply` how to handle whitespaces, in the same way
 	as the '--whitespace' option. See gitlink:git-apply[1].
diff --git a/git.c b/git.c
index c43d4ff..fc08396 100644
--- a/git.c
+++ b/git.c
@@ -159,6 +159,16 @@ static int handle_alias(int *argcp, const char ***argv)
 	alias_command = (*argv)[0];
 	git_config(git_alias_config);
 	if (alias_string) {
+		if (alias_string[0] == '!') {
+			trace_printf("trace: alias to shell cmd: %s =&gt; %s\n",
+				     alias_command, alias_string+1);
+			ret = system(alias_string+1);
+			if (ret &gt;= 0 &amp;&amp; WIFEXITED(ret) &amp;&amp; 
+			    WEXITSTATUS(ret) != 127)
+				exit(WEXITSTATUS(ret));
+			die("Failed to run '%s' when expanding alias '%s'\n", 
+			    alias_string, alias_command);
+		}
 		count = split_cmdline(alias_string, &amp;new_argv);
 		option_count = handle_options(&amp;new_argv, &amp;count);
 		memmove(new_argv - option_count, new_argv,
-- 
1.5.0.rc4

-
To: Junio C Hamano <junkio@...>
Cc: <git@...>
Date: Saturday, February 10, 2007 - 2:13 pm

Here's a revised patch which fixes a stupid spelling typo in the
documentation.  ("eqvuialent" --&gt; "equivalent")

From c16544aa786b0fb244fd974a22831a1210286ec5 Mon Sep 17 00:00:00 2001
From: Theodore Ts'o &lt;tytso@mit.edu&gt;
Date: Sat, 10 Feb 2007 10:50:58 -0500
Subject: [PATCH] Allow aliases to expand to shell commands

If the alias expansion is prefixed with an exclamation point, treat
it as a shell command which is run using system(3).

Signed-off-by: "Theodore Ts'o" &lt;tytso@mit.edu&gt;
---
 Documentation/config.txt |    6 ++++++
 git.c                    |   10 ++++++++++
 2 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 4e650af..e6e9409 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -222,6 +222,12 @@ alias.*::
 	spaces, the usual shell quoting and escaping is supported.
 	quote pair and a backslash can be used to quote them.
 
+	If the alias expansion is prefixed with an exclamation point,
+	it will be treated as a shell command.  For example, defining
+	"alias.new = !gitk --all --not ORIG_HEAD", the invocation 
+	"git new" is equivalent to running the shell command 
+	"gitk --all --not ORIG_HEAD".
+
 apply.whitespace::
 	Tells `git-apply` how to handle whitespaces, in the same way
 	as the '--whitespace' option. See gitlink:git-apply[1].
diff --git a/git.c b/git.c
index c43d4ff..fc08396 100644
--- a/git.c
+++ b/git.c
@@ -159,6 +159,16 @@ static int handle_alias(int *argcp, const char ***argv)
 	alias_command = (*argv)[0];
 	git_config(git_alias_config);
 	if (alias_string) {
+		if (alias_string[0] == '!') {
+			trace_printf("trace: alias to shell cmd: %s =&gt; %s\n",
+				     alias_command, alias_string+1);
+			ret = system(alias_string+1);
+			if (ret &gt;= 0 &amp;&amp; WIFEXITED(ret) &amp;&amp; 
+			    WEXITSTATUS(ret) != 127)
+				exit(WEXITSTATUS(ret));
+			die("Failed to run '%s' when expanding alias '%s'\n", 
+			    alias_string, alias_command);
...
To: Theodore Tso <tytso@...>
Cc: Junio C Hamano <junkio@...>, <git@...>
Date: Saturday, February 10, 2007 - 4:34 pm

Hi,


Here, you add 1 to alias string (though I would put spaces around the 

So, shouldn't you here, too?

It made me feel a little uneasy that we can execute _any_ command now, but 
I can only find one way to exploit this, when an attacker does not have 
shell access anyway: git-shell.

Ciao,
Dscho

-
To: Johannes Schindelin <Johannes.Schindelin@...>
Cc: Junio C Hamano <junkio@...>, <git@...>
Date: Saturday, February 10, 2007 - 8:13 pm

That's not how I code but it does seem to be the prevailing git coding

Yes, that makes the error message look a bit nicer.  I'll respin the

... and git-shell only allows git-receive-pack and git-upload-pack to
be called, with a single argument, and aliases aren't allowed to
override commands.  So we're safe here, I think.

						- Ted
-
To: Theodore Tso <tytso@...>
Cc: Junio C Hamano <junkio@...>, <git@...>
Date: Sunday, February 11, 2007 - 12:03 pm

Hi,


Yes, sorry. I have a modified git-shell, which allows the git wrapper, 
too, to allow setting the config. I'll just fix it here.

Ciao,
Dscho

-
To: Johannes Schindelin <Johannes.Schindelin@...>
Cc: Junio C Hamano <junkio@...>, <git@...>
Date: Sunday, February 11, 2007 - 12:21 pm

If all you've enabled is the ability to set the config, I think we're
still safe, since aliases can't override commands.  

Still there are enough config options that might be scary, either now
(the http.ssl* options) or in the future (someone might think that it
makes sense to set the post-commit, post-push, et. al hooks in the
config), that I wouldn't be particularly comfortable letting git-shell
have unrestricted access to set the config without having some
restriction about which config parameters were allowed to be set from
the restricted shell.  Why did you add that ability, out of curiosity?

						- Ted
-
To: Theodore Tso <tytso@...>
Cc: Johannes Schindelin <Johannes.Schindelin@...>, <git@...>
Date: Sunday, February 11, 2007 - 5:44 pm

I feel a bit uneasy to hear safety argument based on that
current restriction, since we might want to loosen it later.

-
To: Junio C Hamano <junkio@...>
Cc: Johannes Schindelin <Johannes.Schindelin@...>, <git@...>
Date: Sunday, February 11, 2007 - 11:56 pm

Loosen which restriction?

1) The ability for aliases to shadow existing git commands?
2) The ability for untrusted users to make arbitrary changes to the 
      config file?
3) The ability for untrusted users to execute arbitrary git commands via 
      git-shell?

You hjave to loosen at least 2 of the 3 current restrictions before
the ability to execute shell commands out of aliases becomes a problem
--- and I would argue that either (2) or (3) are things that we would
be insane to loosen at least to the point of allowing untrusted users
to make arbitrary changes to the config or execute arbitrary git
commands, since even today, they could do a huge amount of damage
already.

						- Ted
-
To: Theodore Tso <tytso@...>
Cc: Junio C Hamano <junkio@...>, Johannes Schindelin <Johannes.Schindelin@...>, <git@...>
Date: Monday, February 12, 2007 - 2:53 am

I agree, 2 and 3 are the real issue here, not 1.  1 is only an
issue for scripts which expect the plumbing to behave a certain
way, but doesn't, as the user has aliased the plumbing command.

-- 
Shawn.
-
To: Junio C Hamano <junkio@...>
Cc: Theodore Tso <tytso@...>, <git@...>
Date: Sunday, February 11, 2007 - 6:03 pm

Hi,


After seeing that it was a personal breakage only, I think we only have to 
keep the safety in mind, _iff_ we are to loosen it later, not before that.

For the moment, there are no safety issues, but real advantages, IMHO.

Ciao,
Dscho

-
To: Theodore Tso <tytso@...>
Cc: <git@...>
Date: Sunday, February 11, 2007 - 12:36 pm

Hi,


It seemed a good idea to make the description for gitweb a config 
variable, and I wanted the users to change that themselves. It no longer 
seems a good idea, so I will probably just undo my changes.

Ciao,
Dscho

-
To: Theodore Ts'o <tytso@...>
Cc: Junio C Hamano <junkio@...>, <git@...>
Date: Saturday, February 10, 2007 - 2:04 pm

ACK. This should also make it possible to do pipelines etc as aliases, 
although to be *really* useful we would probably have to have some way to 
specify where the arguments to the alias would go.

The more generic solution is obviously to just do it as external shell 
scripts (which can be named "git-xyzzy" so that you don't even need this 
kind of thing), but for the simple cases like gitk/qgit/xmerge/whatever, 
this approach by Ted seems to be a good way to get easy access to stuff 
that doesn't need anything fancier..

			Linus
-
To: Linus Torvalds <torvalds@...>
Cc: <git@...>, Jakub Narebski <jnareb@...>
Date: Thursday, February 8, 2007 - 5:57 pm

Well, I have read all of the very welcome advice and am comfortable
with all of it.

However, I still have a few open issues with the other branch of this
discussion, i.e., why can we not have an update operation that
respects branches in the first place, as 'git pull' seems to do, when
run from the master branch?  I do realize that the branch 'foo' in my
repo is different from the branch 'foo' in your repo.  However, I want
to track things, and "track" here is a very appropriate word.  Tracks
don't cross, and I don't want to cross my "logically equivalent"
branches (at least yet), even though, as Linus pointed out in great
detail, this is easy to undo (though, do see below for a qualification
of "easy").

So, why should I care?

Because, an ounce of prevention is worth a pound of cure.  So, if a
pound of undo is so very easy, then, in my mind, an ounce of
preventing the problem in the first place is at least 1/16th that.

When working in a peer-to-peer relationship, I often push and pull
with my peers, perhaps on a daily basis, perhaps weekly.  Just the
other day, my peer was the one who goofed up his branches and I pulled
them into my public repo, all tangled up, and did not realize it.
Thence pulled into my private repo, did lots of work, pushed back to
my public repo, and after more time intervened, realized something was
wrong.  It took a LOT of work (for me, I'm sure for others here it
would have been much, much less) for me to 1) figure out the genesis
of the problem, and 2) figure out how to undo it all without
destroying my subsequent work.  When we both do this, and merge
unexpectedly, at different points on one branch from a different
point on another, and then pollute each others' repos, it does become
rather ... well, annoying is the best way to put it.

In CVS, if I am on branch topic and say 'cvs update', it updates my
branch topic.  If I am on branch master and say 'cvs update', it
updates my branch master.  Etc., etc.  It doesn't matter that you move
from on...
To: Bill Lear <rael@...>
Cc: <git@...>, Jakub Narebski <jnareb@...>
Date: Thursday, February 8, 2007 - 6:13 pm

Actually, git does that all correctly for other branches too, but only in 
git-1.5.

It's one of the bigger UI warts that got fixed since the last release 
(although it got fixed by better config management, and as such you'll 
only *see* the fixes if you end up doing the initial clone with the new 
git version - if you use a new git version with an old repo, many - but 
not all - bad semantics will remain).

Considering how stable the -rc kernels are (and actually, git "master" in 
general), there's really very little reason to wait for the real release. 
Junio has been very careful, and I think a lot of the delay in 1.5 has 
been about trying to get all the new stuff that changes semantics subtly 
in before the release, so that Junio will not have to do any real user- 
visible changes later.

So it might be worth while trying out git-1.5.0-rc4, and seeing if that 
solves some of the UI issues for you guys. It changes things like where 
the default remote branches are, and makes the distinction between "my 
local copy of branch X" and "the remote branch X" much clearer, which has 
clearly been a UI problem.

			Linus
-
To: Linus Torvalds <torvalds@...>
Cc: Bill Lear <rael@...>, <git@...>, Jakub Narebski <jnareb@...>
Date: Friday, February 9, 2007 - 12:38 am

Heh, I do not work on kernels ;-)

Seriously, I think you are giving me a bit too much credit, but
I do agree that the tip of "master" tends to be very stable most
of the time.  This is especially true since some tagged releases
were followed up with immediate corrections for "oops, brown
paper bag" bugs in the past X-&lt;.

But the tip of "master" contains dubious change from time to
time (for example, I still haven't sorted out your "log -z"
stuff, which is already in my tree).

-
To: Linus Torvalds <torvalds@...>
Cc: <git@...>, Jakub Narebski <jnareb@...>
Date: Thursday, February 8, 2007 - 7:25 pm

With regard to the new version and old repos, am I correct in assuming
that we can upgrade our old repo (a bare one) to the new git by first
installing the new git, and then doing this:

% cd /repos/git
% mv project project.old_git
% git --bare clone project.old_git project

or is there something else we must do?


Bill
-
To: Bill Lear <rael@...>
Cc: <git@...>, Jakub Narebski <jnareb@...>
Date: Thursday, February 8, 2007 - 7:46 pm

I would actually suggest against that. Why? Because it will set a new 
"origin" (pointing to your old repo), and if you had something else 
before, that's probably not what you want.

Anyway, for the *shared* repositories, the git-1.5 changes really don't 
tend to make any difference anyway (since they don't even tend to really 
_care_ about things like origin branches - they are just used to push and 
pull from).

It's much more noticeable for the actual *development* repositories, 
because they are the ones that have "origin" pointing to something else.

And yes, for those development repositories, it's usually a good idea to 
just do

	mv project old-project
	git clone /repos/git/project
	cd project 
	.. work work work ..

and be happy.

You can also set up the new configurations by hand in an old repository, 
but there really doesn't tend to be a lot of reason to do that. Just as an 
example: the above was _literally_ what I did myself, just because I was 
too lazy to start editing .git/config files and setting things up in other 
ways (renaming origin branches etc).

In fact, I just did it the other day for my "sparse" repository (which is 
another project I started, but that is maintained by others these days). 
So here's a snippet from my bash history:

  ...
  837  mv sparse old-sparse
  838  cat old-sparse/.git/config
  839  git clone master.kernel.org:/pub/scm/linux/kernel/git/josh/sparse
  ...

(that "cat old-sparse/.git/config" was just because I had forgotten 
exactly where the origin of that repo was, so I did that cat just to do a 
cut-and-paste for the subsequent "git clone" ;^).

And yes, I did that just to get the nicer branch layout, something that my 
old sparse git repo didn't have, because I had set it up with an old 
version of git (and done some minimal manual maintenance).

			Linus
-
To: Bill Lear <rael@...>
Cc: Linus Torvalds <torvalds@...>, <git@...>, Jakub Narebski <jnareb@...>
Date: Thursday, February 8, 2007 - 7:33 pm

In the case of a bare repo, there isn't anything to do.

-- 
Shawn.
-
To: Shawn O. Pearce <spearce@...>
Cc: Linus Torvalds <torvalds@...>, <git@...>, Jakub Narebski <jnareb@...>
Date: Thursday, February 8, 2007 - 7:40 pm

So, I assume I need to tell our developers that once we have installed
the new git, they will need to set aside their old repos and just
clone again from our company repo?


Bill
-
To: Bill Lear <rael@...>
Cc: Shawn O. Pearce <spearce@...>, <git@...>, Jakub Narebski <jnareb@...>
Date: Thursday, February 8, 2007 - 8:17 pm

Not unless they want to take advantage of *all* the new features.

The new version of git will work fine with old repositories, both on the 
"server" side and the "user" side. And people can use a lot of the new 
features even if they do nothing at all.

But for the _specific_ case of having a clearly separated "local branch" 
vs "remote branch" case, you do need to make that distinction clear when 
you create the repository (unless you want to get really down and dirty 
with the repo and just modify it yourself: certainly possible but 
generally just not worth the effort since it's just easier to clone a new 
one instead).

So it's really a matter of how you use it. Switching to a new version of 
git on the "server side" (ie the shared repository operations) won't 
really affect anything at all. 

		Linus
-
To: Bill Lear <rael@...>
Cc: Shawn O. Pearce <spearce@...>, Linus Torvalds <torvalds@...>, <git@...>, Jakub Narebski <jnareb@...>
Date: Friday, February 9, 2007 - 4:58 am

Hint:
If a developer has some relevant data in his old private repository, he can always
pull from old to new repository there after he clones from the public repository.

This way you won't lose any data in the conversion.

-- 
MST
-
To: Bill Lear <rael@...>
Cc: Shawn O. Pearce <spearce@...>, Linus Torvalds <torvalds@...>, <git@...>
Date: Thursday, February 8, 2007 - 8:03 pm

Nope.


1. New git works with old repositories, and would continue to work.
Nevertheless you need new layout and new configuration to make use
of some new features.


2. They need to clone _their own_ repositories. It's the simplest
way, but


3. You can simply

 a) convert remotes configuration from .git/remotes/origin file
    to .git/config using remotes2config.sh script in contrib area
    of git, or http://repo.or.cz/w/git.git?a=blob_plain;f=contrib/remotes2config.sh

 b) hand edit remotes configuration to use globbing for refspec,
    and per branch configuration

If old repository was _not_ cloned with --use-separate-remote (using
separate remote layout), you would also have to:

 c) move branches from old layout to new layout using "git branch -m"
    command: 'refs/heads/origin' branch to 'refs/remotes/origin/master',
    all branches except 'master' (refs/heads/master) from 
    'refs/heads/&lt;branch&gt;' to 'refs/remotes/origin/&lt;branch&gt;'.

That's all. You have new layout and new configuration without re-cloning.

-- 
Jakub Narebski
Poland
-
To: Bill Lear <rael@...>
Cc: Linus Torvalds <torvalds@...>, <git@...>, Jakub Narebski <jnareb@...>
Date: Thursday, February 8, 2007 - 7:50 pm

Right.  Otherwise they need to do the config changes by hand in their
existing repository, which may be annoying/tedious/painful/difficult,
depending on your knowledge level with git.

You can actually use the old developer repositories with the newer
Git without doing anything specific to upgrade them.  Its just that
1.5.0 sets up the initial config of the repository differently,
and that's exactly the change in functionality you are looking for.

They can save their old topic branches (if they are important)
by doing something like:

	mv proj old_proj
	git clone git://server/proj proj
	cd proj
	git fetch ../old_proj topicA:topicA [topicB:topicB ...]

at which point ../old_proj can be tossed.

-- 
Shawn.
-
To: Linus Torvalds <torvalds@...>
Cc: <git@...>, Jakub Narebski <jnareb@...>
Date: Thursday, February 8, 2007 - 6:33 pm

Ok, very reasonable.  I've been our corporate guinea pig, so I'll give
this a whirl.  One thing I'm very, very happy about in git is the
ability to quickly experiment.  Believe it or not, I have solved
actual git problems in our company by doing just that.  Of necessity,
it's largely my complaints and problems that are aired here, though.


Bill
-
To: Bill Lear <rael@...>
Cc: Linus Torvalds <torvalds@...>, <git@...>
Date: Thursday, February 8, 2007 - 6:29 pm

Bill Lear wrote:
[cut]

With git 1.5.0-rc4 cloned repository, with globbing refspecs for origin
you don't have the problem. When you are on branch 'master', "git pull"
fetches and merges 'origin/master' into 'master'. When on any other
branch, "git pull" would fetch only (unless configured otherwise).

Note: you cannot pull into 'master' if you are not on 'master' because

In CVS branches are totally f**ked up. And enforced update before commit 


So do fetch, and do pull only when changes are ready...

RTFM. Take a look at http://git.or.cz/gitwiki/GitLinks namely section
"Seminars and presentations", read new Git User's Manual also at
http://www.fieldses.org/~bfields/git-user-manual.html, browse GitWiki.

By the way, the workflow looks slightly different if you pull directly
from one another (A pulls or fetches from B, B pulls or fetches from A),
and if you have one central public bare repository (A pulls or fetches
from 'public' and pushes her changes to 'public', B pulls or fetches
from 'public' and pushes his changes to 'public'). In the latter git
asks you to pull (fetch) before pushing if you are not up to date. Notice
that it is on push, not on commit!


We should really update http://git.or.cz/gitwiki/GitWorkflows ...
but how to make diagrams: ASCII art is hard because it needs monospace,
upload of images attachements is not possible...
-- 
Jakub Narebski
Poland
-
To: Bill Lear <rael@...>
Cc: <git@...>
Date: Wednesday, February 7, 2007 - 8:22 pm

Hi,


git reset --hard

It's probably explained in the new user manual (I did not check).

Ciao,
Dscho

-
To: Johannes Schindelin <Johannes.Schindelin@...>
Cc: <git@...>
Date: Wednesday, February 7, 2007 - 8:24 pm

Hmm ... from my topic branch:

% git reset -hard
Usage: /usr/bin/git-reset [--mixed | --soft | --hard]  [&lt;commit-ish&gt;]


Bill
-
To: Bill Lear <rael@...>
Cc: <git@...>
Date: Wednesday, February 7, 2007 - 8:25 pm

Hi,


Please use two dashes: "--" instead of "-".

Ciao,
Dscho

-
To: Johannes Schindelin <Johannes.Schindelin@...>
Cc: <git@...>
Date: Wednesday, February 7, 2007 - 8:34 pm

My apologies.  That does seem to work better...


Bill
-
To: Bill Lear <rael@...>
Cc: <git@...>
Date: Wednesday, February 7, 2007 - 8:48 pm

Because you told it to.

      %  cat .git/remotes/origin
      URL: /repos/git/project
      Pull: refs/heads/master:refs/heads/origin
      Pull: refs/heads/topic:refs/heads/topic

It tells "git pull" to drive "git fetch" to copy their master to
your origin and overwrite your topic with their topic, and then
merge their master to whatever branch you are currently on.

The sane/safe thing to do in the traditional layout (I'll talk
about non-traditional one in a second) is:

 - do your 'pull' only and always while on your 'master' and not
   anywhere else.

 - never build on a branch that appears on the RHS of ':'.

This layout is convenient when you always do fetches and pulls
while on 'master', but has burned enough people.  So what people
on the list seem to recommend is to use a separate remote layout
in the repository.

The principle is:

 * The branches you work on in the repository are kept in refs/heads/

 * Copies of branches from other repositories (it does not
   matter who is in control of them -- some of them may be your
   repository) are kept in refs/remotes/&lt;symbolic name&gt;.

So the current "git clone" (if you are using 1.4.4 series, you
can say "git clone --use-separate-remote") creates something
like this instead:

      URL: /repos/git/project
      Pull: refs/heads/master:refs/remotes/origin/master
      Pull: refs/heads/topic:refs/remotes/origin/topic

(git-clone from 1.5.0 does not actually make remotes/origin file
in .git/ that has the above -- it creates the moral equivalent
in .git/config).

So whatever you do the first step of "git pull", which is "git
fetch", will _not_ overwrite the current branch.

In order to prevent merging their 'master' into your 'topic'
when you are on 'topic', git-fetch/git-pull from 1.5.0 uses
further safety which is left by 'git clone'.  The real
configuration created by 'git clone' looks like this:

	[remote "origin"]
        	url = /repos/git/project
                fetch = refs/heads/*:refs/remote...
To: Junio C Hamano <junkio@...>
Cc: <git@...>
Date: Thursday, February 8, 2007 - 12:28 am

I think this should go to git-pull/git-clone man pages. Personaly for me this 
post dispels dark magic about git-pull's merging logic. I always did 
git-fetch and then git-pull . &lt;some-branch&gt; to control what and where should 
be merged.
-
To: Alexander Litvinov <litvinov2004@...>
Cc: <git@...>, Bill Lear <rael@...>
Date: Thursday, February 8, 2007 - 8:53 pm

Fair enough.  But I am known to be very bad at writing, so I
would ask the list to proofread this to see if it makes sense,
and prefereably rewrite it to make it easier to understand.

I think it is technically accurate -- I just do not know if I am
not writing enough, leaving certain necessary things unsaid,
because I assumed (wrongly) too much knowledge on the reader's
side.


diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index a81d68c..94478ed 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -33,6 +33,60 @@ include::urls.txt[]
 
 include::merge-strategies.txt[]
 
+DEFAULT BEHAVIOUR
+-----------------
+
+Often people use `git pull` without giving any parameter.
+Traditionally, this has been equivalent to saying `git pull
+origin`.  However, when configuration `branch.&lt;name&gt;.remote` is
+present while on branch `&lt;name&gt;`, that value is used instead of
+`origin`.
+
+In order to determine what URL to use to fetch from, the value
+of the configuration `remote.&lt;origin&gt;.url` is consulted
+and if there is not any such variable, the value on `URL: ` line
+in `$GIT_DIR/remotes/&lt;origin&gt;` file is used.
+
+In order to determine what remote branches to fetch (and
+optionally store in the tracking branches) when the command is
+run without any refspec parameters on the command line, values
+of the configuration variable `remote.&lt;origin&gt;.fetch` are
+consulted, and if there aren't any, `$GIT_DIR/remotes/&lt;origin&gt;`
+file is consulted and its `Pull: ` lines are used.
+In addition to the refspec formats described in the OPTIONS
+section, you can have a globbing refspec that looks like this:
+
+------------
+refs/heads/*:refs/remotes/origin/*
+------------
+
+A globbing refspec must have a non-empty RHS (i.e. must store
+what were fetched in tracking branches), and its LHS and RHS
+must end with `/*`.  The above specifies that all remote
+branches are tracked using tracking branches in
+`refs/remote...
To: Junio C Hamano <junkio@...>
Cc: <git@...>, Bill Lear <rael@...>
Date: Thursday, February 8, 2007 - 11:32 pm

It is cleary enought for me to understand. Thanks a lot.
-
To: Junio C Hamano <junkio@...>
Cc: <git@...>
Date: Thursday, February 8, 2007 - 11:27 am

This I understand, and can follow.  Sorry, but there my comprehension
stops.  Lots of confusion and befuddlement follow.  Thank you in

This I don't quite understand.  So, if it is on the LHS, it is ok?
But, if it is ALSO on the RHS it is not?

So, this:

      Pull: refs/heads/topic:refs/heads/topic

really means don't don't work on a branch named topic in this
repository?

I assume by "build on" you mean "work, compile, check stuff in,

I don't currently have any 'refs/remotes' of any sort, so I guess you
mean that the new principle, using git clone --use-separate-remote

So, using 1.4.4 series, or 1.5, the "sane" way to work in git

I assume by this you mean that if I do the separate remote trick, I
will not shoot myself by doing a 'git pull' while on my topic branch,

Ok, so if I am on master, I do this:

[master] % git pull

and this will fetch the remote master and merge it to my master, and
fetch the remote topic and merge it to my local topic.

While, if I am on my topic branch, if I do this:

[topic] % git pull

it sill fetches from the remote master and the remote topic, but will
not merge at all.

Could you verify if I have stated your position correctly?

If I am, this still seems bizarre.  I really just want a way to sync
two repos that works consistently, and is invoked consistently, no
matter what branch I am currently on.  And, again, by "sync", I just
mean no cross-branch merging --- no "crossing of the streams".  Even
if it were limited to syncing the current branch only, that would be
ok, but this variable behavior seems rather odd and confusing.  In
other words, I just want to type the equivalent of 'git sync' and have
it work, and not have to give a branch name, or be in the "right
place" for it to work as I expect.

Thus, I don't want to have to think "oh, I'm on my topic branch, and
if I really want to sync from my remote repo, I need to get on my
master branch".  It seems that the only difference in the "insane" way
I was doing things a...
To: Bill Lear <rael@...>
Cc: Junio C Hamano <junkio@...>, <git@...>
Date: Thursday, February 8, 2007 - 7:24 pm

It means to fetch the remote's branch "refs/heads/topic" and store the
current head in _your_ "refs/heads/topic" as a tracking branch, but only
if it's a fast-forward. Yes, I know it says "Pull:", but it's really
about fetching.

You can then merge the result of that fetch into your current branch. So
what you want is something like:

Pull: refs/heads/topics:refs/heads/remote-topic

which will use 'remote-topic' as a tracking branch, always updating it
at fetch time to reflect the remote's version of topic. You can then
merge remote-topic into your local topic branch by fetching+merging, or

I believe he means 'store commits in'. That is, the RHS of the refspec
should be used solely for tracking fetches from the remote. If you make
a commit on top of it (either directly, or by doing a merge), then the
fetch must either throw away your commits, or fail to fast-forward to

Yes. It will basically give you a RHS of "refs/remotes/$REMOTE/$BRANCH"
to track a branch $BRANCH coming from $REMOTE (generally "origin"); it's
a more organized way of doing what I mentioned above (RHS of

Most people think so (though I think Junio actually still uses the
traditional layout, because he finds it more convenient). Note that in
1.5, --use-separate-remote is the default (the option is still

No, you will not shoot yourself because the fetch part of the pull will
store the remote's position of 'refs/heads/topic' at
'refs/remotes/origin/topic' instead of trying to overwrite the branch
you've been working on.

As an additional bonus, you can put this in your .git/config:

[branch "topic"]
remote = origin
merge = refs/heads/topic

which means "When I'm on my refs/heads/topic branch and I issue a
git-pull without any arguments, do a git-fetch on origin. Then, merge
what the remote end calls refs/heads/topic into my current branch."
Without this, git-pull in v1.4.* will attempt to merge the remote's

That is correct. If you add the config I mentioned above, you can get
the "automatically mer...
To: Jeff King <peff@...>
Cc: Junio C Hamano <junkio@...>, <git@...>
Date: Thursday, February 8, 2007 - 7:32 pm

A very good point, and an obvious one in retrospect.  I guess I will
be entirely satisfied if I am on branch X I can just say 'git pull'
and it will NOT pull from any other branch.  You have added to my
understanding on this, and thank you for taking the time.


Bill
-
Previous thread: Re: [PATCH] add -C[NUM] to git-am by Jakub Narebski on Wednesday, February 7, 2007 - 7:54 pm. (3 messages)

Next thread: [BUG] Empty reflogs and "git log -g" by sbejar on Wednesday, February 7, 2007 - 9:21 pm. (6 messages)
speck-geostationary