git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Better cooperation between checkouts and stashing

From
Michael Witten <mfwitten@gmail.com>
Date
Mar 1, 2010, 17:02 UTC
Message-ID
<4b8bf32f.0706c00a.26cb.691d@mx.google.com>
In-Reply-To
<4B8B9BF1.10408@web.de>
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

Previous: Markus ElfringNext: Junio C Hamano
Message 18 of 56 in “Better cooperation between checkouts and stashing”
  1. Markus ElfringFeb 1, 2010
  2. Junio C HamanoFeb 1, 2010
  3. Markus ElfringFeb 1, 2010
  4. Eugene SajineFeb 1, 2010
  5. Petr BaudisFeb 2, 2010
  6. Markus ElfringFeb 2, 2010
  7. Petr BaudisFeb 2, 2010
  8. Markus ElfringFeb 9, 2010
  9. Junio C HamanoFeb 9, 2010
  10. Markus ElfringFeb 9, 2010
  11. Markus ElfringFeb 18, 2010
  12. Junio C HamanoFeb 18, 2010
  13. Markus ElfringFeb 27, 2010
  14. Junio C HamanoFeb 27, 2010
  15. Markus ElfringFeb 28, 2010
  16. Michael WittenFeb 28, 2010
  17. Markus ElfringMar 1, 2010
  18. Michael WittenMar 1, 2010
  19. Junio C HamanoMar 1, 2010
  20. Michael WittenMar 1, 2010
  21. Markus ElfringMar 1, 2010
  22. Junio C HamanoMar 1, 2010
  23. Markus ElfringMar 1, 2010
  24. Michael WittenMar 2, 2010
  25. Markus ElfringMar 2, 2010
  26. Junio C HamanoMar 2, 2010
  27. Markus ElfringMar 3, 2010
  28. Michael WittenMar 4, 2010
  29. Markus ElfringMar 4, 2010
  30. Markus ElfringMar 2, 2010
  31. Junio C HamanoMar 2, 2010
  32. Markus ElfringMar 3, 2010
  33. Markus ElfringMar 17, 2010
  34. Avery PennarunMar 17, 2010
  35. Markus ElfringMar 17, 2010
  36. Junio C HamanoMar 17, 2010
  37. Markus ElfringMar 17, 2010
  38. Junio C HamanoMar 17, 2010
  39. Michael WittenMar 17, 2010
  40. Junio C HamanoMar 17, 2010
  41. Markus ElfringMar 18, 2010
  42. Avery PennarunMar 18, 2010
  43. Michael WittenMar 18, 2010
  44. Avery PennarunMar 18, 2010
  45. Markus ElfringMar 19, 2010
  46. Avery PennarunMar 19, 2010
  47. Markus ElfringMar 20, 2010
  48. Markus ElfringMar 19, 2010
  49. Markus ElfringMar 30, 2010
  50. Junio C HamanoMar 30, 2010
  51. Ramkumar RamachandraMar 31, 2010
  52. Junio C HamanoApr 1, 2010
  53. Ramkumar RamachandraApr 1, 2010
  54. Markus ElfringApr 1, 2010
  55. Markus ElfringApr 10, 2010
  56. Junio C HamanoApr 10, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.