3

I have forked a repo from GitHub and made some commit on my master branch. And the upstream repo's master branch have some commits ahead of mine. So I need sync these commits.

$ git remote -v
origin  git@github.com:johnwatsondev/react-navigation.git (fetch)
origin  git@github.com:johnwatsondev/react-navigation.git (push)
upstream    https://github.com/react-community/react-navigation.git (fetch)
upstream    https://github.com/react-community/react-navigation.git (push)


$ git pull --rebase upstream master
From https://github.com/react-community/react-navigation
 * branch            master     -> FETCH_HEAD
First, rewinding head to replay your work on top of it...
Applying: Update: add logic for invoking back key pressed listener in CardStack.js and remove default process logic
Applying: Update: only android platform need process physical back key pressed event


$ git status
On branch master
Your branch and 'origin/master' have diverged,
and have 6 and 2 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)

nothing to commit, working tree clean


$ git pull
Merge made by the 'recursive' strategy.


$ git status
On branch master
Your branch is ahead of 'origin/master' by 7 commits.
(use "git push" to publish your local commits)

nothing to commit, working tree clean

I got this ugly commit history in my origin repo's master branch below:

commit history ugly

How can I make a elegant OP to sync my origin repo's master branch to upstream's master branch without ugly duplicate commits and the Merge branch *** commit?
(PS: I have make some change in my origin repo's master branch)

JohnWatsonDev
  • 1,227
  • 9
  • 16
  • You want to remove commits from the remote? – Nandu Kalidindi Nov 22 '17 at 02:41
  • you should be able to `git reset` to the fourth commit. – Serge Nov 22 '17 at 02:41
  • @NanduKalidindi Yes. I want a effective way to sync upstream's ahead commit and keep my origin's commit. I attached my OP command log above. Can you give me some hint? – JohnWatsonDev Nov 22 '17 at 02:47
  • I am not sure I completely understand but if you want to remove commits from remote, AFAIK you need to do a force push by resetting the last three commits. – Nandu Kalidindi Nov 22 '17 at 02:53
  • 1
    You can squash the previous `n` commits into a single commit using `git rebase HEAD~n -i` and then choosing which commits to squash and which to pick. Don't know if that's what you're looking for – Dane Nov 22 '17 at 02:59
  • @Dane I have changed my question for making a clear statement. – JohnWatsonDev Nov 22 '17 at 03:02
  • What do you mean by remove ugly commit history ? What do you want done ?? My comment allows you to merge the last n commits into a single one, with your preferred commit message – Dane Nov 22 '17 at 03:10
  • @Dane Thanks very much. Your method works well after I screw the commit history. – JohnWatsonDev Nov 22 '17 at 03:31
  • Then I shall post it as an answer, so that future viewers of this question may find it useful :) – Dane Nov 22 '17 at 03:34

3 Answers3

2

As answered in Squash my last X commits together using Git, you can squash the previous n commits into a single commit using

git rebase HEAD~n -i

When you run this command, a text editor will open, and you have to replace the pick in front of all n-1 commits you want to squash, with s. Please note that you have to do a force push after squashing. This way you can merge many commits into one.

Dane
  • 9,242
  • 5
  • 33
  • 56
  • 1
    In my case, I use `git rebase HEAD~3 -i`. I just use `drop` to drop the two duplicate commits `1a77371` and `7827f1c` . And I use `pick` to keep `1359c38` and `8ae63e5`. – JohnWatsonDev Nov 22 '17 at 03:44
1

If you want to get rid of the first three commits from remote, you need to force push to squash the commits.

  • git reset HEAD~3
  • git stash save 'Save the commit changes just in case'
  • git push origin -f master

Check this article out as well https://ncona.com/2011/07/how-to-delete-a-commit-in-git-local-and-remote/

DISCLAIMER: This could lead to data loss. Force push is not at all safe but that is the only way I know to remove commits from remote. Please feel free to suggest a robust solution or edit the answer that is more safe.

Nandu Kalidindi
  • 6,075
  • 1
  • 23
  • 36
  • Thanks very much. I have made a clear statement of my question now. – JohnWatsonDev Nov 22 '17 at 03:09
  • 1
    Data loss is not a problem here. You can recover the old commits from the refllog by a default of 90 days. The problem is that you force every developer who pulled from this branch during the faulty push and the reset to also reset their remote ref (and you might not even now everyone, if its a big project, so you have to make an announcement somewhere). – David Ongaro Nov 22 '17 at 03:13
  • I think he is trying to do this in his own forked repository. Because I was not able to see any such commits in the master repository. – Nandu Kalidindi Nov 22 '17 at 03:14
1

There are already lots of answers available on SO regarding how to reset a remote and local history, but I guess your question is more about how to avoid these ugly merge commits during a pull.

In general you don't want to use the default pull behavior when you want to keep a linear history, otherwise you get this ugly merge commits when there are both local and remote changes. You should get into the habit of using git pull -r to use rebase instead of merge strategy during pulls.

Of course you can also can make an alias for that or change the default pull behavior via pull.rebase=true or branch.master.rebase=true if you want to set this in a branch specific way. But git pull -r does some pretty magic stuff sometimes so I'm always wary in changing the default behavior.

The way I like to do it is to do an explicit fetch first via git fetch and only then do a git merge if it's a fast forward merge, or do a git rebase after reviewing the remote changes. This gives way more control. In fact git pull (in its default behavior) is basically a git fetch && git merge which is explains why you get a merge commit when there are new local and remote commits.

Of course you can also work on a local non-remote tracking branch and do explicit merges and rebases on the master branch.

David Ongaro
  • 3,568
  • 1
  • 24
  • 36
  • Thanks very much, buddy. You got my question. You pointed the right reason of why making a ugly commit history. I just executed `git pull origin master` command stupidly. This is the real reason. – JohnWatsonDev Nov 22 '17 at 03:48
  • If that happens and you notice right away that you get an unwanted merge commit it's also no biggie. Just do a `git reset --merge ORIG_HEAD`. It's only after a push that it gets more complicated. The `ORIG_HEAD` ref is also useful to inspect what new stuff was coming in with `git log ORIG_HEAD..` etc. – David Ongaro Nov 22 '17 at 04:26