1

I'm trying to push a specific commit to an upstream repo, which is the same as the one I'm working on, but with slight changes.

The current repo is ahead of the upstream one and I want to push some of the changes I made in the current repo, but not all of them.

When I do something like

git push upstream <commit SHA>:<remotebranchname>

It works, but it also pushes all the other commits done between the last commit in my upstream repo and the commit that I'm pushing.

I want, however, to push only the changes made in that one commit, not the changes done prior to that commit.

How to avoid them being integrated?

UPDATE The answers given explain how to push a specific commit (with all the history before it), but I want to push just the specific commit without the history behind it.

Aerodynamika
  • 7,883
  • 16
  • 78
  • 137
  • try checking out a branch from upstream, cherry-pick the commit you would want to push. make --set-upstream to whatever branch you want to push the commit to or make a PR – ankidaemon Nov 27 '19 at 10:02

3 Answers3

0

You first have to make your local history look like what you want to be pushed. Then you can push.

One of the thousands of possible ways is to use git rebase, for example:

git rebase -i upstream/remotebranchname

will show you an editor window with a list of commits you made that aren't pushed yet along with a small docu what to do. Just leave the lines with commits you want to push untouched, but delete the lines you don't want to push. Then save & exit. Hopefully, you won't have conflicts (changed files in the commits you want and in those you don't want).

Then you can push.

(If you locally want to preserve the commits you don't want to push (for whatever reason), first make, for example, a tag:

git tag usefultagname
houman.sanati
  • 1,054
  • 3
  • 18
  • 34
Marcus
  • 617
  • 3
  • 8
  • Yes, but in that case, say, I revert to that commit, I will push also all the history behind that commit. And I want to push ONLY the changes made in that commit. – Aerodynamika Nov 27 '19 at 11:03
  • 1
    No, if you rebase onto the remote branch, you will exactly get the commits you select. – Marcus Nov 27 '19 at 11:57
  • 1
    Git will *always* push the complete missing part of history. The only way not to push commits is to remove them from local history before pushing. – Marcus Nov 27 '19 at 12:03
  • this is not true. You can adjust git so it pushes only a certain commit. For instance, using `cherry-pick` – Aerodynamika Nov 27 '19 at 18:08
  • @DmitryParanyushkin: Note that `git push` does not push *changes*. It pushes *commits*. Git commits are not changesets; they are snapshots plus metadata. – torek Nov 27 '19 at 18:33
0

In order to avoid pushing certain changes, your branch should be set to the last commit which you would want to include. In your case, best option would be to create a new branch, reset it to the last commit you'd like to include, cherry-pick the one commit you want to push and push.

git checkout -b new-branch # make sure to do this **while you're on** the upstream branch
git pull <remote> <upstream branch> #just to be sure you're right where the remote upstream branch is
git cherry-pick <commit hash>
git push <remote> new-branch
unixia
  • 4,102
  • 1
  • 19
  • 23
  • Hm... I don't really get it... So while I'm in my `current` repo, I need to create a new branch, then get the commit and push it to the `upstream`? But why in your example it's written `remote`? – Aerodynamika Nov 27 '19 at 10:55
  • Also when I do that, because my commit is ancestor, then it does not revert to that commit, so i basically upload all the current changes. – Aerodynamika Nov 27 '19 at 11:03
  • @DmitryParanyushkin `upstream` that you are mentioning must be the name of a particular remote. If I understand correctly, you want to apply a specific commit on top of an upstream branch *without* having the commits that you have pushed to another branch which is yours, is this correct? If not, could you please make a flow chart of commits so its easier to understand? – unixia Nov 27 '19 at 18:03
0

This is forbidden.

A Git commit includes its parent hash ID(s). If you, as a sender, offer commit H (for some hash ID H) to another Git, that other Git need not accept H until it also has H's parent (or parents, if it is a merge commit). So you must offer H's parent(s). It need not accept that commit until it has that (or those) commit's parent(s) in turn, and so on.

To put it another way, the ID of a commit is its hash, but to have that commit in a repository implies that you also have all of its ancestors.1 Hence the only way to work with such a commit is to have all of its ancestors.

At that point, you can make a copy of that commit—e.g., via git cherry-pick—to get a different commit with a different hash ID, different parent, and whatever other differences you might want as a result of this different parent.2 You can then deliver this different commit (by its different hash ID) to some other Git repository. If that other Git repository does have the parent of this new copy, they won't demand any additional commits first.


1This rule is relaxed in shallow clones, and there is ongoing work to relax it in other ways, but it's still at least required in principal. A commit that doesn't have its ancestry is at least suspicious; it could be a fake; the integrity of the chain is determined by following the chain all the way back to the root.

2In particular, you probably want a different snapshot as well. Remember that Git commits hold snapshots—a full copy of every file—rather than changesets. So if your copy H' of commit H is to be applied to commit B, what you want in H' is not the snapshot that is in H, but rather the snapshot that results from changing H into a changeset, then applying that changeset to commit B, while taking into account any other differences between H's parent and B as well. To change H into a changeset, we (or Git) will compare its snapshot to its parent's snapshot.

(The git cherry-pick command is a tool for making H' from H-and-its-parent while having commit B checked out.)

torek
  • 448,244
  • 59
  • 642
  • 775