git workflow for D

Steven Schveighoffer schveiguy at yahoo.com
Tue Dec 5 16:07:47 UTC 2017


On 12/4/17 3:14 PM, Ali Çehreli wrote:

> Dear git experts, given 3 repos, now what are the steps? Is the 
> following correct? What are the exact commands?

Disclaimer: I'm not a git expert.

> - Only once, create the original repo as an upstream of your local repo.

The wording is off (s/repo/remote), but yes. This one I always have to 
look up, because I don't remember the order of the URL vs. the name, and 
git doesn't care if you swap them. But the command is this:

git remote add upstream <url>

Where url is the https version of dlang's repository (IMPORTANT: for 
dlang members, do NOT use the ssh version, as then you can accidentally 
push to it without any confirmation).

> 
> - For each change:
> 
> 1) Fetch from upstream

git fetch upstream

will fetch EVERYTHING, all branches. But just for reference so you can 
use it without affecting your local repo.

> 
> 2) Rebase origin/master (on upstream, right?)

No, don't do this every time! If you never commit to your local master 
(which you shouldn't), you do it this way:

# This checks out your local master branch
git checkout master

# This moves your local master branch along to match that of master.
# The --ff-only is to ensure it only works if the merge is a fast-forward.
# A fast forward merge happens when your master is on the same commit
# history as the upstream master.
git merge --ff-only upstream/master

Optionally you can push your local master to origin, but it's not 
strictly necessary:

git push origin master

> 
> 3) Make changes

Step 2.1: checkout a local branch. You can even do this after you have 
changed some files but *before* you have committed them (IMO one of the 
best features of git as compared to, say, subversion).

# creates a new branch called mylocalfix based on local master, and 
checks it out.
git checkout -b mylocalfix

> 
> 4) Commit (potentially after 'add')

Protip: git commit -a automatically adds any modified files that are 
currently in the repo, but have been changed.

> 
> 5) Repeat steps 3 and 4 as needed

Correct!

> 
> 6) 'git push -force' so that your GitHub repo is up-to-date right? 
> (There, I mentioned "force". :) )

I'd say:

git push origin mylocalfix

This pushes *only* your mylocalfix branch to *your* fork of the repo.

No need to force as long as you do not want to squash. Squashing is when 
you merge multiple commits into one commit so that the history looks 
cleaner. I'd recommend never using force (btw, it's --force with 2 
dashes) unless it complains. And then, make sure you aren't doing 
something foolish before using the --force command! Because you are 
committing only to your fork, and to your branch, even if you mess up 
here, it's pretty easy to recover.

A couple of examples:

1. You commit, but missed a space between "if" and "(". Instead of 
generating a commit and log for the typo, you just squash the new commit 
into the first one.
2. You commit a work in progress, but then change the design. The first 
commit is useless in the history, as it probably doesn't even apply 
anymore, so you squash them together, as if you only ever committed the 
correct version.

To squash the last few commits, I recommend using rebase -i:

# Replace 3 with the number of the last few commits you want to work with.
# IMPORTANT: this must contain the commit you want to squash into!
git rebase -i HEAD~3

This will pop up an editor. Follow the instructions listed there! If you 
want to squash 2 commits together, use "fixup", or even just "f". Note: 
do NOT "fixup" your first commit, as this will try to squash into 
someone else's commit that happened before you changed anything!

Once you write the file and exit, git will rebase using your directions.

At this point you need to use --force to push (as long as you have 
already pushed before), as your commit history now differs from github's.

> 
> 7) Go to GitHub and press the big button to create a pull request

Correct! After you do this, you can continue to run steps 3, 4, 6 to 
update your PR.

One further step that I like to do to keep my repo clean:

8) When your PR is pulled:

git fetch upstream
git checkout master
git merge --ff-only upstream/master
git branch -d mylocalfix

This pulls the new changes that were successfully merged into dlang's 
master into your master. Then it deletes the mylocalfix branch (no 
longer needed). The lower case -d means to only delete if the changes 
have been merged (git will complain if they aren't in the history). This 
is a nice way to clean your local branches up, and verify there isn't 
anything amiss.

Note also, if you want to work on several fixes at once, you can 
checkout more than one local branch, and switch between them. Just 
remember to commit before you checkout the different branches (git will 
complain if you have uncommitted files, but not files that haven't ever 
been added).

Hope this all helps!

-Steve


More information about the Digitalmars-d-learn mailing list