You cannot get what you are asking for. You can get some approximations.
Git repositories are made up of commits. They don't hold files—at least not directly. The commits hold files, but the commit itself is the unit of storage. That's why git log
shows you the commit hash IDs: each one is a usable thing, all by itself.
Each commit stores a full snapshot of every file. You might think that this would take up a lot of space. It would, except for cleverness: Git compresses and de-duplicates the files inside each commit. They're not stored like regular files on your computer. They're in a special form that only Git can read, and literally nothing—not even Git itself—can overwrite.
This read-only property is a property of every internal Git object, in fact. So not only are the files contained inside commits read-only, so are the commits themselves. Git makes use of this in multiple ways. In particular, the hash ID that identifies each commit is unique to that one particular commit, and consists of a cryptographic checksum of the commit's content. This means that any two chunks of software that implement the Git transfer protocol can connect to each other, and one can then, in effect, say to the other: I have commit _____ (fill in the blank with a hash ID), would you like it? The other Git can tell whether it has that commit just by checking the hash ID. If it does have that commit, it has every file.
Not only that, but in all except shallow repositories, if the potential receiver has that commit, it also has every earlier commit and the sender is now done: there's nothing left to send. If the receiver doesn't have that commit, the sender is obligated to offer the parent commit(s) of that commit. This goes on until the sender has offered all the commits, or the sender and receiver have reached a point of shared commits. So that's how the sender and receiver can negotiate a minimal set of files and commits to send, just by swapping a few hash IDs.
Anyway, the point of all this is that senders send—and receivers receive—whole commits. The file de-duplication trick means that the sender knows whether the receiver has some file already, because the sender knows which commits the receiver has, and those commits (that the sender also has) have the file hash IDs in them. So the sender only really has to send any new commits and new files, and the receiver automatically uses the duplicate files to fill out newly-received commits as needed. It's all a very clever system, but it depends, fundamentally, on this hashing system and the idea that commits never change and that repositories only exchange whole commits.1
What this means for you is that git push
sends some commits, and then that's it. You can't send part of a commit somewhere else. Every commit holds a full snapshot of every file. The only way to send commits that have fewer files in them is ... to make commits that have fewer files in them.
There are some tools for doing this, such as git-subtree
. The subtree code is not currently maintained. See When to use git subtree? The lack of maintenance would concern me if I were looking at using it.
The other tool for doing this, which is maintained, is Git's submodules. These are described lightly in the same linked SO question, but basically a submodule is a way to say, in one Git repository: Clone this other Git repository, into a sub-directory within the working tree I'll be using. Once your Git has cloned the other Git repository into that location, your Git uses the detached HEAD mode in the submodule to keep that submodule on one particular commit in that other Git repository.
This setup is kind of rigid and brittle and doesn't please many of its users.2 It does work though, and it can solve real problems. Consider it as an option.
1There's a recent deliberate weakening of this system with what Git calls partial clones, but they're still not really ready for everyday use. Think of the weakening as a sort of game of Jenga, where we pull out bits of solid structure to make everything lighter. If we pull out the wrong bit, the whole thing crashes down: oops!
2I've personally come to the conclusion that Submodules Are Wrong, and I have some thoughts about how to do them "right", but these thoughts have a long way to go before they might be realized in the form of any kind of usable code.