If you have changes—i.e., a dirty work-tree—you have something to commit. At most, you have something you want to commit temporarily.
In other version control systems, you might do this by committing it on a branch. In Git, you can do that too: you don't have to use a branch, but that may be the most convenient way to deal with it in Git, too.
You mention a starting scenario, for which I have a work pattern I find helpful:
A very common scenario arising when people code together is to have to bring yourself (let's say, the feature branch you're working on) up-to-date.
Let's say that you are working on feature-X, which will eventually be put into dev (development branch). Other developers have been working on features Y and Z and one of them has finished and dev is now updated, so you run:
$ git fetch
and see that your dev is now behind origin/dev. That is, you now have:
...--C--D--H <-- master
\
\ I--J <-- origin/dev
\ /
E--F--G <-- dev, feature-X (HEAD)
in your repository. You also have some things in your work-tree that are different from files in commit G. (You might not have a branch named feature-X yet, and have HEAD attached to dev instead. If this is the case, you can simply create it now with git checkout -b feature-X, and now you match the picture.)
The thing to do at this point is to commit the stuff you're working on anyway. This makes one new commit K:
...--C--D--H <-- master
\
\ I--J <-- origin/dev
\ /
E--F--G <-- dev
\
K feature-X (HEAD)
You can now fast-forward your own dev to origin/dev. The basic command method is:
$ git checkout dev # safe, since your work is committed
$ git merge --ff-only origin/dev # or `git pull` if you really insist
The drawing now looks like this:
...--C--D--H <-- master
\
\
\
E--F--G--I--J <-- dev (HEAD), origin/dev
\
K <-- feature-X (HEAD)
Here's where most people just run git checkout feature-X; git rebase dev, which is fine and you should feel free to use that method. (I do that a lot of the time. Consider doing that followed by the git reset HEAD^ trick described below.) But what I sometimes do is simply rename feature-X to feature-X.0, and then create a new feature-X with git checkout -b feature-X:
...--C--D--H <-- master
\
\
\
E--F--G--I--J <-- dev, origin/dev, feature-X (HEAD)
\
K <-- feature-X.0
I am now ready to begin working on feature-X again, and at this point I simply cherry-pick all the feature-X.0 commits:
$ git cherry-pick dev..feature-X.0
which produces commit K' which is a copy of K:
...--C--D--H <-- master
\
\ K' <-- feature-X (HEAD)
\ /
E--F--G--I--J <-- dev, origin/dev
\
K <-- feature-X.0
This works even if there are multiple commits on feature-X.0:
...--C--D--H <-- master
\
\ K'-L' <-- feature-X (HEAD)
\ /
E--F--G--I--J <-- dev, origin/dev
\
K--L <-- feature-X.0
If the last commit of this new feature-X (L' in this version, K' in the one that had just one commit) is really, seriously not-ready-to-be-committed yet, at this point I just use git reset HEAD^ (you can spell it HEAD~ if that's easier, as apparently is the case on Windows) to move the branch name back one step. This removes the end-most commit from the current branch, giving:
...--C--D--H <-- master
\
\ K' <-- feature-X (HEAD)
\ /
E--F--G--I--J <-- dev, origin/dev
\
K--L <-- feature-X.0
and leaves the work-tree "dirty" in exactly the way it was before I began this whole process. (In general, a partial commit is fine, as I'll use git rebase -i later to clean everything up when feature-X is mostly ready.)
If I have to repeat the process, for whatever reason, I rename the current in-progress feature-X to feature-X.1, or feature-X.2, or whatever. I grow a small collection of feature-X-es and occasionally go out to the branch garden and prune the weediest ones. The latest-and-greatest is still named feature-X, but I have all of my previous work available as needed, up until I weed them out. This is better than either rebase or stash, because if the code is complicated and I miss something, I still have the older version, under a name that's recognizable, not just some incomprehensible hash ID in a reflog, and not a stash that's indistinguishable from a dozen other stashes.