2018-04-19 17:58:19 +00:00
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
test_description="merge cases"
|
|
|
|
|
|
|
|
# The setup for all of them, pictorially, is:
|
|
|
|
#
|
|
|
|
# A
|
|
|
|
# o
|
|
|
|
# / \
|
|
|
|
# O o ?
|
|
|
|
# \ /
|
|
|
|
# o
|
|
|
|
# B
|
|
|
|
#
|
|
|
|
# To help make it easier to follow the flow of tests, they have been
|
|
|
|
# divided into sections and each test will start with a quick explanation
|
|
|
|
# of what commits O, A, and B contain.
|
|
|
|
#
|
|
|
|
# Notation:
|
|
|
|
# z/{b,c} means files z/b and z/c both exist
|
|
|
|
# x/d_1 means file x/d exists with content d1. (Purpose of the
|
|
|
|
# underscore notation is to differentiate different
|
|
|
|
# files that might be renamed into each other's paths.)
|
|
|
|
|
2024-05-27 11:47:18 +00:00
|
|
|
TEST_PASSES_SANITIZE_LEAK=true
|
2018-04-19 17:58:19 +00:00
|
|
|
. ./test-lib.sh
|
2020-10-26 17:01:36 +00:00
|
|
|
. "$TEST_DIRECTORY"/lib-merge.sh
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
###########################################################################
|
|
|
|
# SECTION 1: Cases involving no renames (one side has subset of changes of
|
|
|
|
# the other side)
|
|
|
|
###########################################################################
|
|
|
|
|
|
|
|
# Testcase 1a, Changes on A, subset of changes on B
|
|
|
|
# Commit O: b_1
|
|
|
|
# Commit A: b_2
|
|
|
|
# Commit B: b_3
|
|
|
|
# Expected: b_2
|
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_setup_1a () {
|
2022-08-26 03:49:19 +00:00
|
|
|
git init 1a_$1 &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
2019-10-22 21:22:51 +00:00
|
|
|
cd 1a_$1 &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
|
|
|
|
git add b &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "O" &&
|
|
|
|
|
|
|
|
git branch O &&
|
|
|
|
git branch A &&
|
|
|
|
git branch B &&
|
|
|
|
|
|
|
|
git checkout A &&
|
|
|
|
test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
|
|
|
|
git add b &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "A" &&
|
|
|
|
|
|
|
|
git checkout B &&
|
|
|
|
test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
|
|
|
|
git add b &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "B"
|
|
|
|
)
|
2019-10-22 21:22:51 +00:00
|
|
|
}
|
2018-04-19 17:58:19 +00:00
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_expect_success '1a-L: Modify(A)/Modify(B), change on B subset of A' '
|
|
|
|
test_setup_1a L &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
2019-10-22 21:22:51 +00:00
|
|
|
cd 1a_L &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
git checkout A^0 &&
|
|
|
|
|
t6022, t6046: fix flaky files-are-updated checks
Several tests wanted to verify that files were actually modified by a
merge, which it would do by checking that the mtime was updated. In
order to avoid problems with the merge completing so fast that the mtime
at the beginning and end of the operation was the same, these tests
would first set the mtime of a file to something "old". This "old"
value was usually determined as current system clock minus one second,
truncated to the nearest integer. Unfortunately, it appears the system
clock and filesystem clock are different and comparing across the two
runs into race problems resulting in flaky tests.
From https://stackoverflow.com/questions/14392975/timestamp-accuracy-on-ext4-sub-millsecond:
date will call the gettimeofday system call which will always return
the most accurate time available based on the cached kernel time,
adjusted by the CPU cycle time if available to give nanosecond
resolution. The timestamps stored in the file system however, are
only based on the cached kernel time. ie The time calculated at the
last timer interrupt.
and from https://apenwarr.ca/log/20181113:
Does mtime get set to >= the current time?
No, this depends on clock granularity. For example, gettimeofday()
can return times in microseconds on my system, but ext4 rounds
timestamps down to the previous ~10ms (but not exactly 10ms)
increment, with the surprising result that a newly-created file is
almost always created in the past:
$ python -c "
import os, time
t0 = time.time()
open('testfile', 'w').close()
print os.stat('testfile').st_mtime - t0
"
-0.00234484672546
So, instead of trying to compare across what are effectively two
different clocks, just avoid using the system clock. Any new updates to
files have to give an mtime at least as big as what is already in the
file, so we could define "old" as one second before the mtime found in
the file before the merge starts. But, to avoid problems with leap
seconds, ntp updates, filesystems that only provide two second
resolution, and other such weirdness, let's just pick an hour before the
mtime found in the file before the merge starts.
Also, clarify in one test where we check the mtime of different files
that it really was intentional. I totally forgot the reasons for that
and assumed it was a bug when asked.
Reported-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-13 20:03:02 +00:00
|
|
|
test-tool chmtime --get -3600 b >old-mtime &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
|
|
|
|
|
|
|
|
test_must_be_empty err &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
# Make sure b was NOT updated
|
|
|
|
test-tool chmtime --get b >new-mtime &&
|
|
|
|
test_cmp old-mtime new-mtime &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
git ls-files -s >index_files &&
|
|
|
|
test_line_count = 1 index_files &&
|
|
|
|
|
|
|
|
git rev-parse >actual HEAD:b &&
|
|
|
|
git rev-parse >expect A:b &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
git hash-object b >actual &&
|
|
|
|
git rev-parse A:b >expect &&
|
|
|
|
test_cmp expect actual
|
|
|
|
)
|
|
|
|
'
|
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_expect_success '1a-R: Modify(A)/Modify(B), change on B subset of A' '
|
|
|
|
test_setup_1a R &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
2019-10-22 21:22:51 +00:00
|
|
|
cd 1a_R &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
t6022, t6046: fix flaky files-are-updated checks
Several tests wanted to verify that files were actually modified by a
merge, which it would do by checking that the mtime was updated. In
order to avoid problems with the merge completing so fast that the mtime
at the beginning and end of the operation was the same, these tests
would first set the mtime of a file to something "old". This "old"
value was usually determined as current system clock minus one second,
truncated to the nearest integer. Unfortunately, it appears the system
clock and filesystem clock are different and comparing across the two
runs into race problems resulting in flaky tests.
From https://stackoverflow.com/questions/14392975/timestamp-accuracy-on-ext4-sub-millsecond:
date will call the gettimeofday system call which will always return
the most accurate time available based on the cached kernel time,
adjusted by the CPU cycle time if available to give nanosecond
resolution. The timestamps stored in the file system however, are
only based on the cached kernel time. ie The time calculated at the
last timer interrupt.
and from https://apenwarr.ca/log/20181113:
Does mtime get set to >= the current time?
No, this depends on clock granularity. For example, gettimeofday()
can return times in microseconds on my system, but ext4 rounds
timestamps down to the previous ~10ms (but not exactly 10ms)
increment, with the surprising result that a newly-created file is
almost always created in the past:
$ python -c "
import os, time
t0 = time.time()
open('testfile', 'w').close()
print os.stat('testfile').st_mtime - t0
"
-0.00234484672546
So, instead of trying to compare across what are effectively two
different clocks, just avoid using the system clock. Any new updates to
files have to give an mtime at least as big as what is already in the
file, so we could define "old" as one second before the mtime found in
the file before the merge starts. But, to avoid problems with leap
seconds, ntp updates, filesystems that only provide two second
resolution, and other such weirdness, let's just pick an hour before the
mtime found in the file before the merge starts.
Also, clarify in one test where we check the mtime of different files
that it really was intentional. I totally forgot the reasons for that
and assumed it was a bug when asked.
Reported-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-13 20:03:02 +00:00
|
|
|
test-tool chmtime --get -3600 b >old-mtime &&
|
2018-04-19 17:58:19 +00:00
|
|
|
GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
# Make sure b WAS updated
|
|
|
|
test-tool chmtime --get b >new-mtime &&
|
|
|
|
test $(cat old-mtime) -lt $(cat new-mtime) &&
|
|
|
|
|
2018-04-19 17:58:19 +00:00
|
|
|
test_must_be_empty err &&
|
|
|
|
|
|
|
|
git ls-files -s >index_files &&
|
|
|
|
test_line_count = 1 index_files &&
|
|
|
|
|
|
|
|
git rev-parse >actual HEAD:b &&
|
|
|
|
git rev-parse >expect A:b &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
git hash-object b >actual &&
|
|
|
|
git rev-parse A:b >expect &&
|
|
|
|
test_cmp expect actual
|
|
|
|
)
|
|
|
|
'
|
|
|
|
|
|
|
|
|
|
|
|
###########################################################################
|
|
|
|
# SECTION 2: Cases involving basic renames
|
|
|
|
###########################################################################
|
|
|
|
|
|
|
|
# Testcase 2a, Changes on A, rename on B
|
|
|
|
# Commit O: b_1
|
|
|
|
# Commit A: b_2
|
|
|
|
# Commit B: c_1
|
|
|
|
# Expected: c_2
|
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_setup_2a () {
|
2022-08-26 03:49:19 +00:00
|
|
|
git init 2a_$1 &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
2019-10-22 21:22:51 +00:00
|
|
|
cd 2a_$1 &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
test_seq 1 10 >b &&
|
|
|
|
git add b &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "O" &&
|
|
|
|
|
|
|
|
git branch O &&
|
|
|
|
git branch A &&
|
|
|
|
git branch B &&
|
|
|
|
|
|
|
|
git checkout A &&
|
|
|
|
test_seq 1 11 >b &&
|
|
|
|
git add b &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "A" &&
|
|
|
|
|
|
|
|
git checkout B &&
|
|
|
|
git mv b c &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "B"
|
|
|
|
)
|
2019-10-22 21:22:51 +00:00
|
|
|
}
|
2018-04-19 17:58:19 +00:00
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_expect_success '2a-L: Modify/rename, merge into modify side' '
|
|
|
|
test_setup_2a L &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
2019-10-22 21:22:51 +00:00
|
|
|
cd 2a_L &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
git checkout A^0 &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
test_path_is_missing c &&
|
2018-04-19 17:58:19 +00:00
|
|
|
GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
test_path_is_file c &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
git ls-files -s >index_files &&
|
|
|
|
test_line_count = 1 index_files &&
|
|
|
|
|
|
|
|
git rev-parse >actual HEAD:c &&
|
|
|
|
git rev-parse >expect A:b &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
git hash-object c >actual &&
|
|
|
|
git rev-parse A:b >expect &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
test_must_fail git rev-parse HEAD:b &&
|
|
|
|
test_path_is_missing b
|
|
|
|
)
|
|
|
|
'
|
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_expect_success '2a-R: Modify/rename, merge into rename side' '
|
|
|
|
test_setup_2a R &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
2019-10-22 21:22:51 +00:00
|
|
|
cd 2a_R &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
t6022, t6046: fix flaky files-are-updated checks
Several tests wanted to verify that files were actually modified by a
merge, which it would do by checking that the mtime was updated. In
order to avoid problems with the merge completing so fast that the mtime
at the beginning and end of the operation was the same, these tests
would first set the mtime of a file to something "old". This "old"
value was usually determined as current system clock minus one second,
truncated to the nearest integer. Unfortunately, it appears the system
clock and filesystem clock are different and comparing across the two
runs into race problems resulting in flaky tests.
From https://stackoverflow.com/questions/14392975/timestamp-accuracy-on-ext4-sub-millsecond:
date will call the gettimeofday system call which will always return
the most accurate time available based on the cached kernel time,
adjusted by the CPU cycle time if available to give nanosecond
resolution. The timestamps stored in the file system however, are
only based on the cached kernel time. ie The time calculated at the
last timer interrupt.
and from https://apenwarr.ca/log/20181113:
Does mtime get set to >= the current time?
No, this depends on clock granularity. For example, gettimeofday()
can return times in microseconds on my system, but ext4 rounds
timestamps down to the previous ~10ms (but not exactly 10ms)
increment, with the surprising result that a newly-created file is
almost always created in the past:
$ python -c "
import os, time
t0 = time.time()
open('testfile', 'w').close()
print os.stat('testfile').st_mtime - t0
"
-0.00234484672546
So, instead of trying to compare across what are effectively two
different clocks, just avoid using the system clock. Any new updates to
files have to give an mtime at least as big as what is already in the
file, so we could define "old" as one second before the mtime found in
the file before the merge starts. But, to avoid problems with leap
seconds, ntp updates, filesystems that only provide two second
resolution, and other such weirdness, let's just pick an hour before the
mtime found in the file before the merge starts.
Also, clarify in one test where we check the mtime of different files
that it really was intentional. I totally forgot the reasons for that
and assumed it was a bug when asked.
Reported-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-13 20:03:02 +00:00
|
|
|
test-tool chmtime --get -3600 c >old-mtime &&
|
2018-04-19 17:58:19 +00:00
|
|
|
GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
# Make sure c WAS updated
|
|
|
|
test-tool chmtime --get c >new-mtime &&
|
|
|
|
test $(cat old-mtime) -lt $(cat new-mtime) &&
|
|
|
|
|
2018-04-19 17:58:19 +00:00
|
|
|
test_must_be_empty err &&
|
|
|
|
|
|
|
|
git ls-files -s >index_files &&
|
|
|
|
test_line_count = 1 index_files &&
|
|
|
|
|
|
|
|
git rev-parse >actual HEAD:c &&
|
|
|
|
git rev-parse >expect A:b &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
git hash-object c >actual &&
|
|
|
|
git rev-parse A:b >expect &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
test_must_fail git rev-parse HEAD:b &&
|
|
|
|
test_path_is_missing b
|
|
|
|
)
|
|
|
|
'
|
|
|
|
|
|
|
|
# Testcase 2b, Changed and renamed on A, subset of changes on B
|
|
|
|
# Commit O: b_1
|
|
|
|
# Commit A: c_2
|
|
|
|
# Commit B: b_3
|
|
|
|
# Expected: c_2
|
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_setup_2b () {
|
2022-08-26 03:49:19 +00:00
|
|
|
git init 2b_$1 &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
2019-10-22 21:22:51 +00:00
|
|
|
cd 2b_$1 &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
|
|
|
|
git add b &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "O" &&
|
|
|
|
|
|
|
|
git branch O &&
|
|
|
|
git branch A &&
|
|
|
|
git branch B &&
|
|
|
|
|
|
|
|
git checkout A &&
|
|
|
|
test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
|
|
|
|
git add b &&
|
|
|
|
git mv b c &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "A" &&
|
|
|
|
|
|
|
|
git checkout B &&
|
|
|
|
test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
|
|
|
|
git add b &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "B"
|
|
|
|
)
|
2019-10-22 21:22:51 +00:00
|
|
|
}
|
2018-04-19 17:58:19 +00:00
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_expect_success '2b-L: Rename+Mod(A)/Mod(B), B mods subset of A' '
|
|
|
|
test_setup_2b L &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
2019-10-22 21:22:51 +00:00
|
|
|
cd 2b_L &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
git checkout A^0 &&
|
|
|
|
|
t6022, t6046: fix flaky files-are-updated checks
Several tests wanted to verify that files were actually modified by a
merge, which it would do by checking that the mtime was updated. In
order to avoid problems with the merge completing so fast that the mtime
at the beginning and end of the operation was the same, these tests
would first set the mtime of a file to something "old". This "old"
value was usually determined as current system clock minus one second,
truncated to the nearest integer. Unfortunately, it appears the system
clock and filesystem clock are different and comparing across the two
runs into race problems resulting in flaky tests.
From https://stackoverflow.com/questions/14392975/timestamp-accuracy-on-ext4-sub-millsecond:
date will call the gettimeofday system call which will always return
the most accurate time available based on the cached kernel time,
adjusted by the CPU cycle time if available to give nanosecond
resolution. The timestamps stored in the file system however, are
only based on the cached kernel time. ie The time calculated at the
last timer interrupt.
and from https://apenwarr.ca/log/20181113:
Does mtime get set to >= the current time?
No, this depends on clock granularity. For example, gettimeofday()
can return times in microseconds on my system, but ext4 rounds
timestamps down to the previous ~10ms (but not exactly 10ms)
increment, with the surprising result that a newly-created file is
almost always created in the past:
$ python -c "
import os, time
t0 = time.time()
open('testfile', 'w').close()
print os.stat('testfile').st_mtime - t0
"
-0.00234484672546
So, instead of trying to compare across what are effectively two
different clocks, just avoid using the system clock. Any new updates to
files have to give an mtime at least as big as what is already in the
file, so we could define "old" as one second before the mtime found in
the file before the merge starts. But, to avoid problems with leap
seconds, ntp updates, filesystems that only provide two second
resolution, and other such weirdness, let's just pick an hour before the
mtime found in the file before the merge starts.
Also, clarify in one test where we check the mtime of different files
that it really was intentional. I totally forgot the reasons for that
and assumed it was a bug when asked.
Reported-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-13 20:03:02 +00:00
|
|
|
test-tool chmtime --get -3600 c >old-mtime &&
|
2018-04-19 17:58:19 +00:00
|
|
|
GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
|
|
|
|
|
|
|
|
test_must_be_empty err &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
# Make sure c WAS updated
|
|
|
|
test-tool chmtime --get c >new-mtime &&
|
|
|
|
test_cmp old-mtime new-mtime &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
git ls-files -s >index_files &&
|
|
|
|
test_line_count = 1 index_files &&
|
|
|
|
|
|
|
|
git rev-parse >actual HEAD:c &&
|
|
|
|
git rev-parse >expect A:c &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
git hash-object c >actual &&
|
|
|
|
git rev-parse A:c >expect &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
test_must_fail git rev-parse HEAD:b &&
|
|
|
|
test_path_is_missing b
|
|
|
|
)
|
|
|
|
'
|
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_expect_success '2b-R: Rename+Mod(A)/Mod(B), B mods subset of A' '
|
|
|
|
test_setup_2b R &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
2019-10-22 21:22:51 +00:00
|
|
|
cd 2b_R &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
test_path_is_missing c &&
|
2018-04-19 17:58:19 +00:00
|
|
|
GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
# Make sure c now present (and thus was updated)
|
|
|
|
test_path_is_file c &&
|
|
|
|
|
2018-04-19 17:58:19 +00:00
|
|
|
test_must_be_empty err &&
|
|
|
|
|
|
|
|
git ls-files -s >index_files &&
|
|
|
|
test_line_count = 1 index_files &&
|
|
|
|
|
|
|
|
git rev-parse >actual HEAD:c &&
|
|
|
|
git rev-parse >expect A:c &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
git hash-object c >actual &&
|
|
|
|
git rev-parse A:c >expect &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
test_must_fail git rev-parse HEAD:b &&
|
|
|
|
test_path_is_missing b
|
|
|
|
)
|
|
|
|
'
|
|
|
|
|
|
|
|
# Testcase 2c, Changes on A, rename on B
|
|
|
|
# Commit O: b_1
|
|
|
|
# Commit A: b_2, c_3
|
|
|
|
# Commit B: c_1
|
|
|
|
# Expected: rename/add conflict c_2 vs c_3
|
|
|
|
#
|
|
|
|
# NOTE: Since A modified b_1->b_2, and B renamed b_1->c_1, the threeway
|
|
|
|
# merge of those files should result in c_2. We then should have a
|
|
|
|
# rename/add conflict between c_2 and c_3. However, if we note in
|
|
|
|
# merge_content() that A had the right contents (b_2 has same
|
|
|
|
# contents as c_2, just at a different name), and that A had the
|
|
|
|
# right path present (c_3 existed) and thus decides that it can
|
|
|
|
# skip the update, then we're in trouble. This test verifies we do
|
|
|
|
# not make that particular mistake.
|
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_setup_2c () {
|
2022-08-26 03:49:19 +00:00
|
|
|
git init 2c &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
|
|
|
cd 2c &&
|
|
|
|
|
|
|
|
test_seq 1 10 >b &&
|
|
|
|
git add b &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "O" &&
|
|
|
|
|
|
|
|
git branch O &&
|
|
|
|
git branch A &&
|
|
|
|
git branch B &&
|
|
|
|
|
|
|
|
git checkout A &&
|
|
|
|
test_seq 1 11 >b &&
|
|
|
|
echo whatever >c &&
|
|
|
|
git add b c &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "A" &&
|
|
|
|
|
|
|
|
git checkout B &&
|
|
|
|
git mv b c &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "B"
|
|
|
|
)
|
2019-10-22 21:22:51 +00:00
|
|
|
}
|
2018-04-19 17:58:19 +00:00
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_expect_success '2c: Modify b & add c VS rename b->c' '
|
|
|
|
test_setup_2c &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
|
|
|
cd 2c &&
|
|
|
|
|
|
|
|
git checkout A^0 &&
|
|
|
|
|
t6022, t6046: fix flaky files-are-updated checks
Several tests wanted to verify that files were actually modified by a
merge, which it would do by checking that the mtime was updated. In
order to avoid problems with the merge completing so fast that the mtime
at the beginning and end of the operation was the same, these tests
would first set the mtime of a file to something "old". This "old"
value was usually determined as current system clock minus one second,
truncated to the nearest integer. Unfortunately, it appears the system
clock and filesystem clock are different and comparing across the two
runs into race problems resulting in flaky tests.
From https://stackoverflow.com/questions/14392975/timestamp-accuracy-on-ext4-sub-millsecond:
date will call the gettimeofday system call which will always return
the most accurate time available based on the cached kernel time,
adjusted by the CPU cycle time if available to give nanosecond
resolution. The timestamps stored in the file system however, are
only based on the cached kernel time. ie The time calculated at the
last timer interrupt.
and from https://apenwarr.ca/log/20181113:
Does mtime get set to >= the current time?
No, this depends on clock granularity. For example, gettimeofday()
can return times in microseconds on my system, but ext4 rounds
timestamps down to the previous ~10ms (but not exactly 10ms)
increment, with the surprising result that a newly-created file is
almost always created in the past:
$ python -c "
import os, time
t0 = time.time()
open('testfile', 'w').close()
print os.stat('testfile').st_mtime - t0
"
-0.00234484672546
So, instead of trying to compare across what are effectively two
different clocks, just avoid using the system clock. Any new updates to
files have to give an mtime at least as big as what is already in the
file, so we could define "old" as one second before the mtime found in
the file before the merge starts. But, to avoid problems with leap
seconds, ntp updates, filesystems that only provide two second
resolution, and other such weirdness, let's just pick an hour before the
mtime found in the file before the merge starts.
Also, clarify in one test where we check the mtime of different files
that it really was intentional. I totally forgot the reasons for that
and assumed it was a bug when asked.
Reported-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-13 20:03:02 +00:00
|
|
|
test-tool chmtime --get -3600 c >old-mtime &&
|
2018-07-13 05:52:02 +00:00
|
|
|
GIT_MERGE_VERBOSITY=3 &&
|
|
|
|
export GIT_MERGE_VERBOSITY &&
|
|
|
|
test_must_fail git merge -s recursive B^0 >out 2>err &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep "CONFLICT (.*/add):" out &&
|
2020-02-27 00:14:23 +00:00
|
|
|
test_must_be_empty err &&
|
|
|
|
|
2023-01-14 18:49:46 +00:00
|
|
|
git ls-files -s >index_files &&
|
|
|
|
test_line_count = 2 index_files &&
|
|
|
|
|
|
|
|
# Ensure b was removed
|
|
|
|
test_path_is_missing b &&
|
|
|
|
|
|
|
|
# Make sure c WAS updated...
|
2020-02-27 00:14:23 +00:00
|
|
|
test-tool chmtime --get c >new-mtime &&
|
2023-01-14 18:49:46 +00:00
|
|
|
test $(cat old-mtime) -lt $(cat new-mtime) &&
|
|
|
|
|
|
|
|
# ...and has correct index entries and working tree contents
|
|
|
|
git rev-parse >actual :2:c :3:c &&
|
|
|
|
git rev-parse >expect A:c A:b &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
git cat-file -p A:b >>merge-me &&
|
|
|
|
git cat-file -p A:c >>merged &&
|
|
|
|
>empty &&
|
|
|
|
test_must_fail git merge-file \
|
|
|
|
-L "HEAD" \
|
|
|
|
-L "" \
|
|
|
|
-L "B^0" \
|
|
|
|
merged empty merge-me &&
|
|
|
|
test_cmp merged c
|
2018-04-19 17:58:19 +00:00
|
|
|
)
|
|
|
|
'
|
|
|
|
|
|
|
|
|
|
|
|
###########################################################################
|
|
|
|
# SECTION 3: Cases involving directory renames
|
|
|
|
#
|
|
|
|
# NOTE:
|
|
|
|
# Directory renames only apply when one side renames a directory, and the
|
|
|
|
# other side adds or renames a path into that directory. Applying the
|
|
|
|
# directory rename to that new path creates a new pathname that didn't
|
|
|
|
# exist on either side of history. Thus, it is impossible for the
|
|
|
|
# merge contents to already be at the right path, so all of these checks
|
|
|
|
# exist just to make sure that updates are not skipped.
|
|
|
|
###########################################################################
|
|
|
|
|
|
|
|
# Testcase 3a, Change + rename into dir foo on A, dir rename foo->bar on B
|
|
|
|
# Commit O: bq_1, foo/whatever
|
|
|
|
# Commit A: foo/{bq_2, whatever}
|
|
|
|
# Commit B: bq_1, bar/whatever
|
|
|
|
# Expected: bar/{bq_2, whatever}
|
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_setup_3a () {
|
2022-08-26 03:49:19 +00:00
|
|
|
git init 3a_$1 &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
2019-10-22 21:22:51 +00:00
|
|
|
cd 3a_$1 &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
mkdir foo &&
|
|
|
|
test_seq 1 10 >bq &&
|
|
|
|
test_write_lines a b c d e f g h i j k >foo/whatever &&
|
|
|
|
git add bq foo/whatever &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "O" &&
|
|
|
|
|
|
|
|
git branch O &&
|
|
|
|
git branch A &&
|
|
|
|
git branch B &&
|
|
|
|
|
|
|
|
git checkout A &&
|
|
|
|
test_seq 1 11 >bq &&
|
|
|
|
git add bq &&
|
|
|
|
git mv bq foo/ &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "A" &&
|
|
|
|
|
|
|
|
git checkout B &&
|
|
|
|
git mv foo/ bar/ &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "B"
|
|
|
|
)
|
2019-10-22 21:22:51 +00:00
|
|
|
}
|
2018-04-19 17:58:19 +00:00
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_expect_success '3a-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
|
|
|
|
test_setup_3a L &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
2019-10-22 21:22:51 +00:00
|
|
|
cd 3a_L &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
git checkout A^0 &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
test_path_is_missing bar/bq &&
|
merge-recursive: switch directory rename detection default
When all of x/a, x/b, and x/c have moved to z/a, z/b, and z/c on one
branch, there is a question about whether x/d added on a different
branch should remain at x/d or appear at z/d when the two branches are
merged. There are different possible viewpoints here:
A) The file was placed at x/d; it's unrelated to the other files in
x/ so it doesn't matter that all the files from x/ moved to z/ on
one branch; x/d should still remain at x/d.
B) x/d is related to the other files in x/, and x/ was renamed to z/;
therefore x/d should be moved to z/d.
Since there was no ability to detect directory renames prior to
git-2.18, users experienced (A) regardless of context. Choice (B) was
implemented in git-2.18, with no option to go back to (A), and has been
in use since. However, one user reported that the merge results did not
match their expectations, making the change of default problematic,
especially since there was no notice printed when directory rename
detection moved files.
Note that there is also a third possibility here:
C) There are different answers depending on the context and content
that cannot be determined by git, so this is a conflict. Use a
higher stage in the index to record the conflict and notify the
user of the potential issue instead of silently selecting a
resolution for them.
Add an option for users to specify their preference for whether to use
directory rename detection, and default to (C). Even when directory
rename detection is on, add notice messages about files moved into new
directories.
As a sidenote, x/d did not have to be a new file here; it could have
already existed at some other path and been renamed to x/d, with
directory rename detection just renaming it again to z/d. Thus, it's
not just new files, but also a modification to all rename types (normal
renames, rename/add, rename/delete, rename/rename(1to1),
rename/rename(1to2), and rename/rename(2to1)).
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-05 15:00:26 +00:00
|
|
|
GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
test_must_be_empty err &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
test_path_is_file bar/bq &&
|
|
|
|
|
2018-04-19 17:58:19 +00:00
|
|
|
git ls-files -s >index_files &&
|
|
|
|
test_line_count = 2 index_files &&
|
|
|
|
|
|
|
|
git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
|
|
|
|
git rev-parse >expect A:foo/bq A:foo/whatever &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
git hash-object bar/bq bar/whatever >actual &&
|
|
|
|
git rev-parse A:foo/bq A:foo/whatever >expect &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
|
2021-02-12 13:29:41 +00:00
|
|
|
test_path_is_missing bq &&
|
|
|
|
test_path_is_missing foo/bq &&
|
|
|
|
test_path_is_missing foo/whatever
|
2018-04-19 17:58:19 +00:00
|
|
|
)
|
|
|
|
'
|
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_expect_success '3a-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
|
|
|
|
test_setup_3a R &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
2019-10-22 21:22:51 +00:00
|
|
|
cd 3a_R &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
test_path_is_missing bar/bq &&
|
merge-recursive: switch directory rename detection default
When all of x/a, x/b, and x/c have moved to z/a, z/b, and z/c on one
branch, there is a question about whether x/d added on a different
branch should remain at x/d or appear at z/d when the two branches are
merged. There are different possible viewpoints here:
A) The file was placed at x/d; it's unrelated to the other files in
x/ so it doesn't matter that all the files from x/ moved to z/ on
one branch; x/d should still remain at x/d.
B) x/d is related to the other files in x/, and x/ was renamed to z/;
therefore x/d should be moved to z/d.
Since there was no ability to detect directory renames prior to
git-2.18, users experienced (A) regardless of context. Choice (B) was
implemented in git-2.18, with no option to go back to (A), and has been
in use since. However, one user reported that the merge results did not
match their expectations, making the change of default problematic,
especially since there was no notice printed when directory rename
detection moved files.
Note that there is also a third possibility here:
C) There are different answers depending on the context and content
that cannot be determined by git, so this is a conflict. Use a
higher stage in the index to record the conflict and notify the
user of the potential issue instead of silently selecting a
resolution for them.
Add an option for users to specify their preference for whether to use
directory rename detection, and default to (C). Even when directory
rename detection is on, add notice messages about files moved into new
directories.
As a sidenote, x/d did not have to be a new file here; it could have
already existed at some other path and been renamed to x/d, with
directory rename detection just renaming it again to z/d. Thus, it's
not just new files, but also a modification to all rename types (normal
renames, rename/add, rename/delete, rename/rename(1to1),
rename/rename(1to2), and rename/rename(2to1)).
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-05 15:00:26 +00:00
|
|
|
GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
test_must_be_empty err &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
test_path_is_file bar/bq &&
|
|
|
|
|
2018-04-19 17:58:19 +00:00
|
|
|
git ls-files -s >index_files &&
|
|
|
|
test_line_count = 2 index_files &&
|
|
|
|
|
|
|
|
git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
|
|
|
|
git rev-parse >expect A:foo/bq A:foo/whatever &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
git hash-object bar/bq bar/whatever >actual &&
|
|
|
|
git rev-parse A:foo/bq A:foo/whatever >expect &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
|
2021-02-12 13:29:41 +00:00
|
|
|
test_path_is_missing bq &&
|
|
|
|
test_path_is_missing foo/bq &&
|
|
|
|
test_path_is_missing foo/whatever
|
2018-04-19 17:58:19 +00:00
|
|
|
)
|
|
|
|
'
|
|
|
|
|
|
|
|
# Testcase 3b, rename into dir foo on A, dir rename foo->bar + change on B
|
|
|
|
# Commit O: bq_1, foo/whatever
|
|
|
|
# Commit A: foo/{bq_1, whatever}
|
|
|
|
# Commit B: bq_2, bar/whatever
|
|
|
|
# Expected: bar/{bq_2, whatever}
|
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_setup_3b () {
|
2022-08-26 03:49:19 +00:00
|
|
|
git init 3b_$1 &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
2019-10-22 21:22:51 +00:00
|
|
|
cd 3b_$1 &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
mkdir foo &&
|
|
|
|
test_seq 1 10 >bq &&
|
|
|
|
test_write_lines a b c d e f g h i j k >foo/whatever &&
|
|
|
|
git add bq foo/whatever &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "O" &&
|
|
|
|
|
|
|
|
git branch O &&
|
|
|
|
git branch A &&
|
|
|
|
git branch B &&
|
|
|
|
|
|
|
|
git checkout A &&
|
|
|
|
git mv bq foo/ &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "A" &&
|
|
|
|
|
|
|
|
git checkout B &&
|
|
|
|
test_seq 1 11 >bq &&
|
|
|
|
git add bq &&
|
|
|
|
git mv foo/ bar/ &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "B"
|
|
|
|
)
|
2019-10-22 21:22:51 +00:00
|
|
|
}
|
2018-04-19 17:58:19 +00:00
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_expect_success '3b-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
|
|
|
|
test_setup_3b L &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
2019-10-22 21:22:51 +00:00
|
|
|
cd 3b_L &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
git checkout A^0 &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
test_path_is_missing bar/bq &&
|
merge-recursive: switch directory rename detection default
When all of x/a, x/b, and x/c have moved to z/a, z/b, and z/c on one
branch, there is a question about whether x/d added on a different
branch should remain at x/d or appear at z/d when the two branches are
merged. There are different possible viewpoints here:
A) The file was placed at x/d; it's unrelated to the other files in
x/ so it doesn't matter that all the files from x/ moved to z/ on
one branch; x/d should still remain at x/d.
B) x/d is related to the other files in x/, and x/ was renamed to z/;
therefore x/d should be moved to z/d.
Since there was no ability to detect directory renames prior to
git-2.18, users experienced (A) regardless of context. Choice (B) was
implemented in git-2.18, with no option to go back to (A), and has been
in use since. However, one user reported that the merge results did not
match their expectations, making the change of default problematic,
especially since there was no notice printed when directory rename
detection moved files.
Note that there is also a third possibility here:
C) There are different answers depending on the context and content
that cannot be determined by git, so this is a conflict. Use a
higher stage in the index to record the conflict and notify the
user of the potential issue instead of silently selecting a
resolution for them.
Add an option for users to specify their preference for whether to use
directory rename detection, and default to (C). Even when directory
rename detection is on, add notice messages about files moved into new
directories.
As a sidenote, x/d did not have to be a new file here; it could have
already existed at some other path and been renamed to x/d, with
directory rename detection just renaming it again to z/d. Thus, it's
not just new files, but also a modification to all rename types (normal
renames, rename/add, rename/delete, rename/rename(1to1),
rename/rename(1to2), and rename/rename(2to1)).
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-05 15:00:26 +00:00
|
|
|
GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
test_must_be_empty err &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
test_path_is_file bar/bq &&
|
|
|
|
|
2018-04-19 17:58:19 +00:00
|
|
|
git ls-files -s >index_files &&
|
|
|
|
test_line_count = 2 index_files &&
|
|
|
|
|
|
|
|
git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
|
|
|
|
git rev-parse >expect B:bq A:foo/whatever &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
git hash-object bar/bq bar/whatever >actual &&
|
|
|
|
git rev-parse B:bq A:foo/whatever >expect &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
|
2021-02-12 13:29:41 +00:00
|
|
|
test_path_is_missing bq &&
|
|
|
|
test_path_is_missing foo/bq &&
|
|
|
|
test_path_is_missing foo/whatever
|
2018-04-19 17:58:19 +00:00
|
|
|
)
|
|
|
|
'
|
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_expect_success '3b-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
|
|
|
|
test_setup_3b R &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
2019-10-22 21:22:51 +00:00
|
|
|
cd 3b_R &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
git checkout B^0 &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
test_path_is_missing bar/bq &&
|
merge-recursive: switch directory rename detection default
When all of x/a, x/b, and x/c have moved to z/a, z/b, and z/c on one
branch, there is a question about whether x/d added on a different
branch should remain at x/d or appear at z/d when the two branches are
merged. There are different possible viewpoints here:
A) The file was placed at x/d; it's unrelated to the other files in
x/ so it doesn't matter that all the files from x/ moved to z/ on
one branch; x/d should still remain at x/d.
B) x/d is related to the other files in x/, and x/ was renamed to z/;
therefore x/d should be moved to z/d.
Since there was no ability to detect directory renames prior to
git-2.18, users experienced (A) regardless of context. Choice (B) was
implemented in git-2.18, with no option to go back to (A), and has been
in use since. However, one user reported that the merge results did not
match their expectations, making the change of default problematic,
especially since there was no notice printed when directory rename
detection moved files.
Note that there is also a third possibility here:
C) There are different answers depending on the context and content
that cannot be determined by git, so this is a conflict. Use a
higher stage in the index to record the conflict and notify the
user of the potential issue instead of silently selecting a
resolution for them.
Add an option for users to specify their preference for whether to use
directory rename detection, and default to (C). Even when directory
rename detection is on, add notice messages about files moved into new
directories.
As a sidenote, x/d did not have to be a new file here; it could have
already existed at some other path and been renamed to x/d, with
directory rename detection just renaming it again to z/d. Thus, it's
not just new files, but also a modification to all rename types (normal
renames, rename/add, rename/delete, rename/rename(1to1),
rename/rename(1to2), and rename/rename(2to1)).
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-04-05 15:00:26 +00:00
|
|
|
GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
test_must_be_empty err &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
test_path_is_file bar/bq &&
|
|
|
|
|
2018-04-19 17:58:19 +00:00
|
|
|
git ls-files -s >index_files &&
|
|
|
|
test_line_count = 2 index_files &&
|
|
|
|
|
|
|
|
git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
|
|
|
|
git rev-parse >expect B:bq A:foo/whatever &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
git hash-object bar/bq bar/whatever >actual &&
|
|
|
|
git rev-parse B:bq A:foo/whatever >expect &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
|
2021-02-12 13:29:41 +00:00
|
|
|
test_path_is_missing bq &&
|
|
|
|
test_path_is_missing foo/bq &&
|
|
|
|
test_path_is_missing foo/whatever
|
2018-04-19 17:58:19 +00:00
|
|
|
)
|
|
|
|
'
|
|
|
|
|
|
|
|
###########################################################################
|
|
|
|
# SECTION 4: Cases involving dirty changes
|
|
|
|
###########################################################################
|
|
|
|
|
|
|
|
# Testcase 4a, Changed on A, subset of changes on B, locally modified
|
|
|
|
# Commit O: b_1
|
|
|
|
# Commit A: b_2
|
|
|
|
# Commit B: b_3
|
|
|
|
# Working copy: b_4
|
|
|
|
# Expected: b_2 for merge, b_4 in working copy
|
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_setup_4a () {
|
2022-08-26 03:49:19 +00:00
|
|
|
git init 4a &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
|
|
|
cd 4a &&
|
|
|
|
|
|
|
|
test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
|
|
|
|
git add b &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "O" &&
|
|
|
|
|
|
|
|
git branch O &&
|
|
|
|
git branch A &&
|
|
|
|
git branch B &&
|
|
|
|
|
|
|
|
git checkout A &&
|
|
|
|
test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
|
|
|
|
git add b &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "A" &&
|
|
|
|
|
|
|
|
git checkout B &&
|
|
|
|
test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
|
|
|
|
git add b &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "B"
|
|
|
|
)
|
2019-10-22 21:22:51 +00:00
|
|
|
}
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
# NOTE: For as long as we continue using unpack_trees() without index_only
|
2020-07-28 20:45:38 +00:00
|
|
|
# set to true, it will error out on a case like this claiming that the locally
|
2018-04-19 17:58:19 +00:00
|
|
|
# modified file would be overwritten by the merge. Getting this testcase
|
|
|
|
# correct requires doing the merge in-memory first, then realizing that no
|
|
|
|
# updates to the file are necessary, and thus that we can just leave the path
|
|
|
|
# alone.
|
2020-10-26 17:01:36 +00:00
|
|
|
test_expect_merge_algorithm failure success '4a: Change on A, change on B subset of A, dirty mods present' '
|
2019-10-22 21:22:51 +00:00
|
|
|
test_setup_4a &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
|
|
|
cd 4a &&
|
|
|
|
|
|
|
|
git checkout A^0 &&
|
|
|
|
echo "File rewritten" >b &&
|
|
|
|
|
t6022, t6046: fix flaky files-are-updated checks
Several tests wanted to verify that files were actually modified by a
merge, which it would do by checking that the mtime was updated. In
order to avoid problems with the merge completing so fast that the mtime
at the beginning and end of the operation was the same, these tests
would first set the mtime of a file to something "old". This "old"
value was usually determined as current system clock minus one second,
truncated to the nearest integer. Unfortunately, it appears the system
clock and filesystem clock are different and comparing across the two
runs into race problems resulting in flaky tests.
From https://stackoverflow.com/questions/14392975/timestamp-accuracy-on-ext4-sub-millsecond:
date will call the gettimeofday system call which will always return
the most accurate time available based on the cached kernel time,
adjusted by the CPU cycle time if available to give nanosecond
resolution. The timestamps stored in the file system however, are
only based on the cached kernel time. ie The time calculated at the
last timer interrupt.
and from https://apenwarr.ca/log/20181113:
Does mtime get set to >= the current time?
No, this depends on clock granularity. For example, gettimeofday()
can return times in microseconds on my system, but ext4 rounds
timestamps down to the previous ~10ms (but not exactly 10ms)
increment, with the surprising result that a newly-created file is
almost always created in the past:
$ python -c "
import os, time
t0 = time.time()
open('testfile', 'w').close()
print os.stat('testfile').st_mtime - t0
"
-0.00234484672546
So, instead of trying to compare across what are effectively two
different clocks, just avoid using the system clock. Any new updates to
files have to give an mtime at least as big as what is already in the
file, so we could define "old" as one second before the mtime found in
the file before the merge starts. But, to avoid problems with leap
seconds, ntp updates, filesystems that only provide two second
resolution, and other such weirdness, let's just pick an hour before the
mtime found in the file before the merge starts.
Also, clarify in one test where we check the mtime of different files
that it really was intentional. I totally forgot the reasons for that
and assumed it was a bug when asked.
Reported-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-13 20:03:02 +00:00
|
|
|
test-tool chmtime --get -3600 b >old-mtime &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
|
|
|
|
|
|
|
|
test_must_be_empty err &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
# Make sure b was NOT updated
|
|
|
|
test-tool chmtime --get b >new-mtime &&
|
|
|
|
test_cmp old-mtime new-mtime &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
git ls-files -s >index_files &&
|
|
|
|
test_line_count = 1 index_files &&
|
|
|
|
|
|
|
|
git rev-parse >actual :0:b &&
|
|
|
|
git rev-parse >expect A:b &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
git hash-object b >actual &&
|
|
|
|
echo "File rewritten" | git hash-object --stdin >expect &&
|
|
|
|
test_cmp expect actual
|
|
|
|
)
|
|
|
|
'
|
|
|
|
|
|
|
|
# Testcase 4b, Changed+renamed on A, subset of changes on B, locally modified
|
|
|
|
# Commit O: b_1
|
|
|
|
# Commit A: c_2
|
|
|
|
# Commit B: b_3
|
|
|
|
# Working copy: c_4
|
|
|
|
# Expected: c_2
|
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_setup_4b () {
|
2022-08-26 03:49:19 +00:00
|
|
|
git init 4b &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
|
|
|
cd 4b &&
|
|
|
|
|
|
|
|
test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
|
|
|
|
git add b &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "O" &&
|
|
|
|
|
|
|
|
git branch O &&
|
|
|
|
git branch A &&
|
|
|
|
git branch B &&
|
|
|
|
|
|
|
|
git checkout A &&
|
|
|
|
test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
|
|
|
|
git add b &&
|
|
|
|
git mv b c &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "A" &&
|
|
|
|
|
|
|
|
git checkout B &&
|
|
|
|
test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
|
|
|
|
git add b &&
|
|
|
|
test_tick &&
|
|
|
|
git commit -m "B"
|
|
|
|
)
|
2019-10-22 21:22:51 +00:00
|
|
|
}
|
2018-04-19 17:58:19 +00:00
|
|
|
|
2019-10-22 21:22:51 +00:00
|
|
|
test_expect_success '4b: Rename+Mod(A)/Mod(B), change on B subset of A, dirty mods present' '
|
|
|
|
test_setup_4b &&
|
2018-04-19 17:58:19 +00:00
|
|
|
(
|
|
|
|
cd 4b &&
|
|
|
|
|
|
|
|
git checkout A^0 &&
|
|
|
|
echo "File rewritten" >c &&
|
|
|
|
|
t6022, t6046: fix flaky files-are-updated checks
Several tests wanted to verify that files were actually modified by a
merge, which it would do by checking that the mtime was updated. In
order to avoid problems with the merge completing so fast that the mtime
at the beginning and end of the operation was the same, these tests
would first set the mtime of a file to something "old". This "old"
value was usually determined as current system clock minus one second,
truncated to the nearest integer. Unfortunately, it appears the system
clock and filesystem clock are different and comparing across the two
runs into race problems resulting in flaky tests.
From https://stackoverflow.com/questions/14392975/timestamp-accuracy-on-ext4-sub-millsecond:
date will call the gettimeofday system call which will always return
the most accurate time available based on the cached kernel time,
adjusted by the CPU cycle time if available to give nanosecond
resolution. The timestamps stored in the file system however, are
only based on the cached kernel time. ie The time calculated at the
last timer interrupt.
and from https://apenwarr.ca/log/20181113:
Does mtime get set to >= the current time?
No, this depends on clock granularity. For example, gettimeofday()
can return times in microseconds on my system, but ext4 rounds
timestamps down to the previous ~10ms (but not exactly 10ms)
increment, with the surprising result that a newly-created file is
almost always created in the past:
$ python -c "
import os, time
t0 = time.time()
open('testfile', 'w').close()
print os.stat('testfile').st_mtime - t0
"
-0.00234484672546
So, instead of trying to compare across what are effectively two
different clocks, just avoid using the system clock. Any new updates to
files have to give an mtime at least as big as what is already in the
file, so we could define "old" as one second before the mtime found in
the file before the merge starts. But, to avoid problems with leap
seconds, ntp updates, filesystems that only provide two second
resolution, and other such weirdness, let's just pick an hour before the
mtime found in the file before the merge starts.
Also, clarify in one test where we check the mtime of different files
that it really was intentional. I totally forgot the reasons for that
and assumed it was a bug when asked.
Reported-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-13 20:03:02 +00:00
|
|
|
test-tool chmtime --get -3600 c >old-mtime &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
|
|
|
|
|
|
|
|
test_must_be_empty err &&
|
|
|
|
|
2020-02-27 00:14:23 +00:00
|
|
|
# Make sure c was NOT updated
|
|
|
|
test-tool chmtime --get c >new-mtime &&
|
|
|
|
test_cmp old-mtime new-mtime &&
|
2018-04-19 17:58:19 +00:00
|
|
|
|
|
|
|
git ls-files -s >index_files &&
|
|
|
|
test_line_count = 1 index_files &&
|
|
|
|
|
|
|
|
git rev-parse >actual :0:c &&
|
|
|
|
git rev-parse >expect A:c &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
git hash-object c >actual &&
|
|
|
|
echo "File rewritten" | git hash-object --stdin >expect &&
|
|
|
|
test_cmp expect actual &&
|
|
|
|
|
|
|
|
test_must_fail git rev-parse HEAD:b &&
|
|
|
|
test_path_is_missing b
|
|
|
|
)
|
|
|
|
'
|
|
|
|
|
|
|
|
test_done
|