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.