Git rebase in developing with an iterative upstream

267 views Asked by At

Git rebase for me is a good way to get a linear history, but recently I got a little confused of its behavior. The situation is that I have my local repo, my origin repo on GitLab and the read-only upstream repo of my course.

Basically TAs release documentations and codes in upstream repo, I fetch it and merge into my repo, and then finish the lab. It is an iterative process, for the lab2 is released after I finish lab1 and push it into origin. Things confusing happens in this iteration.

After lab3 was released, I rebased master (which contains my code for lab1 and lab2) onto upstream/master, only to find that my commits were all gathered together at latest location of git history, like:

lab1-TA-release -> lab2-TA-release -> lab3-TA-release -> lab1-my-code (with rebase time) -> lab2-my-code (with rebase time)

I think it is commits time that shows the track of my work, so what I'd like to see is a linear history like:

lab1-TA-release -> lab1-my-code -> lab2-TA-release -> lab2-my-code -> lab3-TA-release

Is there any way to realize my wish?

-----update-----

For example, now I have finished lab2 and lab3 has been released on upstream/master. lab3-TA-release is not on my local master (so I cannot simply use rebase to resort my master). I need to git rebase upstream/master first. It is here that my lab2-my-code and lab1-my-code got gathered together and all refreshed with new time. So the real commit time (when I finished my work) disappear and I got confused.

Is there any way to automatically reserve original time (means the real time) of commits and make it linear?

2

There are 2 answers

0
Kiyoaki On BEST ANSWER

I got it!

The tests I have been made was all in wrong direction. I'd like to answer my own question and give anyone who passes by some information.

Suppose that I have finished lab2 and lab3 has been released on upstream/master. lab3-TA-release is not on my local master.

The first thing is

$ git fetch upstream/master
$ git checkout upstream/master

And now HEAD is detached, simply run

$ git rebase master

to rebase upstream/master onto master.

Then it is important to save changes by creating a new temporary branch, for HEAD is detached. If you just checkout to other branch, changes are gone.

$ git branch temp
$ git checkout master
$ git merge temp

And the merge would be fast-forward, things all set.

Then just delete temp branch by

$ git branch -d temp
4
syohey On

If there is no conflicts between lab2-TA-release and lab1-my-code commits, you can do git rebase -i HEAD~4 (It doesn't need to be 4, but probably 4 in your case.) and simply change the order of the commits.

For example, when you run git rebase -i HEAD~4, you should probably see something like this:

pick <hash4...> Lab 2 released.
pick <hash3...> Lab 1 finished.
pick <hash2...> Lab 2 finished.
pick <hash1...> Lab 3 released.

# Rebase ...
# ...

Then you can simply switch the order by cutting and pasting:

pick <hash3...> Lab 1 finished.
pick <hash4...> Lab 2 released.
pick <hash2...> Lab 2 finished.
pick <hash1...> Lab 3 released.

# Rebase ...
# ...

I think if you only care about the commit timeline of your local repo, then it should retain the original times commited after reordering.

But, when you are to push the change to your remote repo, you might have to git push --force because otherwise you might get asked to git pull first before you push the new change, which is probably not what you're wanting because you seem to want your local commit timeline looking straight, not any merging happening in the graph of your commit history?

It's just that when you git push --force, it will not change the original times commited locally, but will change the times commited in the remote repo to the time you've pushed at.

Maybe you could try creating a temp branch and test it out to see what it looks like.

$ git checkout -b temp
$ git push -u origin temp
$ git rebase -i HEAD~n # Replace n with an appropriate number and reorder the commits. It should be successful if there isn't any conflict.

And when you git status, you should see the following messages:

On branch temp
Your branch and 'origin/temp' have diverged,
and have n and n different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)

nothing to commit, working tree clean

So you git push --force, and when you git log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=rfc2822, you should see a straight commit history with original time stamps.

And you can also look at the commit timeline of your remote repo to see what it looks like.