All of lore.kernel.org
 help / color / mirror / Atom feed
* BUG? git stash and immediate git apply results in conflict
@ 2022-06-01  6:55 Akos Vandra-Meyer
  2022-06-02  6:32 ` Chris Torek
  0 siblings, 1 reply; 4+ messages in thread
From: Akos Vandra-Meyer @ 2022-06-01  6:55 UTC (permalink / raw)
  To: git

Hello!

I believe there might be a bug in how a git stash is calculated with
the -k flag.
I would expect to always be able to stash and pop a set of changes,
but if the working directory contains staged and unstaged changes for
a file, this results in a conflict.

The stashed diff shows the changes from the last commit, rather than
what is in the current working directory, so when the stash is applied
it results in a conflict, because there are staged changes in the
current working directory.

Steps to reproduce:

 mkdir test
 cd test
 git init .
 echo foo > a
 echo bar >> a
 echo baz >> a
 git add a
 git commit -m "initial"
 cat a | sed s/bar/foo2/ > a2; mv a2 a git status
 git add a
 cat a | sed s/foo2/xxx/ > a2; mv a2 a
 git status
 git stash -ku
 git stash pop

Thanks for looking into this,
  Akos Vandra-Meyer

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: BUG? git stash and immediate git apply results in conflict
  2022-06-01  6:55 BUG? git stash and immediate git apply results in conflict Akos Vandra-Meyer
@ 2022-06-02  6:32 ` Chris Torek
  2022-06-02 11:31   ` Akos Vandra-Meyer
  0 siblings, 1 reply; 4+ messages in thread
From: Chris Torek @ 2022-06-02  6:32 UTC (permalink / raw)
  To: Akos Vandra-Meyer; +Cc: Git List

On Wed, Jun 1, 2022 at 2:11 PM Akos Vandra-Meyer <axos88@gmail.com> wrote:
>  git stash -ku
>  git stash pop

This is not a bug in `git stash` itself, but rather in the way you're using it.

There are two mistakes on your part here:

1: You are using `-k`, aka `--keep-index`. This flag is intended for usages
that are not yours here.

2. You are *not* using `--index` in your `git pop`.  The `--index` flag is
intended for the kind of thing you are doing here.

It's a bit unfortunate (and perhaps worth some work in the documentation)
that the `--keep-index` and `--index` flags sound so similar, and yet are so
different.  The documentation could use some examples here, I think.

Note that if you *do* want to use `--keep-index` during the `git stash` step,
you will need a `git reset --hard` before your `git stash apply --index &&
git stash drop` step (aka `git stash pop --index`).

Chris

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: BUG? git stash and immediate git apply results in conflict
  2022-06-02  6:32 ` Chris Torek
@ 2022-06-02 11:31   ` Akos Vandra-Meyer
  2022-06-02 12:24     ` Chris Torek
  0 siblings, 1 reply; 4+ messages in thread
From: Akos Vandra-Meyer @ 2022-06-02 11:31 UTC (permalink / raw)
  To: Chris Torek; +Cc: Git List

Hi Chris,

Thanks for getting back to me on this.
My use case is the following:

I made a bunch of (loosely related) changes to my code, but I have
been asked to submit them as separate commits, so I need to separate
the changes to dependent files relating to the first and second
feature.

