Git development
 help / color / mirror / Atom feed
* Re: [RFC] Submodules in GIT
From: Andy Parkins @ 2006-12-02  9:22 UTC (permalink / raw)
  To: git
In-Reply-To: <Pine.LNX.4.64.0612011540010.3695@woody.osdl.org>

On Saturday 2006, December 02 00:12, Linus Torvalds wrote:

> 	100644 blob 08602f522183dc43787616f37cba9b8af4e3dade	xdiff-interface.c
> 	100644 blob 1346908bea31319aabeabdfd955e2ea9aab37456	xdiff-interface.h
> 	040000 tree 959dd5d97e665998eb26c764d3a889ae7903d9c2	xdiff
> 	050000 link 0215ffb08ce99e2bb59eca114a99499a4d06e704	xyzzy
>
> where that 050000 is the new magic type (I picked one out of my *ss: it's
> not a valid type for a file mode, so it's a godo choice, but it could be
> anythign that cannot conflict with a real file), which just specifies the
> "link" part. The SHA1 is the SHA1 of the commit, and the "xyzzy" is
> obviously just the name within the directory of the submodule.

Can I argue that the hash in that object should actually be to a real object 
in the supermodule repository rather than a link?  Then THAT object would 
contain the hash?  So in your above example:

  100644 blob 08602f522183dc43787616f37cba9b8af4e3dade	xdiff-interface.c
  100644 blob 1346908bea31319aabeabdfd955e2ea9aab37456	xdiff-interface.h
  040000 tree 959dd5d97e665998eb26c764d3a889ae7903d9c2	xdiff
  050000 link a7f26495b7b7e32bf949efbd91ee32267b792cba	xyzzy

And then the local object a7f26495b7b7e32bf949efbd91ee32267b792cba would 
contain your original hash 0215ffb08ce99e2bb59eca114a99499a4d06e704.

The reason I suggest this as without out it the "link" object is the only hash 
in the tree that doesn't point to a valid object.  The contents of objects is 
entirely arbitrary so it's perfectly okay for that to contain a hash that 
won't dereference to a real object in the supermodule.

The main advantage of this is (I think) that git-prune, git-fsck, and whatever 
else relies on tree objects all being real, don't need to be modified at all.

It also gives you scope to later add fields to the "link" object if you 
wanted.


Andy
-- 
Dr Andrew Parkins, M Eng (Hons), AMIEE

^ permalink raw reply

* Re: [RFC] Submodules in GIT
From: Andy Parkins @ 2006-12-02  9:27 UTC (permalink / raw)
  To: git
In-Reply-To: <Pine.LNX.4.64.0612011621380.3695@woody.osdl.org>

On Saturday 2006, December 02 00:33, Linus Torvalds wrote:

> Yes, you do need to have a list of submodules somewhere, and you'd need to
> maintain that separately. One of the results of having the submodules be

Why?  You just recursively search for every "link" object in the supermodule.  
That tells you which submodules you need and where they should be.

During a supermodule clone, it can tell the client end to start a new clone 
with the correct path because it knows what the local path is at that moment.



Andy
-- 
Dr Andrew Parkins, M Eng (Hons), AMIEE

^ permalink raw reply

* Re: [PATCH] Make git-commit cleverer - have it figure out whether it needs -a automatically
From: Carl Worth @ 2006-12-02  9:45 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Andy Parkins, git
In-Reply-To: <7vbqmmzplm.fsf@assigned-by-dhcp.cox.net>

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

On Sat, 02 Dec 2006 00:09:09 -0800, Junio C Hamano wrote:
> But I think the problem with this 'cleverer' commit runs
> deeper.

I agree. Being too clever is a problem.

It's very helpful to estimate usability and learnability by the length
of prose needed to describe a command.

>  1. With paths, "git commit <paths>" means "forget for a moment
>     the changes I staged to be committed, and make a commit that
>     includes only these paths (i.e. the new commit and the
>     current HEAD are different at exactly these paths and
>     nowhere else, and the new commit has contents from the
>     working tree for these paths)".
>
>  2. Without paths, "git commit" means "make a commit out of
>     everything I have told you to commit (aka 'staged') so far".
>     The primary ways to tell git to stage contents are "git
>     add/rm/mv".  But as a short-hand, you can say "git commit
>     -a" to ask the command to place all the changes in the
>     working tree in the changeset to be committed before making
>     the new commit.

Junio, thanks so much for these descriptions. They help ground the
discussion quite nicely, (and will also contribute to improved
documentation).

Here's pseudo-code for the above descriptions:

	if (command-line has paths) {
		ignore staging area, commit named files
	else {
		if (commit -a)
			update all files into staging area
		commit staging area
	}

One problem I see in that is that the primary distinction is made
based on what appears on the command-line, rather than what job the
user is trying to perform. Also, "commit -a" is define in terms of the
staging area, even though the staging area is basically irrelevant to
this operation, (just as it is in the case of a commit with paths).

So I would re-factor that in a way that focuses on what the user is
trying to do:

	if (! doing a staged commit) {
		if (file list is empty)
			file list = all tracked files
		commit file list
	} else {
		commit staging area
	}

This brings the description of "commit -a" and "commit files..."
together, (which I think are conceptually more related than "commit
-a" is to a commit of the staging area, (and yes, this ignores the
history of the implementation). What we're talking about is how to
document what the user wants to do, not how the implementation does
it.

Notice also that "staging area" never appears in the description of
the else clause, (which is good since the conceptual use of these
commands does not involve staging).

So translating my re-factored version back into prose, we might get:

   commit <paths>
   commit -a

	Commit the working-tree contents of the named <paths>, (or all
	tracked paths for -a). Files which no longer exist in the
	working tree will be removed. New files to be tracked must be
	added with "git add".

   commit

	Commit the content that exists in the staging area. The
	staging area initially consists of the contents of the most
	recent commit, but can be modified with the "git add",
	"git rm", and "git mv".

So that's shorter. I think it's also more clear and focused on what
the user wants to do without being any less accurate.

It doesn't make it obvious that "commit -a" is the most common form
and what users should look at first. So what I'd like to see is the
semantic changes that would allow us to document this as:

   commit
   commit <paths>

	Commit the working-tree contents of all tracked paths, (or
	just the specific paths listed). Files which no longer exist
	in the working tree will be removed. New files to be tracked
	must be added with "git add".

   commit --staged

	Commit the content that exists in the staging area. The
	staging area initially consists of the contents of the most
	recent commit, but updated content from the working tree can
	be placed into it with "git stage <paths>".

-Carl

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

^ permalink raw reply

* Re: [PATCH] make 'git add' a first class user friendly interface to the index
From: Jakub Narebski @ 2006-12-02  9:52 UTC (permalink / raw)
  To: git
In-Reply-To: <7vpsb36yem.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:

>  - We keep the word "index", and not reword it to "stage" in the
>    names of commands and options.  "to stage" is very good verb
>    to explain the _concept_, but there is no need to use
>    inconsistent wording Porcelain-ish and plumbing use to
>    describe the entity used for staging.
> 
>    (1) New people need to learn the new concept anyway, and they
>        are intelligent enough to learn what that new concept has
>        been called for a long time in git-land at the same time.
> 
>        "The index" is the receiver of new contents to be staged;
>        conversely, "to stage" is the act of registering contents
>        to the index.

I think we should refer to "the index" as "the staging area [for commits]",
at least the first time (it is a bit longish to use it later).
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git


^ permalink raw reply

* Re: [RFC] Submodules in GIT
From: Andy Parkins @ 2006-12-02 10:04 UTC (permalink / raw)
  To: git
In-Reply-To: <20061201220821.GL18810@admingilde.org>

On Friday 2006, December 01 22:08, Martin Waitz wrote:

> > echo $SUBMODULE_HASH >
> > submodule/.git/refs/supermodules/commit$SUPERMODULE_HASH
>
> I guess you are aware that you have to scan _all_ trees inside _all_
> supermodule commits for possible references.

No you don't; you do it as part of the appropriate normal operations.

 * supermodule commit - scan the current tree for "link" objects in the
   tree.  If you find one write the reference in the submodule.
 * adding a new submodule - if this is a new submodule there can't be any
   references in the supermodule already.
 * cloning a supermodule, every new commit that gets written in the 
   supermodule gets checked from "link" objects.

> So what do you do with deleted submodules?
> You wouldn't want them to still sit around in your working directory,
> but you still have to preserve them.

Now that is a tricky one.  Mind you, I think that problem exists for any 
implementation.  I haven't got a good answer for that.


Andy

-- 
Dr Andrew Parkins, M Eng (Hons), AMIEE

^ permalink raw reply

* Re: [PATCH] make 'git add' a first class user friendly interface to the index
From: Jakub Narebski @ 2006-12-02 10:11 UTC (permalink / raw)
  To: git
In-Reply-To: <7vlklq20n5.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:

> By the way, aren't people disturbed that "git rm" does not
> default to "-f" -- I rarely use the command myself but that
> makes it feel even more awkward that "git rm foo" does not
> remove the file "foo".

But _only_ if file is unmodified. I think that "git rm" meaning
"remove this file from version control, but not from working area"
is a good thing; if you want to remove file, just /usr/bin/rm it.
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git


^ permalink raw reply

* using xdl_merge(), was Re: Resolving conflicts
From: Johannes Schindelin @ 2006-12-02 10:49 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Linus Torvalds, git
In-Reply-To: <7vejri20mf.fsf@assigned-by-dhcp.cox.net>

Hi,

On Fri, 1 Dec 2006, Junio C Hamano wrote:

> Linus Torvalds <torvalds@osdl.org> writes:
> 
> > [ Tangentially related.. ]
> >
> > On Thu, 30 Nov 2006, Wink Saville wrote:
> >> 
> >> Earlier had a problem with git wanting merge but didn't have it and
> >> couldn't figure out which package it was in Ubuntu:( So I symlinked merge
> >> to kdiff3 which worked at the time:
> >
> > Btw, what's the status of the xdl_merge() thing in "pu"?
> 
> I haven't looked at the code any further than minimally checking
> its external interface to be able to interface it with
> merge-recursive and no more.  Namely:
> 
>  - I haven't read the algorithm to judge its correctness;

With my track record of blamable patches, that should be done by somebody 
else than me.

>  - I haven't looked for leaks;

Neither have I.

>  - I haven't used the resulting merge-recursive in any real
>    merge; some of our tests do rely on a correctly working
>    merge-recursive, so it is not like the algorithm is always
>    emitting "boo ha ha" and returning no conflicts ;-).

