[git] Git copy file preserving history

All you have to do is:

  1. move the file to two different locations,
  2. merge the two commits that do the above, and
  3. move one copy back to the original location.

You will be able to see historical attributions (using git blame) and full history of changes (using git log) for both files.

Suppose you want to create a copy of file foo called bar. In that case the workflow you'd use would look like this:

git mv foo bar
git commit

SAVED=`git rev-parse HEAD`
git reset --hard HEAD^
git mv foo copy
git commit

git merge $SAVED     # This will generate conflicts
git commit -a        # Trivially resolved like this

git mv copy foo
git commit

Why this works

After you execute the above commands, you end up with a revision history that looks like this:

( revision history )            ( files )

    ORIG_HEAD                      foo
     /     \                      /   \
SAVED       ALTERNATE          bar     copy
     \     /                      \   /
      MERGED                     bar,copy
        |                           |
     RESTORED                    bar,foo

When you ask Git about the history of foo, it will:

  1. detect the rename from copy between MERGED and RESTORED,
  2. detect that copy came from the ALTERNATE parent of MERGED, and
  3. detect the rename from foo between ORIG_HEAD and ALTERNATE.

From there it will dig into the history of foo.

When you ask Git about the history of bar, it will:

  1. notice no change between MERGED and RESTORED,
  2. detect that bar came from the SAVED parent of MERGED, and
  3. detect the rename from foo between ORIG_HEAD and SAVED.

From there it will dig into the history of foo.

It's that simple. :)

You just need to force Git into a merge situation where you can accept two traceable copies of the file(s), and we do this with a parallel move of the original (which we soon revert).

Examples related to git

Does the target directory for a git clone have to match the repo name? Git fatal: protocol 'https' is not supported Git is not working after macOS Update (xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools) git clone: Authentication failed for <URL> destination path already exists and is not an empty directory SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443 GitLab remote: HTTP Basic: Access denied and fatal Authentication How can I switch to another branch in git? VS 2017 Git Local Commit DB.lock error on every commit How to remove an unpushed outgoing commit in Visual Studio?

Examples related to file

Gradle - Move a folder from ABC to XYZ Difference between opening a file in binary vs text Angular: How to download a file from HttpClient? Python error message io.UnsupportedOperation: not readable java.io.FileNotFoundException: class path resource cannot be opened because it does not exist Writing JSON object to a JSON file with fs.writeFileSync How to read/write files in .Net Core? How to write to a CSV line by line? Writing a dictionary to a text file? What are the pros and cons of parquet format compared to other formats?

Examples related to copy

Copying files to a container with Docker Compose Copy filtered data to another sheet using VBA Copy output of a JavaScript variable to the clipboard Dockerfile copy keep subdirectory structure Using a batch to copy from network drive to C: or D: drive Copying HTML code in Google Chrome's inspect element What is the difference between `sorted(list)` vs `list.sort()`? How to export all data from table to an insertable sql format? scp copy directory to another server with private key auth How to properly -filter multiple strings in a PowerShell copy script

Examples related to filenames

Rename multiple files in a folder, add a prefix (Windows) How to loop over files in directory and change path and add suffix to filename Why do I get a SyntaxError for a Unicode escape in my file path? Git copy file preserving history A html space is showing as %2520 instead of %20 How do I get the file name from a String containing the Absolute file path? DateTime.ToString() format that can be used in a filename or extension? Get only filename from url in php without any variable values which exist in the url Obtaining only the filename when using OpenFileDialog property "FileName" Build the full path filename in Python