commit - 4135d7d058f245363e836faa15dbedbd91bd1334
commit + 40dde666c0e7cae797b8652b1f4368e52c2c7b13
blob - 152352cad8daa30cc23016c559df4f22a087bd74
blob + 7e5ee06994a5158bc937ce8307bd19f51d7e0ef5
--- lib/diff.c
+++ lib/diff.c
if (outfile) {
char *modestr1 = NULL, *modestr2 = NULL;
+ int modebits;
if (mode1 && mode1 != mode2) {
+ if (S_ISLNK(mode1))
+ modebits = S_IFLNK;
+ else
+ modebits = (S_IRWXU | S_IRWXG | S_IRWXO);
if (asprintf(&modestr1, " (mode %o)",
- mode1 & (S_IRWXU | S_IRWXG | S_IRWXO)) == -1) {
+ mode1 & modebits) == -1) {
err = got_error_from_errno("asprintf");
goto done;
}
}
if (mode2 && mode1 != mode2) {
+ if (S_ISLNK(mode2))
+ modebits = S_IFLNK;
+ else
+ modebits = (S_IRWXU | S_IRWXG | S_IRWXO);
if (asprintf(&modestr2, " (mode %o)",
- mode2 & (S_IRWXU | S_IRWXG | S_IRWXO)) == -1) {
+ mode2 & modebits) == -1) {
err = got_error_from_errno("asprintf");
goto done;
}
if (!id_match)
return diff_modified_tree(&te1->id, &te2->id,
label1, label2, repo, cb, cb_arg, diff_content);
- } else if (S_ISREG(te1->mode) && S_ISREG(te2->mode)) {
+ } else if ((S_ISREG(te1->mode) || S_ISLNK(te1->mode)) &&
+ (S_ISREG(te2->mode) || S_ISLNK(te2->mode))) {
if (!id_match ||
- (te1->mode & S_IXUSR) != (te2->mode & S_IXUSR)) {
+ ((te1->mode & (S_IFLNK | S_IXUSR))) !=
+ (te2->mode & (S_IFLNK | S_IXUSR))) {
if (diff_content)
return diff_modified_blob(&te1->id, &te2->id,
label1, label2, te1->mode, te2->mode,
blob - cfc0d4b524be60277183c28685d392dbde650020
blob + eaff0579c403d60f90fdc01f50fde183091286a2
--- lib/object.c
+++ lib/object.c
*/
if (S_ISDIR(mode))
return mode & S_IFDIR;
+
+ /*
+ * For symlinks, the only relevant bit is the IFLNK bit.
+ * This allows us to detect paths changing from a symlinks
+ * to a file or directory and vice versa.
+ */
+ if (S_ISLNK(mode))
+ return mode & S_IFLNK;
/* For files, the only change we care about is the executable bit. */
return mode & S_IXUSR;
blob - 649ab258d4c149e3942f5f2da369992a8dd44f69
blob + dbc39580319a7e28e9adc23ded3e53d643d3d6e0
--- regress/cmdline/diff.sh
+++ regress/cmdline/diff.sh
echo 'blob - /dev/null' >> $testroot/stdout.expected
echo 'file + zeta.link' >> $testroot/stdout.expected
echo '--- zeta.link' >> $testroot/stdout.expected
+ echo '+++ zeta.link' >> $testroot/stdout.expected
+ echo '@@ -0,0 +1 @@' >> $testroot/stdout.expected
+ echo '+epsilon/zeta' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
+function test_diff_symlinks_in_repo {
+ local testroot=`test_init diff_symlinks_in_repo`
+
+ (cd $testroot/repo && ln -s alpha alpha.link)
+ (cd $testroot/repo && ln -s epsilon epsilon.link)
+ (cd $testroot/repo && ln -s /etc/passwd passwd.link)
+ (cd $testroot/repo && ln -s ../beta epsilon/beta.link)
+ (cd $testroot/repo && ln -s nonexistent nonexistent.link)
+ (cd $testroot/repo && ln -s .got/foo dotgotfoo.link)
+ (cd $testroot/repo && git add .)
+ git_commit $testroot/repo -m "add symlinks"
+ local commit_id1=`git_show_head $testroot/repo`
+
+ (cd $testroot/repo && ln -sf beta alpha.link)
+ (cd $testroot/repo && ln -sfh gamma epsilon.link)
+ (cd $testroot/repo && ln -sf ../gamma/delta epsilon/beta.link)
+ (cd $testroot/repo && ln -sf .got/bar $testroot/repo/dotgotfoo.link)
+ (cd $testroot/repo && git rm -q nonexistent.link)
+ (cd $testroot/repo && ln -sf epsilon/zeta zeta.link)
+ (cd $testroot/repo && git add .)
+ git_commit $testroot/repo -m "change symlinks"
+ local commit_id2=`git_show_head $testroot/repo`
+
+ got diff -r $testroot/repo $commit_id1 $commit_id2 > $testroot/stdout
+
+ echo "diff $commit_id1 $commit_id2" > $testroot/stdout.expected
+ echo -n 'blob - ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -c $commit_id1 -i | \
+ grep 'alpha.link@ -> alpha$' | \
+ cut -d' ' -f 1 >> $testroot/stdout.expected
+ echo -n 'blob + ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -c $commit_id2 -i | \
+ grep 'alpha.link@ -> beta$' | \
+ cut -d' ' -f 1 >> $testroot/stdout.expected
+ echo '--- alpha.link' >> $testroot/stdout.expected
+ echo '+++ alpha.link' >> $testroot/stdout.expected
+ echo '@@ -1 +1 @@' >> $testroot/stdout.expected
+ echo '-alpha' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo '+beta' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo -n 'blob - ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -c $commit_id1 -i | \
+ grep 'dotgotfoo.link@ -> .got/foo$' | \
+ cut -d' ' -f 1 >> $testroot/stdout.expected
+ echo -n 'blob + ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -c $commit_id2 -i | \
+ grep 'dotgotfoo.link@ -> .got/bar$' | \
+ cut -d' ' -f 1 >> $testroot/stdout.expected
+ echo '--- dotgotfoo.link' >> $testroot/stdout.expected
+ echo '+++ dotgotfoo.link' >> $testroot/stdout.expected
+ echo '@@ -1 +1 @@' >> $testroot/stdout.expected
+ echo '-.got/foo' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo '+.got/bar' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo -n 'blob - ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -c $commit_id1 -i epsilon | \
+ grep 'beta.link@ -> ../beta$' | \
+ cut -d' ' -f 1 >> $testroot/stdout.expected
+ echo -n 'blob + ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -c $commit_id2 -i epsilon | \
+ grep 'beta.link@ -> ../gamma/delta$' | \
+ cut -d' ' -f 1 >> $testroot/stdout.expected
+ echo '--- epsilon/beta.link' >> $testroot/stdout.expected
+ echo '+++ epsilon/beta.link' >> $testroot/stdout.expected
+ echo '@@ -1 +1 @@' >> $testroot/stdout.expected
+ echo '-../beta' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo '+../gamma/delta' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo -n 'blob - ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -c $commit_id1 -i | \
+ grep 'epsilon.link@ -> epsilon$' | \
+ cut -d' ' -f 1 >> $testroot/stdout.expected
+ echo -n 'blob + ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -c $commit_id2 -i | \
+ grep 'epsilon.link@ -> gamma$' | \
+ cut -d' ' -f 1 >> $testroot/stdout.expected
+ echo '--- epsilon.link' >> $testroot/stdout.expected
+ echo '+++ epsilon.link' >> $testroot/stdout.expected
+ echo '@@ -1 +1 @@' >> $testroot/stdout.expected
+ echo '-epsilon' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo '+gamma' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo -n 'blob - ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -c $commit_id1 -i | \
+ grep 'nonexistent.link@ -> nonexistent$' | \
+ cut -d' ' -f 1 | sed -e 's/$/ (mode 120000)/' \
+ >> $testroot/stdout.expected
+ echo 'blob + /dev/null' >> $testroot/stdout.expected
+ echo '--- nonexistent.link' >> $testroot/stdout.expected
+ echo '+++ /dev/null' >> $testroot/stdout.expected
+ echo '@@ -1 +0,0 @@' >> $testroot/stdout.expected
+ echo '-nonexistent' >> $testroot/stdout.expected
+ echo '\ No newline at end of file' >> $testroot/stdout.expected
+ echo 'blob - /dev/null' >> $testroot/stdout.expected
+ echo -n 'blob + ' >> $testroot/stdout.expected
+ got tree -r $testroot/repo -c $commit_id2 -i | \
+ grep 'zeta.link@ -> epsilon/zeta$' | \
+ cut -d' ' -f 1 | sed -e 's/$/ (mode 120000)/' \
+ >> $testroot/stdout.expected
+ echo '--- /dev/null' >> $testroot/stdout.expected
echo '+++ zeta.link' >> $testroot/stdout.expected
echo '@@ -0,0 +1 @@' >> $testroot/stdout.expected
echo '+epsilon/zeta' >> $testroot/stdout.expected
run_test test_diff_ignore_whitespace
run_test test_diff_submodule_of_same_repo
run_test test_diff_symlinks_in_work_tree
+run_test test_diff_symlinks_in_repo