threads / discuss / 22474

Better cooperation between checkouts and stashing

Subject: Better cooperation between checkouts and stashing

## tl;dr

56 messages between Feb 1, 2010 and Apr 10, 2010.

replies: 55people: 7as markdown or json

Markus Elfring· Feb 1, 2010, 18:50 UTC · lore
Hello,

The content control tool "Git" maintains a single file system view that can be actively worked on. It can be switched to different topic branches by the command "git checkout". If the current active working copy contains "dirty" changes, they need to be stashed away before each switch to a different issue. http://ariejan.net/2008/04/23/git-using-the-stash/

I imagine that there are opportunities for further improvements.
- How do you think about the feature that a checkout performs also a stash
operation before by default and a stash would offer the option to checkout a
branch afterwards in one step?
- Would you like to offer a more powerful filter expression for the command "git
stash list" to make the navigation between the available intermediate work
results easier?

Regards, Markus

Junio C Hamano· Feb 1, 2010, 20:40 UTC · re: Markus Elfring · lore

Re: Better cooperation between checkouts and stashing

Markus Elfring <Markus.Elfring@web.de> writes:
Show 10 quoted lines
> The content control tool "Git" maintains a single file system view that can be
> actively worked on. It can be switched to different topic branches by the
> command "git checkout". If the current active working copy contains "dirty"
> changes, they need to be stashed away before each switch to a different issue.
> http://ariejan.net/2008/04/23/git-using-the-stash/
>
> I imagine that there are opportunities for further improvements.
> - How do you think about the feature that a checkout performs also a stash
> operation before by default and a stash would offer the option to checkout a
> branch afterwards in one step?

If you are starting from "if your work tree is dirty, you MUST stash before checking out another branch", the suggestion is understandable. But the thing is, that starting point is not quite correct. And the end result is that such a change you are suggesting would inconvenience people greatly, I am afraid, if not designed carefully (I'll outline at the end).

Checking out another branch (branch switching) is designed to carry your local modification across with you. This is to allow you to start working on something, realize that your changes are better suited for another branch, and at that point after the fact "git checkout" that other branch, while keeping what you have done so far.

If the original branch you started your work from and the branch you are checking out have different contents in files you have changed (aka "your changes conflict at the paths level"), without -m option, "git checkout" refuses to check out the other branch, because it will need a three-way merge to carry your changes forward, and you might not be prepared to resolve conflicts resulting from such a merge.

In practice, however, your changes often don't conflict with the changes between the branches at the paths level, and "git checkout" lets you carry your local changes across just fine. I'd say this is the majority of the case especially for experienced git users, as they tend to commit in smaller and more logical units than those from other SCM background.

Forcing auto-stash on them would mean they now have to pop the stash, after checking out the other branch, which is not an improvement for them (and remember, soon you will be part of "them" after getting used to git). Doing an auto-pop in addition to your auto-stash "to help them" is even worse, as you essentially made "git checkout other-branch" to always use "-m" option.

I actually have explained this at least a few times here in the past:
 http://thread.gmane.org/gmane.comp.version-control.git/77700/focus=77708
 http://thread.gmane.org/gmane.comp.version-control.git/135661/focus=135663

but I don't see anything that states clearly that "checkout" is designed to carry your local changes across in any documentation (I gave a cursory look to the user manual, tutorial and checkout manual page). Probably "git checkout --help" needs a "Switching branches" section, just like the planned enhancement for "Detached HEAD" section.

We _can_ start experimenting with an option (similar to "checkout -m"), which does:

 - Internally try 'git checkout other-branch' without disturbing the user
   with any error message; if it does not fail due to paths level
   conflicts, we have successfully checked out the other branch and we are
   done;
 - If the above trial would fail for some other reason (perhaps your index
   was unmerged), then don't do anything---just fail as before;
 - Internally run 'git stash', then run 'git checkout other-branch'.  If
   either of these steps fail, you are in deep trouble.  Design what you
   have to do carefully in this case (I won't do that in this message);
 - Then finally run 'git stash pop'.
Markus Elfring· Feb 1, 2010, 21:57 UTC · re: Junio C Hamano · lore

Re: Better cooperation between checkouts and stashing

> But the thing is, that starting point is not quite correct.
Thanks for your detailed explanations.
> I actually have explained this at least a few times here in the past:
>
>  http://thread.gmane.org/gmane.comp.version-control.git/77700/focus=77708
>   

I am also very interested in the three use cases that were mentioned in the discussion for the topic "Switching branches without committing changes".

> but I don't see anything that states clearly that "checkout" is designed
> to carry your local changes across in any documentation (I gave a cursory
> look to the user manual, tutorial and checkout manual page).

I find it interesting that these descriptions might need still a few more clarifications about the involved relationships.

>  - Internally run 'git stash', then run 'git checkout other-branch'.
>   

I imagine that this case is useful because of usual work interruptions in software development. A developer tries to bring various tasks forward in parallel. Branches will be switched often with unfinished work that needs to be kept before the reactivation of another task.

Regards, Markus

Eugene Sajine· Feb 1, 2010, 22:44 UTC · re: Markus Elfring · lore

Re: Better cooperation between checkouts and stashing

Show 9 quoted lines
>
> I imagine that this case is useful because of usual work interruptions
>
> in software development. A developer tries to bring various tasks
>
> forward in parallel. Branches will be switched often with unfinished
>
> work that needs to be kept before the reactivation of another task.
>

Aren't this and similar statements based on a general problem of people being afraid to commit, because CVS/SVN taught them to be affraid? We are in progress of migrating from CVS to GIT and this is one of the things i'm desperately fighting with. In Git Commit doesn't equal Share (it does in CVS), so why not to commit and save your work in progress and switch branches painlessly?

Thanks, Eugene

Petr Baudis· Feb 2, 2010, 01:36 UTC · re: Eugene Sajine · lore

Re: Better cooperation between checkouts and stashing

On Mon, Feb 01, 2010 at 05:44:25PM -0500, Eugene Sajine wrote:
Show 16 quoted lines
> >
> > I imagine that this case is useful because of usual work interruptions
> >
> > in software development. A developer tries to bring various tasks
> >
> > forward in parallel. Branches will be switched often with unfinished
> >
> > work that needs to be kept before the reactivation of another task.
> >
> 
> Aren't this and similar statements based on a general problem of
> people being afraid to commit, because CVS/SVN taught them to be
> affraid? We are in progress of migrating from CVS to GIT and this is
> one of the things i'm desperately fighting with.
> In Git Commit doesn't equal Share (it does in CVS), so why not to
> commit and save your work in progress and switch branches painlessly?

There are various pressures pushing against each other and the balance will be different for each individual and each project. One aspect is that committing often is encouraged. However, greatly contradicting force is the pressure to have "clean history" - that is, self-contained, clearly separated cnd bisectable ommits which introduce independent changes and are pretty to look at, frequently quite different to chronological log of the performed work.

Of course you can ignore that and just commit away, or build up large changes "in advance", then split them up at once. The resulting number of commits will be about the same, but their quality _and_ the spent effort will be quite different. Optimum lies in appropriate balance of the processes, as usual.

There are several ways to achieve the latter process, moreover. One possibility is to do all changes in the working tree, then carefulling factoring out various aspects to separate commits using index manipulation and heavy `git add -p` usage; you would then certainly need `git stash` in case you wanted to switch the branch. The other way is to commit regularly creating a history structure similar to the "careless committer", _however_ before pushing out and publishing the commits, the history gets cleaned up and rewritten by `git rebase -i`.

Choosing the appropriate method involves all kinds of subtle tradeoffs and I wonder whether there is a single good answer, it is a matter of taste. I do the former, but maybe that's because I just dislike rebase for different reasons. ;-) One natural way would be to hack in the working tree, splitting up your work to 1-3 commits in the index, then reviewing your complete local changeset and tweaking it by rebase -i before finally publishing your self-contained masterpiece.

For better or worse, There Is More Than One Way To Do It in Git. ;-)
-- 
				Petr "Pasky" Baudis
If you can't see the value in jet powered ants you should turn in
your nerd card. -- Dunbal (464142)
Markus Elfring· Feb 2, 2010, 10:26 UTC · re: Petr Baudis · lore

Re: Better cooperation between checkouts and stashing

> For better or worse, There Is More Than One Way To Do It in Git. ;-)
>   

