commit 68c7693588c1316ee15664810fb8b0f06b912e1f from: Stefan Sperling date: Tue Feb 19 12:20:39 2019 UTC update cached timestamps of files left unmodified after a merge commit - 3cbbd752fbb743b19cc6954d6256fed51c1eaf30 commit + 68c7693588c1316ee15664810fb8b0f06b912e1f blob - 4eccffd610b224983a5ebcaf1cdc065830d8c882 blob + 43324d9d2a975fe0fb3fd9bab3662cfaa9da691e --- lib/worktree.c +++ lib/worktree.c @@ -598,6 +598,96 @@ add_dir_on_disk(struct got_worktree *worktree, const c done: free(abspath); + return err; +} + +static const struct got_error * +check_file_contents_equal(int *same, FILE *f1, FILE *f2) +{ + const struct got_error *err = NULL; + uint8_t fbuf1[8192]; + uint8_t fbuf2[8192]; + size_t flen1 = 0, flen2 = 0; + + *same = 1; + + while (1) { + flen1 = fread(fbuf1, 1, sizeof(fbuf1), f1); + if (flen1 == 0 && ferror(f1)) { + err = got_error_from_errno(); + break; + } + flen2 = fread(fbuf2, 1, sizeof(fbuf2), f2); + if (flen2 == 0 && ferror(f2)) { + err = got_error_from_errno(); + break; + } + if (flen1 == 0) { + if (flen2 != 0) + *same = 0; + break; + } else if (flen2 == 0) { + if (flen1 != 0) + *same = 0; + break; + } else if (flen1 == flen2) { + if (memcmp(fbuf1, fbuf2, flen2) != 0) { + *same = 0; + break; + } + } else { + *same = 0; + break; + } + } + + return err; +} + +static const struct got_error * +check_files_equal(int *same, const char *f1_path, const char *f2_path) +{ + const struct got_error *err = NULL; + struct stat sb; + size_t size1, size2; + FILE *f1 = NULL, *f2 = NULL; + + *same = 1; + + if (lstat(f1_path, &sb) != 0) { + err = got_error_from_errno(); + goto done; + } + size1 = sb.st_size; + + if (lstat(f2_path, &sb) != 0) { + err = got_error_from_errno(); + goto done; + } + size2 = sb.st_size; + + if (size1 != size2) { + *same = 0; + return NULL; + } + + f1 = fopen(f1_path, "r"); + if (f1 == NULL) + return got_error_from_errno(); + + f2 = fopen(f2_path, "r"); + if (f2 == NULL) { + err = got_error_from_errno(); + goto done; + } + + err = check_file_contents_equal(same, f1, f2); +done: + if (f1 && fclose(f1) != 0 && err == NULL) + err = got_error_from_errno(); + if (f2 && fclose(f2) != 0 && err == NULL) + err = got_error_from_errno(); + return err; } @@ -622,7 +712,7 @@ merge_blob(struct got_worktree *worktree, struct got_f struct got_object_id id2; char *id_str = NULL; char *label1 = NULL; - int overlapcnt = 0; + int overlapcnt = 0, update_timestamps = 0; char *parent; parent = dirname(ondisk_path); @@ -689,6 +779,14 @@ merge_blob(struct got_worktree *worktree, struct got_f if (fsync(merged_fd) != 0) { err = got_error_from_errno(); goto done; + } + + /* Check if a clean merge has subsumed all local changes. */ + if (overlapcnt == 0) { + err = check_files_equal(&update_timestamps, blob1_path, + merged_path); + if (err) + goto done; } if (rename(merged_path, ondisk_path) != 0) { @@ -701,7 +799,7 @@ merge_blob(struct got_worktree *worktree, struct got_f * the status walk would treat them as unmodified files again. */ err = got_fileindex_entry_update(ie, ondisk_path, - blob1->id.sha1, worktree->base_commit_id->sha1, 0); + blob1->id.sha1, worktree->base_commit_id->sha1, update_timestamps); done: if (merged_fd != -1 && close(merged_fd) != 0 && err == NULL) err = got_error_from_errno();