Search code examples
gitgit-rebase

Has the Pro Git book got the syntax of git-rebase backwards?


Just as the title illustrates. I recently tried to run a git rebase command that had the reverse effect from what the Git pro's section on rebasing had. Maybe I interpreted it wrong, but its driving me crazy because what I thought was supposed to happen failed and I need to know what went wrong.

The section that I refer to is under More Interesting Rebases, particularly with the example when you rebase the server work branch onto the master branch. Git Rebasing.

enter image description here

The way how I interpreted was that the server work would be pasted on top of the master work, which is clearly what it happening based on the illustration.

I had two branches named OTWO-3196 (Capistrano configurations) and origin/orgs_phase_2 on my local machine. What I intended to do was to have the origin/orgs_phase_2 work rebase on top of my OTWO-3196 (Capistrano configurations) work. I typed into the terminal this command:

git rebase OTWO-3196(basebranch) origin/orgs_phase_2(topicbranch)

What I thought would place the orgs_phase_2 work on OTWO-3196 (Capistrano work) instead placed the OTWO-3196 (Capistrano work) onto orgs_phase_2. This was the exact reverse of what I wanted.

This command however worked:

git rebase origin/orgs_phase_2 OTWO-3196

This placed the work of origin/orgs_phase_2 onto OTWO-3196.

Did I interpret the command wrong? Is the book incorrect? What exactly happened? An extra pair of eyes would be helpful. Thanks.


Solution

  • I don't know what you did, or think you did, but origin/orgs_phase_2 is a remote-tracking branch. Its only purpose is to indicate where the branch reference called orgs_phase_2 pointed to in the remote repo called origin the last time you communicated with the latter. The only way such a reference can move is via a fetch or a push. In particular, you can't rebase a remote-tracking branch.

    Besides, the Pro Git book is correct. You have got the git-rebase syntax backwards. Git's rebase works as advertised in that book,

    git rebase [basebranch] [topicbranch]
    

    checks out the topic branch [...] for you and replays it onto the base branch [...]

    and in the git-rebase man page,

    Assume the following history exists and the current branch is "topic":

          A---B---C topic
         /
    D---E---F---G master
    

    From this point, the result of either of the following commands:

    git rebase master
    git rebase master topic
    

    would be:

                  A'--B'--C' topic
                 /
    D---E---F---G master
    

    To fix ideas, here is a baby example that you can reproduce at home:

    #!/bin/bash
    
    # set things up
    cd ~/Desktop
    mkdir test
    cd test
    git init
    
    # write an initial shopping list
    printf "4 pears\n" > shopping.txt
    printf "3 lemons\n" >> shopping.txt 
    printf "1 stalk of celery\n" >> shopping.txt 
    printf "4 bananas\n" >> shopping.txt 
    
    # make a first commit on master
    git add shopping.txt
    git commit -m "add shopping list"
    
    # modify the shopping list and make a second commit on master
    sed -i '' 's/4 pears/4 apples/' shopping.txt 
    git add shopping.txt
    git commit -m "replace pears by apples"
    
    # create and check out a new branch called "kidscominghome"
    git checkout -b kidscominghome
    
    # make two more commits on kidscominghome
    printf "16 pots of yoghurt\n" >> shopping.txt
    git add shopping.txt
    git commit -m "add yoghurt"
    printf "beer\n" >> shopping.txt 
    git add shopping.txt
    git commit -m "add beer"
    
    # check out master, modify the file, and make one more commit
    git checkout master
    sed -i '' 's/stalk of celery/cauliflower/' shopping.txt 
    git add shopping.txt
    git commit -m "replace celery by cauliflower"
    

    At this stage, the output of

    git log --graph --decorate --oneline --all
    

    should be

    * 5a0e340 (HEAD, master) replace celery by cauliflower
    | * d3d22d0 (kidscominghome) add beer
    | * edd730d add yoghurt
    |/  
    * 7dc55b7 replace pears by apples
    * 7079948 add shopping list
    

    Here is a nicer-looking graph showing the same history:

    enter image description here

    Now, if you run

    git rebase master kidscominghome
    

    and then run the same git log command, you should see

    * 2acf37d (HEAD, kidscominghome) add beer
    * dfac4a8 add yoghurt
    * 5a0e340 (master) replace celery by cauliflower
    * 7dc55b7 replace pears by apples
    * 7079948 add shopping list
    

    Again, here is a nicer-looking graph showing the same history:

    enter image description here

    As advertised, the kidscominghome branch has been checked out, and the commits that were only reachable from kidcominghome have been replayed on top of master; not the other way around!