Do you see also a need for improvements in the cooperation between the functions "checkout" and "stash"? Would it be useful to combine them into a single command on demand to make the switching of branches without committing changes a bit more convenient?

Regards, Markus

Petr Baudis· Feb 2, 2010, 11:04 UTC · re: Markus Elfring · lore

Re: Better cooperation between checkouts and stashing

On Tue, Feb 02, 2010 at 11:26:52AM +0100, Markus Elfring wrote:
Show 9 quoted lines
> 
> > For better or worse, There Is More Than One Way To Do It in Git. ;-)
> >   
> 
> Do you see also a need for improvements in the cooperation between the
> functions "checkout" and "stash"?
> Would it be useful to combine them into a single command on demand to
> make the switching of branches without committing
> changes a bit more convenient?

I personally prefer to tell Git explicitly what to do when I'm checkouting a different branch, and have a habit of checking what kind of uncommitted changes I have all the time (and I think it's a good habit ;-), so I have no problem with explicitly stashing before checkouting different branch if I need to.

The thing is, I use multiple branches less than I should. If I used them more, I'd probably be simply using stash much less than making temporary commits and possibly cleaning them up later instead. (But if you get really used to sensibly separating commits, you end up actually adjusting your programming process subconsciously in a way to lend to the appropriate commit sequence naturally.)

-- 
				Petr "Pasky" Baudis
If you can't see the value in jet powered ants you should turn in
your nerd card. -- Dunbal (464142)
Markus Elfring· Feb 9, 2010, 19:20 UTC · re: Junio C Hamano · lore

Re: Better cooperation between checkouts and stashing

>
> We _can_ start experimenting with an option (similar to "checkout -m"),
> which does:
>   

Does the documentation need any improvements on the dependencies between the mentioned subfunctions? Would we like to collect further ideas on the suggested issue?

Regards, Markus

Junio C Hamano· Feb 9, 2010, 20:06 UTC · re: Markus Elfring · lore

Re: Better cooperation between checkouts and stashing

Markus Elfring <Markus.Elfring@web.de> writes:
Show 7 quoted lines
>>
>> We _can_ start experimenting with an option (similar to "checkout -m"),
>> which does:
>>   
>
> Does the documentation need any improvements on the dependencies between
> the mentioned subfunctions?

Sorry, you lost me. I did say and still think that it would be good to have in the documentation a separate section that teaches the users what happens to their uncommitted changes when checking out a different branch (or an unnamed branch). But I am at loss guessing what dependencies among what "subfunctions" you are talking about.

Markus Elfring· Feb 9, 2010, 21:01 UTC · re: Junio C Hamano · lore

Re: Better cooperation between checkouts and stashing

>
> But I am at loss guessing what dependencies among what "subfunctions"
> you are talking about.
>   

I propose further clarifications and improvements between the git functions "checkout" and "stash".

Regards, Markus

Markus Elfring· Feb 18, 2010, 17:43 UTC · re: Junio C Hamano · lore

Re: Better cooperation between checkouts and stashing

> I did say and still think that it would be good to have in the documentation 
> a separate section that teaches the users what happens to their uncommitted 
> changes when checking out a different branch (or an unnamed branch).
>   
How are the chances to achieve progress on this issue?

Regards, Markus

Junio C Hamano· Feb 18, 2010, 20:09 UTC · re: Markus Elfring · lore

Re: Better cooperation between checkouts and stashing

Markus Elfring <Markus.Elfring@web.de> writes:
Show 5 quoted lines
>> I did say and still think that it would be good to have in the documentation 
>> a separate section that teaches the users what happens to their uncommitted 
>> changes when checking out a different branch (or an unnamed branch).
>
> How are the chances to achieve progress on this issue?

How would _I_ know? It depends on the probability of somebody who cares about improving the documentation having enough time and motivation to do the actual work, and submitting the patch. It also depends on the quality of the result.

Markus Elfring· Feb 27, 2010, 21:33 UTC · re: Junio C Hamano · lore

Re: Better cooperation between checkouts and stashing

> If you are starting from "if your work tree is dirty, you MUST stash
> before checking out another branch", the suggestion is understandable.
> But the thing is, that starting point is not quite correct.

Does an option exist for the command "git checkout" to return to the specified branch without modifications in one step? When will it not be needed to reset the work tree to the last corresponding commit?

Regards, Markus

Junio C Hamano· Feb 27, 2010, 21:51 UTC · re: Markus Elfring · lore

Re: Better cooperation between checkouts and stashing

Markus Elfring <Markus.Elfring@web.de> writes:
Show 5 quoted lines
>> If you are starting from "if your work tree is dirty, you MUST stash
>> before checking out another branch", the suggestion is understandable.
>> But the thing is, that starting point is not quite correct.
> ...
> When will it not be needed to reset the work tree to the last corresponding commit?
A response to a month old message is a blast from the past ;-).

The answer is "almost always" for me. IOW, if checkout stashed away my local changes, it would be very inconvenient.

It is important to understand that a local change does not belong to your current branch (it does not belong to _any_ branch). It belongs to you, and you can take it around while switching between branches. And that is a big time-saving feature.

This lets you work like this:
 - You are reading a mailing list message that asks for help, and you know
   the solution---you can give the help real quick.
 - You hack in whatever branch that happen to be checked out.  The change
   is perfect, it works.
 - The branch you happen to have checked out was 'next', but the solution
   is a bugfix, and should go to 'maint'.

Now, at this point, you want to checkout 'maint' without losing your local change. The paths you touched with your quick fix are often not different between the two branches, and "checkout maint" will checkout the branch while keeping your local changes intact. All that is left for you to do is to run another round of test to make sure that your fix didn't depend on anything not in 'maint' and commit the change with appropriate log message, and then you can go back to whatever you were doing with "checkout next".

When the change involves paths that were touched between 'maint' and 'next', of course you won't be able to switch without merging the local change to the difference between 'next' and 'maint'. There are a few workflows to deal with such a case, and the easiest is "checkout -m", if you are confident that you can resolve it.

