3

I want to remove wordpress core files from a lot of git repositories but keep the files so it doesn't break local

git rm --cached -r wp-includes/ wp-admin/ ......

Solves the problem, the question is how, on production server, git pull the commit WITHOUT deleting physically the files so it doesn't break the production ?

What the solution to this ? (commit both on production and locally, and since the commit will be the same, nothing will be physically ereased ?)

sf_tristanb
  • 8,725
  • 17
  • 74
  • 118

1 Answers1

3

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.

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
  • I'm impressed by your detailled answer, thank you, i'm going to try this on 1 repository, but since I have this operation on 50+ repositories, is there any chance I could do the reset operation not by SHA1 commit, but with "last commit" so I can automate this process instead of performing this operations one by one ? Thanks for your feedback ! – sf_tristanb Apr 26 '17 at 14:35
  • I will manage my way with git ls-remote . Thanks, your solution works like a charm :-) – sf_tristanb Apr 26 '17 at 14:54
  • 1
    You can use any commit specifier in place of the SHA. So you could tag the commit and distribute the tag, or use HEAD~*N* if you know that the commit is `N` commits ago (or HEAD^ if you know it's the most recent commit). If you're just automating across many repo instances but only doing this once, then the SHA1 values will be the same for all instances, so capturing them once and putting them in a script might work just fine. – Mark Adelsberger Apr 26 '17 at 15:05