0

I have multiple files in my local in which I only want to push a certain file to my github, but everytime I add and commit that one particular file, even if I make the push to my github; all files get transferred to it instead of only pushing that one file which I want to be the only one transferred to that github. So im wondering, do I perhaps have to make another branch other than that of my master branch, since it seems like no matter what all my push attempts are going to transfer all my files instead of a particular one. Somewhere I read that github only pushes to files that you most recently commited, but this isnt true for me because when I add and commit a file, when I push all files get pushed and not that single edited. So how do a push that single file ONLY?

Mr Miyagi
  • 31
  • 6

1 Answers1

1

Git never pushes files. Git only pushes commits.

Every commit contains every file—or rather, every file that goes with that commit, as a snapshot.

For instance, suppose you have a small repository with just three commits:

$ git init
Initialized empty Git repository in ...
$ echo example > README.md
$ git add README.md
$ git commit -m initial
[master (root-commit) 1ba91cb] initial
 1 file changed, 1 insertion(+)
 create mode 100644 README.md
$ echo contents for file1 > file1.txt; git add file1.txt
$ echo contents for file2 > file2.txt; git add file2.txt
$ git commit -m commit-2
[master a232778] commit-2
 2 files changed, 2 insertions(+)
 create mode 100644 file1.txt
 create mode 100644 file2.txt
$ echo different content > file1.txt; git add file1.txt
$ git commit -m commit-3
[master b6b2eee] commit-3
 1 file changed, 1 insertion(+), 1 deletion(-)

Let's view the names of, and information about, the files inside commit-3:

$ git ls-tree -r HEAD
100644 blob 33a9488b167e4391ad6297a1e43e56f7ec8a294e    README.md
100644 blob 802d4bbd2e8eae48bbaab3b2bb65d5b7396a374a    file1.txt
100644 blob 43a59a7b12bfe183338873ba47312d0840488539    file2.txt

We only changed one file in this third commit, but all three files are in it. How about the names and information about the files in the initial commit?

$ git ls-tree -r HEAD~2
100644 blob 33a9488b167e4391ad6297a1e43e56f7ec8a294e    README.md

So, this is perfectly normal: each commit has all of that commit's files. This is always what you want!

Somewhere I read that github only pushes to files that you most recently committed ...

There is a quite different concept lurking here. While git push pushes commits, each commit itself is composed of multiple objects. Let's take a closer look at the third commit:

$ git cat-file -p HEAD | sed 's/@/ /'
tree 9a5b053002b6113f670344f397042dcf1b04ea68
parent a2327788f785cda09275bcbb02bf57121dc537ca
author Chris Torek <chris.torek gmail.com> 1586474456 -0700
committer Chris Torek <chris.torek gmail.com> 1586474456 -0700

commit-3

Note that the commit object itself consists of the lines tree, parent, author, committer, a blank line, and the commit message text.

The tree object is what we see in the git ls-tree output:

$ git cat-file -p HEAD^{tree}
100644 blob 33a9488b167e4391ad6297a1e43e56f7ec8a294e    README.md
100644 blob 802d4bbd2e8eae48bbaab3b2bb65d5b7396a374a    file1.txt
100644 blob 43a59a7b12bfe183338873ba47312d0840488539    file2.txt

This tree object refers to three blob objects. The copy of README.md in this tree object is exactly the same as the copy in the first commit's tree:

$ git cat-file -p 33a9488b167e4391ad6297a1e43e56f7ec8a294e
example

When you invoke git push, Git actually packages objects in order to send commits. This package usually takes the form of what Git calls a thin pack. A thin pack makes use of knowing what commits they already have, and thereby, which tree and blob objects they must have.

Suppose they already have the first two commits. Your Git will call up their Git and offer commit #3. They'll say: Okay, I need that commit. Your Git will immediately offer commit #2 as well, as that's required here, but for this one, they will say: No thanks, I have that and all its ancestors. So your Git now knows that they have the initial commit and the middle commit, and it's only the last one they need.

Hence, when you run git push origin master, your Git won't send objects 33a9488b167e4391ad6297a1e43e56f7ec8a294e and 43a59a7b12bfe183338873ba47312d0840488539. The Git over at origin already has them. So your Git sends a thin pack containing the latest commit object, its latest tree—they don't have that object—and the object for the one updated file, which in this case is the object with hash ID 802d4bbd2e8eae48bbaab3b2bb65d5b7396a374a. The thin pack does not contain the other two blob objects; they already have those.

They will "fatten up" the thin pack once they receive it. So now the pack has all the objects required. They have all the files, even though you only sent them one! They already had the other two.

There is nothing you need to do here. Just run git push; Git takes care of figuring out what Git objects are required. Make ordinary commits in the ordinary way, and Git will do Git's job.

torek
  • 448,244
  • 59
  • 642
  • 775