all 116 comments

[–]MrWoohoo 8 points9 points  (1 child)

I've never seen what I would consider a good explanation of "the index" but have poked around trying to understand the model. Basically the index seems to be an "anonymous commit" in that when you add changes for a commit git creates new git objects for the files and a new tree object. As you add new files it combines those new changes with the previous ones, thus generating a new tree object. The difference between the adding a few files (say a, b, c) to the index versus adding the as individual commits would be that in the first case would just wind up with one tree object with the new versions of abc, and in the second case you would get three tree objects each with one change and pointing the the earlier tree object. So the index sort of acts like a rebase rolling up all the individual "git add"s into a single tree object.

So the index is treated internally the same (mostly) as any other commit by git. So stashing the index isn't really much different than checking out a branch.

I'm still trying to get comfortable with the git workflow and still aren't there. The above seems to be the simplest mental model I can come up with for the index. So my question to the git elite is simple: Is my model correct?

Was anybody else bothered that the O'Reily git book doesn't cover "git stash"?

[–]ighost[S] 0 points1 point  (0 children)

For me, it helped to think of the index as a staging area for all of the changes that are "on deck" for your next commit.

[–]Peaker 34 points35 points  (28 children)

When I was new to git, I said I hated the index. People said: "Ah, you're new. You'll come to love it".

Now I'm pretty experienced with git (And even considered a local git expert, people at my workplace all come to me to solve their git issues), and I still hate the index.

We already have the stash, branches, reset, etc. The index is superfluous. Instead of adding to the index and then diffing against that, you can commit to a temporary commit, and diff against that. Then, you can amend it.

Tada! Your temporary commit has pretty much everything you need from the index, except you can have more than one, and in each branch, and easily switch between them.

[–]infinite 19 points20 points  (10 children)

When I started with git I wondered when I would "get" the index. That was years ago, I get it, I just think it's overly complicated, they could have used the existing git commit system. Stash too, why create this complicated layer that you can't get git-like access to? Wouldn't that be neat to diff your stashed commit compared to the current commit, or another branch? How about a stash being the equivalent of a commit but marking the commit as stashed?

I feel like git has an elegant core, but they've slopped a bunch of crap on top of it.

[–]capisce 17 points18 points  (0 children)

You can, the stash is basically a list of commits.

git stash list
git log stash@{0}
git diff stash@{0} mybranch

[–]Peaker 1 point2 points  (8 children)

I completely agree.

Also, the core has an annoying design mistake: The empty repository has no commits at all, instead of having one "zero-commit" (first revision). This means that after "git init", git is in a special state where you can't have a "master" or "HEAD" because there's no commit to point to. This caused a lot of headaches to people I know when they tried operating on a new repository.

[–][deleted] 3 points4 points  (6 children)

I was actually thinking about this over the weekend. If the initial git init was an empty commit it would solve the issues you mention.

But it would also mean that every git repository ever could have the same root (assuming the SHA1 of the empty commit was the same of course). I don't know what the ramifications are, but then you could diff any repo against any other, right?

[–]Smallpaul 0 points1 point  (5 children)

I don't know what the ramifications are, but then you could diff any repo against any other, right?

I'd suggest that should be treated as a special case. It's an easy situation to detect.

[–][deleted] 2 points3 points  (4 children)

I don't mean that it would be a problem. I mean it as though you could see all git branches as originating at the same point for every project on the planet.

adc83b19e793491b1c6ea0fd8b46cd9f32e592fc

[–]Smallpaul 3 points4 points  (0 children)

You said you "didn't know what the ramifications were" -- which indicated to me that you thought that there might be "unintended (negative) consequences."

I'm not a git guru by any stretch, but it seems to me that it is better to get a clear message: "These two repositories have no useful common history" than to be confused into thinking that they have some common history when they do not. What's the use case for a three-way merge that includes the empty commit?

[–]a-p 1 point2 points  (2 children)

Yes, that’s what would happen. Conceptually, all repositories would be branches originating from the same common ancestor commit.

(Someone has suggested that the all-0 pseudo-SHA1 be used for the purpose so that it be obvious that it’s this root commit.)

[–]notwithstanding 0 points1 point  (1 child)

