git add -p (interactive patch) and edit mode gives a "corrupt patch at line XX" error
Asked Answered
L

1

6

I'm addind my change to a commit with git add -p, now I'd like to use the manual hunk edit mode.

I simply have this hunk:

# Manual hunk edit mode -- see bottom for a quick guide
@@ -46,6 +46,7 @@ function signIn(email, password) {
             }
         })
         .catch((error) => {
+            console.log(error);
             ToastAndroid.show(translations.translations.error_occurred, ToastAndroid.SHORT);
             that.setState({isLoading: false});
         });
# ---
# To remove '-' lines, make them ' ' lines (context).
# To remove '+' lines, delete them.
# Lines starting with # will be removed.

If I delete completely the line added (with console.log) then save and quit the editor, I get this error:

error: corrupt patch at line 12

I have totally no idea of what I'm doing wrong.

Lazes answered 14/8, 2018 at 15:52 Comment(6)
The only change the patch hunk makes is to add that one line. If you take it out, the patch becomes a directive to change the file by making no change to the file, which is not sensible. The error message here is kind of silly but the action you need is simply "skip this one".Closet
Ok thanks, so if there was an other line added that I didn't touch, I wouldn't have any error? And I don't want to skip this one but I want to cancel the change. Do I have to skip the change and checkout after? (I hope that here is a faster way to achieve this.)Lazes
Yes, if there were still some other change the modified patch should apply. Note that what you are doing is, in fact, editing the copy of the file that is in the index. There are three copies of each file at all times. The two obvious ones are the committed version in the current commit—you cannot change this one!—and the easy-to-see-and-edit one in your work-tree. You can edit that one in your favorite editor at any time. But there is a third copy, stored in what Git calls the index or the staging-area or the cache (three names for the same thing). [continued]Closet
The index copy starts out matching the committed file. If you run git add <filename>, Git simply copies the work-tree version into the index, so now the index copy matches the work-tree version. These are the two most common situations: matches HEAD or matches work-tree. (If HEAD and work-tree copies match, the index copy can and usually does match both.) What git add -p is for is to take whatever's different between work-tree copy and index copy, and add some of that difference to the index copy. This leaves the work-tree version alone! It only patches the index copy.Closet
Thanks for all these explications, you can post the first response in order to me to accept it.Lazes
OK. BTW I goofed up the description of git reset -p, so I'll delete that comment.Closet
C
5

[note: comments turned into answer - the top section is all you need, the rest is just explication]

The only change the patch hunk makes is to add that one line. If you take out the added line, the patch becomes a directive to change the file by making no change to the file, which is not very sensible. The error message here is kind of silly, but the action you need is simply "skip this one".

Lots of details, read only if interesting

Note that there are, at all times while you're working on your next commit to make, three of what I call active copies of each file. Well, more precisely, there are up to three such copies. The first one is whatever you committed previously, or had inside the commit that you got when you ran git checkout. This copy, being stored inside a commit, is fundamentally read-only: you cannot change it, as it's part of that particular commit. But you can access it whenever you like. For instance, given a README.txt file you can run:

git show HEAD:README.txt

to view it. Internally, this file is stored in a special Git-only format (zlib-deflated and perhaps even further compressed)—non-Git programs in general cannot read this copy of the file.

There's also a copy of that same file in your work-tree, where you can work on it. This copy is stored in its ordinary computer format, so that you can read it. Your editor—atom or emacs or sublime or vim or whatever it is you use—can read and write the file. Your compiler, if you compile programs, can read and write it, and so on. You need not do anything special with the file, as it's just like any other file. Oddly, Git almost doesn't care about this copy of README.txt—Git has to be kind of hands-off, since anything can change it!

But there's a third copy of README.txt too, and that's the one that is in what Git calls, variously, the index, or the staging area, or the cache. (Which name Git uses depends on which Git documentation you're looking at.) This third copy, which you can see with git show :README.txt, is in the special Git-only format, but unlike the copy in a commit, you can overwrite this one. The usual way that you overwrite this one is with git add, which simply copies the work-tree file into the index.

Hence, the index :README.txt starts out matching the HEAD:README.txt file. If you change the work-tree copy, the HEAD and index versions still match. If you then git add README.txt, that overwrites the index copy from the work-tree copy, and now HEAD:README.txt and README.txt no longer match, but :README.txt does match README.txt.

This is where git add -p comes in: if the index copy and the work-tree copy of some file are different, you can have Git come up with a patch—a set of hunks, each of which says to add and/or remove some line or lines—that, if applied, would change the index version to match the work-tree version. If Git were to follow all the instructions in the patch, that would change the index copy of the file to match the work-tree copy, just like git add would do.

But now Git has you go through that patch, one patch-hunk at a time, and:

  • tell Git to apply it as is; or
  • tell Git to skip it entirely; or even
  • fiddle with the change instructions so as to partially apply the patch.

When you choose to apply a particular patch-hunk (perhaps after editing it), Git extracts the index version of the file, applies that set of instructions, and goes on to look at the next one. If you skip it, Git just goes on to the next one.

Note that there is a companion to git add -p: running git reset -p README.txt tells Git that it should compare HEAD:README.txt and :README.txt (HEAD and index versions), and prepare a patch that would, if followed to the letter, change the index copy so that it matches the HEAD copy again. Then Git goes through the same process as for git add -p.


Last, let's take a quick look at git status. This does a lot of useful things, but the one where it tells you about changes staged for commit and changes not staged for commit consists of running, in essence, two git diff commands. The first one is:

  • What's different in HEAD vs the index?

For every file that is exactly the same here, Git is just silent about that. But if HEAD:README.txt and :README.txt are different, Git tells you that there is something staged for commit in README.txt.

Having listed all of those files, Git runs a second diff, this time to find out:

  • What's different in the index vs the work-tree?

Here, any file that's different, Git tells you that there is something not staged for commit. That's because you could run git add on that file, to copy it into the index.

If you were to run git commit right now, Git would make the new commit from whatever is in the index right now, so HEAD-vs-index tells you: these files would be different, in this new commit, from what's in the current commit. Meanwhile index-vs-work-tree tells you: these files could be different, but won't be unless you git add them.

This second diff is also the step that discovers any untracked files. An untracked file is, quite simply, a file that's in the work-tree, but not in the index. If such a file is ignored, Git shuts up about it. If the untracked file is not ignored, Git tells you that it is untracked. Note that a file that is in the index is by definition tracked, so Git never even checks for an ignore directive.

This fact—about new / untracked files—is why there are up to three copies of each file. If you create a new file, it's not in the HEAD commit at all. It's also untracked until you git add the file to copy it into the index. So you start out with one copy, in the work-tree only; then you have two, in the index and work-tree. Then you make a new commit, which becomes the current (HEAD) commit, and only then are there three copies of that new file.

Closet answered 16/8, 2018 at 15:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.