On Sun, Jun 30, 2019 at 12:28 PM Johannes Sixt <j6t@xxxxxxxx> wrote: > > Am 30.06.19 um 15:05 schrieb Lars Schneider: > >> On Jun 24, 2019, at 11:58 AM, Jeff King <peff@xxxxxxxx> wrote: > >> You'd have to split the renames into separate delete/adds, since they > >> can have a circular dependency. E.g. renaming "foo" to "bar" and "bar" > >> to "foo", you must remove "foo" and "bar" both, and then add them back > >> in. > > > > @peff: Can you give me a hint how one would perform this circular > > dependency in a single commit? I try to write a test case for this. > > git mv Makefile foo > git mv COPYING Makefile > git mv foo COPYING > git diff -B HEAD > > -- Hannes Interestingly, fast-export has special code to handle cases like this; possibly due to the understanding of how all filemodify/filedelete/filerename commands take effect immediately (see below for more on that). If I make the above changes in git.git and commit them, then: $ git diff --name-status -B HEAD~1 HEAD R100 Makefile COPYING R100 COPYING Makefile BUT: $ git fast-export -B -M --no-data HEAD~2..HEAD | tail -n 10 commit refs/heads/master mark :7 author Elijah Newren <newren@xxxxxxxxx> 1562000065 -0600 committer Elijah Newren <newren@xxxxxxxxx> 1562000065 -0600 data 8 Testing from :6 R COPYING Makefile M 100644 8a7e2353520ddd7e0c8074d2b32d0441d97c1597 COPYING I.e. fast-export breaks the rename and translates it into a modify instead. This comes from here: case DIFF_STATUS_COPIED: case DIFF_STATUS_RENAMED: /* * If a change in the file corresponding to ospec->path * has been observed, we cannot trust its contents * because the diff is calculated based on the prior * contents, not the current contents. So, declare a * copy or rename only if there was no change observed. */ if (!string_list_has_string(changed, ospec->path)) { <snipped code for handling rename/copy> } /* fallthrough */ case DIFF_STATUS_TYPE_CHANGED: case DIFF_STATUS_MODIFIED: case DIFF_STATUS_ADDED: There is a question of whether fast-import should try to handle different exporters that aren't as careful; e.g. if one gets a stream like: commit refs/heads/master mark :4 author Me My <self@xxxxxxx> 110000000 -0700 committer Me My <self@xxxxxxx> 110000000 -0700 data 11 correction R letters numbers R numbers letters Should git-fast-import attempt to divine the user's intent to swap these two files (though it's not clear if that is the intent; see below), or would that violate the documented behavior: A filerename command takes effect immediately. Once the source location has been renamed to the destination any future commands applied to the source location will create new files there and not impact the destination of the rename. (I'm pretty sure Shawn would have said the latter; see e.g. https://public-inbox.org/git/20100706193455.GA19476@xxxxxxxxxxx/ and the follow-ups.) I think the view of "immediately taking effect" implies that this is a rename of 'letters' to 'numbers' which deletes 'numbers', and that the subsequent entry just renames the file back, making it an expensive almost no-op; almost because it has the side-effect of deleting the original 'numbers' file. This is certainly what fast-import does right now. Elijah