In general, it's a good idea to read an actual book on git, rather than trying to understand it purely through manpages. The one I used (almost a decade ago) is this one:

        https://www.amazon.com/gp/product/1449316387/

It doesn't tell you everything you might want to know, but it covers most of it, while giving you enough backround to understand more esoteric stuff that you might find via Google.

On Sat, 11 Nov 2023, Hal Murray via devel wrote:

Merge requests seem reasonable if all goes well.  My work flow is roughly:
 download the patch  (URL plus ".patch")
 scan it
 maybe apply and test
 approve and merge

But things go downhill if I don't like something.  What I get from James is an
update to the MR, a patch to the patch.  That makes reading/checking the patch
harder and clutters up the git log.

What if I don't like the description of a patch?

Merge has an option to reduce all the patches to one.  But often that isn't
appropriate.

git works so well for most things.  I think I/we are missing something in the
workflow.

Indeed. The best way to obtain the content of an MR locally is via "git fetch", a highly underrated command. It's also good for updating your local repo in general. It tends to get overlooked because so many people use "git pull", which is a combination of "git fetch" and either "git merge" or "git rebase", depending on options. But performing the two steps separately gives you better control. Personally, I never use "git pull".

The first form of "git fetch" is:

        git fetch <remote>

This fetches all new commits from all branches in <remote> to your local repo, and updates the *local* heads of the *remote* branches to reflect that state. It does not touch your local branches, your index, or your working directory, so it's completely safe to use at any time (well, except during another git operation :-)).

The second form is:

        git fetch <remote> [+]<remote_branch>:<local_branch>

This updates <local_branch> to match <remote_branch>, creating <local_branch> if necessary. If <local_branch> already exists and the update wouldn't be a "fast forward" (appending new commits without replacing existing ones), then it fails unless the '+' is included (the equivalent of '-f' on "git push"). It does *not* touch the index or working directory, so it's safe to use in the middle of other activities, but for that reason it refuses to fetch into the currently checked out local branch. When that's a problem, there are multiple ways around it, with the choice depending on circumstances.

To get the contents of an MR locally:

        git fetch <MR_repo> <MR_branch>:<local_test_branch>

The one annoying thing is that GitLab doesn't provide a feature to get "<MR_remote> <MR_branch>" into the clipboard, so that requires some minor chasing.

This pulls in the content of the MR to <local_test_branch>, not just as a patch, but as the exact same set of commits as in <MR_branch>, complete with identical commit IDs. If you simply checkout <local_test_branch>, you now have exact same content as the MR head, but you can also rebase it, cherry-pick it, merge it, or do whatever else you want with it for testing. This includes being able to compare whatever different states you want with normal git tools.

If the MR is updated, you can simply repeat the same fetch to update your local copy. If the update was a forced update (e.g., after rebasing it to a later master), you'll need to use the '+' on the fetch to allow the local forced update.

BTW, it's best not to develop on the local master branch, but instead to use a separate local branch. That way, the local master can be fast-forwarded to the upstream master at any time. It also makes it less likely that you'll have the local master checked out and hence blocking the fetch to master. Even if the intent is to push to the upstream master directly rather than going through the MR mechanism, you can develop in another branch and push the final state to master.

Should we be throwing away merges and making new ones rather than patching
them?

Generally no, though I wouldn't exactly say that "patching them" is the right way to look at it.

How do I backup a bunch of commits that turned into a MR so I can make them
better and try again?

You don't need to explicitly "backup" anything. You can simply update your branch and then push it to the MR's source branch. This requires '-f' on the push if the changes are anything other than adding new commits. If you're referring to editing someone else's MR, just fetch it (see above) and go from there.

You can modify the latest commit on the current branch with "git commit --amend", though during development it may make more sense to just add new commits and clean it up afterward. Such cleanups don't necessarily have to be done before updating the MR for review, but should be done before actually merging it.

The general mechanism for updating a whole set of recent commits (in the curently checked-out branch) is interactive rebase. This serves a very different purpose than normal rebase, but it uses the same underlying mechanism, and consequently the same command. It starts with:

        git rebase -i <starting_commit>

Note that <starting commit> is actually the *last* commit *not* to be modified, i.e., the parent of the first commit to be potentially modified. In the particular case of cleaning up a short-term development branch, typical usage (assuming your branch is up to date with master) would be:

        git rebase -i master

This puts you in your editor with a "sequence file" listing all commits from the starting point to HEAD, in a one-line format, in *forward* chronological order. Each is preceded by an action keyword, initially 'pick', with means "apply this commit as is". You can drop commits either by changing the action to 'drop', or by simply deleting them from the list. You can change the order of the commits (which may introduce conflcts that need to be resolved. You can modify the content of any commit by changing its action to 'edit'. You can change a commit message without changing its content by specifying 'reword'. And you can combine two or more consecutive commits by changing the action of all but the first to 'squash'. Note that this is selective - it's not all or nothing like the WebGUI option (AIUI).

Beware that the default behavior of interactive rebase is probably not what you want if it straddles merge commits. There's a '-r' option that fixes this by adding tags to the sequence file so that it can preserve the branch structure, but its setup involves processing *all* lines of descent from the starting point, and may take a while. But this project makes very little use of merge commits, so the issue is mostly moot.

I'm on a list or two where patches are distributed via email.  git has several
commands for that.  Iterations usually have a v1 v2 ... as part of the
Subject.  Often individual parts will be approved.  It's a lof of clutter in
the email stream but the discussion gets archived in email rather than hidden
over in a MR.

Patches via email are more tedious, more error-prone, and sooo 20th century. :-)

MR discussions aren't "hidden" - they remain forever in the MR history (though the default display is limited to open MRs). Admittedly, having to use a hidden sidebar to get to the MR list has poor discoverability; I like GitHub's UI better.

Is there a way in gitlab to approve only one of the patches rather than all of
them?  I think I could do that by downloading the patch which is several email
messages, editing out the one I want...  Again, if that was the right thing to
be doing, I'd expect git to support it which it probably does if you use their
email mode.

I don't think this can be done from the WebGUI. Of course, once you have the content in your local repo, you can push anything you want, but the end run around the WebGUI probably confuses the history. With or without this problem, it's a bad idea to combine multiple unrelated changes into a single MR anyway. It's best to stick to one topic per branch, both locally and in any MRs derived from such branches. As long as the topical changes don't conflict, you can easily create a merge branch with whatever set of branches you want at any given time, so putting multiple topics in one development branch just to combine them for testing is unnecessary.


On Sat, 11 Nov 2023, James Browning via devel wrote:

"git rebase -i" allows you to selectively drop, reorder, squash,
and/or amend commits.  At least, that is what I have heard.

Yes - see above.

 I use GUI tools.

I avoid most GUI tools since they hide too much and aren't scriptable. I do, however, sometimes use gitk to view the branch structure graphically.

Fred Wright
_______________________________________________
devel mailing list
devel@ntpsec.org
https://lists.ntpsec.org/mailman/listinfo/devel

Reply via email to