Re: Add porcelain command to revert a single staged file to its HEAD state while preserving its staged state

4 messages, 2 authors, 2016-06-15 · open the first message on its own page

Re: Add porcelain command to revert a single staged file to its HEAD state while preserving its staged state

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:57:08

Junio C Hamano [off-list ref] writes:
"I have something worth saving, better than HEAD in some way
(e.g. contains fixes), in my index. I want to keep it while I
experiment an approach that is unrelated to it, so I want a clean
slate in the working tree from HEAD without disturbing the index".

At the first glance, that looks like a reasonable thing to ask, but
after thinking about it a bit more, I am not sure if it really is,
primarily because it is unclear what you can productively do to the
end result next.

Suppose you matched the working tree to HEAD while keeping a
valuable change in the index, and after working for a while, now
have finished the experiment and have something in your working
tree.

What is your next move?

If the end result in the working tree were "Nah, this other approach
does not work, trash it", you can checkout the working tree from the
index, so nothing is lost.

But if your result is _also_ something worth saving, what would you
do?  "git add" to update the index will trash the work that was in
the index, and that is by definition unrelated to what you worked on
in the working tree (you wanted to start from the version in the
HEAD, not from the version in the index, so the end result is likely
to lack the work you saved in the index).

That makes me think that "match working tree from HEAD bypassing
index" is not a very useful strategy, unless you are expecting a
failed experiment from the start.

As Thomas said, I think a more reasonable workflow would begin by
saving the "somewhat worth saving" state you have in your index as a
WIP commit, i.e.

	git commit -m wip

When I experiment starting from a clean slate (after saving away
such a WIP commit), I would then do this:

        git checkout HEAD^

to start at the state before the WIP commit and hack away.  As I do
not know how the experiment would go when I do this, I often do not
bother giving the experiment its own branch.

If the experiment does not seem to go in a productive direction, I
can simply "git reset --hard && git checkout -" to get rid of it.

On the other hand, if its direction shows promise but turns out to
be more involved than a quick hack, I can at that point decide to
give it its own branch with "git checkout -b newbranch".  Then I can
choose to keep working on it, or switch to other tasks after making
a wip commit on that new branch.

Or if the experiment results in a series of good and straightforward
changes that should come _before_ that original wip (which happens
very often), then I could do:

	git commit ;# maybe more commits.
      git cherry-pick @{-1} ;# the one stashed away
      git co -B @{-1}

to update the original branch and come back to it.
Also, if the alternative experiment was really to replace what you
originally did to your index, as a natural extension to the above
workflow, you would omit "cherry-pick" step in the above.  Your
perfected alternative solution will become the true history of the
original branch, discarding the tentative solution in the index.

Re: Add porcelain command to revert a single staged file to its HEAD state while preserving its staged state

From: Dimitar Bonev <hidden>
Date: 2016-06-15 22:57:08

On Sat, May 4, 2013 at 9:48 PM, Jonathan Nieder [off-list ref] wrote:
Is there no way to convince PowerShell to treat the output of a
command as binary data with no particular encoding?
The best I could find out is to pipe the output to set-content:

git show HEAD:targetfile | set-content targetfile

The default console output redirection pipes the output to Out-File
which encodes the resulting file by default with little endian unicode
encoding, but it can be overridden by providing an argument:

git show HEAD:targetfile | Out-File -encoding utf8 targetfile

Also if I provide 'default' encoding to Out-File it produces the exact
same result as set-content command:

git show HEAD:targetfile | Out-File -encoding default targetfile

The API docs state that "Default" uses the encoding of the system's
current ANSI code page. So I guess it is system dependent, it could be
the case for set-content also, but at the very least set-content is
shorter to write.

On Sat, May 4, 2013 at 11:01 PM, Junio C Hamano [off-list ref] wrote:
Junio C Hamano [off-list ref] writes:
quoted
But if your result is _also_ something worth saving, what would you
do?  "git add" to update the index will trash the work that was in
the index, and that is by definition unrelated to what you worked on
in the working tree (you wanted to start from the version in the
HEAD, not from the version in the index, so the end result is likely
to lack the work you saved in the index).

As Thomas said, I think a more reasonable workflow would begin by
saving the "somewhat worth saving" state you have in your index as a
WIP commit, i.e.

      git commit -m wip

When I experiment starting from a clean slate (after saving away
such a WIP commit), I would then do this:

        git checkout HEAD^
Actually this is not the case as I tried to explain with the 'git
commit' followed by 'git checkout HEAD~1 -- targetfile' followed by
'git commit --amend' example. The index and the working dir states are
very well related. Lets imagine that I am adding an MVC feature X - it
could be implemented with 3 or more files. If I stage the files and
came up with an idea that requires a major rewrite of one of these
files - lets say the controller one - then it is more convenient to
checkout the file's HEAD state and build on top of it - I had been
doing just that right before staging - building the previous
implementation so this is so familiar and still recent in time. If the
new controller implementation is less acceptable than the old one I
just commit, otherwise I stage the new implementation and just commit.
So simple, so common workflow.