I have. There is a subtle difference to merge, but it might be serious 
enough:

diff --just-made-up orig new1
 Hello world
+This conflicts
 Bye bye world
+This does not conflict

diff --just-made-up orig new2
 Hello world
+This is different in new2
 Bye bye world

If my interpretation of the test is correct, then the last line of new1 
will _not_ conflict with xdl_merg( as is, but with RCS merge. I will fix 
that shortly.

>  - I haven't benched it to see how much performance is gained
>    by bypassing an extra fork+exec.

There is room for improvement, but I get shaky numbers betwen 31% and 
118% (runtime git-merge-recursive xdl_merge() / RCS merge). These are 
extremely ad-hoc generated numbers, so handle with care. My 
gut feeling is that a few improvements in the code will give a rough 
30%-50% in the average case.

These improvements include not parsing orig twice, and compacting the 
merge script before applying it.

> Among the four patches Johannes sent out to the list and Davide,
> one was already in his original patch I have in 'pu', another
> makes the same return value change I did myself when interfacing
> the code with merge-recursive.

Yeah, sorry. When I sent the patches, I did not see xdl_merge() in pu.

> I have queued the remaining two in 'pu', so there should be nothing 
> missing.
> 
> One of them is marked as "fix off by one error" but it was about
> more than off by one (the code walks two arrays using one index
> for each, but the original code incorrectly used the same index
> to access both arrays at one point, which was also fixed).  I
> did mind the lack of explanation and wanted to reword the log
> message, but as I said, I haven't read the algorithm to
> understand what the code is doing enough, so I cannot write
> anything useful there yet X-<, which is one of the reasons why
> it is still queued in 'pu'.

Sorry again. I fixed that bug in the middle of the night, and committed 
the next day, trying to deduct what I fixed.

Again, I do not see the patches in pu, though. I will concoct a nice 
commit message later today, okay?

Linus, you raised the concern that git-cvsserer still relies on 
external merge. I'd just bastardize git-merge-one-file to work as a 
replacement of RCS merge (just like git apply works as a replacement of 
patch), in addition to its original function.

Ciao,
Dscho

^ permalink raw reply

* Re: [RFC] Submodules in GIT
From: Josef Weidendorfer @ 2006-12-02 11:32 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: sf, git, Martin Waitz
In-Reply-To: <Pine.LNX.4.64.0612011540010.3695@woody.osdl.org>

On Saturday 02 December 2006 01:12, Linus Torvalds wrote:
> On Sat, 2 Dec 2006, Josef Weidendorfer wrote:
> > 
> > So you are for a global submodule namespace in supermodule repositories,
> > do I understand correctly?
> > 
> > Otherwise, how would you specify the submodules at clone time given the
> > ability that submodule roots can have relative path changed arbitrarily
> > between commits?
> 
> The only _true_ namespace would be the SHA1 of the commit (and maybe allow 
> a pointer to a tag too, but the namespace ends up being the same).

I am not so sure about this.
Perhaps we want the namespace to be more than the space of commit ids.

Suppose you have some superproject which uses two compiler major versions
(GCC 3 and GCC 4) as submodules because you want to have your regression
test suite run with both major versions.
So you would have a submodule at path "gcc3/" and "gcc4/" in your supermodule.
As both the gcc 3 and gcc 4 are branches from the same project, the submodule
links will go into a connected DAG (suppose GCC uses git).

Alone from the commit link, it is not easy to see to what submodule it belongs
to (at least from a practical point of view).

So it actually _is_ more information if the proposed link objects in the supermodule
contain some submodule ID they belong to. They only need be unique in the scope of
the superproject (not really globally unique).

So another argument for submodule names: Merging. Otherwise, how do you decide
to which submodule a link belongs to, especially in the scope of above example?

> How to _find_ a repository that contains that SHA1 must be left to higher 
> levels. After all, repositories move around, and the place you found them 
> originally is not a stable name.

I did not talk about a special format for these submodule IDs yet.
We could use an URL, but with such a value a user automatically associates
some semantic which can be confusing, as repository URLs can change. 

We can use some symbolic name which has some meaning in the scope of
the superproject, and is specified at submodule creation, like "gcc3" or
"gcc4". However, this is a local decision of the person which is importing
the submodule. So if two developers of the same project using supermodules
independently decide that the import of "gcc" as submodule is the right
thing, but use slightly different submodule IDs, you will get 2 different
submodules when merging.

I argue that this is even the correct thing, and they should decide about the
name before both are doing the import, or only one imports and the other
pulls.

Another option for a submodule ID could be the root commit of the submodule
commit DAG. This looks nice as such an ID really is globally unique for
projects (more or less: the first commit always contains the time stamp at
creation, and the author/commiter email address, even if the tree happens
to be the same because you start with the same dummy file).

But my example above (with the 2 different submodules from the
same GCC project) shows that this is not working. A superproject never
could create different submodules from the same (e.g. GCC) project.

So I just vote for a symbolic name choosen at submodule creation time.


^ permalink raw reply

* Re: [RFC] Submodules in GIT
From: Jakub Narebski @ 2006-12-02 12:48 UTC (permalink / raw)
  To: git
In-Reply-To: <20061201110032.GL18810@admingilde.org>

[cut]

From this discussion I think it follows that supermodule should track HEAD
version of submodule. Perhaps the supermodule index should have sha1 of
submodule commit, so (as usual) you have to update-index in supermodule to
record changes in submodule; the difference being that you update to HEAD
version, not to working directory version. Or you can just git-commit -a
in supermodule which would take working directory version of files, and HEAD
version of submodules.

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git


^ permalink raw reply

* Re: [RFC] Submodules in GIT
From: Jakub Narebski @ 2006-12-02 13:08 UTC (permalink / raw)
  To: git
In-Reply-To: <45706758.2020907@b-i-t.de>

Stephan Feder wrote:

> That's it: There is no need for a separate branch or repository. If you 
> have the subproject's commit in the superproject's object database (and 
> we really have that, see 1. and 2. above), why do you _have to_ store it 
> elsewhere?

It would be much simpler to have subproject's commit in subproject object
database, and have it available in superproject's object database by the
way of alternates.

Otherwise when commiting new submodule state in supermodule you would have
to fetch all the needed objects (submodule mighe have evolved few commits
in history inbetween) into superproject's object database.
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git


^ permalink raw reply

* Re: [RFC] Submodules in GIT
From: Jakub Narebski @ 2006-12-02 13:14 UTC (permalink / raw)
  To: git
In-Reply-To: <200612012104.39897.andyparkins@gmail.com>

Andy Parkins wrote:

>> You still don't have a totally separated repository then, because
>> you can't do a reachability analysis in the submodule repository alone.
> 
> I'm going to guess by reachability analysis, you mean that the submodule 
> doesn't know that some of it's commits are referenced by the supermodule.  As 
> I suggested elsewhere in the thread, that's easily fixed by making a 
> refs/supermodule/commitXXXX file for each supermodule commit that references 
> as particular submodule commit.  Then you can git-prune, git-fsck whenever 
> you want.

I think it would be better resolve this in universal way by adding
to git repository layout the optional "borrowers" file, which would
protect against pruning objects that are referenced by repositories
which have given repository as one of the "alternates".

By the way, how to slurp all the objects from alternates into repo
object repository?
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git


^ permalink raw reply

* Re: [PATCH] Print progress message to stderr, not stdout
From: Marco Costalba @ 2006-12-02 13:20 UTC (permalink / raw)
  To: Karl Hasselström; +Cc: Catalin Marinas, git
In-Reply-To: <20061111121625.8988.45195.stgit@localhost>

On 11/11/06, Karl Hasselström <kha@treskal.com> wrote:
> Printing progress messages to stdout causes them to get mixed up with
> the actual output of the program. Using stderr is much better, since
> the user can then redirect the two components separately.
>

This patch breaks qgit.

GUI interface to stgit pop and push commands is broken because a
command that prints to stderr is considered a failing one by qgit.

I would kindly ask you to:

1 - Revert the patch. That would be the best. You can use a prefix to
printed message instead, see git pull, something like 'stg: bla bla
bla' . In any case, IMHO, using stderr for normal activity logging
does not sound like a great idea in general.

2 - At least add a '-v' '--verbose' option that defaults to quiet so
to not break back compatibility.


Thanks
Marco

P.S: I cannot change the stderr == 'something has gone wrong'
behaviour because the interface to git commands works with this, and,
BTW, _all_ the git commands respect the behaviour stderr == empty ->

^ permalink raw reply

* Re: [RFC] Submodules in GIT
From: Josef Weidendorfer @ 2006-12-02 13:50 UTC (permalink / raw)
  To: Andy Parkins; +Cc: git
In-Reply-To: <200612021004.22236.andyparkins@gmail.com>

On Saturday 02 December 2006 11:04, Andy Parkins wrote:
> > So what do you do with deleted submodules?
> > You wouldn't want them to still sit around in your working directory,
> > but you still have to preserve them.
> 
> Now that is a tricky one.  Mind you, I think that problem exists for any 
> implementation.  I haven't got a good answer for that.

That suggests that it is probably better to separate submodule repositories
from their checked out working trees. Why not put the GITDIRs of the submodules
in subdirectories of the supermodules GITDIR instead?


^ permalink raw reply

* Re: [PATCH] make 'git add' a first class user friendly interface to the index
From: Han-Wen Nienhuys @ 2006-12-02 14:51 UTC (permalink / raw)
  To: git
In-Reply-To: <ekrjc9$8uc$1@sea.gmane.org>

Jakub Narebski escreveu:
> Junio C Hamano wrote:
> 
>> By the way, aren't people disturbed that "git rm" does not
>> default to "-f" -- I rarely use the command myself but that
>> makes it feel even more awkward that "git rm foo" does not
>> remove the file "foo".
> 
> But _only_ if file is unmodified. I think that "git rm" meaning
> "remove this file from version control, but not from working area"
> is a good thing; if you want to remove file, just /usr/bin/rm it.

In my workflow,  I regularly get bitten by this: 

I do 

  git checkout devel
  git rm src/foo.cc
  git commit src/foo.cc    # or whatever -a -i --difficult option is necessary

  git checkout stable

     ...barf: trying to overwrite untracked src/foo.cc file..


I think for the default to remove from the working area is better. 

FWIW, I consider it annoyance with CVS as well 

-- 
 Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen

^ permalink raw reply

* Re: [RFC] Submodules in GIT
From: Jakub Narebski @ 2006-12-02 15:16 UTC (permalink / raw)
  To: git
In-Reply-To: <20061201123739.GT18810@admingilde.org>

Martin Waitz wrote:

> hoi :)
> 
> On Fri, Dec 01, 2006 at 12:20:42PM +0000, Andy Parkins wrote:
>> Is there a public repository I can look at to see what you've done?
>> I'm interested in the sort of plumbing changes needed to make
>> something like this work.
> 
> link is in the mail that started this thread ;-).