So I need to separate the changes in my workdir into two commits
(let's call them two features). Turns out the first feature needs a
dependent file changed in one way, and the second feature improves on
it, so it needs it changed in another way - normally this would result
in a conflict if they would have been done separately in different
branches.

I start off by stashing everything except stuff directly relating to
the first feature and stashing everything else. Check for build
errors, unstage, and incrementally staging more stuff that need to be
added in order to make the first feature build correctly. At some
point I reach the file that has to be changed differently, so I will
have a set of changes staged for that file, while another set of
changes remain unstaged - the changes that will be required by the
second feature.

At this point you pointed out that apparantly I'm misusing git, but I
am confused on how to correctly stash the unstaged changes to check if
the code would build with the staged changes only, and unstage them
and add more stuff if not?

Thanks,
  Akos





On Thu, 2 Jun 2022 at 08:32, Chris Torek <chris.torek@gmail.com> wrote:
>
> On Wed, Jun 1, 2022 at 2:11 PM Akos Vandra-Meyer <axos88@gmail.com> wrote:
> >  git stash -ku
> >  git stash pop
>
> This is not a bug in `git stash` itself, but rather in the way you're using it.
>
> There are two mistakes on your part here:
>
> 1: You are using `-k`, aka `--keep-index`. This flag is intended for usages
> that are not yours here.
>
> 2. You are *not* using `--index` in your `git pop`.  The `--index` flag is
> intended for the kind of thing you are doing here.
>
> It's a bit unfortunate (and perhaps worth some work in the documentation)
> that the `--keep-index` and `--index` flags sound so similar, and yet are so
> different.  The documentation could use some examples here, I think.
>
> Note that if you *do* want to use `--keep-index` during the `git stash` step,
> you will need a `git reset --hard` before your `git stash apply --index &&
> git stash drop` step (aka `git stash pop --index`).
>
> Chris

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: BUG? git stash and immediate git apply results in conflict
  2022-06-02 11:31   ` Akos Vandra-Meyer
@ 2022-06-02 12:24     ` Chris Torek
  0 siblings, 0 replies; 4+ messages in thread
From: Chris Torek @ 2022-06-02 12:24 UTC (permalink / raw)
  To: Akos Vandra-Meyer; +Cc: Git List

On Thu, Jun 2, 2022 at 4:31 AM Akos Vandra-Meyer <axos88@gmail.com> wrote:
> Hi Chris,
>
> Thanks for getting back to me on this.
> My use case is the following:
>
> I made a bunch of (loosely related) changes to my code, but I have
> been asked to submit them as separate commits, so I need to separate
> the changes to dependent files relating to the first and second
> feature.

I snipped the rest of this because I *dislike* and *recommend against*
the use of `git stash` in the first place. If you want to use it that way, I am
sure it is possible, but I recommend doing something else entirely.
The rest of this message is all opinion! You seem to be looking for
a recommended method, so I'm recommending mine.

Let's say for concreteness that your current branch is named "topic".
Here is what I would do (though I might change strategies and use
various short-cuts depending on various sub-scenarios; this is meant
for illustrating how to do what you want, in a way that provides the
most clarity):

git add (files as needed)
git commit -m "final version, to be split up"
git branch -m not-final-topic

Then:

# create a new topic branch
git checkout -b new-topic <start-point>

# get a view of commits
git log HEAD..topic

# copy some commits, up until some point
git cherry-pick <some of those commits as desired>

# begin splitting a commit:
git cherry-pick -n <hash>

# split it up: use a mix of the following:
git reset / git add -p / git reset -p
                # as needed here to take part of the commit)

# observe what's to be committed
git diff --cached
git commit      # and write a commit message

git add -p ...  # as needed again
git diff --cached
git commit      # repeat until satisfied with broken up commit(s)

# make sure final result matches - optional: use the same
# hash here as for the `git cherry-pick -n` command
git diff HEAD <hash>

# repeat copying whole and partial commits:

git cherry-pick ...     # add more whole commits as desired
git cherry-pick -n ...  # add commit that is to be split up
                        # repeat the split-up process

# When finally done, ensure that new-topic and not-final-topic
# have the same contents. If they do, the split-up was successful.
git diff not-final-topic HEAD

Note that there is no longer any branch named "topic" at this
point: we have instead "not-final-topic" and "new-topic". We
can now rename "new-topic" to "topic" and use `git push -f`
or whatever else is appropriate for whatever review system(s)
you may be using.

The entire process above can often be done with a single `git
rebase -i` command, but that obscures the fundamental nature of
what you're really doing. The repeated cherry-pick, reset, add
-p, and/or reset -p sequence is what you're really doing: you are
taking some set of existing commits, which are *close* to the
commits you'd like to have, and rebuilding them to make a new set
of commits (with different hash IDs) that represent what you
really do want.

In the end, you will have Git *find* your commits by name: the
name "topic" will name the last commit in a chain of commits.
The names here are up to you, and you can change any name at
any time using `git branch -m`. Both Git and any review system
you use is going to use the *commits*, with their scary looking
hash IDs, but like you they will *find* these commits by starting
from a branch name: so by changing the hash ID stored in the
branch name, you change the set of commits they (and you) find.

What `git stash` does is make several commits that are not on
*any* branch. These commits are a little weird, requiring the
use of the `git stash` command to access them. Ordinary commits
on ordinary branches are not weird and do not need any special
access, so that's what I prefer.  But the fact that the stash commits
are on *no* branch makes it easy to slide them from one branch to
another without having to think about hash IDs; that's one reason
some people prefer `git stash`. I'm just not one of those people.

Chris

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-06-02 12:25 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-01  6:55 BUG? git stash and immediate git apply results in conflict Akos Vandra-Meyer
2022-06-02  6:32 ` Chris Torek
2022-06-02 11:31   ` Akos Vandra-Meyer
2022-06-02 12:24     ` Chris Torek

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.