0

In the couple of the commits I need to pull there are a couple of deletions. Those files belong to some basic project files that shouldn't be present in git repository (that was our mistake in the first place, yeah). So I am afraid that the deletion of that files might cause some malfunctioning and I don't want to spend time fixing it.

I am looking for something like

git rm --cached

That deletes file from the remote repo but leaves in local

And I need something like

    git pull --cached

that won't delete local files but will remove them from tracked files

phd
  • 82,685
  • 13
  • 120
  • 165
anneteka
  • 33
  • 1
  • 7
  • So you have a file which you've removed from the repo but kept locally? And someone else has removed the file so when you pull git wants to delete the file? – evolutionxbox Jun 18 '19 at 15:22
  • @evolutionbox someone else has removed the file and I want to keep it and move from tracked to untracked – anneteka Jun 18 '19 at 15:29
  • If someone else has removed it from the repo then it will be untracked. Try moving the file elsewhere outside the repo, pull, and then put it back? – evolutionxbox Jun 18 '19 at 15:30
  • Why don't you make a backup of the deleted files, pull the changes and copy the files back (if necessary) – dan1st Jun 18 '19 at 15:37

2 Answers2

2

There is no simple way to do that — git pull will delete the removed files anyway. You can restore deleted files from the previous commit(s). Providing the commit that removes the files is the last commit in the branch:

git pull
git checkout @~ -- `git diff --diff-filter=D --name-only @~`
git reset -- `git diff --diff-filter=D --name-only @~`

This restores deleted files from the commit before the last. git reset is required to remove the files from the index (cache): git checkout puts them there.

phd
  • 82,685
  • 13
  • 120
  • 165
  • can you explain the args in the last 2 commands? I ran it, and didn't seem to do anything but did give a msg about 'detached HEAD' state. – Reed Jones Jan 02 '23 at 20:08
  • 1
    @ReedJones `git diff --diff-filter=D --name-only @~` lists deleted (`--diff-filter=D`) file names (`--name-only`) since the previous commit (`@~`). `git checkout @~ -- list_of_files` checks out the files from the previous commit, put them into the current directory and add to the index. `git reset -- list_of_files` resets the files i.e. removes the files from the index to avoid committing them. – phd Jan 02 '23 at 20:27
  • @ReedJones Detached `HEAD` means `HEAD` points to a commit, not a branch; it could be a result of a wrong `git checkout` command, for example `git checkout @~` without files checks out the previous commit instead of checking out files from the previous commit. To fix detached `HEAD` state do `git checkout master` (or whatever branch you want). – phd Jan 02 '23 at 20:28
  • Ok gotcha, yeah I was confused about this @~ syntax, get checkout branch worked – Reed Jones Jan 02 '23 at 22:27
0

I have an update to the answer from @phd on how to do this. Thought I'd share since it took me hours of troubleshooting to do what I was trying to accomplish and it could be helpful to other people that come across this.

I had a situation where I needed to delete a LOT of previously tracked files from the remote repo but wanted to keep those files locally for any developers that had already checked out the version of the repo where those files were tracked. What made this worse is that these files were in multiple directories, subdirectories and a few individual files in the root directory.

The main issue was that the commit where the files were deleted was NOT the last commit made to the repo. It was a few commits back.

This solution lets you use any commit to do the same thing so you aren't just limited to the last commit. This answer combines a some blog posts and other Stackoverflow answers

  1. Pull from the latest version of the branch (e.g. git pull origin master)
  2. Git checkout the commit right before all of the files were removed from git (e.g. commit_hash_right_before_files_were_deleted)
  3. Get the difference between the list of files in the current commit vs the list of files that were deleted in the commit where all the files were deleted (e.g git log --diff-filter D --pretty="oneline" --name-only --format= -l 0 commit_hash_right_before_files_were_deleted..commit_hash_where_where_files_were_deleted)
  4. Convert that list into the sed command to remove empty lines (e.g. sed '/^$/d' Got that from here: https://waylonwalker.com/git-find-deleted-files/#git-reflog-diff-filter)
  5. Pipe that list to the Zip command to zip all of those deleted files up into zip file (e.g. sed '/^$/d' | zip deleted-files.zip -@ . The sed command removes blank empty lines from the output. Got that from here https://superuser.com/a/1228717/1247351 )
  6. Switch back to the branch (e.g. git checkout master)
  7. Unzip the deleted files zip file (e.g. unzip deleted-files.zip)
  8. Reset the list of files to remove it from the local index to avoid committing them.

Full code:

git pull origin master
git checkout commit_hash_right_before_files_were_deleted
git log --diff-filter D --pretty="oneline" --name-only --format= -l 0 commit_hash_right_before_files_were_deleted..commit_hash_where_files_were_deleted | sed '/^$/d' | zip deleted-files.zip -@
git checkout master
unzip deleted-files.zip
git reset -- `git diff --diff-filter=D --name-only commit_hash_where_files_were_deleted`

There are some additional arguments that we are passing to the git log command . We are passing the -l 0 argument to avoid git log from truncating the list of returned changed files. We are also passing the --format= argument to prevent git log from outputting the commit hash and the commit message; we only care about the list of changed files.

Tried a few solutions including trying to to the git update-index --assume-unchanged command but when I tried to pull from the remote branch, it would just keep deleting the files. This is best solution that met my needs.

De'Yonte W.
  • 127
  • 7