In a case where "checkout -m" would result in a conflict too big to resolve, the original fix you made would not be applicable to 'maint' (iow, you should have solved it differently starting from 'maint'), and you may end up doing "reset --hard" and start from scratch, but that is a rare worst case.

I said it is rare, because you would notice, while doing the "quick fix" based on 'next' codebase, that the code you are touching have changed since 'maint' and won't be applicable to its final destination (by that time you know you are "fixing"), and you won't waste too much time continuing to work in a checkout of 'next'.

Markus Elfring· Feb 28, 2010, 13:55 UTC · re: Junio C Hamano · lore

Re: Better cooperation between checkouts and stashing

> It is important to understand that a local change does not belong to your
> current branch (it does not belong to _any_ branch).  It belongs to you,
> and you can take it around while switching between branches.  And that is
> a big time-saving feature.

It seems that we have got different expectations on the editing work flow when we discuss the following situation.

elfring@Sonne:~/Projekte> git --version && mkdir try && cd try && git init --quiet \
> && echo one > XYZ.h && git add . && git commit --message=check-in --quiet \
> && git checkout --quiet -b feature1 && echo two > XYZ.h \
> && git checkout --quiet master && git status

git version 1.7.0 # On branch master # Changed but not updated: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: XYZ.h # no changes added to commit (use "git add" and/or "git commit -a")

I would prefer to return to the unchanged work tree because I made an adjustment for a source file with the intention that this update should only belong to the new topic branch. The switch did not provide a clean state from my view.

>  - You are reading a mailing list message that asks for help, and you know
>    the solution---you can give the help real quick.
> 
>  - You hack in whatever branch that happen to be checked out.
I would create another topic branch before.
Show 7 quoted lines
>  - The branch you happen to have checked out was 'next', but the solution
>    is a bugfix, and should go to 'maint'.
> 
> Now, at this point, you want to checkout 'maint' without losing your local
> change.  The paths you touched with your quick fix are often not different
> between the two branches, and "checkout maint" will checkout the branch
> while keeping your local changes intact.

I can follow your view on convenience if the desired software maintenance is so easy as in this example. I guess that it matters if only a simple branch switch is needed or a corresponding content restore will also be required.

Show 5 quoted lines
> In a case where "checkout -m" would result in a conflict too big to
> resolve, the original fix you made would not be applicable to 'maint'
> (iow, you should have solved it differently starting from 'maint'), and
> you may end up doing "reset --hard" and start from scratch, but that is a
> rare worst case.
I would like to be more careful so that I do not want to mix changes by accident.
Show 5 quoted lines
> I said it is rare, because you would notice, while doing the "quick fix"
> based on 'next' codebase, that the code you are touching have changed
> since 'maint' and won't be applicable to its final destination (by that
> time you know you are "fixing"), and you won't waste too much time
> continuing to work in a checkout of 'next'.

I imagine that stashing will help to split the collected changes for different branch targets.

Regards, Markus

Michael Witten· Feb 28, 2010, 22:57 UTC · re: Markus Elfring · lore

Re: Better cooperation between checkouts and stashing

On Sun, Feb 28, 2010 at 07:55, Markus Elfring <Markus.Elfring@web.de> wrote:
>
> I would prefer to return to the unchanged work tree because I made an adjustment
> for a source file with the intention that this update should only belong to the
> new topic branch. The switch did not provide a clean state from my view.

I don't think you're properly reading what Junio has been saying. I suggest you look over this thread again from the beginning.

Markus Elfring· Mar 1, 2010, 10:50 UTC · re: Junio C Hamano · lore

Re: Better cooperation between checkouts and stashing

Show 7 quoted lines
>  - The branch you happen to have checked out was 'next', but the solution
>    is a bugfix, and should go to 'maint'.
> 
> Now, at this point, you want to checkout 'maint' without losing your local
> change.  The paths you touched with your quick fix are often not different
> between the two branches, and "checkout maint" will checkout the branch
> while keeping your local changes intact.
Does the wording in the manual fit to the mentioned software development practice?

"When <paths> are not given, this command switches branches by updating the index, working tree, and HEAD to reflect the specified branch."

I see a need for further clarifications of the involved details.
- Only the focus will be set on the specified branch.
- Would it be useful if it will become configurable if the corresponding
contents will also be automatically restored by a checkout?

Regards, Markus

Michael Witten· Mar 1, 2010, 17:02 UTC · re: Markus Elfring · lore

Re: Better cooperation between checkouts and stashing

To Junio in particular: See the very bottom of this email.
On Mon, Mar 1, 2010 at 04:50, Markus Elfring <Markus.Elfring@web.de> wrote:
Show 14 quoted lines
>>  - The branch you happen to have checked out was 'next', but the solution
>>    is a bugfix, and should go to 'maint'.
>>
>> Now, at this point, you want to checkout 'maint' without losing your local
>> change.  The paths you touched with your quick fix are often not different
>> between the two branches, and "checkout maint" will checkout the branch
>> while keeping your local changes intact.
>
> Does the wording in the manual fit to the mentioned software development practice?
>
> "When <paths> are not given, this command switches branches by updating the
> index, working tree, and HEAD to reflect the specified branch."
>
> I see a need for further clarifications of the involved details.
Junio pointed out that the documentation is currently lacking:
  [Unfortunately,] I don't see anything that states
  clearly that "checkout" is designed to carry your
  local changes across in any documentation (I gave
  a cursory look to the user manual, tutorial and
  checkout manual page). Probably "git checkout --help"
  needs a "Switching branches" section, just like the
  planned enhancement for "Detached HEAD" section.

