But isn't this what changelists do? I've certainly done pretty much what you describe in hg, svn and Perforce, which don't have staging areas.
Also, if you end up committing only parts of files, then how do you know that what you commit works?
This. I can't test the staging area so I have zero interest in committing it. Actually I have less than zero interest; I would like my team to be prevented from ever creating untested commits.
This isn't an argument against using staging areas, but against creating untested commits.
If your workflow is that every commit must be tested, the correct approach is to enforce that rule, rather than banning an only tangentially related feature.
> I would like my team to be prevented from ever creating untested commits
Frankly, this demonstrates that you have exactly zero understanding of how git works. If I were the sort to force my team to do something, I would force them to never test uncommitted code. Committed /= pushed. A commit means you can keep working on the code while the tests run, and you won't forget what you actually tested. Then, when the tests come back clean, you won't accidentally push some additional, untested change along with the tested changes.
If you can concurrently build/test and edit, you necessarily have more than one workspace, one of which can take the place of the staging area.
I do like the idea of having a snapshot of a test run, though we'd have to amend the commit or something to indicate that it passed its tests and is a sane parent for new commits on its branch, and I would switch to working on an independent feature rather than trying to do work on code which may or may not be broken.
> If you can concurrently build/test and edit, you necessarily have more than one workspace, one of which can take the place of the staging area.
This takes a really narrow view of what software projects can be hosted in git. If you're working on a huge project which must be built (at least for full builds) and tested "in the cloud", which you trigger by pushing to a temporary remote branch, then no, you need not have more than one workspace. If you're a webdev, then yeah, gitless or any other git workflow without the staging area might be useful for you.
I'm sure that workflow can be made to work, but if I had to answer the question "assume you can't test on your editing box nor edit on your testing box, so how do you get source from your editing box to your testing box?" git would not be anywhere near the top of my list of solutions because it leaves known-bad commits pushed that need to be contained like waste.
> Also, if you end up committing only parts of files, then how do you know that what you commit works?
Because one part was, say, whitespace-errors corrected by my editor, or added/updated comments, or removed dead-and-commented code paths, while the other part was an actual logic change. There are many reasons to modify a file of source-code beyond making the code behave differently, but frequently those aspects come together as "oh, I'll just fix this while it's staring me in the face" and must be picked back apart later.
I do this all the time and the answer is:
I test it.
If there's a certain set of changes i wish to commit in one unit, but i have other changes in flight, then i use staging to prepare and reason about them while being able to diff both staging<->previous and staging<->hdd, make the commit, then stash the hdd state and run tests. Afterwards i can restore the hdd from stash and either amend the commit if necessary, or keep on working.
> Also, if you end up committing only parts of files, then how do you know that what you commit works?
You use your knowledge as a programmer to determine what that part of the file does and whether it can stand independently as a change. This is not always obvious, so in that case, you don't do it. But when it is obvious, it makes it quick and easy to commit it separately.
For example, say you rewrote a function in a script, and while you were at it you improved the usage info (--help). Then you go to commit your changes. You look at each changed hunk, and you see that there are two changed hunks: the function you changed and the help message. With Magit, it's dead simple to commit them separately: 1) select the first hunk, 2) s to stage, 3) c to commit, 4) write the commit message and execute the commit, 5) select the second hunk...
And let's say that, while you were rewriting the function, you commented out some code in the old function. You obviously don't want to keep that old code in the new function, so when you are looking through the changed hunks, you select those lines and press k to revert (or kill) those lines containing the commented code. If you have already staged them, then you can simply select those lines and press u to unstage just those lines, removing them from the staging area but preserving them in the working tree.
The workflow of 1) develop, 2) review and stage related hunks, 3) commit staged hunks, 4) goto 2, also helps a lot by forcing the developer to look at the code he's about to commit. Of course you can just stage everything that's changed and make a big commit, but I find that using the staging area to build up commits before making them helps me catch things that I don't want to commit in the first place. It's really useful for managing config files, because you can commit only the parts you want to save or sync to other systems, while leaving some parts active in the working tree but out of the committed branch.
For example, the Picard music tagger stores window and dialog positions in the same config file along with behavioral settings. I want to store and sync changes to the options, but I don't want to commit and sync every time the window position changes.
The staging area is a powerful (yet essentially optional) feature that, when used correctly, gives the developer great power to make commits more logically independent, while allowing him to develop freely, with little concern for how he will eventually commit the changes he's making.
Well, you don't, so... don't do that. Same thing goes for Perforce; you can already create multiple changelists that you commit independently, so it's easy enough to create a bad commit, because it contains only some of the changes you've got locally.
What you're supposed to do in Perforce of course is to create your changelist, shelves the others, make sure your proposed changelist works independently, and commit it only when it does. Which is analogous to what you're supposed to do with git:
- stage parts of files
- `git stash -k'
- check it works
- `git stash pop'
- commit
But let's be serious here - the true advantage of git comes when you do the pro move.
- stage parts of files
- commit
- (90% of the time) it's good
- (10% of the time) bzzt... it's bad
Now, if you were using Perforce, in the 10% case, you'd be stuffed. Somebody would come over to your desk.
- (them) "Your commit is broken"
Now what can you do? There's no denying it... you gone done fucked up, and there's no denying it.
But with git, you have options. So let's try that again.
- (them) "Your commit is broken"
- (you) (confident tone of voice) "Ah no, you are using git incorrectly, you forgot to git fetchpack
--inflate-upstream-probability-leaves --deny-downstream-packs
--integrate-sideway-arguments --discombobulate-flat-file-compressed-alignment-jobs
-P -Q -J 5 -N 311 -X 0771 -R 0x134774"
- (them) (uncertain)
- (you) (confident gaze. Straight into their eyes. YOU = TIGER)
- (them) (increasingly uncertain)
- (you) (unblinking gaze. You have the upper hand. YOU = 2 TIGERS)
- (them) (wanders off to try your technobabble)
- (you) (fixes your commit)
There's an xkcd about this.
The advantages, I think, are clear.
Aah, sweet, someone else who uses Perforce! I've been wondering, do you use version control as:
1. a way to record logical changes to files (e.g. implement two features without making any commits, then when you're done, pick out the files/chunks that encode each feature and create commits out of them),
2. a record of history (e.g. just start writing code and make a commit every time you compile/run tests without unexpected failures),
3. something else?
I've found it very painful to apply my git-adapted workflow to Perforce: I _want_ to just start coding, testing out various possible design choices and implementations instead of only theorizing about them, but can't (e.g. "I wonder if I could factor out these methods + fields into a different class?" Perforce: oh well, I guess I should write it down somewhere to remember for later. Git: branch my current work, spend five minutes sketching an extraction, then realize it's insane and continue working). Am I crazy and just don't realize ow much better the Perforce model is?