And on GitWiki as well:
  http://git.or.cz/gitwiki/SubprojectSupport

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git


^ permalink raw reply

* Re: [PATCH] make 'git add' a first class user friendly interface to the index
From: Carl Worth @ 2006-12-02 16:49 UTC (permalink / raw)
  To: Alan Chandler; +Cc: git, Junio C Hamano, Nicolas Pitre
In-Reply-To: <200612020828.57989.alan@chandlerfamily.org.uk>

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

On Sat, 2 Dec 2006 08:28:57 +0000, Alan Chandler wrote:
> There is a conceptual difference between thinking that git-add is about adding
> a file and git-add adding the current state of a files content.

Yes, there is.

>                                                                 If your
> conceptual model is the first of these - then I can see why you see a problem
> with git-add being used to say a files contents have changed.

Yes. (And of course, I personally understand the second conceptual
model. But there are a lot of "brain-damaged" people out there.)

> However, if you regard the git-add command is "adding the current content of
> the file to a staging area" , and you say this is an SCM which by definition
> keeps the history of things once its been told about them I don't see why
> there is a need for a different name for the operation the first time and for
> the operation later.

Yes, that's also true. Once you know the model then you wouldn't need
two different commands. One can certainly get by with just the
functionality of "update-index" for everything.

> Trying to put myself in the shoes of a newbie - if taught to use add in both
> ways up front - is to ask why git isn't clever enough to notice that I have
> changed the content of something it already knows about rather than having it
> to manually add it again.

