5

A colleague made a git commit after changing permissions on the project's files (he wasn't expecting them to be commited).

Now all our images are "corrupted" unreadable, but we don't understand how, and what to do.

Here is what git show edd703783a8802284fb975e9f354394541f1bad5 displays:

diff --git a/public/bootstrap/img/glyphicons-halflings-white.png b/public/bootstrap/img/glyphicons-halflings-white.png
index 3bf6484..c016d6b 100644
Binary files a/public/bootstrap/img/glyphicons-halflings-white.png and b/public/bootstrap/img/glyphicons-halflings-white.png differ

What does it mean?

We tried removing and re-commiting the images but the problem remains. As soon as we switch/reswitch on the branch, the images are corrupted.

I even tried to git revert the commit, but it puts all the image files in an updated state and stops with the following error:

error: 'commit' is not possible because you have unmerged files.
hint: Fix them up in the work tree,
hint: and then use 'git add/rm <file>' as
hint: appropriate to mark resolution and make a commit,
hint: or use 'git commit -a'.
fatal: Exiting because of an unresolved conflict.

Now I can't revert it, and the commit has been pushed a few days ago (and deployed to dev environment), so I can't rebase or something similar.

Matthieu Napoli
  • 48,448
  • 45
  • 173
  • 261

1 Answers1

7
diff --git a/public/bootstrap/img/glyphicons-halflings-white.png b/public/bootstrap/img/glyphicons-halflings-white.png
index 3bf6484..c016d6b 100644
Binary files a/public/bootstrap/img/glyphicons-halflings-white.png and b/public/bootstrap/img/glyphicons-halflings-white.png differ

This simply means that glyphicons-halflings-white.png was altered in that commit, but the contents are binary and are not suitable for display in a terminal. As a result, it omits any actual diff to avoid corrupting your terminal (the terminal interprets some codes, so you don't want to stream raw data to it).

The next bit is more interesting:

error: 'commit' is not possible because you have unmerged files.
hint: Fix them up in the work tree,
hint: and then use 'git add/rm <file>' as
hint: appropriate to mark resolution and make a commit,
hint: or use 'git commit -a'.
fatal: Exiting because of an unresolved conflict.

This means you attempted a merge and the file had conflicts. This happens because the version the change was based on is not the same as the version in the tip of the branch you're merging into. Graphically, it would look like this

                       C
         .-------------*------------.
        /                            \
*------*---------------*--------------+
A      B               D              E

So, let's say you had a feature branch that updated these icons (commit C) that was based on commit B. Then someone else landed a change on master that altered the same file, say commit D. Now when you attempt to merge, commit C and D are conflicting because they touched the same binary file. Git doesn't understand binary formats and so doesn't know how to merge them together. You, as the user, need to resolve the conflict and then add and commit the result. That means you need to examine all three versions: the one based on commit B (the merge base), the one based on commit C (MERGE_HEAD/your version), and the one based on commit D (HEAD/version on master). You can see each of these versions by doing this:

git show :1:path/to/file.ext > file.merge-base.ext    # The merge base (commit B)
git show :2:path/to/file.ext > file.HEAD.ext          # The version on the branch you're merging into (commit D)
git show :3:path/to/file.ext > file.MERGE_HEAD.ext    # The version on your branch (commit C)

The commands for getting at these different version is documented in the git merge man page. For a little more information on the staging syntax, you can look at the Specifying Revisions section of the gitrevisions man page.

You can try restoring the original versions before that commit. It would look like:

git show edd703783a8802284fb975e9f354394541f1bad5~1:public/bootstrap/img/glyphicons-halflings-white.png > public/bootstrap/img/glyphicons-halflings-white.png
git commit -M "Revert the last set of changes made to icons." public/bootstrap/img/glyphicons-halflings-white.png

when run from the top of your tree. You can also choose to keep your version with:

git checkout --ours  # Keeps the version on master (commit D, the :2: version)

Or,

git checkout --theirs  # Keeps the version from your branch (commit C, the :3: version)

You then need to add the file and commit to resolve the merge.

Finally, if you don't already have a line like this in your .gitattributes file, you may want to consider it:

*.png    binary

This means to treat binary files as binary. Git won't attempt to merge the file contents. Normally git does binary detection by looking for a NUL character in the first 100 bytes (IIRC). I don't remember the PNG format, but perhaps it's possible that there isn't guaranteed to be one in the first 100 bytes, so git may attempt to merge the contents of the file and insert conflict markers. That would corrupt the image in a way that it can't be viewed by image programs or the browser, and I suspect it's what happened to you. The above line in your .gitattributes file will make sure that git doesn't insert conflict markers, and it will avoid trying to merge uncommitted changes between branches to .png files.

Eric
  • 18,512
  • 4
  • 29
  • 34
John Szakmeister
  • 44,691
  • 9
  • 89
  • 79
  • Thanks for fixing the typos @eric! – John Szakmeister Jul 09 '13 at 15:42
  • No problem. Really great, detailed answer. – Eric Jul 09 '13 at 15:44
  • `This means you attempted a merge and the file had conflicts` > I didn't attempted a merge. This was the result of the `git revert` command. There are no branches at stake, everything is happening on a single branch. So thanks for the detailed answer but I guess (if I read correctly) that it doesn't apply to my problem? – Matthieu Napoli Jul 09 '13 at 18:23
  • I'm guessing that the `git revert` does a merge, and that this merge poses problems... I'll try the `.gitattributes` configuration for binary files – Matthieu Napoli Jul 09 '13 at 18:26
  • `git revert` does do a 3-way merge under the hood, so this still applies. – John Szakmeister Jul 09 '13 at 18:41
  • @jszakmeister ok, but I don't understand where the merge conflict is (between what), and how I can fix it. – Matthieu Napoli Jul 10 '13 at 07:45
  • @jszakmeister wooow I managed to resolve the problem by restoring the files to the version before the problematic commit. Thanks for suggesting that in your answer – Matthieu Napoli Jul 10 '13 at 07:46
  • @MatthieuNapoli `git status` should tell you that there are `unmerged paths` when there's a conflict. In your case it's possible that the file got committed with conflict markers in it, and then simply reverting the commit wasn't enough, which is why I suggested restoring the correct version of the file. But great job! Glad you got it sorted out! – John Szakmeister Jul 10 '13 at 08:13
  • AHHHHH how have i never ran into this before. Adding new images removed the CR's in my PNGs..... – Ascherer Feb 07 '17 at 08:03