0

I'm new to git and I think I made a mistake and I want to know if I can still fix it. I have 3 branches which are main (remote repo), development (remote repo), branchA (in local repo). I'm working on branchA and I add two commits in it and pushed it to remote repo using the code: git push origin branchA

But I noticed I committed those two commits using a wrong github account. I changed the author of the last recent commit using this code:git commit --amend --author="username <email@email.com>"

Then I did git rebase -i commithash to be able to edit the author on my commit before my recent commit. After I've set to 'edit', I ran this command again: git commit --amend --author="username <email@email.com>"

After that, I changed something on my code and committed it again in branchA. Then I pushed it in my remote repo using git push origin branchA and now im getting this error now:

To github.com:somename/githubrepo.git
! [rejected]        branchA -> branchA (non-fast-forward)        
error: failed to push some refs to 'github.com:somename/githubrepo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

I understand that the hash of the commit changes if you amend something in it. But I don't understand why the error message states that my local branchA is behind remote branchA when as per my understanding my local branchA is ahead of my remote branchA. Can I fix this? Not sure if its safe to do git push force. Please help. Thank you!

astra.xvi
  • 43
  • 7

1 Answers1

0

I understand that the hash of the commit changes if you amend something in it.

That's close, but not quite precise enough.

But I don't understand why the error message states that my local branchA is behind remote branchA when as per my understanding my local branchA is ahead of my remote branchA.

What git commit --amend does is kick the final commit off the end of the branch and add a new commit in its place. That is, if the branch used to look like this:

...--F--G--H   <-- branchA (HEAD), origin/branchA

(where each letter stands in for some hash ID; the most recent commit here is hash H), then after git commit --amend you have:

          H   <-- origin/branchA
         /
...--F--G
         \
          I   <-- branchA (HEAD)

You are now one commit ahead of origin/branchA (called branchA over in that other Git repository, stored over on the machine you call origin) and one commit behind origin/branchA. The one commit you're "behind" is the one you deliberately tossed off the end of your branchA so that you could add a substitute commit in place of commit H.

Commit H is not gone, or changed. It's still there, exactly the same as it was before. You have a new and improved commit I you'd like to use instead of commit H.

Can I fix this?

Maybe.

Not sure if its safe to do git push force.

Some kind of force is required, if you'd like to have the other Git repository also ditch their copy of (shared) commit H. Whether that's "safe" depends on who else might have a copy of H as well.

The approach that's completely safe is to avoid using git commit --amend. That is, instead of adding a replacement commit I, we add a new commit I—or maybe J now—that adds on to the history, rather than being a substitute:

             I   ??? [abandoned]
            /
...--F--G--H   <-- origin/branchA
            \
             J   <-- branchA (HEAD)

You can now git push commit J to origin because it adds on, even as it undoes and replaces the mistakes of commit H. The history in which H continues to exist, continues to exist on origin as well. Since Git everywhere is built to add new commits, everyone knows how to handle this.

Git can be (grudgingly) convinced to drop commits, and that's what force-pushing is generally about: they have some commits that we have decided are bad and we'd like them to drop those entirely, perhaps with no replacements, perhaps with our new and improved commits as replacements. But since commits spread virally from Git to Git, it's possible that you'll have to force-remove the bad commit(s) from two, or three, or a thousand repositories by now.

If you're pretty sure there's just one, or that the owners of the other two or 999 or whatever repositories all know how to deal with the idea that "commit H was bad, let's drop it", force-pushing is OK. Consider using --force-with-lease, which lets you verify that you're only dropping commit H and not some additional commits someone else added that depend on and use commit H (maybe they have already created commits J and K, in other words).

torek
  • 448,244
  • 59
  • 642
  • 775