Yes, and "put myself in the shoes of a newbie" is what I've been doing
through the whole conversation. That's why I keep coming across as so
stubbornly stupid in these threads, ("why can't Carl just understand
how git works?!").

> So I am with you that we need to effective teach
>
> git add <filename>   #add content of filename to the SCM
> #edit <filename>
> git commit -a		#commit current state of all tracked content
>
> first, and then move on to teach selective commiting

Yes. That's the only way to avoid this confusion.

So all of the conditions above, ("if your conceptual model is", "if
you regard the git-add command", "if taught to use git-add up front",
"if we effectively teach 'commit -a' first"), are barriers to learning
git. We can't guarantee these are all met for new users, and when
they're not, the users can get confused.

If git's model imposes the requirement, "we should first teach one
thing, then move on to teach a subsequent thing", it would be just
that much nicer if the commands themselves could help us do that,
(because the default would do the thing they would need first, and
then the user has to explicitly do _something_ else to get the
subsequent thing).

See? I'm just trying to make the command set more naturally provide
the same flow of learning that we've been proposing for the tutorial.

-Carl

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

^ permalink raw reply

* On removing files and "git-rm is pointless"
From: Carl Worth @ 2006-12-02 17:05 UTC (permalink / raw)
  To: git

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

Some people have recently asked questions about why we even have a
"git rm" command since it seems so pointless if you understand git's
model and "commit -a" well enough.

I wrote that command, so let me explain.

The problem I was trying to address is that a new user (me), was
trying to learn git and made it through a scenario like this:

	git init-db
	echo a > a
	git add a
	git commit

	"Cool, that works. Now let's explore file deletion:"

	rm file
	git commit

	"Hmm... that' didn't work, and git commit says:

		#   (use git-update-index to mark for commit)
		#
		#       deleted:    file

	I explored the documentation and found
	"git update-index --remove file" and thought, "this git system
	is insane! what a horrible command line that is!"

So, with "git commit", it doesn't work to just plain delete the file.

Now, a really cool thing about git and something that makes it easier
than other systems, (like cvs say), is that you don't _have_ to do
anything extra to tell it about file deletion, (nor file rename). But
to get the cool feature to work, you have to use "commit -a":

	rm file
	git commit -a

Is our new documentation going to lead users to discover this great
feature? We're talking about documenting "commit -a" as, "'add' all
tracked files then commit". It would take an exceptional stretch for a
new reader to take that sentence and realize that it would also mean
that any deleted file would also be removed from git's tracking. We're
using a verb with the _opposite_ meaning for crying out loud!

So, back to "git rm". I added it not just because some people might be
trained to tell the SCM about file removal. I added it to make "git
commit" seem more reliable, (since it can feel broken to new
users---it doesn't seem 'smart' enough to just figure out what changes
have been made to files that are being tracked).

So we should show the "smarter" behavior to users by default. Then
"git commit" wouldn't feel broken. We could even throw away "git rm"
and use its absence as a selling point for git. "Hey, git's actually
_easier_ to use than that broken stuff you've been using."

Wouldn't that be great?

-Carl




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

^ permalink raw reply

* Re: [PATCH] make 'git add' a first class user friendly interface to the index
From: Jakub Narebski @ 2006-12-02 17:12 UTC (permalink / raw)
  To: git
In-Reply-To: <87psb22qgu.wl%cworth@cworth.org>

Carl Worth wrote:

> If git's model imposes the requirement, "we should first teach one
> thing, then move on to teach a subsequent thing", it would be just
> that much nicer if the commands themselves could help us do that,
> (because the default would do the thing they would need first, and
> then the user has to explicitly do _something_ else to get the
> subsequent thing).
> 
> See? I'm just trying to make the command set more naturally provide
> the same flow of learning that we've been proposing for the tutorial.

Not exactly. For example more user-friendly is "mv -i" than "mv",
but noone proposes to make "mv -i" default (well, you can alias
"mv" to "mv -i" in shell, while you cannot alias "commit" to "commit -a"
in git).

So i think having the default geared towards advanced users and not
newbie users is O.K.

By the way, I find it a bit annoying that "git commit" outputs
git-status output (possibly multi-line if you have many untracked
but unignored files in working area) before "nothing to commit".

P.S. Is there a difference between "git commit ." and "git commit -a"?
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git


^ permalink raw reply

* Re: On removing files and "git-rm is pointless"
From: Linus Torvalds @ 2006-12-02 17:37 UTC (permalink / raw)
  To: Carl Worth; +Cc: git
In-Reply-To: <87odqm2ppv.wl%cworth@cworth.org>



On Sat, 2 Dec 2006, Carl Worth wrote:
>
> Some people have recently asked questions about why we even have a
> "git rm" command since it seems so pointless if you understand git's
> model and "commit -a" well enough.

I have to admit that I'm not a big fan of "git rm".

I'd like it more if it defaulted to actually removing the file, preferably 
refusing to with an error message if the file didn't match the index. And 
then use "git rm -f" to force-remove a dirty file.

As it is, because I just find "git rm" to be annoying, I simply do what 
you talk about:

> 	rm file
> 	git commit -a

Works fine for me, and is more natural than "git rm" at least in my mind.

> Is our new documentation going to lead users to discover this great
> feature?

I definitely wouldn't object at all. The _best_ of both worlds would be 
to:

 - document how git will detect changes to files it knows about 
   (_including_ removal) automatically with "git commit -a", and make it 
   clear that "git rm" thus isn't really needed.

 - but because it makes sense to have the mirror symmetry of "git add" and 
   "git rm", and because people expect to be able to do "git rm" from 
   other systems anyway, just keep the command around, and possibly make 
   the default behaviour a bit more obvious.

On "git rm", I'd suggest:

 - with no flags: remove the working file too, but _only_ if it matches 
   the index. NOTE! This is a change in semantics, but damn, if people 
   have found "git add" hard to understand, I think "git rm" is much 
   worse, and doesn't even match "git mv" (whcih _does_ move the working 
   file, and doesn't just do a in-index move)

 - with "-f": do what "git rm -f" does now. Just force the thing. Don't 
   care whether the file is dirty in the working tree or whether it even 
   exists in the index. Just get rid of it already, both in the index 
   (regardless of state or whether it is there at all) _and_ in the 
   working tree (again, regardless of state)

One thing to look out for: "git rm" actually defaults to the recursive 
behaviour, something that might take people by surprise. If you give it a 
directory name, it will happily delete all tracked files from within that 
directory, even without "-r". That is probably a design mistake. So it 
would probably make sense to:

 - without "-r", don't do the partial matches at the beginning (but still 
   do globbing matches, of course, so "git rm dir/*" wouldn't need an 
   "-r", but "git rm -r dir/", which does the same thing, _would_ need an 
   "-r" to be effective)

Final note: arguably, the current "git rm" is a better mirror image of 
"git add" than what I suggest above. "git add" doesn't actually create the 
working file (you had to do that yourself), so you _could_ argue that "git 
rm" as it stands now is closer to the "reverse" of git add. The same is 
true of the recursive behaviour.

However, I'd argue that:

 - "rm" isn't the reverse of "add" in the first place. If we had a "git 
   subtract" file, _that_ would be the reverse of "git add" ;)

 - "rm" isn't the reverse of "add" in another sense: "rm" is just more 
   dangerous. So not having the mirror-image semantics makes sense simply 
   becaue the dangerousness of the commands aren't mirror images.