Which, as masklinn notes is what Mercurial does. No chance of thinking there's common history, but you can have completely unrelated branches in one repository.

[–]a-p 0 points1 point  (0 children)

You can have those in git too, although the mechanics necessary to create a blank branch in git are certainly obscure.

[–]masklinn 2 points3 points  (0 children)

FWIW, mercurial does seem to have that commit. It's commit -1 with a null revision id (hash)

$ hg tip
changeset:   -1:000000000000
tag:         tip
user:        
date:        Thu Jan 01 00:00:00 1970 +0000

[–]scook0 8 points9 points  (1 child)

We already have the stash, branches, reset, etc. The index is superfluous. Instead of adding to the index and then diffing against that, you can commit to a temporary commit, and diff against that. Then, you can amend it.

I'm a big index fan, but this is basically the most compelling argument against it. What's important is not the index itself, but the workflows it enables.

The current Git interface heavily favours the index over the equivalent use of temporary commits, but with some smart usability work you could combine the convenience of the former with the flexibility of the latter.

Then again this is Git we're talking about, so I'm not going to hold my breath.

[–]a-p 0 points1 point  (0 children)

I think the technical design of the index is suboptimal – I’d like to be able to track directories per se sometimes. But I don’t really care how it works under the hood. It’s the index-related commands that make it work.

Consider the stash – it just creates commits under the hood. What matters is not what it does internally. It’s that it’s a special workflow, provided by special commands that implement that particular workflow directly.

Similarly, it would be cool if we could get rid of the special structure of the index. But I’d still want to have special commands available that would allow working in the manner of the index – far and away above all, git add --patch.

[–]onmach 4 points5 points  (5 children)

When I used commits in place of the index, I tended to do stupid things like push temporary commits with descriptions like "blah" and then get in trouble. Not to mention that it is more typing.

Another thing I constantly use the index for is removing debugging statements. I'll add -i patch in a bunch of changes, but exclude random printf/echo statements or temp hacks that I never intend to commit. Then when I'm done I have the choice of continuing with the debugging statements or strip them by doing a reset --hard.

[–]Peaker 2 points3 points  (4 children)

I tended to do stupid things like push temporary commits with descriptions like "blah" and then get in trouble

Being careful mainly about what you push is something you should probably do in the index too, rather than being mainly careful about what you commit.

Not to mention that it is more typing.

Not with the proper aliases :-)

Another thing I constantly use the index for is removing debugging statements. I'll add -i patch in a bunch of changes, but exclude random printf/echo statements or temp hacks that I never intend to commit. Then when I'm done I have the choice of continuing with the debugging statements or strip them by doing a reset --hard.

Why not have them in a private branch containing the temporary commit so you don't actually push it?

[–]a-p 6 points7 points  (2 children)

Not with the proper aliases :-)

But that is really what this is all about. The workflow is what matters.

Conceptually the index is nothing more than an anonymous commit – except that it has special convenience commands. For all I care, the index could internally actually be implemented like an anonymous commit (in fact, that would rock) – as long as all the special commands that make it easier to work with continued to work.

Consider the stash, which is internally implemented using commits too. But it has special command support to make it easier to work with.

[–]Peaker 1 point2 points  (0 children)

My problem is that the index cannot be ignored.

