First, addressing your proposed solution: you will cause yourself unneeded trouble if you commit the same change in both places. The commits will not be the same from git's point of view (different SHA1 values) if anything is different; and even if you try to do everything perfectly, the timestamps will differ. I've messed myself up by forgetting the timestamps before, so trust me on this one. Once you have two different commits with the same changes, getting everything back in sync will probably be tedious, and there's a fair chance you'll end up accidentally deleting the files from production anyway, just to add insult to injury.
So instead:
I'm assuming that in the same commit where you delete the files you add them to .gitignore. (If not... well, it would be a good idea.) Even if you didn't, what I'm about to suggest will still work easily enough if there are no other deletes in the commit. (Bear with me, I think it will all make sense in a minute.)
So as you note, if you do a pull
then the commit (including the deletes) will be applied; and that's bad. But you can use reset
to "step over" those changes. I'll give the most general procedure. Suppose you have on production:
X --- X <--(master)
but you're behind origin
; now instead of pull
do
git fetch
giving you
X --- X <--(master)
\
A --- B --- C <--(origin/master)
^
deletes are here
If there is no A
(i.e. the first newly-fetched commit has the deletes), then you can skip this step; but otherwise:
git reset --hard A
and now we have
X --- X --- A <--(master)
\
B --- C <--(origin/master)
^
deletes are here
Next we need to let git think that B
is applied
git reset --mixed B
which leaves our work tree untouched. That means that git status
would now show the inverse of each change from B
as an unstaged change (unless (a) that change is a delete, and (b) a corresponding entry was put in .gitignore); more on that in a second, but our picture now looks like
X --- X --- A --- B <--(master)
\
C <--(origin/master)
If B
had changes other than deleting the files, you need to remove the "undoing" of those changes from your work tree.
git checkout -- .
should apply anything except file deletes (which is good, because you don't want to apply the deletes - that being the point of this exercise). If there are other deletes, you'll need to reapply those manually. The git status
output will lead the way (especially if you updated .gitignore
, since in that case you'll know you're done when git status
reports a clean work tree).
From here we just go back to normal approach, so if there is a commit C
(i.e. there have been commits after the deletes):
git pull
and finally we have
X --- X --- A --- B --- C <--(master)(origin/master)
without the worktree copies of the deleted files having been affected.