Is it possible to move/rename files in Git and maintain their history?

前端 未结 14 2466
梦如初夏
梦如初夏 2020-11-22 04:42

I would like to rename/move a project subtree in Git moving it from

/project/xyz

to

/components/xyz

If I

14条回答
  •  半阙折子戏
    2020-11-22 05:37

    I would like to rename/move a project subtree in Git moving it from

    /project/xyz
    

    to

    /components/xyz

    If I use a plain git mv project components, then all the commit history for the xyz project gets lost.

    No (8 years later, Git 2.19, Q3 2018), because Git will detect the directory rename, and this is now better documented.

    See commit b00bf1c, commit 1634688, commit 0661e49, commit 4d34dff, commit 983f464, commit c840e1a, commit 9929430 (27 Jun 2018), and commit d4e8062, commit 5dacd4a (25 Jun 2018) by Elijah Newren (newren).
    (Merged by Junio C Hamano -- gitster -- in commit 0ce5a69, 24 Jul 2018)

    That is now explained in Documentation/technical/directory-rename-detection.txt:

    Example:

    When all of x/a, x/b and x/c have moved to z/a, z/b and z/c, it is likely that x/d added in the meantime would also want to move to z/d by taking the hint that the entire directory 'x' moved to 'z'.

    But they are many other cases, like:

    one side of history renames x -> z, and the other renames some file to x/e, causing the need for the merge to do a transitive rename.

    To simplify directory rename detection, those rules are enforced by Git:

    a couple basic rules limit when directory rename detection applies:

    1. If a given directory still exists on both sides of a merge, we do not consider it to have been renamed.
    2. If a subset of to-be-renamed files have a file or directory in the way (or would be in the way of each other), "turn off" the directory rename for those specific sub-paths and report the conflict to the user.
    3. If the other side of history did a directory rename to a path that your side of history renamed away, then ignore that particular rename from the other side of history for any implicit directory renames (but warn the user).

    You can see a lot of tests in t/t6043-merge-rename-directories.sh, which also point out that:

    • a) If renames split a directory into two or more others, the directory with the most renames, "wins".
    • b) Avoid directory-rename-detection for a path, if that path is the source of a rename on either side of a merge.
    • c) Only apply implicit directory renames to directories if the other side of history is the one doing the renaming.

提交回复
热议问题