threads / discuss / 25808

OK, how should I have done this...

Subject: OK, how should I have done this...

## tl;dr

7 messages between Nov 22, 2010 and Nov 23, 2010.

replies: 6people: 4as markdown or json

Patrick Doyle· Nov 22, 2010, 13:22 UTC · lore

I just checked in modifications to 1/2 dozen or so files in a single commit and pushed them to my server.

Then I switched to a different machine, pulled the latest version of my repository from the server, tried running my code, and discovered that I introduced a problem that didn't manifest itself when running on my laptop.

So now I want to figure out which modification(s) in which file(s) introduced the problem.

I did a git log and saw that things were fine back at commit 5ccce3, so I did
$ git checkout 5ccce3

fully expecting (and seeing) the warning about 'moving to "5ccce3" which isn't a local branch'

ran my code.  It worked (as expected).
$ git diff --name-status master
Saw the list of files that had changed.
$ git checkout master -- file1

Grabbed the version of file1 from master & reran my test. It passed. Repeated the process until I'd identified the set of 3 files that caused things to break, and fixed those three files.

Now I want to check those 3 files in on the master branch. My first inclination, since every time I've tried doing stuff like this in the past has failed miserably, was to copy those 3 files to a safe location, revert them to their unmodified state, switch to the master branch, copy the modified files into my working directory, and commit them.

Instead, I did:
$ git checkout master

hoping that would just switch me to the master branch, keeping those 3 modified files. Instead, what I got was:

error: Entry 'blah/file7' not uptodate.  Cannot merge.

and now "git status" shows a bunch of files staged to be committed (all the files that were different between master and rev 5ccce3) and my 3 files with their modifications.

I'm gonna go back to plan A, copy those 3 files to someplace safe, and checkout/reset until I get back to a clean checkout of master, copy those 3 files in, and commit that change.

But I _know_ that there must be a better way to do this. What should I have done?

--wpd
Matthieu Moy· Nov 22, 2010, 13:34 UTC · re: Patrick Doyle · lore

Re: OK, how should I have done this...

Patrick Doyle <wpdster@gmail.com> writes:
> I just checked in modifications to 1/2 dozen or so files in a single
> commit and pushed them to my server.
> So now I want to figure out which modification(s) in which file(s)
> introduced the problem.

'didn't read all the details of your message, but the way I'd have done this would be with stash --keep-index:

(untested)
git checkout the-one-that-works # staging area and tree checked out.
git reset the-one-that-doesnt   # just change the staging area
git add -p
# pick some commits
git stash --keep-index
# run some tests
# if test fail then
   # happy, "git diff --staged" tells you what.
# else
   git commit -m "first modification"
   git stash pop
   # goto the git add -p step.
# fi
-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/
Patrick Doyle· Nov 22, 2010, 14:22 UTC · re: Matthieu Moy · lore

Re: OK, how should I have done this...

On Mon, Nov 22, 2010 at 8:34 AM, Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> wrote:

Show 26 quoted lines
> Patrick Doyle <wpdster@gmail.com> writes:
>
>> I just checked in modifications to 1/2 dozen or so files in a single
>> commit and pushed them to my server.
>
>> So now I want to figure out which modification(s) in which file(s)
>> introduced the problem.
>
> 'didn't read all the details of your message, but the way I'd have
> done this would be with stash --keep-index:
>
> (untested)
>
> git checkout the-one-that-works # staging area and tree checked out.
> git reset the-one-that-doesnt   # just change the staging area
> git add -p
> # pick some commits
> git stash --keep-index
> # run some tests
> # if test fail then
>   # happy, "git diff --staged" tells you what.
> # else
>   git commit -m "first modification"
>   git stash pop
>   # goto the git add -p step.
> # fi