One more argument against the suggestion of doing a commit ahead of
time is that I like to think in separation to reduce complexity - in
particular I like to think only for the working dir and index states,
commits - I treat them as finished work. If I have to amend a commit,
it is about fixing a mistake - adding/removing a wrong file, fixing a
typo, that sort of things and not for actual work to be done.

Re: Add porcelain command to revert a single staged file to its HEAD state while preserving its staged state

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:57:08

Dimitar Bonev [off-list ref] writes:

[administrivia: please do not drop people out of Cc list]
Actually this is not the case as I tried to explain with the 'git
commit' followed by 'git checkout HEAD~1 -- targetfile' followed by
'git commit --amend' example. The index and the working dir states are
very well related.
That invites another question: if it is very well related, why isn't
it an option to start from the state you have in the working tree
(i.e. doing nothing), or in the index (i.e. "git checkout
controller")?

But the answer does not matter that much in the end.
Lets imagine that I am adding an MVC feature X - it
could be implemented with 3 or more files. If I stage the files and
came up with an idea that requires a major rewrite of one of these
files - lets say the controller one - then it is more convenient to
checkout the file's HEAD state and build on top of it - I had been
doing just that right before staging
So you have satisfactory changes for view and model in the index,
and changes to the controller that maybe is OK but you think it
could be improved, and you want to go back to the clean slate to
rethink the approach only for the controller part?

I think the story is essentially the same.  Let's say you did

    git diff HEAD controller | git apply -R
    edit controller

to get rid of the changes in the working tree, further worked on the
controller part, and came up with a different implementation.  Then
you would presumably do

    git add controller

but at that point you would lose the "maybe OK" version you had in
the index.  What if you think the version in the working tree might
end up being better than "maybe OK" but can still be improved
further?  You never "git add" until the working tree version gets
into truly a better shape?

What happens fairly often is that you end up having more than _one_
versions that are both better than the version from the HEAD but
cannot immediately say one is clearly better than the others in all
counts, and at some point, you would need more than one intermediate
states (while the index can have only one), to keep these competing
versions. The next thing you would want to do is to take a deep
breath and pick better parts from these good versions to come up
with the single final version. Keeping one good version in the index
does not let you do so.
... commits - I treat them as finished work.
I think people should learn to take the biggest advantage of using a
distributed source control system, which is that commits do not have
to be "finished work", until you choose to declare they are done and
push them out for others to see.

Fear of commitment is a disease we do not have to suffer once we
graduated centralized systems ;-).

Re: Add porcelain command to revert a single staged file to its HEAD state while preserving its staged state

From: Dimitar Bonev <hidden>
Date: 2016-06-15 22:57:10

Junio C Hamano [off-list ref] wrote:
Dimitar Bonev [off-list ref] writes:

[administrivia: please do not drop people out of Cc list]

That invites another question: if it is very well related, why isn't
it an option to start from the state you have in the working tree
(i.e. doing nothing), or in the index (i.e. "git checkout
controller")?

But the answer does not matter that much in the end.
It isn't an option to start from the staged state, because the staged
implementation modified code that is present in the HEAD state. So the
new implementation that I have in my mind requires to add its own kind
of modifications which are incompatible with the staged
implementation. It is much easier to start from HEAD state when both
implementations require modifying 10% HEAD code and adding 90% new
code. If I start from staged state I have to drop 90% new code and to
figure out if the 10% modified state can work without the 90% dropped
code. At the same time I know HEAD state is stable working code. There
is no doubt that I have to start from HEAD state of the controller
file for the described MVC example
I think the story is essentially the same.  Let's say you did

    git diff HEAD controller | git apply -R
    edit controller

to get rid of the changes in the working tree, further worked on the
controller part, and came up with a different implementation.  Then
you would presumably do

    git add controller

but at that point you would lose the "maybe OK" version you had in
the index.  What if you think the version in the working tree might
end up being better than "maybe OK" but can still be improved
further?  You never "git add" until the working tree version gets
into truly a better shape?
Yes, I 'git add' only what is to become part of the next commit so at
least it has to be stable code (that passes some smoke tests or
something similar).
What happens fairly often is that you end up having more than _one_
versions that are both better than the version from the HEAD but
cannot immediately say one is clearly better than the others in all
counts, and at some point, you would need more than one intermediate
states (while the index can have only one), to keep these competing
versions. The next thing you would want to do is to take a deep
breath and pick better parts from these good versions to come up
with the single final version. Keeping one good version in the index
does not let you do so.
My case was not like that but if it was I would have made a commit to
preserve the old implementation while working on the new one.
I think people should learn to take the biggest advantage of using a
distributed source control system, which is that commits do not have
to be "finished work", until you choose to declare they are done and
push them out for others to see.

Fear of commitment is a disease we do not have to suffer once we
graduated centralized systems ;-).
I used the wrong words - I meant 'stable state' instead of 'finished
work'. If every commit was finished work then all my branches would
have contain one specific commit. My branches are built from more than
one commit and every commit adds a subfeature and the commit should be
stable in sense that it should run without throwing exceptions - like
trying to load some file that would be created in a future commit. One
should be able to checkout a random commit and be able to run,
inspect, write tests against, add new subfeature on top of that
commit.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help