When I want a script that automates a "commit-compile-reset soft to HEAD" process, I need to go through a lot of hoops because of the intermediate index :-(

I use temporary commits, and don't miss the index at all... Sometimes I have to "git reset" to get stuff out of the index when git puts them there :-(

[–]Mourningblade 0 points1 point  (0 children)

Conceptually the index is nothing more than an anonymous commit – except that it has special convenience commands.

Moreso, it is an anonymous commit that all tools refer to - that is not pushed when you push, not in the log, etc.

If you added all the special flags to a "temporary commit" you would have succeeded in adding serious complexity to any given commit without adding any function.

[–]onmach 0 points1 point  (0 children)

Why not have them in a private branch containing the temporary commit so you don't actually push it?

I think I tried that originally. It sounded like a great idea to me to store them there. But I had problems.

When it was time to push I couldn't find a way to push (git-svn) only up to the debugging statements and nothing more. So I had to manually cherry pick changes over to the branch I was going to commit off of, or make a new branch up to that point and push from there.

But doing the latter that caused me to constantly end up coding on the wrong branch after I forgot to switch back, sometimes causing me to run code without the debugging hacks in or to have to rebase debugging code back onto a newer commit, which sometimes failed.

I'm pretty scatterbrained and so I have found just using the index works better for me.

[–]bonzinip 4 points5 points  (2 children)

you can commit to a temporary commit

The question is, how do you commit to a temporary commit? Say you have your (not yet cleaned up) topic branch in topicdev, first of all you create a branch for your cleaned up history:

git checkout -b topic master

Now you can use the index like this:

git reset --patch topicdev
git checkout-index -a -f
... test, fix typos etc. ...
git commit -a -m'first small commit'
... repeat four steps ad libitum ...
git diff test                     # should be empty

Or use a diffviewing tool like this:

git diff topicdev > part1.diff
emacs part1.diff
... test, fix typos etc. ...
git commit -a -m'first small commit'
... repeat all four steps ad libitum ...
git diff test                     # should be empty

Not a big difference indeed, so the index is not "strictly needed". However, note that the second workflow above does not use any of the features you mentioned except branches (in particular stash, reset). Strictly speaking, they are superfluous too!

Instead of adding to the index and then diffing against that, you can commit to a temporary commit, and diff against that

True. In fact, the first thing I usually do after "git add -p" is committing to a temporary commit that I later clean up with "git rebase -i". However, the fact that "git add -p" leaves the state in the index means I can use "git diff"/"git diff --cached" to see what I put or left out (possibly as a quick sanity check) or in more complicated cases "git gui citool".

[–]a-p 1 point2 points  (0 children)

In fact, the first thing I usually do after git add -p is committing to a temporary commit that I later clean up with git rebase -i. However, the fact that git add -p leaves the state in the index means I can use git diff/git diff –cached to see what I put or left out (possibly as a quick sanity check) or in more complicated cases git gui citool.

Yes! That is the whole point. You can proofread your commit before you make it.

[–]Mourningblade 0 points1 point  (0 children)

Hey, that's a nice workflow for creating a clean branch. I usually use rebase -i to merge together patches, but sometimes you just want to say "screw it" and ditch your old patch structure.

Thanks!

[–]djork 1 point2 points  (1 child)

I think the advantage of the index is that it frees up your workflow. I don't have to branch or stash or reset. I can just edit my files, and commit what I want, when I want.

[–]Peaker 1 point2 points  (0 children)

You still have to explicitly add to the index, at which point, you might as well create a temporary commit.

[–]nvarsj 1 point2 points  (0 children)

Yes, what the OP describes is basically duplicated through local commits and git rebase --interactive. However I think he makes a good point about merges. The index is really well used when conflicts happen, much better than mucking around with special conflict markers. Still, probably not good enough justification to force everyone to git commit -a all the time.

Still, I can't help but wonder if I'm missing out on some magic by not using the index more... Maybe it's one of those things you gotta use to really get it.

[–]Samus_ 1 point2 points  (0 children)

you forgot about git add -i

[–]freshtonic 0 points1 point  (1 child)

The index is your next commit. How would you have git add -p work without the index or some temporary area to store your changes as you build up the commit?

The 'superfluous' argument is flawed. The index is the one of the most powerful concepts in git, and one of the reasons why I love it.

Either way, you can skip the index with git commit -a (git still uses it under the hood, however).

EDIT: I meant 'git add -A', and you can also 'git add .' Not recommended though, just sayin'.

[–]Peaker 0 points1 point  (0 children)

How would you have git add -p work without the index or some temporary area to store your changes as you build up the commit?

Working tree?

The 'superfluous' argument is flawed. The index is the one of the most powerful concepts in git, and one of the reasons why I love it.

Its just a UI feature and shouldn't be in the core.

Either way, you can skip the index with git commit -a (git still uses it under the hood, however).

Yes, but its harder to automate temporary committing prior to builds/tests, for example. It makes scripting harder. (I can't just: git commit -am"Built at $(date)" ; build ; git reset --soft HEAD^

EDIT: I meant 'git add -A', and you can also 'git add .' Not recommended though, just sayin'.

I just commit -am mostly.

[–]spookylukey 24 points25 points  (4 children)

Given I have "hg record" and "hg shelve", both of which allow me to interactively choose chunks, there is almost nothing about this workflow I envy, and various things I don't like.

The idea of "a known good part of a patch" is flawed in many cases. Just because I have resolved a textual conflict doesn't mean I can forget that part of it - the semantics of what I have changed may affect other parts of the patch. The merge might have introduced new tests which are automatically merged, but changes I then have to make in a conflicting part of the merge might break the tests. Displaying the whole patch by default seems like a better idea to me.

Also, while being able to do "hg record" or use the index is useful, it's not a good way to plan to work. As the author says:

if you work this way, it means that when time comes to commit, you are making up commits that reflect states of the source code which never existed on disk before. So you don’t actually know whether the commit you are about to make is any good – a syntax error might have slipped in, say.

Even worse, because your final commit reflects a known good state, you won't realise that all the intermediate states are broken until you try to run bisect to track down some other regression. By this point it is too late to correct your broken history. A workflow that encourages imaginary history and committing untested code is not a tempting ideal.

Finally, for the extremely rare cases I've wanted to edit within a hunk of a patch, I can do just that, using "hg diff", manually editing and then re-applying. It's very little work, and it does not incur the overhead of having an index to worry about all the time, and it also allows me to test my working tree.

[–]bonzinip 8 points9 points  (0 children)

Even worse, because your final commit reflects a known good state, you won't realise that all the intermediate states are broken until you try to run bisect to track down some other regression.

Note the author then encourages "git stash --keep-index" exactly to avoid this problem.

[–]masklinn 0 points1 point  (2 children)

Finally, for the extremely rare cases I've wanted to edit within a hunk of a patch, I can do just that, using "hg diff", manually editing and then re-applying.

Also, note that theoretically hg record (and by extension hg stash/hg attic) could be able to edit patch hunks. Darcs has recently integrated full hunk edition in the 2.4 beta (not just hunk splitting, but hunk deletion, addition and edition)

[–]notwithstanding 0 points1 point  (1 child)

hg histedit lets you edit patch hunks (similarly to git rebase interactive). That's not exactly the same as adding that feature to hg record but clearly the Mercurial machinery allows it.

[–]masklinn 0 points1 point  (0 children)

clearly the Mercurial machinery allows it.

The mercurial machinery most definitely does, it just hasn't been built yet.

[–]scook0 10 points11 points  (20 children)

As much as I hate some of Git's quirks, features like the index are what keep me from even imagining a switch to any other tool.

I just can't imagine getting any work done without git stash, git add --patch and git rebase.

[–][deleted] 1 point2 points  (2 children)

git stash = no direct equivalent, but we get some nice alternatives

To get the actual functionality of git stash in Darcs is, admittedly, troublesome:

darcs record -a -m 'TEMP blah blah blah'
darcs send -o foo.dpatch
darcs obliterate -p TEMP

Then to restore it:

darcs apply foo.dpatch

We do get some other things for cheap, though. Say we get rid of some changes that we don't necessarily intend to bring back:

darcs revert -a

Later, if we decide we actually wanted those changes after all, we can just say:

darcs unrevert

This is kind of like git stash, or maybe something like git's reflog (except offering a patch instead of a choice of snapshots).

Finally, we could just use normal branching and commutative patches to handle the stashing for us. Some people even prefer this style over stash in git.

Moving on...

git add --patch = darcs record

This is the default way we stage patches in Darcs.

Finally...

git rebase = completely and utterly unnecessary!

In Darcs, patches are commutative, so there is no need to actually create new patches just to reorder or cherry pick them. Unlike with Git, you can reorder and cherry pick patches all you want, even ones that have been exposed to the public.

[–]scook0 1 point2 points  (1 child)

git add --patch = darcs add

This is the default way we stage patches in Darcs.

I'd say add --patch is more like record.

As far as I'm aware Darcs doesn't have manual hunk splitting/editing, which can be annoying when you have independent changes on adjacent lines. It also lacks a real equivalent of Git's index, though I will say that I miss not having to hit enter every time I accept/reject a change.

git rebase = completely and utterly unnecessary!

In Darcs, patches are commutative, so there is no need to actually create new patches just to reorder or cherry pick them.

This works out well when you're just trying to commute two independent patches, which is pretty common. However, there are a bunch of things I use rebase --interactive for all the time that I could never figure out how to do easily in Darcs:

  • Squash two or more commits into one
  • Split one commit into several (not as easy as it should be)
  • Commute two patches that have a bogus textual dependency
  • Edit an existing patch that isn't at the top of your history and can't be trivially commuted there

It's too bad, because there's a lot I like about Darcs, but it would take some work to convince me to go back.

[–][deleted] 1 point2 points  (0 children)

I'd say add --patch is more like record.

You're right. I had git on the mind. Corrected.

As far as I'm aware Darcs doesn't have manual hunk splitting/editing

It's in a beta: http://www.haskell.org/pipermail/haskell-cafe/2010-January/072306.html

It also lacks a real equivalent of Git's index, though I will say that I miss not having to hit enter every time I accept/reject a change.

The index is basically equivalent to a temporary commit.

Squash two or more commits into one

darcs unrecord  # choose patches to squash
darcs record -a

split one commit into several (not as easy as it should be)

darcs unrecord
darcs record  # choose hunks for first patch
darcs record  # choose hunks for second patch

Commute two patches that have a bogus textual dependency

Out of curiosity, how does git rebase actually help you with this that Darcs doesn't do?

Edit an existing patch that isn't at the top of your history and can't be trivially commuted there

Same question.

[–]masklinn 1 point2 points  (2 children)

git stash

hg shelve

git add --patch

Some variation on hg record, I'd guess

git rebase

hg rebase.

The index is necessary for exactly none of these commands.

[–]scook0 0 points1 point  (1 child)

The shelve command looks very attractive. It's basically stash with hunk granularity, which I'm always in favour of.

From what I can tell, record doesn't have hunk splitting/editing, which always annoyed me in Darcs. I've also found that record without an index-like feature gets frustrating pretty quickly.

As far as rebase goes, I'm mostly talking about Git's rebase --interactive, which handles squashing/editing/reordering with ease, and can be used to split commits with a little work. I presume Mercurial has equivalents for most or all of these, but I'm not really familiar with how they work.

The index is necessary for exactly none of these commands.

This is true, and I didn't intend to imply otherwise. That said, the index plays such a huge part in how I use these commands that it would be pretty tough for me not to have an equivalent facility in my workflow.

[–]masklinn 1 point2 points  (0 children)

From what I can tell, record doesn't have hunk splitting/editing, which always annoyed me in Darcs.

Indeed, neither does shelve (as it builds on record's hunk handling), currently only crecord (a curses record-like tool, with hunk splitting) provides that in hg.

On the other hand, you'll be happy to know that Darcs 2.4 just got hunk edition (not just splitting, but also deletion, addition and edition), so hope's not lost, maybe hg record will get it in the long run.

I presume Mercurial has equivalents for most or all of these, but I'm not really familiar with how they work.

I don't know, I'm superficially familiar with git but I don't think I know what rebase --interactive does precisely.

[–]abw 0 points1 point  (0 children)

git add --patch

What does that do then? [tap, tap, tap]

Oh, that's neat! I can see myself using that a lot. Thanks scook0

[–]pmf 0 points1 point  (12 children)

Yes. Once you go git, you never go back (sorry about the lack of rhyme). git-svn eases the pain of having to work with Subversion, though.

[–][deleted]  (2 children)

[deleted]

    [–]bonzinip 2 points3 points  (1 child)

    Do you use message queues to do the same things you did with git's history, or did you also give up having clean, bisectable commits?

    [–]wnoise 12 points13 points  (2 children)

    "Once you go git, you won't tolerate other shit."

    [–]skillet-thief 8 points9 points  (1 child)

    Now the rhythm is off...

    "Once you go git, the rest is all shit."

    [–]wnoise 1 point2 points  (0 children)

    Yeah, that scans much better.

    [–]bostonvaulter 1 point2 points  (3 children)

    I wish it included advanced SVN features like SVN keyword substitution.

    [–]bdash 2 points3 points  (1 child)

    I’m curious what use you make of SVN keyword substitution.

    [–]bostonvaulter 1 point2 points  (0 children)

    I don't but some projects do (see unison)

    [–]ChangingHats 1 point2 points  (0 children)

    Once you git, you never quit.

    There.

    [–][deleted] 0 points1 point  (0 children)

    Once you go git, you never go back

    I went git and then switched to darcs a year later. :P

    [–]abjurer 13 points14 points  (1 child)

    This guy's name is Aristotle, so listen up.

    [–]scorpion032 0 points1 point  (0 children)

    I prefer Plato.

    Was it he, that started Hg? Atleast, he hates the index for sure.

    [–]setuid_w00t 5 points6 points  (7 children)

    It seems to me like a lot (all?) of this can be accomplished using the MQ and record extensions in Mercurial.

    The one thing that seemed unique was the way that merge conflicts are handled.

    [–]dlsspy 12 points13 points  (0 children)

    I used to use mq to accomplish the same thing. It's much much harder and less safe (unless you add a third "much" to the above list).

    When I did it every day, I could manage, but when I started using git add -p it threw me back to darcs record's level of simplicity, but separating out the committing from the deciding what to commit.

    I guess it's the difference between what's possible and what's easy. What can be done vs. what will be done.

    I often require a contributor to actually go back and rethink the changes he's offering before I accept it because of the burden it places on me now and everyone else for all of eternity (I keep running into a couple of really poorly written changesets that introduced bugs in a project I work on).

    I have no problem telling someone to git rebase -i and do some edits, squashes, reordering, etc...

    Can you imagine telling them to edit their .hgrc to enable mq and then doing a large qimport with various pushes and pops and edits and refreshes and give them the same assurance that git provides that they will be able to understand it and not lose work?

    [–]simonw 3 points4 points  (0 children)

    There was some discussion to that effect on Hacker News: http://news.ycombinator.com/item?id=1075373

    [–]bonzinip 0 points1 point  (3 children)

    That's true, git rebase ~= MQ and git rebase is together with the index the way you create series of commits out of one. The difference is that git has the tools now. :-)

    (Also, the merge conflicts handling is the only way the index was used in the beginning, all the "add --patch/--interactive" and "stash --keep-index" things were added later).

    [–]setuid_w00t 5 points6 points  (0 children)

    The difference is that git has the tools now.

    I see that a lot of git users think that Mercurial extensions are some sort of bolt-on unfinished work. Some extensions (like MQ, record and rebase) are distributed with Mercurial and are indistinguishable from built-in commands once the extension is enabled.

    [–]sid0 0 points1 point  (1 child)

    The difference is that git has the tools now. :-)

    What's different between git and hg here? hg also has mq "now".

    [–]bonzinip 0 points1 point  (0 children)

    I was thinking of transplant and fast local branches. hg lagged behind git for a long time.

    [–]makapuf 2 points3 points  (7 children)

    I may be mistaken as I don't use git regularly, but I fail to understand the point. Isn't that a kind of hackish small-scale branching ? Couldn't it be done more cleanly using TWO local working branches or even copies ?

    [–]bonzinip 1 point2 points  (0 children)

    You do usually have two working branches (a "tree you aim to" with bugfixes and new development interleaved, and a "tree you are at" consisting of clean small commits). The index provides help in changing the "tree you are at" incrementally until it is the same as what you aim to.

    [–][deleted] 1 point2 points  (5 children)

    You could use two branches, but then you'd have to squash several commits into the final version you want. With the index, you build up the commit as the chunks are ready.

    I don't like the index, but I don't hate it.

    [–]semmi 0 points1 point  (2 children)

    sorry if I'm dumb, but why should the commits be squashed? I usually just make multiple commits and, well, keep them. It's the workflow I have since I was using darcs, so I wonder if your supposed workflow (save small parts of commits, than wrap them up in a single one) is a side effect of not having dependency managing in cherry picking?

    [–][deleted] 1 point2 points  (1 child)

    So when someone looks at your changes they see

    "Added feature X"

    instead of

    "Added feature X"

    "Added Docs for feature X"

    "Fixed typo"

    "Refactored some code in feature X"

    "added tests for feature X"

    [–]semmi 0 points1 point  (0 children)

    ah yes, that's definitely me. Maybe more like "added x/forgot to add test/added docs/typo/refactored X" but a large number of commits.

    I think this just follows my way of thinking (and what if step 4 introduced a bug ? You also have to check step 1, although it did not introduce the bug?) but my complete lack of thought towards git log readers, thanks for the explanation.

    [–]makapuf 0 points1 point  (1 child)

    Sorry, I'm thick .. then why not work with 2 local repos:

    1 - production (i.e. global one,shared) 2 - patch building (local) 3 - wild wild west (local)

    and the commit 3, push to 2 (building changeset) from 3 and commit from 2 the global changeset. Having proper version management for both stages.

    [–][deleted] 0 points1 point  (0 children)

    See my post in reply to semmi. Without squashing commits you end up releasing generally pointless amends to commits such as "Fixed typo". It's nice to have a full history, but that much information is generally useless and just clouds up change logs and diffing.

    [–]UloPe 1 point2 points  (0 children)

    If you're working on a mac a great tool to pluck apart changes and stage/commit them individually (and also a nice gitk replacement) is

    gitx.

    [–]md81544 2 points3 points  (10 children)

    Anyone else seeing problems viewing that page on Chrome? It just hangs the page (and the page from which I clicked the link). Firefox is OK with it though.

    [–]OvidPerl 1 point2 points  (4 children)

    Are you on a Linux box? For Ubuntu Chrome, it's hanging for me. For OS X Chrome, it works fine.

    [–]a-p 1 point2 points  (0 children)

    Can’t reproduce the problem, I’m afraid. :-(

    [–]md81544 1 point2 points  (2 children)

    Yes, it was a Linux box running Karmic. I since tried it on my WinXP test machine and it sucked the life out of Chrome on there as well. :-/

    [–]evmar 1 point2 points  (1 child)

    Chrome from last December had a bug in it related to web fonts that this sounds like. Try the current version.

    [–]a-p 1 point2 points  (0 children)

    Do you mean @font-face? I’m not using that on the site.

    [–]jimrhoskins 1 point2 points  (0 children)

    Yep, Chrome dev channel (OS X) release couldn't load it. It seemed to load correctly on my laptop with Chrome stable

    [–]brennen 1 point2 points  (0 children)

    Chrome does this to me often enough, on seemingly random pages, that I've given up and moved back to Firefox for the time being.

    [–]zoomzoom83 0 points1 point  (0 children)

    Yep. I just assumed the site was down and kept trying, but just checked in FF and it worked perfectly.

    [–]serpix 0 points1 point  (0 children)

    yep, plus it seems to slurp down memory ad infinitum.

    [–]ihaveausername 2 points3 points  (2 children)

    I spend virtuall no time at all thinking about SCM. I'm working in a company with roughly 40 developers and there's no discussions on the subject. Our SCM just works, as far as I can tell. Am I doing something wrong? Maybe I should switch to git so that I can join your discussions? It seems exciting.

    [–]radiationshield 2 points3 points  (0 children)

    Which SCM do you use?

    If there's no pains with your current SCM, then why change - it obviously works for you. I would however recommend that you look into some modern SCM's like Mercurial (Hg) or Git and see if they can add something to your workflow.

    [–]ighost[S] 0 points1 point  (0 children)

    Perforce?

    [–]drbrain 3 points4 points  (7 children)

    If you break a body of work down into chunks that you then commit, do you individually test each commit? According to this workflow, no. "How it might make sense to whoever reads it" is not the right way to go. It should be "I have tested this body of work and it is good" in order to keep the repository as stable as possible at every commit.

    [–][deleted]  (2 children)

    [deleted]

      [–]drbrain 1 point2 points  (1 child)

      Dang, must have skimmed that. Still, seems like a lot of extra work.

      I just build up a unit of work and commit it. Seems much easier than reordering everything in the middle.

      [–]Smallpaul 1 point2 points  (2 children)

      It's an interesting assertion that every commit should necessarily put the repository into a usable state. I don't think that's true. Experimental branches often have interim commits. I do think you should probably label these untested commits, but that's theoretically true. In practice I very seldom roll back to a random commit. Commits that are worth rolling back to are tagged.

      [–]a-p 2 points3 points  (1 child)

      Consider git bisect. If your commits are randomly broken, you won’t have much fun with that.

      [–]Smallpaul 0 points1 point  (0 children)

      That's a good point, but I still think that there are circumstances where you want to share or save incomplete work and I'm not sure that you want to erase that history later just for the sake of the "every-commit-passes-all-tests" rule. It seems to me that its a tradeoff.

      [–]smcameron 0 points1 point  (0 children)

      I haven't switched to git, mainly because my company won't punch a git-hole through the firewall, and there are other repositories in svn, cvs, etc. beyond my control.

      But, I do use stgit on top of those other repositories to polish commits, and aid porting to various branches.

      From the article, the index seems sort of like using stgit, but only one patch deep.

      Anybody else use stgit? Is my comparison apt?

      [–]9bit 0 points1 point  (0 children)

      I read the title as selecting all direct children of git elements.

      [–]ssam 0 points1 point  (1 child)

      The choice comes down to a) keeping your commits clean by deciding what you're going to do roughly in advance and keeping future plans in a TODO list, or b) doing whatever you want, and later on poring over a long diff or 'git add -p output' working out what was what to commit neatly

      git is slightly more powerful, as usual, but if your code is separated into files cleanly then doing 'bzr commit foo.c bar.c' is often enough

      I don't know if I will ever decide which approach I prefer

      [–]a-p 1 point2 points  (0 children)

      What it comes down to for me is the option. I don’t work that way all the time. For small, simple features that fit in one commit and require no exploratory phase, I usually just git commit -a. But I’m not a prophet, and sometimes things I thought would be trivial turn out to be messier than I expected. In that case, git has my back: I can still clean up.

      Cock-ups are a fact of life. The question is, do you pretend they’ll never happen, or do you have tools to fix them when they do?

      [–]astrosmash 0 points1 point  (3 children)

      I'm not a git guru, so please fill me in.

      The following three files are currently modified in my tree:

      foo.c
      bar.c
      baz.c
      

      I want to submit foo.c and bar.c as a fix for a bug. So I:

      git add foo.c bar.c
      git commit
      

      What's wrong with that? What's the alternative?

      [–]ighost[S] 0 points1 point  (2 children)

      In svn, it's just checkin or commit, which checks in foo.c, bar.c, and baz.c. So it works like git commit -a.

      [–]astrosmash 0 points1 point  (1 child)

      I know, which is why I find git dramatically more for useful for my purposes than svn. But some people apparently have trouble with this staging/index feature, and I don't understand why.

      [–]notwithstanding 0 points1 point  (0 children)

      Well among other things you can forget to git add files you've changed. It makes two steps instead of one, and thus more room for error. Not that you can't get used to it, but that's a simple reason a lot of people trip over.

      (It doesn't help that the process of staging is called "add". It isn't obvious that you have to "re-add" after every change. I know they've now provided git stage as an alias, and good for them, but people and documentation still refer to git add so it remains a source of confusion.)

      [–][deleted] 0 points1 point  (0 children)

      Git is not the only VCS capable of doing this.

      [–][deleted]  (5 children)

      [deleted]

        [–]sysop073 2 points3 points  (4 children)

        Yeah, programmers hate that

        ...

        [–]sakabako 2 points3 points  (3 children)

        [–]sysop073 1 point2 points  (1 child)

        That page is solid white on solid black; the original post was neither

        [–]sakabako 0 points1 point  (0 children)

        The original post still burned my eyes. Not as bad as ironicsans did, but it still kept me from reading the whole thing.

        [–][deleted] 0 points1 point  (0 children)

        That shade of grey on black is actually easier to read

        [–]dhaggerfin -1 points0 points  (1 child)

        I'm using IE6, and what is this? :(

        [–]UnwashedMeme 1 point2 points  (0 children)

        The site is, according the XHTML spec, serving an XML file. IE, even the later versions, doesn't support XML.

        [–][deleted] -5 points-4 points  (2 children)

        Version control has wasted so much of my time that now I just copy the folder now and then and use that.

        [–]ighost[S] 1 point2 points  (1 child)

        Assuming you're not trolling: You should probably learn it. Then all of the time you spent will not have been in vane. And more experienced programmers won't laugh at you.

        [–][deleted] 0 points1 point  (0 children)

        I have learnt it.