Re: Git documentation on branching.
- Date: Mon, 10 Apr 2017 20:13:13 +0300
- From: Konstantin Khomoutov <kostix+git@xxxxxxxxx>
- Subject: Re: Git documentation on branching.
On Mon, 10 Apr 2017 12:24:47 +0200
Samuel Åslund <samuel@xxxxxxxxxxxx> wrote:
> >> One feature with "git branch xyz" and "git checkout xyz" that is
> >> rather obvious if you know them but bit me a little since I did
> >> not, is that uncommitted work in progress is not affected or saved
> >> when switching between branches.
> > [...]
> > But neither is uncommitted work saved anywhere when you do
> > `svn switch` in Subversion which is analogous to `git checkout`.
> > While I do know quite many people expect Git to somehow "preserve"
> > their work when switching branches without having them do anything,
> > I wonder what in Subversion workflow makes you think Git should have
> > had the behaviour you expected?
> svn switch is heavy, thus I usually checked out a new branch in
> another directory. So probably not the Subversion workflow but rather
> _my_ workflow in Subversion.
Yes. The equivalent thing with Git would be using its `git worktree`
subcommand (which is a stock subcommand since some time, and previously
was available in the form of an external script). The said command
basically creates another "checkout" -- a working tree and a separate
index -- linked to the original repository. You can have any number of
such separate work trees, and what's checked out in them is completely
irrelevant to the repository itself (which only keeps commits and the
data they refer to).
Note that since `git worktree` was (is?) sort of a clever hack not
originally envisioned as one of "stock" workflows, its insufficiently
covered by the documentation. And while it indeed may be useful --
sometimes it's ineed convenient to have two versions of the same
codebase to be checked out side-by-side, -- I'd warn you against
rushing for using `git worktree` as it appears to support what you did
with Subversion: there is another approach to support your mindset
which I'll explain in a moment.
> Either way, your comment about peoples expectations was what I wanted
> to address. Expectation management is the responsibility of the
> documentation, right?
It's hard to tell -- as Ævar Arnfjörð pointed out: there are two kinds
of documentation: manuals and books / introductory courses. As was
shown to you, the manual page on `git checkout` explains what it does.
Whether that's clear right away to any newcomer, I cannot say.
Probably not, but if we'd turn that manual page to a book it will lose
its original meaning of being dry and to the point.
I have that problem with manual pages all the time: quite often they
are most useful on some Nth re-reading, where you approach them with
certain working knowledge under your belt -- and suddenly certain
things you read there "click" in your head; you did read them before
but your mind just skimmed over them while having the impression of
grasping the material.
> I find it quite reasonable to choose whether to stash the work in
> progress myself before checking out another branch, but since I did
> not expect to need to do that I didn't.
> I think that what made me expect Git to handle my uncommitted work is
> how the documentation talks about making it easy to switch between
> working on different features, most of the time I do not feel
> comfortable checking in when a feature is in a broken state and
> interruptions for quick fixes usually comes in those situations.
That's more complicated that it sounds.
Consider the following things (in no particular order).
Sometimes "carrying your uncommitted work over" to another state of the
codebase is precisely what you'd want to happen, and that's what
`git checkout` does for your. It even has a specual "I DO REALLY WANT
IT TO HAPPEN" switch, "-m", which makes that command to try to merge
your local modifications into what is about to be checked out if
otherwise your changes would be in conflict with that state.
What's with untracked files? Sometimes they should be considered part
of the work to be saved away before checking out another state, and
sometimes not (`git stash` has a special switch, "-u" to make it stash
untracked stuff as well). What would be the default mode? Think of
it, and supposedly you'll come to a conclusion that either mode Git
could implement would alienate some group of folks. ;-)
Now let's consider the most interesting bit.
People switching from a non-distributed VC system are inherently and
subconsciously afraid of committing anything which "is not ready".
This is definitely a correct mindset with Subversion (which, IIUC,
still does not implement shelving it considered for a long time)
but not with Git.
Here, it's absolutely OK to lump together all the stuff you're
currently working it by `git add`-ing them, `git commit` it all --
usually putting an informal "WIP" prefix in the front of the commit
message to indicate it's work in progress -- and then switch away to
When back, you just to `git reset HEAD~1` to move your checked out
branch one commit back and still having all your changes where you had
them -- in your work tree. You could have saved a series of N WIP
commits if you wanted it this way for some reason, and then you'd do
`git reset HEAD~N` to achieve the same effect. When you record a new
commit afterwards it will be recorded on to of what you've just reset
your branch to -- as if those WIP commits never existed.
This way your "not ready yet" changes maintained on particular branches
are kept right there -- at the tips of those branches.
Since Git is fine with using any commit for anything -- forking a
branch off it or pushing it, -- it's okay if, say, your boss orders you
to push what you've done on the "develop" branch while you have some
WIP commits at its tip: you just push not its tip but the last "ready"
commit on that branch.
Consider more possibilities ;-)