Page MenuHomePhabricator

arc diff/export generate wrong GIT patch when file is deleted and then create a same name symbol link file.
Closed, DuplicatePublic

Description

Hi Guys:

I find a bug in Arcanist. I used arc diff to generate a revision, I found arc generate a wrong GIT patch, cause I cannot use arc patch to apply diff to local branch.

After a long time debug, I find that arc generate GIT patch is different than git diff does. there is one block comment in diff.c which belong to GIT source tree

3186         if (!pgm &&
3187             DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) &&
3188             (S_IFMT & one->mode) != (S_IFMT & two->mode)) {
3189                 /*
3190                  * a filepair that changes between file and symlink
3191                  * needs to be split into deletion and creation.
3192                  */
3193                 struct diff_filespec *null = alloc_filespec(two->path);
3194                 run_diff_cmd(NULL, name, other, attr_path,
3195                              one, null, &msg, o, p);
3196                 free(null);
3197                 strbuf_release(&msg);
3198
3199                 null = alloc_filespec(one->path);
3200                 run_diff_cmd(NULL, name, other, attr_path,
3201                              null, two, &msg, o, p);
3202                 free(null);
3203         }

this comment shows git treat file type change more carefully. if change between file and symlink, it will be split into two changes. but arc doesn't.

// file: src/parser/ArcanistBundle.php

  public function toGitPatch() {
    $eol = $this->getEOL('git');

    $result = array();
    $changes = $this->getChanges();
......
    foreach ($changes as $change) {
      $type = $change->getType();
      $file_type = $change->getFileType();
......
      $old_mode = idx($change->getOldProperties(), 'unix:filemode', '100644');
      $new_mode = idx($change->getNewProperties(), 'unix:filemode', '100644');
......
      if ($type == ArcanistDiffChangeType::TYPE_COPY_HERE ||
          $type == ArcanistDiffChangeType::TYPE_MOVE_HERE ||
          $type == ArcanistDiffChangeType::TYPE_COPY_AWAY ||
          $type == ArcanistDiffChangeType::TYPE_CHANGE) {
        if ($old_mode !== $new_mode) {
          $result[] = "old mode {$old_mode}".$eol;
          $result[] = "new mode {$new_mode}".$eol;
        }
      }

this code show arc just output old file mode and new file mode to patch file. for my case, it looks like this:

diff --git a/projects/lib/libprotobuf.so.7 b/projects/lib/libprotobuf.so.7
old mode 100755
new mode 120000
index 3f5f2a5be18a8fb65033b21a6777838475a98386..64f9ac68837117655ef3ced85f18c71c86d163b3
GIT binary patch
literal 20
bc$~}0Oe!eKFUe0TP17sR*E82M&@%u4QWOT-

literal 6789021
zc$|E_2|QHa|Hpr4ERD6X?-^?-TTvt$A|z|bR@tJEWNBAp$&!>MgcMO(Dv^{WiG)fa
zr6>`llq{u1$^Y$h&-}kL{{8;*csxI^_j%oO&pq2c_ukRm&k>Ui>xcvbM*py22H0H6
zU6Jj-G!^;#lD+=lJXA~vV}t)HVsiiGWyAjOkH+qWOp0NY|Nc9-ANyQDLq1KNNef-@
zWXl$eX+I*`&+IC`pV?J)ChbQ}p(_dPZSyYFn-#P^ljpzmd_9gDN>^62pDpai{{Pdy

And finally. arc patch will failed. cause arc patch use git apply to apply diff. git apply will check is that patch validate by the following code:

// file: builtin/apply.c
// function: check_patch()

3763         if (new_name && old_name) {
3764                 int same = !strcmp(old_name, new_name);
3765                 if (!patch->new_mode)
3766                         patch->new_mode = patch->old_mode;
3767                 if ((patch->old_mode ^ patch->new_mode) & S_IFMT) {
3768                         if (same)
3769                                 return error(_("new mode (%o) of %s does not "
3770                                                "match old mode (%o)"),
3771                                         patch->new_mode, new_name,
3772                                         patch->old_mode);
3773                         else
3774                                 return error(_("new mode (%o) of %s does not "
3775                                                "match old mode (%o) of %s"),
3776                                         patch->new_mode, new_name,
3777                                         patch->old_mode, old_name);
3778                 }
3779         }

So this bug is obviously now. the last thing is to change the code in src/parser/ArcanistBundle.php. BUT, I'm not a phper. I can read the php code just because it looks like C. PLS fix it, it has already blocked me long time. thanks.

Revisions and Commits