0

Git twists my brain. But I think I'm halfway there with this problem.

I committed (twice) and pushed to GitHub, but the first commit contained two files that should not have been included. So I have done the following...

git reset --hard HEAD~2

This brought the HEAD back to the first commit with the extra files.

HEAD is now at 1979096c2

Now, if I amend, commit (and force push) again with ONLY the two files that were needed, does this correct the commit on GitHub?

To be more clear... the initial (wrong) commit contained 4 files. I want to amend it to only have 2 files. Am I on the right track?

edcincy
  • 321
  • 2
  • 3
  • 14
  • Only you can say if this will "correct the commit" since we don't know what you try to obtain. But if that's what you're in fact asking, if you do what you described, only the two files will be changed. Do you expect changes to other files to be there too? or not? – Romain Valeri Feb 07 '19 at 14:01
  • Yes. But be careful with force pushing as you are rewriting history and anyone who had pulled those commits will diverge now. – tayfun Feb 07 '19 at 14:01
  • My initial (wrong) commit contained 4 files. I want to amend that commit to only have 2 files. Will the amend, commit, push do this? – edcincy Feb 07 '19 at 14:04

3 Answers3

0

You are right and that will fix things. Be careful with force pushing though as you are basically rewriting history. Anyone who had pulled those commits you are going to delete will diverge from the remote. If you are the only person working on the repo or the branch, that wouldn't matter though.

tayfun
  • 3,065
  • 1
  • 19
  • 23
0

Instead of doing a hard reset, you can also do a git revert.

git revert <commit_id>

Use git log to refer to the commit id you want to revert.

5eeker
  • 1,016
  • 1
  • 9
  • 30
  • Yes... I actually did that one time before. Can you tell I'm a Git newbie? But this time it was telling me the files needed to be "moved or removed" before the merge could happen. When I attempted to use "--cache /path/to/file" git said it couldn't find the file! So I decided to use the amend method. – edcincy Feb 07 '19 at 14:21
  • THIS WORKED. Finally. Since I could not seem to delete the files from the bash command line, I found them on the file system and deleted them that way. The revert would replace them anyway. After using revert, I committed again with only the two files I needed. Amend (as noted in another comment) does not work as I suspected. – edcincy Feb 08 '19 at 12:29
-1

No.

First of all, when you say "amend, commit (and force push)", are you referring to the git commit --amend command? The naming of the amend option can be a little confusing. While it does reflect the command's purpose, it suggests that it edits the existing commit - which it does not do, because that is impossible.

What you have after resetting is something like this

O <--(master)
 \
  A -- B <--(origin/master)

So you committed twice (A and B), but A contains files you don't want in the repo, so you reset back 2 commits (to before A). Then the first thing to understand is, if you do a commit --amend from here it will be amending commit O - not commit A.

But also, what does it mean to "amend" a commit, given that - as I said above - you cannot change an existing commit? Well, it means you create a new commit - which has a new ID - and "replace" the old commit with it. Which sounds like hair-splitting, but it's important because "replacing" a commit doesn't do all the things you might assume it would do.

Let's suppose you reset to commit A. In your example as described, that would be git reset --hard master^ (1 commit before the branch tip - so you've checked out the commit that was "wrong"). Now you have

O -- A <--(master)
      \
       B <--(origin/master)

Now you can edit the worktree (i.e. delete the unwanted files), and then you could tell git to "amend" commit A. But what you'd get is

O -- A -- B <--(origin/master)
 \
  C <--(master)

C is a new commit with a new ID. IF you only made small changes before the commit --amend, then it applies mostly the same changes, relative to O, as A - but it is still an entirely distinct commit. In your local branch's history, C replaces A - but only in your local branch - not throughout the repository. B still sees A as its parent, and origin/master still points to B.

If you then force push, you will move origin/master to C. This is a history edit, which has consequences if the repository is shared with others. See the git rebase docs under "recovering from upstream rebase"; this section is applicable to any rewrite, whether or not it involves the rebase command. Also note that if you don't properly coordinate a force push with the other users of the repo, it is possible that any one of them will do the wrong thing when recovering and undo the changes you made.

So in addition to replacing A with C, this procedure removes B from the branch history, because "replacing' A with C is not an in-place replacement throughout the repository.

You could fix that by rebasing B from A to C. There are a few ways to go about that, such as

git checkout origin/master
git rebase --onto master HEAD^

This gives you

O -- A -- B <--(origin/master)
 \
  C -- B' <--(master)

Here I've used a notation that indicates that the new commit (B') applies the same changes as the old commit (B) relative to a new base - but it is still an entirely new commit. Again this is a history rewrite, and you would have to coordinate with any other users and force push.

Depending on why those files should be excluded from the repo, it may also be important to know that this does not (yet) physically remove the original history (including the files you've deleted). Your local repo will hold onto them for at least as long as the old history remains in the reflog. There are steps you can take to perform an earlier clean-up locally; but the remote (depending on how it's hosted) might or might not have convenient procedures for removing the files from there. And nothing you can do would guarantee that the files are removed from any other clones that might exist.

So if the files contained sensitive information (and if anyone else had access to the remote), you will need to treat that information as compromised. If the files are simply large, you can search for existing questions and answers that detail how to purge them from history to recover the space

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
  • And now I know why Git confuses me. I get numerous answers to the same problem. I am amending a commit to a branch on my own repo and then will open a pull request. Am I not safe using the amend as I described it? – edcincy Feb 07 '19 at 14:32
  • @edcincy - You get multiple answers because some people are focused on how they would have approached the original problem (rather than on the question you asked), and others either are wrong in their own understanding of git, or did not understand the question. That is why my answer is structured to give you enough information to understand WHY what you're doing won't do what I understand you to ask. If you prefer the "easier to digest' answers, that's fine - but they may lead you astray, and unless you take the time to understand git in its terms, it will continue to be confusing – Mark Adelsberger Feb 07 '19 at 16:36