Anyway, I don't personally much care. As mentioned, I'll happily just 
remove the file and do "git commit -a" instead (or, indeed, if I want to 
play with the index, I'm perfectly comfy just doing "git update-index" 
with "--force-remove" or something - but clearly I'm more confy with the 
index and it's strangly named commands than most ;^).


^ permalink raw reply

* Re: [PATCH] make 'git add' a first class user friendly interface to the index
From: Alan Chandler @ 2006-12-02 18:05 UTC (permalink / raw)
  To: git; +Cc: Carl Worth, Junio C Hamano, Nicolas Pitre
In-Reply-To: <87psb22qgu.wl%cworth@cworth.org>

On Saturday 02 December 2006 16:49, Carl Worth wrote:
> On Sat, 2 Dec 2006 08:28:57 +0000, Alan Chandler wrote:
> > There is a conceptual difference between thinking that git-add is about
> > adding a file and git-add adding the current state of a files content.
>
> Yes, there is.
>
> >                                                                 If your
> > conceptual model is the first of these - then I can see why you see a
> > problem with git-add being used to say a files contents have changed.
>
> Yes. (And of course, I personally understand the second conceptual
> model. But there are a lot of "brain-damaged" people out there.)
>
> > However, if you regard the git-add command is "adding the current content
> > of the file to a staging area" , and you say this is an SCM which by
> > definition keeps the history of things once its been told about them I
> > don't see why there is a need for a different name for the operation the
> > first time and for the operation later.
>
> Yes, that's also true. Once you know the model then you wouldn't need
> two different commands. One can certainly get by with just the
> functionality of "update-index" for everything.
...
> So all of the conditions above, ("if your conceptual model is", "if
> you regard the git-add command", "if taught to use git-add up front",
> "if we effectively teach 'commit -a' first"), are barriers to learning
> git. We can't guarantee these are all met for new users, and when
> they're not, the users can get confused.
>

The argument I was _trying_ to make was that we should teach the second 
conceptual model not the first one AND stick with just the git add command 
(in response to your (Carl's) statement earlier in the thread that there 
needs to be two separate commands) .  My if statements were to illustrate 
that there are two fundamental ways of looking at this, not lots of ifs that 
newbies would have to consider.  We should up-front (in the tutorial, in 
appropriate man pages) use the one conceptual model (and I also like Junio's 
argument that git should take an aggressive stance of this is how the 
conceptual model is rather than the "contrary to ..." approach).



-- 
Alan Chandler

^ permalink raw reply

* Re: [RFC] Submodules in GIT
From: Torgil Svensson @ 2006-12-02 18:57 UTC (permalink / raw)
  To: sf-gmane, Linus Torvalds, sf, git, Martin Waitz
In-Reply-To: <4570BFA4.8070903@stephan-feder.de>

> If you need a common infrastructure to be able to work with the
> submodule, then the submodule is not independent of of the supermodule.
> I see a contradiction in your requirements.

Here's an real-world example that doesn't contradict:

http://amarok.kde.org/wiki/Installation_HowTo#From_Anonymous_SVN

"svn co -N svn://anonsvn.kde.org/home/kde/trunk/extragear/multimedia
cd multimedia
svn co svn://anonsvn.kde.org/home/kde/branches/KDE/3.5/kde-common/admin
svn up amarok

To compile the sources (from the multimedia directory):"

and there's probably very few people that want to clone the entire KDE
multimedia sub&super-module in this case.

//Torgil


On 12/2/06, sf <sf-gmane@stephan-feder.de> wrote:
> Linus Torvalds wrote:
> >
> > On Fri, 1 Dec 2006, sf wrote:
> >> Linus Torvalds wrote:
> >> ...
> >>> In contrast, a submodule that we don't fetch is an all-or-nothing
> >>> situation: we simply don't have the data at all, and it's really a matter
> >>> of simply not recursing into that submodule at all - much more like not
> >>> checking out a particular part of the tree.
> >> If you do not want to fetch all of the supermodule then do not fetch the
> >> supermodule.
> >
> > So why do you want to limit it? There's absolutely no cost to saying "I
> > want to see all the common shared infrastructure, but I'm actually only
> > interested in this one submodule that I work with".
>
> If you need a common infrastructure to be able to work with the
> submodule, then the submodule is not independent of of the supermodule.
> I see a contradiction in your requirements.
>
> > Also, anybody who works on just the build infrastructure simply may not
> > care about all the submodules. The submodules may add up to hundreds of
> > gigs of stuff. Not everybody wants them. But you may still want to get the
> > common build infrastructure.
>
> See above.
>
> > In other words, your "all or nothing" approach is
> >  (a) not friendly
> > and
> >  (b) has no real advantages anyway, since modules have to be independent
> >      enough that you _can_ split them off for other reasons anyway.
> >
> > So forcing that "you have to take everything" mentality onyl has
> > negatives, and no positives. Why do it?
>
> (There have been lots of use cases for shallow clones but for a long
> time git did not support them).
>
> If you can extend this partial fetch feature to the non-subproject case
> I would agree with your reasoning. What makes the subprojects so special
> in this regard. Do I have to turn a plain tree into a subproject to be
> able to ignore it? Once you can restrict fetches to parts of the
> contents you get the ability to restrict fetches to the "common
> infrastructure" and selected submodules for free.
>
> Regards
>
> Stephan
>
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [RFC] Submodules in GIT
From: Linus Torvalds @ 2006-12-02 19:41 UTC (permalink / raw)
  To: Torgil Svensson; +Cc: sf-gmane, sf, git, Martin Waitz
In-Reply-To: <e7bda7770612021057mc9f3eb9q7fc047dd1b5c235f@mail.gmail.com>



On Sat, 2 Dec 2006, Torgil Svensson wrote:
> 
> Here's an real-world example that doesn't contradict:

And I'll add the note that people who do things like submodules aren't 
generally even _used_ to them being "seamless", and most of the time 
probably don't even want complete seamlessness.

As the example that Torgil points to shows, people are quite used to 
actually even naming the submodules separately, and things like having the 
"default" set of submodules not equal the "complete" set. 

In other words, I don't think people expect or want something hugely more 
complicated than the CVS/modules kind of file. 

What people _do_ want (and that CVS in general is horribly bad at, and 
this is not a module-specific issue) is to have the _versioning_ work 
well. When you check out a specific version of a module, you want any 
_linked_ modules to follow along too.

This is the same reason why CVS users use tags a lot: because even 
_within_ a single project (no modules, no nothing), it's often hard to 
re-create the exact state of a version any other way. So you tag every 
single file and do insane things like that, because CVS just isn't very 
good at guaranteeing consistency across the whole project.

The exact same thing is true about subprojects. I don't think that people 
who have used CVS subprojects a lot really mind the CVS/modules file 
itself (but hey, maybe I'm wrong - I've seen _other_ people maintain 
modules in CVS, but I've never done it myself), but they do mind the fact 
that it's hard as hell to do something as simple as "get all modules back 
to version X" without lots and lots of careful crud (ie tagging every 
singl emodule, things like that).

Now, I'm not exactly sure who wants to use git modules, so this is the 
time to ask: did you hate the CVS/modules file? Or was it something you 
set up once, and then basically forgot about? People clearly use the 
ability to mark certain modules as depending on each other, and aliases to 
say "if you ask for this module, you actually get a set of _these_ 
modules".

_I_ suspect that that isn't the problem people had, and isn't what they 
have any problems with. What CVS didn't do very well (or at all, afaik) is 
to say "I want supermodule version XYZ", and then got all the submodules 
automatically to that (reliable) state. And THAT is something I think is 
really important for submodules, and it's why I think the most important 
part isn't actually all the veneer to make "git clone" and "git pull" work 
(which is really about the CVS/modules kind of wrapper parsing), but 
actually about the supermodule "tree" object pointing to a very specific 
version, so that you get the exact same "atomic snapshotting" of multiple 
trees that you get within a single git tree.

In other words, I _suspect_ that that is really what module users are all 
about. They want the ability to specify an arbitrary collection of these 
atomic snapshots (for releases etc), and just want a way to copy and move 
those things around, and are less interested in making everything else 
very seamless (because most people are happy to do the actual 
_development_ entirely within the submodules, so the "development" part 
is actually not that important for the supermodule, the supermodule is 
mostly for aggregation and snapshots, and tying different versions of 
different submodules together).

So that's where I come from. And maybe I'm totally wrong. I'd like to hear 
what people who actually _use_ submodules think.


^ permalink raw reply

* Re: [RFC] Submodules in GIT
From: Martin Waitz @ 2006-12-02 19:46 UTC (permalink / raw)
  To: sf; +Cc: git
In-Reply-To: <4570BC07.4080203@stephan-feder.de>

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

hoi :)

On Sat, Dec 02, 2006 at 12:34:31AM +0100, sf wrote:
> > Now your submodule is no longer seen as an independent git repository
> > and I think this would cause problems when you want to push/pull between
> > the submodule and its upstream repository.
> 
> You can always pick a single commit or several commits out of a larger
> repository and have a complete git repository.
> 
> And I already explained how to push and pull even from within superprojects.

Sure it you are able to make it work, but it needs more work on the UI part.
How do you handle the index? How do you allow to clone only the
submodule?

I really thought about such a setup too, but then decided that it is
much easier to work with submodules when you can really see it as a
repository of its own.

> > But you could still call the "xdiff" part of the git repository a
> > submodule.  And then changes to the xdiff directory result in a new
> > submodule commit, even when there is no direct reference to it.
> > So you'd still "commit to the xdiff submodule".
> 
> Let's make certain that we understand each other. I see a clear
> distinction between the submodule code in a supermodule branch (commits
> in the supermodule's tree and nothing else) and submodule branches which
> are independent of the superproject. Supermodule branches and submodule
> branches do not interact, only if I want them to.

Agreed.
I think the thing which caused some discussion is that I make the
current submodule commit which is used by the supermodule available in a
refs/head in the submodule.
So there is one "branch" in the submodule which corresponds to the
version used by the supermodule, but this is just for user interface.
It's most important purpose is to give this special commit a name, so
that it can be used in merges, etc.

By selecting another refs/heads "branch" in the submodule you can also
easily detach the submodule from the supermodule.
It is really important to understand that you can't branch the submodule
alone and still have it connected to the supermodule, because the
supermodule always tracks only one commit for each submodule.
So every branch that affects the project has to be done on project
(topmost supermodule) level.
But of course the submodule can have other branches which are not
tracked by the supermodule.
So by checking out refs/heads/master (as it is used in my
implementation) you can attach the submodule to the supermodule (attach
as in: bring the working directory in sync with the whole project), and
you can detach it by selecting another refs/heads (the submodule is
still part of the supermodule, but not in the state which is currently
visible in the working directory).
This may sound confusing, but it really is the only semantic for
submodule branches that makes sense.
There are fears that you may commit something that does not match your
current working directory.  Sure, but you explicitly asked for it and I
think it won't be a problem if git-status tells about this fact.


> The double slashes is the only way I can think of that clearly indicates
> that I do not mean the contents named by the path, but the commit that
> you find there. Once you have named a commit in that way, you can
> continue to apply other revision naming suffixes, paths, and so on.

With the current semantics, you can already get to the submodule commit
(just leave out your double slashes), but what is missing is simply to
apply all the modifiers again on this submodule commit.
So I think we can do without the double slashes.

-- 
Martin Waitz

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

^ permalink raw reply

* [RFC/PATCH] runstatus: restructure visual appearance
From: Lars Hjemli @ 2006-12-02 19:37 UTC (permalink / raw)
  To: git

Modify the output from runstatus so that all modified files are shown
in the same list, prefixed with a state symbol (A/C/D/M/R/T/X/U) and
possibly a state modifier (+/-).

The '+' indicates that the working copy has been changed since the file
was added to the index, while the '-' indicates that the file hasn't
been added to the index at all.

If either '+' or '-' is displayed for any of the modified files, then a
big warning is printed, informing the user that she might want to run
'git commit -a' or 'git add file'.

Experienced users who find this warning annoying, can turn if off with
'git repo-config status.showwarning 0'.

Signed-off-by: Lars Hjemli <hjemli@gmail.com>

---

This is a rather subjective 'improvement', but I think it makes the commit 
message easier to comprehend and I hope that goes for both new and 
experienced users.

Btw: the warning message somewhat implies that 'git add' can be used to add 
changed content to the index, even for files already added. So I obviously 
liked the patch Nicolas Pitre sendt earlier today...


 Documentation/git-runstatus.txt |   28 +++
 wt-status.c                     |  384 +++++++++++++++++++++++----------------
 wt-status.h                     |    1 +
 3 files changed, 260 insertions(+), 153 deletions(-)

diff --git a/Documentation/git-runstatus.txt b/Documentation/git-runstatus.txt
index 89d7b92..cc6ed92 100644
--- a/Documentation/git-runstatus.txt
+++ b/Documentation/git-runstatus.txt
@@ -53,6 +53,34 @@ OUTPUT
 The output from this command is designed to be used as a commit
 template comments, and all the output lines are prefixed with '#'.
 
+EXAMPLES
+--------
+
++
+--------
+$ git runstatus
+#
+# On branch refs/heads/runstatus
+#
+# Modified files
+#   M  Documentation/git-runstatus.txt
+#   M+ wt-status.c
+#
+# WARNING:
+#   If you want to commit all of your changes, you need to run
+#   'git commit -a' (or 'git add file...' for selected files).
+#
+$ git add wt-status.c
+$ git runstatus
+#
+# On branch refs/heads/runstatus
+#
+# Modified files
+#   M  Documentation/git-runstatus.txt
+#   M  wt-status.c
+#
+--------
++
 
 Author
 ------
diff --git a/wt-status.c b/wt-status.c
index de1be5b..db0c945 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -9,11 +9,20 @@
 #include "diffcore.h"
 
 int wt_status_use_color = 0;
+int wt_status_warn = 1;
+
+struct fileinfo{
+	int status;
+	char *one, *two;
+	struct fileinfo *next;
+};
+
 static char wt_status_colors[][COLOR_MAXLEN] = {
 	"",         /* WT_STATUS_HEADER: normal */
 	"\033[32m", /* WT_STATUS_UPDATED: green */
 	"\033[31m", /* WT_STATUS_CHANGED: red */
-	"\033[31m", /* WT_STATUS_UNTRACKED: red */
+	"",         /* WT_STATUS_UNTRACKED: normal */
+	"\033[31m", /* WT_STATUS_WARNING: red */
 };
 
 static int parse_status_slot(const char *var, int offset)
@@ -43,7 +52,6 @@ void wt_status_prepare(struct wt_status *s)
 
 	head = resolve_ref("HEAD", sha1, 0, NULL);
 	s->branch = head ? xstrdup(head) : NULL;
-
 	s->reference = "HEAD";
 	s->amend = 0;
 	s->verbose = 0;
@@ -51,17 +59,15 @@ void wt_status_prepare(struct wt_status *s)
 	s->untracked = 0;
 }
 
-static void wt_status_print_header(const char *main, const char *sub)
+static void wt_status_print_trailer(void)
 {
-	const char *c = color(WT_STATUS_HEADER);
-	color_printf_ln(c, "# %s:", main);
-	color_printf_ln(c, "#   (%s)", sub);
-	color_printf_ln(c, "#");
+	color_printf_ln(color(WT_STATUS_HEADER), "#");
 }
 
-static void wt_status_print_trailer(void)
+static void wt_status_print_header(const char *main)
 {
-	color_printf_ln(color(WT_STATUS_HEADER), "#");
+	wt_status_print_trailer();
+	color_printf_ln(color(WT_STATUS_HEADER), "# %s", main);
 }
 
 static const char *quote_crlf(const char *in, char *buf, size_t sz)
@@ -70,6 +76,9 @@ static const char *quote_crlf(const char *in, char *buf, size_t sz)
 	char *out;
 	const char *ret = in;
 
+	if (!in)
+		return ret;
+
 	for (scan = in, out = buf; *scan; scan++) {
 		int ch = *scan;
 		int quoted;
@@ -93,133 +102,13 @@ static const char *quote_crlf(const char *in, char *buf, size_t sz)
 	return ret;
 }
 
-static void wt_status_print_filepair(int t, struct diff_filepair *p)
-{
-	const char *c = color(t);
-	const char *one, *two;
-	char onebuf[PATH_MAX], twobuf[PATH_MAX];
-
-	one = quote_crlf(p->one->path, onebuf, sizeof(onebuf));
-	two = quote_crlf(p->two->path, twobuf, sizeof(twobuf));
-
-	color_printf(color(WT_STATUS_HEADER), "#\t");
-	switch (p->status) {
-	case DIFF_STATUS_ADDED:
-		color_printf(c, "new file:   %s", one);
-		break;
-	case DIFF_STATUS_COPIED:
-		color_printf(c, "copied:     %s -> %s", one, two);
-		break;
-	case DIFF_STATUS_DELETED:
-		color_printf(c, "deleted:    %s", one);
-		break;
-	case DIFF_STATUS_MODIFIED:
-		color_printf(c, "modified:   %s", one);
-		break;
-	case DIFF_STATUS_RENAMED:
-		color_printf(c, "renamed:    %s -> %s", one, two);
-		break;
-	case DIFF_STATUS_TYPE_CHANGED:
-		color_printf(c, "typechange: %s", one);
-		break;
-	case DIFF_STATUS_UNKNOWN:
-		color_printf(c, "unknown:    %s", one);
-		break;
-	case DIFF_STATUS_UNMERGED:
-		color_printf(c, "unmerged:   %s", one);
-		break;
-	default:
-		die("bug: unhandled diff status %c", p->status);
-	}
-	printf("\n");
-}
-
-static void wt_status_print_updated_cb(struct diff_queue_struct *q,
-		struct diff_options *options,
-		void *data)
-{
-	struct wt_status *s = data;
-	int shown_header = 0;
-	int i;
-	for (i = 0; i < q->nr; i++) {
-		if (q->queue[i]->status == 'U')
-			continue;
-		if (!shown_header) {
-			wt_status_print_header("Updated but not checked in",
-					"will commit");
-			s->commitable = 1;
-			shown_header = 1;
-		}
-		wt_status_print_filepair(WT_STATUS_UPDATED, q->queue[i]);
-	}
-	if (shown_header)
-		wt_status_print_trailer();
-}
-
-static void wt_status_print_changed_cb(struct diff_queue_struct *q,
-                        struct diff_options *options,
-                        void *data)
-{
-	int i;
-	if (q->nr)
-		wt_status_print_header("Changed but not updated",
-				"use git-update-index to mark for commit");
-	for (i = 0; i < q->nr; i++)
-		wt_status_print_filepair(WT_STATUS_CHANGED, q->queue[i]);
-	if (q->nr)
-		wt_status_print_trailer();
-}
-
-void wt_status_print_initial(struct wt_status *s)
-{
-	int i;
-	char buf[PATH_MAX];
-
-	read_cache();
-	if (active_nr) {
-		s->commitable = 1;
-		wt_status_print_header("Updated but not checked in",
-				"will commit");
-	}
-	for (i = 0; i < active_nr; i++) {
-		color_printf(color(WT_STATUS_HEADER), "#\t");
-		color_printf_ln(color(WT_STATUS_UPDATED), "new file: %s",
-				quote_crlf(active_cache[i]->name,
-					   buf, sizeof(buf)));
-	}
-	if (active_nr)
-		wt_status_print_trailer();
-}
-
-static void wt_status_print_updated(struct wt_status *s)
-{
-	struct rev_info rev;
-	init_revisions(&rev, NULL);
-	setup_revisions(0, NULL, &rev, s->reference);
-	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
-	rev.diffopt.format_callback = wt_status_print_updated_cb;
-	rev.diffopt.format_callback_data = s;
-	rev.diffopt.detect_rename = 1;
-	run_diff_index(&rev, 1);
-}
-
-static void wt_status_print_changed(struct wt_status *s)
-{
-	struct rev_info rev;
-	init_revisions(&rev, "");
-	setup_revisions(0, NULL, &rev, NULL);
-	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
-	rev.diffopt.format_callback = wt_status_print_changed_cb;
-	rev.diffopt.format_callback_data = s;
-	run_diff_files(&rev, 0);
-}
-
-static void wt_status_print_untracked(const struct wt_status *s)
+static int wt_status_print_untracked(const struct wt_status *s)
 {
 	struct dir_struct dir;
 	const char *x;
 	int i;
 	int shown_header = 0;
+	int ret = 0;
 
 	memset(&dir, 0, sizeof(dir));
 
@@ -249,14 +138,15 @@ static void wt_status_print_untracked(const struct wt_status *s)
 				continue;
 		}
 		if (!shown_header) {
-			wt_status_print_header("Untracked files",
-				"use \"git add\" to add to commit");
+			wt_status_print_header("Untracked files:");
 			shown_header = 1;
 		}
-		color_printf(color(WT_STATUS_HEADER), "#\t");
+		color_printf(color(WT_STATUS_HEADER), "#   ");
 		color_printf_ln(color(WT_STATUS_UNTRACKED), "%.*s",
 				ent->len, ent->name);
+		ret++;
 	}