That looks kinda scary to me. The last time I played with git-reset, I ended up losing(*) the commit at the head of my branch. ((*) Well, I didn't "lose" it in the sense of "it's gone forever", but I lost it in the sense of "it doesn't show up in git log anymore".)

This looks like I would end up committing changes on top of the "the one that works" commit and not on the more recent, already on the server, "the-one-that-doesnt" commit.

--wpd
Tay Ray Chuan· Nov 22, 2010, 14:29 UTC · re: Patrick Doyle · lore

Re: OK, how should I have done this...

Hi,
On Mon, Nov 22, 2010 at 10:22 PM, Patrick Doyle <wpdster@gmail.com> wrote:
> That looks kinda scary to me.  The last time I played with git-reset,
> I ended up losing(*) the commit at the head of my branch.  ((*) Well,
> I didn't "lose" it in the sense of "it's gone forever", but I lost it
> in the sense of "it doesn't show up in git log anymore".)

That's the whole idea of git reset. If you want to see what the "lost" commit was, try git reflog; it's very likely at HEAD@{1}.

-- 
Cheers,
Ray Chuan
Matthieu Moy· Nov 22, 2010, 16:14 UTC · re: Patrick Doyle · lore

Re: OK, how should I have done this...

Patrick Doyle <wpdster@gmail.com> writes:
Show 31 quoted lines
> On Mon, Nov 22, 2010 at 8:34 AM, Matthieu Moy
> <Matthieu.Moy@grenoble-inp.fr> wrote:
>> Patrick Doyle <wpdster@gmail.com> writes:
>>
>>> I just checked in modifications to 1/2 dozen or so files in a single
>>> commit and pushed them to my server.
>>
>>> So now I want to figure out which modification(s) in which file(s)
>>> introduced the problem.
>>
>> 'didn't read all the details of your message, but the way I'd have
>> done this would be with stash --keep-index:
>>
>> (untested)
>>
>> git checkout the-one-that-works # staging area and tree checked out.
>> git reset the-one-that-doesnt   # just change the staging area
>> git add -p
>> # pick some commits
>> git stash --keep-index
>> # run some tests
>> # if test fail then
>>   # happy, "git diff --staged" tells you what.
>> # else
>>   git commit -m "first modification"
>>   git stash pop
>>   # goto the git add -p step.
>> # fi
>
> That looks kinda scary to me.  The last time I played with git-reset,
> I ended up losing(*) the commit at the head of my branch.

In general, you should think twice before doing this kind of surgery. But :

* The git checkout at the beginning brings you in detached HEAD state,
  so you're not going to damage the branches themselves. The
  intermediate commits you'll do will be unreachable unless you create
  a ref explicitely. So, "git checkout branch-name" will bring you
  back to your branch when you're done.
* Git has this great "reflog" thing, so even if you mess up your
  branch, it's still in the reflog.
* Hopefully, you're working on a local clone, and really important
  stuff have already been pushed to a safer place, so the very worst
  thing that can happen is to start over with a fresh clone.

In my proposal, *if* you end up with a set of small commit that you prefer over your initial big commit, you can chose to record it in history (either git update-ref, dangerous if you've already pushed anything, or git merge, to keep both the big commit and the small ones in the history).

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/
Junio C Hamano· Nov 23, 2010, 00:05 UTC · re: Patrick Doyle · lore

Re: OK, how should I have done this...

Patrick Doyle <wpdster@gmail.com> writes:
> But I _know_ that there must be a better way to do this.  What should
> I have done?

Depends on how you wanted to fix your history (we already know from your description what shape of tree you want to end up in).

If you want to pretend that you were perfect and never made mistakes in these three files you had to fix later, then history surgery like what Matthieu suggested would be necessary (I won't repeat how).

On the other hand, if you want to record what you did in the time order, then I would probably do this:

 $ git checkout master ; test ;# broken
 $ git checkout 5ccce3 ; test ;# ok
 $ git checkout master -- file1 ; test ;# ok
 $ git checkout master -- file2 ; test ;# ok
 $ git checkout master -- blah/file7 ; test ;# broken
 $ edit blah/file7 ; test ;# ok
 $ git reset --soft master
 $ git commit -a -m 'The change to file3 was borked on the other env' -e

and in this particular case, this would be what I would have done, as a separate "fix-up" commit will give me a place to describe why a solution different from the initial attempt, which was Ok on the original machine, was necessary.

 
Patrick Doyle· Nov 23, 2010, 00:17 UTC · re: Junio C Hamano · lore

Re: OK, how should I have done this...

On Mon, Nov 22, 2010 at 7:05 PM, Junio C Hamano <gitster@pobox.com> wrote:
Show 28 quoted lines
> Patrick Doyle <wpdster@gmail.com> writes:
>
>> But I _know_ that there must be a better way to do this.  What should
>> I have done?
>
> Depends on how you wanted to fix your history (we already know from your
> description what shape of tree you want to end up in).
>
> If you want to pretend that you were perfect and never made mistakes in
> these three files you had to fix later, then history surgery like what
> Matthieu suggested would be necessary (I won't repeat how).
>
> On the other hand, if you want to record what you did in the time order,
> then I would probably do this:
>
>  $ git checkout master ; test ;# broken
>  $ git checkout 5ccce3 ; test ;# ok
>  $ git checkout master -- file1 ; test ;# ok
>  $ git checkout master -- file2 ; test ;# ok
>  $ git checkout master -- blah/file7 ; test ;# broken
>  $ edit blah/file7 ; test ;# ok
>  $ git reset --soft master
>  $ git commit -a -m 'The change to file3 was borked on the other env' -e
>
> and in this particular case, this would be what I would have done, as a
> separate "fix-up" commit will give me a place to describe why a solution
> different from the initial attempt, which was Ok on the original machine,
> was necessary.

Thanks Junio, that's exactly what I was trying to do. I keep getting confused about checkout vs. reset. Both affect the index and the working copy. Both manipulate the ref pointer. I just can't keep straight when I should use reset. I understand using checkout to grab a particular version of the repository.

But your recipe is what I wanted to do. I just used "checkout" instead of "reset --soft".

Thanks again.
--wpd

← back to recent threads