I’m working on updating several WordPress sites. Part of each site’s update includes converting the WordPress core and all frequently used plugins to Git submodules. While many recommend staying away from submodules all together, I’ve been using them for a while now and never had any issues, that is, until today. Luckily, it’s nothing severe, and in my case, pretty straight forward to fix (once you know the solution), but because the error didn’t make any sense, I’ve decided to document it here.
The main problem is that I’m unable to checkout the master
branch after adding the submodules on the develop
branch. Git complains with the following error:
error: The following untracked working tree files would be overwritten by checkout
That said, let’s look at the problem in detail and how we can solve it.
Problem
Let me setup the problem for you, in detail, using an example:
- You’re working on the
develop
branch - You removed the
wp-content/plugins/akismet
directory - You committed the changes
- You added
akismet
back as a submodule - You committed the changes
Attempt to checkout master branch
At this point, we’re on the develop
branch and trying to checkout the master
branch, but we’re greeted with this error:
# git checkout master error: The following untracked working tree files would be overwritten by checkout: wp-content/plugins/akismet/admin.php wp-content/plugins/akismet/akismet.css wp-content/plugins/akismet/akismet.gif wp-content/plugins/akismet/akismet.js wp-content/plugins/akismet/akismet.php wp-content/plugins/akismet/index.php wp-content/plugins/akismet/legacy.php wp-content/plugins/akismet/readme.txt wp-content/plugins/akismet/widget.php Aborting
For some reason, Git doesn’t recognize that those files have already been added and committed within the akismet
submodule, so it’s aborting the checkout to prevent them from being overwritten.
Review Git status
If there were truly untracked files, running a git status
would reveal them, but there aren’t any:
# git status On branch develop Your branch is up-to-date with 'origin/develop'. nothing to commit, working directory clean
Checkout master branch
Since we can’t checkout the master
branch the regular way, we’ll force it:
# git checkout master -f warning: unable to rmdir wp-content/plugins/akismet: Directory not empty Checking out files: 100% (1993/1993), done. Switched to branch 'master' Your branch is up-to-date with 'origin/master'.
Git displays a warning that it couldn’t remove our akismet
directory, which doesn’t make any sense, because it also exists on the master
branch, just not as a submodule.
Review Git status
We check the status again, just to find an untracked image directory:
# git status On branch master Your branch is up-to-date with 'origin/master'. Untracked files: (use "git add <file>..." to include in what will be committed) wp-content/plugins/akismet/img/ nothing added to commit but untracked files present (use "git add" to track)
To avoid tumbling down the rabbit hole deeper and deeper, let’s switch back to the develop
branch.
Checkout develop branch
It seems that everything is back to normal, but after a closer look, all submodule directories are either empty or incomplete. Running another git status
reveals that Git does recognize that something changed:
# git status On branch develop Your branch is up-to-date with 'origin/develop'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) (commit or discard the untracked or modified content in submodules) modified: wp-content/plugins/akismet (modified content) no changes added to commit (use "git add" and/or "git commit -a")
But to avoid any more confusion, let’s just reset all submodules.
Reset submodules
We’ll go inside the akismet
directory and hard reset it:
# cd wp-content/plugins/akismet # git reset --hard HEAD is now at 645e807 Version 2.5.9
We’re basically back to square one, and to save you all from hours of trial and error, let’s look at the solution.
Solution
The only reason I wanted to checkout the master
branch in the first place, was to merge in the develop
branch and apply my updates. So let’s go ahead and do that.
1. Remove submodules
First, we’re going to remove the submodules that caused the conflict:
rm -rf wp-content/plugins/akismet
Note that we’re removing it without Git (rm
vs git rm
); the goal here is just to get the problem directories out of the way. A git status
should display this:
# git status On branch develop Your branch is up-to-date with 'origin/develop'. Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) deleted: wp-content/plugins/akismet no changes added to commit (use "git add" and/or "git commit -a")
Not this:
# git status On branch develop Your branch is up-to-date with 'origin/develop'. Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: .gitmodules deleted: wp-content/plugins/akismet
2. Checkout master branch
Second, we’ll checkout the master
branch:
# git checkout master Checking out files: 100% (1993/1993), done. Switched to branch 'master' Your branch is up-to-date with 'origin/master'.
As you can see, without having to force it, we didn’t get the error we got before.
3. Merge develop into master branch
Third, we’ll merge our develop
branch into the master
branch:
# git merge develop Updating 957cfdc..f3b9cfd Fast-forward ... wp-content/plugins/akismet | 1 + wp-content/plugins/akismet/admin.php | 850 --- wp-content/plugins/akismet/akismet.css | 12 - wp-content/plugins/akismet/akismet.gif | Bin 2777 -> 0 bytes wp-content/plugins/akismet/akismet.js | 112 - wp-content/plugins/akismet/akismet.php | 608 -- wp-content/plugins/akismet/index.php | 2 - wp-content/plugins/akismet/legacy.php | 396 -- wp-content/plugins/akismet/readme.txt | 153 - wp-content/plugins/akismet/widget.php | 108 - ... create mode 160000 wp-content/plugins/akismet delete mode 100644 wp-content/plugins/akismet/admin.php delete mode 100644 wp-content/plugins/akismet/akismet.css delete mode 100644 wp-content/plugins/akismet/akismet.gif delete mode 100644 wp-content/plugins/akismet/akismet.js delete mode 100644 wp-content/plugins/akismet/akismet.php delete mode 100644 wp-content/plugins/akismet/index.php delete mode 100644 wp-content/plugins/akismet/legacy.php delete mode 100644 wp-content/plugins/akismet/readme.txt delete mode 100644 wp-content/plugins/akismet/widget.php ...
You’ll notice that our akismet
directory is now empty, but that’s because the files for the submodule weren’t actually part of the develop
branch, so this is expected.
4. Fetch and update submodules
Lastly, we’ll fetch and update our submodules:
git submodule foreach git fetch --tags git submodule update --init --recursive
Which will checkout the very versions we chose on the develop
branch:
# git submodule update --init --recursive Submodule path 'wp-content/plugins/akismet': checked out '645e80750a543e2682b2369adfc77814d284b6f3'
That’s it. You’re now on the master
branch with all the changes you’ve made on the develop
branch.
Conclusion
Granted, this is not the most elegant way to accomplish the task, but it does, nevertheless, fix the problem… and with just a few commands:
rm -rf wp-content/plugins/akismet git checkout master git merge develop git submodule foreach git fetch --tags git submodule update --init --recursive
If you have any thoughts, questions or problems, let me know in the comments.
You save me from a strong headhache, thanks a lot!
I’m always struggling with this cause from time to time I’m moving some in-house module to public github’s ones… but sometimes I need to go to master and do something there which is NOT merging back the new branch with the brand new external submodule, any idea on how to fix this?
This is simply a pain point when dealing with submodules. I guess you either have to temporarily get them out of the way, as apposed to removing them permanently, or perhaps move from submodules to subtrees, which would, I believe, circumvent the issue altogether.
You just saved my day! Thank You! 🙂
Thank you