+	return ret;
 }
 
 static void wt_status_print_verbose(struct wt_status *s)
@@ -269,30 +159,215 @@ static void wt_status_print_verbose(struct wt_status *s)
 	run_diff_index(&rev, 1);
 }
 
-void wt_status_print(struct wt_status *s)
+static void wt_status_copy_cb(struct diff_queue_struct *q,
+			      struct diff_options *options,
+			      void *data)
+{
+	struct fileinfo *p, *t = (struct fileinfo *)data;
+	int i;
+
+	for(i=0; i<q->nr; i++){
+		if (q->queue[i]->status=='U')
+			continue;
+		p = xmalloc(sizeof(*p));
+		p->status = q->queue[i]->status;
+		p->one = xstrdup(q->queue[i]->one->path);
+		p->two = xstrdup(q->queue[i]->two->path);
+		t = t->next = p;
+	}
+	t->next = NULL;
+}
+
+static void wt_status_find_indexed(struct fileinfo *head)
+{
+	struct fileinfo *t = head, *p;
+	int i;
+
+	read_cache();
+        for (i = 0; i < active_nr; i++) {
+		p = xmalloc(sizeof(*p));
+		p->status = DIFF_STATUS_ADDED;
+		p->one = xstrdup(active_cache[i]->name);
+		p->two = NULL;
+		t = t->next = p;
+        }
+	t->next = NULL;
+}
+
+static void wt_status_find_staged(struct wt_status *s, void *q)
+{
+	struct rev_info rev;
+	init_revisions(&rev, NULL);
+	setup_revisions(0, NULL, &rev, s->reference);
+	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = wt_status_copy_cb;
+	rev.diffopt.format_callback_data = q;
+	rev.diffopt.detect_rename = 1;
+	run_diff_index(&rev, 1);
+}
+
+static void wt_status_find_unstaged(struct wt_status *s, void *q)
 {
-	if (s->branch && strcmp(s->branch, "refs/heads/master"))
-		color_printf_ln(color(WT_STATUS_HEADER),
-			"# On branch %s", s->branch);
-
-	if (s->is_initial) {
-		color_printf_ln(color(WT_STATUS_HEADER), "#");
-		color_printf_ln(color(WT_STATUS_HEADER), "# Initial commit");
-		color_printf_ln(color(WT_STATUS_HEADER), "#");
-		wt_status_print_initial(s);
+	struct rev_info rev;
+	init_revisions(&rev, NULL);
+	setup_revisions(0, NULL, &rev, NULL);
+	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = wt_status_copy_cb;
+	rev.diffopt.format_callback_data = q;
+	run_diff_files(&rev, 0);
+}
+
+
+static void wt_status_print_warning()
+{
+	static const char w1[] =
+		"If you want to commit all of your changes, you need to run";
+	static const char w2[] =
+		"'git commit -a' (or 'git add file...' for selected files)";
+
+	wt_status_print_header("WARNING:");
+	color_printf(color(WT_STATUS_HEADER), "#   ");
+	color_printf_ln(color(WT_STATUS_WARNING), w1);
+	color_printf(color(WT_STATUS_HEADER), "#   ");
+	color_printf_ln(color(WT_STATUS_WARNING), w2);
+}
+
+static int wt_status_print_one(int staged, int unstaged, const char *one,
+			const char *two)
+{
+	char mode[3] = "??";
+	const char *c;
+	int ret = 0;
+	char onebuf[PATH_MAX], twobuf[PATH_MAX];
+
+	one = quote_crlf(one, onebuf, sizeof(onebuf));
+	two = quote_crlf(two, twobuf, sizeof(twobuf));
+
+	if (staged!=0 && unstaged==0) {
+		mode[0] = staged;
+		mode[1] = ' ';
+	} else if (staged==0 && unstaged!=0) {
+		mode[0] = unstaged;
+		mode[1] = '-';
+		ret = 1;
+	} else {
+		mode[0] = staged;
+		mode[1] = '+';
+		ret = 2;
 	}
-	else {
-		wt_status_print_updated(s);
-		discard_cache();
+	printf("#   ");
+	if (mode[1]==' ')
+		c = color(WT_STATUS_UPDATED);
+	else
+		c = color(WT_STATUS_CHANGED);
+
+	if (mode[0]==DIFF_STATUS_COPIED || mode[0]==DIFF_STATUS_RENAMED)
+		color_printf_ln(c, "%s %s -> %s", mode, one, two);
+	else
+		color_printf_ln(c, "%s %s", mode, one);
+	return ret;
+}
+
+static void wt_status_free_list(struct fileinfo *p)
+{
+	struct fileinfo *t = p->next;
+
+	while (t){
+	        p = t;
+		t = t->next;
+		free(p->one);
+		free(p->two);
+		free(p);
 	}
+}
+
+static int wt_status_print_tracked(struct wt_status *status)
+{
+	struct fileinfo staged, unstaged, *s, *u;
+	int warn = 0;
+	int ret = 0;
+
+	staged.next = unstaged.next = NULL;
+
+	if (status->is_initial)
+		wt_status_find_indexed(&staged);
+	else
+		wt_status_find_staged(status, &staged);
+
+	wt_status_find_unstaged(status, &unstaged);
 
-	wt_status_print_changed(s);
-	wt_status_print_untracked(s);
+	s = staged.next;
+	u = unstaged.next;
+
+	if (!s && !u)
+		return ret;
+
+	wt_status_print_header("Modified files:");
+	while(s || u) {
+		if (!s) {
+			warn |= wt_status_print_one(0, u->status, u->one,
+						    u->two);
+			u = u->next;
+		} else if (!u) {
+			warn |= wt_status_print_one(s->status, 0, s->one,
+						    s->two);
+			s = s->next;
+		} else {
+			int i = strcmp(s->one, u->one);
+			if (i<0) {
+				warn |= wt_status_print_one(s->status, 0,
+							    s->one, s->two);
+				s = s->next;
+			} else if (i>0) {
+				warn |= wt_status_print_one(0, u->status,
+							    u->one, u->two);
+				u = u->next;
+			} else {
+				warn |= wt_status_print_one(s->status,
+							    u->status, s->one,
+							    s->two);
+				s = s->next;
+				u = u->next;
+			}
+		}
+		ret++;
+	}
 
-	if (s->verbose && !s->is_initial)
-		wt_status_print_verbose(s);
-	if (!s->commitable)
-		printf("%s\n", s->amend ? "# No changes" : "nothing to commit");
+	/* if warn==0 or warn==2, something is staged for commit */
+	status->commitable = (warn != 1);
+
+	if (warn && wt_status_warn)
+		wt_status_print_warning();
+	wt_status_free_list(&staged);
+	wt_status_free_list(&unstaged);
+	return ret;
+}
+
+void wt_status_print(struct wt_status *status)
+{
+	int cnt;
+
+	if (status->branch && strcmp(status->branch, "refs/heads/master")){
+		wt_status_print_trailer();
+		color_printf_ln(color(WT_STATUS_HEADER), "# On branch %s",
+				status->branch);
+	}
+
+	if (status->is_initial)
+		wt_status_print_header("Initial commit");
+
+	cnt = wt_status_print_tracked(status);
+	cnt += wt_status_print_untracked(status);
+
+	if (cnt)
+		wt_status_print_trailer();
+
+	if (status->verbose && !status->is_initial)
+		wt_status_print_verbose(status);
+
+	if (!status->commitable)
+		printf("%s\n",
+		       status->amend ? "# No changes" : "nothing to commit");
 }
 
 int git_status_config(const char *k, const char *v)
@@ -305,5 +380,8 @@ int git_status_config(const char *k, const char *v)
 		int slot = parse_status_slot(k, 13);
 		color_parse(v, k, wt_status_colors[slot]);
 	}
+	if (!strcmp(k, "status.showwarning"))
+		wt_status_warn = git_config_bool(k, v);
+
 	return git_default_config(k, v);
 }
