My mental model is basically that they're separate repos, and the main repo has a pointer to a commit in the submodule. Do your work that needs to be done for the submodule, push your changes, and then check out that new commit. Make a commit in the main repo to officially bump the submodule to that new commit. Done.
The annoying part is when you do a pull on the main repo, you have to remember to run git submodule update --recursive.
If, for example, you add a submodule with the wrong url, then want to change the url, then you instinctively change .gitmodules. But that won't work, and it won't even nearly work.
If you add a submodule, then remove it, but not from all of those places, and try to add the submodule again (say, to a different path), then you also get wierd errors.
If you add a submodule and want to move it to another directory then just no.
Oh and also one time a colleague ran into problems because he had added the repo to the index directly - with git add ..
Oh and let's talk about tracking submodule branches and how you can mess that up by entering the submodule directories and running commands...
But seriously, the fact that there is a .gitmodules file lulls you into a sense that that file is "the configuration file". If you don't know about these other files, then it's natural to edit .gitmodules. When you make errors, the fixing those errors are pretty hard. There is no "git submodule remove x" or "git submodule set-url" or "git submodule mv".
For example, do you know how, on the top of your head, to get an existing submodule to track a branch?
How do you think someone who does not quite understand git would do it? Even with a pretty ok understanding of git infernal, you can put yourself deep in the gutter. (case in point, if you enter the submodule directory and push head to a new commit, you can just "git add submodule-directory" to get point the submodule to the new commit. But if you were to change upstream url or branch or something else in the submodule, you're screwed. That's not intuitive by a long shot)
Edit: git submodule sync is not enough by the way... You can fuck up your repo like crazy even if you sync the two configuration files.
Git subrepo or subtree are some of a solution but not quite complete and easy to use.
In some other scms (P4 and SVN, partly hg) the answer is don't do that, which had a whole lot of its own problems.
What's the alternative? Managing all dependencies by an external dependency manager does not exactly reduce complexity (if you're not within a closed ecosystem like Java + Maven that has a mature, de-facto standard dependency manager; npm might count, too).
It's absolutely not feasible for C++ projects; all projects that do this have horrible hacks upon hacks to fetch and mangle data and usually require gratuitous "make clean"s to untangle.
My point is, while your basic commands do the work, your habits and knowledge keep you from losing code like this without you knowing.
Not even once I lost I code worked on with git. stash is a reliable companion across branches and large timespans.
When using Git daily we never really did anything complicated, just a few feature branches per developer, commit, push, pull-request, merge. Basic stuff. We had Git crap out all the time. Never something that couldn't be fixed, but sometimes the fix was: copy your changes somewhere else, nuke your local repo, clone, copy changes in and then commit an continue as normal.
Haven't used reset personally though but only when trying to fix someone's repo.
You have a working directly/checkout - that can be: identical (apart from ignored files) to some version in git; or different.
If it's different ; some or all changes can be marked for storing in the git repo - most commonly as a new commit.
It's a bit unfortunate that the repo typically is inside your work directory/checkout - under '.git' along with some files like hooks, that are not in the repo at all...
Same is true of merge-based pull.
In other words, shouldn't git just fix ux for branches and rip out stash?
# git stash:
prev_ref="$(git rev-parse --abbrev-ref HEAD)"
git checkout -b wip-stash
git add .
git commit -m 'wip stuff'
git checkout "$prev_ref"
# git stash pop:
git checkout wip-stash -- .
git checkout -D wip-stash
It's quite a considerable saving. I suppose by "fix UX" you mean make it so the saving would be less anyway, but I think really they're just conceptually different: - branch: pointer to a line of history, i.e. a commit and inherently its ancestors
- stash: a single commit-like dump of patches
If stashing disappeared from git tomorrow, I think I'd use orphan commits rather than branches to replace it.Here to 'present' feature branches, we take a feature development branch will all the associated crud... Once it's ready to merge, the dev checkouts a new 'please merge me' branch, resets (or rebase -i --autosquash) to the original head, and re-lay all the changes as a set of 'public' commits to the subsystems, with proper headings, documentation etc.
At the end, he has the exact same code as the dirty branch, but clean... So he merges --no-ff the dirty branch in (no conflicts, same code!) and then the maintainer can merge --no-ff that nice, clean branch in the trunk/master.
What it gives us is a real, true history of the development (the dirty branch is kept) -- and a nice clean set of commits that is easy to review/push (the clean branch).
> I'll be darned if I understand the fear of the merge commit
I apologize in advance for not adding much substance in this reply, but I agree too much to just upvote alone.
I just know 5 basic commands; pull, push, commit, branch, and merge. Never ran into any issues. People who run into issues are usually editing git log or doing something fancy with “advanced” commands. I have a feeling that these people get into trouble with git cause they issue commands without really knowing what those commands do or even what they want to achieve.