RichiH / vcsh

config manager based on Git

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Handle existing files when cloning

RichiH opened this issue · comments

User expectation seems to be that existing files are left intact when cloning a repo.

This is counter-intuitive to me, but with a proper warning, it's not an issue so why not?

  • Fetch
  • Detect files
  • Move existing to tempfile
  • Finish clone
  • Move tempfile to existing

Are you proposing to do this by default or via an option? If default then we will need an option to do the opposite as well.

What I'd like:

  • Fetch
  • If file(s) already exists {
    • display conflicting file(s)
    • ask user to cancel, overwrite or create a backup
      • cancel -> exit
      • overwrite -> rm file
      • backup -> (mv file file.backup) }
  • Finish clone

Alternatively, keeping the default behavior but introducing a new flag e.g. vcsh clone repo --overwrite would be almost as good.

I can't see why one would like to finish with Move tempfile to existing, because that would overwrite the dotfile you just cloned.
As I said before in #190, maybe I am misinterpreting the full vcsh/mr concept...

Or vcsh clone [--backup|--overwrite] $url $repo, which could overwrite the files or back them up to ~/.config/vcsh/repos.d/$repo.git/bakcups

What is verdict on this issue ? It would be really helpful for bootstrapping a new environment

As a former yadm user I really like the idea of using git stash to handle conflicts with existing files. This way, cloning always succeeds and you can easily review / merge any differences between the local version and the cloned version of a file with the full power of git. This might be integrated to the core functionality of vcsh, but it can also be achieved with a pre-merge hook:

#!/bin/bash
# vim: set ft=sh:

REMOTE_BRANCH=$(git branch -a)
# unfortunately VCSH_BRANCH is not exported by vcsh
VCSH_BRANCH=${REMOTE_BRANCH#*remotes/origin/}
git reset --mixed origin/${VCSH_BRANCH}
git stash && git ls-tree -r --name-only origin/${VCSH_BRANCH} | xargs rm
rm ${GIT_DIR}/index ${GIT_DIR}/refs/heads/${VCSH_BRANCH}

Be careful, it seems to work but is not tested very well. It will delete your pre-existing files after they have been stashed. After vcsh clone you can show the differences:

vcsh reponame stash show -p

You can restore the local files with

vcsh reponame stash pop

I honestly can't believe this is still low priority after all these years! When I set up my repositories with vcsh, I thought cloning my dotfiles into a new system would be as simple as running vcsh $repo clone ..., since newly created users will most likely always have simple .bashrc and .profile which were copied from /etc/skel/. [--backup|--overwrite] is really essential.

@teresaejunior I agree this should have been dealt with years ago. In the mean time you might review my solution using hooks that handles exactly this situation. The tricky thing with setting up a new system is that you need these hooks in place before cloning anything, and the hooks themselves are in my repos. To deal with the catch 22, I use a bootstrap script that downloads the hooks before cloning any vcsh repos. It also takes care of getting SSH keys in place to clone other vcsh repositories, but that is out of scope for this issue report.

Thanks, @alerque! Since I don't need multiple repositories, I've moved at least temporarily to yadm.

I too am using a hook-based solution but unlike @alerque I move the existing files to a backup directory and leave them there; my common use case is to replace existing files with the ones I track with vcsh.

Anyway, however this is handled, It would be good to have VCSH_BRANCH available in the hooks called by the clone command, as @PiQuer remarked.

commented

@ao2 mind sharing that hook with me?

@ao2 mind sharing that hook with me?

@soulofmischief I have something like this in hooks-available/backup-existing-files.sh:

#!/bin/sh

set -e

BACKUP_DIR="vcsh-backup/${VCSH_REPO_NAME}-$(date "+%F-%R")"

git ls-tree --name-only origin/master | \
while read -r object; 
do
  if [ -e "$object" ];
  then
    echo "The path '${object}' already exists, moving the existing copy to '${BACKUP_DIR}'."
    [ -d "$BACKUP_DIR" ] || mkdir -p "$BACKUP_DIR"
    mv "$object" "$BACKUP_DIR"
  fi
done

unset BACKUP_DIR

And I link it to hooks-enabled/pre-merge.00-backup-existing-files.sh.

It's still rough so I didn't commit to my public repo.

For the record, this is the hook I implemented to move the clobbering file out of the way by simply renaming the file in place: https://gitlab.com/brlin/brlin-os-customizations/-/blob/6dfc7742/files/vcsh-hooks/pre-merge-10-unclobber.sh