In other words, the documentation NEEDS to be updated to include the explanation and rationale that Junio also supplied:

  Checking out another branch (branch switching) is
  designed to carry your local modification across
  with you. This is to allow you to start working on
  something, realize that your changes are better suited
  for another branch, and at that point after the fact
  "git checkout" that other branch, while keeping what
  you have done so far.
  If the original branch you started your work from and
  the branch you are checking out have different contents
  in files you have changed (aka "your changes conflict
  at the paths level"), without -m option, "git checkout"
  refuses to check out the other branch, because it will
  need a three-way merge to carry your changes forward,
  and you might not be prepared to resolve conflicts
  resulting from such a merge.
  In practice, however, your changes often don't conflict
  with the changes between the branches at the paths
  level, and "git checkout" lets you carry your local
  changes across just fine. I'd say this is the majority
  of the case especially for experienced git users, as
  they tend to commit in smaller and more logical units
  than those from other SCM background.
and Junio expanded on this later:
  It is important to understand that a local change does
  not belong to your current branch (it does not belong to
  _any_ branch). It belongs to you, and you can take it
  around while switching between branches. And that is a
  big time-saving feature.
  
  This lets you work like this:
  
   - You are reading a mailing list message that
   asks for help, and you know the solution---you
   can give the help real quick.
  
   - You hack in whatever branch that happen to be
   checked out. The change is perfect, it works.
  
   - The branch you happen to have checked out
   was 'next', but the solution is a bugfix, and
   should go to 'maint'.
  
  Now, at this point, you want to checkout 'maint' without
  losing your local change. The paths you touched with
  your quick fix are often not different between the two
  branches, and "checkout maint" will checkout the branch
  while keeping your local changes intact. All that is
  left for you to do is to run another round of test to
  make sure that your fix didn't depend on anything not
  in 'maint' and commit the change with appropriate log
  message, and then you can go back to whatever you were
  doing with "checkout next".
  
  When the change involves paths that were touched
  between 'maint' and 'next', of course you won't be
  able to switch without merging the local change to the
  difference between 'next' and 'maint'. There are a few
  workflows to deal with such a case, and the easiest is
  "checkout -m", if you are confident that you can resolve
  it.
  In a case where "checkout -m" would result in a conflict
  too big to resolve, the original fix you made would not
  be applicable to 'maint' (iow, you should have solved it
  differently starting from 'maint'), and you may end up
  doing "reset --hard" and start from scratch, but that is
  a rare worst case.
  I said it is rare, because you would notice, while doing
  the "quick fix" based on 'next' codebase, that the code
  you are touching have changed since 'maint' and won't be
  applicable to its final destination (by that time you
  know you are "fixing"), and you won't waste too much
  time continuing to work in a checkout of 'next'.

I think it would be a great contribution if you could clean up Junio's explanation and submit a patch that includes it in the documentation for "git checkout".

> - Would it be useful if it will become configurable if the corresponding
> contents will also be automatically restored by a checkout?
>From what you've said, I think you essentially want to implement

"git checkout" with something like the following (this hack is **not** meant as a solution; it is only meant to illustrate what I think is Markus Elfring's desire):

  # Utility:
    get_stash_id()
    {
      local branch=$(git rev-parse --symbolic-full-name HEAD)
      [ $branch = HEAD ] && return 1 # don't stash for detached HEAD
      echo -n "$branch" | md5sum | awk -F" " '{print $1}'
    }
  # New implementation:
    checkout()
    {
      # Stash local modifications (including index modifications) if
      # necessary, using an easily identifiable message known as the
      # 'stash id':
	local stash_id
        stash_id=$(get_stash_id) &&
          git stash save -q "$stash_id" ||    # Save local modifications
            git reset --hard HEAD             # Throw away changes on detached HEAD
      # Do the checkout that was requested:
        git checkout "$@"
      # Unstash previously stashed local modifications (including
      # index modifications) if they were automatically stashed
      # before (the lookup is done with the relevant 'stash id'):
        stash_id=$(get_stash_id)                                            &&
          stash_id=$(git stash list | awk -F': ' "/$stash_id/ {print \$1}") &&
            [ -n "$stash_id" ]                                              &&
              git stash pop --index "$stash_id"
    }

Sincerely, Michael Witten

Junio C Hamano· Mar 1, 2010, 17:23 UTC · re: Michael Witten · lore

Re: Better cooperation between checkouts and stashing

>Michael Witten <mfwitten@gmail.com> writes:
> ..., I think you essentially want to implement
> "git checkout" with something like the following (this hack is **not**
> meant as a solution; it is only meant to illustrate what I think is
> Markus Elfring's desire):

Your "checkout" needs a bit better error checking. For example, you don't want to "reset --hard" when stash failed for whatever reason.

For performance and cleanliness reasons, it should first try a branch switch, and only after seeing it fail due to local changes, perform your stash-unstash magic. You would probably want to use the usual "stash save", as you will be consuming the stashed change yourself as its first user, and "pop" will clear it if things resolve cleanly, or the stash will be left as the first element to make it easy to re-attempt the conflict resolution. No need for stash-id nor special casing of detached HEAD situation.

And it should do all that only under "-m" option, i.e. when the user indicated that s/he is willilng to face conflict resolution while switching. That would be a genuine improvement compared to the current system (and I suspect it would be easier to implement). "checkout -m" so far has been as bad as "CVS/SVN update" in that it can get you into an unresolvable mess without a chance to go back and retry. autostash will remedy that.

Michael Witten· Mar 1, 2010, 18:14 UTC · re: Junio C Hamano · lore

Re: Better cooperation between checkouts and stashing

On Mon, Mar 1, 2010 at 11:23, Junio C Hamano <gitster@pobox.com> wrote:
> Your "checkout" needs a bit better error checking.  For example, you
> don't want to "reset --hard" when stash failed for whatever reason.
Yes, you are correct.

However, in my defense, the goal was just to illustrate the gist of the desired functionality.

Show 16 quoted lines
> For performance and cleanliness reasons, it should first try a branch
> switch, and only after seeing it fail due to local changes, perform your
> stash-unstash magic.  You would probably want to use the usual "stash
> save", as you will be consuming the stashed change yourself as its first
> user, and "pop" will clear it if things resolve cleanly, or the stash will
> be left as the first element to make it easy to re-attempt the conflict
> resolution.  No need for stash-id nor special casing of detached HEAD
> situation.
>
> And it should do all that only under "-m" option, i.e. when the user
> indicated that s/he is willilng to face conflict resolution while
> switching.  That would be a genuine improvement compared to the current
> system (and I suspect it would be easier to implement).  "checkout -m" so
> far has been as bad as "CVS/SVN update" in that it can get you into an
> unresolvable mess without a chance to go back and retry.  autostash will
> remedy that.

You've still got the wrong problem in your head (though you're solving a more useful issue).

Markus Elfring's goal (I think) is to associate local modifications with a particular branch, *not* carry them across branches; that is, the goal is to stash local modifications away when we leave a branch and only pop them off the stash when we RETURN to that same branch.

Here's an example using the previously defined custom `checkout' function (don't bother trying to follow the file modifications exactly; what's important is how the stash is used during `checkout'):

  $ git init repo
  Initialized empty Git repository in /home/michael/repo/.git/
  $ cd repo
  $ echo 0 > file_0
  $ git add file_0
  $ git commit -m 0
  [master (root-commit) 26ea762] 0
   1 files changed, 1 insertions(+), 0 deletions(-)
   create mode 100644 file_0
  $ echo 1 > file_1
  $ git add file_1
  $ git commit -m 1
  [master 2faaa55] 1
   1 files changed, 1 insertions(+), 0 deletions(-)
   create mode 100644 file_1
  $ echo 2 > file_0
  $ echo 3 > file_1
  $ git add file_1
  $ git branch branch
  $ checkout branch               # Note: That's the custom 'checkout'
  Switched to branch 'branch'
  $ git stash list | cat
  stash@{0}: On master: e2f0bfbd9de98acd4941a1842e4bc55f
  $ echo 4 > file_0
  $ checkout HEAD^
  Note: checking out 'HEAD^'.
  
  You are in 'detached HEAD' state. You can look around, make experimental
  changes and commit them, and you can discard any commits you make in this
  state without impacting any branches by performing another checkout.
  
  If you want to create a new branch to retain commits you create, you may
  do so (now or later) by using -b with the checkout command again. Example:
  
    git checkout -b new_branch_name
  
  HEAD is now at 26ea762... 0
  $ git stash list | cat
  stash@{0}: On branch: 3e4d8fe5cbdcf73b9272ad21b4510424
  stash@{1}: On master: e2f0bfbd9de98acd4941a1842e4bc55f
  $ echo 5 > file_0 
  $ checkout master
  HEAD is now at 26ea762 0
  Previous HEAD position was 26ea762... 0
  Switched to branch 'master'
  # On branch master
  # Changes to be committed:
  #   (use "git reset HEAD <file>..." to unstage)
  #
  #	modified:   file_1
  #
  # Changed but not updated:
  #   (use "git add <file>..." to update what will be committed)
  #   (use "git checkout -- <file>..." to discard changes in working directory)
  #
  #	modified:   file_0
  #
  Dropped stash@{1} (6871afd660a5814a1caffe5275a9c145dba3c85a)
  $ git stash list | cat
  stash@{0}: On branch: 3e4d8fe5cbdcf73b9272ad21b4510424
  $ checkout branch
  Switched to branch 'branch'
  # On branch branch
  # Changed but not updated:
  #   (use "git add <file>..." to update what will be committed)
  #   (use "git checkout -- <file>..." to discard changes in working directory)
  #
  #	modified:   file_0
  #
  no changes added to commit (use "git add" and/or "git commit -a")
  Dropped stash@{1} (f6ecf1ceed97c760cb2b3279bbb39fc1cd16f052)
  $ git stash list | cat
  stash@{0}: On master: e2f0bfbd9de98acd4941a1842e4bc55f
  $ checkout master
  Switched to branch 'master'
  # On branch master
  # Changes to be committed:
  #   (use "git reset HEAD <file>..." to unstage)
  #
  #	modified:   file_1
  #
  # Changed but not updated:
  #   (use "git add <file>..." to update what will be committed)
  #   (use "git checkout -- <file>..." to discard changes in working directory)
  #
  #	modified:   file_0
  #
  Dropped stash@{1} (46a64d63441a924d9684c8a733a9fae4c7aa4b92)
  $ git stash list | cat
  stash@{0}: On branch: 3e4d8fe5cbdcf73b9272ad21b4510424
  $ git diff | cat
  diff --git a/file_0 b/file_0
  index 573541a..0cfbf08 100644
  --- a/file_0
  +++ b/file_0
  @@ -1 +1 @@
  -0
  +2
  $ git diff --staged | cat
  diff --git a/file_1 b/file_1
  index d00491f..00750ed 100644
  --- a/file_1
  +++ b/file_1
  @@ -1 +1 @@
  -1
  +3
etc.
Markus Elfring· Mar 1, 2010, 18:29 UTC · re: Michael Witten · lore

Re: Better cooperation between checkouts and stashing

> Markus Elfring's goal (I think) is to associate local modifications with
> a particular branch, *not* carry them across branches; that is, the goal
> is to stash local modifications away when we leave a branch and only pop
> them off the stash when we RETURN to that same branch.
You are right. - I am especially interested in this use case.

I would like to stress the relationships of files for a specific software development task

Regards, Markus

Junio C Hamano· Mar 1, 2010, 19:44 UTC · re: Michael Witten · lore

Re: Better cooperation between checkouts and stashing

Michael Witten <mfwitten@gmail.com> writes:
> Markus Elfring's goal (I think) is to associate local modifications with
> a particular branch, *not* carry them across branches;

You fooled me by having "stash pop" in the same script after you wrote 'git checkout "$@"' to switch branches. If you want to have per-branch stash, that is a totally independent problem, and I'd suggest using real refs ($GIT_DIR/refs/stashes/$branch_name) instead of the md5 hack, if that is the motivation.

Markus Elfring· Mar 1, 2010, 21:20 UTC · re: Junio C Hamano · lore

Re: Better cooperation between checkouts and stashing

> If you want to have per-branch stash, that is a totally independent problem,
> and I'd suggest using real refs ($GIT_DIR/refs/stashes/$branch_name) instead
> of the md5 hack, if that is the motivation.

How is this use case different from the other? Which "problem" have you got in mind?

Regards, Markus

Michael Witten· Mar 2, 2010, 01:41 UTC · re: Markus Elfring · lore

Re: Better cooperation between checkouts and stashing

On Mon, Mar 1, 2010 at 15:20, Markus Elfring <Markus.Elfring@web.de> wrote:
>
> How is this use case different from the other?

The other use case is the one that git already assumes to be popular: People want local modifications to remain in place across branch checkouts.

> Which "problem" have you got in mind?

The "git checkout" command is designed to carry local modifications across branches transparently; when it's not so clear that such transparency is possible, "git checkout" refuses to continue unless the "-m" flag is used to try a 3-way merge involving:

  * the local modifications.
  * the files in the branch being left.
  * the files in the branch being checked out.

This 3-way merge can get tricky if it ends in conflict, and so a smart use of the stash in this process might help users untangle themselves.

That is what Junio has been thinking about in this thread.
Markus Elfring· Mar 2, 2010, 09:35 UTC · re: Michael Witten · lore

Re: Better cooperation between checkouts and stashing

> The other use case is the one that git already assumes to be popular:
> People want local modifications to remain in place across branch checkouts.

Are there software developers (besides me) who would like to work in the opposite way on demand?

How are the chances to make unfinished and uncommitted content updates sticky for a particular branch (or a selection of branches) so that changes will not be mixed more as it will be really required for an editing task?

> The "git checkout" command is designed to carry local modifications
> across branches transparently;

Which wording will be preferred to "reflect" this fact in the manual and other documentation?

Regards, Markus

Junio C Hamano· Mar 2, 2010, 17:50 UTC · re: Markus Elfring · lore

Re: Better cooperation between checkouts and stashing

Markus Elfring <Markus.Elfring@web.de> writes:
> How are the chances to make unfinished and uncommitted content updates sticky
> for a particular branch (or a selection of branches) so that changes will not be
> mixed more as it will be really required for an editing task?

Traditionally the right way to do this has been to make a temporary commit on the branch, i.e.

    $ git checkout topic
    work work work... yikes, I cannot get this working
    $ git commit -a -m 'wip: does not work yet' ;# temporary commit
    $ git checkout other-topic
    work work work....
    $ git checkout topic
    $ git reset --soft HEAD^ ;# drop the temporary commit

I didn't re-read our documentation set for some time, but don't we teach this anymore?

Markus Elfring· Mar 3, 2010, 15:55 UTC · re: Junio C Hamano · lore

Re: Better cooperation between checkouts and stashing

> Traditionally the right way to do this has been to make a temporary commit
> on the branch, i.e.

I would like to avoid such commits for unfinished content updates. Should the storage operation be provided by the stash instead for intermediate work results? Will it happen to forget corresponding clean-up for "temporary" changes that might be committed too early just to get them stored?

Regards, Markus

Michael Witten· Mar 4, 2010, 07:46 UTC · re: Markus Elfring · lore

Re: Better cooperation between checkouts and stashing

On Wed, Mar 3, 2010 at 09:55, Markus Elfring <Markus.Elfring@web.de> wrote:
Show 7 quoted lines
>> Traditionally the right way to do this has been to make a temporary commit
>> on the branch, i.e.
>
> I would like to avoid such commits for unfinished content updates. Should the
> storage operation be provided by the stash instead for intermediate work results?
> Will it happen to forget corresponding clean-up for "temporary" changes that
> might be committed too early just to get them stored?
Junio,

I'm not sure how often WIP commits become accidentally published or left in the history, but perhaps it would be advantageous to provide a means of specifying officially that a particular commit is in fact a WIP commit such that no other commits can be made on top of this WIP commit and it can't be merged with other branches or pushed or whatever.

Markus Elfring· Mar 4, 2010, 19:55 UTC · re: Michael Witten · lore

Re: Better cooperation between checkouts and stashing

Show 5 quoted lines
> I'm not sure how often WIP commits become accidentally published or
> left in the history, but perhaps it would be advantageous to provide
> a means of specifying officially that a particular commit is in fact
> a WIP commit such that no other commits can be made on top of this WIP
> commit and it can't be merged with other branches or pushed or whatever.

When will such blocking commits be useful? Would you really like to support a stopper or barrier for branches?

Regards, Markus

Junio C Hamano· Mar 2, 2010, 18:05 UTC · re: Markus Elfring · lore

Re: Better cooperation between checkouts and stashing

Markus Elfring <Markus.Elfring@web.de> writes:
>> You've still got the wrong problem in your head (though you're
>> solving a more useful issue).
>
> Which idea would be better?

They are different problems, and I don't think there is no "better" between them. Is a squirrel 48% juicier than an orange?

Markus Elfring· Mar 17, 2010, 16:35 UTC · re: Michael Witten · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

>From 828d97e2f50b49c87138f382d579605dc134d8ca Mon Sep 17 00:00:00 2001
From: Markus Elfring <Markus.Elfring@web.de>
Date: Wed, 17 Mar 2010 17:05:08 +0100
Subject: [PATCH] Documentation: clarification for the command "git checkout <branch>"

The software implementation worked differently in comparison to the description in the first paragraph. The updated explanation should reflect the current behaviour.

Signed-off-by: Markus Elfring <Markus.Elfring@web.de>
---
> I think it would be a great contribution if you could clean up
> Junio's explanation and submit a patch that includes it in the
> documentation for "git checkout".
Will the following wording be acceptable?

Regards, Markus

 Documentation/git-checkout.txt |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 37c1810..5fcea56 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -15,10 +15,11 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-
-When <paths> are not given, this command switches branches by
-updating the index, working tree, and HEAD to reflect the specified
-branch.
+When <paths> are not given, this command marks the specified branch
+as the next commit target. (The reference "HEAD" points to its tip.)
+Checking out another branch (branch switching) is designed to carry
+your local modifications across with you. The working tree is not
+restored to the state of its last commit.
 
 If `-b` is given, a new branch is created and checked out, as if
 linkgit:git-branch[1] were called; in this case you can
-- 
1.7.0.1
Avery Pennarun· Mar 17, 2010, 16:44 UTC · re: Markus Elfring · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

On Wed, Mar 17, 2010 at 12:35 PM, Markus Elfring <Markus.Elfring@web.de> wrote:
Show 11 quoted lines
> -When <paths> are not given, this command switches branches by
> -updating the index, working tree, and HEAD to reflect the specified
> -branch.
> +When <paths> are not given, this command marks the specified branch
> +as the next commit target. (The reference "HEAD" points to its tip.)
> +Checking out another branch (branch switching) is designed to carry
> +your local modifications across with you. The working tree is not
> +restored to the state of its last commit.
>
>  If `-b` is given, a new branch is created and checked out, as if
>  linkgit:git-branch[1] were called; in this case you can

The new version spends all the time talking about weird exceptions and none of the time actually saying what the basic functionality is supposed to be. How about this:

-- When <paths> are not given, this command switches from your current branch to the given branch. This is done by updating HEAD to point at the given branch, reading the new branch's content into the index, and checking out the content into your working tree. Where possible, any files you have modified in your current working tree or index remain modified in the newly-checked-out branch. This cannot be done, however, when those modified files differ between the old and new branches, in which case the checkout will abort in order to avoid losing your changes. You might want to use 'git stash' in this case. --

Have fun,
Avery
Markus Elfring· Mar 17, 2010, 17:00 UTC · re: Avery Pennarun · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

> This is done by updating HEAD to point at the given branch,

Is it supposed that Git users should know from other information sources already what the key word "HEAD" means?

Regards, Markus

Junio C Hamano· Mar 17, 2010, 17:58 UTC · re: Avery Pennarun · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

Avery Pennarun <apenwarr@gmail.com> writes:
Show 20 quoted lines
> On Wed, Mar 17, 2010 at 12:35 PM, Markus Elfring <Markus.Elfring@web.de> wrote:
>> -When <paths> are not given, this command switches branches by
>> -updating the index, working tree, and HEAD to reflect the specified
>> -branch.
> ...
> The new version spends all the time talking about weird exceptions and
> none of the time actually saying what the basic functionality is
> supposed to be.  How about this:
>
> --
> When <paths> are not given, this command switches from your current
> branch to the given branch.  This is done by updating HEAD to point at
> the given branch, reading the new branch's content into the index, and
> checking out the content into your working tree.  Where possible, any
> files you have modified in your current working tree or index remain
> modified in the newly-checked-out branch.  This cannot be done,
> however, when those modified files differ between the old and new
> branches, in which case the checkout will abort in order to avoid
> losing your changes.  You might want to use 'git stash' in this case.
> --

I like the "First state what it conceptually does and for what purpose it is used.", but isn't this going down to too low-level details without saying what these low-level details mean to the visible effects?

When <paths> are not given, this command makes the named branch the current branch, so that a further work will be committed on that branch.

The index and the working tree are updated to the contents of the new branch, while carrying the uncommitted changes you made so far along with you. If you made changes to paths that are different from the current branch and the new branch, the command will stop you in order to prevent you from losing your uncommited changes in potential conflicts between them and the changes between two branches. You may want retry the command after recording the local changes (1) in a temporary commit on the current branch, or (2) by using "git stash". Alternatively, see "-m" option.

Markus Elfring· Mar 17, 2010, 18:21 UTC · re: Junio C Hamano · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

>      If you made changes to paths that are different from the current
> branch and the new branch, the command will stop you in order to prevent
> you from losing your uncommited changes in potential conflicts between
> them and the changes between two branches.

I find it hard to realise what will be inside or outside of a path structure under the mentioned conditions.

Regards, Markus

Junio C Hamano· Mar 17, 2010, 18:37 UTC · re: Markus Elfring · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

Markus Elfring <Markus.Elfring@web.de> writes:
Show 7 quoted lines
>>      If you made changes to paths that are different from the current
>> branch and the new branch, the command will stop you in order to prevent
>> you from losing your uncommited changes in potential conflicts between
>> them and the changes between two branches.
>
> I find it hard to realise what will be inside or outside of a path structure
> under the mentioned conditions.

Sorry, but I didn't say anything about path structure, and I am unsure what you were talking about. Here is what I meant:

Imagine you are on branch A and trying to switch to branch B. There are changed paths between these two branches (i.e. the paths that appear in the output from "git diff --name-only A B") and there are unchanged paths. If you have local changes to the former, such local changes may conflict with the change made between A and B, and stops the command.

Michael Witten· Mar 17, 2010, 18:50 UTC · re: Junio C Hamano · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

On Wed, Mar 17, 2010 at 13:37, Junio C Hamano <gitster@pobox.com> wrote:
> such local changes may conflict with the change
> made between A and B, and stops the command.
I'm sensing that it needs to be clarified what a conflict is.
Junio C Hamano· Mar 17, 2010, 19:23 UTC · re: Michael Witten · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

Michael Witten <mfwitten@gmail.com> writes:
Show 5 quoted lines
> On Wed, Mar 17, 2010 at 13:37, Junio C Hamano <gitster@pobox.com> wrote:
>> such local changes may conflict with the change
>> made between A and B, and stops the command.
>
> I'm sensing that it needs to be clarified what a conflict is.

Hmm, a conflict is "you changed it in one way, and I am trying to change the same thing in another way, you two have to fight it out". What other interpretations are there, especially in a context of SCM?

I wouldn't mind a patch to add the definition to glossary, though.
Markus Elfring· Mar 18, 2010, 10:11 UTC · re: Junio C Hamano · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

> You may want retry the command after recording the local changes
> (1) in a temporary commit on the current branch,

Can commits be consistently marked for intermediate use? Can such "special" commits be easily found later on?

> or (2) by using "git stash".

Is this storage operation supported per branch? Does a checkout look if any files were stashed away for the specified branch before?

Regards, Markus

Avery Pennarun· Mar 18, 2010, 16:36 UTC · re: Markus Elfring · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

On Thu, Mar 18, 2010 at 6:11 AM, Markus Elfring <Markus.Elfring@web.de> wrote:
Show 5 quoted lines
>> You may want retry the command after recording the local changes
>> (1) in a temporary commit on the current branch,
>
> Can commits be consistently marked for intermediate use?
> Can such "special" commits be easily found later on?

You just make the commit with a 'FIXME' type commit message, then 'git commit --amend' to fix it when you come back later.

>> or (2) by using "git stash".
>
> Is this storage operation supported per branch?
> Does a checkout look if any files were stashed away for the specified branch before?

stashing isn't really something you'd want to do on a per-branch basis. Most of the point is that you stash away your changes, then switch to another branch, then restore your stash to your *current* working state sometime later.

Have fun,
Avery
Michael Witten· Mar 18, 2010, 17:19 UTC · re: Avery Pennarun · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

On Thu, Mar 18, 2010 at 11:36, Avery Pennarun <apenwarr@gmail.com> wrote
Show 9 quoted lines
> On Thu, Mar 18, 2010 at 6:11 AM, Markus Elfring <Markus.Elfring@web.de> wrote:
>>> You may want retry the command after recording the local changes
>>> (1) in a temporary commit on the current branch,
>>
>> Can commits be consistently marked for intermediate use?
>> Can such "special" commits be easily found later on?
>
> You just make the commit with a 'FIXME' type commit message, then 'git
> commit --amend' to fix it when you come back later.

Something more explicit might be useful in my opinion, as suggested in this previous post:

    http://marc.info/?l=git&m=126768880311121&w=2
    > I'm not sure how often WIP commits become
    > accidentally published or left in the history,
    > but perhaps it would be advantageous to
    > provide a means of specifying officially that
    > a particular commit is in fact a WIP commit
    > such that no other commits can be made on top
    > of this WIP commit and it can't be merged with
    > other branches or pushed or whatever.
>>> or (2) by using "git stash".
>>
>> Is this storage operation supported per branch?
>> Does a checkout look if any files were stashed away for the specified branch before?
Markus, this was discussed ad nauseum in the other thread:
    http://marc.info/?l=git&m=126746296820948&w=2
    http://marc.info/?l=git&m=126749413508313&w=2
    http://marc.info/?l=git&m=126746730431007&w=2
Are you not reading? Are you not comprehending? Are you trolling?
> stashing isn't really something you'd want to do on a per-branch
> basis.  Most of the point is that you stash away your changes, then
> switch to another branch, then restore your stash to your *current*
> working state sometime later.

As you may know, "git checkout" carries local modifications to the new working tree if there are no conflicts, so no explicit stash usage is necessary in many cases.

Anyway, I think it would be useful to be able to manage multiple stashes rather than having to rely on just one global stash. However, I imagine than explicit Work In Progress (WIP) commits as sketched above would go a long way in keeping histories and workflows clean and organized.

Avery Pennarun· Mar 18, 2010, 17:33 UTC · re: Michael Witten · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

On Thu, Mar 18, 2010 at 1:19 PM, Michael Witten <mfwitten@gmail.com> wrote:
Show 9 quoted lines
> On Thu, Mar 18, 2010 at 11:36, Avery Pennarun <apenwarr@gmail.com> wrote
>> stashing isn't really something you'd want to do on a per-branch
>> basis.  Most of the point is that you stash away your changes, then
>> switch to another branch, then restore your stash to your *current*
>> working state sometime later.
>
> As you may know, "git checkout" carries local modifications to the new
> working tree if there are no conflicts, so no explicit stash usage is
> necessary in many cases.

I'm almost never lucky enough that switching branches won't touch the same files as the ones I've been editing (especially Makefile). I imagine this works better with larger repositories like the Linux kernel. But my fingers have learned that if I do 'git stash' it always works, while if I don't it doesn't always work, so I stash without thinking nowadays.

The other big advantage of using stash is that your half-done files end up in the repo, so if you later screw up by doing something idiotic like 'git reset --hard' at the wrong time, you can still get it back. I love that feeling of safety.

Show 5 quoted lines
> Anyway, I think it would be useful to be able to manage multiple
> stashes rather than having to rely on just one global stash. However,
> I imagine than explicit Work In Progress (WIP) commits as sketched
> above would go a long way in keeping histories and workflows clean and
> organized.

The stash can contain multiple entries. They're stored in a stack, but you can pull prior entries out of the stack if you want. Personally, I don't need anything more.

Have fun,
Avery
Markus Elfring· Mar 19, 2010, 08:28 UTC · re: Avery Pennarun · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

> The stash can contain multiple entries.  They're stored in a stack,
> but you can pull prior entries out of the stack if you want.

I am missing a semantic relationship of the stashed files to the work that they belong to in various branches. I would appreciate to see a clear connection between them.

Regards, Markus

Avery Pennarun· Mar 19, 2010, 17:17 UTC · re: Markus Elfring · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

On Fri, Mar 19, 2010 at 4:28 AM, Markus Elfring <Markus.Elfring@web.de> wrote:
Show 6 quoted lines
>> The stash can contain multiple entries.  They're stored in a stack,
>> but you can pull prior entries out of the stack if you want.
>
> I am missing a semantic relationship of the stashed files to the work that they
> belong to in various branches. I would appreciate to see a clear connection
> between them.
Then what you want is just a temporary commit.

I think your mental model has exaggerated the cost of a commit. Commits cost almost exactly zero.

    git commit -a -m 'FIXME temporary'

And there you have it. When you want to undo the commit or update it, you just do

    git reset HEAD^

and it's as if the commit never happened. Or don't reset, but just make further changes and replace the commit:

    git commit -a --amend
Which part isn't acceptable?
Have fun,
Avery
Markus Elfring· Mar 20, 2010, 06:00 UTC · re: Avery Pennarun · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

> Commits cost almost exactly zero.

The storage costs are negligible. I am more concerned about unwanted work flow effects because a modification might be committed and suddenly merged too early.

>     git commit -a -m 'FIXME temporary'

The specified message is not independent from a language. I see also a potential for typos by this approach which will make it harder to distinguish non-temporary commits from the real ones.

Regards, Markus

Markus Elfring· Mar 19, 2010, 08:15 UTC · re: Michael Witten · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

> Are you not reading? Are you not comprehending? Are you trolling?
I answer these three questions with "NO".

I find that the discussion is not finished yet. It was not achieved a common conclusion and consensus on all mentioned details so far.

>> stashing isn't really something you'd want to do on a per-branch
>> basis.  Most of the point is that you stash away your changes, then
>> switch to another branch, then restore your stash to your *current*
>> working state sometime later.

I have got different expectations. I would expect that there are enough intermediate work results available to justify a stash per branch so that unwanted "temporary" or "throw-away" commits can be avoided.

> As you may know, "git checkout" carries local modifications to the new
> working tree if there are no conflicts, so no explicit stash usage is
> necessary in many cases.

Various software projects have got different amounts of uncommitted changes between branches.

Show 5 quoted lines
> Anyway, I think it would be useful to be able to manage multiple
> stashes rather than having to rely on just one global stash. However,
> I imagine than explicit Work In Progress (WIP) commits as sketched
> above would go a long way in keeping histories and workflows clean
> and organized.

I am also interested in improvements for this feature request. Does a "WIP" really need a commit to get the unfinished changes stored?

Regards, Markus

Markus Elfring· Mar 30, 2010, 15:57 UTC · re: Markus Elfring · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

> I find that the discussion is not finished yet. It was not achieved a common
> conclusion and consensus on all mentioned details so far.
Can we achieve progress for an update of the manual?

Regards, Markus

Junio C Hamano· Mar 30, 2010, 22:13 UTC · re: Markus Elfring · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

Markus Elfring <Markus.Elfring@web.de> writes:
Show 7 quoted lines
>> I find that the discussion is not finished yet. It was not achieved a common
>> conclusion and consensus on all mentioned details so far.
>
> Can we achieve progress for an update of the manual?
>
> Regards,
> Markus
Something like this?
 Documentation/git-checkout.txt |   27 ++++++++++++++++++++++++---
 1 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 37c1810..d443a12 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -16,9 +16,9 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-When <paths> are not given, this command switches branches by
-updating the index, working tree, and HEAD to reflect the specified
-branch.
+When <paths> are not given, this command makes the named branch the
+current branch, so that a further work will be committed on that branch.
+See "Switching Branches" below.
 
 If `-b` is given, a new branch is created and checked out, as if
 linkgit:git-branch[1] were called; in this case you can
@@ -149,6 +149,27 @@ checks out the branch (instead of detaching).  You may also specify
 	the index will be used.
 
 
+Switching Branches
+------------------
+
+While switching to another branch (or more in general, to another commit
+that is not the current commit), the index and the working tree are
+updated to the contents of the new branch, while carrying the uncommitted
+changes you made so far along with you.  People often start making changes
+and then realize that the changes belong to a branch that is different
+from the current one, and it helps these people to carry the changes
+forward upon switching branches.
+
+If the branch you are switching to has one version of a file, and the
+current branch has a different version of it, which you changed in your
+working tree to yet another version, carrying the changes forward is not
+possible without merging.  But you may not be ready to resolve such
+conflicts right now.  By default, the command refuses to switch branches
+to prevent you from losing your local changes due to such conflicts.  In
+such a case, you may want retry the command after recording the local
+changes (1) in a temporary commit on the current branch, or (2) by using
+"git stash".  Alternatively, use "-m" option to force a merge.
+
 
 Detached HEAD
 -------------
Ramkumar Ramachandra· Mar 31, 2010, 03:58 UTC · re: Junio C Hamano · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

Hi,
On Wed, Mar 31, 2010 at 3:43 AM, Junio C Hamano <gitster@pobox.com> wrote:
> +such a case, you may want retry the command after recording the local
> +changes (1) in a temporary commit on the current branch, or (2) by using
> +"git stash".  Alternatively, use "-m" option to force a merge.

Couple of things: Is (1) really an option? The user will have to go through documentation on rewriting history, which I find completely unnecessary to just switch branches. Second, you might want to mention a "git stash apply" and include a reference to git-stash documentation.

-- Ram
Junio C Hamano· Apr 1, 2010, 04:52 UTC · re: Ramkumar Ramachandra · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

Ramkumar Ramachandra <artagnon@gmail.com> writes:
Show 6 quoted lines
> On Wed, Mar 31, 2010 at 3:43 AM, Junio C Hamano <gitster@pobox.com> wrote:
>> +such a case, you may want retry the command after recording the local
>> +changes (1) in a temporary commit on the current branch, or (2) by using
>> +"git stash". Alternatively, use "-m" option to force a merge.
>
> Couple of things: Is (1) really an option?

Of course; otherwise I wouldn't have written it, but another option (0) would be:

    (0) if you are in the middle of working something for the current
    branch, finish it first before switching to other task.
But that would go without saying.
> The user will have to go
> through documentation on rewriting history, which I find completely
> unnecessary to just switch branches.

I think you are thinking backwards. If the user always does a perfect job before making each and every commit, she doesn't ever need to learn "amend". Otherwise, she will learn "amend" way before learning to switch between branches to work on different things at the same time.

IOW, by the time the user learns branch switching, I expect she at least knows about "amend" (if not rebase-i/filter-branch), and that is all that is necessary to restart from a WIP commit when she comes back.

Ramkumar Ramachandra· Apr 1, 2010, 13:09 UTC · re: Junio C Hamano · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

> I think you are thinking backwards.  If the user always does a perfect job
> before making each and every commit, she doesn't ever need to learn
> "amend".  Otherwise, she will learn "amend" way before learning to switch
> between branches to work on different things at the same time.

Right. Got it. It's pretty difficult to think from a new user's perspective actually :)

-- Ram
Markus Elfring· Apr 1, 2010, 06:38 UTC · re: Junio C Hamano · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

> In such a case, you may want retry the command after recording
> the local changes (1) in a temporary commit on the current branch,

Should corresponding work flow actions be also mentioned to clean up such "temporaries"?

> or (2) by using "git stash".
Do we need a new feature "stash per branch" here?

Will an option be useful to specify that uncommitted changes can be overwritten by data from the branch switch?

Regards, Markus

Junio C Hamano· Apr 10, 2010, 22:31 UTC · re: Markus Elfring · lore

Re: [PATCH] Clarification for the command "git checkout <branch>"

Markus Elfring <Markus.Elfring@web.de> writes:
>> Something like this?
>
> Which update will be published for the manual?
Neither one without any clear support by reviews on the list.  You asked
    Markus Elfring <Markus.Elfring@web.de> writes:
    >> I find that the discussion is not finished yet. It was not achieved a common
    >> conclusion and consensus on all mentioned details so far.
    >
    > Can we achieve progress for an update of the manual?

and the patch was only to illustrate what _you_ could do to help the topic.

IOW, the message you are responding to is a "Yes you could help it by doing something like this and asking for comments" in response to "Can we achieve progress?"

← back to recent threads