How to re-order dependent changes in darcs? - patch

In darcs, what if I want to re-order to the top (or just throw away) a patch which other patches depend on (i.e., change the same file)?
In git, I'd simply do a git rebase -i <UNTOUCHED-REVISION> and reorder or throw away some changes; then git would in a dumb fashion try to apply the old changes to the new variant of the tree one by one, and ask me to resolve the arising conflicts.
In darcs, I see no way to force it to ignore the dependencies between patches. If I obliterate or suspend (or unrecord) a patch which other patches depend on, darcs refuses to do it. (Because it wants to behave in a clever manner.)

I had the following plan to do this:
suspend the dependent patches (those which depend on the patch
which I want to re-order or throw away).
somehow unrecord the patch to re-order and save it somewhere else
(perhaps in another "darcs branch", i.e., a copy of the repo) and revert
the changes to the working directory so that the working directory is
clean.
after that, unsuspend the suspended patches up to the state
where I want to insert the re-ordered patch. (Resolving all arising conflicts.)
apply the saved patch (perhaps, by pulling from the saved "branch",
i.e., the copy of the darcs repo which I have saved on step 2).
unsuspend all remaining patches. (Resolving all arising conflicts.)
Here are some notes on how all this has proceeded.
1. suspend the dependent patches
If among the patches dependent on the patch you want to re-order there
is a single "minimal" one (according to the graph of dependencies),
then you simply give the command to suspend it (and after that there
will be no "active" patches which would depend on the re-ordered
patch):
darcs suspend -h <MINIMAL-DEPENDENT-HASH>
(and confirm the suspension of all other dependent patches).
Of course, if there are several minimal dependent patches, you have to
suspend each (each's subgraph will be asked for suspension).
2. save and revert the unwanted changes
Preparation
First, I look at the changes I'm going to work with:
darcs diff -h 61fbb4aeac9e69cf30d232eda274c18194d7a8d9 --diff-command='emacs -f ediff-directories-with-ancestor-command %1 %2'
(The change was logically simple, but diff showed it in a
complicated way, so, here, I launched Emacs's ediff via a special
function I had written for this purpose.)
I saw that the change included some cleanup and the addition of a new
feature. So, the plan is now to split it: unrecord the patch, and record two
patches instead.
darcs unrec -h 61fbb4aeac9e69cf30d232eda274c18194d7a8d9
Now, I can view and (perhaps, work) with the changes with ediff, too.
darcs diff --diff-command='emacs -f ediff-directories-with-ancestor-command %1 %2'
First, I record the cleanup patch (selecting and editing only the
relevant hunks). Then, the added action:
darcs rec -m 'examples/Process.hs: code cleanup (present as a sequence of actions and error handling)'
darcs rec -m 'examples/Process.hs: print the C program (from the AST) after the check (as gcc -E does)'
Saving as a patch (a variant)
One could use darcs obliterate -o or -O to save the obliterated
change, and then restore it with darcs apply (according to that advice).
But I proceeded differently:
Saving as a branch (a variant)
Cloning didn't work for a repo with suspended patches:
~/TOOLS/prog/language-c $ darcs clone . ../language-c_printAST
darcs failed: Can't clone a repository with a rebase in progress
~/TOOLS/prog/language-c $
So, let's make a copy (and check whether we would be allowed to pull
from it):
~/TOOLS/prog/language-c $ cp -a ../language-c ../language-c_printAST
~/TOOLS/prog/language-c $ darcs pull ../language-c_printAST
darcs failed: Incompatibility with repository /home/imz/TOOLS/prog/language-c_printAST:
Cannot transfer patches from a repository where a rebase is in progress
~/TOOLS/prog/language-c $ cd ../language-c_printAST/
~/TOOLS/prog/language-c_printAST $ darcs rebase obliterate
<...>
Really obliterate all undecided patches? y
Rebase finished!
~/TOOLS/prog/language-c_printAST $ cd ../language-c
~/TOOLS/prog/language-c $ darcs pull ../language-c_printAST
HINT: if you want to change the default remote repository to
/home/imz/TOOLS/prog/language-c_printAST,
quit now and issue the same command with the --set-default flag.
No remote patches to pull in!
~/TOOLS/prog/language-c $
Ok, good, so we will pull from that repo later.
Revert the changes
Throw away the unwanted (or re-ordered) patch:
darcs obliterate
3. Unsuspend the patches that should come before it
It's a good idea to make a backup copy of the repo at this point, because you
might screw something up during the unsuspending and resolving conflicts.
Unsuspend the patches that should come before it. (Unfortunately,
external merge tool is not supported in unsuspend.) It's better to
unsuspend them one by one as you'll have to resolve the conflicts
caused by each one and amend the patch:
darcs rebase unsuspend
# resolve conflicts
darcs amend
# repeat for the remaining patches you want to have
4. Apply the saved patch
darcs pull ../../language-c_printAST
# resolve conflicts
darcs amend
5. Unsuspend all remaining patches.
(Again, it's better to do this one by one.)
darcs rebase unsuspend
# resolve conflicts
darcs amend
# repeat for the remaining patches you want to have
(For some reason, on the first attempt, I lost a hunk in the last
unsuspended patch. But I repeated everything in a copy of the backup
copy, and there I reached the wished final state.)

Related

How to make `arc land` check local and phabricator review are in sync?

Consider the following workflow:
make some changes
git add . && git commit -am 'update 1'
arc diff, now local and phabricator code review are in sync
make some further changes and git commit -a --amend --no-edit
arc land and the local amended (unreviewed) changes are happily accepted by Arcanist and gets merged to master.
Apparently, if I don't do --amend in step 4 and create another commit, arc land would fail complaining a mismatch. But I would like to configure Arcanist so that with --amend arc land can fail as well. Is this possible?
It turns out the arc command I am using is monkey patched by my employer and there is a bug in the patch.

git-ignore dvc.lock in repositories where only the DVC pipelines are used

I want to use the pipeline functionality of dvc in a git repository. The data is managed otherwise and should not be versioned by dvc. The only functionality which is needed is that dvc reproduces the needed steps of the pipeline when dvc repro is called. Checking out the repository on a new system should lead to an 'empty' repository, where none of the pipeline steps are stored.
Thus, - if I understand correctly - there is no need to track the dvc.lock file in the repository. However, adding dvc.lock to the .gitginore file leads to an error message:
ERROR: 'dvc.lock' is git-ignored.
Is there any way to disable the dvc.lock in .gitignore check for this usecase?
This is definitely possible, as DVC features are loosely coupled to one another. You can do pipelining by writing your dvc.yaml file(s), but avoid data management/versioning by using cache: false in the stage outputs (outs field). See also helper dvc stage add -O (big O, alias of --outs-no-cache).
And the same for initial data dependencies, you can dvc add --no-commit them (ref).
You do want to track dvc.lock in Git though, so that DVC can determine the latest stage of the pipeline associated with the Git commit in every repo copy or branch.
You'll be responsible for placing the right data files/dirs (matching .dvc files and dvc.lock) in the workspace for dvc repro or dvc exp run to behave as expected. dvc checkout won't be able to help you.

Which means distributing a modified program as patches?

I've read articles from the GNU project about open-source and other licenses. Some licenses allow you to post your changes as patches, not complete source code (for example Q Public License or gnuplot license). What does it mean? What do such patches look like? Can you get an example?
I do not want to focus on the legal situation, but on the programming - general definition, etc.
A patch is the result of a diff between a reference source tree (typically the original version of a project) and your modified version.
It's typically obtained with the POSIX diff command. But nowadays, with the ubiquitous use of versioning tools like SVN, Mercurial or git, the patch is generally generated with these tools (svn diff, hg diff, git diff, etc.)
On the receiver end, the patch is typically applied with the POSIX patch command.
Here is an example. Let's suppose you are working on a project (the orig_version directory below). Before making any change, you wisely create a copy of it (the my_version directory below) and modify a file from the copy:
cp -a orig_version my_version
# Change "This is the original version"
# ... to "This is my modified version"
$ vi my_version/README.txt
Let's see the differences:
$ diff -ruN orig_version my_version
diff -ruN orig_version/README.txt my_version/README.txt
--- orig_version/README.txt 2021-02-16 10:53:05.303423169 +0100
+++ my_version/README.txt 2021-02-16 10:53:00.243495007 +0100
## -1 +1 ##
-This is the original version
+This is my modified version
# Rredirect this output so as to
# create a patch file we can send
$ diff -ruN orig_version my_version > /tmp/my.patch
The output above shows the difference between the two directory trees. We have put that difference in a file that we can later send (e.g. by mail) to someone else who will then be able to take a look at the changes and apply them with patch:
# First we create a copy of our project
$ cp -a orig_version test_version
$ cd test_version
$ cat README.txt
This is the original version
# Then we apply the patch
$ patch -p1 < /tmp/my.patch
patching file README.txt
# Let's see the result
$ cat README.txt
This is my modified version
Note: since we are in the test_version directory, we used the -p1 option so that patch ignores the first element of the file paths found in the output of diff (--- orig_version/README.txt becomes --- README.txt, same for the +++ line).
25 years ago, people used to send and receive patches by mail and apply them like I just shown. Today, with the advent of distributed version control systems and of websites like Bitbucket and Github, people clone repositories, use their tool to pull the last changes, to get a diff, to push their changes and they send pull requests instead of sending patches by mail.

Do not re-create repositories after updating

We manage systems and thus manage repositories. We remove repositories which we do not use, present in /etc/yum.repos.d/<file>
Our problem is: after an update/upgrade of the system, CentOS automatically re-creates the repositories which were removed, which is an issue for us.
Question: Is there a command / method to ensure repositories are not re-created after an upgrade on CentOS 7 systems.
Those repositories are created by someone, the OS doesn't recreate them.
Either they are restored by an update of a RPM package such as centos-release or by an automatic script you setup/run (ansible?).
I'm not aware of an automatic method to delete a repo; I see a couple of solutions:
Exclude centos-release from the upgradable packages, by adding
exclude=centos-release
to /etc/yum.conf (space separated list), but this could break some updates;
Disable them with:
# yum-config-manager --disable base,updates,extras,centosplus,epel,whatever
(this can be easily scripted and put in a cron or in your ansible playbook)
Write a small script and place it in /etc/cron.hourly/, e.g. /etc/cron.hourly/wipe_repos, containing:
#!/usr/bin/env bash
rm -f /etc/yum.repos.d/CentOS-Base.repo
or, better:
#!/usr/bin/env bash
yum-config-manager --disable base,updates,extras,centosplus,epel,whatever
I would suggest to use solution 2, since the repo files aren't overwritten by updates, but the new versions are placed along the old in .rpmnew files.
This is guaranteed by the flag %config(noreplace) in the source rpm of centos-release, applied to all files in /etc/yum.repos.d/.
You can check this by downloading the .src.rpm and opening the centos-release.spec file.
$ mkdir test && cd test
$ yumdownloader --source centos-release
$ rpm2cpio centos-release*.rpm | cpio -idmv
$ cat centos-release.spec
(or search for the package online and download the src.rpm)
Then scroll down to section %files and you'll notice:
%config(noreplace) /etc/yum.repos.d/*
%config(noreplace) means that all those files are not replaced with new files from an update, but the files from the new rpm are saved with the extension .rpmnew, so you'll have:
$ ls /etc/yum.repos.d/
CentOS-Base.repo <-- here you set them as disabled
CentOS-Base.repo.rpmnew <-- this comes from the update, but yum will ignore it
For reference, see http://people.ds.cam.ac.uk/jw35/docs/rpm_config.html or https://serverfault.com/a/48819/.
As I already said in the comments below the question, the reason why those repositories keep reappearing after an update is quite simple: the files defining the system repositories are owned by the package centos-release and whenever this package gets updated or reinstalled, the repositories reappear.
The package centos-release is a very basic package, it provides the capabilities redhat-release and system-release, and a number of other basic packages depend on it.
[local ~]$ rpm -q --provides centos-release
centos-release = 7-6.1810.2.el7.centos
centos-release(upstream) = 7.6
centos-release(x86-64) = 7-6.1810.2.el7.centos
config(centos-release) = 7-6.1810.2.el7.centos
redhat-release = 7.6-1
system-release = 7.6-1
system-release(releasever) = 7
[local ~]$ rpm -q --whatrequires system-release
setup-2.8.71-10.el7.noarch
grubby-8.28-25.el7.x86_64
[local ~]$ rpm -q --whatrequires redhat-release
initscripts-9.49.46-1.el7.x86_64
systemd-219-62.el7_6.5.x86_64
There is no easy way out of this.
But one possible solution might be to create a customized RPM package to replace centos-release. It should contain the pointers to your own repositories and of course needs to provide the capabilities redhat-release and system-release.
Please be aware that I have no idea if this is actually going to work, it's just something that came to my mind while thinking about the problem. It might save you the work of creating a full custom distribution derived from CentOS, which is the only other way I can think of to achieve what you seem to want.
My solution doesn't exactly solve the problem you request ("how do I delete default repository config files forever?"), but it does stabilize your config changes. If you zero out the files instead of deleting them, then system updates will leave your 'edited' versions unchanged.
I do feel that this is a 'hack', leaving named ghost files, but it's one I can live with. No need to disable or customize redhat-release or system-release.
My problem was slightly different than yours - I maintained different configs for the same repositories for different situations, indicated by filename. On updates the original files would return, leaving me with redundant and incorrect definitions. Now they don't.

Git merge results in 400 rename/rename conflicts, how do I resolve them quickly?

So, I have a number of Wordpress sites managed with a Git repository, all of which are branches off of a central upstream Git repository. I recently applied a bunch of updates to the parent repo, but one of the child website repos had a plugin updated to a different version and now throws up about 400 rename/rename conflicts. All of these conflicts are in an upstream plugin directory that would be safe to just resolve in favor of the upstream branch.
I want to do the following:
Ensure the upstream version of the files 'wins' the merge conflict (e.g. what the --theirs flag does with checkout)
Produce a mergeable history (If it's not safe for a coworker to type "git pull origin master" with an old repo, it's not an option. I'm religiously opposed to rebasing.)
Not restructure my Git repository (My hosting provider, Pantheon, will not install Composer dependencies at deploy time. Upstream plugins have to be part of the repo.)
Not get a repetitive stress injury (Has to be a reasonably small number of commands because I have to resolve these kinds of messes once a month or so.)
If I just type "git checkout wp-content/plugins/** --theirs", I get hit in the face with about 400 errors, and Git refuses to checkout the files. They look like this:
....400 or so errors omitted...
error: path 'wp-content/plugins/wordpress-seo/js/dist/wp-seo-quick-edit-handler-710.min.js' does not have their version
error: path 'wp-content/plugins/wordpress-seo/js/dist/wp-seo-quick-edit-handler-720.min.js' does not have their version
error: path 'wp-content/plugins/wordpress-seo/js/dist/wp-seo-recalculate-710.min.js' does not have their version
error: path 'wp-content/plugins/wordpress-seo/js/dist/wp-seo-recalculate-720.min.js' does not have their version
I categorically refuse to type 400 git rm/git add commands with each individual path included. git checkout --force is not an option, as --theirs and --force are mutually incompatible (for some reason). My current solution is to open Git GUI and manually right-click -> Use Remote Version and then click Yes... 400 times. I don't have to type the path at least but this is still time consuming.
How do I efficiently resolve a large number of rename/rename conflicts in favor of the remote repository?
Do you want to just resolve the conflicted files in favour of the remote, or just take a whole tree as it is in the remote?
For the latter, you could do this:
Just accept the files as-is with conflicts. git add . or similar
Commit the merge.
rm -Rf path/in/question
git checkout origin/branch -- path/in/question
git commit --amend -a
For the former, it's probably something pretty similar
Just accept the files as-is with conflicts. git add . or similar
Commit the merge.
Find files with conflicts. e.g. grep -r -l '>>>>' path/in/question > /tmp/conflicts.txt
Delete the files with conflicts, check out the desired versions, and amend the commit in a similar means to the above.
(If there are files/paths with spaces in them, small adjustments to the above commands may be necessary. I've given the simpler versions for clarity.)

Resources