diff --git a/wt-status.h b/wt-status.h
index 0a5a5b7..b8337ee 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -6,6 +6,7 @@ enum color_wt_status {
 	WT_STATUS_UPDATED,
 	WT_STATUS_CHANGED,
 	WT_STATUS_UNTRACKED,
+	WT_STATUS_WARNING
 };
 
 struct wt_status {
-- 
1.4.4.1.g1210

^ permalink raw reply related

* Re: [RFC] Submodules in GIT
From: Linus Torvalds @ 2006-12-02 19:52 UTC (permalink / raw)
  To: Josef Weidendorfer; +Cc: sf, Git Mailing List, Martin Waitz, Andy Parkins
In-Reply-To: <200612021232.08699.Josef.Weidendorfer@gmx.de>



On Sat, 2 Dec 2006, Josef Weidendorfer wrote:
> > 
> > The only _true_ namespace would be the SHA1 of the commit (and maybe allow 
> > a pointer to a tag too, but the namespace ends up being the same).
> 
> I am not so sure about this.
> Perhaps we want the namespace to be more than the space of commit ids.

I don't think it would be wrong at all to have a "link object" type, and 
have the "link" tree entry actually point to that "link object" instead of 
pointing directly to the commit in the submodule.

And yes, that extra indirection would allow for more flexibility (the 
"link object" can contain comments about the particular version used, 
pointers to where you can get it - whether human-readable or strictly 
meant for automation - etc etc).

So I agree with Andy Parkins' comment about the link object allowing not 
only extended namespaces, but also allowing a certain amount of 
flexibility (ie there's some built-in extensibility and ability to perhaps 
add future fields if there's a new object type).

I just want the naming of the links themselves to use all the same SHA1 
hashes etc, so that you always have a very explicit, and very trustworthy 
version - and never end up in the situation that you know which repository 
you want at that position, but you don't know exactly which commit in that 
repo was supposed to be checked out with that particular version of the 
super-module.


^ 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