* The git newbie experience
@ 2006-05-14 18:36 Tommi Virtanen
2006-05-14 21:26 ` Junio C Hamano
2006-05-14 22:09 ` Junio C Hamano
0 siblings, 2 replies; 12+ messages in thread
From: Tommi Virtanen @ 2006-05-14 18:36 UTC (permalink / raw)
To: git
Here's my thoughts from teaching half a dozen people git recently:
Minimal newbie command set
--------------------------
The complete set of "newbie commands" for useful development work should
be as small as possible, for fast learning.
People can always look up new things when they want to, but if they
don't get the simple things going quickly they will forever see git
as "that overcomplex thing I tried to use once".
Concretely: explain the indexless "git commit -a" case first,
so people don't need update-index right away. Most new docs are
pretty good at this, already.
Fix the cases where "git commit -a" is not enough. Here's a case I
ran into:
- Jack is a beginning user of git and does not (want to) understand
the index (right now).
- Jack works on branch X, say his HEAD points to X1. He has an edited,
uncommitted files with the names A, B and C.
- Jack wants to pull new changes made by others to his branch.
There are merge conflicts in files D, E, ..., Z.
- Jack resolves the merge conflicts and is ready to commit the resulting
merge. Note files A, B and C should not be committed.
1. if Jack says "git commit -a", then A, B and C will be committed
also.
2. if Jack says "git commit", then the current state of the index will
be committed. That is, the commit will not contain the proper
merged state of files D, E, ..., Z.
3. if Jack says "git commit D E ... Z", things work correctly. But
Jack does not want to type or copy-paste that much, and that's
horribly error-prone anyway. If the leaves one file out, or
accidentally adds B there too, the merge goes wrong.
4. if Jack says "git update-index --refresh" and then "git commit",
things work correctly. But Jack doesn't (want to) know about the
index.
My best idea so far is to add a "git commit -A" option, that
essentially does the "update-index --refresh". Whenever index
has a file state != HEAD, update-index it. The modified unrelated
files will have index state == HEAD. Or altering "git commit -a"
to do that.
Except, trying to solve usability problems by _adding_ options
is just insane.
I'd really like to see a way to use git without caring about the
index, and just having things work. I can appreciate the index
is useful, and possibly even necessary to work on projects the size
of the Linux kernel, but I really wish it would default to being
_only_ an optimization, not the central bit of user interface to
prepare commits.
Basic git use _should_ be as easy as basic svn/bzr/hg use. Anything
else will just mean git is not used outside of what codebases Linus
has dictatorship over. (At least not after bzr is more done or hg
more well known; right now git has a very nice feature set, but the
others are catching up fast.)
This is a part that Subversion got right. Basic use needs to be simple.
(If you catch me in agitated mood, I'd claim it's the _only_ part
Subversion got right;-)
And to reply to a comment on IRC I missed at the time:
(21:05:35) gitster: as gittus said much earlier, refusing index is like
refusing git. We might be able to implement "index-less" mode in which
things like merge and am refuse to operate when you have any change from
HEAD in the working tree. Then new users can always do "commit -a".
(21:06:04) gitster: "git-repo-config core.newuser yes" perhaps?
If you do it that way, you only make git unnecessarily hard to use for
newbies. For example, we had a case where we absolutely _had_ to keep
an ugly workaround in the tree, in a file not otherwise edited, but
we definitely did not want to commit the kludge, at least not to the
branch that was really being worked on. So such restricted mode would
just have meant either people could not merge, or they had to use index
anyway. That's a point where people who have a choice make on, and stop
trying to use git.
(21:08:34) ***gitster personally considers getting more users a very
high priority but agrees that from usability point of view, having a
mode to expose "stripped down" set of features for simple needs would be
beneficial.
That I can 100% agree with.
Branch management
-----------------
"master" and "origin" are good enough for the really simple use, but
that starts to fail fast when you add in more branches.
The remotes/* branch support is really nice, but should be used better.
Here's a bunch of wild ideas:
- When cloning a repository, just clone all the non-remote heads to
local remotes/* heads. See what name the remote HEAD points to, store
that locally also as a refs/heads/master, set local HEAD to it. Note,
origin is gone, and is now called remotes/master.
- Alternatively (and I think I like this more): When cloning a
repository, just clone all the non-remote heads to local remotes/*
heads. See what the remote HEAD points to, store that locally
also as a refs/heads/* head, set local HEAD to it. Note, origin and
master are both gone, and accessible via remotes/X and refs/heads/X
(where X is the name remote HEAD pointed to).
- Currently, when people start tracking a new remote branch, they end
up editing .git/remotes/origin and adding new Pull: lines. If they
intend to work on the branch, they also clone the branch locally, and
add a Push: line. Make this simpler. Here's a rough sketch:
"git track [--read-only] REMOTE [BRANCH | --all]"
Without --all, git track would:
- abort if refs/remotes/foo exists
- add "Pull: foo:remotes/foo" to .git/remotes/origin (or the
equivalent config file)
- if --read-only is not given:
- add "Push: foo:foo" to .git/remotes/origin
- fetch foo from origin to remotes/foo
- if --read-only is not given:
- run "git branch foo remotes/foo"
With --all, it would do the same, but for everything the REMOTE has
in refs/remotes/. Exactly when to abort is a bit harder to define,
but still..
- Or, if that's too much, at least make peek-remote understand
.git/remotes/* shortcuts, so finding out what branches exist is a bit
simpler.
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: The git newbie experience
2006-05-14 18:36 The git newbie experience Tommi Virtanen
@ 2006-05-14 21:26 ` Junio C Hamano
2006-05-14 22:09 ` Junio C Hamano
1 sibling, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2006-05-14 21:26 UTC (permalink / raw)
To: Tommi Virtanen; +Cc: git
Tommi Virtanen <tv@inoi.fi> writes:
> (21:08:34) ***gitster personally considers getting more users a very
> high priority but agrees that from usability point of view, having a
> mode to expose "stripped down" set of features for simple needs would be
> beneficial.
>
> That I can 100% agree with.
Sorry, I personally consider it is not a very high priority; the
above is a typo (otherwise "but agrees" does not make _any_
sense).
The rest of the message I'll find a time to comment on
separately, but I am in the middle of migrating the development
environment, so it might take some time.
Oh, and please send patches cc'ed to the list at least for a few
days, because I am fighting with fetchmail/getmail configuration
right now and might lose a few mails while doing so.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: The git newbie experience
2006-05-14 18:36 The git newbie experience Tommi Virtanen
2006-05-14 21:26 ` Junio C Hamano
@ 2006-05-14 22:09 ` Junio C Hamano
2006-05-15 5:06 ` Tommi Virtanen
1 sibling, 1 reply; 12+ messages in thread
From: Junio C Hamano @ 2006-05-14 22:09 UTC (permalink / raw)
To: Tommi Virtanen; +Cc: git
Tommi Virtanen <tv@inoi.fi> writes:
> My best idea so far is to add a "git commit -A" option, that
> essentially does the "update-index --refresh". Whenever index
> has a file state != HEAD, update-index it. The modified unrelated
> files will have index state == HEAD. Or altering "git commit -a"
> to do that.
I am not sure what you are trying to achieve by --refresh. It
does not update the object names in the index. Maybe you are
thinking about --again, but that is when you did something to
the index yourself, so it would not buy you much in the "novice
faced with merge" case.
Anyway, I think the time to commit is too late to save somebody
who does not understand the index. How would you explain why
you sometimes need to use -A and sometimes -a? That is why I
suggested to make "git pull" and "git merge" refuse to work if
there are local changes for novice users, where the definition
of novice is "git commit -a" is the only way to make a commit.
We can have [core] novice = yes in .git/config for that.
If somebody does not understand the index, if the merge is
prevented because the local change does conflict with it, how
would you explain why sometimes you can merge and sometimes you
cannot?
But if you insist going that route, I would say we could make
"git commit -a" on a merge commit to do a bit more magic.
For example, we could make -a do something special for a merge
by looking at the presense of .git/MERGE_HEAD.
- if "commit -a", and without .git/MERGE_HEAD, just grab
all the local modifications that are not in index yet,
and commit it.
- upon "commit -a", and when .git/MERGE_HEAD exists,
grab the paths that ls-files -u reports, update-index
them. Other automerged paths are already registered
in the index.
> Except, trying to solve usability problems by _adding_ options
> is just insane.
I am not sure if it is "usability" but additional option to
simplify things does not sound right, I'd agree.
> For example, we had a case where we absolutely _had_ to keep
> an ugly workaround in the tree, in a file not otherwise
> edited, but we definitely did not want to commit the kludge,
> at least not to the branch that was really being worked on. So
> such restricted mode would just have meant either people could
> not merge, or they had to use index anyway.
Your example is a very ill-thought out one.
If you are leaving the uncommitable kludge around, you cannot be
using "commit -a" with the normal non-merge workflow. Why
would you worry about not being able to do "commit -a" on a
merge then?
For the beginning user without index, I would rewrite your
scenario like this.
- Jack is a beginning user of git and does not (want to) understand
the index (right now).
- Jack works on branch X, say his HEAD points to X1. He has an edited,
uncommitted files with the names A, B and C.
- Jack wants to pull new changes made by others to his branch.
But "git merge" invoked from "git pull" says he needs to stash
away the local changes to do the merge.
- Jack stashes away what he has been working on and cleans up
his mess.
git diff >P.diff
git checkout HEAD A B C
- Jack then pulls. There are merge conflicts in files D, E, ..., Z.
- Jack resolves the merge conflicts and is ready to commit the resulting
merge. Note files A, B and C do not have his unfinished work.
There is no "if Jack does this or that" problem; he says "git
commit -a" because that is the only "commit" command he knows
about.
- Jack then reapplies what he stashed away with "git apply P.diff"
and keeps working.
Maybe "git stash" command that does "git diff --full-index" with
some frills, and "git unstash" command which does an equivalent
of "git am -3" would help this workflow (bare "git apply" does
not do the three-way merge like am does).
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: The git newbie experience
2006-05-14 22:09 ` Junio C Hamano
@ 2006-05-15 5:06 ` Tommi Virtanen
2006-05-15 5:18 ` Junio C Hamano
2006-05-15 5:27 ` Shawn Pearce
0 siblings, 2 replies; 12+ messages in thread
From: Tommi Virtanen @ 2006-05-15 5:06 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Junio C Hamano wrote:
> Anyway, I think the time to commit is too late to save somebody
> who does not understand the index. How would you explain why
> you sometimes need to use -A and sometimes -a?
I guess what I really want is "a smarter -a".
> That is why I
> suggested to make "git pull" and "git merge" refuse to work if
> there are local changes for novice users, where the definition
> of novice is "git commit -a" is the only way to make a commit.
> We can have [core] novice = yes in .git/config for that.
>
> If somebody does not understand the index, if the merge is
> prevented because the local change does conflict with it, how
> would you explain why sometimes you can merge and sometimes you
> cannot?
By the same logic that is already implemented. "pull refuses to pull
changes to files that are modified but not committed".
>> For example, we had a case where we absolutely _had_ to keep
>> an ugly workaround in the tree, in a file not otherwise
>> edited, but we definitely did not want to commit the kludge,
> Your example is a very ill-thought out one.
>
> If you are leaving the uncommitable kludge around, you cannot be
> using "commit -a" with the normal non-merge workflow. Why
> would you worry about not being able to do "commit -a" on a
> merge then?
The indexless working mode means you know two kinds of commits.
"git commit -a" or "git commit FILE..". The uncommitted kludge hanging
around means people listed file names. The case where the merge differs
is that it's not just a few files, and they didn't even really
know what files to list. And "git status" showed them something
they were not used to seeing.
> For the beginning user without index, I would rewrite your
> scenario like this.
>
...
> - Jack stashes away what he has been working on and cleans up
> his mess.
>
> git diff >P.diff
> git checkout HEAD A B C
...
> - Jack then reapplies what he stashed away with "git apply P.diff"
> and keeps working.
>
> Maybe "git stash" command that does "git diff --full-index" with
> some frills, and "git unstash" command which does an equivalent
> of "git am -3" would help this workflow (bare "git apply" does
> not do the three-way merge like am does).
Oh, I'd love to have a quick stash, that's what we actually ended up
doing a lot. Although I'd rather see a real implementation use a branch
and not just a diff file, but.. yes please.
Although, "git stash" and "git unstash" are yet another command to add
to the newbie set, and I just complained about the size of the set ;)
--
Inoi Oy, Tykistökatu 4 D (4. krs), FI-20520 Turku, Finland
http://www.inoi.fi/
Mobile +358 40 762 5656
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: The git newbie experience
2006-05-15 5:06 ` Tommi Virtanen
@ 2006-05-15 5:18 ` Junio C Hamano
2006-05-15 5:31 ` Shawn Pearce
2006-05-15 5:27 ` Shawn Pearce
1 sibling, 1 reply; 12+ messages in thread
From: Junio C Hamano @ 2006-05-15 5:18 UTC (permalink / raw)
To: Tommi Virtanen; +Cc: git
Tommi Virtanen <tv@inoi.fi> writes:
> Oh, I'd love to have a quick stash, that's what we actually ended up
> doing a lot. Although I'd rather see a real implementation use a branch
> and not just a diff file, but.. yes please.
I'd rather do that with a diff file that can be used to do a
3-way (see how rebase does it with --full-index diff with am -3).
No point creating and forgetting to remove a throw away branch
and getting more complaints.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: The git newbie experience
2006-05-15 5:18 ` Junio C Hamano
@ 2006-05-15 5:31 ` Shawn Pearce
2006-05-15 8:39 ` Junio C Hamano
0 siblings, 1 reply; 12+ messages in thread
From: Shawn Pearce @ 2006-05-15 5:31 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Tommi Virtanen, git
Junio C Hamano <junkio@cox.net> wrote:
> Tommi Virtanen <tv@inoi.fi> writes:
>
> > Oh, I'd love to have a quick stash, that's what we actually ended up
> > doing a lot. Although I'd rather see a real implementation use a branch
> > and not just a diff file, but.. yes please.
>
> I'd rather do that with a diff file that can be used to do a
> 3-way (see how rebase does it with --full-index diff with am -3).
> No point creating and forgetting to remove a throw away branch
> and getting more complaints.
How is a quick stash different from a topic branch? I don't see
any difference between the two. Your working directory was a topic
branch, just an unnamed topic branch. Why don't you name it and
deal with it once it is named?
I can see new users getting confused about what changes are in
their quick stash or accidentially losing their quick stash by
running it twice in a row.
Teaching new users to always work on a topic branch and committing
before pulling/merging should be the favored workflow.
--
Shawn.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: The git newbie experience
2006-05-15 5:31 ` Shawn Pearce
@ 2006-05-15 8:39 ` Junio C Hamano
2006-05-15 16:46 ` Carl Baldwin
2006-05-15 20:42 ` Carl Worth
0 siblings, 2 replies; 12+ messages in thread
From: Junio C Hamano @ 2006-05-15 8:39 UTC (permalink / raw)
To: Shawn Pearce, Tommi Virtanen; +Cc: git
Shawn Pearce <spearce@spearce.org> writes:
>> I'd rather do that with a diff file that can be used to do a
>> 3-way (see how rebase does it with --full-index diff with am -3).
>> No point creating and forgetting to remove a throw away branch
>> and getting more complaints.
>
> How is a quick stash different from a topic branch?
The original version of my message in response to TV looked like
this.
- Jack is a beginning user of git and does not (want to) understand
the index (right now).
- Jack works on branch X, say his HEAD points to X1. He has an edited,
uncommitted files with the names A, B and C.
- Jack wants to pull new changes made by others to his branch.
But "git merge" invoked from "git pull" says he needs to stash
away the local changes to do the merge.
- Jack stashes away what he has been working on and cleans up
his mess.
git checkout -b stash ;# risks error when "stash" exists
git commit -a -m 'Stashing WIP'
git checkout master ;# assuming that was where he was
- Jack then pulls. There are merge conflicts in files D, E, ..., Z.
- Jack resolves the merge conflicts and is ready to commit the resulting
merge. Note files A, B and C do not have his unfinished work.
There is no "if Jack does this or that" problem; he says "git
commit -a" because that is the only "commit" command he knows
about.
- Jack then reapplies what he stashed away, and keeps working.
git pull . --no-commit stash
git branch -D stash
You have to teach the new user to (1) name something, only to
immediately discard it when he returns to what he was in the
middle of, (2) remember to clean up the temporary thing once he
is done lest he forgets to clean it up (and common names like
"stash", "tmp" will be reused by accident causing grief next
time he needs to do another stash), and (3) use of --no-commit
pull.
On the other hand, "git stash/unstash" workflow would be quite
simple:
$ git stash >my.precious.state
... do whatever you want to deviate to
$ git unstash <my.precious.state
Merge resolve might be needed while unstashing, but
we are talking about pulling somebody else's work in "do
whatever" part, so that is something the user knows how to
perform anyway.
A quick and dirty stash implementation would go like this:
Stash is easy.
#!/bin/sh
# git stash
git diff --binary HEAD
git reset --hard
Unstash is a bit involved.
#!/bin/sh
# git unstash
. git-sh-setup
O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
O_DIR=`cd "$GIT_DIR" && pwd`
stash="$O_DIR/.stash$$"
rm -fr "$stash.*"
trap 'rm -rf $stash.*' 0
cat >"$stash.patch"
git-apply -z --index-info <"$stash.patch" >"$stash.list"
GIT_INDEX_FILE="$stash.index" \
GIT_OBJECT_DIRECTORY="$O_OBJECT" \
(
mkdir -p "$stash.tmp" &&
git-update-index -z --index-info <"$stash.list" &&
git-write-tree >"$stash.base" &&
cd "$stash.tmp" &&
git-apply --binary --index <"$stash.patch" &&
git-write-tree >"$stash.his"
)
his_tree=$(cat "$stash.his")
orig_tree=$(cat "$stash.base")
rm -fr "$stash.*"
git-merge-resolve $orig_tree -- HEAD $his_tree
This is essentially the core of "am -3" logic; if you are going
to use this for real, you would probably want to see if the
patch applies cleanly before falling back on the three-way
merge, though.
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: The git newbie experience
2006-05-15 8:39 ` Junio C Hamano
@ 2006-05-15 16:46 ` Carl Baldwin
2006-05-15 20:47 ` Junio C Hamano
2006-05-15 20:42 ` Carl Worth
1 sibling, 1 reply; 12+ messages in thread
From: Carl Baldwin @ 2006-05-15 16:46 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Shawn Pearce, Tommi Virtanen, git
Junio,
This seems a lot like what I tried to do with git-undo/git-redo quite a
while back.
My implementation actually wrote the working file state into the object
store as a tree and stored a reference to the tree under something like
.git/refs/undo (or .git/refs/stash). Redo was a simple merge of this
tree back onto the current working files.
I think I would like something like this better than the 'generate
binary patch and reapply the patch later.
If these commands were added to git I think they would be better if the
commands chose a temporary branch name, committed the current state to
that branch and did everything else that someone more experienced would
do using branches having chosen a temporary branch name.
The redo or unstash operation could just pick the most recent tempory
branch name (top of stack) and merge changes into the working copy.
Carl
On Mon, May 15, 2006 at 01:39:08AM -0700, Junio C Hamano wrote:
> Shawn Pearce <spearce@spearce.org> writes:
>
> >> I'd rather do that with a diff file that can be used to do a
> >> 3-way (see how rebase does it with --full-index diff with am -3).
> >> No point creating and forgetting to remove a throw away branch
> >> and getting more complaints.
> >
> > How is a quick stash different from a topic branch?
>
> The original version of my message in response to TV looked like
> this.
>
> - Jack is a beginning user of git and does not (want to) understand
> the index (right now).
>
> - Jack works on branch X, say his HEAD points to X1. He has an edited,
> uncommitted files with the names A, B and C.
>
> - Jack wants to pull new changes made by others to his branch.
> But "git merge" invoked from "git pull" says he needs to stash
> away the local changes to do the merge.
>
> - Jack stashes away what he has been working on and cleans up
> his mess.
>
> git checkout -b stash ;# risks error when "stash" exists
> git commit -a -m 'Stashing WIP'
> git checkout master ;# assuming that was where he was
>
> - Jack then pulls. There are merge conflicts in files D, E, ..., Z.
>
> - Jack resolves the merge conflicts and is ready to commit the resulting
> merge. Note files A, B and C do not have his unfinished work.
>
> There is no "if Jack does this or that" problem; he says "git
> commit -a" because that is the only "commit" command he knows
> about.
>
> - Jack then reapplies what he stashed away, and keeps working.
>
> git pull . --no-commit stash
> git branch -D stash
>
> You have to teach the new user to (1) name something, only to
> immediately discard it when he returns to what he was in the
> middle of, (2) remember to clean up the temporary thing once he
> is done lest he forgets to clean it up (and common names like
> "stash", "tmp" will be reused by accident causing grief next
> time he needs to do another stash), and (3) use of --no-commit
> pull.
>
> On the other hand, "git stash/unstash" workflow would be quite
> simple:
>
> $ git stash >my.precious.state
> ... do whatever you want to deviate to
> $ git unstash <my.precious.state
>
> Merge resolve might be needed while unstashing, but
> we are talking about pulling somebody else's work in "do
> whatever" part, so that is something the user knows how to
> perform anyway.
>
> A quick and dirty stash implementation would go like this:
>
> Stash is easy.
>
> #!/bin/sh
> # git stash
> git diff --binary HEAD
> git reset --hard
>
> Unstash is a bit involved.
>
> #!/bin/sh
> # git unstash
> . git-sh-setup
> O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
> O_DIR=`cd "$GIT_DIR" && pwd`
> stash="$O_DIR/.stash$$"
> rm -fr "$stash.*"
> trap 'rm -rf $stash.*' 0
> cat >"$stash.patch"
> git-apply -z --index-info <"$stash.patch" >"$stash.list"
> GIT_INDEX_FILE="$stash.index" \
> GIT_OBJECT_DIRECTORY="$O_OBJECT" \
> (
> mkdir -p "$stash.tmp" &&
> git-update-index -z --index-info <"$stash.list" &&
> git-write-tree >"$stash.base" &&
> cd "$stash.tmp" &&
> git-apply --binary --index <"$stash.patch" &&
> git-write-tree >"$stash.his"
> )
> his_tree=$(cat "$stash.his")
> orig_tree=$(cat "$stash.base")
> rm -fr "$stash.*"
> git-merge-resolve $orig_tree -- HEAD $his_tree
>
> This is essentially the core of "am -3" logic; if you are going
> to use this for real, you would probably want to see if the
> patch applies cleanly before falling back on the three-way
> merge, though.
>
>
> -
> 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
>
--
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Carl Baldwin RADCAD (R&D CAD)
Hewlett Packard Company
MS 88 work: 970 898-1523
3404 E. Harmony Rd. work: Carl.N.Baldwin@hp.com
Fort Collins, CO 80525 home: Carl@ecBaldwin.net
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: The git newbie experience
2006-05-15 16:46 ` Carl Baldwin
@ 2006-05-15 20:47 ` Junio C Hamano
0 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2006-05-15 20:47 UTC (permalink / raw)
To: Carl Baldwin; +Cc: Tommi Virtanen, Shawn Pearce, git
Carl Baldwin <cnb@fc.hp.com> writes:
> My implementation actually wrote the working file state into the object
> store as a tree and stored a reference to the tree under something like
> .git/refs/undo (or .git/refs/stash). Redo was a simple merge of this
> tree back onto the current working files.
>
> I think I would like something like this better than the 'generate
> binary patch and reapply the patch later.
When you think of the "binary patch" as a human readable
representation of your (hierarchical set of) tree objects, you
would realize that these two approaches aren't that much
different at the tree merge level, and it's just a matter of
which representation is more convenient and human readable.
Pros and cons I see are:
* Branch approach needs to teach users only one thing -- create
a branch, merge with it, throw it away. Which is something
the user needs to know anyway, so it is a plus.
* Branch approach needs to store a full postimage tree and the
base commit (so you can use it as a merge base); the
postimage tree includes paths that are not involved in the
change being stashed.
* Patch records only the object names of paths that are relevant
to the stash. Instead of keeping the full postimage tree, it
creates one on the fly when you actually do the unstashing.
* Patch is human readable and can be used for purposes other
than falling back to a three-way merge. When cleanly applies
apply + write-tree is faster than a tree merge.
* Patch could be verbose if the change being stashed is large;
after all the primary information used are the object names
recorded on the "index" lines and the patch text itself is a
waste from storage point of view. This is a disadvantage of
the "patch" approach, but its readability might offset it.
If a change being stashed is large, the user had better be
doing it on a separate topic branch anyway, so this might not
be a big issue.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: The git newbie experience
2006-05-15 8:39 ` Junio C Hamano
2006-05-15 16:46 ` Carl Baldwin
@ 2006-05-15 20:42 ` Carl Worth
2006-05-15 21:10 ` Junio C Hamano
1 sibling, 1 reply; 12+ messages in thread
From: Carl Worth @ 2006-05-15 20:42 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Shawn Pearce, Tommi Virtanen, git
[-- Attachment #1: Type: text/plain, Size: 3477 bytes --]
On Mon, 15 May 2006 01:39:08 -0700, Junio C Hamano wrote:
> - Jack stashes away what he has been working on and cleans up
> his mess.
>
> git checkout -b stash ;# risks error when "stash" exists
> git commit -a -m 'Stashing WIP'
> git checkout master ;# assuming that was where he was
I really like the proposal made elsewhere to implement a new:
commit -b <newbranch>
which would then allow for a single command to achieve at least the
first two commands above:
git commit -a -b stash -m 'Stashing WIP'
It might even make sense for this command to effectively perform all
three of the above commands. That is, should "commit -b" also checkout
the newly created branch or should it leave HEAD unchanged. I'm not
sure.
> You have to teach the new user to (1) name something, only to
> immediately discard it when he returns to what he was in the
> middle of, (2) remember to clean up the temporary thing once he
> is done lest he forgets to clean it up (and common names like
> "stash", "tmp" will be reused by accident causing grief next
> time he needs to do another stash), and (3) use of --no-commit
> pull.
I threw out a simple git-stash earlier, (which stashed to a branch
rather than to a file). I've spent some time using it, and am now
quite sure it's the wrong thing, and the above problems outline the
defect quite well:
1) Naming.
Here, git-stash is doing too much. I prefer the idea of a stash
command using a branch rather than a patch file, (and allowing one
stash per branch rather than one stash per repository). But the
namespace of branches is something the user owns, and we should
avoid adding commands that steal from it unnecessarily. So my
git-stash fails on this point, while "commit -b <newbranch>" is
much better.
2) Cleanup and --no-commit pull
Here, git-stash is doing too little. It's really only performing
one piece of what needs to be done in order to switch back and
forth between different topics of work.
So here are my thoughts on what I'd like instead:
In git, a branch is what we use to name a topic of work.
Historically, a branch has been extremely lightweight, (a name and
reference to a parent for subsequent commits). But there's been a
recent trend (in proposals at least) to add other, useful things to a
branch, (as in the discussions of branch-specific configuration).
In my work, I've found that the uncommitted state of my working tree
is something that I associate very strongly with my "current topic"
and expect the branch-changing commands respected that.
In particular, when using checkout to change branches, unless I've
specifically stated with "-m" that I want to carry my changes along, I
would like git to stash my working tree "into" the branch I'm
switching away from.
Similarly, when switching to a branch, I'd like to have the working
tree restored to what it was the last time I switched away from that
branch.
Does that seem unreasonable to anyone?
The only snag I've imagined is that when using "checkout -m" to switch
to a branch that also had a stashed working tree, then there's a merge
to be performed and that could obviously conflict. I've intentionally
not mentioned how the stashing/restoring should be implemented, since
the user shouldn't care. But a merge conflict is one case where the
implementation might leak out to the user. The wimpy thing to do would
be to refuse to allow "checkout -m" to a branch with stashed changes.
-Carl
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: The git newbie experience
2006-05-15 20:42 ` Carl Worth
@ 2006-05-15 21:10 ` Junio C Hamano
0 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2006-05-15 21:10 UTC (permalink / raw)
To: Carl Worth; +Cc: git
Carl Worth <cworth@cworth.org> writes:
> In particular, when using checkout to change branches, unless I've
> specifically stated with "-m" that I want to carry my changes along, I
> would like git to stash my working tree "into" the branch I'm
> switching away from.
>
> Similarly, when switching to a branch, I'd like to have the working
> tree restored to what it was the last time I switched away from that
> branch.
>
> Does that seem unreasonable to anyone?
I would not call it unreasonable to want to have an easy access
to that mode of operation _as_ _well_, as an option.
If you were suggesting to make it the only way for future git to
work (I think you are not), then it sounds very unreasonable to
me.
The implementation behind the scene does not matter, but I think
set of "stashes" that can be attached to each branch would work
well for what you would want. OTOH, isn't it called stgit?
The reason why I want it to stay as an option is because I often
do a throw-away patch on top of whatever branch is checked out
in my working tree while reading the list traffic to compose a
response with an alternative patch. Usually I follow that by a
"git reset" once the message is sent out, but when I like the
idea well enough, I do "checkout -b jc/that-topic master" to
switch to a new branch with the dirty state carried along, to
work on it further. I do not want that workflow to require -m
flag, which means something different (-m means "I accept the
possibility of the three-way merge failing while doing this
switch that needs a merge"). Instead, I want "checkout -b" to
try carrying state forward and stop if it cannot without
file-level merging (i.e. the current behaviour). Then I can
think if I want to do a stash with "git diff", or if I want to
do the temporary branch not based on "master" but the current
branch (which is guaranteed to work without -m) and deal with
the mess later.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: The git newbie experience
2006-05-15 5:06 ` Tommi Virtanen
2006-05-15 5:18 ` Junio C Hamano
@ 2006-05-15 5:27 ` Shawn Pearce
1 sibling, 0 replies; 12+ messages in thread
From: Shawn Pearce @ 2006-05-15 5:27 UTC (permalink / raw)
To: Tommi Virtanen; +Cc: Junio C Hamano, git
Tommi Virtanen <tv@inoi.fi> wrote:
> Junio C Hamano wrote:
[snip]
> > - Jack stashes away what he has been working on and cleans up
> > his mess.
> >
> > git diff >P.diff
> > git checkout HEAD A B C
> ...
> > - Jack then reapplies what he stashed away with "git apply P.diff"
> > and keeps working.
> >
> > Maybe "git stash" command that does "git diff --full-index" with
> > some frills, and "git unstash" command which does an equivalent
> > of "git am -3" would help this workflow (bare "git apply" does
> > not do the three-way merge like am does).
>
> Oh, I'd love to have a quick stash, that's what we actually ended up
> doing a lot. Although I'd rather see a real implementation use a branch
> and not just a diff file, but.. yes please.
>
> Although, "git stash" and "git unstash" are yet another command to add
> to the newbie set, and I just complained about the size of the set ;)
This is perhaps one area where SVN's user interface is actually nice.
SVN's equiv. of stash is making a copy of your working directory into
the repository; something that is rather simple to do for the user.
What about "git commit -b foo -a" to commit the current working
directory to branch 'foo'?
Then restoring is a pull of foo ("git pull . foo"), but that
intermediate commit is now part of the repository history. And "git
commit -a" doesn't automatically add extra/other files to the
repository and it probably should in the case of a "stash".
--
Shawn.
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2006-05-15 21:10 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-14 18:36 The git newbie experience Tommi Virtanen
2006-05-14 21:26 ` Junio C Hamano
2006-05-14 22:09 ` Junio C Hamano
2006-05-15 5:06 ` Tommi Virtanen
2006-05-15 5:18 ` Junio C Hamano
2006-05-15 5:31 ` Shawn Pearce
2006-05-15 8:39 ` Junio C Hamano
2006-05-15 16:46 ` Carl Baldwin
2006-05-15 20:47 ` Junio C Hamano
2006-05-15 20:42 ` Carl Worth
2006-05-15 21:10 ` Junio C Hamano
2006-05-15 5:27 ` Shawn Pearce
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).